1 | //␊ |
2 | // PreferencesControllerBase.mm␊ |
3 | // ChameleonPrefPane␊ |
4 | //␊ |
5 | // Created by Rekursor on 1/22/10.␊ |
6 | //␊ |
7 | ␊ |
8 | #import "PreferencesControllerBase.h"␊ |
9 | #import "KernOptionsParser.h"␊ |
10 | #include <string>␊ |
11 | #include <list>␊ |
12 | #include <map>␊ |
13 | #include <ctype.h>␊ |
14 | ␊ |
15 | ␊ |
16 | //--------------------------------------------------------------------------␊ |
17 | static std::list< id<GroupControllerProtocol> > groupList;␊ |
18 | ␊ |
19 | // for unix-like options types␊ |
20 | static std::map<void*, std::string> IdToUCmdList;␊ |
21 | static KernOptionsParser kernelFlags;␊ |
22 | ␊ |
23 | //--------------------------------------------------------------------------␊ |
24 | ␊ |
25 | ␊ |
26 | @implementation PreferencesControllerBase␊ |
27 | ␊ |
28 | -(ChameleonPrefPane*) chameleon { return [ChameleonPrefPane instance]; }␊ |
29 | ␊ |
30 | ␊ |
31 | //--------------------------------------------------------------------------␊ |
32 | - (id) init␊ |
33 | {␊ |
34 | ␉self = [super init];␊ |
35 | ␉␊ |
36 | ␉[PreferencesControllerBase registerPreferencesGroup: self];␊ |
37 | ␉␊ |
38 | ␉return self;␊ |
39 | }␉␊ |
40 | ␊ |
41 | //--------------------------------------------------------------------------␊ |
42 | // from the id to desc map in BootProp()., set all default values for dict␊ |
43 | + (void) loadAllValues: (NSMutableDictionary*) dict ␊ |
44 | {␊ |
45 | ␉[self doForEachGroup:LoadPreferencesOptions withOption: dict];␊ |
46 | ␉for(const BootOptionDesc* bod = BootProp::instance().firstOption();bod; bod=BootProp::instance().nextOption())␊ |
47 | ␉{␊ |
48 | ␉␉switch (bod->Type) ␊ |
49 | ␉␉{␊ |
50 | ␉␉␉case OptionYesNo:␊ |
51 | ␉␉␉␉[(NSButton*)bod->ID setIntValue: (toupper(bod->Default[0])=='Y' ? 1 : 0) ];␊ |
52 | ␉␉␉␉break;␊ |
53 | ␉␉␉case OptionKernel:␊ |
54 | ␉␉␉case OptionString:␊ |
55 | ␉␉␉␉[(NSButton*)bod->ID setIntValue: 0 ];␊ |
56 | ␉␉␉case OptionKernel1:␊ |
57 | ␉␉␉␉[(NSTextField*)bod->contentID setStringValue: ␊ |
58 | ␉␉␉␉␉[[NSString alloc] initWithUTF8String: bod->Default] ];␊ |
59 | ␉␉␉␉break;␊ |
60 | ␉␉␉case OptionUnix:␊ |
61 | ␉␉␉␉[(NSButton*)bod->ID setIntValue: 0 ];␊ |
62 | ␉␉␉␉break;␊ |
63 | ␉␉␉␉␊ |
64 | ␉␉␉default:␊ |
65 | ␉␉␉␉break;␊ |
66 | ␉␉}␊ |
67 | ␉}␊ |
68 | }␊ |
69 | ␊ |
70 | //--------------------------------------------------------------------------␊ |
71 | // get authorisation from main panel lock␊ |
72 | - (AuthorizationRef) getAuthorization␊ |
73 | {␊ |
74 | ␉AuthorizationRef auth= [[self chameleon] isUnlocked] ? ␊ |
75 | ␉[[ [self chameleon]->authView authorization] authorizationRef] : NULL;␊ |
76 | ␉return auth;␊ |
77 | }␊ |
78 | //--------------------------------------------------------------------------␊ |
79 | + (void) registerPreferencesGroup:(id) myGroup␊ |
80 | {␊ |
81 | ␉groupList.push_back(myGroup);␊ |
82 | }␊ |
83 | ␊ |
84 | //--------------------------------------------------------------------------␊ |
85 | + (void) refreshLockState: (id) item␊ |
86 | {␊ |
87 | [item setEnabled:[[ChameleonPrefPane instance] isUnlocked]];␊ |
88 | ␉␊ |
89 | }␊ |
90 | ␊ |
91 | //--------------------------------------------------------------------------␊ |
92 | + (void) refreshLockStates␊ |
93 | {␊ |
94 | ␉for (const BootOptionDesc* bod=BootProp::instance().firstOption(); ␊ |
95 | ␉␉ bod; ␊ |
96 | ␉␉ bod=BootProp::instance().nextOption())␊ |
97 | ␉{␊ |
98 | ␉␉[self refreshLockState: (id) bod->ID ];␊ |
99 | ␉␉if (bod->contentID) [self refreshLockState: (id) bod->contentID ];␊ |
100 | ␉}␊ |
101 | ␉␊ |
102 | }␊ |
103 | //--------------------------------------------------------------------------␊ |
104 | + (void) doForEachGroup: (GroupAction) action withOption:(id) option␊ |
105 | {␊ |
106 | ␉std::list<id>::iterator it;␊ |
107 | ␉for (it=groupList.begin(); it!=groupList.end(); it++)␊ |
108 | ␉{␊ |
109 | ␉␉switch (action) {␊ |
110 | ␉␉␉case SetDefaultValues:␊ |
111 | ␉␉␉␉[*it setDefaultsValues: option];␊ |
112 | ␉␉␉␉break;␊ |
113 | ␉␉␉case RefreshLockStates:␊ |
114 | ␉␉␉␉[*it refreshLockStates ];␊ |
115 | ␉␉␉␉[PreferencesControllerBase refreshLockStates];␊ |
116 | ␉␉␉␉break;␊ |
117 | ␉␉␉case LoadPreferencesOptions:␊ |
118 | ␉␉␉␉[*it loadOptionsFromPreferencesFile: option];␊ |
119 | ␉␉␉␉break;␊ |
120 | ␉␉␉case LoadBootConfigOptions:␊ |
121 | ␉␉␉␉[*it loadOptionsFromBootFile];␊ |
122 | ␉␉␉␉break;␊ |
123 | ␉␉␉case AddOptionsDesc:␊ |
124 | ␉␉␉␉[*it addOptionsDesc];␊ |
125 | ␉␉␉␉break;␊ |
126 | ␉␉␉case SaveBootConfigOptions:␊ |
127 | ␉␉␉␉break;␊ |
128 | ␉␉␉default:␊ |
129 | ␉␉␉␉break;␊ |
130 | ␉␉}␊ |
131 | ␉}␊ |
132 | }␊ |
133 | ␉␉ ␊ |
134 | //--------------------------------------------------------------------------␊ |
135 | + (void) loadOptionsFromBootFile␊ |
136 | {␊ |
137 | ␉// parse unix like command string:␊ |
138 | ␉kernelFlags.parseOptions(BootProp::instance().getStringForKey(kKernelFlags));␊ |
139 | ␉␊ |
140 | ␉for (const BootOptionDesc* bod=BootProp::instance().firstOption(); ␊ |
141 | ␉␉ bod; ␊ |
142 | ␉␉ bod=BootProp::instance().nextOption())␊ |
143 | ␉{␊ |
144 | ␉␉[PreferencesControllerBase loadOptionFromBootFile:(id)bod->ID ];␊ |
145 | ␉}␊ |
146 | }␊ |
147 | ␊ |
148 | //--------------------------------------------------------------------------␊ |
149 | ␊ |
150 | + (void) loadOptionFromBootFile:(id) optionID␊ |
151 | {␊ |
152 | ␉const BootOptionDesc* bod = BootProp::instance().findOption(optionID);␊ |
153 | ␉if (!bod) ␊ |
154 | ␉{␊ |
155 | ␉␉NSRunAlertPanel(@"Error Parsing Option",@"loadOptionFromBootFile failed",@"OK", nil, nil);␊ |
156 | ␉␉return;␊ |
157 | ␉} ␊ |
158 | ␉␊ |
159 | ␉const char * stringForKey = BootProp::instance().getStringForKey(bod->Name);␊ |
160 | ␉std::string s = stringForKey ? trim(stringForKey) : "";␊ |
161 | ␉std::string def = trim(bod->Default ? bod->Default : "");␊ |
162 | ␉␊ |
163 | ␉switch (bod->Type) ␊ |
164 | ␉{␊ |
165 | ␉␉case OptionYesNo:␊ |
166 | ␉␉␉if (s.length()>0) ␊ |
167 | ␉␉␉␉[(NSButton*)optionID setIntValue: (toupper(s[0])=='Y' ? 1 : 0 ) ];␊ |
168 | ␉␉␉else␊ |
169 | ␉␉␉␉[(NSButton*)optionID setIntValue: (toupper(def[0])=='Y' ? 1 : 0 ) ];␊ |
170 | ␉␉␉break;␊ |
171 | ␉␉␉␊ |
172 | ␉␉case OptionKernel1:␊ |
173 | ␉␉{␊ |
174 | ␉␉␉int val = (s.length()>0 ? 1 : 0 );␊ |
175 | ␉␉␉[(NSButton*)optionID setIntValue: val ];␊ |
176 | ␉␉␉[(NSTextField*) bod->contentID setStringValue: ␊ |
177 | ␉␉␉ [[NSString alloc] initWithUTF8String: s.c_str()] ];␊ |
178 | ␉␉␉[(NSTextField*) bod->contentID setEnabled: val ? true : false]; ␊ |
179 | ␉␉␉[(NSTextField*) bod->contentID setEditable: val ? true : false]; ␊ |
180 | ␉␉}␊ |
181 | ␉␉␉break;␊ |
182 | ␉␉case OptionString:␊ |
183 | ␉␉{␊ |
184 | ␉␉␉int val = (s.length()>0 ? 1 : 0 );␊ |
185 | ␉␉␉[(NSButton*)optionID setIntValue: val ];␊ |
186 | ␉␉␉[(NSTextField*) bod->contentID setStringValue: ␊ |
187 | ␉␉␉␉[[NSString alloc] initWithUTF8String: s.c_str()] ];␊ |
188 | ␉␉␉[(NSTextField*) bod->contentID setEnabled: val ? true: false]; ␊ |
189 | ␉␉␉[(NSTextField*) bod->contentID setEditable: val ? true : false]; ␊ |
190 | ␉␉}␊ |
191 | ␉␉␉break;␊ |
192 | ␉␉␉␊ |
193 | ␉␉case OptionUnix:␊ |
194 | ␉␉case OptionKernel:␊ |
195 | ␉␉{␊ |
196 | ␉␉␉std::string s = kernelFlags.stringFromKey(bod->Name);␊ |
197 | ␉␉␉if (s.length()>0)␊ |
198 | ␉␉␉{␊ |
199 | ␉␉␉␉[(NSButton*)optionID setIntValue: 1 ];␊ |
200 | ␉␉␉␉if(bod->Type==OptionKernel)␊ |
201 | ␉␉␉␉{␊ |
202 | ␉␉␉␉␉[(NSTextField*) bod->contentID setStringValue: ␊ |
203 | ␉␉␉␉␉ [[NSString alloc] initWithUTF8String: ␊ |
204 | ␉␉␉␉␉␉kernelFlags.rightMember(s).c_str()] ];␊ |
205 | ␉␉␉␉␉[(NSTextField*) bod->contentID setEnabled: true]; ␊ |
206 | ␉␉␉␉␉[(NSTextField*) bod->contentID setEditable: true]; ␊ |
207 | ␉␉␉␉}␊ |
208 | ␊ |
209 | ␉␉␉}␊ |
210 | ␉␉␉else␊ |
211 | ␉␉␉{ // set the default for thiso option ␊ |
212 | ␉␉␉␉[(NSButton*)optionID setIntValue: (bod->Default[0] ? 1 :0) ];␊ |
213 | ␉␉␉␉if(bod->Type==OptionKernel)␊ |
214 | ␉␉␉␉{␊ |
215 | ␉␉␉␉␉[(NSTextField*) bod->contentID setEnabled: false]; ␊ |
216 | ␉␉␉␉␉[(NSTextField*) bod->contentID setEditable: false]; ␊ |
217 | ␉␉␉␉}␊ |
218 | ␊ |
219 | ␉␉␉}␊ |
220 | ␉␉}␊ |
221 | ␉␉␉break;␊ |
222 | ␉␉default:␊ |
223 | ␉␉␉break;␊ |
224 | ␉}␊ |
225 | ␉␊ |
226 | }␊ |
227 | ␊ |
228 | //--------------------------------------------------------------------------␊ |
229 | - (void) loadPreferences␊ |
230 | {␊ |
231 | ␉[ [ChameleonPrefPane instance] loadPreferences];␊ |
232 | }␊ |
233 | ␊ |
234 | //--------------------------------------------------------------------------␊ |
235 | - (bool) savePreferences␊ |
236 | {␊ |
237 | ␉return [ [ChameleonPrefPane instance] savePreferences: [self preferencesFile] ];␊ |
238 | ␉␊ |
239 | }␊ |
240 | //--------------------------------------------------------------------------␊ |
241 | // update the boot Config with one option change and its associated desc ␊ |
242 | - (bool) saveBootConfig: (id) sender withBootOptionDesc: (BootOptionDesc*) bod␊ |
243 | {␊ |
244 | ␉if(!bod) ␊ |
245 | ␉{␊ |
246 | ␉␉return false;␊ |
247 | ␉}␊ |
248 | ␉// load boot config file so that we don't risk to loose␊ |
249 | ␉// externally modified parameters␊ |
250 | ␉␊ |
251 | ␉int val = [(NSButton*) sender intValue ];␊ |
252 | ␉std::string sDefaultValue = trim(bod->Default ? bod->Default : "");␊ |
253 | ␉bool status = false;␊ |
254 | ␉std::string name = trim(bod->Name);␊ |
255 | ␉␊ |
256 | ␉switch (bod->Type) {␊ |
257 | ␉␉case OptionYesNo:␊ |
258 | ␉␉{␊ |
259 | ␉␉␉std::string sVal = val ? "Yes" : "No"; ␊ |
260 | ␉␉␉if (sDefaultValue.length()==0) sDefaultValue␉= "No";␊ |
261 | ␉␉␉// Avoid populating bootConfig with unnecessary options:␊ |
262 | ␉␉␉if (sVal == sDefaultValue) ␊ |
263 | ␉␉␉␉status = BootProp::instance().removeKeyAndValue(name.c_str());␊ |
264 | ␉␉␉else␊ |
265 | ␉␉␉␉status = BootProp::instance().setStringForKey(name, sVal.c_str());␊ |
266 | ␉␉}␊ |
267 | ␉␉␉break;␊ |
268 | ␉␉case OptionUnix:␊ |
269 | ␉␉␉if (!val)␉kernelFlags.removeFlag(name);␊ |
270 | ␉␉␉else␉␉kernelFlags.addFlag(name);␊ |
271 | ␉␉␉BootProp::instance().setStringForKey(kKernelFlags,kernelFlags.options());␊ |
272 | ␉␉␉status = true;␊ |
273 | ␉␉␉break;␊ |
274 | ␉␉case OptionKernel:␊ |
275 | ␉␉{␊ |
276 | ␉␉␉std::string contentValue = trim(␊ |
277 | ␉␉␉[ [(NSTextField*) bod->contentID stringValue] UTF8String ]);␊ |
278 | ␉␉␉kernelFlags.removeFlag(kernelFlags.stringFromKey(bod->Name));␊ |
279 | ␉␉␉if(val && contentValue.length()>0)␊ |
280 | ␉␉␉{␊ |
281 | ␉␉␉␉std::string concat = trim(name);␊ |
282 | ␉␉␉␉concat+= "=";␊ |
283 | ␉␉␉␉concat+= trim(contentValue);␊ |
284 | ␉␉␉␉␊ |
285 | ␉␉␉␉kernelFlags.addFlag(concat);␊ |
286 | ␉␉␉}␊ |
287 | ␉␉␉BootProp::instance().setStringForKey(kKernelFlags,kernelFlags.options());␊ |
288 | ␉␉␉status = true;␊ |
289 | ␉␉}␊ |
290 | ␉␉␉break;␊ |
291 | ␉␉case OptionKernel1:␊ |
292 | ␉␉case OptionString:␊ |
293 | ␉␉␉// Avoid populating bootConfig with unnecessary options:␊ |
294 | ␉␉␉if (val == 0 && bod->Type!=OptionKernel1) ␊ |
295 | ␉␉␉␉status = BootProp::instance().removeKeyAndValue(bod->Name);␊ |
296 | ␉␉␉else␊ |
297 | ␉␉␉{␊ |
298 | ␉␉␉␉std::string contentValue =␊ |
299 | ␉␉␉␉␉[ [(NSTextField*) bod->contentID stringValue] UTF8String ];␊ |
300 | ␉␉␉␉if (contentValue.length()>0)␊ |
301 | ␉␉␉␉␉status = BootProp::instance().setStringForKey(bod->Name, contentValue.c_str());␊ |
302 | ␉␉␉␉else {␊ |
303 | ␉␉␉␉␉return false; // no content to save so don't save it␊ |
304 | ␉␉␉␉}␊ |
305 | ␊ |
306 | ␉␉␉}␊ |
307 | ␉␉␉break;␊ |
308 | ␉␉default:␊ |
309 | ␉␉␉break;␊ |
310 | ␉}␊ |
311 | ␉␊ |
312 | ␉// Now save the bootConfig␊ |
313 | ␉AuthorizationRef auth = [self getAuthorization ];␊ |
314 | ␉if (status)␉status = BootProp::instance().save(auth);␊ |
315 | ␊ |
316 | ␉return status;␊ |
317 | }␊ |
318 | //--------------------------------------------------------------------------␊ |
319 | -(NSMutableDictionary*) preferencesFile␊ |
320 | {␉␊ |
321 | ␉return [[ChameleonPrefPane instance] preferencesFile];␊ |
322 | }␊ |
323 | ␊ |
324 | //--------------------------------------------------------------------------␊ |
325 | -(NSMutableDictionary*) preferencesParts ␊ |
326 | { ␊ |
327 | ␉return [[ChameleonPrefPane instance] preferencesParts];␊ |
328 | }␊ |
329 | ␊ |
330 | //--------------------------------------------------------------------------␊ |
331 | - (bool) handleSender: (id) sender␊ |
332 | {␊ |
333 | ␊ |
334 | ␉const BootOptionDesc * bod = BootProp::instance().findOption(sender);␊ |
335 | ␉␊ |
336 | ␉if (!bod) {␊ |
337 | ␉␉bod = BootProp::instance().findOptionContent(sender);␊ |
338 | ␉␉NSTextField* textField = (NSTextField*) sender;␊ |
339 | ␉␉std::string content = [[textField stringValue] UTF8String ];␊ |
340 | ␉␉if(bod->ID!=nil) sender = (id) bod->ID;␊ |
341 | ␉}␊ |
342 | ␉else␊ |
343 | ␉{␊ |
344 | ␉␉␊ |
345 | ␉␉int state = [sender intValue];␊ |
346 | ␉␊ |
347 | ␉␉switch (bod->Type) {␊ |
348 | ␉␉␉case OptionKernel:␊ |
349 | ␉␉␉case OptionKernel1:␊ |
350 | ␉␉␉case OptionString:␊ |
351 | ␉␉␉[(NSTextField*) bod->contentID setEnabled: state ? true : false];␊ |
352 | ␉␉␉[(NSTextField*) bod->contentID setEditable: state ? true : false];␊ |
353 | ␉␉␉␉break;␊ |
354 | ␉␉␉default:␊ |
355 | ␉␉␉␉break;␊ |
356 | ␉␉}␊ |
357 | ␉}␉␊ |
358 | ␉if(![self saveBootConfig: sender withBootOptionDesc: (BootOptionDesc*) bod] && !bod->contentID )␊ |
359 | ␉{ // Couldn't save, so warn user ...␊ |
360 | ␉␉NSRunAlertPanel(@"Error saving bootConfig", @"Could not save com.apple.Boot.plist",␊ |
361 | ␉␉␉␉␉␉␉@"OK", nil, nil);␊ |
362 | ␉}␊ |
363 | ␉return true;␊ |
364 | }␊ |
365 | ␊ |
366 | @end␊ |
367 | |