]> git.donarmstrong.com Git - dactyl.git/blobdiff - common/modules/prefs.jsm
Import 1.0b7.1 supporting Firefox up to 8.*
[dactyl.git] / common / modules / prefs.jsm
index 981a6beb0f609ed1c751e6d284879b836f54c280..13500685dbb10318a2925b33be7ced0a96db680f 100644 (file)
@@ -16,36 +16,71 @@ defineModule("prefs", {
 }, this);
 
 var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]), {
-    SAVED: "extensions.dactyl.saved.",
+    ORIGINAL: "extensions.dactyl.original.",
     RESTORE: "extensions.dactyl.restore.",
+    SAVED: "extensions.dactyl.saved.",
     INIT: {},
 
-    init: function (branch, defaults) {
+    init: function init(branch, defaults) {
         this._prefContexts = [];
 
         this.branch = services.pref[defaults ? "getDefaultBranch" : "getBranch"](branch || "");
-        if (this.branch instanceof Ci.nsIPrefBranch2)
-            this.branch.QueryInterface(Ci.nsIPrefBranch2);
+        this.branch instanceof Ci.nsIPrefBranch2;
 
         this.defaults = defaults ? this : this.constructor(branch, true);
 
+        this.branches = memoize({
+            __proto__: this,
+            get original() this.constructor(this.ORIGINAL + this.root),
+            get restore() this.constructor(this.RESTORE + this.root),
+            get saved() this.constructor(this.SAVED + this.root),
+        });
+
         if (!defaults)
             this.restore();
 
         this._observers = {};
     },
 
-    cleanup: function cleanup() {
+    cleanup: function cleanup(reason) {
         if (this.defaults != this)
             this.defaults.cleanup();
+
         this._observers = {};
         if (this.observe) {
             this.branch.removeObserver("", this);
             this.observe.unregister();
             delete this.observe;
         }
+
+        if (this == prefs) {
+            if (~["uninstall", "disable"].indexOf(reason)) {
+                for (let name in values(this.branches.saved.getNames()))
+                    this.safeReset(name, null, true);
+
+                this.branches.original.resetBranch();
+                this.branches.saved.resetBranch();
+            }
+
+            if (reason == "uninstall" && this == prefs)
+                localPrefs.resetBranch();
+        }
     },
 
+    /**
+     * Returns the full name of this object's preference branch.
+     */
+    get root() this.branch.root,
+
+    /**
+     * Returns a new Prefs instance for the sub-branch *branch* of this
+     * branch.
+     *
+     * @param {string} branch The branch to branch to.
+     * @returns {Prefs}
+     */
+    Branch: function Branch(branch) Prefs(this.root + branch),
+
     observe: null,
     observers: {
         "nsPref:changed": function (subject, data) {
@@ -69,7 +104,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
      * @param {function(object)} callback The callback, called with the
      *    new value of the preference whenever it changes.
      */
-    watch: function (pref, callback, strong) {
+    watch: function watch(pref, callback, strong) {
         if (!this.observe) {
             util.addObserver(this);
             this.branch.addObserver("", this, false);
@@ -116,7 +151,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
             }
         };
 
-        return template.options(config.host + " Preferences", prefs.call(this));
+        return template.options(_("pref.hostPreferences", config.host), prefs.call(this));
     },
 
     /**
@@ -161,17 +196,22 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
      * @param {string} branch The branch in which to search preferences.
      *     @default ""
      */
-    getNames: function (branch) this.branch.getChildList(branch || "", { value: 0 }),
+    getNames: function getNames(branch) this.branch.getChildList(branch || "", { value: 0 }),
 
-    _checkSafe: function (name, message, value) {
+    _checkSafe: function _checkSafe(name, message, value) {
         let curval = this.get(name, null);
+
+        if (this.branches.original.get(name) == null)
+            this.branches.original.set(name, curval, true);
+
         if (arguments.length > 2 && curval === value)
             return;
+
         let defval = this.defaults.get(name, null);
-        let saved  = this.get(this.SAVED + name);
+        let saved  = this.branches.saved.get(name);
 
         if (saved == null && curval != defval || saved != null && curval != saved) {
-            let msg = "Warning: setting preference " + name + ", but it's changed from its default value.";
+            let msg = _("pref.safeSet.warnChanged", name);
             if (message)
                 msg = template.linkifyHelp(msg + " " + message);
             util.dactyl.warn(msg);
@@ -184,11 +224,13 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
      *
      * @param {string} name The preference name.
      * @param {value} value The new preference value.
+     * @param {boolean} silent Ignore errors.
      */
-    safeReset: function (name, message) {
+    safeReset: function safeReset(name, message, silent) {
         this._checkSafe(name, message);
-        this.reset(name);
-        this.reset(this.SAVED + name);
+        this.set(name, this.branches.original.get(name), silent);
+        this.branches.original.reset(name);
+        this.branches.saved.reset(name);
     },
 
     /**
@@ -198,10 +240,10 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
      * @param {string} name The preference name.
      * @param {value} value The new preference value.
      */
-    safeSet: function (name, value, message, skipSave) {
+    safeSet: function safeSet(name, value, message, skipSave) {
         this._checkSafe(name, message, value);
         this.set(name, value);
-        this[skipSave ? "reset" : "set"](this.SAVED + name, value);
+        this.branches.saved[skipSave ? "reset" : "set"](name, value);
     },
 
     /**
@@ -209,40 +251,45 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
      *
      * @param {string} name The preference name.
      * @param {value} value The new preference value.
+     * @param {boolean} silent Ignore errors.
      */
-    set: function (name, value) {
-        if (this._prefContexts.length) {
-            let val = this.get(name, null);
-            if (val != null)
-                this._prefContexts[this._prefContexts.length - 1][name] = val;
-        }
+    set: function set(name, value, silent) {
+        if (this._prefContexts.length)
+            this._prefContexts[this._prefContexts.length - 1][name] = this.get(name, null);
 
         function assertType(needType)
             util.assert(type === Ci.nsIPrefBranch.PREF_INVALID || type === needType,
                 type === Ci.nsIPrefBranch.PREF_INT
-                                ? "E521: Number required after =: " + name + "=" + value
-                                : "E474: Invalid argument: " + name + "=" + value);
+                                ? /*L*/"E521: Number required after =: " + name + "=" + value
+                                : /*L*/"E474: Invalid argument: " + name + "=" + value);
 
         let type = this.branch.getPrefType(name);
-        switch (typeof value) {
-        case "string":
-            assertType(Ci.nsIPrefBranch.PREF_STRING);
-
-            this.branch.setComplexValue(name, Ci.nsISupportsString, services.String(value));
-            break;
-        case "number":
-            assertType(Ci.nsIPrefBranch.PREF_INT);
-
-            this.branch.setIntPref(name, value);
-            break;
-        case "boolean":
-            assertType(Ci.nsIPrefBranch.PREF_BOOL);
-
-            this.branch.setBoolPref(name, value);
-            break;
-        default:
-            throw FailedAssertion("Unknown preference type: " + typeof value + " (" + name + "=" + value + ")");
+        try {
+            switch (typeof value) {
+            case "string":
+                assertType(Ci.nsIPrefBranch.PREF_STRING);
+
+                this.branch.setComplexValue(name, Ci.nsISupportsString, services.String(value));
+                break;
+            case "number":
+                assertType(Ci.nsIPrefBranch.PREF_INT);
+
+                this.branch.setIntPref(name, value);
+                break;
+            case "boolean":
+                assertType(Ci.nsIPrefBranch.PREF_BOOL);
+
+                this.branch.setBoolPref(name, value);
+                break;
+            default:
+                if (value == null && this != this.defaults)
+                    this.reset(name);
+                else
+                    throw FailedAssertion("Unknown preference type: " + typeof value + " (" + name + "=" + value + ")");
+            }
         }
+        catch (e if silent) {}
+        return value;
     },
 
     /**
@@ -251,7 +298,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
      *
      * @param {string} name The preference to save.
      */
-    save: function (name) {
+    save: function save(name) {
         let val = this.get(name);
         this.set(this.RESTORE + name, val);
         this.safeSet(name, val);
@@ -263,7 +310,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
      * @param {string} branch The branch from which to restore
      *      preferences. @optional
      */
-    restore: function (branch) {
+    restore: function restore(branch) {
         this.getNames(this.RESTORE + (branch || "")).forEach(function (pref) {
             this.safeSet(pref.substr(this.RESTORE.length), this.get(pref), null, true);
             this.reset(pref);
@@ -275,21 +322,30 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
      *
      * @param {string} name The preference name.
      */
-    reset: function (name) {
+    reset: function reset(name) {
         try {
             this.branch.clearUserPref(name);
         }
         catch (e) {} // ignore - thrown if not a user set value
     },
 
+    /**
+     * Resets the preference branch *branch* to its default value.
+     *
+     * @param {string} branch The preference name. @optional
+     */
+    resetBranch: function resetBranch(branch) {
+        this.getNames(branch).forEach(this.closure.reset);
+    },
+
     /**
      * Toggles the value of the boolean preference *name*.
      *
      * @param {string} name The preference name.
      */
-    toggle: function (name) {
+    toggle: function toggle(name) {
         util.assert(this.branch.getPrefType(name) === Ci.nsIPrefBranch.PREF_BOOL,
-                    _("error.trailing", name + "!"));
+                    _("error.trailingCharacters", name + "!"));
         this.set(name, !this.get(name));
     },
 
@@ -298,7 +354,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
      *
      * @see #withContext
      */
-    pushContext: function () {
+    pushContext: function pushContext() {
         this._prefContexts.push({});
     },
 
@@ -307,7 +363,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
      *
      * @see #withContext
      */
-    popContext: function () {
+    popContext: function popContext() {
         for (let [k, v] in Iterator(this._prefContexts.pop()))
             this.set(k, v);
     },
@@ -322,7 +378,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
      * @see #pushContext
      * @see #popContext
      */
-    withContext: function (func, self) {
+    withContext: function withContext(func, self) {
         try {
             this.pushContext();
             return func.call(self);
@@ -333,7 +389,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
     }
 }, {
 }, {
-    completion: function (dactyl, modules) {
+    completion: function init_completion(dactyl, modules) {
         modules.completion.preference = function preference(context) {
             context.anchored = false;
             context.title = [config.host + " Preference", "Value"];
@@ -341,7 +397,7 @@ var Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference])
             context.completions = prefs.getNames();
         };
     },
-    javascript: function (dactyl, modules) {
+    javascript: function init_javascript(dactyl, modules) {
         modules.JavaScript.setCompleter([this.get, this.safeSet, this.set, this.reset, this.toggle],
                 [function (context) (context.anchored=false, this.getNames().map(function (pref) [pref, ""]))]);
     }