source: trunk/ICeCoffEE/ICeCoffEE/ICeCoffEEServicePrefController.m@ 432

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

Fragile hack to determine whether we should draw the highlighted row as active.

File size: 19.9 KB
Line 
1//
2// ICeCoffEEServicePrefController.m
3// ICeCoffEE APE
4//
5// Created by Nicholas Riley on Fri Jun 06 2003.
6// Copyright (c) 2003 Nicholas Riley. All rights reserved.
7//
8
9#import "ICeCoffEEShared.h"
10#import "ICeCoffEEServices.h"
11#import "ICeCoffEEServicePrefController.h"
12#import "ICeCoffEEMenuOutlineView.h"
13#import "ICeCoffEENonHighlightingButtonCell.h"
14#import "ICeCoffEEInvertingTextFieldCell.h"
15#import "ICeCoffEELabeledIconCell.h"
16#import <objc/objc.h>
17#import <ApplicationEnhancer/ApplicationEnhancer.h>
18#import <QuartzCore/QuartzCore.h>
19
20const int ICCF_SERVICE_UNKNOWN = 0;
21const int ICCF_SERVICE_SHOWN = 1;
22const int ICCF_SERVICE_HIDDEN = 2;
23const int ICCF_SERVICE_MIXED = 3;
24
25static NSDictionary *ICCF_SERVICE_OPTION_HIDDEN;
26
27static float ICCF_TableViewCellHeight(NSTableView *tableView) {
28 return ([tableView rowHeight] + [tableView intercellSpacing].height);
29}
30
31static NSMutableDictionary *keyEquivalents;
32static NSDictionary *userKeyEquivalents;
33
34static void ICCF_RemoveSingleKeyEquivalents() {
35 NSMutableArray *singleKeys = [[NSMutableArray alloc] init];
36 NSEnumerator *e = [[keyEquivalents allKeys] objectEnumerator];
37 NSString *keyEquivalent;
38 ICLog(@"before ICCF_RemoveSingleKeyEquivalents: %@", keyEquivalents);
39 while ( (keyEquivalent = [e nextObject]) != nil) {
40 if ([[keyEquivalents objectForKey: keyEquivalent] count] == 1)
41 [singleKeys addObject: keyEquivalent];
42 }
43 [keyEquivalents removeObjectsForKeys: singleKeys];
44 [singleKeys release];
45 ICLog(@"after ICCF_RemoveSingleKeyEquivalents: %@", keyEquivalents);
46}
47
48static inline unsigned ICCF_CountForKeyEquivalent(NSString *keyEquivalent) {
49 if (keyEquivalent == nil) return 0;
50 NSMutableSet *setOrNil = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
51 return (setOrNil == nil) ? 0 : [setOrNil count];
52}
53
54static inline void ICCF_AddKeyEquivalentForItem(NSMenuItem *item) {
55 NSString *keyEquivalent = [item toolTip];
56 if (keyEquivalent == nil) return;
57 NSMutableSet *setOrNil = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
58 if (setOrNil == nil) return;
59 [setOrNil addObject: item];
60}
61
62static inline void ICCF_RemoveKeyEquivalentForItem(NSMenuItem *item) {
63 NSString *keyEquivalent = [item toolTip];
64 if (keyEquivalent == nil) return;
65 NSMutableSet *setOrNil = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
66 if (setOrNil == nil) return;
67 [setOrNil removeObject: item];
68}
69
70static int ICCF_GetServiceState(NSMenuItem *item) {
71 return [item tag];
72}
73
74static void ICCF_SetServiceState(NSMenuItem *item, int state) {
75 [item setTag: state];
76}
77
78static inline void ICCF_UpdateKeyEquivalentForItem(NSMenuItem *item, int state) {
79 return; // XXX disabled until we can affect menubar Services menu(s)
80 int oldState = ICCF_GetServiceState(item);
81 if ((oldState == ICCF_SERVICE_UNKNOWN || oldState == ICCF_SERVICE_SHOWN) && state == ICCF_SERVICE_HIDDEN)
82 ICCF_RemoveKeyEquivalentForItem(item);
83 else if (oldState == ICCF_SERVICE_HIDDEN && (state == ICCF_SERVICE_SHOWN || state == ICCF_SERVICE_UNKNOWN))
84 ICCF_AddKeyEquivalentForItem(item);
85}
86
87
88static inline NSCellStateValue ICCF_ServiceItemState(NSMenuItem *item) {
89 int state = ICCF_GetServiceState(item);
90 if (state == ICCF_SERVICE_HIDDEN)
91 return NSOffState;
92 if (state == ICCF_SERVICE_MIXED)
93 return NSMixedState;
94 return NSOnState;
95}
96
97static void ICCF_PropagateServiceStateChange(NSMenu *menu, int state) {
98 NSEnumerator *e = [[menu itemArray] objectEnumerator];
99 NSMenuItem *item;
100 NSMenu *submenu;
101
102 while ( (item = [e nextObject]) != nil) {
103 submenu = [item submenu];
104 if (submenu != nil)
105 ICCF_PropagateServiceStateChange(submenu, state);
106 else
107 ICCF_UpdateKeyEquivalentForItem(item, state);
108
109 ICCF_SetServiceState(item, state);
110 }
111}
112
113static NSCellStateValue ICCF_PropagateServiceState(NSMenuItem *item, NSMenuItem *changedItem) {
114 NSMenu *submenu = [item submenu];
115 if (submenu == nil) return ICCF_ServiceItemState(item);
116
117 if (item == changedItem) ICCF_PropagateServiceStateChange(submenu, [item tag]);
118
119 BOOL areOn = NO, areOff = NO;
120 NSEnumerator *e = [[submenu itemArray] objectEnumerator];
121 NSMenuItem *subItem;
122 while ( (subItem = [e nextObject]) != nil) {
123 switch (ICCF_PropagateServiceState(subItem, changedItem)) {
124 case NSOnState: if (!areOff) { areOn = YES; continue; }
125 break;
126 case NSOffState: if (!areOn) { areOff = YES; continue; }
127 break;
128 case NSMixedState:
129 break;
130 }
131 ICCF_SetServiceState(item, ICCF_SERVICE_MIXED);
132 return NSMixedState;
133 }
134 if (areOn) {
135 ICCF_SetServiceState(item, ICCF_SERVICE_SHOWN);
136 return NSOnState;
137 } else {
138 ICCF_SetServiceState(item, ICCF_SERVICE_HIDDEN);
139 return NSOffState;
140 }
141}
142
143static NSMutableDictionary *ICCF_RetainedServiceOptionsDictionary(NSMenu *menu) {
144 NSEnumerator *e = [[menu itemArray] objectEnumerator];
145 NSMenuItem *item;
146 NSMenu *submenu;
147 NSMutableDictionary *dict = nil, *subDict = nil, *submenuDict = nil;
148
149 while ( (item = [e nextObject]) != nil) {
150 submenu = [item submenu];
151 if (ICCF_ServiceItemState(item) == NSOffState) {
152 subDict = [ICCF_SERVICE_OPTION_HIDDEN retain];
153 } else if (submenu != nil) {
154 submenuDict = ICCF_RetainedServiceOptionsDictionary(submenu);
155 if (submenuDict == nil)
156 continue;
157 subDict = [[NSDictionary alloc] initWithObjectsAndKeys: submenuDict, kICServiceSubmenu, nil];
158 [submenuDict release];
159 } else continue;
160 if (dict == nil) {
161 dict = [[NSMutableDictionary alloc] init];
162 }
163 [dict setObject: subDict forKey: [item title]];
164 [subDict release];
165 }
166 return dict;
167}
168
169static void ICCF_RestoreServiceOptionsDictionary(NSMenu *menu, NSDictionary *dict) {
170 NSEnumerator *e = [dict keyEnumerator];
171 NSString *itemTitle;
172 NSDictionary *subDict, *submenuDict;
173 NSMenuItem *item;
174 NSMenu *submenu;
175
176 // XXX handle exceptions
177 while ( (itemTitle = [e nextObject]) != nil) {
178 item = (NSMenuItem *)[menu itemWithTitle: itemTitle];
179 if (item == nil) continue;
180 subDict = [dict objectForKey: itemTitle];
181 if ([[subDict objectForKey: (NSString *)kICServiceHidden] boolValue]) {
182 ICCF_SetServiceState(item, ICCF_SERVICE_HIDDEN);
183 ICCF_RemoveKeyEquivalentForItem(item);
184 }
185 if ( (submenu = [item submenu]) != nil) {
186 submenuDict = [subDict objectForKey: (NSString *)kICServiceSubmenu];
187 if ([submenuDict count] == 0)
188 ICCF_PropagateServiceStateChange(submenu, ICCF_SERVICE_HIDDEN);
189 else
190 ICCF_RestoreServiceOptionsDictionary(submenu, submenuDict);
191 }
192 }
193}
194
195static void ICCF_AddServiceKeyEquivalentsAndIcons(NSMenu *menu, NSDictionary *serviceInfo) {
196 if (serviceInfo == nil) return;
197 NSEnumerator *enumerator = [[menu itemArray] objectEnumerator];
198 NSMenuItem *menuItem;
199 NSMenu *submenu;
200 NSDictionary *itemInfo = nil;
201 while ( (menuItem = [enumerator nextObject]) != nil) {
202 itemInfo = [serviceInfo objectForKey: [menuItem title]];
203 if (itemInfo == nil) continue;
204
205 if ( (submenu = [menuItem submenu]) != nil) {
206 ICCF_AddServiceKeyEquivalentsAndIcons(submenu, [itemInfo objectForKey: (NSString *)kICServiceSubmenu]);
207 } else {
208 NSString *keyEquivalent = (NSString *)[itemInfo objectForKey: (NSString *)kICServiceShortcut];
209 if (keyEquivalent == nil) {
210 keyEquivalent = [userKeyEquivalents objectForKey: [menuItem title]];
211 } else if ([keyEquivalent length] != 1) {
212 keyEquivalent = nil;
213 } else {
214 // XXX Inconsistency between Cocoa and Carbon: always command-shift in Carbon, not in Cocoa. Since we only patch Cocoa for the moment, keep as is.
215 unichar key = [keyEquivalent characterAtIndex: 0];
216 if ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember: key])
217 keyEquivalent = [NSString stringWithFormat: @"$@%c", key];
218 else
219 keyEquivalent = [NSString stringWithFormat: @"@%c", key];
220 }
221 if (keyEquivalent != nil) {
222 [menuItem setToolTip: keyEquivalent];
223 NSMutableSet *equivalentItems = (NSMutableSet *)[keyEquivalents objectForKey: keyEquivalent];
224 if (equivalentItems == nil) {
225 equivalentItems = [[NSMutableSet alloc] initWithObjects: menuItem, nil];
226 [keyEquivalents setObject: equivalentItems forKey: keyEquivalent];
227 [equivalentItems release];
228 } else {
229 [equivalentItems addObject: menuItem];
230 }
231 }
232 }
233
234 NSString *bundlePath = (NSString *)[itemInfo objectForKey: (NSString *)kICServiceBundlePath];
235 if (bundlePath == NULL) continue;
236 IconRef serviceIcon = ICCF_CopyIconRefForPath(bundlePath);
237 if (serviceIcon == NULL) continue;
238 [menuItem _setIconRef: serviceIcon];
239 ReleaseIconRef(serviceIcon);
240 }
241}
242
243@implementation ICeCoffEEServicePrefController
244
245#pragma mark class initialization
246
247+ (void)initialize;
248{
249 ICCF_SERVICE_OPTION_HIDDEN = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithBool: YES], kICServiceHidden, nil];
250}
251
252#pragma mark initialize-release
253
254- (id)initWithParentWindow:(NSWindow *)parent;
255{
256 if ( (self = [self initWithWindowNibName: @"Select services"])) {
257 NSWindow *window = [self window]; // connect outlets
258 [serviceOutline setAutoresizesOutlineColumn: NO];
259
260 NSButtonCell *checkBoxCell = [[ICeCoffEENonHighlightingButtonCell alloc] init];
261 [checkBoxCell setButtonType: NSSwitchButton];
262 [checkBoxCell setImagePosition: NSImageOnly];
263 [checkBoxCell setAllowsMixedState: YES];
264
265 [[serviceOutline tableColumnWithIdentifier: @"show"] setDataCell: checkBoxCell];
266 [checkBoxCell release];
267
268 NSTextFieldCell *textFieldCell = [[serviceOutline tableColumnWithIdentifier: @"service"] dataCell];
269 [textFieldCell setWraps: YES];
270 [[serviceOutline tableColumnWithIdentifier: @"service"] setDataCell:
271 [ICeCoffEELabeledIconCell copyFromTextFieldCell: textFieldCell]];
272
273 textFieldCell = [[serviceOutline tableColumnWithIdentifier: @"key"] dataCell];
274 ((struct objc_object *)textFieldCell)->isa = [ICeCoffEEInvertingTextFieldCell class];
275
276 [serviceOutline noteNumberOfRowsChanged]; // or we get no active scroll bar or initial selection
277
278 [window setResizeIncrements: NSMakeSize(1, ICCF_TableViewCellHeight(serviceOutline))];
279 if (parent != nil) {
280 [NSApp beginSheet: window modalForWindow: parent modalDelegate: self didEndSelector: nil contextInfo: nil];
281 } else {
282 [window center];
283 [window makeKeyAndOrderFront: nil];
284 }
285 }
286 return self;
287}
288
289- (void)dealloc;
290{
291 [keyEquivalents release]; keyEquivalents = nil;
292 [userKeyEquivalents release]; userKeyEquivalents = nil;
293 [servicesMenu release]; servicesMenu = nil;
294 [closedTriangle release]; closedTriangle = nil;
295 [selectedClosedTriangle release]; selectedClosedTriangle = nil;
296 [openTriangle release]; openTriangle = nil;
297 [selectedOpenTriangle release]; selectedOpenTriangle = nil;
298 [super dealloc];
299}
300
301#pragma mark actions
302
303- (IBAction)showAll:(NSButton *)sender;
304{
305 ICCF_PropagateServiceStateChange(servicesMenu, 0);
306 [serviceOutline reloadData];
307}
308
309- (IBAction)hideAll:(NSButton *)sender;
310{
311 ICCF_PropagateServiceStateChange(servicesMenu, ICCF_SERVICE_HIDDEN);
312 [serviceOutline reloadData];
313}
314
315- (void)closeWithReturnCode:(int)returnCode;
316{
317 if ([[self window] isSheet]) {
318 [NSApp endSheet: [self window] returnCode: NSRunAbortedResponse];
319 }
320 [self close];
321}
322
323- (IBAction)cancel:(NSButton *)sender;
324{
325 [self closeWithReturnCode: NSRunAbortedResponse];
326}
327
328- (IBAction)saveChanges:(NSButton *)sender;
329{
330 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
331 NSMutableDictionary *icDefaults = [[defaults persistentDomainForName: (NSString *)kICBundleIdentifier] mutableCopy];
332 NSDictionary *serviceOptions = ICCF_RetainedServiceOptionsDictionary(servicesMenu);
333 if (serviceOptions != nil) {
334 [icDefaults setObject: serviceOptions forKey: (NSString *)kICServiceOptions];
335 [serviceOptions release];
336 } else {
337 [icDefaults removeObjectForKey: (NSString *)kICServiceOptions];
338 }
339 [defaults setPersistentDomain: icDefaults forName: (NSString *)kICBundleIdentifier];
340 [defaults synchronize];
341 APEMessageBroadcast(kICBundleIdentifier, kICPreferencesChanged, NULL);
342 [icDefaults release];
343 [self closeWithReturnCode: NSRunStoppedResponse];
344}
345
346@end
347
348@implementation ICeCoffEEServicePrefController (NSOutlineViewDataSource)
349
350- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item;
351{
352 if (servicesMenu == nil) {
353 keyEquivalents = [[NSMutableDictionary alloc] init];
354 userKeyEquivalents = [[[NSUserDefaults standardUserDefaults] dictionaryForKey: @"NSUserKeyEquivalents"] retain];
355 servicesMenu = [[NSMenu alloc] initWithTitle: @""];
356 ICCF_SetServicesMenu(servicesMenu);
357 ICCF_AddServiceKeyEquivalentsAndIcons(servicesMenu, ICCF_GetServicesInfo());
358 ICCF_RemoveSingleKeyEquivalents();
359
360 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
361 NSDictionary *icDefaults = [defaults persistentDomainForName: (NSString *)kICBundleIdentifier];
362 NSDictionary *serviceOptions = [icDefaults objectForKey: (NSString *)kICServiceOptions];
363 ICCF_RestoreServiceOptionsDictionary(servicesMenu, serviceOptions);
364 }
365 return [(item == nil ? servicesMenu : [item submenu]) numberOfItems];
366}
367
368- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item;
369{
370 return (item == nil ? YES : [item submenu] != nil);
371}
372
373- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item;
374{
375 return [(item == nil ? servicesMenu : [item submenu]) itemAtIndex: index];
376}
377
378NSAttributedString *ICCF_KeyEquivalentAttributedString(NSString *self, unsigned count);
379
380- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
381{
382 if ([[tableColumn identifier] isEqualToString: @"service"]) {
383 static NSDictionary *attrDict = nil;
384 if (attrDict == nil) { // XXX we leak this, but so does the Apple sample code...
385 NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
386 [style setLineBreakMode: NSLineBreakByTruncatingMiddle];
387 attrDict = [[NSDictionary alloc] initWithObjectsAndKeys: style, NSParagraphStyleAttributeName, nil];
388 [style release];
389 }
390 return [[[NSAttributedString alloc] initWithString: [item title] attributes: attrDict] autorelease];
391 } else if ([[tableColumn identifier] isEqualToString: @"show"]) {
392 int state = ICCF_GetServiceState(item);
393 if ([item submenu] != nil && state == ICCF_SERVICE_UNKNOWN) {
394 return [NSNumber numberWithInt: ICCF_PropagateServiceState(item, nil)];
395 }
396 return [NSNumber numberWithInt: ICCF_ServiceItemState(item)];
397 } else if ([[tableColumn identifier] isEqualToString: @"key"]) {
398 NSString *equivalent = [item toolTip];
399 if (equivalent == nil)
400 return nil;
401 return ICCF_KeyEquivalentAttributedString(equivalent, ICCF_CountForKeyEquivalent(equivalent));
402 }
403 return nil;
404}
405
406- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
407{
408 if ([[tableColumn identifier] isEqualToString: @"show"]) {
409 int newState = [object boolValue] ? ICCF_SERVICE_SHOWN : ICCF_SERVICE_HIDDEN;
410 ICCF_UpdateKeyEquivalentForItem(item, newState);
411 ICCF_SetServiceState(item, newState);
412
413 NSMenu *submenu = [item menu];
414 if (submenu == servicesMenu) {
415 ICCF_PropagateServiceState(item, item);
416 } else {
417 NSMenu *supermenu;
418 while ( (supermenu = [submenu supermenu]) != servicesMenu) {
419 submenu = supermenu;
420 }
421 ICCF_PropagateServiceState((NSMenuItem *)[supermenu itemAtIndex: [supermenu indexOfItemWithSubmenu: submenu]], item);
422 }
423 [outlineView reloadData];
424 }
425}
426
427@end
428
429@implementation ICeCoffEEServicePrefController (NSOutlineViewDelegate)
430
431- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item;
432{
433 if (![[tableColumn identifier] isEqualToString: @"service"])
434 return;
435 [(ICeCoffEELabeledIconCell *)cell setIconRef: [item _iconRef]];
436}
437
438static NSImage *ICCF_InvertedImage(NSImage *image) {
439 NSImage *invertedImage = [[NSImage alloc] initWithSize: [image size]];
440 NSBitmapImageRep *imageRep = [NSBitmapImageRep imageRepWithData: [image TIFFRepresentation]];
441 CIImage *source = [[CIImage alloc] initWithBitmapImageRep: imageRep];
442 CIColor *black = [[CIColor alloc] initWithColor: [NSColor blackColor]];
443
444 CIFilter *monochromeFilter = [CIFilter filterWithName: @"CIColorMonochrome"];
445 [monochromeFilter setValue: source forKey: @"inputImage"];
446 [monochromeFilter setValue: [NSNumber numberWithFloat: 1.0] forKey: @"inputIntensity"];
447 [monochromeFilter setValue: black forKey: @"inputColor"];
448
449 CIFilter *invertFilter = [CIFilter filterWithName: @"CIColorInvert"];
450 [invertFilter setValue: [monochromeFilter valueForKey: @"outputImage"] forKey: @"inputImage"];
451
452 CIFilter *maskToAlphaFilter = [CIFilter filterWithName: @"CIMaskToAlpha"];
453 [maskToAlphaFilter setValue: [invertFilter valueForKey: @"outputImage"] forKey: @"inputImage"];
454
455 [invertedImage lockFocus];
456 CIContext *context = [CIContext contextWithCGContext: [[NSGraphicsContext currentContext] graphicsPort]
457 options: nil];
458 CIImage *result = [maskToAlphaFilter valueForKey: @"outputImage"];
459 [context drawImage: result atPoint: CGPointZero fromRect: [result extent]];
460 [invertedImage unlockFocus];
461
462 [source release];
463 [black release];
464
465 return invertedImage;
466}
467
468- (void)outlineView:(NSOutlineView *)outlineView willDisplayOutlineCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item;
469{
470 static BOOL isInverted = NO;
471
472 if (closedTriangle == nil) {
473 closedTriangle = [[cell image] retain];
474 openTriangle = [[cell alternateImage] retain];
475 selectedClosedTriangle = ICCF_InvertedImage(closedTriangle);
476 selectedOpenTriangle = ICCF_InvertedImage(openTriangle);
477 }
478
479 if (![outlineView isRowSelected: [outlineView rowForItem: item]] ||
480 ![(ICeCoffEEMenuOutlineView *)outlineView shouldUseActiveHighlight]) {
481 if (!isInverted)
482 return;
483
484 [cell setImage: closedTriangle];
485 [cell setAlternateImage: openTriangle];
486 isInverted = NO;
487 return;
488 }
489
490 // not checking for isInverted is intentional - images reset when triangle is flipped
491 [cell setImage: selectedClosedTriangle];
492 [cell setAlternateImage: selectedOpenTriangle];
493 isInverted = YES;
494}
495
496@end
497
498@implementation ICeCoffEEServicePrefController (NSWindowDelegate)
499
500- (NSRect)windowWillUseStandardFrame:(NSWindow *)sender defaultFrame:(NSRect)defaultFrame;
501{
502 NSWindow *window = [serviceOutline window];
503 NSRect frame = [window frame];
504 NSScrollView *scrollView = [serviceOutline enclosingScrollView];
505 float displayedHeight = [[scrollView contentView] bounds].size.height;
506 float heightChange = [[scrollView documentView] bounds].size.height - displayedHeight;
507 float heightExcess;
508
509 if (heightChange >= 0 && heightChange <= 1) {
510 // either the window is already optimal size, or it's too big
511 float rowHeight = ICCF_TableViewCellHeight(serviceOutline);
512 heightChange = (rowHeight * [serviceOutline numberOfRows]) - displayedHeight;
513 }
514
515 frame.size.height += heightChange;
516
517 if ( (heightExcess = [window minSize].height - frame.size.height) > 1 ||
518 (heightExcess = [window maxSize].height - frame.size.height) < 1) {
519 heightChange += heightExcess;
520 frame.size.height += heightExcess;
521 }
522
523 frame.origin.y -= heightChange;
524
525 return frame;
526}
527
528@end
529
530@implementation ICeCoffEEServicePrefController (NSWindowNotifications)
531
532- (void)windowWillClose:(NSNotification *)notification;
533{
534 [self autorelease];
535}
536
537@end
Note: See TracBrowser for help on using the repository browser.