UNDO機能なしで動作することを検証する

UNDO機能なしの動作を検証するために,UndoRedo.h内のすべてのクラス定義を止めてビルドしたバージョンをテストしているところだが,実行時にFAMILYTREE:GetCardBaseで(PHASE < DRAWSTAGE)エラーが発生する.これは系統並び替えが実施されていないことを意味する.UNDOではサポートするすべてのコマンドの入口と出口でUNDOSYSTEM:CommandStartとCommandEndという関数を呼び出しているが,系図木に変化があった場合にはCommandEndで必ず系統並び替えを実行している.フェーズがDRAWSTAGEになっているということは,系統並び替えが実施されたことと同義だ.

GetCardBaseは,アプリの人名カード画面に表示するためのデータを取り出す関数で,この処理はフェーズに関わりなく実行可能なはずであるから,まず,ここでは停止しないようにしておこう.⇒今度は,TREEVIEW::GetScrollValueで同じエラーが発生する.GetScrollValueはアプリ側のCenteringCardSubから呼び出されている.ここでは図面のセンタリングを実行しようとしているのだから,その前に図面がレンダリングされている必要がある.⇒やや変則的だが,GetScrollValueから直接系統並び替えを実行できるようにしておこう.⇒これで問題は解決した.UI的にはUNDOシステムが搭載されていないので,カードを削除しても系図画面のツールバーのUNDOボタンは有効にならない.

これでUNDOとゴミ箱なしでもシステムが問題なく動作することを確認できた.TRASHCANはアプリケーションコードにまったく依存しないネイティブなnoduleクラスとして確立されたが,UNDOにそこまでのことを要求するのは無理がある.実際,UNDOを機能させるためにはアプリケーションコードのあちこちにUNDOSYSTEMのコードを埋め込む必要がある.(コードと言っても少数の特定関数を呼び出すだけだが…)問題はUNDOSYSTEM自体が(どの程度)アプリケーションに依存しているかという点だ.まず,この点を確認してみよう.

UNDOCOMMAND(a.k.a. UNDOCHAIN)にはもろにCARDLINKへの参照が4個設置されている.これについては後で考えるとして,暫定的にvoid*としておこう.⇒「暫定:UNDOSYSTEMの外部依存度@20201217」というマクロでコンパイルエラーを止めてビルドは通るようになったが,もちろんこのコードでは実行できない.「暫定:UNDOSYSTEMの外部依存度@20201217」は45箇所も入っている.満身創痍というところだ.今回はこれを一掃するところまでは目論んでいないのだが,何が可能か?考えてみよう.高度に抽象化されたUNDOシステムを想定することは可能だが,今日明日の課題ではない.

アプリケーションとUNDOシステムを切り離すための速攻的な措置を考えるとすると,アプリとUNDOの間にヘルパーないしサポートクラスのようなものを入れるということがまず考えられる.UNDOSYSTEMクラスを基本クラスと拡張クラスに分解し,基本クラスを完全にアプリから切り離すということも考えられる.これを実装するのはそれほど難しくないのでやってみることにしよう.ただし,その前に基本クラスや基本関数自体がアプリ依存になっているという問題がある.たとえば,UNDONODEクラスには最初からCARDLINKへの参照が入っているし,UndoProcessというUNDO処理関数まで余分な情報を必要としている.

int UndoProcess(bool redo, long &basenode, long &primary, short &lastcommand, TITLEINFO &titleinfo);

UNDONODEに入っているCARDLINK*はそれぞれ,①主選択カード,②現基準カード,③全体図基準カード,④部分図基準カードへの参照だ.系統並び替えなどを実施すると基準カードが変化するが,系統並び替えなどの操作はUNDOの保全対象となっていない.(その代わり系統並び替え履歴,主選択カード履歴で巻き戻しすることはできる)これらの情報は本来UNDOの守備範囲外なのだが,UNDO/REDOで再描画したときの画面を元の状態に近いものとして表示するためにはどうしてもこれらの情報を時系列で保全しておく必要がある.

それにしても,UNDONODEのような構成要素にその情報を持たせるというのは適切とは言えないが,便宜上このような仕様になってしまった.それどころか,UndoProcessの最後の引数であるTITLEINFOはアプリに現在の部分図タイトル情報を渡すという目的のためだけに設置されているようで,もしそれが本当ならかなりの手抜きというか,横着としか言いようがない.まず,この点を確認してみよう.

確かにそうなっている.TITLEINFOは下り方向でしか使われていない.宅急便の戻り脚に発送を依頼するというのはありとしても,これではまるきり,郵便屋さんに宅急便の荷物を預けるようなものだ… UndoRedoCommandを実行しているのはGCのmZelkova:mUndoRedoで,取り出したTITLEINFOはLastTitleというところに格納されている.TITLEINFOの取り出し関数ないしコマンドが見当たらない.TITLEINFORMATIONを取り出す関数はあるが,TITLEINFOとは内容が異なる.すべてのTITLEINFOを取り出す関数と現部分図エントリを取り出す関数を組み合わせれば目的は達成できそうだが,ここでは放置して動作を観察してみることにする.

▲mZelkova::mUndoRedoでTITLEINFOを更新する手段を導入する

UNDOCOMMANDに入っているCARDLINK情報は現状のままとして,UNDOSYSTEMを2階層に分解するというのをやってみよう.外部からはUNDOSYSTEMとして認識されているので,この名前を拡張クラス名として維持,基本クラスはUNDOBASEとしてみる.⇒実装した.

UNDONODE::RestoreShadowでLINKTABLEを参照している.これを避けるためにこの関数をUNDOSYSTEMに移管してみる.UNDONODE:UndoRestoreもUNDOSYSTEMに移管する.⇒一応動作しているようなのでバックアップを取っておこう.UNDOシステムにはUNDONODE,UNDOCOMMAND,UNDOBASE,UNDOSYSTEMの4つのコンポーネントがあるが,外部依存コードはUNDOSYSTEMが単独で扱うようになった.UNDOCOMMANDが持っていた4つのCARDLINK*はすべてlong整数に変えてカードの参照番号を格納するようにした.

UNDOSYSTEMのコードを少し整理してみよう.現在UNDOBASEは17個関数を持っているが,そのうちの6個はUNDOBASEで完結してUNDOSYSTEMでオーバーライドされないものだ.それ以外のものも,UNDOBASEの関数でカバーできるところはできるだけUNDOBASEの関数を呼び出すようにして,UNDOSYSTEMには外部依存部分だけが記述されるという体裁にしたい.

  1. BackupPointData 一部にはネイティブコードもあるが,ほとんどまるごと外部依存コード
  2. CommandStart UNDOBASEのコード+FAMILYTREE:SetUndoBase BackupPointDataは仮想関数とした
  3. UndoProcess ほとんど外部依存コード
  4. RestoreShadow オーバーライドは不要
  5. GetUndoStat UndoCurptr不在のときは,FAMILYTREE:SetUndoStat
  6. UndoRedoCommand ほとんど外部依存コード
  7. UNDOSYSTEM::CommandEnd UNDOBASE+外部依存コード

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA