NSUndoManager(Chapter 9 of Cocoa Programming for Mac OS X)
2011-02-15 11:15
861 查看
Document 1 //
2 // MyDocument.m
3 // RaiseMan
4 //
5 // Created by b1mobile on 2/14/11.
6 // Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "MyDocument.h"
10 #import "Person.h"
11
12 @implementation MyDocument
13
14 - (id)init
15 {
16 self = [super init];
17 employees = [[NSMutableArray alloc] init];
18 return self;
19 }
20
21 - (void)dealloc
22 {
23 [super setEmployees:nil];
24 [super dealloc];
25 }
26
27 - (void)setEmployees:(NSMutableArray *)a
28 {
29 if(a == employees)
30 {
31 return;
32 }
33
34 for(Person *person in employees)
35 {
36 [self stopObservingPerson:person];
37 }
38
39 [a retain];
40 [employees release];
41 employees = a;
42
43 for(Person *person in employees)
44 {
45 [self startObservingPerson:person];
46 }
47 }
48
49 - (void)insertObject:(Person *)p inEmployeesAtIndex:(int)index
50 {
51 NSLog(@"adding %@ to %@", p, employees);
52 NSUndoManager *undo = [self undoManager];
53 [[undo prepareWithInvocationTarget:self] removeObjectFromEmployeesAtIndex:index];
54 if(![undo isUndoing])
55 {
56 [undo setActionName:@"Insert Person"];
57 }
58 [self startObservingPerson:p];
59 [employees insertObject:p atIndex:index];
60 }
61
62 - (void)removeObjectFromEmployeesAtIndex:(int)index
63 {
64 Person *p = [employees objectAtIndex:index];
65 NSLog(@"removing %@ from %@", p, employees);
66 NSUndoManager *undo = [self undoManager];
67 [[undo prepareWithInvocationTarget:self] insertObject:p inEmployeesAtIndex:index];
68
69 if(![undo isUndoing])
70 {
71 [undo setActionName:@"Delete Person"];
72 }
73 [self stopObservingPerson:p];
74 [employees removeObjectAtIndex:index];
75 }
76
77 - (void)startObservingPerson:(Person *)person
78 {
79 [person addObserver:self forKeyPath:@"personName" options:NSKeyValueObservingOptionOld context:NULL];
80 [person addObserver:self forKeyPath:@"expectedRaise" options:NSKeyValueObservingOptionOld context:NULL];
81 }
82
83 - (void)stopObservingPerson:(Person *)person
84 {
85 [person removeObserver:self forKeyPath:@"personName"];
86 [person removeObserver:self forKeyPath:@"expectedRaise"];
87 }
88
89 - (void)changeKeyPath:(NSString *)keyPath ofObject:(id)obj toValue:(id)newValue
90 {
91 [obj setValue:newValue forKeyPath:keyPath];
92 }
93
94 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
95 {
96 NSUndoManager *undo = [self undoManager];
97 id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
98
99 if(oldValue == [NSNull null])
{
oldValue = nil;
}
NSLog(@"oldValue = %@", oldValue);
[[undo prepareWithInvocationTarget:self] changeKeyPath:keyPath ofObject:object toValue:oldValue];
[undo setActionName:@"Edit"];
}
- (IBAction)createEmployee:(id)sender
{
NSWindow *w = [tableView window];
BOOL editingEnded = [w makeFirstResponder:w];
if(!editingEnded)
{
NSLog(@"Unable to end editing");
return;
}
NSUndoManager *undo = [self undoManager];
if ([undo groupingLevel])
{
[undo endUndoGrouping];
[undo beginUndoGrouping];
}
Person *p = [employeeController newObject];
[employeeController addObject:p];
[p release];
[employeeController rearrangeObjects];
NSArray *a = [employeeController arrangedObjects];
int row = [a indexOfObjectIdenticalTo:p];
NSLog(@"starting edit of %@ in row %@", p, row);
[tableView editColumn:0 row:row withEvent:nil select:YES];
}
- (NSString *)windowNibName
{
// Override returning the nib file name of the document
// If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead.
return @"MyDocument";
}
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
[super windowControllerDidLoadNib:aController];
// Add any code here that needs to be executed once the windowController has loaded the document's window.
}
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
{
// Insert code here to write your document to data of the specified type. If the given outError != NULL, ensure that you set *outError when returning nil.
// You can also choose to override -fileWrapperOfType:error:, -writeToURL:ofType:error:, or -writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead.
// For applications targeted for Panther or earlier systems, you should use the deprecated API -dataRepresentationOfType:. In this case you can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead.
if ( outError != NULL ) {
*outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL];
}
return nil;
}
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
{
// Insert code here to read your document from the given data of the specified type. If the given outError != NULL, ensure that you set *outError when returning NO.
// You can also choose to override -readFromFileWrapper:ofType:error: or -readFromURL:ofType:error: instead.
// For applications targeted for Panther or earlier systems, you should use the deprecated API -loadDataRepresentation:ofType. In this case you can also choose to override -readFromFile:ofType: or -loadFileWrapperRepresentation:ofType: instead.
if ( outError != NULL ) {
*outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL];
}
return YES;
}
@end
2 // MyDocument.m
3 // RaiseMan
4 //
5 // Created by b1mobile on 2/14/11.
6 // Copyright 2011 __MyCompanyName__. All rights reserved.
7 //
8
9 #import "MyDocument.h"
10 #import "Person.h"
11
12 @implementation MyDocument
13
14 - (id)init
15 {
16 self = [super init];
17 employees = [[NSMutableArray alloc] init];
18 return self;
19 }
20
21 - (void)dealloc
22 {
23 [super setEmployees:nil];
24 [super dealloc];
25 }
26
27 - (void)setEmployees:(NSMutableArray *)a
28 {
29 if(a == employees)
30 {
31 return;
32 }
33
34 for(Person *person in employees)
35 {
36 [self stopObservingPerson:person];
37 }
38
39 [a retain];
40 [employees release];
41 employees = a;
42
43 for(Person *person in employees)
44 {
45 [self startObservingPerson:person];
46 }
47 }
48
49 - (void)insertObject:(Person *)p inEmployeesAtIndex:(int)index
50 {
51 NSLog(@"adding %@ to %@", p, employees);
52 NSUndoManager *undo = [self undoManager];
53 [[undo prepareWithInvocationTarget:self] removeObjectFromEmployeesAtIndex:index];
54 if(![undo isUndoing])
55 {
56 [undo setActionName:@"Insert Person"];
57 }
58 [self startObservingPerson:p];
59 [employees insertObject:p atIndex:index];
60 }
61
62 - (void)removeObjectFromEmployeesAtIndex:(int)index
63 {
64 Person *p = [employees objectAtIndex:index];
65 NSLog(@"removing %@ from %@", p, employees);
66 NSUndoManager *undo = [self undoManager];
67 [[undo prepareWithInvocationTarget:self] insertObject:p inEmployeesAtIndex:index];
68
69 if(![undo isUndoing])
70 {
71 [undo setActionName:@"Delete Person"];
72 }
73 [self stopObservingPerson:p];
74 [employees removeObjectAtIndex:index];
75 }
76
77 - (void)startObservingPerson:(Person *)person
78 {
79 [person addObserver:self forKeyPath:@"personName" options:NSKeyValueObservingOptionOld context:NULL];
80 [person addObserver:self forKeyPath:@"expectedRaise" options:NSKeyValueObservingOptionOld context:NULL];
81 }
82
83 - (void)stopObservingPerson:(Person *)person
84 {
85 [person removeObserver:self forKeyPath:@"personName"];
86 [person removeObserver:self forKeyPath:@"expectedRaise"];
87 }
88
89 - (void)changeKeyPath:(NSString *)keyPath ofObject:(id)obj toValue:(id)newValue
90 {
91 [obj setValue:newValue forKeyPath:keyPath];
92 }
93
94 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
95 {
96 NSUndoManager *undo = [self undoManager];
97 id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
98
99 if(oldValue == [NSNull null])
{
oldValue = nil;
}
NSLog(@"oldValue = %@", oldValue);
[[undo prepareWithInvocationTarget:self] changeKeyPath:keyPath ofObject:object toValue:oldValue];
[undo setActionName:@"Edit"];
}
- (IBAction)createEmployee:(id)sender
{
NSWindow *w = [tableView window];
BOOL editingEnded = [w makeFirstResponder:w];
if(!editingEnded)
{
NSLog(@"Unable to end editing");
return;
}
NSUndoManager *undo = [self undoManager];
if ([undo groupingLevel])
{
[undo endUndoGrouping];
[undo beginUndoGrouping];
}
Person *p = [employeeController newObject];
[employeeController addObject:p];
[p release];
[employeeController rearrangeObjects];
NSArray *a = [employeeController arrangedObjects];
int row = [a indexOfObjectIdenticalTo:p];
NSLog(@"starting edit of %@ in row %@", p, row);
[tableView editColumn:0 row:row withEvent:nil select:YES];
}
- (NSString *)windowNibName
{
// Override returning the nib file name of the document
// If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this method and override -makeWindowControllers instead.
return @"MyDocument";
}
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
{
[super windowControllerDidLoadNib:aController];
// Add any code here that needs to be executed once the windowController has loaded the document's window.
}
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
{
// Insert code here to write your document to data of the specified type. If the given outError != NULL, ensure that you set *outError when returning nil.
// You can also choose to override -fileWrapperOfType:error:, -writeToURL:ofType:error:, or -writeToURL:ofType:forSaveOperation:originalContentsURL:error: instead.
// For applications targeted for Panther or earlier systems, you should use the deprecated API -dataRepresentationOfType:. In this case you can also choose to override -fileWrapperRepresentationOfType: or -writeToFile:ofType: instead.
if ( outError != NULL ) {
*outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL];
}
return nil;
}
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
{
// Insert code here to read your document from the given data of the specified type. If the given outError != NULL, ensure that you set *outError when returning NO.
// You can also choose to override -readFromFileWrapper:ofType:error: or -readFromURL:ofType:error: instead.
// For applications targeted for Panther or earlier systems, you should use the deprecated API -loadDataRepresentation:ofType. In this case you can also choose to override -readFromFile:ofType: or -loadFileWrapperRepresentation:ofType: instead.
if ( outError != NULL ) {
*outError = [NSError errorWithDomain:NSOSStatusErrorDomain code:unimpErr userInfo:NULL];
}
return YES;
}
@end
相关文章推荐
- Keyboard Events(Chapter 19 of Cocoa Programming for Mac OS X)
- Drawing Text With Attributes(Chapter 20 of Cocoa Programming for Mac OS X)
- Memory Management(Chapter 4 of Cocoa Programming for Mac OS X)
- Objective-C(Chapter 3 of Cocoa Programming for Mac OS X)
- NSArrayController(Chapter 8 of Cocoa Programming for Mac OS X)
- Using Notifications(Chapter 14 of Cocoa Programming for Mac OS X)
- Core Data Relationships(Chapter 30 of Cocoa Programming for Mac OS X)
- Basic Core Data(Chapter 11 of Cocoa Programming for Mac OS X)
- Printing(Chapter 27 of Cocoa Programming for Mac OS X)
- Using Alert Panels(Chapter 15 of Cocoa Programming for Mac OS X)
- Localization(Chapter 16 of Cocoa Programming for Mac OS X)
- Pasteboards and Nil-Targeted Actions(Chapter 21 of Cocoa Programming for Mac OS X)
- User Defaults(Chapter 13 of Cocoa Programming for Mac OS X)
- Key-Value Coding, Key-Value observing(Chapter 7 of Cocoa Programming for Mac OS X)
- View Swapping(Chapter 29 of Cocoa Programming for Mac OS X)
- Web Service(Chapter 28 of Cocoa Programming for Mac OS X)
- NSTimer(Chapter 24 of Cocoa Programming for Mac OS X)
- Images and Mouse Events(Chapter 18 of Cocoa Programming for Mac OS X)
- Drag-and-Drop(Chapter 23 of Cocoa Programming for Mac OS X)
- Sheets(Chapter 25 of Cocoa Programming for Mac OS X)