Extraits de code:Préférences
Un article de MDC.
Cet article propose des exemples pour les développeurs d'extension qui veulent utiliser le système de préférences de Mozilla. Les informations ici présentes s'appliquent à la suite Mozilla, Firefox, Thunderbird, et probablement d'autres applications basées sur Mozilla. Pour plus de détails sur les préférences dans Mozilla, consultez Système de préférences.
Si vous ne l'avez pas encore fait, lisez d'autres documents concernant les préférences Mozilla sur XULPlanet et sur mozilla.org (cf les liens plus bas dans la section ressources).
[modifier] Interfaces XPCOM pour le système de préférences
Mozilla expose son système de préférences au travers d'un certain nombre d'interfaces XPCOM. Regardez dans la section ressources ci-dessous pour la liste des interfaces relatives aux préférences.
Les trois interfaces utilisées sont nsIPrefService, nsIPrefBranch et nsIPrefBranch2. Elles sont figées et ne changeront pas.
Ce n'est pas tout, car il y a aussi une autre interface nsIPref. Bien qu'elle soit utilisée à plusieurs endroits, elle n'est pas conseillée (deprecated) et ne devrait pas être utilisée.
Le service de préférences est instancié de la même façon que vous instanciez n'importe quel service XPCOM (consultez l'article sur la création de composants XPCOM sur XULPlanet pour plus de détails). Pour obtenir une nsIPrefBranch, appelez QueryInterface() pour le service pref (ce qui vous donnera la branche racine) ou appelez nsIPrefService.getBranch() pour obtenir une sous-branche.
Voici deux exemples :
// Obtention de la branche racine
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
// Obtention de la branche "extensions.myext."
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService);
prefs = prefs.getBranch("extensions.myext.");
[modifier] Types simples
Il existe trois types de préférences : string, integer et boolean. Chaque entrée dans la base de données des préférences (prefs.js) est de l'un de ces types. Six méthodes sont disponibles dans nsIPrefBranch pour lire et écrire des préférences : getBoolPref(), setBoolPref(), getCharPref(), setCharPref(), getIntPref() et setIntPref(). Leur utilisation est aussi simple que :
// prefs est un nsIPrefBranch.
// Regardez dans la section précédente comment l'obtenir
var value = prefs.getBoolPref("accessibility.typeaheadfind"); // récupère une préférence
prefs.setBoolPref("accessibility.typeaheadfind", !value); // définit une préférence
[modifier] Types complexes
Comme signalé dans la section précédente, chaque entrée dans la base de données préférence (prefs.js) doit être une chaîne de caractères, un entier ou une valeur booléenne. Toutefois, il existe un concept de types complexes qui facilite pour les développeurs le chargement et la sauvegarde d'objets nsILocalFile et nsISupportsString dans les préférences (comme des chaînes — notez que du point de vue du système de préférence, les valeurs complexes ont un type nsIPrefBranch.PREF_STRING).
Deux méthodes nsIPrefBranch implémentent le concept — setComplexValue() et getComplexValue(). Vous pouvez rechercher leurs implémentations dans nsPrefBranch.cpp. Voici les définitions IDL :
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);
Comme vous voyez, les deux méthodes prennent un paramètre, aType, pouvant avoir l'une des valeurs suivantes (pour être précis, vous pouvez passer Components.interfaces.nsIWhatever au lieu de simplement nsIWhatever qui est indéfini) :
nsISupportsString- Utilisé pour traiter les chaînes Unicode dans les préférences. Utilisez-le lorsque la valeur de préférence peut contenir des caractères non-ASCII (par exemple, le nom d'un utilisateur).
nsIPrefLocalizedString- Presque comme
nsISupportsString, mais géré différemment dansgetComplexValue()où il n'y a aucune valeur pour la préférence donnée ; voir plus bas pour plus de détails. nsILocalFileetnsIRelativeFilePref- Sauvegarde des chemins dans les préférences.
nsILocalFilesert à sauvegarder des chemins absolus tandis quensIRelativeFilePrefsert à sauvegarder des chemins relatifs vers un répertoire "spécial", tel que le répertoire du profil.
[modifier] nsISupportsString
Comme noté plus haut, cette interface sert à gérer les chaînes de caractères Unicode dans les préférences. Par exemple :
// prefs est un nsIPrefBranch
// Exemple 1 : Récupérer une valeur Unicode
var value = prefs.getComplexValue("preference.avec.valeur.non.ascii",
Components.interfaces.nsISupportsString).data;
// Exemple 2 : Définir une valeur Unicode
var str = Components.classes["@mozilla.org/supports-string;1"]
.createInstance(Components.interfaces.nsISupportsString);
str.data = "un peu de texte non-ascii";
prefs.setComplexValue("preference.avec.valeur.non.ascii",
Components.interfaces.nsISupportsString, str);
[modifier] nsIPrefLocalizedString
Un autre type complexe supporté par Mozilla est nsIPrefLocalizedString. Il est similaire à nsISupportsString, sauf lorsqu'il n'y a aucune valeur utilisateur. getComplexValue() récupère la valeur par défaut depuis un fichier de localisation (ce qui rend la valeur par défaut localisable).
Il est plus facile d'expliquer par un exemple. Supposons que vous vouliez rendre localisable la valeur par défaut pour la préférence extensions.myext.welcomemessage. Vous devrez procéder ainsi :
- Ajoutez cette ligne à vos fichiers
.properties(pour toutes vos localisations), comme pourchrome://myext/locale/defaults.properties:extensions.myext.welcomemessage=Valeur localisée par défaut
- Ajoutez la valeur par défaut pour
extensions.myext.welcomemessage, pointant vers ce fichier de propriété, en mettant la ligne suivante dans votre fichier de préférences par défaut (voir plus bas).pref("extensions.myext.welcomemessage", "chrome://myext/locale/defaults.properties"); - Lire la préférence avec
getComplexValue, définissant la variable (passing)nsIPrefLocalizedStringen tant queaType: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;
Si aucune valeur n'est entrée, le code à l'étape 3 lira la valeur par défaut depuis chrome://myext/locale/defaults.properties et se comportera exactement de la même manière que si nsISupportsString était défini autrement en tant que aType .
Définir des préférences nsIPrefLocalizedString est similaire à définir nsISupportsString:
var pls = Components.classes["@mozilla.org/pref-localizedstring;1"]
.createInstance(Components.interfaces.nsIPrefLocalizedString);
pls.data = val;
prefs.setComplexValue("preference.with.non.ascii.value",
Components.interfaces.nsIPrefLocalizedString, pls);
[modifier] nsILocalFile and nsIRelativeFilePref
Veuillez consulter l'article sur les fichiers E/S pour plus de détails sur nsILocalFile et nsIRelativeFilePref.
[modifier] Préférences par défaut
Chaque préférence peut avoir deux valeurs — la valeur courante et la valeur par défaut. Cela signifie qu'il y a deux "arbres de préférences" : le courant et celui par défaut, et chacun d'eux peut avoir ou non une valeur de préférence.
Vous pouvez voir la liste des préférences dans about:config. Les préférences qui ont une valeur d'utilisateur sont en gras, et celles qui n'ont pas été définies par l'utilisateur sont affichées en police normale.
Vous pouvez obtenir ces deux arbres en utilisant les fonctions nsIPrefService.getBranch() et nsIPrefService.getDefaultBranch(). Voir ci-dessous pour plus de détails.
[modifier] L'effet des préférences par défaut sur les méthodes get
Lorsqu'une des méthodes get de nsIPrefBranch (en supposant qu'il s'agisse d'une branche de l'arbre des valeurs courantes) est appelée, voici ce qu'il se passe :
- Vérification si l'arbre courant possède une valeur pour cette préférence et si elle est ou non bloquée.
- S'il existe une valeur du bon type (par exemple,
getBoolValue()attend une valeur de typensIPrefBranch.PREF_BOOL), et que la préférence n'est pas bloquée, la méthode renvoie cette valeur. - S'il existe une valeur d'un type incorrect et que la préférence n'est pas bloquée, une exception
NS_ERROR_UNEXPECTEDest lancée. - Si la préférence est bloquée ou s'il n'y a pas de valeur pour cette préférence dans l'arbre courant, la méthode
getvérifie l'arbre par défaut. - S'il existe une valeur ayant le type attendu dans l'arbre par défaut, elle est retournée (avec la seule exception étant que l'appel de
getComplexValue()doit se faire avec le paramètreaTypeànsIPrefLocalizedString, comme décrit plus haut). - Autrement une exception
NS_ERROR_UNEXPECTEDest lancée.
Si la branche provient de l'arbre par défaut, la méthode get ne vérifie pas du tout l'arbre des valeurs courantes.
(Ce n'est pas exactement codé comme cela dans libpref, mais c'est équivalent)
[modifier] D'où sont lues les valeurs par défaut ?
- Toutes les applications basées sur Mozilla lisent (répertoire de l'application)/defaults/pref/*.js.
- De plus, les versions récentes des applications du toolkit (Firefox 1.0, Thunderbird 1.0 et d'autres mais pas la suite Mozilla) lisent les préférences par défaut des extensions -- habituellement situées dans
(répertoire profil)/extensions/(ID)/defaults/preferences/
Ces fichiers ont une syntaxe proche du JavaScript. Pour ajouter une valeur de préférence par défaut, vous devrez ajouter à votre fichier de préférences une ligne comme ceci :
pref("extensions.nomextension.nompreference", false);
[modifier] Comment installer les fichiers par défaut d'une extension
Pour la suite Mozilla (pas Firefox et Thunderbird), copiez les vers (appdir)/defaults/pref dans votre script d'installation.
Pour Firefox/Thunderbird, placez les simplement dans monext.xpi/defaults/preferences/. Ils seront automatiquement copiés et enregistrés avec le système de préférences.
[modifier] Plus de détails concernant les "branches" de préférences
Les noms des préférences consistent en quelques chaînes de caractères séparées par des points, et dont les préférences en relation commençant généralement par le même préfixe. Par exemple, la plupart des préférences d'accessibilité dans Mozilla débute par "accessibility."
Cela signifie que toutes les préférences existantes peuvent être vues comme si elles étaient dans un arbre, comme ceci :
+
|
+-- accessibility
| |
| +-- typeaheadfind
| | |
| | +-- autostart (accessibility.typeaheadfind.autostart)
| | |
| | +-- enablesound (accessibility.typeaheadfind.enablesound)
| |
| +-- usebrailledisplay (accessibility.usebrailledisplay)
|
+-- extensions
|
+-- lastAppVersion (extensions.lastAppVersion)
C'est la métaphore derrière nsIPrefBranch. Toutefois, vous devez savoir que le système de préférences de Mozilla ne donne aucune signification particulière aux points. Par exemple, ce code lira également la valeur de la préférence accessibility.typeaheadfind.enablesound :
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService);
var branch = prefs.getBranch("acce");
var enablesound = branch.getBoolPref("ssibility.typeaheadfind.enablesound");
C'est la raison pour laquelle vous devez habituellement passer à getBranch() des chaînes de caractères se terminant avec un point, comme prefs.getBranch("accessibility.").
Autre avertissement, nsIPrefBranch.getChildList("") renvoie un tableau des noms des préférences qui commencent par la branche root. Par exemple
var branch = prefs.getBranch("accessibility.");
var children = branch.getChildList("", {});
renverra les items suivants (pour l'arbre exemple ci-dessus) : "typeaheadfind.autostart", "typeaheadfind.enablesound", et "usebrailledisplay", et pas simplement le fils direct ("typeaheadfind" et "usebrailledisplay"), comme vous l'espériez.
[modifier] Utilisation des observateurs de préférences
Vous pouvez utiliser l'interface nsIPrefBranchInternal pour "scruter" les modifications sur des préférences dans une branche donnée.
nsIPrefBranchInternal a été renommé en nsIPrefBranch2 [1] et a été figée. Le nom nsIPrefBranchInternal est toujours supporté dans Gecko 1.8, donc c'est celui-ci que vous devez utiliser pour que vos extensions soient compatibles avec Gecko 1.7 et Gecko 1.8 (Firefox 1.0/1.5/2.0). Pour de nouvelles extensions, utilisez nsIPrefBranch2.Voici un exemple :
var myPrefObserver =
{
register: function()
{
var prefService = Components.classes["@mozilla.org/preferences-service;1"]
.getService(Components.interfaces.nsIPrefService);
this._branch = prefService.getBranch("extensions.myextension.");
this._branch.QueryInterface(Components.interfaces.nsIPrefBranch2);
this._branch.addObserver("", this, false);
},
unregister: function()
{
if(!this._branch) return;
this._branch.removeObserver("", this);
},
observe: function(aSubject, aTopic, aData)
{
if(aTopic != "nsPref:changed") return;
// aSubject est le nsIPrefBranch que nous observons (après la QI appropriée)
// aData est le nom de la préférence qui a été modifiée (relativement à aSubject)
switch (aData) {
case "pref1":
// extensions.myextension.pref1 a été modifiée
break;
case "pref2":
// extensions.myextension.pref2 a été modifiée
break;
}
}
}
myPrefObserver.register();
nsIPrefBranch2.idl comporte plus de renseignements.
[modifier] Utilisation de prefHasUserValue()
nsIPrefBranch.prefHasUserValue(preference) vérifie si la préférence a été modifiée par rapport à la valeur par défaut. Si c'est le cas, elle renvoie true, autrement elle renvoie false. En particulier, si aucune valeur par défaut n'existe pour une préférence, prefHasUserValue() indique si une préférence existe.
Toute tentative de lire une préférence inexistante en utilisant une des méthodes get*Pref lancera une exception. L'utilisation de prefHasUserValue() vous permet de vérifier si la préférence existe avant d'essayer de la lire. Par exemple :
if(prefs.prefHasUserValue("mypref")) {
alert(prefs.getCharPref("mypref");
}
Notez que l'appel de getCharPref() pourrait lancer tout de même une exception si la préférence existe, par exemple dans le cas où elle aurait un type différent.
[modifier] Utilisation de préférences dans des extensions
Si vous écrivez votre extension pour l'une des applications du toolkit (Firefox, Thunderbird, Nvu), vous devez fournir des valeurs par défaut aux préférences de votre extension (voir ci-dessus pour plus d'information sur comment faire). Cela a l'avantage suivant :
- Vous n'avez pas à dupliquer des valeurs par défaut dans différentes parties de votre code.
- Le code pour lire les préférences s'en trouve simplifié puisque vous n'avez pas à vous soucier que les méthodes
getlancent des exceptions.
[modifier] Paquetages JavaScript du système de préférence
Il existe quelques paquetages JavaScript pour vous simplifier la vie, tels que celui trouvé dans http://mozilla.doslash.org/prefutils et le paquetage nsPreferences inclus avec Firefox et Thunderbird (chrome://global/content/nsUserSettings.js).
[modifier] Ressources
- Documentation complémentaire sur les préférences
- API de préférences
- Un court guide sur les préférences de Mozilla — décrit le système de préférences d'un point de vue utilisateur / administrateur.
- Un article issu de XULPlanet (et traduit sur xulfr) sur les préférences — Une explication du système de préférence avec des exemples simples - À lire absolument.
- Interfaces XPCOM de Mozilla sur le système de préférences.
- Liste complète
- Interfaces les plus utilisées (celles-ci sont gelées et ne seront pas modifiées):
nsIPrefBranchetnsIPrefService - Interface
nsIPrefBranch2(avant Gecko 1.8, elle était appeléensIPrefBranchInternal).
- Système de préférences - une méthode facile pour créer une fenêtre d'options XUL pour votre extension ou application.
- Pages LXR pour libpref, le module du code source qui implémente le système de préférences.
- Un paquet JavaScript pour des API de préférences : http://mozilla.doslash.org/prefutils