タイトル【Carbon化シリーズ】Navigation Serviceでファイル保存ダイアログ(3)カテゴリーCarbon/CF, Carbon化
作成日2000/7/4 19:28:47作成者新居雅行
Navigation Servicesについて延々と対応方法を説明してきたが、今回で最後になる。何回もかかって説明しているだけに、いわば、それなりに大変なところでもある。APIを置き換えるだけでは済まなくなるというのが総括的なところとなるだろうか。今回は、名前を付けて保存、つまり、Save Asコマンドのときのファイル指定ダイアログボックスを組み込む。もちろん、前々回と同様に、NavPutFileを使うのであるが、TextDrawでは書類ファイルだけでなく、PICTファイルやテキストファイルへの保存もサポートしたい。つまり、保存フォーマットを選択するユーザインタフェースを付け、その選択結果に従って分岐処理をしたいというわけだ。ここでは、ポップアップメニューをカスタマイズすることと、ポップアップメニューの選択結果をダイアログボックスを閉じた後に取得する方法がポイントになる。

FileメニューのSave Asを選択して呼び出されるのが、DoCommand.cというソースファイルにあるDoSaveAsCommand関数だ。まずは、フォーマットを選択するポップアップメニューのカスタマイズの方法を追ってみよう。もちろん、NavPutFileが保存ダイアログボックスを表示するもので、詳細は前々回に説明しているためここでは違いだけを説明するが、3つ目の引数にNavDialogOptions型構造体で、ダイアログボックスの各種の設定を行う。この構造体のメンバであるpopupExtensionに、カスタマイズするメニュー項目を指定することになる。ただ、この指定がややこしい。具体的には構造体の配列を指定すると、その配列の1つ1つの要素がメニュー項目の1つ1つを指定することができる。メニュー項目の1つ1つを指定する構造体は、NavMenuItemSpecであるが、その構造体へのポインタ、ハンドルして、NavMenuItemSpecArrayPtrとNavMenuItemSpecArrayHandleという型が用意されている。Insde Carbonのドキュメントには間違いがあるので、正しい定義はNavigation.hヘッダファイルで確認するのが良いだろう。そして、構造体へのポインタは、構造体の配列へのポインタとも認識できるというC言語のもっともややこしいプログラムをここでしなければならない。おそらく、NavPutFileは、ハンドルの先にあるメモリ領域のサイズを見て、構造体がいくつ連続しているかを判断しているものと思われるが、ドキュメントにもその点についてはあいまいにしか書いていなかった。
DoSaveAsCommand関数の前半を見てもらおう。ここではポップアップメニューとして、3項目を用意したいので、まずはNewHandleを使って、NavMenuItemSpec構造体3つ分のメモリ領域を確保する。NavDialogOptions構造体のpopupExtensionメンバには、このハンドルを指定するのでよい。そして、ハンドルが指し示すメモリ領域に、メニュー名をセットするのだが、各構造体の中身は、versionメンバに規定の定義定数をセット、menuCreatorにクリエイタ情報(TextDrawではあまり意味はない)、nemuTypeにメニューを選択したときに得られる値、nemuItemNameにメニュー項目として実際に表示されるPascal文字列を指定する。ポインタと配列とが入り乱れ、正直なところちょっと苦労したが、示しているようなプログラムでとりあえずうまく動いた。3つの構造体のいずれにも必要な値を代入している。なお、何もしなくても、そのアプリケーションの書類を示す項目と、書類かひな形かを選択するダイアログボックスを表示するメニュー項目は自動的に追加される。このプログラムでは、前者は使うが後者は表示しないことにする。その場合には、NavDialogOptions構造体dialogOptionFlagsのあるビットを落とせばよい。そのために、kNavAllowStationeryという定数が用意されているので、-=演算子でビットを落としている。実際に表示されたダイアログボックスの、フォーマットのポップアップメニューを表示したところは次の通りだ。ポップアップメニューは合計4つの項目を持っている。

◇Save Asのダイアログボックスを表示したところ


では、実際にダイアログボックスで、フォーマットの選択のどの項目が選ばれているのかを検知する方法を説明しよう。NavReplyRecord構造体で分かる…なら話は早いのだが、それはできないようだ。この方法は、従来のStandard File Packageと同じような方法を取らないといけない。
ダイアログボックスでポップアップメニューを選択すると、Navgation Servicesベースのイベントが発生する。つまり、そのイベントを捕らえ、どのメニューが選ばれたかを得て、それを記録し、NavPutFileを実行後に残さないといけない。データを残す手段としては、もちろんNavPutFileの最後に指定するユーザデータを使う。ここではMyUserData2という構造体を定義して、選択された項目を記録するようにした。構造体もNewHandleで作り、初期値として、書類ファイルの形式を設定し、それをPutNavFileの引数として指定している。
Navigation Servicesからコールバックされるイベントプロシージャは、ここでは、myNavEventProc2関数として定義をした。以前から何度か紹介しているイベントプロシージャと同じようなものだ。ポップアップメニューが選択されたときには、イベントプロシージャの引数callBackSelecterの値が、定義定数のkNavCBPopupMenuSelectになる。case文でこの場合のプログラムを追加すればいいが、どのメニューが選択されたかがcallBackParam引数から得られるイベントレコードのwhenメンバに記録されている。ちょっとこれは分かりづらい仕様だ。通常、whenはイベント発生時刻を示すが、ポップアップメニューが選ばれた時には、NavMenuItemSpec構造体のmenyTypeというメンバに代入した値が、イベントプロシージャではイベントレコードのメンバwhenで得られるのである。その値を、ユーザデータの構造体にセットしておく。そうすれば、NavPutFileを終了後、ユーザデータの構造体を調べることで、選択したポップアップメニューの項目を知ることができるのである。

DoSaveAsCommandでは、NavPutFile実行後は、NavReplyRecordからダイアログボックスで指定したファイルとフォルダを取得し、ポップアップメニューで選択した項目に応じた処理を行っている。やはりカスタマイズを行うとプログラムはややこしくなると言えるだろう。
関連リンクInside Carbon: Navigation Services