Dev : Using preferences: Difference between revisions

From MozillaZine Knowledge Base
Jump to navigationJump to search
m (recategorizing + restyling)
m (cat redirect)
 
(24 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 <code>nsIPrefService</code>, <code>nsIPrefBranch</code> and <code>nsIPrefBranchInternal</code>. 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 <code>nsIPref</code> 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 <code>nsIPrefBranch</code>, either QI the pref service (that will give you the root branch) or call <code>nsIPrefService.getBranch()</code> 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 <code>nsIPrefBranch</code> that read and write them: <code>getBoolPref</code>, <code>setBoolPref</code>, <code>getCharPref</code>, <code>setCharPref</code>, <code>getIntPref</code> and <code>setIntPref</code>. 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 <code>nsILocalFile</code> and <code>nsISupportsString</code> objects in preferences (as strings &mdash; note that from the preferences system's POV, complex values have a <code>nsIPrefBranch.PREF_STRING</code> type.)
 
There are two <code>nsIPrefBranch</code> methods implementing the concept &mdash; <code>setComplexValue</code> and <code>getComplexValue</code>. 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 <code>aType</code> parameter. It can have the following values <small>(to be precise, you should pass <code>Components.interfaces.nsIWhatever</code> instead of just <code>nsIWhatever</code>, which is undefined):</small>
*<code>[[#nsISupportsString|nsISupportsString]]</code> &mdash; used to handle unicode strings in preferences. Use this when the preference value may contain non-ASCII characters (for example, user's name).
*<code>[[#nsIPrefLocalizedString|nsIPrefLocalizedString]]</code> &mdash; almost same as <code>nsISupportsString</code>, but it is handled differently in <code>getComplexValue</code> when there's no user value for given preference, see below for details.
*[[Dev : Extensions : Example Code : File IO|<code>nsILocalFile</code> and <code>nsIRelativeFilePref</code>]] &mdash; store paths in preferences. <code>nsILocalFile</code> is used to store absolute paths, while <code>nsIRelativeFilePref</code> 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 <code>nsIPrefLocalizedString</code>. It is similar to <code>nsISupportsString</code>, the only difference is that when there is no user value, <code>getComplexValue</code> 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 <code>extensions.myext.welcomemessage</code> preference localizable. You should do the following:
<ol>
<li>Add this line to some <code>.properties</code> file (for all of your locales), say to <code>chrome://myext/locale/defaults.properties</code>:
<pre>extensions.myext.welcomemessage=Localized default value</pre></li>
 
<li>Add the default value for <code>extensions.myext.welcomemessage</code>, 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 <code>getComplexValue</code>, passing <code>nsIPrefLocalizedString</code> as <code>aType</code>:
<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 <code>chrome://myext/locale/defaults.properties</code> when no user value is set, and will behave exactly the same as if <code>nsISupportsString</code> was passed as <code>aType</code> 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 <code>nsILocalFile</code> and <code>nsIRelativeFilePref</code>.
 
==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 <code>nsIPrefBranch</code> (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. <code>getBoolValue</code> expects a value of type <code>nsIPrefBranch.PREF_BOOL</code>), 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 (<code>NS_ERROR_UNEXPECTED</code>)
#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, <code>getComplexValue</code> with <code>aType</code> parameter = <code>nsIPrefLocalizedString</code>, [[#nsIPrefLocalizedString|described above]])
#Otherwise an exception is thrown (<code>NS_ERROR_UNEXPECTED</code>).
 
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 <code>libpref</code>, but it's equivalent)</small>
 
===Where are the default values read from===
*All Mozilla-based applications read <code>(application directory)/defaults/pref/*.js</code> <!-- (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 <code>(profile folder)/defaults.ini</code> &mdash; usually <code>(profile folder)/extensions/{guid}/defaults/preferences/</code>
 
===How to install extension's defaults files===
For Mozilla, copy them to <code>(appdir)/defaults/pref</code> in your [[Install.js|install script]].
 
For Firefox/Thunderbird, just put them in <code>myext.xpi/defaults/preferences/</code>. They will be copied and registered in <code>defaults.ini</code> automatically.
 
==Using preferences observers==
You can use <code>nsIPrefBranchInternal</code> 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 <code>nsIPrefBranch</code>] and [http://xulplanet.com/references/xpcomref/ifaces/nsIPrefService.html <code>nsIPrefService</code>]
*[http://lxr.mozilla.org/mozilla/source/modules/libpref/ LXR pages for <code>libpref</code>], the module implementing preferences system.
 
[[Category:Example code|Using preferences]] [[Category:XPCOM example code|Using preferences]]

Latest revision as of 21:31, 22 January 2007

Moved here