source: trunk/Cocoa/F-Script Anywhere/Source/FSAWindowManager.m@ 395

Last change on this file since 395 was 16, checked in by Nicholas Riley, 22 years ago

F-Script Anywhere 1.1.5

File size: 8.1 KB
Line 
1//
2// FSAWindowManager.m
3// F-Script Anywhere
4//
5// Created by Nicholas Riley on Mon Sep 30 2002.
6// Copyright (c) 2002 Nicholas Riley. All rights reserved.
7//
8
9#import "FSAWindowManager.h"
10#import "FSAnywhere.h"
11
12@interface FSAWindowRecord:NSObject
13{
14 unsigned level;
15 NSWindow *window;
16 BOOL windowClosed;
17 FSAWindowRecord *parent;
18 NSMutableArray *subordinates;
19 NSMenuItem *menuItem;
20}
21- (id)initWithWindow:(NSWindow *)aWindow parent:(FSAWindowRecord *)aRecord;
22- (void)addSubordinate:(FSAWindowRecord *)aRecord;
23- (void)removeSubordinate:(FSAWindowRecord *)aRecord;
24- (BOOL)hasSubordinates;
25- (unsigned)level;
26- (NSString *)levelPaddedTitle;
27- (NSMenuItem *)menuItem;
28- (NSWindow *)window;
29@end
30
31@implementation FSAWindowRecord
32
33- (id)initWithWindow:(NSWindow *)aWindow parent:(FSAWindowRecord *)aRecord;
34{
35 if ( (self = [super init]) != nil) {
36 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
37 window = [aWindow retain];
38 [nc addObserver: self selector: @selector(windowWillClose:)
39 name: NSWindowWillCloseNotification object: window];
40 [nc addObserver: self selector: @selector(windowDidBecomeKey:)
41 name: NSWindowDidBecomeKeyNotification object: window];
42 [nc addObserver: self selector: @selector(windowDidResignKey:)
43 name: NSWindowDidResignKeyNotification object: window];
44 if (aRecord == nil) {
45 level = 1;
46 } else {
47 parent = aRecord; // note: not retaining parent
48 [parent addSubordinate: self];
49 level = [parent level] + 1;
50 }
51 [self retain]; // manage own object lifetime, tie to window lifetime
52 }
53 return self;
54}
55
56- (void)dealloc;
57{
58 [[NSNotificationCenter defaultCenter] removeObserver: self];
59 [[menuItem menu] removeItem: menuItem];
60 [menuItem release]; menuItem = nil;
61 [window release]; window = nil;
62 parent = nil;
63 NSAssert1(![self hasSubordinates], @"Window still has subordinates at dealloc: %@", self);
64 [subordinates release]; subordinates = nil;
65 // XXX still get this from time to time, canÕt reproduce reliably... please let me know if you can!
66 NSAssert1(windowClosed, @"Window hasn't closed at dealloc: %@", self);
67 [super dealloc];
68}
69
70- (unsigned)level;
71{
72 return level;
73}
74
75- (NSWindow *)window;
76{
77 return window;
78}
79
80- (void)addSubordinate:(FSAWindowRecord *)aRecord;
81{
82 if (subordinates == nil)
83 subordinates = [[NSMutableArray alloc] init];
84 NSAssert(![subordinates containsObject: aRecord], @"subordinate already exists");
85 [subordinates addObject: aRecord];
86}
87
88- (BOOL)hasSubordinates;
89{
90 return (subordinates != nil && [subordinates count] > 0);
91}
92
93- (void)removeSubordinate:(FSAWindowRecord *)aRecord;
94{
95 NSAssert(subordinates != nil && [subordinates containsObject: aRecord], @"subordinate does not exist");
96 [subordinates removeObject: aRecord];
97 if ([subordinates count] == 0 && windowClosed)
98 [self release];
99}
100
101- (NSString *)levelPaddedTitle;
102{
103 NSString *windowTitle = [window title];
104 NSMutableString *paddedTitle = [[NSMutableString alloc] initWithCapacity: [windowTitle length] + 3 * level + 2 * windowClosed];
105 unsigned i;
106 for (i = 0 ; i < level ; i++) {
107 [paddedTitle appendString: @" "];
108 }
109 if (windowClosed) [paddedTitle appendString: @"("];
110 [paddedTitle appendString: windowTitle];
111 if (windowClosed) [paddedTitle appendString: @")"];
112 return [paddedTitle autorelease];
113}
114
115- (NSMenuItem *)menuItem;
116{
117 if (menuItem == nil) {
118 menuItem = [[NSMenuItem alloc] initWithTitle: [self levelPaddedTitle]
119 action: @selector(makeKeyAndOrderFront:)
120 keyEquivalent: @""];
121 [menuItem setTarget: window];
122 [menuItem setRepresentedObject: window];
123 [menuItem setState: NSOnState];
124 }
125 return menuItem;
126}
127
128- (NSString *)description;
129{
130 return [NSString stringWithFormat: @"%@ [L%u] for %@%@ subs %u%@%@", [super description], level, window, windowClosed ? @" (closed)" : @"", [subordinates count], menuItem == nil ? @"" : [NSString stringWithFormat: @" item %@", menuItem], parent == nil ? @"" : [NSString stringWithFormat: @"\n parent: %@", parent]];
131}
132
133@end
134
135@implementation FSAWindowRecord (NSWindowNotifications)
136
137- (void)windowWillClose:(NSNotification *)notification;
138{
139 windowClosed = YES;
140
141 [parent removeSubordinate: self];
142
143 FSALog(@"windowWillClose (rc %u): %@", [self retainCount], notification);
144 if ([self hasSubordinates]) {
145 [menuItem setTitle: [self levelPaddedTitle]];
146 } else {
147 [self release];
148 }
149}
150
151- (void)windowDidBecomeKey:(NSNotification *)notification;
152{
153 if (windowClosed) {
154 windowClosed = NO;
155 [menuItem setTitle: [self levelPaddedTitle]];
156 [parent addSubordinate: self];
157 }
158 [menuItem setState: NSOnState];
159}
160
161- (void)windowDidResignKey:(NSNotification *)notification;
162{
163 [menuItem setState: NSOffState];
164}
165
166@end
167
168static FSAWindowManager *FSASharedWindowManager;
169
170@implementation FSAWindowManager
171
172+ (FSAWindowManager *)sharedManager;
173{
174 if (FSASharedWindowManager == nil) {
175 FSASharedWindowManager = [[self alloc] init];
176 }
177 return FSASharedWindowManager;
178}
179
180- (id)init;
181{
182 if ( (self = [super init]) != nil) {
183 if (FSASharedWindowManager != nil) {
184 [self release];
185 self = nil;
186 } else {
187 records = [[NSMutableDictionary alloc] init];
188 }
189 }
190 return self;
191}
192
193- (void)setWindowMenu:(NSMenu *)windowMenu;
194{
195 menu = [windowMenu retain];
196}
197
198- (FSAWindowRecord *)recordForWindow:(NSWindow *)window;
199{
200 FSAWindowRecord *record = [records objectForKey: [NSValue valueWithNonretainedObject: window]];
201 NSAssert1(record != nil, @"no record for window %@", window);
202 return record;
203}
204
205- (void)addRecord:(FSAWindowRecord *)aRecord;
206{
207 NSWindow *window = [aRecord window];
208 NSValue *wValue = [NSValue valueWithNonretainedObject: window];
209 [[NSNotificationCenter defaultCenter]
210 addObserver: self selector: @selector(windowWillClose:)
211 name: NSWindowWillCloseNotification object: window];
212 NSAssert1(![self windowIsRegistered: window], @"Window already registered: %@", window);
213 [records setObject: aRecord forKey: wValue];
214 if ([records count] == 1) {
215 separator = [NSMenuItem separatorItem];
216 [menu addItem: separator];
217 label = [menu addItemWithTitle: @"Windows" action: NULL keyEquivalent: @""];
218 }
219 FSALog(@"Registered:\n%@", aRecord);
220}
221
222- (void)registerWindow:(NSWindow *)window;
223{
224 FSAWindowRecord *record = [[FSAWindowRecord alloc] initWithWindow: window parent: nil];
225 [self addRecord: record];
226 [menu addItem: [record menuItem]];
227 [record release];
228}
229
230- (void)registerSubordinateWindow:(NSWindow *)subWindow forWindow:(NSWindow *)window;
231{
232 FSAWindowRecord *record = [[FSAWindowRecord alloc] initWithWindow: subWindow parent:
233 [self recordForWindow: window]];
234 int itemIndex = [menu indexOfItemWithRepresentedObject: window];
235
236 NSAssert1(itemIndex != -1, @"CanÕt get menu item for window %@", window);
237 [self addRecord: record];
238 [menu insertItem: [record menuItem] atIndex: itemIndex + 1];
239 [record release];
240}
241
242- (BOOL)windowIsRegistered:(NSWindow *)window;
243{
244 return [records objectForKey: [NSValue valueWithNonretainedObject: window]] != nil;
245}
246
247@end
248
249@interface FSAWindowManager (Private)
250- (FSAWindowRecord *)recordForWindow:(NSWindow *)window;
251@end
252
253@implementation FSAWindowManager (NSWindowNotifications)
254
255- (void)windowWillClose:(NSNotification *)notification;
256{
257 NSWindow *window = [notification object];
258 FSAWindowRecord *record = [self recordForWindow: window];
259
260 if ([record hasSubordinates]) return;
261 [records removeObjectForKey: [NSValue valueWithNonretainedObject: window]];
262 if ([records count] == 0) {
263 [menu removeItem: separator];
264 [menu removeItem: label];
265 separator = nil;
266 }
267 [[NSNotificationCenter defaultCenter]
268 removeObserver: self name: NSWindowWillCloseNotification object: window];
269}
270
271@end
Note: See TracBrowser for help on using the repository browser.