The R Project SVN R-packages

Rev

Rev 814 | Rev 4330 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
648 iacus 1
//
2
//  AMPreferenceWindowController.m
3
//  PrefPane
4
//
5
//  Created by Andreas on Sat May 31 2003.
6
//  Copyright (c) 2003 Andreas Mayer. All rights reserved.
7
//
8
 
1048 urbaneks 9
#import "../RGUI.h" /* for NLS nacro */
648 iacus 10
#import "AMPreferenceWindowController.h"
11
#import "AMPrefPaneProtocol.h"
12
#import "AMPrefPaneIcon.h"
13
#import "AMPrefPaneIconView.h"
14
 
15
 
16
@interface NSToolbar (AMPrivate)
17
- (void)_setCustomizesAlwaysOnClickAndDrag:(BOOL)flag;
18
- (void)_setFirstMoveableItemIndex:(int)index;
19
- (void)setCustomizationSheetWidth:(int)width;
20
@end
21
 
22
 
23
// ============================================================
24
#pragma mark -
25
#pragma mark ━ private interface ━
26
// ============================================================
27
 
28
@interface AMPreferenceWindowController (Private)
29
- (void)setPrefPanes:(NSDictionary *)newPrefPanes;
30
- (AMPreferencePane *)activePane;
31
- (void)setActivePane:(AMPreferencePane *)newActivePane;
32
- (void)removeAllPanes;
33
- (NSString *)autosaveName;
34
- (void)setAutosaveName:(NSString *)newAutosaveName;
814 urbaneks 35
- (AMPrefPaneIcon *)iconForPrefPane:(id<AMPrefPaneProtocol>)prefPane;
648 iacus 36
- (void)changeContentView:(NSView *)contentView;
37
- (void)createIconViewPane;
38
- (void)toolbarShowAll;
39
- (NSArray *)validPrefPaneIdentifiers;
40
@end
41
 
42
// ============================================================
43
#pragma mark -
44
#pragma mark ━ implementation ━
45
// ============================================================
46
 
47
@implementation AMPreferenceWindowController
48
 
49
// ============================================================
50
#pragma mark -
51
#pragma mark ━ initialisation ━
52
// ============================================================
53
 
54
- (id)initWithAutosaveName:(NSString *)name
55
{
56
	NSWindow *panel = [[[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 200, 100) styleMask:(NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask) backing:NSBackingStoreBuffered defer:YES] autorelease];
57
		// create a new window
58
	[panel setDelegate:self];
59
	[panel setOpaque:YES];
60
	[panel setContentView:[[[NSView alloc] initWithFrame:NSMakeRect(0, 0, 200, 100)] autorelease]];
61
	[self setPrefPanes:[NSMutableDictionary dictionary]];
62
	[self setAutosaveName:name];
63
	[self setTitle:@"Preferences"];
64
	[self createIconViewPane];
65
	[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:) name:NSApplicationWillTerminateNotification object:NSApp];
66
	_am_oldContentViewFrame = [[panel contentView] frame];
67
	return [super initWithWindow:panel];
68
}
69
 
70
- (void)dealloc
71
{
72
	[iconView release];
73
	[prefPanes release];
74
	[activePane release];
75
	[super dealloc];
76
}
77
 
78
// ============================================================
79
#pragma mark -
80
#pragma mark ━ setters / getters ━
81
// ============================================================
82
 
