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