goo blog サービス終了のお知らせ 

Hironytic Status

ひろんの開発日誌

[CoveredCalc] 例外からのエラーメッセージを取得を修正中

2005-01-28 22:37:26 | 開発状況
BeOS 版もひとまず公開できたので、前々から設計が気になっていた部分を修正中です。
それは、期待した処理が行えなかったときに発生する「例外」オブジェクトに対応するエラーメッセージを取得する部分です。

まず、例外オブジェクトの構造はクラス図にするとこんな感じになっています。
すべて Exception というインタフェースを実装したかたちで例外の種類ごとにクラスがあります。
図には書いていませんが、Exception を実装する各クラスには、そのクラスに特化したメソッドも持っています。
たとえば、XML ファイルの解析中に発生する例外クラス XMLParseException は、例外の発生した行を得るための GetLine() を持っています。

ここで、Exception には GetErrorMessage() があるのですが、これは必ずしもユーザにお見せできるようなものではありません。また、将来、多言語対応を考えているのですが、言語によるエラーメッセージの切り替えを各例外クラスの中で行いたくはありません。
そこで、ExceptionMessageResolver というものを導入しました。クラス図にするとこんなものです。これだけではわかりにくいので、オブジェクト図も一緒に見てください
ExceptionMessageResolver は Resolve() に渡された例外を見て、自分の知っているものなら対応するエラーメッセージを返します。
たとえば、MemoryExceptionMessageResolver は、渡された例外が MemoryException なら「メモリが不足しています」というようなメッセージを返します。
利用する側では、ExceptionMessageResolver の集団に対して、その 1 つ 1 つに「この例外知ってたらメッセージをちょうだい」とお願いしていきます。メッセージをもらえればそれをユーザに表示するわけです。

さて、XMLParseExceptionMessageResolver は CoverDefParseException を渡されたとき、それを XMLParseException だと判断して「XML ファイルの解析に失敗しました」のようなエラーを返しますが、本当は CoverDefParseException なんだから、そこは CoverDefParseExceptionMessageResolver に任せてもっと細かいメッセージをもらいたいものです。
そこで、XMLParseExceptionMessageResolver はまず CoverDefParseExceptionMessageResolver に処理を頼んで、解決できなかったときだけ自分が解決しようとします。そのための仕組みが ChainedExceptionMessageResolver で、あらかじめ登録されたものに処理をお願いできるようにしてあります。
オブジェクト図では各クラスオブジェクトがどういう関係で登録されているかわかるようにしています。
また、この仕組みを使って、1 つ 1 つのオブジェクトに「これ知ってる?」って聞いてまわるだけのやつも作りました。
オブジェクト図で allInOne という名前のついた HandsOffExceptionMessageResolver のオブジェクトです。
こいつは人に頼むばっかりで自分は何も解決しません。

さらに C++ なので誰かがこれらのオブジェクトの寿命を管理してやる必要があります。
そこで、すべての ExceptionMessageResolver オブジェクトの寿命は ExceptionMessageResolverStorage が管理してやることにしました。
欲しいオブジェクトの取得も Get でできます。たとえば、ある例外がすでに XMLParseException だとわかっているなら、allInOne を使う必要はなくて、直接 XMLParseExceptionMessageResolver のオブジェクトを使えばいいのです。
そして、この storage くんが makeStorage() というメソッド内で各オブジェクトの主従(?)関係を登録しています。

こういう設計にしたところ、非常に大きな問題が目の前にのしかかってきました。
1 つ例外を作ろうと思ったらえらく面倒なのです。
その例外に対応する Resolver クラスを用意して(これが面倒)、ExceptionMessageResolverStorage::makeStorage() でその Resolver を生成して、場合によっては主従関係の登録をしなおして、さらに ExceptionMessageResolverStorage::Get() でその Resolver をもらえるように、Resolver の種類を表す列挙型(EMRSClass)を追加しなければいけません。
こういうのを「懲りすぎ」といいます。全くもって無駄に複雑になっています。考えなしに作るとこうなります。
割と早いうちにうすうす気づいてはいたのですが、さっさと動くものを作りたかったこともあって、そのままがんばってました。
Windows と BeOS の両バージョンをとりあえずリリースできたので、これを大きく作り直しています。
単なる作り直しでしかないので、残念ながらここが作り直されてもユーザさんにはメリットはありません。すみません。

