Bug 470455 - test_database_sync_embed_visits.js leaks, r=sdwilsh
[wine-gecko.git] / toolkit / components / url-classifier / content / moz / preferences.js
blobbf85ca3e0344926e8955fde42780fb4728148a25
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 Google Safe Browsing.
16 # The Initial Developer of the Original Code is Google Inc.
17 # Portions created by the Initial Developer are Copyright (C) 2006
18 # the Initial Developer. All Rights Reserved.
20 # Contributor(s):
21 #   Fritz Schneider <fritz@google.com> (original author)
23 # Alternatively, the contents of this file may be used under the terms of
24 # either the GNU General Public License Version 2 or later (the "GPL"), or
25 # the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 # in which case the provisions of the GPL or the LGPL are applicable instead
27 # of those above. If you wish to allow use of your version of this file only
28 # under the terms of either the GPL or the LGPL, and not to allow others to
29 # use your version of this file under the terms of the MPL, indicate your
30 # decision by deleting the provisions above and replace them with the notice
31 # and other provisions required by the GPL or the LGPL. If you do not delete
32 # the provisions above, a recipient may use your version of this file under
33 # the terms of any one of the MPL, the GPL or the LGPL.
35 # ***** END LICENSE BLOCK *****
38 // Class for manipulating preferences. Aside from wrapping the pref
39 // service, useful functionality includes:
41 // - abstracting prefobserving so that you can observe preferences
42 //   without implementing nsIObserver 
43 // 
44 // - getters that return a default value when the pref doesn't exist 
45 //   (instead of throwing)
46 // 
47 // - get-and-set getters
49 // Example:
50 // 
51 // var p = new PROT_Preferences();
52 // dump(p.getPref("some-true-pref"));     // shows true
53 // dump(p.getPref("no-such-pref", true)); // shows true   
54 // dump(p.getPref("no-such-pref", null)); // shows null
56 // function observe(prefThatChanged) {
57 //   dump("Pref changed: " + prefThatChanged);
58 // };
60 // p.addObserver("somepref", observe);
61 // p.setPref("somepref", true);            // dumps
62 // p.removeObserver("somepref", observe);
64 // TODO: should probably have the prefobserver pass in the new and old
65 //       values
67 // TODO(tc): Maybe remove this class and just call natively since we're no
68 //           longer an extension.
70 /**
71  * A class that wraps the preferences service.
72  *
73  * @param opt_startPoint        A starting point on the prefs tree to resolve 
74  *                              names passed to setPref and getPref.
75  *
76  * @param opt_useDefaultPranch  Set to true to work against the default 
77  *                              preferences tree instead of the profile one.
78  *
79  * @constructor
80  */
81 function G_Preferences(opt_startPoint, opt_getDefaultBranch) {
82   this.debugZone = "prefs";
83   this.observers_ = {};
84   this.getDefaultBranch_ = !!opt_getDefaultBranch;
86   this.startPoint_ = opt_startPoint || null;
89 G_Preferences.setterMap_ = { "string": "setCharPref",
90                              "boolean": "setBoolPref",
91                              "number": "setIntPref" };
93 G_Preferences.getterMap_ = {};
94 G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_STRING] = "getCharPref";
95 G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_BOOL] = "getBoolPref";
96 G_Preferences.getterMap_[Ci.nsIPrefBranch.PREF_INT] = "getIntPref";
98 G_Preferences.prototype.__defineGetter__('prefs_', function() {
99   var prefs;
100   var prefSvc = Cc["@mozilla.org/preferences-service;1"]
101                   .getService(Ci.nsIPrefService);
103   if (this.getDefaultBranch_) {
104     prefs = prefSvc.getDefaultBranch(this.startPoint_);
105   } else {
106     prefs = prefSvc.getBranch(this.startPoint_);
107   }
109   // QI to prefs in case we want to add observers
110   prefs.QueryInterface(Ci.nsIPrefBranchInternal);
111   return prefs;
115  * Stores a key/value in a user preference. Valid types for val are string,
116  * boolean, and number. Complex values are not yet supported (but feel free to
117  * add them!).
118  */
119 G_Preferences.prototype.setPref = function(key, val) {
120   var datatype = typeof(val);
122   if (datatype == "number" && (val % 1 != 0)) {
123     throw new Error("Cannot store non-integer numbers in preferences.");
124   }
126   var meth = G_Preferences.setterMap_[datatype];
128   if (!meth) {
129     throw new Error("Pref datatype {" + datatype + "} not supported.");
130   }
132   return this.prefs_[meth](key, val);
136  * Retrieves a user preference. Valid types for the value are the same as for
137  * setPref. If the preference is not found, opt_default will be returned 
138  * instead.
139  */
140 G_Preferences.prototype.getPref = function(key, opt_default) {
141   var type = this.prefs_.getPrefType(key);
143   // zero means that the specified pref didn't exist
144   if (type == Ci.nsIPrefBranch.PREF_INVALID) {
145     return opt_default;
146   }
148   var meth = G_Preferences.getterMap_[type];
150   if (!meth) {
151     throw new Error("Pref datatype {" + type + "} not supported.");
152   }
154   // If a pref has been cleared, it will have a valid type but won't
155   // be gettable, so this will throw.
156   try {
157     return this.prefs_[meth](key);
158   } catch(e) {
159     return opt_default;
160   }
164  * Delete a preference. 
166  * @param which Name of preference to obliterate
167  */
168 G_Preferences.prototype.clearPref = function(which) {
169   try {
170     // This throws if the pref doesn't exist, which is fine because a 
171     // non-existent pref is cleared
172     this.prefs_.clearUserPref(which);
173   } catch(e) {}
177  * Add an observer for a given pref.
179  * @param which String containing the pref to listen to
180  * @param callback Function to be called when the pref changes. This
181  *                 function will receive a single argument, a string 
182  *                 holding the preference name that changed
183  */
184 G_Preferences.prototype.addObserver = function(which, callback) {
185   // Need to store the observer we create so we can eventually unregister it
186   if (!this.observers_[which])
187     this.observers_[which] = { callbacks: [], observers: [] };
189   /* only add an observer if the callback hasn't been registered yet */
190   if (this.observers_[which].callbacks.indexOf(callback) == -1) {
191     var observer = new G_PreferenceObserver(callback);
192     this.observers_[which].callbacks.push(callback);
193     this.observers_[which].observers.push(observer);
194     this.prefs_.addObserver(which, observer, false /* strong reference */);
195   }
199  * Remove an observer for a given pref.
201  * @param which String containing the pref to stop listening to
202  * @param callback Function to remove as an observer
203  */
204 G_Preferences.prototype.removeObserver = function(which, callback) {
205   var ix = this.observers_[which].callbacks.indexOf(callback);
206   G_Assert(this, ix != -1, "Tried to unregister a nonexistant observer"); 
207   this.observers_[which].callbacks.splice(ix, 1);
208   var observer = this.observers_[which].observers.splice(ix, 1)[0];
209   this.prefs_.removeObserver(which, observer);
213  * Remove all preference observers registered through this object.
214  */
215 G_Preferences.prototype.removeAllObservers = function() {
216   for (var which in this.observers_) {
217     for each (var observer in this.observers_[which].observers) {
218       this.prefs_.removeObserver(which, observer);
219     }
220   }
221   this.observers_ = {};
225  * Helper class that knows how to observe preference changes and
226  * invoke a callback when they do
228  * @constructor
229  * @param callback Function to call when the preference changes
230  */
231 function G_PreferenceObserver(callback) {
232   this.debugZone = "prefobserver";
233   this.callback_ = callback;
237  * Invoked by the pref system when a preference changes. Passes the
238  * message along to the callback.
240  * @param subject The nsIPrefBranch that changed
241  * @param topic String "nsPref:changed" (aka 
242  *              NS_PREFBRANCH_PREFCHANGE_OBSERVER_ID -- but where does it
243  *              live???)
244  * @param data Name of the pref that changed
245  */
246 G_PreferenceObserver.prototype.observe = function(subject, topic, data) {
247   G_Debug(this, "Observed pref change: " + data);
248   this.callback_(data);
252  * XPCOM cruft
254  * @param iid Interface id of the interface the caller wants
255  */
256 G_PreferenceObserver.prototype.QueryInterface = function(iid) {
257   if (iid.equals(Ci.nsISupports) || 
258       iid.equals(Ci.nsIObserver) ||
259       iid.equals(Ci.nsISupportsWeakReference))
260     return this;
261   throw Components.results.NS_ERROR_NO_INTERFACE;
264 #ifdef DEBUG
265 // UNITTESTS
266 function TEST_G_Preferences() {
267   if (G_GDEBUG) {
268     var z = "preferences UNITTEST";
269     G_debugService.enableZone(z);
270     G_Debug(z, "Starting");
272     var p = new G_Preferences();
273     
274     var testPref = "test-preferences-unittest";
275     var noSuchPref = "test-preferences-unittest-aypabtu";
276     
277     // Used to test observing
278     var observeCount = 0;
279     function observe(prefChanged) {
280       G_Assert(z, prefChanged == testPref, "observer broken");
281       observeCount++;
282     };
284     // Test setting, getting, and observing
285     p.addObserver(testPref, observe);
286     p.setPref(testPref, true);
287     G_Assert(z, p.getPref(testPref), "get or set broken");
288     G_Assert(z, observeCount == 1, "observer adding not working");
290     p.removeObserver(testPref, observe);
292     p.setPref(testPref, false);
293     G_Assert(z, observeCount == 1, "observer removal not working");
294     G_Assert(z, !p.getPref(testPref), "get broken");
295     
296     // Remember to clean up the prefs we've set, and test removing prefs 
297     // while we're at it
298     p.clearPref(noSuchPref);
299     G_Assert(z, !p.getPref(noSuchPref, false), "clear broken");
300     
301     p.clearPref(testPref);
302     
303     G_Debug(z, "PASSED");
304   }
306 #endif