Undo/redo for NSTextView appearing in a sheet dialog

  • Hi,

    I want to have a panel (sheet) that displays a NSTextView.  This text view
    is used to edit a (possibly long) block of descriptive text.  The problem is
    that I cannot figure out how best to get Undo/Redo working while the panel
    is open.  I don't want these undo/redo actions to be recorded against the
    NSDocument subclass instance that has presented the panel.

    I've read Bill C.'s Cocoa Recipes and lengths he has to go to to get
    undo/redo working for NSTextField seem overkill.  Is there some easier means
    of getting NSTextView to "do the right thing" in a panel?

    Cheers
    -Mark

    ---------------------------------------------------------------------
    Mark Alldritt                        Late Night Software Ltd.
    Phone: 250-380-1725                  333 Moss Street
    FAX:  250-383-3204                  Victoria, B.C.
    WEB:  http://www.latenightsw.com/    CANADA  V8V-4M9
  • on 2004-11-05 6:23 PM, Mark Alldritt at <alldritt...> wrote:

    > I want to have a panel (sheet) that displays a NSTextView.  This text view
    > is used to edit a (possibly long) block of descriptive text.  The problem is
    > that I cannot figure out how best to get Undo/Redo working while the panel
    > is open.  I don't want these undo/redo actions to be recorded against the
    > NSDocument subclass instance that has presented the panel.
    >
    > I've read Bill C.'s Cocoa Recipes and lengths he has to go to to get
    > undo/redo working for NSTextField seem overkill.  Is there some easier means
    > of getting NSTextView to "do the right thing" in a panel?

    Text _fields_ and text _views_ are different when it comes to undo/redo. The
    main difference is that you can simply turn on undo/redo in a text view in
    Interface Builder and it works, while you have to do something more in
    addition to that to make "live" undo/redo work correctly in a text field. My
    Recipe 7 was designed only to deal with the text _field_ problem.

    My Recipes 16 and 17 describe how to implement a text _view_ in a drawer,
    with undo/redo.

    However, keeping the text view's undo/redo separate from NSDocument's
    undo/redo may be a bit trickier. If I recall correctly, you will have to
    create a separate undo manager instance, similar to part of what Recipe 7
    describes.

    --

    Bill Cheeseman - <wjcheeseman...>
    PLEASE NOTE NEW E-MAIL ADDRESS!
  • > Text _fields_ and text _views_ are different when it comes to undo/redo. The
    > main difference is that you can simply turn on undo/redo in a text view in
    > Interface Builder and it works, while you have to do something more in
    > addition to that to make "live" undo/redo work correctly in a text field. My
    > Recipe 7 was designed only to deal with the text _field_ problem.
    >
    > My Recipes 16 and 17 describe how to implement a text _view_ in a drawer,
    > with undo/redo.
    >
    > However, keeping the text view's undo/redo separate from NSDocument's
    > undo/redo may be a bit trickier. If I recall correctly, you will have to
    > create a separate undo manager instance, similar to part of what Recipe 7
    > describes.

    Hi Bill,

    Thanks for the info.

    I have code that creates a new NSUndoManager for my text view, and I have a
    undoManagerForTextView: delegate method which is being called.  However, the
    Undo/Redo menu commands are never activated when the sheet is running.

    I originally was using the document's undo manager, and using some of your
    code examples to remove the undo/redo actions generated in the panel.
    Here's the code (variables starting with m are instance variables):

    @implementation DescriptionSheetController

    - (void) awakeFromNib
    {
        [mSheet setDelegate:self];

        [mText setDelegate:self];
        [mText setRulerVisible:YES];
        [mText setAllowsUndo:YES];
        [mText setRichText:YES];
    }

    - (void) dealloc
    {
        [mSheet release];
        [mUndoManager release];
        [super dealloc];
    }

    - (void) sheetDidEnd:(id) sheet returnCode:(int) returnCode
    contextInfo:(void*) contextInfo
    {
        [sheet orderOut:self];

        switch (returnCode)
        {
        case NSAlertDefaultReturn:
            {
                NSAttributedString* desc = [[[NSAttributedString alloc]
    initWithAttributedString:[mText textStorage]] autorelease];
                [mOwner setAttributedDescription:desc];
            }
            break;
        }
    }

    - (void) showSheet:(NSWindow*) owningWindow
    {
        [[mText textStorage] setAttributedString:[mOwner
    attributedDescription]];

        [[NSApplication sharedApplication] beginSheet:mSheet
                                      modalForWindow:owningWindow
                                        modalDelegate:self

    didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
                                          contextInfo:NULL];
        [mSheet makeFirstResponder:mText];
    }

    - (IBAction) doCancel:(id) sender
    {
        [[NSApplication sharedApplication] endSheet:mSheet
    returnCode:NSAlertAlternateReturn];
    }

    - (IBAction) doOK:(id) sender
    {
        [[NSApplication sharedApplication] endSheet:mSheet
    returnCode:NSAlertDefaultReturn];
    }

    //    NSTextView delegate methods

    - (NSUndoManager*) undoManagerForTextView: (NSTextView*) aTextView
    {
        if (!mUndoManager)
            mUndoManager = [[NSUndoManager alloc] init];

        return mUndoManager;
    }

    @end

    Cheers
    -Mark

    ---------------------------------------------------------------------
    Mark Alldritt                        Late Night Software Ltd.
    Phone: 250-380-1725                  333 Moss Street
    FAX:  250-383-3204                  Victoria, B.C.
    WEB:  http://www.latenightsw.com/    CANADA  V8V-4M9