|
|
(25 intermediate revisions by 6 users not shown) |
Line 1: |
Line 1: |
| {{extdev}}
| | Moved [http://developer.mozilla.org/en/docs/Code_snippets:Preferences here] |
|
| |
|
| This article is about using Mozilla Preferences system. Information here applies to the Mozilla Suite, Firefox, Thunderbird and possibly other Mozilla-based applications. Intended audience is Mozilla extension developers who wish to learn details about using preferences in Mozilla. <!-- Read about preferences in general [[??? | here]]. -->
| | [[Category:Redirects]] |
| | |
| If you haven't yet, read other documents about Mozilla preferences on XUL Planet and on mozilla.org (links below in [[#Resources|Resources section]]).
| |
| | |
| ==XPCOM interfaces for preferences system==
| |
| Mozilla exposes its preferences system through a few XPCOM interfaces. Look in the [[#Resources|Resources section]] below for the link to list of preferences-related interfaces.
| |
| | |
| Three most used interfaces are <tt>nsIPrefService</tt>, <tt>nsIPrefBranch</tt> and <tt>nsIPrefBranchInternal</tt>. First two are frozen and will not change, last one is “internal”, but is very useful because it allows you to set up prefs observers — see below for an example.
| |
| | |
| It's worth noting that there also is an <tt>nsIPref</tt> interface. Despite it being used in some places, it is '''deprecated''' and should not be used.
| |
| | |
| Preferences service is instantiated exactly as any other service. (See [http://xulplanet.com/references/xpcomref/creatingcomps.html Creating XPCOM Components] document at XUL Planet for details.) To get an <tt>nsIPrefBranch</tt>, either QI the pref service (that will give you the root branch) or call <tt>nsIPrefService.getBranch()</tt> to get a sub-branch.
| |
| | |
| Here are two examples:
| |
| <pre>
| |
| // Get the root branch
| |
| var prefs = Components.classes["@mozilla.org/preferences-service;1"].
| |
| getService(Components.interfaces.nsIPrefBranch);
| |
| </pre>
| |
| <pre>
| |
| // Get the "extensions.myext." branch
| |
| var prefs = Components.classes["@mozilla.org/preferences-service;1"].
| |
| getService(Components.interfaces.nsIPrefService);
| |
| prefs = prefs.getBranch("extensions.myext.");
| |
| </pre>
| |
| | |
| ==Simple types==
| |
| There are three types of preferences: '''string''', '''integer''' and '''boolean'''. Each entry in preferences database (prefs.js) has one of those types. There are six methods of <tt>nsIPrefBranch</tt> that read and write them: <tt>getBoolPref</tt>, <tt>setBoolPref</tt>, <tt>getCharPref</tt>, <tt>setCharPref</tt>, <tt>getIntPref</tt> and <tt>setIntPref</tt>. Using them is as easy as:
| |
| <pre>
| |
| // prefs is an nsIPrefBranch.
| |
| // Look in the above section for examples of getting one.
| |
| var value = prefs.getBoolPref("accessibility.typeaheadfind"); // get a pref
| |
| prefs.setBoolPref("accessibility.typeaheadfind", !value); // set a pref
| |
| </pre>
| |
| | |
| ==Complex types==
| |
| As noted in previous section, each entry in prefs database (prefs.js) must have a string, an integer or a boolean value. However, there is a concept of '''complex types''', which makes it easier for developers to save and load <tt>nsILocalFile</tt> and <tt>nsISupportsString</tt> objects in preferences (as strings — note that from the preferences system's POV, complex values have a <tt>nsIPrefBranch.PREF_STRING</tt> type.)
| |
| | |
| There are two <tt>nsIPrefBranch</tt> methods implementing the concept — <tt>setComplexValue</tt> and <tt>getComplexValue</tt>. You can look up their implementation in [http://lxr.mozilla.org/mozilla/source/modules/libpref/src/nsPrefBranch.cpp#221 nsPrefBranch.cpp]. Here is the IDL definition:
| |
| <pre>void getComplexValue(in string aPrefName, in nsIIDRef aType,
| |
| [iid_is(aType), retval] out nsQIResult aValue);
| |
| | |
| void setComplexValue(in string aPrefName, in nsIIDRef aType, in nsISupports aValue);</pre>
| |
| | |
| As you can see, both of them take <tt>aType</tt> parameter. It can have the following values <small>(to be precise, you should pass <tt>Components.interfaces.nsIWhatever</tt> instead of just <tt>nsIWhatever</tt>, which is undefined):</small>
| |
| *<tt>[[#nsISupportsString|nsISupportsString]]</tt> — used to handle unicode strings in preferences. Use this when the preference value may contain non-ASCII characters (for example, user's name).
| |
| *<tt>[[#nsIPrefLocalizedString|nsIPrefLocalizedString]]</tt> — almost same as <tt>nsISupportsString</tt>, but it is handled differently in <tt>getComplexValue</tt> when there's no user value for given preference, see below for details.
| |
| *[[Dev : Extensions : Example Code : File IO|<tt>nsILocalFile</tt> and <tt>nsIRelativeFilePref</tt>]] — store paths in preferences. <tt>nsILocalFile</tt> is used to store absolute paths, while <tt>nsIRelativeFilePref</tt> is used to store paths relative to one of “special” directories, like the profile folder.
| |
| | |
| ===nsISupportsString===
| |
| As noted above, this is used to handle unicode strings in preferences. Example:
| |
| <pre>
| |
| // prefs is an nsIPrefBranch
| |
| | |
| // Example 1: getting unicode value
| |
| var value = prefs.getComplexValue("preference.with.non.ascii.value",
| |
| Components.interfaces.nsISupportsString).data;
| |
| | |
| // Example 2: setting unicode value
| |
| var str = Components.classes["@mozilla.org/supports-string;1"]
| |
| .createInstance(Components.interfaces.nsISupportsString);
| |
| str.data = "some non-ascii text";
| |
| prefs.setComplexValue("preference.with.non.ascii.value",
| |
| Components.interfaces.nsISupportsString, str);
| |
| </pre>
| |
| | |
| ===nsIPrefLocalizedString===
| |
| Another complex type supported by Mozilla is <tt>nsIPrefLocalizedString</tt>. It is similar to <tt>nsISupportsString</tt>, the only difference is that when there is no user value, <tt>getComplexValue</tt> gets the default value from a locale file (thus making the default value localizable).
| |
| | |
| It's easier to explain this on example. Let's say you want to make the default value for <tt>extensions.myext.welcomemessage</tt> preference localizable. You should do the following:
| |
| <ol>
| |
| <li>Add this line to some <tt>.properties</tt> file (for all of your locales), say to <tt>chrome://myext/locale/defaults.properties</tt>:
| |
| <pre>extensions.myext.welcomemessage=Localized default value</pre></li>
| |
| | |
| <li>Add the default value for <tt>extensions.myext.welcomemessage</tt>, pointing to that properties file, by adding the following line to your file with ''default preferences'' (see below).
| |
| <pre>pref("extensions.myext.welcomemessage", "chrome://myext/locale/defaults.properties");</pre>
| |
| </li>
| |
| | |
| <li>Read the preference with <tt>getComplexValue</tt>, passing <tt>nsIPrefLocalizedString</tt> as <tt>aType</tt>:
| |
| <pre>
| |
| var prefs = Components.classes["@mozilla.org/preferences-service;1"].
| |
| getService(Components.interfaces.nsIPrefService);
| |
| var branch = prefs.getBranch("extensions.myext.");
| |
| var value = branch.getComplexValue("welcomemessage",
| |
| Components.interfaces.nsIPrefLocalizedString).data;
| |
| </pre></li>
| |
| </ol>
| |
| | |
| The code in step 3 will read the default value from <tt>chrome://myext/locale/defaults.properties</tt> when no user value is set, and will behave exactly the same as if <tt>nsISupportsString</tt> was passed as <tt>aType</tt> otherwise.
| |
| | |
| ===nsILocalFile and nsIRelativeFilePref===
| |
| <!-- Leave this section to have nice TOC -->
| |
| Please see the [[Dev : Extensions : Example Code : File IO|File IO article]] for details on <tt>nsILocalFile</tt> and <tt>nsIRelativeFilePref</tt>.
| |
| | |
| ==Default preferences==
| |
| <!-- someone should reword this section -->
| |
| Each preference may have up to two values — '''current''' and '''default'''. That means there are two “pref trees” — current and default, — and each of them may or may not have a value for preference in question.
| |
| | |
| You can see the list of preferences in [[about:config]] (where available). Preferences that have user value are bold, those that don't have a user value are printed in normal font.
| |
| | |
| ===What effect do default preferences have on various ''get'' methods===
| |
| When one of ''get'' methods of <tt>nsIPrefBranch</tt> (assuming it's a branch of the tree with current values) is called, it does the following:
| |
| #Checks whether the “current” tree has a value for the pref and whether the pref is locked.
| |
| #If there's a value of correct type (f.e. <tt>getBoolValue</tt> expects a value of type <tt>nsIPrefBranch.PREF_BOOL</tt>), and the preference is not locked, the method returns that value.
| |
| #If there's a value of incorrect type and the pref is not locked, an exception is thrown (<tt>NS_ERROR_UNEXPECTED</tt>)
| |
| #If the preference is locked or if there is no value for that preference in “current” tree, the ''get'' method checks the default tree.
| |
| #If there's a value of expected type in the “default” tree, it is returned (with the only exception, <tt>getComplexValue</tt> with <tt>aType</tt> parameter = <tt>nsIPrefLocalizedString</tt>, [[#nsIPrefLocalizedString|described above]])
| |
| #Otherwise an exception is thrown (<tt>NS_ERROR_UNEXPECTED</tt>).
| |
| | |
| If the branch is from the “default” tree, the ''get'' method doesn't check the tree with current values at all.
| |
| | |
| <small>(This is not exactly how it's coded in <tt>libpref</tt>, but it's equivalent)</small>
| |
| | |
| ===Where are the default values read from===
| |
| *All Mozilla-based applications read <tt>(application directory)/defaults/pref/*.js</tt> <!-- (xxx are non-.js files read?) -->.
| |
| * In addition to that, the recent versions of new toolkit applications (Firefox 1.0, Thunderbird 1.0 and the like; '''not''' Mozilla Suite) read files listed in <tt>(profile folder)/defaults.ini</tt> — usually <tt>(profile folder)/extensions/{guid}/defaults/preferences/</tt>
| |
| | |
| ===How to install extension's defaults files===
| |
| For Mozilla, copy them to <tt>(appdir)/defaults/pref</tt> in your [[Install.js|install script]].
| |
| | |
| For Firefox/Thunderbird, just put them in <tt>myext.xpi/defaults/preferences/</tt>. They will be copied and registered in <tt>defaults.ini</tt> automatically.
| |
| | |
| ==Using preferences observers==
| |
| You can use <tt>nsIPrefBranchInternal</tt> interface to “listen” to changes to preferences in a certain branch. Here's an example (note, this code hasn't actually been tested, so it may contain typos and other errors):
| |
| | |
| <pre>var myPrefObserver =
| |
| {
| |
| register: function()
| |
| {
| |
| var prefService = Components.classes["@mozilla.org/preferences-service;1"].
| |
| getService(Components.interfaces.nsIPrefService);
| |
| this._branch = prefService.getBranch("extensions.myextension.");
| |
| | |
| var pbi = this._branch.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
| |
| pbi.addObserver("", this, false);
| |
| },
| |
| | |
| unregister: function()
| |
| {
| |
| if(!this._branch) return;
| |
| | |
| var pbi = this._branch.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
| |
| pbi.removeObserver("", this);
| |
| },
| |
| | |
| observe: function(aSubject, aTopic, aData)
| |
| {
| |
| if(aTopic != "nsPref:changed") return;
| |
| // aSubject is the nsIPrefBranch we're observing
| |
| switch (aData) {
| |
| case "pref1":
| |
| // extensions.myextension.pref1 was changed
| |
| break;
| |
| case "pref2":
| |
| // extensions.myextension.pref2 was changed
| |
| break;
| |
| }
| |
| }
| |
| }
| |
| myPrefListener.register();
| |
| </pre>
| |
| | |
| ==Resources==
| |
| *Other documentation on preferences
| |
| **[http://www.mozilla.org/catalog/end-user/customizing/briefprefs.html A Brief Guide to Mozilla Preferences] — describes preferences system from user's / administrator's POV.
| |
| **[http://www.xulplanet.com/tutorials/xulqa/q_prefs.html XUL Planet's article on preferences] — an explanation of the preferences system with simple examples. A must read.
| |
| *Mozilla XPCOM interfaces of the preferences system.
| |
| **[http://xulplanet.com/references/xpcomref/group_Preferences.html#Preferences Complete list]
| |
| **Most used interfaces (these are frozen and will not change): [http://xulplanet.com/references/xpcomref/ifaces/nsIPrefBranch.html <tt>nsIPrefBranch</tt>] and [http://xulplanet.com/references/xpcomref/ifaces/nsIPrefService.html <tt>nsIPrefService</tt>]
| |
| *[http://lxr.mozilla.org/mozilla/source/modules/libpref/ LXR pages for <tt>libpref</tt>], the module implementing preferences system.
| |
| | |
| [[Category:Development|Using preferences]] [[Category:Example code|Using preferences]]
| |