ExceptionMessageResolver(とその周辺クラス)にとってかわる新しい ExceptionMessageGenerator は全くもって単純なものです。クラス図はこんな感じ
見てのとおり、すべての例外をこのクラスがすべて扱います。たとえば、今まで XMLParseExceptionMessageResolver が行っていた機能は processXMLParseException メソッドが引き受けます。processXMLParseException メソッドはその中で processCoverDefParseException メソッドを呼んでいます。そうです。主従関係はここにハードコーディングされています。
だいたい、場合によって主従関係をが変えたくなることはまずないんです。これでいいやん!
それから、たとえそれが XMLParseExeption だとわかっていても、他の process~ を使わないといけない作りになりました。実際の例外は、XMLParseException のサブクラスが数個、CoverDefParseException のサブクラスが数個というように細かい例外ごとに 1 つクラスを作っているので全部比較していたら遅いんですが、そんなことはしませんから。そのためにクラスを階層化してあるんであって、親クラスの例外でなければ、それより下のクラスの例外ではないのでたどる必要はありません。
それなら、せいぜい、数個~十数個の比較で、処理できるはずで、そんなに時間がかかる処理でもないからこれでいいやん!

ということで、BeOS 版の公開でふぬけになってさぼっているわけではありません(笑)
一応、やってますよ、ということで。
まあ、玄箱いじったりしてて開発止まってた時期があったのは確かですけど(ぉ

[CoveredCalc] バグ修正と BeOS 版

2005-01-03 22:58:12 | 開発状況
昨日の晩、MIY ちゃんとチャットで話していて、カバー切り替え時に画像ファイルが見つからないなどのエラーが発生した場合、そのまま終了すると、次回起動時にエラーメッセージが出て二度と起動できなくなることがあるというバグ報告を受けました。

見た目は切り替え前のカバーになっていますが、内部的にはエラーが発生する切り替え後のカバーに変更されている様子。それが 1 つ目のバグ。で、2 つ目のバグとして、前回のカバーが読めなくなっている状態の場合に二度と起動できないというのも関係しています。まあ、後者は既知の不具合なのですが、プログラムの構造を変更する必要があって、現在 BeOS 版を作ってることもあり、そっちができてから直そうと思ってるものです。

そういうわけで、1 つ目のバグをなんとか修正しました。
でもまだわけあってリリースはしていません。

さて、BeOS 版の方ですが、カバーブラウザのリストのダブルクリックでカバーが切り替わらないという点が Windows 版と異なっていますが、それ以外では(正常系の動作なら)ひととおり実装できたと思っています。
エラー処理になるとちょっと怪しいんですが、それはまあ Windows 版も同じということで(爆)
BeOS 版も近いうちに初回リリースができるかなと思っています。

[CoveredCalc for BeOS] アバウト

2004-12-19 23:18:58 | 開発状況
今日は嫁さんと子供たちが出かけてくれて、ぼくに休みをくれました。
それを利用して一気に About(バージョン情報)ダイアログを実装しました。

今日だけではなく、少し前からちょっとずつ実装していたんですが、BTextView、画像のリソース埋め込みとそれを描画する部分、バージョンのリソースからの取得と、初めて体験することが多くて方法を調べるのに手間取りました。
それから、Windows はモーダルダイアログ(ダイアログを閉じるまで動作が止まる)で実装しているんですが、BeOS ではモードレス(ダイアログを出したまま他の操作ができる)が一般的なのでそういう作りにしています。
そのあたりがソースの共通化を妨げかねないところですが、About ダイアログにあまり機能がないので今のところごまかせている感じです。

[CoveredCalc for BeOS] フォント

2004-12-07 00:39:41 | 開発状況
昨日の「登録されているカバーの一覧:」に Plain Font が設定されていない件について調べました。

どうやら、リソース中には、ビューのフォントとしてリソース作成時の Plain Font の名前・サイズが入っているみたいです。
つまり、リソース作成時に Plain Font と指定したら、その時の Plain Font でビューが作られて、それをアーカイブしたら、その時の Plain Font が入ったと。当然か。

ボタンなんかは、Plain Font 以外のフォントを指定してても、Plain Font が強制的に使われるってことなんでしょうか。
よくわからないですが、そうだとしても不思議はありません。
とにかく、ダイアログ初期化時に全てのビューに Plain Font を設定してやるようにしました。

[CoveredCalc for BeOS] ダイアログの大きさ

2004-12-06 03:24:49 | 開発状況
InterfaceElements でダイアログをデザインするときにフォントについては plain font を使うように指定しています。実行時にはユーザが(システムの設定で)指定したフォントが使われるので、フォントの大きさによってはボタンなどの文字列がコントロールの矩形をはみ出してしまう恐れがあります。
InterfaceElements に付いてくる IE Library を使っていれば、デザイン時のフォントサイズ(InterfacceElements が一緒にアーカイブしてくれる)と実行時のフォントサイズを比べて、ウィンドウとビュー(各コントロール)をスケーリングしてくれるのですが、残念ながら CoveredCalc は IE Library を使っていません。
そこで、IE Library でやっているのと同等の処理を実装してやりました。

実験してみたところ、ちゃんとスケーリングはされてるようです。(左:Haru 12、右:Haru 9)
でも、「登録されているカバーの一覧:」のフォントが変わってないのはなんでだ!?
これまで、フォントサイズを変えてみたことがなかったんですが、スケーリング処理とは関係ないはず。調査せねば…。

[CoveredCalc for Windows] 1.0.2 をリリース

2004-11-29 13:40:04 | 開発状況
今回は(修正が)簡単な不具合をなおしました。

実は今回なおした不具合は 桝田道也さんが作ってくださったカバーを会社で使っていて気づいたものだったりします。
#全く関係ないですが、桝田さんの浅倉家騒動記はかなり笑えておすすめです。

これまでにリリースしたバージョンのバージョン番号がむちゃくちゃですね。
1.00 → 1.00.1 → 1.0.2

これからは、1.0.2 つまり、<メジャーバージョン>.<マイナーバージョン>.<リビジョン> の形式で統一します。(リビジョンはない場合もあります)
これは BeOS 版のことを考えた結果です。
メジャーバージョン、マイナーバージョンは実装される機能の仕様に変更や追加・削除があったときに変えます。
リビジョンはバグ修正だけで仕様に変化がないときにつけます。
つまり、Windows 版でも BeOS 版でも、例えば 1.1.x なら 1.1 の仕様を実装したものということです。
なので、もしかしたら、BeOS 版の初回リリースは 1.1 になる可能性もあります。
今のところ、BeOS 版の 1.0 (Windows 版の 1.0.x の機能を実装)を出すつもりなのでその予定はありませんが。

[CoveredCalc for BeOS] BColumnListView

2004-11-11 00:59:20 | 開発状況
カバーブラウザのリスト部分の色(BColumnListView のデフォルト設定色)が気に入らなかったので修正してやることにしました。
ところがやってみてわかったんですが、BColumnListView::SetColor() で色を設定しても全く反映されないものとかあるんですよね。選択テキストの色とかはソース上で全く使われていません。
まあ、作りかけの状態で終わってしまったんだと思うので仕方ないと言えば仕方ないのですが。

BColumnListView は Haiku OS の CVS レポジトリからとってきたものをそのまま手を加えずに使おうと考えていたんですが、やっぱり手を加えることにしました。
修正はしましたが、CoveredCalc の使い方で不都合があったところだけ。
それに修正方法も、周辺のコードを見て適当にやったので正しいのかどうか。(^^;

あと、まだ修正してないんですが、横方向にスクロールしたときに選択部分の描画が少し変です。
どうも、ビューの左端からビューの範囲(すなわちスクロールバーを左端に持って行ったときに表示される範囲)だけに何かやってる感じがします。

とりあえず、今回の修正点:
(CoveredCalc の Subversion リポジトリでとった差分。revision 201 が Haiku OS からとってきたオリジナルです。エディタか何かにコピペしないと意味不明かも…)
Index: ColumnListView.cpp
===================================================================
--- ColumnListView.cpp  (revision 201)
+++ ColumnListView.cpp  (revision 202)
@@ -2559,12 +2559,17 @@
   #if DOUBLE_BUFFERED_COLUMN_RESIZE
               fDrawBuffer->Lock();
               if (row->fNextSelected != 0) {
-                   if(fEditMode) {
-                       fDrawBufferView->SetHighColor(fMasterView->Color(B_COLOR_EDIT_BACKGROUND));
-                       fDrawBufferView->SetLowColor(fMasterView->Color(B_COLOR_EDIT_BACKGROUND));
+                   if (Window()->IsActive()) {
+                       if(fEditMode) {
+                           fDrawBufferView->SetHighColor(fMasterView->Color(B_COLOR_EDIT_BACKGROUND));
+                           fDrawBufferView->SetLowColor(fMasterView->Color(B_COLOR_EDIT_BACKGROUND));
+                       } else {
+                           fDrawBufferView->SetHighColor(fMasterView->Color(B_COLOR_SELECTION));
+                           fDrawBufferView->SetLowColor(fMasterView->Color(B_COLOR_SELECTION));
+                       }
                   } else {
-                       fDrawBufferView->SetHighColor(fMasterView->Color(B_COLOR_SELECTION));
-                       fDrawBufferView->SetLowColor(fMasterView->Color(B_COLOR_SELECTION));
+                       fDrawBufferView->SetHighColor(fMasterView->Color(B_COLOR_NON_FOCUS_SELECTION));
+                       fDrawBufferView->SetLowColor(fMasterView->Color(B_COLOR_NON_FOCUS_SELECTION));
                   }
               } else {
                   fDrawBufferView->SetHighColor(fMasterView->Color(B_COLOR_BACKGROUND));
@@ -2603,7 +2608,11 @@
                   fDrawBufferView->ConstrainClippingRegion(&clipRegion);
                   fDrawBufferView->PushState();
       #endif
-                   fDrawBufferView->SetHighColor(fMasterView->Color(B_COLOR_TEXT));
+                   if (row->fNextSelected != 0) {
+                       fDrawBufferView->SetHighColor(fMasterView->Color(B_COLOR_SELECTION_TEXT));
+                   } else {
+                       fDrawBufferView->SetHighColor(fMasterView->Color(B_COLOR_TEXT));
+                   }
                   float baseline = floor(fieldRect.top + fh.ascent
                                           + (fieldRect.Height()+1-(fh.ascent+fh.descent))/2);
                   fDrawBufferView->MovePenTo(fieldRect.left + 8, baseline);
@@ -2614,7 +2623,7 @@
       #endif
               }
   
-               if (fFocusRow == row) {
+               if (fFocusRow == row && fMasterView->IsFocus() && Window()->IsActive()) {
                   if(!fEditMode) {
                       fDrawBufferView->SetHighColor(0, 0, 0);
                       fDrawBufferView->StrokeRect(BRect(-1, sourceRect.top, 10000.0, sourceRect.bottom - 1));
@@ -2812,7 +2821,10 @@
                           ConstrainClippingRegion(&clipRegion);
                           PushState();
#endif
-                           SetHighColor(fMasterView->Color(B_COLOR_TEXT));
+                           if (row->fNextSelected != 0)
+                               SetHighColor(fMasterView->Color(B_COLOR_SELECTION_TEXT));
+                           else
+                               SetHighColor(fMasterView->Color(B_COLOR_TEXT));
                           float baseline = floor(destRect.top + fh.ascent
                                                   + (destRect.Height()+1-(fh.ascent+fh.descent))/2);
                           MovePenTo(destRect.left + 8, baseline);

[CoveredCalc for BeOS] カバーブラウザ

2004-11-08 00:31:52 | 開発状況
カバーブラウザでカバーが切り替えられるようになりました。
BeOS 独特のウィンドウごとにスレッドが別というところにちょっと悩まされました。
具体的には、カバーブラウザからの操作(つまり、カバーブラウザのスレッド)で、メインウィンドウの状態を切り替えるので、メインウィンドウのロックが必要なのです。
そのロックをどこで行うか悩んでしまいました。

そもそも、メインウィンドウの状態が切り替わるんだから、カバーブラウザはメインウィンドウにメッセージを送ったりしてメインウィンドウ自身に処理を行わせたらいいような気もしてきたんですが、Windows との設計の共有もあるのでそれは少し難しいのです。
このあたりの設計をしたのはずいぶん前なので、自分自身、どうなってるのかいまいち覚えてないのですが(^^; だいたい流れとしてはカバーブラウザ→(カバー変更依頼)→カバー管理クラス→(カバー変更イベント発生)→ UI 管理クラスときて、UI 管理クラスが自分に結び付いた UI 操作インタフェース経由で UI を操作するのです。BeOS版の場合、UI 操作インタフェースを実装しているのがメインウィンドウ内に1つだけ存在するビュー(BBiew継承クラス)です。
そういうわけで、カバーブラウザは最終的にメインウィンドウが影響を受けるなんてことは知らない(知るべきでない)のです。で、結局は、UI操作インタフェースが OS 間の相違を吸収してるわけで、そのインタフェースを実装しているビューのそのメソッドでロックをかけるようにしました。

まだカバーブラウザのウィンドウタブのボタンを押すとブラウザが消えてしまうのを防がなければいけませんが、とりあえず少し進んだかな、と思います。

[CoveredCalc] 小数点のバグ発見!

2004-11-03 21:23:27 | 開発状況
JPBE.net の Koki さんに CoveredCalc を発見していただきました。
まだ BeOS 版は開発中なのですが、JPBE.net で紹介していただけるということです。

(Zeta を持っていないので)Zeta での動作を確認してもらうために現状のものを Koki さんに送る際に、R5 で一応動くことを確認していたら小数点が入力できない(ことがある)バグを見つけてしまいました。
例えば、[1.2+3.4] と入力すると、後の小数点が入力されず、[1.2+34] になってしまいます。
電卓のエンジン部分は BeOS でも Windows でも共通のソースファイルのはずなので、もしやと思い、すでにリリース済みの Windows 版でも実行してみるとやっぱり発生!(泣)

ということで、今日はこれからデバッグです。
Windows 版はリリースしちゃってますからね。さすがに致命的なバグですし…。

(23:00; 追記)
修正しました。
いったん小数点を入力して小数部分を入力しているときに、再度小数点が入力できるとマズいので、小数部分を入力しているかどうかのフラグを持たせていたんですが、そのフラグをクリアするのを忘れていました。とほほ。
というわけで、Windows 版はバージョンアップしました

[CoveredCalc for BeOS] カバーブラウザ

2004-10-22 00:18:38 | 開発状況
カバーブラウザの実装(といっても、BeOS用の差分だけ)を行っていたはずなのですが、本業が忙しくなって手が付けられていませんでした。

今日、少し時間ができたので、さて、何をしてるところだったけ?と subversion リポジトリの最後の更新を見てみると‥ 9月20日!?
そういえば、インストールされているカバーをファイルシステムから列挙するところを作れば一覧に出てくるはず、っていうところまで作っていたのでした。

そこをちょこっと実装したところ、たしかに一覧に出てくるようになりました。
でも、一覧に出てくるだけでその一覧を元にする操作はなにもできません。
なんだかな~。