This is MiscNibManager.m in view mode; [Download] [Up]
/* MiscNibManager.m */ // RCS identification information static char *rcsID = "$Id:$"; static void __AvoidCompilerWarning(void) {if(!rcsID)__AvoidCompilerWarning();} // NeXT Headers #import <Foundation/Foundation.h> #import <AppKit/AppKit.h> // Other Headers #import "MiscWindowManager.h" // Class Headers #import <MiscControllerKit/MiscNibManager.h> // Global Constants NSString* MiscNibManagerWillReleaseNotification = @"MiscNibManagerWillReleaseNotification"; @implementation MiscNibManager /*" MiscNibManager is a lightweight class that manages the resources in a single nib. It is equipped to handle and give access to the window managers in the nib. Subclasses, of course, can always add outlets to manage other objects inside the nib. The nib filename should be within the bundle that the MiscNibManager exists in otherwise you should use the #initWithBundle: and pass in the bundle that contains the nib. You can also manually get the pathname to the nib yourself and use our #initWithNibFilename: method. If the nib you are loading just has MiscWindowManager subclasses and other objects that are taken care of by a window manager or one of it's subclasses then you probably don't even need to create a subclass of MiscNibManager. You can load the nib with #initWithNibFilename: and get the window managers via #windowManagersOfClass or #windowManagersWithName:. Recently I have become enlightened that loading a nib is just an implementation detail. Really you are usually just interested in the window and controllers inside the nib. So why expose nib managers all over your code? When you ask the window manager class for a new instance it can make use of the nib manager to load itself from the nib. For example of this see MiscInfoWindowManager or MiscInspectorManager. You'll notice that no other object knows about MiscInfoNibManager except for the MiscInfoWindowManager. That's probably the way it should be. I'll document this a whole lot better for the next release. "*/ //------------------------------------------------------------------- // Initialization / deallocation //------------------------------------------------------------------- - (id) init /*" Invokes #initWithNibFilename with [self nibFilename] as the argument. Returns nil upon failure. "*/ { return [self initWithNibFilename:[self nibFilename]]; } - (id) initWithNibFilename:(NSString*)nibFilename /*" Our designated initializer. If nibFilename is nil or loading the nib fails, then we autorelease ourselves and return nil since we have nothing to manage. "*/ { BOOL error = ([super init] == nil); // Check arguments. if (!error) { error = (nibFilename == nil || [nibFilename isEqualToString:@""]); } if (!error) { // This has to be done before the nib is loaded because the array // will keep track of the window managers that are found in the nib. _windowManagers = [[NSMutableArray alloc] init]; [self setReleasedWhenAllWindowManagersReleased:YES]; } if (!error) { // If nibFilename is an absolute path then loadNibNamed: doesn't seem // to work so we have to use it's alternative. On the other hand loadNibFile: // doesn't seem to work as well as loadNibNamed: when searching for nibs // with relative pathnames (since it searches the owner's bundle and the // main bundle) so we use a combination. if ([nibFilename isAbsolutePath]) { NSDictionary* externalNameTable; externalNameTable = [NSDictionary dictionaryWithObjects: [NSArray arrayWithObjects:self, nil] forKeys:[NSArray arrayWithObjects:@"NSOwner", nil]]; error = ![NSBundle loadNibFile:nibFilename externalNameTable:externalNameTable withZone:[self zone]]; } // This will find the nib if it is in the owner's bundle too. else { error = ![NSBundle loadNibNamed:nibFilename owner:self]; } if (error) { NSLog(@"MiscNibManager initWithNibFilename: could not load " @"nib named %@.", nibFilename); // It is our responsiblity to free ourselves if there is a problem. [self autorelease]; } } return error ? nil :self; } - (id) initWithBundle:(NSBundle*)aBundle /*" The initializer to use if the nib filename (returned by [self nibFilename]) is in a different bundle than the main one. For example, ... We may also need to create a initWithNibFilename: inBundle: method to be complete. "*/ { NSString* alternateNibFilename; // Try to find [self nibFilename] in the given bundle. alternateNibFilename = [aBundle pathForResource:[self nibFilename] ofType:nil]; return [self initWithNibFilename:alternateNibFilename]; } - (void) dealloc /*" Standard deallocator. We release our window managers. "*/ { NSLog(@"Instance of MiscNibManager is deallocing."); // Let anyone who cares know we are going away. [[NSNotificationCenter defaultCenter] postNotificationName:MiscNibManagerWillReleaseNotification object:self]; [_windowManagers release]; [super dealloc]; } - (NSString*) nibFilename /*" Returns an empty string. Subclasses should override this method to return a nibFilename. It can be an absolute path though for portability reasons it shouldn't be. The main app wrapper and the nib owner's bundle will be searched when looking for the nib. Alternatively you can use #initWithNibFilename: and not override this method at all. This method is preferrable though if you want to hide the actual nib filename from clients. "*/ { return @""; } //------------------------------------------------------------------- // Window manager manipulation //------------------------------------------------------------------- - (void) addWindowManager:(MiscWindowManager*)newManager /*" Adds newManager to our list of window managers as long as it is really an instance or subclass of MiscWindowManager. In Interface Builder if you connect an instance of MiscWindowManager to a nib manager then this method is called when the connection is made (via MiscWindowManager's #setNibManager:). "*/ { BOOL error = NO; // Check our arguments. if (newManager == nil) { error = YES; NSLog (@"MiscNibManager: addWindowManager: argument given was nil."); } if (!error) { if ([newManager isKindOfClass:[MiscWindowManager class]]) { [[self mutableWindowManagers] addObject:newManager]; } else { error = YES; NSLog (@"MiscNibManager: addWindowManager: argument was not an " @"instance of MiscNibManager or one of it's subclasses."); } } } - (void) removeWindowManager:(MiscWindowManager*)oldManager /*" Removes oldManager from our list of window managers. "*/ { BOOL error = NO; // Check our arguments. if (oldManager == nil) { error = YES; NSLog (@"MiscNibManager: removeWindowManager: argument given was " @"nil."); } if (!error) { NSMutableArray* windowManagers = [self mutableWindowManagers]; // We only bother to check if oldManager is one of ours // so we can print an informative error message. if ([windowManagers containsObject:oldManager]) { [windowManagers removeObject:oldManager]; } else { NSLog (@"MiscNibManager removeWindowManager: argument given " @"was not one of our window managers."); } } } - (NSArray*) windowManagers /*" Returns an immutable array containing our window managers. Subclasses should check out our protected #mutableWindowManagers. "*/ { return [[[NSArray alloc] initWithArray:[self mutableWindowManagers]] autorelease]; } - (NSEnumerator*) windowManagerEnumerator /*" Returns an enumerator that can be used to access our window managers. "*/ { // Getting the mutable window manager will save creating an // array just to create an enumerator for it. return [[self mutableWindowManagers] objectEnumerator]; } //------------------------------------------------------------------- // Access to our window manager(s). //------------------------------------------------------------------- - (NSArray*) windowManagersWithName:(NSString*)name /*" Returns an array of our window managers with the given name. If none exist nil is returned. If you know there'll only be a single instance of a given window manager it's probably more convenient to use #windowManagerWithName:. "*/ { NSMutableArray* windowManagersWithName = nil; NSEnumerator* windowManagerEnumerator = [self windowManagerEnumerator]; MiscWindowManager* ourWindowManager; while ((ourWindowManager = [windowManagerEnumerator nextObject]) != nil) { if ([[ourWindowManager name] isEqualToString:name]) { if (windowManagersWithName == nil) { windowManagersWithName = [NSMutableArray arrayWithCapacity:1]; } [windowManagersWithName addObject:ourWindowManager]; } } // This should make an immutable copy before returning but // since MiscWindowManager does not respond to copyWithZone: // (yet) we can't. I'll fix it in a later release. return windowManagersWithName; } - (MiscWindowManager*) windowManagerWithName:(NSString*)name /*" Returns the first of our window managers that have the given name. If none exist then nil is returned. "*/ { NSArray* windowManagersWithName; MiscWindowManager* firstWindowManagerWithName = nil; windowManagersWithName = [self windowManagersWithName:name]; if ([windowManagersWithName count] > 0) { firstWindowManagerWithName = [windowManagersWithName objectAtIndex:0]; } return firstWindowManagerWithName; } - (NSArray*) windowManagersOfClass:(Class)aClass /*" Returns an array of our window managers of the given class (or subclass). If none exist nil is returned. If you know there'll only be a single instance of a given window manager it's probably more convenient to use #windowManagerOfClass:. "*/ { NSMutableArray* windowManagersOfClass = nil; NSEnumerator* windowManagerEnumerator = [self windowManagerEnumerator]; MiscWindowManager* ourWindowManager; while ((ourWindowManager = [windowManagerEnumerator nextObject]) != nil) { if ([ourWindowManager isKindOfClass:aClass]) { if (windowManagersOfClass == nil) { windowManagersOfClass = [NSMutableArray arrayWithCapacity:1]; } [windowManagersOfClass addObject:ourWindowManager]; } } // This should make an immutable copy before returning but // since MiscWindowManager does not respond to copyWithZone: // (yet) we can't. I'll fix it in a later release. return windowManagersOfClass; } - (MiscWindowManager*) windowManagerOfClass:(Class)aClass /*" Returns the first of our window managers of the given aClass (or subclass). If none exist then nil is returned. "*/ { NSArray* windowManagersOfClass; MiscWindowManager* firstWindowManagerOfClass = nil; windowManagersOfClass = [self windowManagersOfClass:aClass]; if ([windowManagersOfClass count] > 0) { firstWindowManagerOfClass = [windowManagersOfClass objectAtIndex:0]; } return firstWindowManagerOfClass; } //------------------------------------------------------------------- // Accessor methods //------------------------------------------------------------------- - (BOOL) isReleasedWhenAllWindowManagersReleased /*" Returns YES if, when the we have no more window managers (they have all been released) we release ourselves. The default is YES. Note, that if we start out with no window managers then we will not release ourselves automatically. "*/ { return _releasedWhenAllWindowManagersReleased; } - (void) setReleasedWhenAllWindowManagersReleased:(BOOL)freeUs /*" Sets whether, when we have no more window managers left (they have all been released either explicitly or when the user has closed the window) we also release ourselves. The default is YES. Note, that if we start out with no window managers then we will not release ourselves automatically. "*/ { _releasedWhenAllWindowManagersReleased = freeUs; } @end @implementation MiscNibManager (MiscWindowManagerNotifications) - (void) windowManagerWillClose:(MiscWindowManager*)closingWindowManager /*" This method is called from MiscWindowManager when the window manager is planning on releasing itself. You should not call this method directly. If closingWindowManager is one of our window managers it is removed from our list of window managers. If closingWindowManager was our last window manager and we should release ourselves when we have no more window managers then we also release ourselves. "*/ { if ([[self windowManagers] containsObject:closingWindowManager]) { [self removeWindowManager:closingWindowManager]; // Release ourselves when we have no more window // managers if we should. if ([[self windowManagers] count] == 0 && [self isReleasedWhenAllWindowManagersReleased]) { [self autorelease]; } } else { NSLog (@"windowManagerWillClose: I was given notification of " @"a window manager closing that I don't own."); } } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.