83
- (NSWindow *)window
84
{
85
	NSWindow *result = [super window];
86
	if (![result toolbar]) {
87
		NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:AMPPToolbarIdentifier];
88
		[toolbar setDelegate:self];
89
		[toolbar setVisible:YES];
90
		[toolbar setAllowsUserCustomization:usesConfigurationPane];
91
		[toolbar setAutosavesConfiguration:YES];
92
		if (usesConfigurationPane) {
93
			[toolbar _setCustomizesAlwaysOnClickAndDrag:YES];
94
			[toolbar _setFirstMoveableItemIndex:2];
95
		}
96
		[result setToolbar:toolbar];
97
		// select first panel
98
		NSString *selectedItemIdentifier = [[[toolbar items] objectAtIndex:0] itemIdentifier];
99
		[toolbar setSelectedItemIdentifier:selectedItemIdentifier];
100
		[self selectPaneWithIdentifier:selectedItemIdentifier];
101
		// set frame size
102
		// gnnn... we need to extract the saved frame ourselfes, since we want to set the origin only
103
		NSString *frameString = [[NSUserDefaults standardUserDefaults] stringForKey:[NSString stringWithFormat:@"NSWindow Frame %@", autosaveName]];
104
		NSRect frame;
105
		if (frameString) {
106
			NSArray *frameArray = [frameString componentsSeparatedByString:@" "];
107
			frame = NSMakeRect([[frameArray objectAtIndex:0] floatValue], [[frameArray objectAtIndex:1] floatValue], [[frameArray objectAtIndex:2] floatValue], [[frameArray objectAtIndex:3] floatValue]);
108
			NSRect oldFrame = [result frame];
109
			oldFrame.origin.x = frame.origin.x;
110
			oldFrame.origin.y = frame.origin.y+(frame.size.height-oldFrame.size.height);
111
			[result setFrame:oldFrame display:NO];
112
		} else {
113
			[result center];
114
		}
115
	}
116
	return result;
117
}
118
 
119
- (NSDictionary *)prefPanes
120
{
121
    return prefPanes;
122
}
123
 
124
- (id)delegate
125
{
126
    return delegate;
127
}
128
 
129
- (void)setDelegate:(id)newDelegate
130
{
131
	// do not retain delegate
132
	delegate = newDelegate;
133
	_am_delegateRespondsToCategoryForPreferencePane = [delegate respondsToSelector:@selector(categoryForPreferencePane:defaultCategory:)];
134
	_am_delegateRespondsToDisplayNameForCategory = [delegate respondsToSelector:@selector(displayNameForCategory:)];
135
}
136
 
137
- (BOOL)usesConfigurationPane
138
{
139
	return usesConfigurationPane;
140
}
141
 
142
- (void)setUsesConfigurationPane:(BOOL)newUsesConfigurationPane
143
{
144
	usesConfigurationPane = newUsesConfigurationPane;
145
}
146
 
147
- (BOOL)sortByCategory
148
{
149
	return [(AMPrefPaneIconView *)iconView sortByCategory];
150
}
151
 
152
- (void)setSortByCategory:(BOOL)newSortByCategory
153
{
154
	BOOL changed = ([(AMPrefPaneIconView *)iconView sortByCategory] != newSortByCategory);
155
	if (changed) {
156
		[(AMPrefPaneIconView *)iconView setSortByCategory:newSortByCategory];
157
		if (activePane == nil) {
158
			[self toolbarShowAll];
159
		}
160
	}
161
}
162
 
163
- (NSArray *)categorySortOrder
164
{
165
	return [(AMPrefPaneIconView *)iconView categorySortOrder];
166
}
167
 
168
- (void)setCategorySortOrder:(NSArray *)newCategorySortOrder
169
{
170
	[(AMPrefPaneIconView *)iconView setCategorySortOrder:newCategorySortOrder];
171
}
172
 
173
- (NSString *)title
174
{
175
	return title;
176
}
177
 
178
- (void)setTitle:(NSString *)newTitle
179
{
180
	id old = nil;
181
 
182
	if (newTitle != title) {
183
		old = title;
184
		title = [newTitle copy];
185
		[old release];
186
	}
187
}
188
 
189
 
190
// ============================================================
191
#pragma mark -
192
#pragma mark ━ public methods ━
193
// ============================================================
194
 
195
- (void)addPluginsOfType:(NSString *)extension fromPath:(NSString *)path
196
{
197
	NSEnumerator* enumerator = [[NSBundle pathsForResourcesOfType:extension inDirectory:path] objectEnumerator];
198
	NSString* pluginPath;
199
	while ((pluginPath = [enumerator nextObject])) {
200
		[self addPluginFromPath:pluginPath];
201
	}
202
}
203
 
