Preferences

この文書では、Mozilla 設定システムを利用しようとする拡張機能開発者向けのサンプルを示しています。ここにあるものは、Mozilla Suite、Firefox、Thunderbird、そしておそらくその他の Mozilla ベースのアプリケーションに適用可能です。Mozilla での設定システムについてのより詳細については、設定システム を参照してください。

もし、まだ理解していないなら、Mozilla 設定システムに関する XULPlanet や mozilla.org にある文書を読んでください。(追加情報 にリンクがあります)

注: この文書は設定を扱う既存の全てのメソッドを説明しているわけではありません。メソッドの完全なリストについては、追加情報 にリストされている XULPlanet XPCOM リファレンスを参照してください。設定のインターフェースはよく文書化されていますので、ここで触れていないメソッドを利用するのも容易だろうと思われます。

設定システムの XPCOM インターフェース

Mozilla はいくつかの XPCOM インターフェースを介して設定を公開します。追加情報 の設定に関連したインターフェースのリストへのリンクを参照してください。

nsIPrefServicensIPrefBranchnsIPrefBranch2 が三つのよく利用されるインターフェースです。これらは凍結されており変更されることはありません。

また、nsIPref インターフェースも存在はします。ある場所で利用されているかもしれませんが、廃止予定 であり、利用すべきではありません。

設定サービスは、あなたが他の XPCOM サービスのインスタンスを作成するときと同じように作成できます。これについての詳細は XULPlanet の XPCOM コンポーネントの作成方法 を見てください。nsIPrefBranch を取得するには、QueryInterface() に設定サービスを入れる (この場合、ルートブランチが取得できます) か、nsIPrefService.getBranch() を呼んで 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) の各エントリは文字列、整数値、もしくは真偽値のどれかを持つ必要があります。ただし、複合型 もあり、開発者にとって nsILocalFilensISupportsString オブジェクトを設定に保存しやすくなります。(文字列として — 設定システムの面からみると、複合型は 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 文字列を含む設置値の場合にこれを利用してください。
nsIPrefLocalizedString
nsISupportString とほぼ同じですが、ユーザ設定値が無い場合に getComplexValue() で異なる動作を示します。詳細は下記を参照してください。
nsILocalFilensIRelativeFilePref
設定にパスを保存します。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> 設定値の既定値をローカライズする時を例にとって説明します。まず、以下のようにする必要があります。

  1. (あなたのロケールの全ての) .properties ファイルに次の行を加えます。chrome://myext/locale/defaults.properties です。
    extensions.myext.welcomemessage=ローカライズされた既定値
  2. extensions.myext.welcomemessage に既定値を追加し、あなたの拡張に 既定の設定 を次のように書き加えることで、properties ファイルを示すようにします。
    pref("extensions.myext.welcomemessage", "chrome://myext/locale/defaults.properties");
  3. 設定を aTypensIPrefLocalizedString を渡して getComplexValue で読みます。
    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 からの既定値が読み込まれているはずです。それ以外の場合は nsISupportStringaType に渡された場合と同じ動作をします。

設定に 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

Leave this section to have nice TOC nsILocalFilensIRelativeFilePref についての詳細は File IO についての文書 を参照してください。

既定の設定値

someone should reword this section それぞれの設定値は最大二つの値をもちます。— 設定値既定値 です。これは、現在と既定の二つの "設定木:" があることを意味し、それぞれが設定に対して値を持つ・持たないの両方が可能であるということです。

設定値の一覧は about:config (存在すれば) でみることが可能です。ユーザ設定値がある場合は太字で、ユーザ設定値が無いものについては通常のフォントで表示されます。

nsIPrefService.getBranch()nsIPrefService.getDefaultBranch() 関数により両方の木を取得できます。詳細は下記を参照してください。

get メソッドでの既定の設定値の影響

nsIPrefBranchget メソッドの一つが呼ばれた (設定値の方の木を想定します) とき、以下のように動作します。

  1. 設定値 の木に値が存在するかと設定がロックされているかどうかを確認します。
  2. 要求に一致する型の値が存在するか (たとえば、getBoolValuensIPrefBranch.PREF_BOOL 型の値を想定します) を確認し、設定がロックされていなければ、その値を返します。
  3. 異なる型の値であり、かつ設定がロックされていなければ、NS_ERROR_UNEXPECTED 例外を投げます。
  4. 設定がロックされているか、設定値 の木に設定値がなければ、get メソッドは既定値の木を確認します。
  5. 既定値 の木に求められる型の値がある場合、それを返します。(例外として、aTypensIPrefLocalizedString が設定された getComplexValue() の呼び出しの場合があります。上記参照)
  6. 上記のどれでもなければ NS_ERROR_UNEXPECTED 例外を投げます。

木が 既定値 のものであれば、get メソッドは設定値を一切チェックしません。

(libpref 内の実装を完全に説明してはいませんが、等価です。)

既定値はどこから取得されるか

  • すべての Mozilla ベースのアプリケーションは (application directory)/defaults/pref/*.js を読みます。 (xxx are non-.js files read?).
  • 付け加えて、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 インターフェースを利用できます。

Gecko 1.8 の開発にて、nsIPrefBranchInternalnsIPrefBranch2 に変更 (バグ 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)

追加情報

ドキュメントのタグと貢献者

 このページの貢献者: ethertank, Gomita, Shimono, Mgjbot
 最終更新者: ethertank,