WebPreferences を Cocoa バインディングで設定する


HOME > TIPS > はじめてのブラウザのつくりかた > はじめてのブラウザのつくり方 10.3 > WebPreferences を Cocoa バインディングで設定する

WebPreferences を Cocoa バインディングで設定する

次は、WebView の初期設定を Cocoa バインディングを使って実装してみよう。初期設定パネルは、たくさんのユーザインタフェースが必要とされるところ。こういうときこそ、Cocoa バインディングの出番だよ!

ここでは、WebView の初期設定、つまり WebPreferences の設定を行う方法を説明するんだ。初期設定といっても、デフォルトデータベースや、NSUSerDefaultsController は使わないので、注意。

2.1 WebPreferences と Cocoa バインディング

WebPreferences には、WebView の設定項目に対応する、たくさんの取得、設定のためのメソッドがあるよね。これをいちいち呼び出すのは、はっきりいってめんどくさい。だけど、ちょっと待ってくれ!よく見ると、これはキー・バリュー・コーディングに準拠していないかい?

たとえば、WebView のデフォルトのフォントサイズを取得、設定するために、defaultFontSize と setDefaultFontSize: というメソッドが用意されている。 これは、WebView クラスが、defaultFontSize というプロパティに対して、アクセッサメソッドを提供している、ととらえることができるんだ!つまり、WebPreferences クラスは、Cocoa バインディングにおける、モデルクラスとして利用できることになる。

webPreferencesController.jpg
図2-1 WebPreferencesController

これを利用すると、初期設定パネルの実装は上の図のようになる。初期設定パネル上に乗っているユーザインタフェースをビューとし、間にコントローラオブジェクトを挟み、WebPreferences をモデルとして使う。この構造を使うことで、WebPreferences の値とユーザインタフェースの同期を、ほとんどコーディングすることなく実現することができるぜ。

2.2 WebPreferences の切り替え

で、Cocoa バインディングを使うには、ビュー、コントローラ、モデルを関連づけてやる必要がある。これは、ちょっと考えなくてはいけない。

まず、ビューを考えよう。ビューである初期設定パネルは、アプリケーションに 1 つ用意することにする。だから、MainMenu.nib に加えよう。これは簡単だ。次に、コントローラ。コントローラも、1 つだけ必要になる。一度に相手するモデルの数は 1 つなので、NSObjectController のインスタンスを MeinMenu.nib に追加することにする。そして、問題はモデル。WebPreferences は、可能性としては、WebView ごとに作られる場合がある。そして、WebView は MyDocument.nib で作られている。この、コントローラとモデルの関連をどうつけようか?

この問題を解決するために、初期設定パネルは、アプリケーションの現在のメインウィンドウ上にある WebView の WebPreferences と関連づける、と仕様を決定しよう。ウィンドウがメインウィンドウになることは、NSWindow のノーティフィケーションを受け取ることで、知ることができる。ウィンドウからは、NSDocumentController を使って、ドキュメントを取得することができる。このアプリケーションのドキュメントである MyDocument クラスに、webView への参照を持たせておくことにすれば、WebView が取得できる。WebView からは WebPreferences が取得できる。そして、取得した WebPreferences は、NSObjectController の setContent: メソッドを使うことで、コントローラに設定できる。

prefSwitching.jpg
図2-2 WebPreferences の切り替え

こうすることで、コントローラとモデルの関連付けができることになる。この仕様では、ウィンドウを切り替えるたびに、初期設定パネルの対象となる WebPreferences が変更されるんだ。ウィンドウが 1 枚も表示されていない状態では、デフォルトの WebPreferences を取得して、それを使うようにしておこう。

2.3 実装

では、実装の説明を。前回説明したプロジェクトの続きからやるよ。

1. まず、MainMenu.nib を編集する。ダブルクリックして開いてくれ。

2. 初期設定パネルを追加する。パレットから、NSPanel を nib ウィンドウにドラッグしてくれ。そして、NSTabView を貼付ける。そのタブの上に、次のようにユーザインタフェースをならべよう。今回は、Safari の初期設定パネルに近づけてみた。

appearance.jpg

security-1.jpg

advanced.jpg
図2-3 Appearances タブ、Security タブ、Advanced タブ

3. コントローラを追加する。パレットから NSObjectController をドラッグして、nib ウィンドウに追加してくれ。名前を、WebPreferencesController に変えてみた。

今回は、nib ウィンドウでコントローラの content を設定しない。ソースコードで、動的に設定することになるんだ。

4. バインディングを設定する。初期設定パネル上のユーザインタフェースに、次のようにバインディングを設定してくれ。

Bind to には、WebPreferencesController を設定

Controller Key には、selection を設定

Model Key Path には、それぞれ対応するプロパティを設定

たとえば、デフォルトのフォントサイズを表示するテキストフィールドのバインディングは、次のような感じだ。


bindings.jpg
図2-4 Default Font Size テキストフィールドのバインディング

5. メニューの設定をする。アプリケーションメニューの「Preferences…」を選択したら、初期設定パネルを表示するようにしよう。「Preferences…」メニューを選択して、コントロールを押しながら、初期設定パネルにドラッグする。そして、makeKeyAndOrderFront: アクションにつなぐんだ。これでオッケー。

