This is MiscController.m in view mode; [Download] [Up]
/* MiscController.m */ // RCS identification information static char *rcsID = "$Id:$"; static void __AvoidCompilerWarning(void) {if(!rcsID)__AvoidCompilerWarning();} // NeXT Headers #import <AppKit/AppKit.h> // System Headers // Other Headers #import "MiscControllerManager.h" // Superclass/Class Headers #import "MiscController.h" // Constants NSString* MiscControllerDidEditNotification = @"MiscControllerDidEditNotification"; @implementation MiscController /*" MiscController is the abstract superclass for all controllers. (Controllers being somewhat like the controllers in a model-view-controller setup). We also implement the interface between controllers and controller managers. Since MiscController is abstract, it shouldn't be instantiated directly. To become a part of the document framework we need a controller manager. This is usually set in IB, though you can also use #setControllerManager:. Inside #setControllerManager: we send a message to our new controller manager to let it know about ourselves. Once you have a controller manager you can ask it for other controllers it knows about. In the next verison, I will explain in detail the #isDirty, #isEditable, #didEdit and #controllerDidEdit: methods. Most of them are used in the little Adder miniexample if you just can't wait for me to formally document them :-). "*/ //------------------------------------------------------------------- // Initialization/deallocation //------------------------------------------------------------------- - (id) init /*" Our designated initializer. Doesn't do much right now. "*/ { BOOL error = ([super init] == nil); return error ? nil : self; } - (void) dealloc /*" Removes ourselve as an observer from the default notification center, then releases any other resources we have. We don't release our controller manager though, since we didn't retain it. "*/ { // Stops the center from sending notification to what's going to be // a freed object. [[NSNotificationCenter defaultCenter] removeObserver:self]; [_name release]; [super dealloc]; } //------------------------------------------------------------------- // Accessor methods //------------------------------------------------------------------- - (MiscControllerManager*) controllerManager /*" Returns our controller manager. From it you can get all kinds of information, like other controllers it knows about, or information about our window, etc. "*/ { return _controllerManager; } - (void) setControllerManager:(MiscControllerManager*)newManager /*" Sets our controller manager to aManager. If we had an old controller manager we first send it a #removeController: method. We then add ourself to our new manager's controller list via #addController. We don't retain our controller manager, since that would introduce a cyclic reference. Raises an NSInvalidArgumentException if the argument isn't a MiscControllerManager or a subclass. (Maybe I shouldn't). "*/ { BOOL error = NO; // Check arguments. if (!error && newManager == nil) { error = YES; } // Raise an exception if the argument is not nil but is also not a // MiscControllerManager (or subclass). if (!error && ![newManager isKindOfClass:[MiscControllerManager class]]) { [NSException raise:NSInvalidArgumentException format:@"The manager of a MiscController subclass must " @"be an instance of a MiscControllerManager subclass. The " @"instance presented was of class %@", [newManager class]]; error = YES; } if (!error) { // If we have an old manager, let it know we have moved // on. [[self controllerManager] removeController:self]; // Let our new controller know about us. [newManager addController:self]; // Set our own ivar, but don't retain it since that would create // a cyclic reference. _controllerManager = newManager; } } - (BOOL) isDirty /*" Returns YES if we've changed in any way since we were last saved. "*/ { return _dirty; } - (void) setDirty:(BOOL)nowDirty /*" This will usually only be set by the controller itself. Calls on our controller manager to update it's document edited status. "*/ { _dirty = nowDirty; // The status of our controller manager may have changed [[self controllerManager] updateDocumentEdited]; } - (BOOL) isEditable /*" Not implemeted yet. Always returns YES. "*/ { return YES; } - (void) setEditable:(BOOL)nowEditable /*" Not implmented yet. For this to work correctly subclasses that are going to be switching between editable and not editable should extend this method to make their accompanying UI elements either editable or not. "*/ { } //------------------------------------------------------------------- // MiscControllerDidEditNotification sender //------------------------------------------------------------------- - (void) didEdit /*" Posts a MiscControllerDidEditNotification with the receiver as the notification's object. We also send a #setDirty:YES message to ourself since editing usually makes us dirty. You should call this method (or #didEditWithUserInfo:) any time you or one of your UI elemetes are edited so other interested objects will know about it. "*/ { [self didEditWithUserInfo:nil]; } - (void) didEditWithUserInfo:(NSDictionary*)userInfo /*" Does the same thing as #didEdit except it allows you to send along userInfo with the posted notification. Of course the receivers of the notification will have to be aware of the extra information and what keys the NSDictionary contains (but then you probably already knew that :-). "*/ { [self _postControllerDidEditNotificationWithUserInfo:userInfo]; [self setDirty:YES]; } //------------------------------------------------------------------- // Edit notification //------------------------------------------------------------------- - (void) controllerDidEdit:(NSNotification*)notification /*" Sent if you used our protected method #_registerForControllerDidEditNotification: to register for notification when another MiscController edits. Of course you can always register for the MiscControllerDidEditNotification yourself through NSNotificationCenter and use a method of your own choosing. This method currently does nothing and is meant to be overridden in subclasses. "*/ { } //------------------------------------------------------------------- // Revert/Save (subclass responsibility) //------------------------------------------------------------------- - (BOOL) save /*" It is up to subclasses to override this method if their controller is saveable (or you are going to use our controller manager's save method). Return YES if the save was successful and NO otherwise. If for some reason the save fails it is up to the controller to let the user know why the failure occurred (through an alert panel I suppose). Also if the save is successful make sure to call #setDirtry:NO in your implementation of #save. "*/ { // This method needs to be overridden in a subclass. [self doesNotRecognizeSelector:_cmd]; // To keep the compiler happy. return NO; } - (BOOL) revert /*" See the description of #save for more useful information on saving and reverting. This method must be overridden if the controller can be reverted. It should return YES if the revert was successful and NO otherwise. Make sure to call #setDirty:NO if the revert was successful. "*/ { // This method needs to be overridden in a subclass. [self doesNotRecognizeSelector:_cmd]; // To keep the compiler happy. return NO; } //------------------------------------------------------------------- // Support for named controllers //------------------------------------------------------------------- - (NSString*) name /*" Returns our controller's name. "*/ { return _name; } - (void) setName:(NSString*)newName /*" Sets our name to be newName. This allows you to ask a controller manager for a controller without keeping an outlet to it (See MiscControllerManager's #{controller(s)WithName:}). We copy newName and autorelease the previous name. "*/ { [_name autorelease]; _name = [newName copy]; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.