Lazy undo for Arrays

  • Using a subclass of NSArrayController for a NSTableView and wishing to
    do the usual litany of edits on the array list, I was having trouble
    wrapping my brain around all the possible undo scenarios.  Being a strong
    believer in using the same hammer to pound most nails, I came up with a
    unified undo approach that may not be optimal, but seems to work quite well,
    with one exception.  For some reason, my attempt at restoring the undo
    selection isn't working although it works for do/redo.

        It works by first making two copies of the array which you want to edit
    -- editArray and undoArray.  You edit editArray, then replace all the
    elements of the original array with those from editArray.  For undo, you
    replace all the original array elements with undoArray's elements.  I also
    pass the the old and new selections.  Here is what I did:

    @interface RTPArrayController : NSArrayController
    {
        (...)

        NSArray* undoArray;    //    Temp array for undo memory
        NSMutableArray* editArray;    //    Temp array to edit
        //  Note that these could have been locals for each method.  It just
    seemed more efficient to use ivars and the "prepareForUndoRedo" method.
    }
    (+Accesors)

    @implementation RTPArrayController

    (...)

    - (void) prepareForUndoRedo
    {
        NSMutableArray* arrayToChange = (NSMutableArray*)[self arrangedObjects];
        [self setUndoArray:[arrayToChange copy]];    //    Temp array for undo
        [self setEditArray:[arrayToChange mutableCopy]];    //    Temp array
    which we will edit
    }

    - (void)changeArray:(NSArray*)changeArray
              withUndo:(NSArray*)memArray
              usingName:(NSString*)name
          newSelection:(NSIndexSet*)newSelects
          oldSelection:(NSIndexSet*)oldSelects
    {
        NSUndoManager* undo = [tableView undoManager];  //  There is an outlet
    to tableView.
        [[undo prepareWithInvocationTarget:self]changeArray:memArray
                                                  withUndo:changeArray
                                                  usingName:name
                                              newSelection:oldSelects
                                              oldSelection:newSelects];
        [undo setActionName:name];

        NSArray* arrayToChange = (NSArray*)[self arrangedObjects];
        [self removeObjects:arrayToChange];    //    Clear the array
        [self addObjects:changeArray];    //    Load new array
        [self setSelectionIndexes:newSelects];
    }

        //    This is a prototype for undoable methods
    - (void)whateverEditMethod {
        [self prepareForUndoRedo];
        NSIndexSet* oldSelects = [self selectionIndexes];

        //    Do your worst to the editArray here

        NSIndexSet* newSelects = whatever;  //    New selections

        [self changeArray:editArray
                withUndo:undoArray
                usingName:@"Whatever"
            newSelection:newSelects
            oldSelection:oldSelects];
    }
previous month september 2007 next month
MTWTFSS
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Go to today