6. PrefDelegate クラスを作る。初期設定パネルのいろいろな設定を行うために、PrefDelegate というクラスを作ろう。NSObject のサブクラスを作って、名前を PrefDelegate にする。

PrefDelegate のアウトレットは、初期設定パネルである preferences、パネル上のタブビューを指す preferencesTab、そして WebPreferencesController を指す preferencesController の 3 つだ。アクションには、フォントパネルを表示するための showFontPanel: と、スタイルシート設定のためのオープンパネルを開く showStyleSheetOpenPanel: を追加しよう。

outlets-4.jpg

actions-2.jpg
図2-5 PrefDelegate のアウトレットとアクション

クラスをデザインしたら、インスタンスを作って、アウトレットとアクションを接続しよう。アウトレットは、それぞれ適切なインスタンスへ。アクションは、Appenarances タブのフォントのためのボタンと、Advanced タブのスタイルシートのためのボタンからつなぐ。

7. Encodings インスタンスを追加する。エンコーディングポップアップメニューを実現するために、ここで紹介している Encodings クラスを使うことにしたよ。Encodings クラスを追加し、インスタンスを作る。そして、ポップアップメニューのバインディングを適切に設定する。

8. 次は、MyDocument.nib を編集する。MyDocument.nib をダブルクリックして開いてくれ。

9. MyDocument クラスに、webView アウトレットを追加する。MyDocument から WebView への参照を取得するために、アウトレットを追加しよう。Classes タブで webView アウトレットを追加し、Instances タブに戻って、コネクションを設定する。

これで、nib の編集はおしまい。Xcode に戻ろう。

10. PrefDelegate を実装する。PrefDelegate は、初期設定パネルのバインディング以外のところをうけもつクラスだ。主にやることは、ツールバーの設定、ウィンドウノーティフィケーションの処理、PrefController の content の設定、フォントパネルの処理、スタイルシート用のオープンパネルの処理、などだ。ここでは、ウィンドウノーティフィケーションを受け取って、PrefController に content を設定するところを見てみよう。

ウィンドウノーティフィケーションを受け取るには、ノーティフィケーションセンターに登録をしてやる必要がある。awakeFromNib メソッドで、次のように呼ぼう。

PrefDelegate.m

  // ウィンドウからのノーティフィケーションを設定します

  NSNotificationCenter* center;

  center = [NSNotificationCenter defaultCenter];

  [center addObserver:self

      selector:@selector(windowDidBecomeMain:)

      name:NSWindowDidBecomeMainNotification

      object:nil];

これで、あるウィンドウがメインウィンドウになると、windowDidBecomeMain: メソッドが呼ばれることになる。

windowDidBecomeMain: メソッドでは、まずウィンドウから関連するドキュメントを取得する。そして、ドキュメントが MyDocument だったら(今回は必ずそうなんだけど)、WebView を取得し、そこから WebPreferences を取得して、PrefController に設定するんだ。

PrefDelegate.m

- (void)windowDidBecomeMain:(NSNotification*)notification
{
  // ウィンドウに関連するドキュメントを取得します
  id document;
  document = [[NSDocumentController sharedDocumentController]
    documentForWindow:[notification object]];

  // ドキュメントがMyDocumentの場合
  if ([document isKindOfClass:[MyDocument class]]) {
    // WebViewからWebPreferencesを取得します
    WebPreferences* pref;
    pref = [[document webView] preferences];
    if (![pref autosaves]) {
      [pref setAutosaves:YES];
    }

    // preferencesControllerのcontentに、WebPreferencesを設定します
    [preferencesController setContent:pref];
  }
}

これで、コントローラに対する設定はオッケーだ。ウィンドウが切り替わるごとに、モデルクラスである WebPreferences も変更されるぜ。

11. WebPreferences クラスを拡張する。WebPreferences は、ほとんどキー・バリュー・コーディング互換なんだけど、1 つだけ準拠していないプロパティがある。それは、plugInsEnabled。このプロパティにたいする取得メソッドは、arePlugInsEnabled となっている。そりゃ複数形だからこれが正しいんだけど、キー・バリュー・コーディング準拠にはならない。

そこで、カテゴリを使って、isPlugInsEnabled というメソッドを WebPreferences に追加しよう。このメソッドの実装は、単に arePlugInsEnabled を呼び出すだけだ。

WebPreferencesEx.m

@implementation WebPreferences (WebPreferencesKVCSupport)

- (BOOL)isPlugInsEnabled
{
return [self arePlugInsEnabled];
}

@end

これで、WebPreferences がキー・バリュー・コーディング準拠になるぜ。

12. ビルドして実行する。これで初期設定パネルが動くはず。

PrefDelegate クラスは、そこそこのコードがあるけど、ツールバーやフォントの処理がほとんどだ。コードよく見れば、WebPreferences に関する処理は、Interface Builder で行えることが分かるはずだ。

browser-9.jpg
図2-6 MyFirstBrowserPanther2 動作図


■ここまでのプロジェクト:
MyFirstBrowserPanther2.zip