This is MiscControllerManager.m in view mode; [Download] [Up]
/* MiscControllerManager.m */ // RCS identification information static char *rcsID = "$Id:$"; static void __AvoidCompilerWarning(void) {if(!rcsID)__AvoidCompilerWarning();} // NeXT Headers #import <AppKit/AppKit.h> // Other Headers #import "MiscController.h" // Superclass/Class Headers #import "MiscControllerManager.h" @implementation MiscControllerManager /*" The MiscControllerManager class is an extension of MiscWindowManager. In addition to managing our window, we now also manage zero or more MiscControllers that'll display information in our window. Our job is to reduce the number of outlets from controller to controller within the same window. Since each controller should have the same controller manager, they can just ask their controller manager for any other controller (by name or class) it knows about. We also keep track of each controller's edited state so we know when the window should be marked as "dirty". Additionally, when the window is closed and releasedWhenWindowClosed (method from our superclass) is YES, we will free our controllers when we release ourselves. "*/ //------------------------------------------------------------------- // Initialization / deallocation //------------------------------------------------------------------- - (id) init /*" Our designated initializer. Right now we only create an array to keep track of our controllers. "*/ { BOOL error = ([super init] == nil) ? YES : NO; if (!error) { _controllers = [[NSMutableArray alloc] init]; // If something goes wrong it is our responsibility to free ourselves // and return nil. if (error) { [self autorelease]; } } return error ? nil : self; } - (void) dealloc /*" Releases our array of controllers. "*/ { [_controllers release]; [super dealloc]; } //------------------------------------------------------------------- // Accessing the managed controllers //------------------------------------------------------------------- - (void) addController:(MiscController*)newController /*" Adds the given controller to our list of controllers if it is a subclass of MiscController. This message is usually sent from our new controller's #setControllerManager: method (if the connection from a controller to it's controller manager is made in IB). "*/ { if ([newController isKindOfClass:[MiscController class]]) { [[self mutableControllers] addObject:newController]; } else { NSLog (@"MiscControllerManager: You attempted to add a controller " @"that was not an instance of MiscController."); } } - (void) removeController:(MiscController*)oldController /*" Though this probably shouldn't be needed too often it is provided for those rare cases. "*/ { if ([oldController isKindOfClass:[MiscController class]]) { [[self mutableControllers] removeObject:oldController]; } else { NSLog (@"MiscControllerManager: You attempted to remove a controller " @"that was not an instance of MiscController."); } } - (NSArray*) controllers /*" Returns our controllers. If you are calling this method in a subclass you can also make use of our protected #mutableControllers method if you plan on altering the array in any way. "*/ { // Shouldn't return our mutable array I suppose. return [[[NSArray alloc] initWithArray:[self mutableControllers]] autorelease]; } - (NSEnumerator*) controllerEnumerator /*" This method will probably be going away since it's easy enough to ask for our controllers and then create an enumerator from that. "*/ { // Might as well use our mutable array of controllers // to save creating an array just to create it's enumerator // (that's what would happen if we used [self controllers]). return [[self mutableControllers] objectEnumerator]; } //------------------------------------------------------------------- // Controllers by class //------------------------------------------------------------------- - (NSArray*) controllersOfClass:(Class)aClass /*" Returns all our controllers that belong to (or are subclasses of) aClass. If you know for sure that this method will return a single controller then you can probably use #controllerOfClass:. If there are no matches then nil is returned. "*/ { NSEnumerator* controllerEnumerator; MiscController* controller; NSMutableArray* controllersToReturn = nil; controllerEnumerator = [self controllerEnumerator]; while ((controller = [controllerEnumerator nextObject]) != nil) { if ([controller isKindOfClass:aClass]) { if (controllersToReturn == nil) { controllersToReturn = [NSMutableArray arrayWithCapacity:1]; } [controllersToReturn addObject:controller]; } } return [[[NSArray alloc] initWithArray:controllersToReturn] autorelease]; } - (MiscController*) controllerOfClass:(Class)aClass /*" Returns the first controller in our list of controllers that belongs to (or is a subclass of) aClass. If there is no such controller, then nil is returned. "*/ { NSArray* controllers; MiscController* controllerToReturn = nil; controllers = [self controllersOfClass:aClass]; if ([controllers count] > 0) { controllerToReturn = [controllers objectAtIndex:0]; } return controllerToReturn; } //------------------------------------------------------------------- // Controllers by name //------------------------------------------------------------------- - (NSArray*) controllersWithName:(NSString*)aName /*" Returns all our controllers that have the name aName (see MiscController's #{setName:}/#{name} methods). If you know for sure that this method will return a single controller then you can probably use #controllerOfClass:. If there are no matches then nil is returned. "*/ { NSEnumerator* controllerEnumerator; MiscController* controller; NSMutableArray* controllersToReturn = nil; controllerEnumerator = [self controllerEnumerator]; while ((controller = [controllerEnumerator nextObject]) != nil) { if ([[controller name] isEqualToString:aName]) { if (controllersToReturn == nil) { controllersToReturn = [NSMutableArray arrayWithCapacity:1]; } [controllersToReturn addObject:controller]; } } return [[[NSArray alloc] initWithArray:controllersToReturn] autorelease]; } - (MiscController*) controllerWithName:(NSString*)aName /*" Returns the first controller in our list of controlllers that has the name aName (see MiscController's #{setName:}/#{name} methods). If there is no such controller, then nil is returned. "*/ { NSArray* controllers; MiscController* controllerToReturn = nil; controllers = [self controllersWithName:aName]; if ([controllers count] > 0) { controllerToReturn = [controllers objectAtIndex:0]; } return controllerToReturn; } //------------------------------------------------------------------- // Updating the document status //------------------------------------------------------------------- - (void) updateDocumentEdited /*" Scans the receiver's controllers and sets the documed edited flag if any of them are dirty, or clears it if none of them are dirty. "*/ { NSEnumerator* controllerEnumerator; MiscController* controller; BOOL documentEdited = NO; controllerEnumerator = [self controllerEnumerator]; while ((controller = [controllerEnumerator nextObject]) != nil) { // Stop on the first controller we find dirty. if ([controller isDirty]) { documentEdited = YES; break; } } [self setDocumentEdited:documentEdited]; } //------------------------------------------------------------------- // Save/Revert //------------------------------------------------------------------- - (BOOL) save /*" Sends save to our controllers. If they all successfully save then we tell our window that our document isn't edited. If any of the controllers return NO when asked to save we also return NO. It is up to the controller that couldn't save to let the user know what went wrong. If you want this code to be called from a menu cell, just create a #save: method in your subclass that calls this method. The reason it's not done for you is that some controller managers will not want to save, and with the new menu cell validation the menu item will be enabled. Also take note that MiscController does not implement the #save method by default, so if you use this method all your subclasses of MiscController will have to respond to save. "*/ { NSEnumerator* controllerEnumerator; MiscController* controller; BOOL saveSuccessful = YES; controllerEnumerator = [self controllerEnumerator]; while ((controller = [controllerEnumerator nextObject]) != nil) { // Stop on the first controller that cannot save. if (![controller save]) { saveSuccessful = NO; break; } } // We probably could have just called setDocumentEdited:NO if the save was // successful or not, but this way the programmer can catch any bugs that // a controller might have when it successfully saves but doesn't say it's // not dirty anymore. [self updateDocumentEdited]; return saveSuccessful; } - (BOOL) revert /*" Sends revert to our controllers. If they all successfully revert then we tell our window that our document isn't edited. If any of the controllers return NO when asked to revert we also return NO. See the #save method for other helpful tips when using these methods. "*/ { NSEnumerator* controllerEnumerator; MiscController* controller; BOOL revertSuccessful = YES; controllerEnumerator = [self controllerEnumerator]; while ((controller = [controllerEnumerator nextObject]) != nil) { // Stop on the first controller that cannot revert. if (![controller revert]) { revertSuccessful = NO; break; } } // We probably could have just called setDocumentEdited: is the save was // successful or not, but this way the programmer can catch any bugs that // a controller might have when it successfully saves but doesn't say it's // not dirty anymore. [self updateDocumentEdited]; return revertSuccessful; } //------------------------------------------------------------------- // Controlling a manager's editability //------------------------------------------------------------------- - (BOOL) isEditable /*" Returns YES if any of our controllers are editable. If they are all uneditable then we return NO. If we happen to have no controllers then the answer will always be NO. "*/ { NSEnumerator* controllerEnumerator; MiscController* controller; BOOL editable = NO; // Go through our controllers until one says he is editable. controllerEnumerator = [self controllerEnumerator]; while ((controller = [controllerEnumerator nextObject]) != nil) { // We check for this because not all MiscController // subclasses respond to isEditable. if ([controller respondsToSelector:@selector(isEditable)]) { if ([controller isEditable]) { editable = YES; break; } } } return editable; } - (void) setEditable:(BOOL)nowEditable /*" Sets all of our controllers to be editable. Feel free to override this method if that's not the behavior you'd like (ie: some controllers should become editable and some should not). "*/ { NSEnumerator* controllerEnumerator; MiscController* controller; // Go through our controllers and set them all editable if they // respond to setEditable: controllerEnumerator = [self controllerEnumerator]; while ((controller = [controllerEnumerator nextObject]) != nil) { if ([controller respondsToSelector:@selector(setEditable:)]) { [controller setEditable:nowEditable]; } } } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.