814 urbaneks 204
- (BOOL)addPane:(id<AMPrefPaneProtocol>)newPane withIdentifier:(NSString *)identifier
648 iacus 205
{
206
	BOOL result;
207
	if (result = ([prefPanes objectForKey:identifier] == nil)) {
208
		if ([delegate respondsToSelector:@selector(shouldLoadPreferencePane:)]) {
209
			result = [delegate shouldLoadPreferencePane:identifier];
210
		}
211
		if (result) {
212
			[prefPanes setObject:newPane forKey:identifier];
814 urbaneks 213
			if ([(NSObject*)newPane respondsToSelector:@selector(mainView)] && [newPane mainView]) {
648 iacus 214
				[(AMPrefPaneIconView *)iconView addIcon:[self iconForPrefPane:newPane]];
215
			}
216
		}
217
	}
218
	return result;
219
}
220
 
221
- (void)addPluginFromPath:(NSString *)path
222
{
223
	NSBundle* pluginBundle = [NSBundle bundleWithPath:path];
224
	if (!pluginBundle) {
225
		NSLog(@"error loading bundle: %@", path);
226
	} else { // loaded successfully
227
		NSLog(@"loaded: %@", [pluginBundle bundlePath]);
228
		NSString* prefPaneIdentifier;
229
		if (prefPaneIdentifier = [pluginBundle objectForInfoDictionaryKey:CFBundleIdentifierKey]) {
230
			if ([prefPanes objectForKey:prefPaneIdentifier]) {
231
				// pane with same identifier exists
232
				NSLog(@"pref pane already loaded %@", prefPaneIdentifier);
233
			} else {
234
				BOOL load = YES;
235
				if ([delegate respondsToSelector:@selector(shouldLoadPreferencePane:)]) {
236
					load = [delegate shouldLoadPreferencePane:prefPaneIdentifier];
237
				}
238
				if (load) {
239
					AMPreferencePane *newPane;
240
					if (newPane = [[AMPreferencePane alloc] initWithBundle:pluginBundle]) {
241
						if (newPane)
242
							[self addPane:newPane withIdentifier:prefPaneIdentifier];
243
					}
244
				} else {
245
					NSLog(@"delegate did not approve plugin %@", prefPaneIdentifier);
246
				}
247
			}
248
		} else {
249
			// no identifier
250
		}
251
	}
252
}
253
 
254
- (BOOL)deselectActivePane
255
{
256
	BOOL result = YES;
257
	if (activePane) {
258
		if ([activePane respondsToSelector:@selector(willUnselect)]) {
259
			[(id)activePane willUnselect];
260
		}
261
		if ([delegate respondsToSelector:@selector(didUnselectPreferencePane:)]) {
262
			[delegate didUnselectPreferencePane:[activePane identifier]];
263
		}
264
		if ([activePane respondsToSelector:@selector(didUnselect)]) {
265
			[(id)activePane didUnselect];
266
		}
267
		[self setActivePane:nil];
268
	}
269
	return result;
270
}
271
 
