Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement undo with NSTextview

I want to implement undo action after replacing portion of text in an NSTextView. I am replacing portion of text with following code

- (void)omeAction
{
    NSString *fullString = [self.textView string];
    NSRange selectedRange = [self.textView selectedRange];
    NSString *selectedString = [fullString substringWithRange:selectedRange];

    NSString *stringToReplace = ...;
    [[self.textView textStorage] beginEditing];
    [[self.textView  textStorage] replaceCharactersInRange:selectedRange withString:stringToReplace];
    [[self.textView textStorage] endEditing];
}

While performing undo I couldn't really undo the text replacement

like image 773
Johnykutty Avatar asked Aug 31 '14 10:08

Johnykutty


2 Answers

From Cocoa Text Architecture Guide: Text Editing – Text Change Notifications and Delegate Messages:

In actually making changes to the text, you must ensure that the changes are properly performed and recorded by different parts of the text system. You do this by bracketing each batch of potential changes with shouldChangeTextInRange:replacementString: and didChangeText messages. These methods ensure that the appropriate delegate messages are sent and notifications posted. …

In my experience, that includes generating the relevant undo operation.

So, you would do:

if ([self.textView shouldChangeTextInRange:selectedRange replacementString:stringToReplace])
{
    [[self.textView textStorage] beginEditing];
    [[self.textView textStorage] replaceCharactersInRange:selectedRange withString:stringToReplace];
    [[self.textView textStorage] endEditing];
    [self.textView didChangeText];
}
like image 200
Ken Thomases Avatar answered Nov 08 '22 22:11

Ken Thomases


First I tried to solve undo and shouldChangeTextInRange:replacementString: did the trick. However I found that insertText:replacementRange: had the same effect.

[self insertText:attributedString replacementRange:range];

Or:

if ([textView shouldChangeTextInRange:range replacementString:string]) { //string
  [textStorage beginEditing];
  [textStorage replaceCharactersInRange:range withAttributedString:attributedString];
  [textStorage endEditing];
  [textView didChangeText];
}
like image 25
Marek H Avatar answered Nov 08 '22 22:11

Marek H