Re: Giving names to undo actions
Re: Giving names to undo actions
- Subject: Re: Giving names to undo actions
- From: Graham Cox <email@hidden>
- Date: Thu, 22 Dec 2016 11:16:40 +1100
I believe NSUndoManager arguably works a bit incorrectly in this regard - I’ve just run into the same issue on one project.
When you register an Undo action, you set the action name. On an Undo or a Redo, because you’re invoking the ‘inverse’ operation which may also be a normal operation, it could set the action name to something else. I believe NSUndoManager should ignore that setting of the action name if it is currently in the middle of undoing or redoing tasks - instead it should copy the action name to the opposite stack so that the name remains as it was when it was first registered. However, it doesn’t - it accepts the new name so you get the weird naming that you are seeing.
It’s possible this has changed at some point because I don’t recall it behaving this way in the distant past.
On my main app project I use my own rewrite of NSUndoManager (GCUndoManager) which copies over the name on an undo or redo, which is why I only just noticed this behaviour in another project where I’m using NSUndoManager. In my case I’ll probably just adopt my own class, since I’m comfortable with its behaviour even when it deviates from the standard NSUndoManager.
In your case you have a couple of options. One is to test whether the method is being invoked by Undo or Redo by querying the undo manager at that point. If it’s undoing or redoing, you can avoid setting the action name, or can set it by copying the current one. If it’s not undoing or redoing, set the name as usual.
A better way to deal with it is to be more strict with your division of classes according to MVC. The registering of undo tasks themselves logically belong in the model - that’s the state that will need to be undone or redone. But setting the action name really belongs in the View (or Controller) - it’s something visible to the user that labels the undo or redo stack. So setting the action name in the model is not strictly correct. To reconcile this, usually there’s a high-level method (like an action method) that responds to the user’s input (e.g. a menu or button) which in turn calls methods on the model. The action name should be set in the action method only, and the model which implements the state shouldn’t do this. This will fix your problem. It’s possible that NSUndoManager’s behaviour has been implemented assuming this strict separation of View/Controller and Model.
As a bonus, one way to avoid hard-coding the Undo action names is to take them from the title of the sender of the intial action method. Unfortunately not all senders have a -title property, but buttons and menus do.
So putting this altogether into a contrived pseudo-example:
- (IBAction) myAction:(id) sender
{
[myModel toggleState];
[self.undoManager setActionName:sender.title];
}
…
- (void) toggleState
{
self.state = !self.state;
}
- (void) setState:(BOOL) state
{
[[self.undoManager prepareWithInvocationTarget:self] setState:_state];
_state = state;
}
—Graham
> On 21 Dec 2016, at 7:06 PM, John Brownie <email@hidden> wrote:
>
> I have undo working correctly in my macOS app, but I have a question about action names.
>
> The documentation tells you to set the name when registering the action on the undo stack. The correct name appears in the Undo menu item. The trouble is when you have symmetric actions, such as add and delete an item. You do an add, which puts the name "add" for the action. Undoing it is a remove, which sets the name "remove". Then you have "Redo remove" as the menu item, which isn't correct.
>
> It seems that the way to get around this is to set the action name only when you are actually doing the original action, and not when doing the undo version of it. Is that a correct interpretation? If so, how do you implement it? Do you test the NSUndoManager's undoing property and only set the name if it is NO?
>
> Any insights welcomed!
> John
> --
> John Brownie
> In Finland on furlough from SIL Papua New Guinea
_______________________________________________
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