272
- (BOOL)selectPaneWithIdentifier:(NSString *)identifier
273
{
274
	BOOL result = NO;
275
	AMPreferencePane *pane = [prefPanes objectForKey:identifier];
276
	if (pane) {
277
		if (pane == activePane) {
278
			// already active
279
			/*
280
			if ([delegate respondsToSelector:@selector(willSelectPreferencePane:)]) {
281
				[delegate willSelectPreferencePane:identifier];
282
			}
283
			 */
284
			result = YES;
285
		} else {
286
			NSView *paneView = [pane mainView];
287
			if (paneView) {
288
				if ([activePane respondsToSelector:@selector(willUnselect)])
289
					[(id)activePane willUnselect];
290
				if ([delegate respondsToSelector:@selector(willSelectPreferencePane:)]) {
291
					[delegate willSelectPreferencePane:identifier];
292
				}
293
				if ([pane respondsToSelector:@selector(willSelect)])
294
					[(id)pane willSelect];
295
				if ([pane respondsToSelector:@selector(loadMainView)])
296
					[(id)pane loadMainView];
297
 
298
				[[self window] setTitle:[[prefPanes objectForKey:identifier] label]];
299
				[self changeContentView:paneView];
300
 
301
				if (activePane) {
302
					if ([delegate respondsToSelector:@selector(didUnselectPreferencePane:)]) {
303
						[delegate didUnselectPreferencePane:[activePane identifier]];
304
					}
305
					if ([activePane respondsToSelector:@selector(didUnselect)])
306
						[(id)activePane didUnselect];
307
				}
308
				if ([pane respondsToSelector:@selector(didSelect)])
309
					[(id)pane didSelect];
310
				[self setActivePane:pane];
311
			} else { // no view?!
312
				NSLog(@"Preference Pane \"%@\" has no view", [pane identifier]);
313
			}
314
		}
315
	}
316
	return result;
317
}
318
 
319
- (BOOL)selectIconViewPane
320
{
321
	BOOL result = [self deselectActivePane];
322
	if (result)
323
		[self toolbarShowAll];
324
	return result;
325
}
326
 
327
- (void)replyToShouldUnselect:(BOOL)shouldUnselect;
328
{}
329
 
330
- (NSString *)categoryForIdentifier:(NSString *)identifier
331
{
332
	NSString *result;
333
	AMPreferencePane *prefPane = [prefPanes objectForKey:identifier];
334
	result = [prefPane category];
335
	if (_am_delegateRespondsToCategoryForPreferencePane) {
336
		result = [delegate performSelector:@selector(categoryForPreferencePane:defaultCategory:) withObject:identifier withObject:result];
337
	}
338
	return result;
339
}
340
 
341
- (NSArray *)categories
342
{
343
	NSArray *result = nil;
344
	NSMutableDictionary *categories = [NSMutableDictionary dictionary];
345
	NSEnumerator *enumerator = [[prefPanes allValues] objectEnumerator];
346
	AMPreferencePane *prefPane;
347
	while (prefPane = [enumerator nextObject]) {
348
		NSString *category = [prefPane category];
349
		if (_am_delegateRespondsToCategoryForPreferencePane) {
350
			category = [delegate performSelector:@selector(categoryForPreferencePane:defaultCategory:) withObject:[prefPane identifier] withObject:category];
351
		}
352
		[categories setObject:category forKey:category];
353
	}
354
	result = [categories allKeys];
355
	return result;
356
}
357
 
358
- (NSString *)categoryDisplayNameForIdentifier:(NSString *)identifier
359
{
360
	NSString *result = nil;
361
	NSString *category = [self categoryForIdentifier:identifier];
362
	if (_am_delegateRespondsToDisplayNameForCategory) {
363
		result = [delegate displayNameForCategory:category];
364
	}
365
	if (result == nil) {
366
		AMPreferencePane *prefPane = [prefPanes objectForKey:identifier];
367
		if ([prefPane respondsToSelector:@selector(categoryDisplayName)]) {
368
			result = [(id)prefPane categoryDisplayName];
369
		}
370
	}
371
	if (result == nil) {
372
		result = category;
373
	}
374
	return result;
375
}
376
 
377
 
378
// ============================================================
379
#pragma mark -
380
#pragma mark ━ private methods ━
381
// ============================================================
382
 
383
- (void)setPrefPanes:(NSDictionary *)newPrefPanes
384
{
385
	id old = nil;
386
 
387
	if (newPrefPanes != prefPanes) {
388
		old = prefPanes;
389
		prefPanes = [newPrefPanes mutableCopy];
390
		[old release];
391
	}
392
}
393
 
394
- (AMPreferencePane *)activePane
395
{
396
	return activePane;
397
}
398
 
