Confused by grouping with NSUndoManager
Confused by grouping with NSUndoManager
- Subject: Confused by grouping with NSUndoManager
- From: Chris Trainor <email@hidden>
- Date: Thu, 27 Sep 2007 23:29:34 -0400
I am having trouble getting NSUndoManager to behave the way I want it
to. I want to group some actions together so that when the user
selects Undo, all those actions are undone at the same time.
However, it isn't as easy as just wrapping the set of actions in
calls to beginUndoGrouping and endUndoGrouping, since the set of
actions is not fixed. What I want to do is analogous to how most
text editors work. (My app has nothing to do with editing text.
This is just a convenient analogy to use.)
Undo works on word boundaries in most text editors. For example, if
I type "foo bar" then Undo, the word "bar" will be removed. Undoing
again will remove the entire word "foo." However, editors can also
undo partial words. If I type "foo ba" then Undo, the partial word
"ba" will be removed. My thinking was that the code for that would
work something like this:
User types "f" - beginUndoGrouping is called to start a new group.
prepareWithInvocationTarget is called with a selector to remove the
letter
User types "o" - prepareWithInvocationTarget is called with a
selector to remove the letter
User types "o" - prepareWithInvocationTarget is called with a
selector to remove the letter
User types a space - prepareWithInvocationTarget is called with a
selector to remove the letter. This is a word boundary, so
endUndoGrouping is called to group the entire word together.
User types "b" - there is no open group, so beginUndoGrouping is
called to start a new group. prepareWithInvocationTarget is called
with a selector to remove the letter
User types "a" - prepareWithInvocationTarget is called with the
selector to remove a letter
User selects Undo - here is where the trouble starts.
Apparently because the group wasn't closed, I am getting this error:
NSUndoManager 0x3ef3b0 is in invalid state, undo was called with too
many nested undo groups
The documentation (which I just updated to be sure) has this
description for the NSUndoManager undo method, "Closes the top-level
undo group if necessary and invokes undoNestedGroup." The Discussion
section for the method says "This method also invokes endUndoGrouping
if the nesting level is 1."
The setGroupsByEvent: method says this, "The default is YES. If you
turn automatic grouping off, you must close groups explicitly before
invoking either undo or undoNestedGroup." I am not changing the
default setting and I have verified that it is set to YES.
The documentation seems to be saying that what I did in the pseudo-
code above should work. I can open a group, do some things, then the
undo method should close the group for me. This does not appear to
be what is happening.
I have tried several ways to work around this. I registered for
NSUndoManagerWillUndoChangeNotification, hoping to close the group
just before the undo method was called. Unfortunately, the exception
happens before the notification is posted and I still get the error.
I derived my own class from NSUndoManager and overrode the undo and
undoNestedGroup methods so that they closed any open groups by
calling endUndoGrouping. This got rid of the error I was getting,
but I ran into another problem. My document no longer accurately
kept track of its dirty state. Even after undoing all the actions
that were done, the document still said it needed to be saved.
If the NSUndoManager subclass is the right way to go, then I will try
to fix the dirty flag problem. However, it doesn't seem like I
should have to do this, since the documentation explicitly says that
it is already doing it.
Either I am misunderstanding the documentation or missing something
else.
Any ideas?
Thanks
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden