This is MiscWindowManager.m in view mode; [Download] [Up]
/* MiscWindowManager.m */ // RCS identification information static char *rcsID = "$Id:$"; static void __AvoidCompilerWarning(void) {if(!rcsID)__AvoidCompilerWarning();} // NeXT Headers #import <AppKit/AppKit.h> // Other headers #import <MiscControllerKit/MiscNibManager.h> // Class headers #import "MiscWindowManager.h" // Private macros #define MISC_CASCADE_XOFFSET 25.0 #define MISC_CASCADE_YOFFSET 25.0 // Global Constants NSString* MiscWindowManagerWillReleaseNotification = @"MiscWindowManagerWillReleaseNotification"; // Private Variables // When the OpenStep MiscKit is released I will use MiscClassVariable // but for now... static Class nibManagerClass = nil; @implementation MiscWindowManager /*" MiscWindowManager is an abstract class that manages the resources of a single window. To work correctly it needs to be the window's delegate. This class will probably change the most in the coming releases. Some of it's methods aren't very useful anymore (they were more so in 3.x development). I also have some other functionality that I'll be adding. "*/ //------------------------------------------------------------------- // Class initialization //------------------------------------------------------------------- + (void) initialize /*" Does nothing right now. "*/ { } //------------------------------------------------------------------- // Nib manager class that'll load us //------------------------------------------------------------------- + (Class) nibManagerClass /*" Returns the nib manager class used to load us. By default it is nil since the abstract MiscNibManager isn't capable to loading a nib. The class returned by this method can be used by subclasses to create new window managers via the class returned by this method. "*/ { return nibManagerClass; } + (void) setNibManagerClass:(Class)newNibManagerClass /*" Sets our nib manager class used to load us. By default it is nil. "*/ { nibManagerClass = newNibManagerClass; } //------------------------------------------------------------------- // All our instances //------------------------------------------------------------------- + (NSArray*) allWindowManagers /*" Returns an array of all known instances of MiscWindowManager and it's subclases. This method assumes that all the instances are are their window's delegate, since these instances are retrieved via the global Window list. Returns nil if no instances exist. "*/ { return [self windowManagersOfClass:[MiscWindowManager class]]; } //------------------------------------------------------------------- // Manager instances by name //------------------------------------------------------------------- + (NSArray*) windowManagersOfClass:(Class)managerClass /*" Returns all instances of class managerClass (or it's subclasses), or nil if there aren't any. "*/ { NSMutableArray* managers = nil; NSArray* windowList = [NSApp windows]; int winCount; int i; id winDelegate; winCount = [windowList count]; for (i = 0; i < winCount; i++) { winDelegate = [[windowList objectAtIndex:i] delegate]; if ([winDelegate isKindOfClass:managerClass]) { if (managers == nil) { managers = [NSMutableArray arrayWithCapacity:1]; } [managers addObject:winDelegate]; } } // Make managers immutable. return [[[NSArray alloc] initWithArray:managers] autorelease]; } + (MiscWindowManager*) windowManagerOfClass:(Class)managerClass /*" Returns the first manager instance that's a kind of managerClass, or nil if one doesn't exist. If you know that you might have more than one instance that has the name "aName" then you should probably use #windowManagersOfClass:. "*/ { NSArray* windowManagersOfClass; MiscWindowManager* firstWindowManagerOfClass = nil; windowManagersOfClass = [self windowManagersOfClass:managerClass]; // If we have at least one manager with that name return the // first one. if ([windowManagersOfClass count] > 0) { firstWindowManagerOfClass = [windowManagersOfClass objectAtIndex:0]; } return firstWindowManagerOfClass; } //------------------------------------------------------------------- // Manager instances by name //------------------------------------------------------------------- + (NSArray*) windowManagersWithName:(NSString*)aName /*" Returns an array of managers that have the name "aName", or nil if none exist. If you know that you'll only have a single instance for aName then you could use #windowManagerWithName:. "*/ { NSEnumerator* allWindowManagersEnumerator; NSMutableArray* windowManagersWithName = nil; MiscWindowManager* windowManager; // Go through each window manager looking for matching names. allWindowManagersEnumerator = [[self allWindowManagers] objectEnumerator]; while ((windowManager = [allWindowManagersEnumerator nextObject]) != nil) { if ([[windowManager name] isEqualToString:aName]) { if (windowManagersWithName == nil) { windowManagersWithName = [NSMutableArray arrayWithCapacity:1]; } [windowManagersWithName addObject:windowManager]; } } return [[[NSArray alloc] initWithArray:windowManagersWithName] autorelease]; } + (id) windowManagerWithName:(NSString*)aName /*" Returns the first manager that has the name "aName", or nil if one doesn't exist. If you know that you might have more than one instance that has the name "aName" then you should probably use #windowManagersWithName:. "*/ { NSArray* windowManagersWithName; MiscWindowManager* firstWindowManagerWithName = nil; windowManagersWithName = [self windowManagersWithName:aName]; // If we have at least one manager with that name return the // first one. if ([windowManagersWithName count] > 0) { firstWindowManagerWithName = [windowManagersWithName objectAtIndex:0]; } return firstWindowManagerWithName; } //------------------------------------------------------------------- // Initialization / deallocation //------------------------------------------------------------------- - init /*" Our designated initializer. If we or our superclass fails initialization we return nil. If we fail we autorelease ourselves. By default we autocascade our windows and don't release ourselves when our window closes. "*/ { BOOL error = ([super init] == nil); if (!error) { // Set our default cascade offset and window cascading to YES. [self setCascadeOffset:MISC_CASCADE_XOFFSET :MISC_CASCADE_YOFFSET]; [self setAutoCascadesWindow:YES]; // It is our responsiblity to free ourselves if there is a problem. if (error) { [self autorelease]; } } return error ? nil :self; } - (void) dealloc /*" Standard deallocator. "*/ { // Let anyone that cares know we are going away. [[NSNotificationCenter defaultCenter] postNotificationName:MiscWindowManagerWillReleaseNotification object:self]; // Stops problems if the window hangs around in NXApp's window list. [_window setDelegate:nil]; // Take it out off screen if it isn't already. [_window close]; [_window autorelease]; [_windowFrameName release]; [_name release]; [super dealloc]; } //------------------------------------------------------------------- // Accessor methods //------------------------------------------------------------------- - (NSString *) name /*" Returns the name of our window manager. This is most useful if, instead of having outlets from your nib manager to window managers or from other window managers, you just ask for it via #windowManager(s)WithName:. "*/ { return _name; } - (void) setName:(NSString*)newName { [_name autorelease]; _name = [newName copy]; } - (MiscNibManager*) nibManager /*" Returns our nib manager of nil if we don't have one. For instance if we were a window manager in the main nib we probably wouldn't have a nib manager. "*/ { return _nibManager; } - (void) setNibManager:(MiscNibManager*)newNibManager /*" Sets our nib manager to aManager. We also add ourself to our new manager's window manager list via #addWindowManager:. We don't retain our nib manager, since that would introduce a cyclic reference. Raises an NSInvalidArgumentException if the argument isn't a MiscNibManager or a subclass. "*/ { BOOL error = NO; // Check arguments. if (!error && newNibManager == nil) { error = YES; } // Raise an exception if the argument is not nil but is also not a // MiscNibManager (or subclass). if (!error && ![newNibManager isKindOfClass:[MiscNibManager class]]) { [NSException raise:NSInvalidArgumentException format:@"The nib manager of a MiscWindowManager " @"subclass must be an instance of a MiscNibManager subclass. " @"The instance presented was of class %@", [[newNibManager class] description]]; error = YES; } if (!error) { // If we have an old manager, let it know we have moved // on. [[self nibManager] removeWindowManager:self]; // Set our own ivar, but don't retain it since that would create // a cyclic reference. _nibManager = newNibManager; // Let our new controller know about us. [[self nibManager] addWindowManager:self]; } } //------------------------------------------------------------------- // Accessing the main window //------------------------------------------------------------------- - (NSWindow*) window /*" Returns the main window. "*/ { return _window; } - (void) setWindow:(NSWindow*)newWindow /*" This is usually just called when the nib is being unarchived if you connected the outlets in IB. We retain our window. "*/ { [_window autorelease]; _window = [newWindow retain]; } - (NSString*) windowTitle /*" Returns the main Window's title. "*/ { return [[self window] title]; } - (void) setWindowTitle:(NSString*)title /*" Sets the main Window's title to the argument. "*/ { [[self window] setTitle:title]; } //------------------------------------------------------------------- // Window cascading //------------------------------------------------------------------- - (BOOL) autoCascadesWindow /*" Returns YES if we try to cascade our window before it is brought on the screen. The default is YES. "*/ { return _autoCascadesWindow; } - (void) setAutoCascadesWindow:(BOOL)cascadeIt /*" Sets whether we try to cascade our window before it's brought to the screen. The default is YES. "*/ { _autoCascadesWindow = cascadeIt; } - (void) setCascadeOffset:(float)x :(float)y /*" Sets the amount we should cascade our window. The default for both the x and y offset is 25.0. "*/ { _xOffset = x; _yOffset = y; } //------------------------------------------------------------------- // Checking the document status //------------------------------------------------------------------- - (BOOL) isDocumentEdited /*" Returns YES if the document has been edited, NO otherwise. "*/ { return [[self window] isDocumentEdited]; } - (void) setDocumentEdited:(BOOL)docNowEdited /*" Sets the document edited flag. This method is invoked automatically if anything in the interface is edited by the user. Subclass should invoke this method if they modify any of their controlled objects outside the normal framwork. "*/ { if ([self isDocumentEdited] != docNowEdited) { NSWindow* myWindow = [self window]; [myWindow setDocumentEdited:docNowEdited]; // Not sure if this is needed... [myWindow displayIfNeeded]; } } //------------------------------------------------------------------- // Display management //------------------------------------------------------------------- - (void) makeKeyConditionallyAndOrderFront:sender /*" Like NSWindow's #makeKeyAndOrderFront: except the window isn't made key unless the application is active to prevent the app from continually asserting itself. This should be used instead of sending our window a #makeKeyAndOrderFront: message. "*/ { NSWindow* window = [self window]; // Autocascade the window if we haven't already, we should, // and it isn't visible yet. if ([self autoCascadesWindow]) { [self _tryToCascadeWindow]; } // Make my main Window key and/or just order it to the front. if ([NSApp isActive]) { [window makeKeyAndOrderFront:sender]; } else { [window orderFront:sender]; } } - (BOOL) isVisible /*" Returns YES if the main Window is visible to the user, NO otherwise. "*/ { return [[self window] isVisible]; } - (void) performClose:(id)sender /*" This message can be sent when we want the manager to close. It just sends a #performClose: message to our main Window which initiates the closing and releasing of everything else. You could extend this method to stop the #performClose: message from being sent under certain circumstances. Currently, the #performClose: message is sent only if our main Window is visible. "*/ { if ([self isVisible]) { [[self window] performClose:self]; } } - (void) close /*" Sends our main window a close message. See the Window documentation for the difference between sending #performClose: and a #close: message to a window. The message is only sent if the window is visible. "*/ { if ([self isVisible]) { [[self window] close]; } } //------------------------------------------------------------------- // Window frame management //------------------------------------------------------------------- - (BOOL) autosavesWindowFrame { return _autosavesWindowFrame; } - (void) setAutosavesWindowFrame:(BOOL)saveFrame { _autosavesWindowFrame = saveFrame; } - (NSString*) windowFrameName { return _windowFrameName; } - (void) setWindowFrameName:(NSString*)frameName { [_windowFrameName autorelease]; _windowFrameName = [frameName copy]; } - (void) setWindowFrameFromDefaults /*" Sets our main window's window frame stored in our defaults. This method only works if #windowFrameName returns something other than nil and the name returned is actually in the defaults database. "*/ { NSString* frameName = [self windowFrameName]; if (frameName != nil) { [[self window] setFrameUsingName:[self windowFrameName]]; } } - (void) saveWindowFrameToDefaults /*" Saves our current window frame in the defaults database so it can later be retrieved with #setWindowFrameFromDefaults. This method only works if #windowFramName returns something other than nil. "*/ { NSString* frameName = [self windowFrameName]; if (frameName != nil) { [[self window] saveFrameUsingName:[self windowFrameName]]; } } - (BOOL) isReleasedWhenWindowClosed /*" Returns YES if, when our window is closed we release ourself (and the window too). The default is NO. "*/ { return _releasedWhenWindowClosed; } - (void) setReleasedWhenWindowClosed:(BOOL)freeUs /*" Sets whether, when our window is closed whether we release ourselves and our window. The default is NO. "*/ { _releasedWhenWindowClosed = freeUs; } @end @implementation MiscWindowManager (WindowDelegate) - (void) windowWillMiniaturize:(NSNotification*)sender /*" Installs the miniwindowIcon. Returns self. "*/ { if ([self _miniwindowIcon] != nil) { [[self window] setMiniwindowImage: [NSImage imageNamed:[self _miniwindowIcon]]]; } } - (BOOL) windowShouldClose:(id)ourWindow /*" If the main Window is dirty *and visible*, ask the user to save before proceeding with the close. If the user closed the Window previously (which they must have if it wasn't visible), they've already been asked this question, so don't ask them again. You shouldn't override or extend this method. Custom code should either be added to #_windowShouldClose:, #_queryWindowShouldClose: or #_windowClosed. "*/ { BOOL shouldClose = YES; // We'll close unless stopped. if (shouldClose) { // Give our class the opportunity to stop the close. If stopped // some sort of alert panel should probably be shown to explain // why we didn't follow their wishes. shouldClose = [self _windowShouldClose:ourWindow]; } if (shouldClose) { // Only runs the alert Panel if the Window is dirty and visible. shouldClose = [self _alertUserOfWindowClose:ourWindow]; } // This code must be the last executed before the window closes. If // you want to add more window will close hooks make sure they are // before this. if (shouldClose) { // We will be freeing the window in our release method so don't // let it free itself prematurely (if it happened to be set to free // early). [ourWindow setReleasedWhenClosed:NO]; // It seems inevitable that we will close now. [self _windowClosed]; } if (shouldClose && [self isReleasedWhenWindowClosed]) { // We'll free the window itself in our release message. [self autorelease]; } // Return value of NO aborts the close operation. return shouldClose; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.