Skip to content

Instantly share code, notes, and snippets.

@chadmoone
Created November 17, 2011 00:16
Show Gist options
  • Save chadmoone/1371970 to your computer and use it in GitHub Desktop.
Save chadmoone/1371970 to your computer and use it in GitHub Desktop.
Undo-Redo Idea
- (IBAction)createFrame:(id)sender
{
NSString *frameType = [frameTypeComboBox stringValue];
id newFrame = (NSManagedObject *)[NSClassFromString(frameType) createEntity];
[newFrame setValue:frameType forKey:@"frameType"];
[newFrame setValue:[[sectionObjectController content] valueForKey:@"identifier"] forKey:@"sectionID"];
[self addObjectToFramesArrayController:newFrame];
}
- (IBAction)deleteFrame:(id)sender
{
id selectedFrame = [[framesArrayController selectedObjects] lastObject];
[self removeObjectFromFramesArrayController:selectedFrame];
}
- (void)addObjectToFramesArrayController:(Frame *)f
{
void (^successBlock)(NSManagedObject *object) = ^(NSManagedObject *object) {
// If the remoting fails, the object is deleted, so only add to undo on success
// Register Undo
NSUndoManager *undo = [self undoManager];
[[undo prepareWithInvocationTarget:self] removeObjectFromFramesArrayController:f];
// Only set the action name if we're not undoing.
// This way, when this method is called during 'Undo Delete Frame', the action item will end up in redo as 'Redo Delete Frame'
if (![undo isUndoing]) {
[undo setActionName:@"Add Frame"];
}
};
NSDictionary *action = [NSDictionary dictionaryWithObjectsAndKeys:f, RemoteObject, successBlock, SuccessBlock, nil];
[NSApp sendAction:@selector(postObject:) to:nil from:action];
}
- (void)removeObjectFromFramesArrayController:(Frame *)f
{
void (^successBlock)(NSManagedObject *object) = ^(NSManagedObject *object) {
// If the remoting fails, the object is not deleted, so only add to undo on success
// Get JSON for string (could also be a clone)
NSString *json = [f json];
NSUndoManager *undo = [self undoManager];
[[undo prepareWithInvocationTarget:self] createFrameFromJSON:json];
// Only set the action name if we're not undoing.
// This way, when this method is called during 'Undo Add Frame', the action item will end up in redo as 'Redo Add Frame'
if (![undo isUndoing]) {
[undo setActionName:@"Delete Frame"];
}
};
NSDictionary *action = [NSDictionary dictionaryWithObjectsAndKeys:f, RemoteObject, successBlock, SuccessBlock, nil];
[NSApp sendAction:@selector(postObject:) to:nil from:action];
}
- (void)createFrameFromJSON:(NSString *)s
{
// create frame from JSON
[self addObjectToFramesArrayController:newFrame];
}
// Also, we could potentially use KVO to handle edits, although I don't know how this works with nested objects
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSUndoManager *undo = [self undoManager];
id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
// NSNull objects are used to represent nil in a dictionary
if (oldValue == [NSNull null]) {
oldValue = nil;
}
[[undo prepareWithInvocationTarget:self] changeKeyPath:keyPath ofObject:object toValue:oldValue];
[undo setActionName:@"Edit Frame"];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment