source: releases/ICeCoffEE/1.4.4b1/ICeCoffEE/ICeCoffEEServicePrefController.m@ 336

Last change on this file since 336 was 336, checked in by Nicholas Riley, 17 years ago

VERSION: Starting with 1.4.4b1, should be close to final.

ICeCoffEEServicePrefController.m: Display correct key equivalents, backported from [319].

ICeCoffEEWebKit.m: Fix Safari 3 beta compatibility; better comment WebKit interfaces.

Info-APE Module.plist: Update version to 1.4.4b1.

ICeCoffEE.xcodeproj: Remove obsolete WebKit header.

English.lproj/APEInfo.rtfd: Backported updates from [320]; release notes.

English.lproj/InfoPlist.strings: Update version to 1.4.4b1.

English.lproj/Localizable.strings: Fix an "APE Manager" reference I didn't catch before.

ape_install: Updated to APE 2.0.3.

ui.plist: Update version to 1.4.4b1.

Info-APEManagerPrefPane.plist: Update version to 1.4.4b1.

File size: 11.9 KB
RevLine 
[142]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"
[182]10#import "ICeCoffEESetServicesMenu.h"
[142]11#import "ICeCoffEEServicePrefController.h"
12#import "ICeCoffEENonHighlightingButtonCell.h"
13#import "ICeCoffEENonHighlightingTextFieldCell.h"
14#import <objc/objc.h>
15#import <ApplicationEnhancer/ApplicationEnhancer.h>
16
17static NSNumber *ICCF_SERVICE_SHOWN, *ICCF_SERVICE_HIDDEN, *ICCF_SERVICE_MIXED;
18static NSDictionary *ICCF_SERVICE_OPTION_HIDDEN;
19
20static float ICCF_TableViewCellHeight(NSTableView *tableView) {
21 return ([tableView rowHeight] + [tableView intercellSpacing].height);
22}
23
[167]24static inline NSCellStateValue ICCF_ServiceItemState(id <NSMenuItem> item) {
[142]25 id state = [item representedObject];
26 return (state == nil) ? NSOnState : [state intValue];
27}
28
29static void ICCF_PropagateServiceStateChange(NSMenu *menu, id state) {
30 NSEnumerator *e = [[menu itemArray] objectEnumerator];
31 NSMenuItem *item;
32 NSMenu *submenu;
33
34 while ( (item = [e nextObject]) != nil) {
35 submenu = [item submenu];
36 if (submenu != nil) {
37 ICCF_PropagateServiceStateChange(submenu, state);
38 [item setRepresentedObject: (state == nil) ? ICCF_SERVICE_SHOWN : state];
39 }
40 [item setRepresentedObject: state];
41 }
42}
43
[167]44static NSCellStateValue ICCF_PropagateServiceState(id <NSMenuItem> item, NSMenuItem *changedItem) {
[142]45 NSMenu *submenu = [item submenu];
46 if (submenu == nil) return ICCF_ServiceItemState(item);
47
48 if (item == changedItem) ICCF_PropagateServiceStateChange(submenu, [item representedObject]);
49
50 BOOL areOn = NO, areOff = NO;
51 NSEnumerator *e = [[submenu itemArray] objectEnumerator];
52 NSMenuItem *subItem;
53 while ( (subItem = [e nextObject]) != nil) {
54 switch (ICCF_PropagateServiceState(subItem, changedItem)) {
55 case NSOnState: if (!areOff) { areOn = YES; continue; }
56 break;
57 case NSOffState: if (!areOn) { areOff = YES; continue; }
58 break;
59 case NSMixedState:
60 break;
61 }
62 [item setRepresentedObject: ICCF_SERVICE_MIXED];
63 return NSMixedState;
64 }
65 if (areOn) {
66 [item setRepresentedObject: ICCF_SERVICE_SHOWN];
67 return NSOnState;
68 } else {
69 [item setRepresentedObject: ICCF_SERVICE_HIDDEN];
70 return NSOffState;
71 }
72}
73
74static NSMutableDictionary *ICCF_RetainedServiceOptionsDictionary(NSMenu *menu) {
75 NSEnumerator *e = [[menu itemArray] objectEnumerator];
76 NSMenuItem *item;
77 NSMenu *submenu;
78 NSMutableDictionary *dict = nil, *subDict = nil, *submenuDict = nil;
79
80 while ( (item = [e nextObject]) != nil) {
81 submenu = [item submenu];
82 if (ICCF_ServiceItemState(item) == NSOffState) {
83 subDict = [ICCF_SERVICE_OPTION_HIDDEN retain];
84 } else if (submenu != nil) {
85 submenuDict = ICCF_RetainedServiceOptionsDictionary(submenu);
86 if (submenuDict == nil)
87 continue;
88 subDict = [[NSDictionary alloc] initWithObjectsAndKeys: submenuDict, kICServiceSubmenu, nil];
89 [submenuDict release];
90 } else continue;
91 if (dict == nil) {
92 dict = [[NSMutableDictionary alloc] init];
93 }
94 [dict setObject: subDict forKey: [item title]];
95 [subDict release];
96 }
97 return dict;
98}
99
100static void ICCF_RestoreServiceOptionsDictionary(NSMenu *menu, NSDictionary *dict) {
101 NSEnumerator *e = [dict keyEnumerator];
102 NSString *itemTitle;
103 NSDictionary *subDict, *submenuDict;
[167]104 id <NSMenuItem> item;
[142]105 NSMenu *submenu;
106
107 // XXX handle exceptions
108 while ( (itemTitle = [e nextObject]) != nil) {
109 item = [menu itemWithTitle: itemTitle];
110 if (item == nil) continue;
111 subDict = [dict objectForKey: itemTitle];
112 if ([[subDict objectForKey: (NSString *)kICServiceHidden] boolValue]) {
113 [item setRepresentedObject: ICCF_SERVICE_HIDDEN];
114 }
115 if ( (submenu = [item submenu]) != nil) {
116 submenuDict = [subDict objectForKey: (NSString *)kICServiceSubmenu];
117 if ([submenuDict count] == 0)
118 ICCF_PropagateServiceStateChange(submenu, ICCF_SERVICE_HIDDEN);
119 else
120 ICCF_RestoreServiceOptionsDictionary(submenu, submenuDict);
121 }
122 }
123}
124
125@implementation ICeCoffEEServicePrefController
126
127#pragma mark class initialization
128
129+ (void)initialize;
130{
131 ICCF_SERVICE_SHOWN = [[NSNumber alloc] initWithInt: NSOnState];
132 ICCF_SERVICE_HIDDEN = [[NSNumber alloc] initWithInt: NSOffState];
133 ICCF_SERVICE_MIXED = [[NSNumber alloc] initWithInt: NSMixedState];
134 ICCF_SERVICE_OPTION_HIDDEN = [[NSDictionary alloc] initWithObjectsAndKeys: [NSNumber numberWithBool: YES], kICServiceHidden, nil];
135}
136
137#pragma mark initialize-release
138
139- (id)initWithParentWindow:(NSWindow *)parent;
140{
141 if ( (self = [self initWithWindowNibName: @"Select services"])) {
142 NSWindow *window = [self window]; // connect outlets
143 NSButtonCell *checkBoxCell = [[ICeCoffEENonHighlightingButtonCell alloc] init];
144 [checkBoxCell setButtonType: NSSwitchButton];
145 [checkBoxCell setImagePosition: NSImageOnly];
146 [checkBoxCell setAllowsMixedState: YES];
147 [[serviceOutline tableColumnWithIdentifier: @"show"] setDataCell: checkBoxCell];
148 [checkBoxCell release];
149
150 NSTextFieldCell *textFieldCell = [[serviceOutline tableColumnWithIdentifier: @"service"] dataCell];
151 ((struct objc_object *)textFieldCell)->isa = [ICeCoffEENonHighlightingTextFieldCell class];
152
153 textFieldCell = [[serviceOutline tableColumnWithIdentifier: @"key"] dataCell];
154 ((struct objc_object *)textFieldCell)->isa = [ICeCoffEENonHighlightingTextFieldCell class];
155
156 [window setResizeIncrements: NSMakeSize(1, ICCF_TableViewCellHeight(serviceOutline))];
157 if (parent != nil) {
158 [NSApp beginSheet: window modalForWindow: parent modalDelegate: self didEndSelector: nil contextInfo: nil];
159 } else {
160 [window center];
161 [window makeKeyAndOrderFront: nil];
162 }
163 }
164 return self;
165}
166
167- (void)dealloc;
168{
169 [servicesMenu release];
170 [super dealloc];
171}
172
173#pragma mark actions
174
175- (IBAction)showAll:(NSButton *)sender;
176{
177 ICCF_PropagateServiceStateChange(servicesMenu, nil);
178 [serviceOutline reloadData];
179}
180
181- (IBAction)hideAll:(NSButton *)sender;
182{
183 ICCF_PropagateServiceStateChange(servicesMenu, ICCF_SERVICE_HIDDEN);
184 [serviceOutline reloadData];
185}
186
187- (void)closeWithReturnCode:(int)returnCode;
188{
189 if ([[self window] isSheet]) {
190 [NSApp endSheet: [self window] returnCode: NSRunAbortedResponse];
191 }
192 [self close];
193}
194
195- (IBAction)cancel:(NSButton *)sender;
196{
197 [self closeWithReturnCode: NSRunAbortedResponse];
198}
199
200- (IBAction)saveChanges:(NSButton *)sender;
201{
202 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
203 NSMutableDictionary *icDefaults = [[defaults persistentDomainForName: (NSString *)kICBundleIdentifier] mutableCopy];
204 NSDictionary *serviceOptions = ICCF_RetainedServiceOptionsDictionary(servicesMenu);
205 if (serviceOptions != nil) {
206 [icDefaults setObject: serviceOptions forKey: (NSString *)kICServiceOptions];
207 [serviceOptions release];
208 } else {
209 [icDefaults removeObjectForKey: (NSString *)kICServiceOptions];
210 }
211 [defaults setPersistentDomain: icDefaults forName: (NSString *)kICBundleIdentifier];
212 [defaults synchronize];
213 APEMessageBroadcast(kICBundleIdentifier, kICPreferencesChanged, NULL);
214 [icDefaults release];
215 [self closeWithReturnCode: NSRunStoppedResponse];
216}
217
218@end
219
220@implementation ICeCoffEEServicePrefController (NSOutlineViewDataSource)
221
222- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item;
223{
224 if (servicesMenu == nil) {
[182]225 servicesMenu = [[NSMenu alloc] initWithTitle: @""];
226 ICCF_SetServicesMenu(servicesMenu);
227 [servicesMenu update]; // XXX necessary on 10.3? or anywhere?
[142]228 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
229 NSDictionary *icDefaults = [defaults persistentDomainForName: (NSString *)kICBundleIdentifier];
230 NSDictionary *serviceOptions = [icDefaults objectForKey: (NSString *)kICServiceOptions];
231 ICCF_RestoreServiceOptionsDictionary(servicesMenu, serviceOptions);
232 }
233 return [(item == nil ? servicesMenu : [item submenu]) numberOfItems];
234}
235
236- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item;
237{
238 return (item == nil ? YES : [item submenu] != nil);
239}
240
241- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item;
242{
243 return [(item == nil ? servicesMenu : [item submenu]) itemAtIndex: index];
244}
245
246NSAttributedString *ICCF_KeyEquivalentAttributedStringWithModifierFlags(NSString *self, unsigned int modifierFlags);
247
248- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
249{
250 if ([[tableColumn identifier] isEqualToString: @"service"]) {
251 return [item title];
252 } else if ([[tableColumn identifier] isEqualToString: @"show"]) {
253 id state = [item representedObject];
254 if ([item submenu] != nil && state == nil) {
255 return [NSNumber numberWithInt: ICCF_PropagateServiceState(item, nil)];
256 }
257 return (state == nil) ? ICCF_SERVICE_SHOWN : state;
258 } else if ([[tableColumn identifier] isEqualToString: @"key"]) {
259 NSString *equivalent = [item keyEquivalent];
260 if (equivalent == nil || [equivalent length] != 1) return nil;
261 // 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.
262 return ICCF_KeyEquivalentAttributedStringWithModifierFlags(equivalent, [item keyEquivalentModifierMask] | ([[NSCharacterSet uppercaseLetterCharacterSet] characterIsMember: [equivalent characterAtIndex: 0]] ? NSShiftKeyMask : 0));
263 }
264 return nil;
265}
266
267- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item;
268{
269 if ([[tableColumn identifier] isEqualToString: @"show"]) {
270 [item setRepresentedObject: [object boolValue] ? nil : ICCF_SERVICE_HIDDEN];
271
272 NSMenu *submenu = [item menu];
273 if (submenu == servicesMenu) {
274 ICCF_PropagateServiceState(item, item);
275 } else {
276 NSMenu *supermenu;
277 while ( (supermenu = [submenu supermenu]) != servicesMenu) {
278 submenu = supermenu;
279 }
280 ICCF_PropagateServiceState([supermenu itemAtIndex: [supermenu indexOfItemWithSubmenu: submenu]], item);
281 }
282 [outlineView reloadData];
283 }
284}
285
286@end
287
288@implementation ICeCoffEEServicePrefController (NSWindowDelegate)
289
290- (NSRect)windowWillUseStandardFrame:(NSWindow *)sender defaultFrame:(NSRect)defaultFrame;
291{
292 NSWindow *window = [serviceOutline window];
293 NSRect frame = [window frame];
294 NSScrollView *scrollView = [serviceOutline enclosingScrollView];
295 float displayedHeight = [[scrollView contentView] bounds].size.height;
296 float heightChange = [[scrollView documentView] bounds].size.height - displayedHeight;
297 float heightExcess;
298
299 if (heightChange >= 0 && heightChange <= 1) {
300 // either the window is already optimal size, or it's too big
301 float rowHeight = ICCF_TableViewCellHeight(serviceOutline);
302 heightChange = (rowHeight * [serviceOutline numberOfRows]) - displayedHeight;
303 }
304
305 frame.size.height += heightChange;
306
307 if ( (heightExcess = [window minSize].height - frame.size.height) > 1 ||
308 (heightExcess = [window maxSize].height - frame.size.height) < 1) {
309 heightChange += heightExcess;
310 frame.size.height += heightExcess;
311 }
312
313 frame.origin.y -= heightChange;
314
315 return frame;
316}
317
318@end
319
320@implementation ICeCoffEEServicePrefController (NSWindowNotifications)
321
322- (void)windowWillClose:(NSNotification *)notification;
323{
324 [self autorelease];
325}
326
327@end
Note: See TracBrowser for help on using the repository browser.