How can I make NSUndoManager's undo/redo action names work properly?
Remember: when you are redoing, your code must set an actionName for the Undo menu item.
When you are undoing or redoing, the actionName in the Redo menu item is set automatically.
setActionName:
changes the Undo menu item only. The Redo menu item actionName is automated.
When you initially setActionName:
when ![[self undoManager] isUndoing]
, this actionName goes to the Undo menu item. When then you choose to Undo ([[self undoManager] isUndoing] == YES
, no actionNames are set by you) the undoManager automatically sets this actionName to the Redo menu item and the previous undo actionName to the Undo menu item. When you then choose to Redo, you still have to pass an actionName to go to the Undo menu item.
In other words: you have to set actionNames only when your code is not Undoing (but you must set when initially invoked or is redoing).
After looking at some sample code, I was able to fix this by adding a condition to the setActionName: calls in each method, like this:
if (![[self undoManager] isUndoing])
[[self undoManager] setActionName:@"Turn On Label"];
I'll give the correct answer to whoever can explain why NSUndoManager needs me to do this.
Because your turnOnLabel: method can be invoked three possible ways:
1) when the control that the selected is associated with is performing its target/action sequence (i.e., the NSUndoManager isUndoing and isRedoing methods would return NO)
2) when you are performing an undo operation, and the turnOnLabel: method is actually being invoked by the NSUndoManager (i.e., isUndoing = YES and isRedoing = NO)
3) when you are performing a redo operation, and the turnOnLabel: method is actually being invoked by the NSUndoManager (i.e., isUndoing = NO and isRedoing = YES)
isUndoing isRedoing Action
-------------------------------------------------
0 0 Turn On Label
0 1 Turn On Label
1 0 Turn Off Label
1 1 <impossible state>