Question

I have a view that implements UITextInput and I added support for undo. Right now each individual key stroke or backspace is recorded as an undoable event.

I know that I can group events and I can open an undo group with the first key stroke. But where would I go and close the group? If the group is open when the user shakes the device I get an exception. You cannot have an open group when doing undo.

I would somehow need to close the open group right before the NSUndoManager instance displays the action menu.

Do I need to subclass NSUndoManager to do that? Or does anybody have a smart idea how I get to close the typing undo group in time before the action?

Note: first responder does not resign when showing the undo actions.

Actually it looks to me like normal text input leaves the typing group somehow open, because if you cancel the undo/redo alert, then you can continue typing and all those keystrokes can subsequently be undone together.

I guess I don't understand when to group actions and whether and when you need to close a group.

Update: I found the following to be working: I have created a subclass of NSUndoManager that keeps track of the number of open groups. On -undo I'm closing all open groups to avoid the exception and then call [super undo]

#import "DTUndoManager.h"

@implementation DTUndoManager
{
    NSUInteger _numberOfOpenGroups;
}

- (void)beginUndoGrouping
{
    _numberOfOpenGroups++;

    [super beginUndoGrouping];
}

- (void)endUndoGrouping
{
    _numberOfOpenGroups--;

    [super endUndoGrouping];
}

- (void)closeAllOpenGroups
{
    while (_numberOfOpenGroups>0)
    {
        [self endUndoGrouping];
    }
}

- (void)undo
{
    [self closeAllOpenGroups];

    [super undo];
}

#pragma mark - Properties

@synthesize numberOfOpenGroups = _numberOfOpenGroups;

@end

Whenever a new operation begins, like changing paragraph style, I call [self.undoManager closeAllOpenGroups] which causes the undo group for the typing to be closed.

in the -deleteBackward: and -insertText: methods I know that a new typing block needs to be be started:

- (void)insertText:(NSString *)text
{
    DTUndoManager *undoManager = (DTUndoManager *)self.undoManager;
    if (!undoManager.numberOfOpenGroups)
    {
        [self.undoManager beginUndoGrouping];
    }

Now that is not too much extra code, but I was hoping to not having to work with my own subclass for DTUndoManager... so I'm open for suggestions.

Was it helpful?

Solution

My solution is contained in the update to the question.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top