1/* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5var EXPORTED_SYMBOLS = ["CalStartupService"]; 6 7var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); 8var { FileSource, L10nRegistry } = ChromeUtils.import("resource://gre/modules/L10nRegistry.jsm"); 9 10/** 11 * Helper function to asynchronously call a certain method on the objects passed 12 * in 'services' in order (i.e wait until the first completes before calling the 13 * second 14 * 15 * @param method The method name to call. Usually startup/shutdown. 16 * @param services The array of service objects to call on. 17 */ 18function callOrderedServices(method, services) { 19 let service = services.shift(); 20 if (service) { 21 service[method]({ 22 onResult() { 23 callOrderedServices(method, services); 24 }, 25 }); 26 } 27} 28 29function CalStartupService() { 30 this.wrappedJSObject = this; 31 this.setupObservers(); 32} 33 34CalStartupService.prototype = { 35 QueryInterface: ChromeUtils.generateQI(["nsIObserver"]), 36 classID: Components.ID("{2547331f-34c0-4a4b-b93c-b503538ba6d6}"), 37 38 // Startup Service Methods 39 40 /** 41 * Sets up the needed observers for noticing startup/shutdown 42 */ 43 setupObservers() { 44 Services.obs.addObserver(this, "profile-after-change"); 45 Services.obs.addObserver(this, "profile-before-change"); 46 Services.obs.addObserver(this, "xpcom-shutdown"); 47 }, 48 49 started: false, 50 51 /** 52 * Gets the startup order of services. This is an array of service objects 53 * that should be called in order at startup. 54 * 55 * @return The startup order as an array. 56 */ 57 getStartupOrder() { 58 let self = this; 59 let tzService = Cc["@mozilla.org/calendar/timezone-service;1"] 60 .getService(Ci.calITimezoneService) 61 .QueryInterface(Ci.calIStartupService); 62 let calMgr = Cc["@mozilla.org/calendar/manager;1"] 63 .getService(Ci.calICalendarManager) 64 .QueryInterface(Ci.calIStartupService); 65 66 // Localization service 67 let locales = { 68 startup(aCompleteListener) { 69 let packaged = Services.locale.packagedLocales; 70 let fileSrc = new FileSource( 71 "calendar", 72 packaged, 73 "resource:///chrome/{locale}/locale/{locale}/calendar/" 74 ); 75 L10nRegistry.registerSources([fileSrc]); 76 aCompleteListener.onResult(null, Cr.NS_OK); 77 }, 78 shutdown(aCompleteListener) { 79 aCompleteListener.onResult(null, Cr.NS_OK); 80 }, 81 }; 82 83 // Notification object 84 let notify = { 85 startup(aCompleteListener) { 86 self.started = true; 87 Services.obs.notifyObservers(null, "calendar-startup-done"); 88 aCompleteListener.onResult(null, Cr.NS_OK); 89 }, 90 shutdown(aCompleteListener) { 91 // Argh, it would have all been so pretty! Since we just reverse 92 // the array, the shutdown notification would happen before the 93 // other shutdown calls. For lack of pretty code, I'm 94 // leaving this out! Users can still listen to xpcom-shutdown. 95 self.started = false; 96 aCompleteListener.onResult(null, Cr.NS_OK); 97 }, 98 }; 99 100 // We need to spin up the timezone service before the calendar manager 101 // to ensure we have the timezones initialized. Make sure "notify" is 102 // last in this array! 103 return [locales, tzService, calMgr, notify]; 104 }, 105 106 /** 107 * Observer notification callback 108 */ 109 observe(aSubject, aTopic, aData) { 110 switch (aTopic) { 111 case "profile-after-change": 112 callOrderedServices("startup", this.getStartupOrder()); 113 break; 114 case "profile-before-change": 115 callOrderedServices("shutdown", this.getStartupOrder().reverse()); 116 break; 117 case "xpcom-shutdown": 118 Services.obs.removeObserver(this, "profile-after-change"); 119 Services.obs.removeObserver(this, "profile-before-change"); 120 Services.obs.removeObserver(this, "xpcom-shutdown"); 121 break; 122 } 123 }, 124}; 125