タイトル小池邦人のプログラミング日記》2001/5/18<Navigation Service 3.0を使う その2>カテゴリーユーザインタフェース, 小池邦人のプログラミング日記
作成日2001/5/18 13:56:2作成者新居雅行
今回から、自作Carbonアプリケーションのソースコードを参考にしながら、Navigation Service 3.0の実装方法についての解説を始めたいと思います。まずは、Sheet Windowにアラートを表示することから挑戦してみます。

さて、前回取り上げた「フォントパネルの謎」について、何人かの読者の方からメールが届きました。みなさんのご協力に感謝いたします。結論としては、現状ではCarbon環境からフォントパネルを利用することはできないようです(涙)。アプリケーションを使うユーザの混乱を避けるためにも、ユーザインターフェースと深く関わる機能については、CocoaでもCarbonでも同じように使えるようAppleに要望したいと思います。さて、今回の「謎」は「ダイアログのインライン対応Text Editで、未変換を示すアンダーラインを表示するにはどうしたら良いのか?」です。ダイアログのテキスト入力カラムの幅は18ピクセルにしろと、Aquaガイドラインでは指示しています。ところが、カラムをこの幅に設定すると、インライン変換中のアンダーラインがはみ出して、ユーザには見えなくなってしまうのです。(文字の高さが18ポイントもある?)

通常、システムが文字入力時に利用しているフォントサイズは14ポイントのようです。これを12ポイントに変えれば直るのかと思ったのですが、アンダーラインが表示されないのに加え、文字の入力位置がどんどんズレていくという現象まで出てしまいました。

 

ところが、システムが用意しているファイル保存ダイアログや「システム環境設定」のテキスト入力カラムでは、フォントサイズが12ポイントでも14ポイントでも、ちゃんとアンダーラインが表示されます。(ファイル保存ダイアログでは、たまに表示されない時がある?)

 

以前、Appleに、Mac OS XのModal Dialogではインライン用テキスト入力コントロール(kControlEditTextInlineInputProc)が利用できないことを報告したら、「それは使わないでくれ」という返事が来たことがありました。結局これは、Mac OS XではModal Dialogを使うなと言う暗黙の圧力なのでしょうか(笑)。ただし、Modeless Dialogで上記のコントロールを使った場合でも、インラインは可能でもアンダーラインが表示されないのは同じでした。今まで何も気にせずに使えていたことが、突然利用できなくなるのは悲しいものです(涙)。

気を取り直してNavigation Service 3.0の解説に移りましょう。Navigation Service 3.0には、Sheet Windowに表示できるアラートが2種類あります。ひとつは、編集済みドキュメントウィンドウを保存せずに閉じようとした時に用いるアラートです。アラートには「保存しない」「キャンセル」「保存」の3つのボタンがあり、次の処理の判断をユーザに促します。ウィンドウが単独で閉じられる時と、作業終了で閉じられる時では、注意文として異なる内容を表記をすることができます。

 

もう一つは、ファイルメニューの「復帰...」で、現在のドキュメント内容を前回保存した状態に戻す時に用いるアラートです。

 

比較のために、昔のNavigation Service APIを使った両アラート表示ルーチンを示しておきます。前者を表示するのがnavSaveAlert()で、後者を表示するのがnavRevertAlert()です。

 

旧方式は、NavGetDefaultDialogOptions()で得たディフォルトNavDialogOptions構造体にドキュメント名やアプリケーション名を代入し、NavAskSaveChanges()またはNavAskDiscardChanges()を呼ぶだけの簡単な処理です。NavAskSaveChanges()の場合には、閉じる時なのか作業終了なのかで、NavAskSaveChangesAction(act)に設定するパラメータを切り替えます。もしアプリケーションがCarbon Event Modelに対応していれば、この時のNavEventUPPルーチン(nav_eventUPP)では何もする必要はありません。ただし、ここにNULL(ゼロ)を渡すと、ダイアログがMovable(移動可能)ではなくなってしまうので注意してください。NavAskSaveChanges()やNavAskDiscardChanges()は、ユーザがどのボタンをクリックしたのかを番号で返してきます(OKなら1番、キャンセルなら2番)。よって、その値を確認して処理を振り分けてやればOKです。

今度は、新方式の方を紹介します。ファイル保存を確認するアラートを表示しているのがnavSaveAlertX()です。

 

