NSUndoManager implementing Redo

  • Hi,
    I am trying to add Undo and Redo in an application and am having trouble
    trying to implement redo. I have a mutable array that holds a data object.
    When I register for the undo I give it a selector of undoAddData: which is
    fine. The undo gets called but when I try redo neither the original method
    that was called where the undo was registered, nor the undoAddData: method
    are called.

    Which method should get called when performing a redo? Can I give the undo
    manager a different method?

    Any help or insight is greatly appreciate.

    Regards,
    Greg
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • On Friday, July 12, 2002, at 01:41 , Greg Hulands wrote:

    > Any help or insight is greatly appreciate.

    Here is what I'm doing in a setter method for example:

    - (void) setCurrentObject: (id) aValue
    {
    if ( [aValue isEqual: _currentObject] == NO )
    {
      if ( _currentObject != nil )
      {
      NSUndoManager* aManager = [self undoManager];

      [aManager beginUndoGrouping];
      [aManager setActionName: [_currentObject description]];
      [aManager registerUndoWithTarget: self selector:
    @selector(displayObject:) object: _currentObject];
      [aManager endUndoGrouping];
      }

      [_currentObject autorelease];
      _currentObject = [aValue retain];
    }
    }

    > Which method should get called when performing a redo?

    In your example: undoAddData.

    > Can I give the undo
    > manager a different method?

    For "redo"? No. They "both" use the same selector.

    PA.
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • Thanks for your reply.

    >
    >> Which method should get called when performing a redo?
    >
    > In your example: undoAddData.
    >

    It only calls undoAddData when undoing and not redoing. Any idea?

    Greg
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • Take a look of these 6 pages. Helped me, might help you !
        www.ex-cinder.com/downloads/undo-article.rtf

        Regards,
          Cristian

    > Subject: NSUndoManager implementing Redo
    >
    >
    > Hi,
    > I am trying to add Undo and Redo in an application and am
    > having trouble
    > trying to implement redo (.....)
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • on 02-07-11 7:41 PM, Greg Hulands at <ghulands...> wrote:

    > I am trying to add Undo and Redo in an application and am having trouble
    > trying to implement redo. I have a mutable array that holds a data object.
    > When I register for the undo I give it a selector of undoAddData: which is
    > fine. The undo gets called but when I try redo neither the original method
    > that was called where the undo was registered, nor the undoAddData: method
    > are called.
    >
    > Which method should get called when performing a redo? Can I give the undo
    > manager a different method?

    Yes, you can specify different methods for undo and redo. In an object
    deletion scenario, you petty much have to do it this way. For example, to
    add an object to a table view, I use three methods:

    1. The addObject method instantiates a new row object and records the
    deleteObject method as its undo action.

    2. The deleteObject method deletes the object and records the undeleteObject
    method as its undo action.

    3. The undeleteObject method restores the object and records the
    deleteObject as its undo action.

    So, the initial addObject method performs the instantiation task, sets up
    the undo action, and then drops out of the picture permanently. Undo and
    Redo then cycle back and forth between the deleteObject and undeleteObject
    methods. In this scenario, deleteObject acts as an Undo action and
    undeleteObject acts as a Redo action.

    An alternative execution path is that an existing object in the table view
    may be deleted by a button that calls the deleteObject method. In this
    scenario, undeleteObject acts as the Undo action and deleteObject acts as
    the Redo action, using the same code as in the first scenario.

    Each of the two methods "stores" the object on the undo or redo stack, so it
    always remains available for restoration, until you clear all undo actions
    (for example, when you save or close the document). This way, you don't have
    to go to the trouble of setting up your own cache of deleted objects waiting
    for possible restoration.

    --

    Bill Cheeseman - <wjcheeseman...>
    Quechee Software, Quechee, Vermont, USA
    http://www.quecheesoftware.com

    The AppleScript Sourcebook - http://www.AppleScriptSourcebook.com
    Vermont Recipes - http://www.stepwise.com/Articles/VermontRecipes
    Croquet Club of Vermont - http://members.valley.net/croquetvermont
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • On Friday, July 12, 2002, at 12:29 , Bill Cheeseman wrote:

    > Yes, you can specify different methods for undo and redo. In an object
    > deletion scenario, you petty much have to do it this way. For example,
    > to
    > add an object to a table view, I use three methods:

    Ummm... I'm a little bit confused about how one will go about doing such
    a thing?!?!? Care to elaborate?

      The NSUndoManager provides only one method:

    - (void)registerUndoWithTarget:(id)target selector:(SEL)selector
    object:(id)anObject;

    There are no real difference between undu and redo. So, short of messing
    around with beginUndoGrouping/endUndoGrouping and/or multiple
    NSUndoManager, what are you talking about exactly?

    Am I missing something obvious?

    Thanks.

    PA.
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • If you have a storage of objects that hold the data and you allow the user
    to delete "records", you have to be able to reinsert them into the array and
    reperform any checks.

    So you have

    - (void)createObject
    {
        register the undo method as undoCreateObject with object just created
    }

    - (void)undoCreateObject:(id)object
    {
        [myStorage removeObject:object];
        register the undo for deleting as redoCreateObject with object
    }

    - (void)redoCreateObject:(id)object
    {
        //run checks on object
        [myStorage addObject:object];
        register the undo for reinsertion as undoCreateObject with object
    }

    Greg

    On 12/7/02 9:31 PM, "petite_abeille" <petite_abeille...> allegedly made
    the following allegations:

    > On Friday, July 12, 2002, at 12:29 , Bill Cheeseman wrote:
    >
    >> Yes, you can specify different methods for undo and redo. In an object
    >> deletion scenario, you petty much have to do it this way. For example,
    >> to
    >> add an object to a table view, I use three methods:
    >
    > Ummm... I'm a little bit confused about how one will go about doing such
    > a thing?!?!? Care to elaborate?
    >
    >
    > The NSUndoManager provides only one method:
    >
    > - (void)registerUndoWithTarget:(id)target selector:(SEL)selector
    > object:(id)anObject;
    >
    > There are no real difference between undu and redo. So, short of messing
    > around with beginUndoGrouping/endUndoGrouping and/or multiple
    > NSUndoManager, what are you talking about exactly?
    >
    > Am I missing something obvious?
    >
    > Thanks.
    >
    > PA.
    > _______________________________________________
    > cocoa-dev mailing list | <cocoa-dev...>
    > Help/Unsubscribe/Archives:
    > http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    > Do not post admin requests to the list. They will be ignored.
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • On Friday, July 12, 2002, at 02:14 , Greg Hulands wrote:

    > If you have a storage of objects that hold the data and you allow the
    > user
    > to delete "records", you have to be able to reinsert them into the
    > array and
    > reperform any checks.
    >
    > So you have

    Ummm... I still don't get it :-( You mean you simply want to register
    multiple action for an undo, eg:

    [NSUndoManager beginUndoGrouping]

    [NSUndoManager registerUndoWithTarget: bla selector: @bla object: bla]
    [NSUndoManager registerUndoWithTarget: blaselector: @blabla object:
    blabla]

    [NSUndoManager endUndoGrouping]

    Is it what you are talking about? One way, or the other,
    registerUndoWithTarget has only one selector as there is no technical
    differences between undo/redo...

    On the other hand, if you are simply talking about adding object to an
    array or something, why not simply follow this "convention"? Eg:

    - (NSMutableArray) departements;

    - (void) addToDepartements: (id) aValue
    {
    [NSUndoManager registerUndoWithTarget: self selector:
    @removeFromDepartements object: aValue]
    }

    - (void) removeFromDepartements: (id) aValue
    {
    [NSUndoManager registerUndoWithTarget: self selector:
    @addToDepartements object: aValue]
    }

    Cheers,

    PA.
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • on 02-07-12 8:38 AM, petite_abeille at <petite_abeille...> wrote:

    > One way, or the other,
    > registerUndoWithTarget has only one selector as there is no technical
    > differences between undo/redo...

    In each of two methods in an array object addition and deletion scenario,
    the selector you register with the undo manager is the other method. In your
    DELETE method, the selector you register is ADD; in your ADD method, the
    selector you register is DELETE. Each method serves as the undo action for
    the other method, and each method serves as its own redo action.

    There is no rule in Cocoa that requires you to register the same method for
    undo and redo, although that is convenient when undo and redo toggle a
    simple data value back and forth between two states. When the action being
    undone and redone is more complex, you often have to resort to calling a
    pair of methods in alternation, one of which knows how to construct a state
    and the other of which knows how to deconstruct it -- for example, insertion
    and removal of objects in arrays. You could even chain multiple selectors to
    one another in a multi-state ring structure, if you wanted to, although this
    would depart from the "toggle" behavior underlying the undo/redo menu item
    concept.

    Most of the documentation and examples for implementing undo and redo use as
    their model a simple, reversible data state, where a single method can serve
    both as undo and redo action by passing alternating data states. For this
    reason, many people start out thinking that registration of undo actions
    *requires* that you register the same method each time, both for undo and
    for redo. Many people even go so far as to understand the underlying
    registration mechanism as somehow causing the method in which an undo action
    is registered to be replayed over and over again, with alternating data
    states being fed to the registration method each time. But it isn't so.

    Registration of a selector as an undo action causes *that selector* (call it
    selectorOne) to be called an Undo time. SelectorOne can be any method; it
    need not be the method in which it is registered, although it often is. At
    Undo time, the registered selectorOne will execute, and it will register
    whatever method it specifies as its undo selector (call it selectorTwo). At
    Redo time, the registered selectorTwo will execute, and it will register
    whatever method it specifies as its undo selector (call it selectorThree).
    And so on. Sometimes selectorOne, selectorTwo, and selectorThree are all the
    same method. Sometimes selectorOne and selectorThree are the same method,
    while selectorTwo (and selectorFour) are another method. And, theoretically
    at least, all of them could be different methods, presumably with selectorN,
    somewhere down the line, being the same method as selectorOne, in order to
    close the circle and allow it to be repeated.

    Another way of explaining this is that many people understand the
    documentation to say that it is only the data state that can be varied when
    an undo action is recorded. In fact, the selector can be varied instead (or
    in addition).

    > On the other hand, if you are simply talking about adding object to an
    > array or something, why not simply follow this "convention"? Eg:
    >
    > - (NSMutableArray) departements;
    >
    > - (void) addToDepartements: (id) aValue
    > {
    > [NSUndoManager registerUndoWithTarget: self selector:
    > @removeFromDepartements object: aValue]
    > }
    >
    > - (void) removeFromDepartements: (id) aValue
    > {
    > [NSUndoManager registerUndoWithTarget: self selector:
    > @addToDepartements object: aValue]
    > }

    This is exactly my original point. Except that a one-time-only method is
    required to instantiate the object aValue in the first place. You can't
    register this initial instantiation method as a redo method, because once
    you're into the undo/redo cycle the object aValue is already in existence
    and saved on the undo or redo stack. You don't want to instantiate another
    copy of it at Redo time.

    --

    Bill Cheeseman - <wjcheeseman...>
    Quechee Software, Quechee, Vermont, USA
    http://www.quecheesoftware.com

    The AppleScript Sourcebook - http://www.AppleScriptSourcebook.com
    Vermont Recipes - http://www.stepwise.com/Articles/VermontRecipes
    Croquet Club of Vermont - http://members.valley.net/croquetvermont
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.
  • On Friday, July 12, 2002, at 07:23 , Bill Cheeseman wrote:

    > This is exactly my original point.

    I see. I simply got confused by the "In each of two methods in an array
    object addition and deletion scenario,
    the selector you register with the undo manager is the other method"
    business... Bewilderingly,  I was cogiting  about *two* selector in the
    registerUndoWithTarget method...

    Sorry for the waste of bandwidth :-)

    Cheers,

    PA.
    _______________________________________________
    cocoa-dev mailing list | <cocoa-dev...>
    Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
    Do not post admin requests to the list. They will be ignored.