PDA

View Full Version : Simple Undo and Bindings Problem




stadidas
Nov 15, 2007, 01:44 PM
Hi everyone,

I'm having a bit of an issue with the undo manager and bindings which I'm sure someone here can help me out with.
In my MyDocument class I have a reference to an instance of DocumentModel, which has the following attributes:


@interface DocumentModel : NSObject
{
double currentBalance;
double amountToSave;
double moneyToSpendPerDay;
double moneyToSpendPerWeek;

int weeksLeft;
int daysLeft;
int numberOfDays;

NSCalendarDate *endOfTermDate;

int saveCheckbox;

NSMutableArray *logEntries;
}



This instance of DocumentModel has an instance of NSObjectController bound to it. I then have an NSArrayController that I bind to the 'logEntries' key of the ObjectController, in order to control the logEntries MutableArray.
This is all working perfectly well. However, I wish to override the insert and remove methods of the NSArrayController, and in the process make use of undo / redo :


- (void)insertObject:(LogEntry *)newLog inLogEntriesAtIndex:(int)index
{
NSUndoManager *undo = [self undoManager];
[[undo prepareWithInvocationTarget:self]
removeObjectFromLogEntriesAtIndex:index];

NSString *undoText;
if(newLog.typeFlag == BALANCE_CHANGE_FLAG)
{
undoText = [NSString stringWithFormat:@"Balance Change"];
}
else
{
undoText = [NSString stringWithFormat:@"Add '%@'", newLog.transactionDescription];
}

if(![undo isUndoing])
{
[undo setActionName:undoText ];
}

[logEntries insertObject:newLog atIndex:index];
[self calculateBalanceAndBudget];
}

- (void)removeObjectFromLogEntriesAtIndex:(int)index
{

LogEntry *entry = [logEntries objectAtIndex:index];
NSUndoManager *undo = [self undoManager];
[[undo prepareWithInvocationTarget:self]
insertObject:entry inLogEntriesAtIndex:index];

NSString *undoText;
if(entry.typeFlag == BALANCE_CHANGE_FLAG)
{
undoText = [NSString stringWithFormat:@"Delete Balance Change"];
}
else
{
undoText = [NSString stringWithFormat:@"Delete '%@'", entry.transactionDescription];
}

if(![undo isUndoing])
{
[undo setActionName:undoText ];
}

[logEntries removeObjectAtIndex:index];
[self calculateBalanceAndBudget];
}


I have tried putting these methods in MyDocument and in the DocumentModel objects, but whenever I add an entry nothing is put in the undo manager.
If anyone can shed any light on the issue I would much appreciate it!



kainjow
Nov 16, 2007, 11:26 PM
Are you sure the NSUndoManager has been properly setup? What does [self hasUndoManager]; return?

stadidas
Nov 17, 2007, 06:18 PM
Are you sure the NSUndoManager has been properly setup? What does [self hasUndoManager]; return?

Hi Kainjow,

I put the following print statement in the insertObject method of DataModel:


NSLog(@"DataModel UndoManager: %@", [self hasUndoManager]);


which printed "*** -[DocumentModel hasUndoManager]: unrecognized selector sent to instance 0x1042c60" to the console. I take it from this that I have not got NSUndoManager correctly set up for this class. How would I go about doing this?

kainjow
Nov 18, 2007, 09:57 AM
Oops I thought your DocumentModel object was a NSDocument subclass. What about your [self undoManager] code. Can you post that?

stadidas
Nov 18, 2007, 11:03 AM
Oops I thought your DocumentModel object was a NSDocument subclass. What about your [self undoManager] code. Can you post that?

Ah no, MyDocument keeps a reference to an instance of DocumentModel. Calling [self undoManager] on DocumentModel returns:
*** -[DocumentModel undoManager]: unrecognized selector sent to instance 0x1044fa0

Is it an acceptable form of obtaining a reference to the document undoManager to just pass a reference to the DocumentModel object at creation from MyDocument. For example to have a variable named 'undoManager' in DocumentModel and then call

[documentModel setUndoManager:[self undoManager]];


from MyDocument?

kainjow
Nov 18, 2007, 11:44 AM
Ok I'm confused then.

In your original post, where are those methods being used? MyDocument or DocumentModel? If MyDocument, then the undoManager methods are fine since NSDocument maintains its own NSUndoManager, but you probably need to make sure setHasUndoManager: returns YES first. If you're calling them in DocumentModel, it will not work unless you have an undoManager method defined.

stadidas
Nov 18, 2007, 12:34 PM
If you're calling them in DocumentModel, it will not work unless you have an undoManager method defined.

They are being called in DocumentModel. I have now added NSUndoManager *undoManager to DocumentModel, and pass it an undoManager from MyDocument like this:


documentModel.undoManager = [self undoManager];


I have edited the insert and remove methods to use this undoManager reference and it all works now, Cheers for your help, you've been very handy as always.