NavGetDefaultDialogCreationOptions()でディフォルトNavDialogCreationOptions構造体を得て、必要なパラメータを各メンバーに代入します。ドキュメント名やアプリケーション名はパスカル文字列ではなくCFStringCreateWithPascalString()を使い、Unicode文字列を示すCFStringRefに変換してから代入します。構造体のpreferenceKeyメンバーには親ウィンドウのWindowRefを、modalityメンバーには「kWindowModalityWindowModal」を代入すれば、このアラートは親ウィンドウのSheet Windowに表示されます。

NavCreatePutFileDialog()でダイアログを作成し、返されたNavDialogRef(dpr)をNavDialogRun()に渡すと、アラート表示が開始されます。旧ルーチンと大きく異なる点は、新方式ではアラートを表示したまま処理から抜け出てしまうことです(ボタン番号は返らない)。よって、ユーザがどのボタンをクリックしたのかを確認し、それに対する処理を実行するのは、NavCreatePutFileDialog()に設定されているNavEventUPPルーチン(nav_alertEventUPP)内となります。この時、NavCreatePutFileDialog()のinClientData(ユーザが自由に利用できる引数)には、親ウィンドウをのWindowRefを渡すようにしています。この手続きは、NavEventUPPルーチン内の処理で、親ウィンドウのWindowRefを使うために必要となります。

ドキュメント復帰を確認するためのアラートを表示しているのがnavRevertAlertX()です。

 

Navigation Service APIの使い方については、navSaveAlertX()とほとんど同じです。もう一度注意しておきますが、この両ルーチンは、Mac OS Xで利用した時にかぎり、Sheet Windowにアラートを表示します。これらをMac OS 9で使うと、アラート表示は普通のModal Dialogとなり、ユーザがどれかボタンをクリックするまでNavDialogRun()から抜け出してきません。つまり、旧方式とまったく同じ挙動を取るわけです。ちなみに、両ルーチンで使われている、setWNavFlag()、setWNavDref()、actControls()、disableQuitMenu() などは、Navigation Service 3.0を使いこなすために用意した自作ルーチンです。これらの目的や役割に関しては、次回以降に詳しく解説します。

続いて、両ルーチンで共有しているNavEventUPPのnavAlertEventProc()ルーチンを紹介しておきます。

 

navAlertEventProc()のエントリーポイントは、アプリケーション開始時に、以下のようにnav_alertEventUPPに代入しておきます。

 nav_alertEventUPP=NewNavEventUPP( navAlertEventProc );

navAlertEventProc()では、アラートのNavDialogRefはcallBackParms->contextに、親ウィンドウのWindowRefはcallBackUDに入っており、それぞれを簡単に参照することができます。引数で得たcallBackSelectorがkNavCBUserActionと一致すれば、ユーザがアラートのボタンのどれかをクリックしたことになります。この時にcallBackParms->userActionも調べ、それが「kNavUserActionSaveChanges」と一致していれば、ファイル保存用アラートの「保存」ボタンが押されたことになります。同様に「kNavUserActionDontSaveChanges」なら「保存しない」ボタンが、「kNavUserActionCancel」なら「キャンセル」ボタンが、それぞれ押されたことになります。また、その値が「kNavUserActionDiscardChanges」であれば、今度は復帰用アラートの「OK」ボタンが押されたことになります。

また、callBackSelectorがkNavCBTerminateであれば、アラートが閉じられたことを意味します。よって、NavDialogDispose()によるアラート削除などの後処理を行います。クリックされたボタンが識別できれば、後は各ケースごとに適切な処理を実行してやればOKです。navAlertEventProc()のsaveImageWindow()はドキュメントのファイル保存を担当し、reloadImageWindow()はファイルからの復帰を担当しています。こうした処理や、getWNavFlag()で得ているフラグの意味と働き、後処理で実行しているsetWNavDref()やenableQuitMenu()などのルーチンについては、次回以降に詳しく解説したいと思います。

次は、いよいよ新方式のファイルオープンや保存ダイアログルーチンの解説に突入します。ただし、次回にかぎりNavigation Service 3.0の話しを中断し、今年のWWDC 2001のトピックスや印象についてまとめてみたいと思います。
[小池邦人/オッティモ]
関連リンクオッティモ