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

Last change on this file since 412 was 412, checked in by Nicholas Riley, 12 years ago

Fewer warnings and extraneous build settings.

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.