ページ

2008年5月5日月曜日

rubberBand(その19)Undoの実装 / NSUndoManager

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

今度は拡大縮小と移動の Undo/Redo ができるようにする。

Cocoa には Undo用の強力なフレームワークが用意されていて簡単に実装できる。Undo時に適用するメソッドを NSUndoManager へ登録しておくと、Undoが呼ばれた時に自動的にそのメソッドが呼出される。プログラマは複雑なUndoの管理をする必要はなく、ただ復元の為のメソッドをNSUndoManagerへ登録するだけで良い。


その状態でユーザが Undoを実行すると NSUndoManagerが自動的に登録されたメソッドを自動的に呼出す。



RubberBandでの実装ポイントは2つ。

まず拡大縮小および移動直前に、現在の情報を NSUndoManager へ登録しておく。

- (void)mouseDown:(NSEvent*)event
{
NSUndoManager* undoManager = [self undoManager];
[[undoManager prepareWithInvocationTarget:self]
setRubberBandFrame:_rect];
:
}


上記だけでも Undoが効くようになるが Redoさせるには #setRubberBandFrame: の中でも NSUndoManager への登録が必要。この時、NSUndoManager は自ら Undo中なのか、Redo中なのかを認識している為、Undo/Redoどちらの用途でも同じメソッドが使える。
-(void)setRubberBandFrame:(NSRect)frame
NSUndoManager* undoManager = [self undoManager];
[[undoManager prepareWithInvocationTarget:self]
setRubberBandFrame:_rect];
:
}


これで Undo/Redo の実装は終わり。実に良くできている。なお #setRuberBandFrame: はUndo/Redo以外でも呼出されるため、このままだとまだ操作をしていない初期状態でも Undoが効いてしまう。そこで Undo/Redo 中かどうかの判断を入れておく。
 NSUndoManager* undoManager = [self undoManager];
if ([undoManager isUndoing] || [undoManager isRedoing]) {
[[undoManager prepareWithInvocationTarget:self]
setRubberBandFrame:_rect];
}



NSUndoManager には #setActionName: が用意されており、これを使うとメニューの Undo欄に表示するメッセージを指定することができる。
[undoManager setActionName:@"Resized rectangle"];




ソース:RubberBand-12.zip