Dev : Using preferences: Difference between revisions

From MozillaZine Knowledge Base
Jump to navigationJump to search
m (s/depreciated/deprecated/)
m (cat redirect)
 
(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 &ldquo;internal&rdquo;, but is very useful because it allows you to set up prefs observers &mdash; 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 &mdash; 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 &mdash; <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> &mdash; 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> &mdash; 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>]] &mdash; 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 &ldquo;special&rdquo; 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 &mdash; '''current''' and '''default'''. That means there are two &ldquo;pref trees&rdquo; &mdash; current and default, &mdash; 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 &ldquo;current&rdquo; 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 &ldquo;current&rdquo; tree, the ''get'' method checks the default tree.
#If there's a value of expected type in the &ldquo;default&rdquo; 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 &ldquo;default&rdquo; 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> &mdash; 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 &ldquo;listen&rdquo; 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] &mdash; describes preferences system from user's / administrator's POV.
**[http://www.xulplanet.com/tutorials/xulqa/q_prefs.html XUL Planet's article on preferences] &mdash; 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]]

Latest revision as of 21:31, 22 January 2007

Moved here