-
Notifications
You must be signed in to change notification settings - Fork 228
/
NewPreferencesController.m
269 lines (229 loc) · 8.32 KB
/
NewPreferencesController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
//
// NewPreferencesController.m
// Vienna
//
// Created by Steve on 10/15/05.
// Copyright (c) 2004-2005 Steve Palmer. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#import "NewPreferencesController.h"
#include <objc/runtime.h>
@interface NewPreferencesController (Private)
-(void)selectPane:(NSString *)identifier;
@end
@interface NSToolbar (NSToolbarPrivate)
-(NSView *)_toolbarView;
@end
@implementation NewPreferencesController
/* init
* Initialises a new instance of the new PreferencesController object.
*/
-(id)init
{
if ((self = [super initWithWindowNibName:@"NewPreferences"]) != nil)
{
prefsDict = nil;
prefPanes = nil;
prefsIdentifiers = nil;
selectedIdentifier = nil;
}
return self;
}
/* awakeFromNib
* Do the things that only make sense after the window file is loaded.
*/
-(void)awakeFromNib
{
static BOOL isPrimaryNib = YES;
// We get called for all view NIBs, so don't handle those or we'll stack overflow.
if (!isPrimaryNib)
return;
NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(handleGoogleAuthFailed:) name:@"MA_Notify_GoogleAuthFailed" object:nil];
// Load the NIBs using the plist to locate them and build the prefIdentifiersArray
// array of identifiers.
NSBundle * thisBundle = [NSBundle bundleForClass:[self class]];
NSString * pathToPList = [thisBundle pathForResource:@"Preferences.plist" ofType:@""];
NSAssert(pathToPList != nil, @"Missing Preferences.plist in build");
// Load the dictionary and sort the keys by name to create the ordered
// identifiers for each pane.
prefsDict = [[NSDictionary dictionaryWithContentsOfFile:pathToPList] retain];
prefsIdentifiers = [[[prefsDict allKeys] sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)] retain];
NSAssert([prefsIdentifiers count] > 0, @"Empty Preferences.plist file");
// Set the title
[prefWindow setTitle:NSLocalizedString(@"Preferences", nil)];
// Create the toolbar
NSToolbar * toolbar = [[NSToolbar alloc] initWithIdentifier:@"PrefsToolbar"];
[toolbar setAllowsUserCustomization:NO];
[toolbar setAutosavesConfiguration:NO];
[toolbar setDisplayMode:NSToolbarDisplayModeIconAndLabel];
[toolbar setDelegate:self];
[prefWindow setToolbar:toolbar];
[toolbar release];
// Hide the toolbar pill button
[[prefWindow standardWindowButton:NSWindowToolbarButton] setFrame:NSZeroRect];
// Create an empty view
blankView = [[NSView alloc] initWithFrame:[[prefWindow contentView] frame]];
// Array of pane objects
prefPanes = [[NSMutableDictionary alloc] init];
// Center the window
[prefWindow center];
// Primary NIB is done.
isPrimaryNib = NO;
// Select the first pane
[self selectPane:[prefsIdentifiers objectAtIndex:0]];
}
-(void)handleGoogleAuthFailed:(NSNotification *)nc
{
if ([[self window] isVisible])
{
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
[alert addButtonWithTitle:@"OK"];
[alert setMessageText:@"Google Authentication Failed"];
[alert setInformativeText:@"Please check your Google username and password in Vienna's preferences."];
[alert setAlertStyle:NSWarningAlertStyle];
[alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:nil contextInfo:nil];
}
}
/* itemForItemIdentifier
* Creates and returns an NSToolbarItem for the specified identifier.
*/
-(NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
{
NSToolbarItem * newItem = [[[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier] autorelease];
NSDictionary * prefsItem = [prefsDict objectForKey:itemIdentifier];
[newItem setLabel:NSLocalizedString([prefsItem valueForKey:@"Title"], nil)];
[newItem setTarget:self];
[newItem setAction:@selector(prefsPaneSelection:)];
NSString * prefImage = [prefsItem valueForKey:@"Image"];
if (prefImage != nil)
[newItem setImage:[NSImage imageNamed:prefImage]];
return newItem;
}
/* prefsPaneSelection
* Change the preference pane.
*/
-(IBAction)prefsPaneSelection:(id)sender
{
NSToolbar * toolbar = [prefWindow toolbar];
[self selectPane:[toolbar selectedItemIdentifier]];
}
/* selectPane
* Activate the preference pane with the given identifier. Resize the main
* window to accommodate the pane contents.
*/
-(void)selectPane:(NSString *)identifier
{
NSDictionary * prefItem = [prefsDict objectForKey:identifier];
NSAssert(prefItem != nil, @"Not a valid preference identifier");
// Skip if we're already the selected pane
if ([identifier isEqualToString:selectedIdentifier])
return;
// Make sure the associated class has been instantiated
id prefPane = [prefPanes objectForKey:identifier];
if (prefPane == nil)
{
NSString * className = [prefItem objectForKey:@"ClassName"];
if (className == nil)
{
NSLog(@"Missing ClassName attribute from preference %@", identifier);
return;
}
Class classObject = objc_getClass([className cStringUsingEncoding:NSASCIIStringEncoding]);
if (classObject == nil)
{
NSLog(@"Cannot find class '%@' in preference %@", className, identifier);
return;
}
prefPane = [[classObject alloc] init];
if (prefPane == nil)
return;
// This is the only safe time to add the pane to the array
[prefPanes setObject:prefPane forKey:identifier];
[prefPane release];
}
// If we get this far, OK to select the new item. Otherwise we're staying
// on the old one.
NSToolbar * toolbar = [prefWindow toolbar];
[toolbar setSelectedItemIdentifier:identifier];
if (selectedIdentifier != nil)
{
// Restore the pref pane to its original window
id oldPrefPane = [prefPanes objectForKey:selectedIdentifier];
NSView * oldView = [[prefWindow contentView] retain];
[prefWindow setContentView:nil];
[[oldPrefPane window] setContentView:oldView];
[oldView release];
}
// Now pull the new pane into view.
[prefWindow setContentView:blankView];
[prefWindow display];
// retain here, release after setting contentView
NSWindow * prefPaneWindow = [prefPane window];
NSView * theView = [[prefPaneWindow contentView] retain];
[prefPaneWindow setContentView:nil];
// Compute the new frame window height and width
NSRect windowFrame = [NSWindow contentRectForFrameRect:[prefWindow frame] styleMask:[prefWindow styleMask]];
float newWindowHeight = NSHeight([theView frame]) + NSHeight([[toolbar _toolbarView] frame]);
float newWindowWidth = NSWidth([theView frame]);
NSRect newFrameRect = NSMakeRect(NSMinX(windowFrame), NSMaxY(windowFrame) - newWindowHeight, newWindowWidth, newWindowHeight);
NSRect newWindowFrame = [NSWindow frameRectForContentRect:newFrameRect styleMask:[prefWindow styleMask]];
[prefWindow setFrame:newWindowFrame display:YES animate:[prefWindow isVisible]];
[prefWindow setContentView:theView];
[theView release]; // balance the retain above
// Remember this pane identifier.
[selectedIdentifier release];
selectedIdentifier = [identifier retain];
}
/* validateToolbarItem
* Every single toolbar item should be enabled.
*/
-(BOOL)validateToolbarItem:(NSToolbarItem*)toolbarItem
{
return YES;
}
/* toolbarAllowedItemIdentifiers
* The allowed toolbar items. These are all preference items.
*/
-(NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
{
return prefsIdentifiers;
}
/* toolbarSelectableItemIdentifiers
* All the selectable toolbar items. This is everything, as usual.
*/
-(NSArray *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
{
return prefsIdentifiers;
}
/* toolbarDefaultItemIdentifiers
* The default toolbar items. These are all preference items.
*/
-(NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
{
return prefsIdentifiers;
}
/* dealloc
* Clean up behind ourselves.
*/
-(void)dealloc
{
[selectedIdentifier release];
[blankView release];
[prefPanes release];
[prefsIdentifiers release];
[prefsDict release];
[super dealloc];
}
@end