Bug 454708 - storage-Legacy can throw when calling ConvertToUnicode. r=gavin
[wine-gecko.git] / browser / components / nsBrowserGlue.js
blob41464daf1fd57b956a4544141dc487323bb07fda
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>
23 # Seth Spitzer <sspitzer@mozilla.com>
24 # Asaf Romano <mano@mozilla.com>
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 const Ci = Components.interfaces;
41 const Cc = Components.classes;
42 const Cr = Components.results;
43 const Cu = Components.utils;
45 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
46 Cu.import("resource:///modules/distribution.js");
48 const PREF_EM_NEW_ADDONS_LIST = "extensions.newAddons";
50 // Check to see if bookmarks need backing up once per
51 // day on 1 hour idle.
52 const BOOKMARKS_ARCHIVE_IDLE_TIME = 60 * 60;
54 // Backup bookmarks once every 24 hours.
55 const BOOKMARKS_ARCHIVE_INTERVAL = 86400 * 1000;
57 // Factory object
58 const BrowserGlueServiceFactory = {
59 _instance: null,
60 createInstance: function (outer, iid)
62 if (outer != null)
63 throw Components.results.NS_ERROR_NO_AGGREGATION;
64 return this._instance == null ?
65 this._instance = new BrowserGlue() : this._instance;
69 // Constructor
71 function BrowserGlue() {
72 this._init();
75 BrowserGlue.prototype = {
76 _saveSession: false,
78 _setPrefToSaveSession: function()
80 var prefBranch = Cc["@mozilla.org/preferences-service;1"].
81 getService(Ci.nsIPrefBranch);
82 prefBranch.setBoolPref("browser.sessionstore.resume_session_once", true);
85 // nsIObserver implementation
86 observe: function(subject, topic, data)
88 switch(topic) {
89 case "xpcom-shutdown":
90 this._dispose();
91 break;
92 case "quit-application":
93 this._onProfileShutdown();
94 break;
95 case "prefservice:after-app-defaults":
96 this._onAppDefaults();
97 break;
98 case "final-ui-startup":
99 this._onProfileStartup();
100 break;
101 case "sessionstore-windows-restored":
102 this._onBrowserStartup();
103 break;
104 case "browser:purge-session-history":
105 // reset the console service's error buffer
106 const cs = Cc["@mozilla.org/consoleservice;1"].
107 getService(Ci.nsIConsoleService);
108 cs.logStringMessage(null); // clear the console (in case it's open)
109 cs.reset();
110 break;
111 case "quit-application-requested":
112 this._onQuitRequest(subject, data);
113 break;
114 case "quit-application-granted":
115 if (this._saveSession) {
116 this._setPrefToSaveSession();
118 break;
119 case "session-save":
120 this._setPrefToSaveSession();
121 subject.QueryInterface(Ci.nsISupportsPRBool);
122 subject.data = true;
123 break;
124 case "idle":
125 if (this.idleService.idleTime > BOOKMARKS_ARCHIVE_IDLE_TIME * 1000) {
126 // Back up bookmarks.
127 this._archiveBookmarks();
129 break;
133 // initialization (called on application startup)
134 _init: function()
136 // observer registration
137 const osvr = Cc['@mozilla.org/observer-service;1'].
138 getService(Ci.nsIObserverService);
139 osvr.addObserver(this, "quit-application", false);
140 osvr.addObserver(this, "xpcom-shutdown", false);
141 osvr.addObserver(this, "prefservice:after-app-defaults", false);
142 osvr.addObserver(this, "final-ui-startup", false);
143 osvr.addObserver(this, "sessionstore-windows-restored", false);
144 osvr.addObserver(this, "browser:purge-session-history", false);
145 osvr.addObserver(this, "quit-application-requested", false);
146 osvr.addObserver(this, "quit-application-granted", false);
147 osvr.addObserver(this, "session-save", false);
150 // cleanup (called on application shutdown)
151 _dispose: function()
153 // observer removal
154 const osvr = Cc['@mozilla.org/observer-service;1'].
155 getService(Ci.nsIObserverService);
156 osvr.removeObserver(this, "quit-application");
157 osvr.removeObserver(this, "xpcom-shutdown");
158 osvr.removeObserver(this, "prefservice:after-app-defaults");
159 osvr.removeObserver(this, "final-ui-startup");
160 osvr.removeObserver(this, "sessionstore-windows-restored");
161 osvr.removeObserver(this, "browser:purge-session-history");
162 osvr.removeObserver(this, "quit-application-requested");
163 osvr.removeObserver(this, "quit-application-granted");
164 osvr.removeObserver(this, "session-save");
167 _onAppDefaults: function()
169 // apply distribution customizations (prefs)
170 // other customizations are applied in _onProfileStartup()
171 var distro = new DistributionCustomizer();
172 distro.applyPrefDefaults();
175 // profile startup handler (contains profile initialization routines)
176 _onProfileStartup: function()
178 // Check to see if the EULA must be shown on startup
180 var prefBranch = Cc["@mozilla.org/preferences-service;1"].
181 getService(Ci.nsIPrefBranch);
182 var mustDisplayEULA = false;
183 try {
184 mustDisplayEULA = !prefBranch.getBoolPref("browser.EULA.override");
185 } catch (e) {
186 // Pref might not exist
189 // Make sure it hasn't already been accepted
190 if (mustDisplayEULA) {
191 try {
192 var EULAVersion = prefBranch.getIntPref("browser.EULA.version");
193 mustDisplayEULA = !prefBranch.getBoolPref("browser.EULA." + EULAVersion + ".accepted");
194 } catch(ex) {
198 if (mustDisplayEULA) {
199 var ww2 = Cc["@mozilla.org/embedcomp/window-watcher;1"].
200 getService(Ci.nsIWindowWatcher);
201 ww2.openWindow(null, "chrome://browser/content/EULA.xul",
202 "_blank", "chrome,centerscreen,modal,resizable=yes", null);
205 this.Sanitizer.onStartup();
206 // check if we're in safe mode
207 var app = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).
208 QueryInterface(Ci.nsIXULRuntime);
209 if (app.inSafeMode) {
210 var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
211 getService(Ci.nsIWindowWatcher);
212 ww.openWindow(null, "chrome://browser/content/safeMode.xul",
213 "_blank", "chrome,centerscreen,modal,resizable=no", null);
216 // initialize Places
217 this._initPlaces();
219 // apply distribution customizations
220 // prefs are applied in _onAppDefaults()
221 var distro = new DistributionCustomizer();
222 distro.applyCustomizations();
224 // handle any UI migration
225 this._migrateUI();
228 // profile shutdown handler (contains profile cleanup routines)
229 _onProfileShutdown: function()
231 this._shutdownPlaces();
232 this.idleService.removeIdleObserver(this, BOOKMARKS_ARCHIVE_IDLE_TIME);
233 this.Sanitizer.onShutdown();
236 // Browser startup complete. All initial windows have opened.
237 _onBrowserStartup: function()
239 var prefBranch = Cc["@mozilla.org/preferences-service;1"].
240 getService(Ci.nsIPrefBranch);
241 // If new add-ons were installed during startup open the add-ons manager.
242 if (prefBranch.prefHasUserValue(PREF_EM_NEW_ADDONS_LIST)) {
243 var args = Cc["@mozilla.org/supports-array;1"].
244 createInstance(Ci.nsISupportsArray);
245 var str = Cc["@mozilla.org/supports-string;1"].
246 createInstance(Ci.nsISupportsString);
247 str.data = "";
248 args.AppendElement(str);
249 var str = Cc["@mozilla.org/supports-string;1"].
250 createInstance(Ci.nsISupportsString);
251 str.data = prefBranch.getCharPref(PREF_EM_NEW_ADDONS_LIST);
252 args.AppendElement(str);
253 const EMURL = "chrome://mozapps/content/extensions/extensions.xul";
254 const EMFEATURES = "chrome,menubar,extra-chrome,toolbar,dialog=no,resizable";
255 var ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
256 getService(Ci.nsIWindowWatcher);
257 ww.openWindow(null, EMURL, "_blank", EMFEATURES, args);
258 prefBranch.clearUserPref(PREF_EM_NEW_ADDONS_LIST);
262 _onQuitRequest: function(aCancelQuit, aQuitType)
264 // If user has already dismissed quit request, then do nothing
265 if ((aCancelQuit instanceof Ci.nsISupportsPRBool) && aCancelQuit.data)
266 return;
268 var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
269 getService(Ci.nsIWindowMediator);
271 var windowcount = 0;
272 var pagecount = 0;
273 var browserEnum = wm.getEnumerator("navigator:browser");
274 while (browserEnum.hasMoreElements()) {
275 windowcount++;
277 var browser = browserEnum.getNext();
278 var tabbrowser = browser.document.getElementById("content");
279 if (tabbrowser)
280 pagecount += tabbrowser.browsers.length;
283 this._saveSession = false;
284 if (pagecount < 2)
285 return;
287 if (aQuitType != "restart")
288 aQuitType = "quit";
290 var prefBranch = Cc["@mozilla.org/preferences-service;1"].
291 getService(Ci.nsIPrefBranch);
292 var showPrompt = true;
293 try {
294 // browser.warnOnQuit is a hidden global boolean to override all quit prompts
295 // browser.warnOnRestart specifically covers app-initiated restarts where we restart the app
296 // browser.tabs.warnOnClose is the global "warn when closing multiple tabs" pref
298 var sessionWillBeSaved = prefBranch.getIntPref("browser.startup.page") == 3 ||
299 prefBranch.getBoolPref("browser.sessionstore.resume_session_once");
300 if (sessionWillBeSaved || !prefBranch.getBoolPref("browser.warnOnQuit"))
301 showPrompt = false;
302 else if (aQuitType == "restart")
303 showPrompt = prefBranch.getBoolPref("browser.warnOnRestart");
304 else
305 showPrompt = prefBranch.getBoolPref("browser.tabs.warnOnClose");
306 } catch (ex) {}
308 if (!showPrompt)
309 return false;
311 var buttonChoice = 0;
312 var bundleService = Cc["@mozilla.org/intl/stringbundle;1"].
313 getService(Ci.nsIStringBundleService);
314 var quitBundle = bundleService.createBundle("chrome://browser/locale/quitDialog.properties");
315 var brandBundle = bundleService.createBundle("chrome://branding/locale/brand.properties");
317 var appName = brandBundle.GetStringFromName("brandShortName");
318 var quitDialogTitle = quitBundle.formatStringFromName(aQuitType + "DialogTitle",
319 [appName], 1);
321 var message;
322 if (aQuitType == "restart")
323 message = quitBundle.formatStringFromName("messageRestart",
324 [appName], 1);
325 else if (windowcount == 1)
326 message = quitBundle.formatStringFromName("messageNoWindows",
327 [appName], 1);
328 else
329 message = quitBundle.formatStringFromName("message",
330 [appName], 1);
332 var promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].
333 getService(Ci.nsIPromptService);
335 var flags = promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_0 +
336 promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_1 +
337 promptService.BUTTON_POS_0_DEFAULT;
339 var neverAsk = {value:false};
340 var button0Title, button2Title;
341 var button1Title = quitBundle.GetStringFromName("cancelTitle");
342 var neverAskText = quitBundle.GetStringFromName("neverAsk");
344 if (aQuitType == "restart")
345 button0Title = quitBundle.GetStringFromName("restartTitle");
346 else {
347 flags += promptService.BUTTON_TITLE_IS_STRING * promptService.BUTTON_POS_2;
348 button0Title = quitBundle.GetStringFromName("saveTitle");
349 button2Title = quitBundle.GetStringFromName("quitTitle");
352 buttonChoice = promptService.confirmEx(null, quitDialogTitle, message,
353 flags, button0Title, button1Title, button2Title,
354 neverAskText, neverAsk);
356 switch (buttonChoice) {
357 case 2: // Quit
358 if (neverAsk.value)
359 prefBranch.setBoolPref("browser.tabs.warnOnClose", false);
360 break;
361 case 1: // Cancel
362 aCancelQuit.QueryInterface(Ci.nsISupportsPRBool);
363 aCancelQuit.data = true;
364 break;
365 case 0: // Save & Quit
366 this._saveSession = true;
367 if (neverAsk.value) {
368 if (aQuitType == "restart")
369 prefBranch.setBoolPref("browser.warnOnRestart", false);
370 else {
371 // always save state when shutting down
372 prefBranch.setIntPref("browser.startup.page", 3);
375 break;
379 // returns the (cached) Sanitizer constructor
380 get Sanitizer()
382 if(typeof(Sanitizer) != "function") { // we should dynamically load the script
383 Cc["@mozilla.org/moz/jssubscript-loader;1"].
384 getService(Ci.mozIJSSubScriptLoader).
385 loadSubScript("chrome://browser/content/sanitize.js", null);
387 return Sanitizer;
390 _idleService: null,
391 get idleService() {
392 if (!this._idleService)
393 this._idleService = Cc["@mozilla.org/widget/idleservice;1"].
394 getService(Ci.nsIIdleService);
395 return this._idleService;
399 * Initialize Places
400 * - imports the bookmarks html file if bookmarks datastore is empty
402 * These prefs are set by the backend services upon creation (or recreation)
403 * of the Places db:
404 * - browser.places.importBookmarksHTML
405 * Set to false by the history service to indicate we need to re-import.
406 * - browser.places.smartBookmarksVersion
407 * Set during HTML import to indicate that Smart Bookmarks were created.
408 * Set to -1 to disable Smart Bookmarks creation.
409 * Set to 0 to restore current Smart Bookmarks.
411 * These prefs are set up by the frontend:
412 * - browser.bookmarks.restore_default_bookmarks
413 * Set to true by safe-mode dialog to indicate we must restore default
414 * bookmarks.
416 _initPlaces: function bg__initPlaces() {
417 // we need to instantiate the history service before checking
418 // the browser.places.importBookmarksHTML pref, as
419 // nsNavHistory::ForceMigrateBookmarksDB() will set that pref
420 // if we need to force a migration (due to a schema change)
421 var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].
422 getService(Ci.nsINavHistoryService);
424 var prefBranch = Cc["@mozilla.org/preferences-service;1"].
425 getService(Ci.nsIPrefBranch);
427 var importBookmarks = false;
428 var restoreDefaultBookmarks = false;
429 try {
430 restoreDefaultBookmarks = prefBranch.getBoolPref("browser.bookmarks.restore_default_bookmarks");
431 } catch(ex) {}
433 if (restoreDefaultBookmarks) {
434 // Ensure that we already have a bookmarks backup for today
435 this._archiveBookmarks();
436 // we will restore bookmarks from html
437 importBookmarks = true;
439 else {
440 try {
441 importBookmarks = prefBranch.getBoolPref("browser.places.importBookmarksHTML");
442 } catch(ex) {}
445 if (!importBookmarks) {
446 // Call it here for Fx3 profiles created before the Places folder
447 // has been added, otherwise it's called during import.
448 this.ensurePlacesDefaultQueriesInitialized();
450 else {
451 // get latest backup
452 Cu.import("resource://gre/modules/utils.js");
453 var bookmarksFile = PlacesUtils.getMostRecentBackup();
455 if (!restoreDefaultBookmarks &&
456 bookmarksFile && bookmarksFile.leafName.match("\.json$")) {
457 // restore a JSON backup
458 PlacesUtils.restoreBookmarksFromJSONFile(bookmarksFile);
460 else {
461 // if there's no JSON backup or we are restoring default bookmarks
463 // ensurePlacesDefaultQueriesInitialized() is called by import.
464 prefBranch.setIntPref("browser.places.smartBookmarksVersion", 0);
466 var dirService = Cc["@mozilla.org/file/directory_service;1"].
467 getService(Ci.nsIProperties);
469 var bookmarksFile = dirService.get("BMarks", Ci.nsILocalFile);
470 if (restoreDefaultBookmarks || !bookmarksFile.exists()) {
471 // get bookmarks.html file from default profile folder
472 bookmarksFile = dirService.get("profDef", Ci.nsILocalFile);
473 bookmarksFile.append("bookmarks.html");
476 // import the file
477 try {
478 var importer = Cc["@mozilla.org/browser/places/import-export-service;1"].
479 getService(Ci.nsIPlacesImportExportService);
480 importer.importHTMLFromFile(bookmarksFile, true /* overwrite existing */);
481 } catch (err) {
482 // Report the error, but ignore it.
483 Cu.reportError(err);
485 prefBranch.setBoolPref("browser.places.importBookmarksHTML", false);
486 if (restoreDefaultBookmarks)
487 prefBranch.setBoolPref("browser.bookmarks.restore_default_bookmarks",
488 false);
492 // Initialize bookmark archiving on idle.
493 // Once a day, either on idle or shutdown, bookmarks are backed up.
494 this.idleService.addIdleObserver(this, BOOKMARKS_ARCHIVE_IDLE_TIME);
498 * Places shut-down tasks
499 * - back up and archive bookmarks
500 * - export bookmarks as HTML, if so configured
502 * Note: quit-application-granted notification is received twice
503 * so replace this method with a no-op when first called.
505 _shutdownPlaces: function bg__shutdownPlaces() {
506 // Backup and archive Places bookmarks.
507 this._archiveBookmarks();
509 // Backup bookmarks to bookmarks.html to support apps that depend
510 // on the legacy format.
511 var prefs = Cc["@mozilla.org/preferences-service;1"].
512 getService(Ci.nsIPrefBranch);
513 var autoExportHTML = false;
514 try {
515 autoExportHTML = prefs.getBoolPref("browser.bookmarks.autoExportHTML");
516 } catch(ex) {
517 Components.utils.reportError(ex);
520 if (autoExportHTML) {
521 Cc["@mozilla.org/browser/places/import-export-service;1"].
522 getService(Ci.nsIPlacesImportExportService).
523 backupBookmarksFile();
528 * Back up and archive bookmarks
530 _archiveBookmarks: function nsBrowserGlue__archiveBookmarks() {
531 Cu.import("resource://gre/modules/utils.js");
533 var lastBackup = PlacesUtils.getMostRecentBackup();
535 // Backup bookmarks if there aren't any backups or
536 // they haven't been backed up in the last 24 hrs.
537 if (!lastBackup ||
538 Date.now() - lastBackup.lastModifiedTime > BOOKMARKS_ARCHIVE_INTERVAL) {
539 var maxBackups = 5;
540 var prefs = Cc["@mozilla.org/preferences-service;1"].
541 getService(Ci.nsIPrefBranch);
542 try {
543 maxBackups = prefs.getIntPref("browser.bookmarks.max_backups");
544 } catch(ex) {}
546 PlacesUtils.archiveBookmarksFile(maxBackups, false /* don't force */);
550 _migrateUI: function bg__migrateUI() {
551 var prefBranch = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
553 var migration = 0;
554 try {
555 migration = prefBranch.getIntPref("browser.migration.version");
556 } catch(ex) {}
558 if (migration == 0) {
559 // this code should always migrate pre-FF3 profiles to the current UI state
561 // grab the localstore.rdf and make changes needed for new UI
562 this._rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
563 this._dataSource = this._rdf.GetDataSource("rdf:local-store");
564 this._dirty = false;
566 let currentsetResource = this._rdf.GetResource("currentset");
567 let toolbars = ["nav-bar", "toolbar-menubar", "PersonalToolbar"];
568 for (let i = 0; i < toolbars.length; i++) {
569 let toolbar = this._rdf.GetResource("chrome://browser/content/browser.xul#" + toolbars[i]);
570 let currentset = this._getPersist(toolbar, currentsetResource);
571 if (!currentset) {
572 // toolbar isn't customized
573 if (i == 0)
574 // new button is in the defaultset, nothing to migrate
575 break;
576 continue;
578 if (/(?:^|,)unified-back-forward-button(?:$|,)/.test(currentset))
579 // new button is already there, nothing to migrate
580 break;
581 if (/(?:^|,)back-button(?:$|,)/.test(currentset)) {
582 let newset = currentset.replace(/(^|,)back-button($|,)/,
583 "$1unified-back-forward-button,back-button$2")
584 this._setPersist(toolbar, currentsetResource, newset);
585 // done migrating
586 break;
590 // force the RDF to be saved
591 if (this._dirty)
592 this._dataSource.QueryInterface(Ci.nsIRDFRemoteDataSource).Flush();
594 // free up the RDF service
595 this._rdf = null;
596 this._dataSource = null;
598 // update the migration version
599 prefBranch.setIntPref("browser.migration.version", 1);
603 _getPersist: function bg__getPersist(aSource, aProperty) {
604 var target = this._dataSource.GetTarget(aSource, aProperty, true);
605 if (target instanceof Ci.nsIRDFLiteral)
606 return target.Value;
607 return null;
610 _setPersist: function bg__setPersist(aSource, aProperty, aTarget) {
611 this._dirty = true;
612 try {
613 var oldTarget = this._dataSource.GetTarget(aSource, aProperty, true);
614 if (oldTarget) {
615 if (aTarget)
616 this._dataSource.Change(aSource, aProperty, oldTarget, this._rdf.GetLiteral(aTarget));
617 else
618 this._dataSource.Unassert(aSource, aProperty, oldTarget);
620 else {
621 this._dataSource.Assert(aSource, aProperty, this._rdf.GetLiteral(aTarget), true);
624 catch(ex) {}
627 // ------------------------------
628 // public nsIBrowserGlue members
629 // ------------------------------
631 sanitize: function(aParentWindow)
633 this.Sanitizer.sanitize(aParentWindow);
636 ensurePlacesDefaultQueriesInitialized: function() {
637 const SMART_BOOKMARKS_VERSION = 1;
638 const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark";
639 const SMART_BOOKMARKS_PREF = "browser.places.smartBookmarksVersion";
641 // XXX should this be a pref? see bug #399268
642 const MAX_RESULTS = 10;
644 var prefBranch = Cc["@mozilla.org/preferences-service;1"].
645 getService(Ci.nsIPrefBranch);
647 // get current smart bookmarks version
648 // By default, if the pref is not set up, we must create Smart Bookmarks
649 var smartBookmarksCurrentVersion = 0;
650 try {
651 smartBookmarksCurrentVersion = prefBranch.getIntPref(SMART_BOOKMARKS_PREF);
652 } catch(ex) {}
654 // bail out if we don't have to create or update Smart Bookmarks
655 if (smartBookmarksCurrentVersion == -1 ||
656 smartBookmarksCurrentVersion >= SMART_BOOKMARKS_VERSION)
657 return;
659 var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
660 getService(Ci.nsINavBookmarksService);
661 var annosvc = Cc["@mozilla.org/browser/annotation-service;1"].
662 getService(Ci.nsIAnnotationService);
664 var callback = {
665 _placesBundle: Cc["@mozilla.org/intl/stringbundle;1"].
666 getService(Ci.nsIStringBundleService).
667 createBundle("chrome://browser/locale/places/places.properties"),
669 _uri: function(aSpec) {
670 return Cc["@mozilla.org/network/io-service;1"].
671 getService(Ci.nsIIOService).
672 newURI(aSpec, null, null);
675 runBatched: function() {
676 var smartBookmarks = [];
677 var bookmarksMenuIndex = 0;
678 var bookmarksToolbarIndex = 0;
680 // MOST VISITED
681 var smart = {queryId: "MostVisited", // don't change this
682 itemId: null,
683 title: this._placesBundle.GetStringFromName("mostVisitedTitle"),
684 uri: this._uri("place:queryType=" +
685 Ci.nsINavHistoryQueryOptions.QUERY_TYPE_HISTORY +
686 "&sort=" +
687 Ci.nsINavHistoryQueryOptions.SORT_BY_VISITCOUNT_DESCENDING +
688 "&maxResults=" + MAX_RESULTS),
689 parent: bmsvc.toolbarFolder,
690 position: bookmarksToolbarIndex++};
691 smartBookmarks.push(smart);
693 // RECENTLY BOOKMARKED
694 smart = {queryId: "RecentlyBookmarked", // don't change this
695 itemId: null,
696 title: this._placesBundle.GetStringFromName("recentlyBookmarkedTitle"),
697 uri: this._uri("place:folder=BOOKMARKS_MENU" +
698 "&folder=UNFILED_BOOKMARKS" +
699 "&folder=TOOLBAR" +
700 "&queryType=" +
701 Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS +
702 "&sort=" +
703 Ci.nsINavHistoryQueryOptions.SORT_BY_DATEADDED_DESCENDING +
704 "&excludeItemIfParentHasAnnotation=livemark%2FfeedURI" +
705 "&maxResults=" + MAX_RESULTS +
706 "&excludeQueries=1"),
707 parent: bmsvc.bookmarksMenuFolder,
708 position: bookmarksMenuIndex++};
709 smartBookmarks.push(smart);
711 // RECENT TAGS
712 smart = {queryId: "RecentTags", // don't change this
713 itemId: null,
714 title: this._placesBundle.GetStringFromName("recentTagsTitle"),
715 uri: this._uri("place:"+
716 "type=" +
717 Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY +
718 "&sort=" +
719 Ci.nsINavHistoryQueryOptions.SORT_BY_LASTMODIFIED_DESCENDING +
720 "&maxResults=" + MAX_RESULTS),
721 parent: bmsvc.bookmarksMenuFolder,
722 position: bookmarksMenuIndex++};
723 smartBookmarks.push(smart);
725 var smartBookmarkItemIds = annosvc.getItemsWithAnnotation(SMART_BOOKMARKS_ANNO, {});
726 // set current itemId, parent and position if Smart Bookmark exists
727 for each(var itemId in smartBookmarkItemIds) {
728 var queryId = annosvc.getItemAnnotation(itemId, SMART_BOOKMARKS_ANNO);
729 for (var i = 0; i < smartBookmarks.length; i++){
730 if (smartBookmarks[i].queryId == queryId) {
731 smartBookmarks[i].itemId = itemId;
732 smartBookmarks[i].parent = bmsvc.getFolderIdForItem(itemId);
733 smartBookmarks[i].position = bmsvc.getItemIndex(itemId);
734 // remove current item, since it will be replaced
735 bmsvc.removeItem(itemId);
736 break;
738 // We don't remove old Smart Bookmarks because user could still
739 // find them useful, or could have personalized them.
740 // Instead we remove the Smart Bookmark annotation.
741 if (i == smartBookmarks.length - 1)
742 annosvc.removeItemAnnotation(itemId, SMART_BOOKMARKS_ANNO);
746 // create smart bookmarks
747 for each(var smartBookmark in smartBookmarks) {
748 smartBookmark.itemId = bmsvc.insertBookmark(smartBookmark.parent,
749 smartBookmark.uri,
750 smartBookmark.position,
751 smartBookmark.title);
752 annosvc.setItemAnnotation(smartBookmark.itemId,
753 SMART_BOOKMARKS_ANNO, smartBookmark.queryId,
754 0, annosvc.EXPIRE_NEVER);
757 // If we are creating all Smart Bookmarks from ground up, add a
758 // separator below them in the bookmarks menu.
759 if (smartBookmarkItemIds.length == 0)
760 bmsvc.insertSeparator(bmsvc.bookmarksMenuFolder, bookmarksMenuIndex);
764 try {
765 bmsvc.runInBatchMode(callback, null);
767 catch(ex) {
768 Components.utils.reportError(ex);
770 finally {
771 prefBranch.setIntPref(SMART_BOOKMARKS_PREF, SMART_BOOKMARKS_VERSION);
772 prefBranch.QueryInterface(Ci.nsIPrefService).savePrefFile(null);
776 // for XPCOM
777 classDescription: "Firefox Browser Glue Service",
778 classID: Components.ID("{eab9012e-5f74-4cbc-b2b5-a590235513cc}"),
779 contractID: "@mozilla.org/browser/browserglue;1",
781 QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
782 Ci.nsISupportsWeakReference,
783 Ci.nsIBrowserGlue]),
785 // redefine the default factory for XPCOMUtils
786 _xpcom_factory: BrowserGlueServiceFactory,
788 // get this contractID registered for certain categories via XPCOMUtils
789 _xpcom_categories: [
790 // make BrowserGlue a startup observer
791 { category: "app-startup", service: true }
795 //module initialization
796 function NSGetModule(aCompMgr, aFileSpec) {
797 return XPCOMUtils.generateModule([BrowserGlue]);