Chameleon Applications

Chameleon Applications Svn Source Tree

Root/trunk/ChameleonPrefPane/Sources/PreferencesControllerBase.mm

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//--------------------------------------------------------------------------
16static std::list< id<GroupControllerProtocol> > groupList;
17
18// for unix-like options types
19static std::map<void*, std::string> IdToUCmdList;
20static KernOptionsParser kernelFlags;
21
22//--------------------------------------------------------------------------
23
24
25@implementation PreferencesControllerBase
26
27-(ChameleonPrefPane*) chameleon { return [ChameleonPrefPane instance]; }
28
29
30//--------------------------------------------------------------------------
31- (id) init
32{
33self = [super init];
34
35[PreferencesControllerBase registerPreferencesGroup: self];
36
37return self;
38}
39//--------------------------------------------------------------------------
40- (id) getResourcePath: (NSString *) str ofType: (NSString*) sType
41{
42if(!str) return nil;
43NSBundle * b = [NSBundle bundleForClass:[self class]];
44id sRes = [b pathForResource: str ofType:sType ];
45return sRes;
46}
47
48
49//--------------------------------------------------------------------------
50// get authorisation from main panel lock
51- (AuthorizationRef) getAuthorization
52{
53AuthorizationRef auth= [[self chameleon] isUnlocked] ?
54[[ [self chameleon]->authView authorization] authorizationRef] : NULL;
55return auth;
56}
57//--------------------------------------------------------------------------
58+ (void) registerPreferencesGroup:(id) myGroup
59{
60groupList.push_back(myGroup);
61}
62
63- (void) synchronizeTextContent:(const BootOptionDesc*) bod withValue:(int) val
64{
65if(!bod || !bod->contentID) return;
66id item = (id) bod->contentID;
67 if ( [item isKindOfClass: [NSTextField class]] ||
68[item isKindOfClass: [NSComboBox class]])
69{
70[item setEnabled: val];
71[item setEditable: val];
72}
73
74}
75//--------------------------------------------------------------------------
76+ (void) refreshLockState: (id) item
77{
78const BootOptionDesc * bod = BootProp::instance().findOption(item);
79if(!bod) bod=BootProp::instance().findOptionContent(item);
80if(bod) [PreferencesControllerBaserefreshBodLockState: bod];
81else[item setEnabled: [[ChameleonPrefPane instance] isUnlocked]];
82}
83//--------------------------------------------------------------------------
84+ (void) refreshBodLockState: (const BootOptionDesc*) bod
85{
86if (!bod) return;
87bool isUnlocked = [[ChameleonPrefPane instance] isUnlocked];
88if (bod->ID) [(id) bod->ID setEnabled: isUnlocked];
89int val = bod->ID ? [(id) bod->ID intValue] : 0;
90 if ( [(id) bod->contentID isKindOfClass: [NSTextField class]] ||
91[(id) bod->contentID isKindOfClass: [NSComboBox class]])
92{
93[(id) bod->contentID setEnabled: (isUnlocked && val) ];
94[(id) bod->contentID setEditable: (isUnlocked && val) ];
95}
96else
97[(id) bod->contentID setEnabled: isUnlocked];
98}
99
100//--------------------------------------------------------------------------
101+ (void) refreshLockStates
102{
103for (const BootOptionDesc* bod=BootProp::instance().firstOption();
104 bod;
105 bod=BootProp::instance().nextOption())
106{
107[self refreshLockState: (id) bod->ID ];
108if (bod->contentID) [self refreshLockState: (id) bod->contentID ];
109}
110
111}
112//--------------------------------------------------------------------------
113+ (void) doForEachGroup: (GroupAction) action withOption:(id) option
114{
115std::list< id<GroupControllerProtocol> >::iterator it;
116for (it=groupList.begin(); it!=groupList.end(); it++)
117{
118switch (action) {
119case SetDefaultValues:
120[*it setDefaultsValues: option];
121break;
122case RefreshLockStates:
123[*it refreshLockStates ];
124[PreferencesControllerBase refreshLockStates];
125break;
126case LoadPreferencesOptions:
127[*it loadOptionsFromPreferencesFile: option];
128break;
129case LoadBootConfigOptions:
130[PreferencesControllerBase loadOptionsFromBootFile];
131break;
132case AddOptionsDesc:
133[*it addOptionsDesc];
134break;
135case SaveBootConfigOptions:
136break;
137default:
138break;
139}
140}
141}
142
143//--------------------------------------------------------------------------
144+ (void) loadOptionsFromBootFile
145{
146// parse unix like command string:
147kernelFlags.parseOptions(BootProp::instance().getStringForKey(kKernelFlags));
148
149for (const BootOptionDesc* bod=BootProp::instance().firstOption();
150 bod;
151 bod=BootProp::instance().nextOption())
152{
153[PreferencesControllerBase loadOptionFromBootFile:(id)bod->ID ];
154}
155}
156
157//--------------------------------------------------------------------------
158
159+ (void) loadOptionFromBootFile:(id) optionID
160{
161const BootOptionDesc* bod = BootProp::instance().findOption(optionID);
162if (!bod)
163{
164NSRunAlertPanel(@"Error Parsing Option",@"loadOptionFromBootFile failed",@"OK", nil, nil);
165return;
166}
167
168const char * stringForKey = BootProp::instance().getStringForKey(bod->Name);
169std::string s = stringForKey ? trim(stringForKey) : "";
170std::string def = trim(bod->Default ? bod->Default : "");
171
172switch (bod->Type)
173{
174case OptionYesNo:
175if (s.length()>0)
176[(NSButton*)optionID setIntValue: (toupper(s[0])=='Y' ? 1 : 0 ) ];
177else
178[(NSButton*)optionID setIntValue: (toupper(def[0])=='Y' ? 1 : 0 ) ];
179break;
180
181case OptionKernel1:
182{
183int val = (s.length()>0 ? 1 : 0 );
184[(NSButton*)optionID setIntValue: val ];
185[(NSTextField*) bod->contentID setStringValue:
186 [[NSString alloc] initWithUTF8String: s.c_str()] ];
187[(NSTextField*) bod->contentID setEnabled: val ? true : false];
188[(NSTextField*) bod->contentID setEditable: val ? true : false];
189}
190break;
191case OptionFileString:
192case OptionString:
193{
194int val = (s.length()>0 ? 1 : 0 );
195[(NSButton*)optionID setIntValue: val ];
196[(NSTextField*) bod->contentID setStringValue:
197[[NSString alloc] initWithUTF8String: s.c_str()] ];
198[(NSTextField*) bod->contentID setEnabled: val ? true: false];
199[(NSTextField*) bod->contentID setEditable: val ? true : false];
200}
201break;
202
203case OptionUnix:
204case OptionKernel:
205{
206std::string s = kernelFlags.stringFromKey(bod->Name);
207if (s.length()>0)
208{
209[(NSButton*)optionID setIntValue: 1 ];
210if(bod->Type==OptionKernel)
211{
212[(NSTextField*) bod->contentID setStringValue:
213 [[NSString alloc] initWithUTF8String:
214kernelFlags.rightMember(s).c_str()] ];
215[(NSTextField*) bod->contentID setEnabled: true];
216[(NSTextField*) bod->contentID setEditable: true];
217}
218
219}
220else
221{ // set the default for thiso option
222[(NSButton*)optionID setIntValue: (bod->Default[0] ? 1 :0) ];
223if(bod->Type==OptionKernel)
224{
225[(NSTextField*) bod->contentID setEnabled: false];
226[(NSTextField*) bod->contentID setEditable: false];
227}
228
229}
230}
231break;
232default:
233break;
234}
235
236}
237
238//--------------------------------------------------------------------------
239- (void) loadPreferences
240{
241[ [ChameleonPrefPane instance] loadPreferences];
242}
243
244//--------------------------------------------------------------------------
245- (bool) savePreferences
246{
247return [ [ChameleonPrefPane instance] savePreferences: [self preferencesFile] ];
248
249}
250//--------------------------------------------------------------------------
251// update the boot Config with one option change and its associated desc
252- (bool) saveBootConfig: (id) sender withBootOptionDesc: (BootOptionDesc*) bod
253{
254if(!bod)
255{
256return false;
257}
258// load boot config file so that we don't risk to loose
259// externally modified parameters
260
261int val = [(NSButton*) sender intValue ];
262std::string sDefaultValue = trim(bod->Default ? bod->Default : "");
263bool status = false;
264std::string name = trim(bod->Name);
265
266switch (bod->Type) {
267case OptionYesNo:
268{
269std::string sVal = val ? "Yes" : "No";
270if (sDefaultValue.length()==0) sDefaultValue= "No";
271// Avoid populating bootConfig with unnecessary options:
272if (sVal == sDefaultValue)
273status = BootProp::instance().removeKeyAndValue(name.c_str());
274else
275status = BootProp::instance().setStringForKey(name, sVal.c_str());
276}
277break;
278case OptionUnix:
279if (!val)kernelFlags.removeFlag(name);
280elsekernelFlags.addFlag(name);
281BootProp::instance().setStringForKey(kKernelFlags,kernelFlags.options());
282status = true;
283break;
284case OptionKernel:
285{
286std::string contentValue = trim(
287[ [(NSTextField*) bod->contentID stringValue] UTF8String ]);
288kernelFlags.removeFlag(kernelFlags.stringFromKey(bod->Name));
289if(val && contentValue.length()>0)
290{
291std::string concat = trim(name);
292concat+= "=";
293concat+= trim(contentValue);
294
295kernelFlags.addFlag(concat);
296}
297BootProp::instance().setStringForKey(kKernelFlags,kernelFlags.options());
298status = true;
299}
300break;
301case OptionKernel1:
302case OptionFileString:
303case OptionString:
304// Avoid populating bootConfig with unnecessary options:
305if (val == 0 && bod->Type!=OptionKernel1)
306status = BootProp::instance().removeKeyAndValue(bod->Name);
307else
308{
309std::string contentValue =
310[ [(NSTextField*) bod->contentID stringValue] UTF8String ];
311if (contentValue.length()>0)
312status = BootProp::instance().setStringForKey(bod->Name, contentValue.c_str());
313else {
314return false; // no content to save so don't save it
315}
316
317}
318break;
319default:
320break;
321}
322
323// Now save the bootConfig
324AuthorizationRef auth = [self getAuthorization ];
325if (status)status = BootProp::instance().save(auth);
326
327return status;
328}
329//--------------------------------------------------------------------------
330-(NSMutableDictionary*) preferencesFile
331{
332return [[ChameleonPrefPane instance] preferencesFile];
333}
334
335//--------------------------------------------------------------------------
336-(NSMutableDictionary*) preferencesParts
337{
338return [[ChameleonPrefPane instance] preferencesParts];
339}
340
341//--------------------------------------------------------------------------
342- (bool) handleSender: (id) sender
343{
344
345const BootOptionDesc * bod = BootProp::instance().findOption(sender);
346
347if (!bod) {
348bod = BootProp::instance().findOptionContent(sender);
349NSTextField* textField = (NSTextField*) sender;
350std::string content = [[textField stringValue] UTF8String ];
351if(bod->ID!=nil) sender = (id) bod->ID;
352}
353else
354{
355
356int state = [sender intValue];
357
358switch (bod->Type) {
359case OptionKernel:
360case OptionKernel1:
361case OptionFileString:
362case OptionString:
363[(NSTextField*) bod->contentID setEnabled: state ? true : false];
364[(NSTextField*) bod->contentID setEditable: state ? true : false];
365if (state && bod->Type==OptionFileString)
366{
367NSString* f = [self selectAnyFile ];
368if (f)
369{
370[(NSTextField*)bod->contentID setStringValue: f];
371[f release];
372}
373}
374[self synchronizeTextContent: bod withValue: state];
375break;
376default:
377break;
378}
379}
380if(![self saveBootConfig: sender withBootOptionDesc: (BootOptionDesc*) bod] && !bod->contentID )
381{ // Couldn't save, so warn user ...
382NSRunAlertPanel(@"Error saving bootConfig", @"Could not save org.chameleon.Boot.plist",
383@"OK", nil, nil);
384}
385return true;
386}
387
388- (bool) executeTaskAndWaitForTermination: (NSString*)taskPath
389{
390return [ self executeTaskAndWaitForTermination:taskPath withArgs:nil ];
391}
392
393- (bool) executeTaskAndWaitForTermination: (NSString*)taskPath withArgs:(NSArray*) args
394{
395NSTask *task = [[NSTask alloc] init];
396[task setLaunchPath:taskPath];
397if (args) [task setArguments: args];
398[task launch];
399
400[task waitUntilExit]; // wait for process termination
401int status = [task terminationStatus];
402
403return (status == 0) ? true : false;
404}
405
406-(NSString*) selectDirectory:(NSString*) dirName
407{
408NSOpenPanel *oPanel = [NSOpenPanel openPanel];
409 [oPanel setAllowsMultipleSelection:NO];
410[oPanel setCanChooseFiles:NO];
411[oPanel setCanChooseDirectories:YES];
412[oPanel setDirectoryURL:[NSURL fileURLWithPath:dirName isDirectory: YES] ];
413
414BOOL result = [oPanel runModal];
415 if (result == NSOKButton)
416{
417 NSArray *dirToOpen = [oPanel filenames];
418 int count = [dirToOpen count];
419 if(count>0)
420{
421 NSString *aDir = [dirToOpen objectAtIndex:0];
422return aDir;
423}
424 }
425 return nil;
426}
427
428- (NSString*) selectPlistFile:(NSString*) name
429{
430NSArray* fileTypes = [NSArray arrayWithObjects: @"plist", nil];
431NSString * s= [self selectFileWithFileTypes: @"/" withName: name
432 withTypes: fileTypes];
433[fileTypes release];
434return s;
435}
436
437- (NSString*) selectAnyFile
438{
439return [self selectFileWithFileTypes: @"/" withName: nil withTypes:nil];
440}
441
442- (NSString*) selectFileWithFileTypes:(NSString*) dir withName: (NSString*) name withTypes:(NSArray*) fileTypes
443{
444 int result;
445 NSOpenPanel *oPanel = [NSOpenPanel openPanel];
446 [oPanel setAllowsMultipleSelection:NO];
447[oPanel setCanChooseFiles:YES];
448[oPanel setCanChooseDirectories:NO];
449[oPanel setAllowedFileTypes: fileTypes];
450if (dir!=nil && [dir length] > 0 )
451[oPanel setDirectoryURL:[NSURL fileURLWithPath:dir isDirectory: YES] ];
452[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"AppleShowAllFiles"];
453
454 result = [oPanel runModal];
455 if (result == NSOKButton)
456{
457 NSArray *filesToOpen = [oPanel filenames];
458 int count = [filesToOpen count];
459 if(count>0)
460{
461 NSString *aFile = [filesToOpen objectAtIndex:0];
462return aFile;
463
464}
465 }
466
467return nil;
468}
469
470-(void) msgBoxInfo:(NSString*) msg
471{
472NSAlert *alert = [[NSAlert alloc] init];
473[alert setAlertStyle: NSInformationalAlertStyle];
474[alert setMessageText:msg ];
475[alert runModal];
476[alert release];
477}
478
479-(void) msgBoxError:(NSString*) msg
480{
481NSAlert *alert = [[NSAlert alloc] init];
482[alert setAlertStyle: NSCriticalAlertStyle];
483[alert setMessageText: msg ];
484[alert runModal];
485[alert release];
486}
487
488@end
489

Archive Download this file

Revision: 386