399
- (void)setActivePane:(AMPreferencePane *)newActivePane
400
{
401
	id old = nil;
402
 
403
	if (newActivePane != activePane) {
404
		old = activePane;
405
		activePane = [newActivePane retain];
406
		[old release];
407
	}
408
}
409
 
410
- (void)removeAllPanes
411
{
412
	NSLog(@"at this time (10.2.6) there's no way to unload bundles, sorry");
413
}
414
 
415
- (NSString *)autosaveName
416
{
417
	return autosaveName;
418
}
419
 
420
- (void)setAutosaveName:(NSString *)newAutosaveName
421
{
422
	id old = nil;
423
 
424
	if (newAutosaveName != autosaveName) {
425
		old = autosaveName;
426
		autosaveName = [newAutosaveName copy];
427
		[old release];
428
	}
429
}
430
 
814 urbaneks 431
- (AMPrefPaneIcon *)iconForPrefPane:(id<AMPrefPaneProtocol>)prefPane
648 iacus 432
{
433
	AMPrefPaneIcon *result = [[[AMPrefPaneIcon alloc] initWithIdentifier:[prefPane identifier] image:[prefPane icon] andTitle:[prefPane label]] autorelease];
434
	[result setCategory:[prefPane category]];
435
	[result setTarget:self];
436
	[result setSelector:@selector(toolbarShowPane:)];
437
	return result;
438
}
439
 
440
- (void)createIconViewPane
441
{
442
	if (!iconView) {
443
		NSMutableArray *icons = [NSMutableArray array];
444
		NSEnumerator *enumerator = [prefPanes objectEnumerator];
445
		AMPreferencePane *prefPane;
446
		while (prefPane = [enumerator nextObject]) {
447
			if ([prefPane respondsToSelector:@selector(mainView)] && [prefPane mainView]) {
448
				[icons addObject:[self iconForPrefPane:prefPane]];
449
			}
450
		}
451
		iconView = [[AMPrefPaneIconView alloc] initWithController:self icons:icons columns:7];
452
	}
453
}
454
 
455
- (void)changeContentView:(NSView *)contentView
456
{
457
	NSRect windowFrame = [[self window] frame];
458
	NSRect newViewFrame = [contentView frame];
459
	float deltaX = (newViewFrame.size.width-_am_oldContentViewFrame.size.width);
460
	float deltaY = (newViewFrame.size.height-_am_oldContentViewFrame.size.height);
461
	windowFrame.size.width += deltaX;
462
	windowFrame.size.height += deltaY;
463
	windowFrame.origin.y -= deltaY;
464
	[[self window] setContentView:contentView];
465
	[[self window] setFrame:windowFrame display:YES animate:YES];
466
	_am_oldContentViewFrame = newViewFrame;
467
}
468
 
469
- (NSArray *)validPrefPaneIdentifiers
470
{
471
	NSMutableArray *result = [NSMutableArray array];
472
	NSEnumerator *enumerator = [prefPanes objectEnumerator];
473
	AMPreferencePane *pane;
474
	while (pane = [enumerator nextObject]) {
475
		if ([pane respondsToSelector:@selector(mainView)] && [pane mainView]) {
476
			[result addObject:[pane identifier]];
477
		}
478
	}
479
	return result;
480
}
481
 
482
 
483
// ============================================================
484
#pragma mark -
485
#pragma mark ━ toolbar action methods ━
486
// ============================================================
487
 
488
- (void)toolbarShowAll
489
{
490
	[self deselectActivePane];
491
	[[self window] setTitle:[self title]];
492
	[self changeContentView:iconView];
493
}
494
 
495
- (void)toolbarShowPane:(id)sender
496
{
497
	NSString *identifier = [(NSToolbarItem *)sender itemIdentifier];
498
	[[[self window] toolbar] setSelectedItemIdentifier:[(NSToolbarItem *)sender itemIdentifier]];
499
	[self selectPaneWithIdentifier:identifier];
500
}
501
 
