Code snippets:Preferences
出典: MDC
この文書では、Mozilla 設定システムを利用しようとする拡張機能開発者向けのサンプルを示しています。ここにあるものは、Mozilla Suite、Firefox、Thunderbird、そしておそらくその他の Mozilla ベースのアプリケーションに適用可能です。Mozilla での設定システムについてのより詳細については、設定システム を参照してください。
もし、まだ理解していないなら、Mozilla 設定システムに関する XULPlanet や mozilla.org にある文書を読んでください。(追加情報 にリンクがあります)
目次 |
[編集] 設定システムの XPCOM インターフェース
Mozilla はいくつかの XPCOM インターフェースを介して設定を公開します。追加情報 の設定に関連したインターフェースのリストへのリンクを参照してください。
nsIPrefService、 nsIPrefBranch と nsIPrefBranch2 が三つのよく利用されるインターフェースです。これらは凍結されており変更されることはありません。
また、nsIPref インターフェースも存在はします。ある場所で利用されているかもしれませんが、廃止予定 であり、利用すべきではありません。
設定サービスは、あなたが他の XPCOM サービスのインスタンスを作成するときと同じように作成できます。これについての詳細は XULPlanet の XPCOM コンポーネントの作成方法 を見てください。nsIPrefBranch を取得するには、QueryInterface() に設定サービスを入れる (この場合、ルートブランチが取得できます) か、nsIPrefService.getBranc() を呼んで sub-branch を取得してください。
次の二つがサンプルです:
// ルートブランチを取得
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefBranch);
// "extensions.myext" ブランチを取得
var prefs = Components.classes["@mozilla.org/preferences-service;1"].
getService(Components.interfaces.nsIPrefService);
prefs = prefs.getBranch("extensions.myext.");
[編集] 単純型
設定には三種類の型が存在します。文字列, 整数値 そして 真偽値 です。設定データベース (prefs.js) の中でそれぞれのエントリは、これらのうちのひとつの型を持ちます。nsIPrefBranch には設定の取得・設定のための 6 つのメソッドがあります。getBoolPref(), setBoolPref(), getCharPref(), setCharPref(), getIntPref() そして setIntPref() です。これらは次のように利用できます。
// nsIPrefBranch 経由の設定操作
// branch を取得する方法は一つ上の章を読んでください
var value = prefs.getBoolPref("accessibility.typeaheadfind"); // 取得
prefs.setBoolPref("accessibility.typeaheadfind", !value); // 設定
[編集] 複合型
前の章で説明したとおり、設定データベース中 (prefs.js) の各エントリは文字列、整数値、もしくは真偽値のどれかを持つ必要があります。ただし、複合型 もあり、開発者にとって nsILocalFile や nsISupportsString オブジェクトを設定に保存しやすくなります。(文字列として — 設定システムの面からみると、複合型は nsIPrefBranch.PREF_STRING の型の値となります。)
この型についての nsIPrefBranch の実装には二つのメソッドがあります — setComplexValue() と getComplexValue() です。これらの実装については、nsPrefBranch.cpp がソースとなり、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);
見て分かるように、二つともパラメータをとり、aType は次の値のいずれかです (正確には、定義されていない nsIWhatever ではなく、Components.interfaces.nsIWhatever を渡す必要があります。)
nsISupportsString- 設定にある Unicode 文字列を処理するのに利用します。ユーザ名のように non-ASCII 文字列を含む設置値の場合にこれを利用してください。
nsIPrefLocalizedStringnsISupportStringとほぼ同じですが、ユーザ設定値が無い場合にgetComplexValue()で異なる動作を示します。詳細は下記を参照してください。nsILocalFileとnsIRelativeFilePref- 設定にパスを保存します。
nsILocalFileは絶対パス、nsIRelativeFilePrefはプロファイルフォルダーなどの特別なディレクトリからの相対パスを保存するために利用します。
[編集] nsISupportsString
上記の通り、これは設定の Unicoide 文字列を処理するのに利用します。たとえば
// prefs is an nsIPrefBranch
// サンプル 1: Unicode 値を得る
var value = prefs.getComplexValue("preference.with.non.ascii.value",
Components.interfaces.nsISupportsString).data;
// サンプル 2: Unicode 値を設定する
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);
[編集] nsIPrefLocalizedString
Mozilla でサポートされている別の複合型として、nsIPrefLocalizedString があります。これは、ユーザ設定値が無い場合を除いて nsISupportsString に似ていますが、getComplexValue() はロケールファイル (既定値をローカライズできるようにするため) から既定値を取得します。
サンプルを示す方が説明がしやすいですので、extensions.myext.welcomemessage<code> 設定値の既定値ををローカライズする時を例にとって説明します。まず、以下のようにする必要があります。
- (あなたのロケールの全ての) <code>.properties</code> ファイルに次の行を加えます。<code>chrome://myext/locale/defaults.properties</code> です。
extensions.myext.welcomemessage=ローカライズされた既定値
- <code>extensions.myext.welcomemessage</code> に既定値を追加し、あなたの拡張に 既定の設定 を次のように書き加えることで、properties ファイルを示すようにします。
pref("extensions.myext.welcomemessage", "chrome://myext/locale/defaults.properties"); - 設定を <code>aType</code> に <code>nsIPrefLocalizedString</code> を渡して <code>getComplexValue</code> で読みます。
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;
ステップ 3 では、ユーザ設定値が無い場合 chrome://myext/locale/defaults.properties からの既定値が読み込まれているはずです。それ以外の場合は <code>nsISupportString が aType に渡された場合と同じ動作をします。
設定に nsIPrefLocalizedString を利用して設定する場合は、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);
[編集] nsILocalFile と nsIRelativeFilePref
nsILocalFile と </code>nsIRelativeFilePref</code> についての詳細は File IO についての文書 を参照してください。
[編集] 既定の設定値
それぞれの設定値は最大二つの値をもちます。— 設定値 と 既定値 です。これは、現在と既定の二つの "設定木:" があることを意味し、それぞれが設定に対して値を持つ・持たないの両方が可能であるということです。
設定値の一覧は about:config (存在すれば) でみることが可能です。ユーザ設定値がある場合は太字で、ユーザ設定値が無いものについては通常のフォントで表示されます。
nsIPrefService.getBranch() と nsIPrefService.getDefaultBranch() 関数により両方の木を取得できます。詳細は下記を参照してください。
[編集] get メソッドでの既定の設定値の影響
nsIPrefBranch の get メソッドの一つが呼ばれた (設定値の方の木を想定します) とき、以下のように動作します。
- 設定値 の木に値が存在するかと設定がロックされているかどうかを確認します。
- 要求に一致する型の値が存在するか (たとえば、
getBoolValueはnsIPrefBranch.PREF_BOOL型の値を想定します) を確認し、設定がロックされていなければ、その値を返します。 - 異なる型の値であり、かつ設定がロックされていなければ、
NS_ERROR_UNEXPECTED例外を投げます。 - 設定がロックされているか、設定値 の木に設定値がなければ、
getメソッドは既定値の木を確認します。 - 既定値 の木に求められる型の値がある場合、それを返します。(例外として、
aTypeにnsIPrefLocalizedStringが設定されたgetComplexValue()の呼び出しの場合があります。上記参照) - 上記のどれでもなければ
NS_ERROR_UNEXPECTED例外を投げます。
木が 既定値 のものであれば、get メソッドは設定値を一切チェックしません。
(libpref 内の実装を完全に説明してはいませんが、等価です。)
[編集] 既定値はどこから取得されるか
- すべての Mozilla ベースのアプリケーションは (application directory)/defaults/pref/*.js を読みます。 .
- 付け加えて、Toolkit アプリケーションの最近のバージョン (Firefox 1.0, Thunderbird 1.0 などで、Mozilla Suite は 違います) は拡張機能の既定を読みます。 --
(profile folder)/extensions/(ID)/defaults/preferences/に通常は置かれます。
これらのファイルは、簡単な JavaScript に似た形式です。設定に既定値を加えるには、あなたの既定の設定ファイルに次の行を加えてください。
pref("extensions.extensionname.preferencename", false);
[編集] 拡張機能の既定値のファイルをインストールするには
Mozilla Suite については、(appdir)/defaults/pref に インストールスクリプト でコピーしてください。
Firefox や Thunderbird については、myext.xpi/defaults/preferences/ に保存してください。設定システムで自動的にコピーされ登録されます。
[編集] 設定 "木" についての詳細
設定名はドット区切りの文字列で構成され、関連する設定は通常は同じプレフィックスをもちます。たとえば、Mozilla のほとんどのアクセシビリティー関係の設定は、"accessibility" で始まります。
これは、全ての存在する設定が木のようにイメージできることを示します。たとえば次のように。
+
|
+-- accessibility
| |
| +-- typeaheadfind
| | |
| | +-- autostart (accessibility.typeaheadfind.autostart)
| | |
| | +-- enablesound (accessibility.typeaheadfind.enablesound)
| |
| +-- usebrailledisplay (accessibility.usebrailledisplay)
|
+-- extensions
|
+-- lastAppVersion (extensions.lastAppVersion)
これは、nsIPrefBranch に隠されたメタファーです。ただ、Mozilla の設定システムはドットを特別なものとして扱わないという事実に注意してください。
たとえば、次のコードも設定の 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");
これは、ドットで終わる文字列を getBranch() に渡すべきであることを示す一つの理由です。つまり prefs.getBranch("accessibility.") のように。
もう一つの注意として、nsIPrefBranch.getChildList("",{}) が、設定木の root で始まる設定名の配列を返すことに注意してください。たとえば
var branch = prefs.getBranch("accessibility.");
var children = branch.getChildList("", {});
は上の木を例に取ると、あなたの期待しているであろう直接の子供 ("typeaheadfind" and "usebrailledisplay") ではなく、"typeaheadfind.autostart", "typeaheadfind.enablesound", and "usebrailledisplay" のアイテムを返します。
[編集] 設定オブザーバを利用する
ある木の設定への変更を監視するのに nsIPrefBranchInternal インターフェースを利用できます。
nsIPrefBranchInternal は nsIPrefBranch2 に変更 (bug 281414) され、凍結されました。nsIPrefBranchInternal は Gecko 1.8 ではまだサポートされていますので、拡張を Gecko 1.7 と Gecko 1.8 (Firefox 1.0/1.5) の両方に対応させる場合はこちらを利用すべきです。新しい拡張では、nsIPrefBranch2 を利用すべきです。サンプルは次のようになります。
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 is the nsIPrefBranch we're observing (after appropriate QI)
// aData is the name of the pref that's been changed (relative to aSubject)
switch (aData) {
case "pref1":
// extensions.myextension.pref1 was changed
break;
case "pref2":
// extensions.myextension.pref2 was changed
break;
}
}
}
myPrefObserver.register();
nsIPrefBranch2.idl により詳細があります。
[編集] prefHasUserValue() を利用する
nsIPrefBranch.prefHasUserValue(preference) により、既定値から設定が変更されたかどうかを確認できます。変更されていれば true を、変更されていなければ false を返します。特に、既定値が設定されていない場合、prefHasUserValue() は設定が存在するかを確認する手段になります。
get*Pref メソッドで存在しない設定を読もうとしたとき例外が投げられます。読み込む前に、prefHasUserValue() を確認することで設定が存在するかどうかを確認できます。たとえば次のように。
if(prefs.prefHasUserValue("mypref")) {
alert(prefs.getCharPref("mypref");
}
注: getCharPref() は設定が存在しても、型が違う場合に例外を投げます。
[編集] 拡張で設定を利用する
Toolkit アプリケーション (Firefox, Thunderbird, Nvu など) 向けに拡張機能を書いている場合、拡張機能の設定に既定値を設定する方が望ましいです。(上記の詳細を参照してください。) これには次のような利点があります。
- コードの中に既定値を入れる必要が無くなる
- 設定を読むコードが単純化され、
getメソッドが例外を投げる可能性を考慮しなくてすむ
[編集] 設定システムの JavaScript でのラッパ
コードを単純化するためにいくつかの JavaScript でのラッパが存在します。http://mozilla.doslash.org/prefutils や Firefox と Thunderbird に含まれる nsPreferences ラッパです。(chrome://global/content/nsUserSettings.js)
[編集] 追加情報
- 設定に関するほかの文書
- Preferences API
- Mozilla 設定システムの概要 — はユーザや管理者の視点からの設定システムの解説です
- XUL Planet の設定に関する文書 — は簡単なサンプルを含む設定システムの解説です。読むべきです。
- 設定システムの Mozilla XPCOM インターフェース
- 完全なリスト
- よく利用されるインターフェース (凍結され変更の可能性が無いもの):
nsIPrefBranchとnsIPrefService -
nsIPrefBranch2インターフェース (Gecko 1.8 以前ではnsIPrefBranchInternalでした)
- Preferences System - は拡張機能やアプリケーションで XUL オプションウィンドウを作成する簡単な方法を説明します。
- LXR での libpref で設定システムの実装をみることができます。
- 設定 API の JavaScript ラッパ : http://mozilla.doslash.org/prefutils