Cocoa Programming for Mac OS X - Aaron Hillegass [53]
Begin Editing on Insert
Your app is coming along nicely, but your users will complain, “Why do I have to double-click to start editing after an insert? It is obvious that I am going to immediately change the name of the new person. Can’t you start the editing as part of the insert?”
Oddly, this is a little tricky to do. So, here is the code snippet you need. First, RMDocument.h is going to need an action and two instance variables:
@interface RMDocument : NSDocument
{
NSMutableArray *employees;
IBOutlet NSTableView *tableView;
IBOutlet NSArrayController *employeeController;
}
- (IBAction)createEmployee:(id)sender;
Save that file. Open RMDocument.xib and Control-drag from the Add Employee button to the File’s Owner (which is the instance of RMDocument). Set its action to createEmployee:
Control-click on the File’s Owner. Drag to connect the tableView outlet to the table view and the employeeController outlet to the array controller (Figure 9.5).
Figure 9.5. Setting the tableView Outlets
Now, in RMDocument.m, add the createEmployee: method:
- (IBAction)createEmployee:(id)sender
{
NSWindow *w = [tableView window];
// Try to end any editing that is taking place
BOOL editingEnded = [w makeFirstResponder:w];
if (!editingEnded) {
NSLog(@"Unable to end editing");
return;
}
NSUndoManager *undo = [self undoManager];
// Has an edit occurred already in this event?
if ([undo groupingLevel] > 0) {
// Close the last group
[undo endUndoGrouping];
// Open a new group
[undo beginUndoGrouping];
}
// Create the object
Person *p = [employeeController newObject];
// Add it to the content array of 'employeeController'
[employeeController addObject:p];
// Re-sort (in case the user has sorted a column)
[employeeController rearrangeObjects];
// Get the sorted array
NSArray *a = [employeeController arrangedObjects];
// Find the object just added
NSUInteger row = [a indexOfObjectIdenticalTo:p];
NSLog(@"starting edit of %@ in row %lu", p, row);
// Begin the edit in the first column
[tableView editColumn:0
row:row
withEvent:nil
select:YES];
}
We don’t really expect you to understand every line of that code now, but browse through the method and try to get the gist. Build and run the application.
For the More Curious: Windows and the Undo Manager
A view can add edits to the undo manager. NSTextView, for example, can put each edit that a person makes to the text onto the undo manager. How does the text view know which undo manager to use? First, it asks its delegate. NSTextView delegates can implement this method:
- (NSUndoManager *)undoManagerForTextView:(NSTextView *)tv;
Next, it asks its window. NSWindow has a method for this purpose:
- (NSUndoManager *)undoManager;
The window’s delegate can supply an undo manager for the window by implementing the following method:
- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *) window;
The undo/redo menu items reflect the state of the undo manager for the key window (Figure 9.6). (The key window is what most users call the “active window.” Cocoa developers call it key because it is the one that will get the keyboard events if the user types.)
Figure 9.6. NSTextView Inspector
Chapter 10. Archiving
While an object-oriented program is running, a complex graph of objects is being created. It is often necessary to represent this graph of objects as a stream of bytes, a process called archiving (Figure 10.1). This stream of bytes can then be sent across a network connection or written into a file. For example, when creating a NIB from the XIB file you edited in the Interface Builder editor, the compiler is archiving objects into a file. (Instead of “archiving,” a Java programmer would call this process “serialization.”)
Figure 10.1. Archiving
When you need