502
// ============================================================
503
#pragma mark -
504
#pragma mark ━ toolbar delegate methods ━
505
// ============================================================
506
 
507
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
508
{
509
	NSToolbarItem *result = nil;
510
	AMPreferencePane *pane = nil;
511
	if ([itemIdentifier isEqualToString:AMPPToolbarShowAllItemIdentifier]) {
512
		if (result = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier]) {
513
			[result setTarget:self];
514
			[result setAction:@selector(toolbarShowAll)];
515
			[result setEnabled:YES];
516
			[result setImage:[NSImage imageNamed:@"Prefs"]];
1048 urbaneks 517
			[result setLabel:NLS(@"Show All")];
648 iacus 518
		}
519
	} else if (pane = [prefPanes objectForKey:itemIdentifier]) {
520
		if (result = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier]) {
521
			[result setTarget:self];
522
			[result setAction:@selector(toolbarShowPane:)];
523
			[result setEnabled:YES];
524
			[result setImage:[pane icon]];
525
			[result setLabel:[pane label]];
526
		}
527
	}
528
	return result;
529
}
530
 
531
- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
532
{
533
	NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
534
	if (usesConfigurationPane) {
535
		[result addObject:AMPPToolbarShowAllItemIdentifier];
536
		[result addObject:NSToolbarSeparatorItemIdentifier];
537
	}
538
	NSMutableArray *prefPaneIdentifiers = [NSMutableArray arrayWithArray:[self validPrefPaneIdentifiers]];
539
	[prefPaneIdentifiers sortUsingSelector:@selector(caseInsensitiveCompare:)];
540
	[result addObjectsFromArray:prefPaneIdentifiers];
541
	return result;
542
}
543
 
544
- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
545
{
546
	NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
547
	if (usesConfigurationPane) {
548
		[result addObject:AMPPToolbarShowAllItemIdentifier];
549
		[result addObject:NSToolbarSeparatorItemIdentifier];
550
	}
551
	[result addObjectsFromArray:[self validPrefPaneIdentifiers]];
552
	return result;
553
}
554
 
555
- (NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
556
{
557
	NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease];
558
	if (usesConfigurationPane) {
559
		[result addObject:AMPPToolbarShowAllItemIdentifier];
560
	}
561
	[result addObjectsFromArray:[self validPrefPaneIdentifiers]];
562
	return result;
563
}
564
 
565
- (void)toolbarDidRemoveItem:(NSNotification *)notification
566
{}
567
 
568
- (void)toolbarWillAddItem:(NSNotification *)notification
569
{}
570
 
571
// ============================================================
572
#pragma mark -
573
#pragma mark ━ window delegate methods ━
574
// ============================================================
575
 
576
- (void)windowWillClose:(NSNotification *)aNotification
577
{
578
	if ([activePane respondsToSelector:@selector(willUnselect)])
579
		[(id)activePane willUnselect];
580
}
581
 
582
- (void)windowDidClose:(NSNotification *)aNotification
583
{
584
	if ([activePane respondsToSelector:@selector(willUnselect)])
585
		[(id)activePane willUnselect];
586
	if ([activePane respondsToSelector:@selector(didUnselect)])
587
		[(id)activePane didUnselect];
588
}
589
 
590
- (void)windowDidMove:(NSNotification *)aNotification
591
{
592
	[[self window] saveFrameUsingName:autosaveName];
593
}
594
 
595
 
596
// ============================================================
597
#pragma mark -
598
#pragma mark ━ notification methods ━
599
// ============================================================
600
 
601
- (void)applicationWillTerminate:(NSNotification *)aNotification
602
{
603
	if ([activePane respondsToSelector:@selector(willUnselect)])
604
		[(id)activePane willUnselect];
605
	if ([activePane respondsToSelector:@selector(didUnselect)])
606
		[(id)activePane didUnselect];
607
}
608
 
609
 
610
@end