source: trunk/CPFPerianPrefPaneController.m @ 452

Revision 452, 23.7 KB checked in by gbooker, 8 years ago (diff)

More robust version checking and corrected some version numbers.

Line 
1#import "CPFPerianPrefPaneController.h"
2#include <sys/stat.h>
3
4#define AC3DynamicRangeKey CFSTR("dynamicRange")
5#define AC3StereoOverDolbyKey CFSTR("useStereoOverDolby")
6#define AC3ProLogicIIKey CFSTR("useDolbyProLogicII")
7#define LastInstalledVersionKey CFSTR("LastInstalledVersion")
8
9@interface NSString (VersionStringCompare)
10- (BOOL)isVersionStringOlderThan:(NSString *)older;
11@end
12
13@implementation NSString (VersionStringCompare)
14- (BOOL)isVersionStringOlderThan:(NSString *)older
15{
16        if([self compare:older] == NSOrderedAscending)
17                return TRUE;
18        if([self hasPrefix:older] && [self length] > [older length] && [self characterAtIndex:[older length]] == 'b')
19                //1.0b1 < 1.0, so check for it.
20                return TRUE;
21        return FALSE;
22}
23@end
24
25@interface CPFPerianPrefPaneController(_private)
26- (void)setAC3DynamicRange:(float)newVal;
27- (void)saveAC3DynamicRange:(float)newVal;
28@end
29
30@implementation CPFPerianPrefPaneController
31
32#pragma mark Preferences Functions
33
34- (BOOL)getBoolFromKey:(CFStringRef)key forAppID:(CFStringRef)appID withDefault:(BOOL)defaultValue
35{
36        CFPropertyListRef value;
37        BOOL ret = defaultValue;
38       
39        value = CFPreferencesCopyAppValue(key, appID);
40        if(value && CFGetTypeID(value) == CFBooleanGetTypeID())
41                ret = CFBooleanGetValue(value);
42       
43        if(value)
44                CFRelease(value);
45       
46        return ret;
47}
48
49- (void)setKey:(CFStringRef)key forAppID:(CFStringRef)appID fromBool:(BOOL)value
50{
51        CFPreferencesSetAppValue(key, value ? kCFBooleanTrue : kCFBooleanFalse, appID);
52}
53
54- (float)getFloatFromKey:(CFStringRef)key forAppID:(CFStringRef)appID withDefault:(float)defaultValue
55{
56    CFPropertyListRef value;
57    float ret = defaultValue;
58   
59        value = CFPreferencesCopyAppValue(key, appID);
60        if(value && CFGetTypeID(value) == CFNumberGetTypeID())
61                CFNumberGetValue(value, kCFNumberFloatType, &ret);
62       
63        if(value)
64                CFRelease(value);
65   
66    return ret;
67}
68
69- (void)setKey:(CFStringRef)key forAppID:(CFStringRef)appID fromString:(NSString *)value
70{
71    CFPreferencesSetAppValue(key, value, appID);
72}
73
74- (NSString *)getStringFromKey:(CFStringRef)key forAppID:(CFStringRef)appID
75{
76    CFPropertyListRef value;
77    NSString *ret = nil;
78   
79        value = CFPreferencesCopyAppValue(key, appID);
80        if(value && CFGetTypeID(value) == CFStringGetTypeID())
81                ret = [NSString stringWithString:(NSString *)value];
82       
83        if(value)
84                CFRelease(value);
85   
86    return ret;
87}
88
89- (void)setKey:(CFStringRef)key forAppID:(CFStringRef)appID fromFloat:(float)value
90{
91    CFNumberRef numRef = CFNumberCreate(NULL, kCFNumberFloatType, &value);
92    CFPreferencesSetAppValue(key, numRef, appID);
93    CFRelease(numRef);
94}
95
96#pragma mark Private Functions
97
98- (NSString *)installationBasePath:(BOOL)userInstallation
99{
100        if(userInstallation)
101                return NSHomeDirectory();
102        return [NSString stringWithString:@"/"];
103}
104
105- (NSString *)quickTimeComponentDir:(BOOL)userInstallation
106{
107        return [[self installationBasePath:userInstallation] stringByAppendingPathComponent:@"Library/QuickTime"];
108}
109
110- (NSString *)coreAudioComponentDir:(BOOL)userInstallation
111{
112        return [[self installationBasePath:userInstallation] stringByAppendingPathComponent:@"Library/Audio/Plug-Ins/Components"];
113}
114
115- (NSString *)frameworkComponentDir:(BOOL)userInstallation
116{
117        return [[self installationBasePath:userInstallation] stringByAppendingPathComponent:@"Library/Frameworks"];
118}
119
120- (NSString *)basePathForType:(ComponentType)type user:(BOOL)userInstallation
121{
122        NSString *path = nil;
123       
124        switch(type)
125        {
126                case ComponentTypeCoreAudio:
127                        path = [self coreAudioComponentDir:userInstallation];
128                        break;
129                case ComponentTypeQuickTime:
130                        path = [self quickTimeComponentDir:userInstallation];
131                        break;
132                case ComponentTypeFramework:
133                        path = [self frameworkComponentDir:userInstallation];
134                        break;
135        }
136        return path;
137}
138
139- (InstallStatus)installStatusForComponent:(NSString *)component type:(ComponentType)type withMyVersion:(NSString *)myVersion
140{
141        NSString *path = nil;
142        InstallStatus ret = InstallStatusNotInstalled;
143       
144        path = [[self basePathForType:type user:userInstalled] stringByAppendingPathComponent:component];
145       
146        NSDictionary *infoDict = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Contents/Info.plist"]];
147        if(infoDict != nil)
148        {
149                NSString *currentVersion = [infoDict objectForKey:BundleVersionKey];
150                if([currentVersion isVersionStringOlderThan:myVersion])
151                        ret = InstallStatusOutdated;
152                else
153                        ret = InstallStatusInstalled;
154        }
155       
156        /* Check other installation type */
157        path = [[self basePathForType:type user:!userInstalled] stringByAppendingPathComponent:component];
158       
159        infoDict = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Contents/Info.plist"]];
160        if(infoDict == nil)
161                /* Above result is all there is */
162                return ret;
163       
164        return setWrongLocationInstalled(ret);
165}
166
167- (void)setInstalledVersionString
168{
169        NSString *path = [[self basePathForType:ComponentTypeQuickTime user:userInstalled] stringByAppendingPathComponent:@"Perian.component"];
170       
171        NSDictionary *infoDict = [NSDictionary dictionaryWithContentsOfFile:[path stringByAppendingPathComponent:@"Contents/Info.plist"]];
172        if(infoDict != nil)
173        {
174                NSString *currentVersion = [infoDict objectForKey:BundleVersionKey];
175                [textField_currentVersion setStringValue:currentVersion];
176        }
177        else
178                [textField_currentVersion setStringValue:@"-"];
179}
180
181#pragma mark Preference Pane Support
182
183- (id)initWithBundle:(NSBundle *)bundle
184{
185    if ( ( self = [super initWithBundle:bundle] ) != nil ) {
186                perianForumURL = [[NSURL alloc] initWithString:@"http://forums.cocoaforge.com/index.php?c=12"];
187                perianDonateURL = [[NSURL alloc] initWithString:@"http://perian.org"];
188                perianWebSiteURL = [[NSURL alloc] initWithString:@"http://perian.org"];
189               
190                perianAppID = CFSTR("org.perian.Perian");
191                a52AppID = CFSTR("com.cod3r.a52codec");
192               
193                NSString *myPath = [[self bundle] bundlePath];
194               
195                if([myPath hasPrefix:@"/Library"])
196                        userInstalled = NO;
197                else
198                        userInstalled = YES;
199    }
200   
201    return self;
202}
203
204- (void)checkForInstallation
205{
206        NSDictionary *infoDict = [[self bundle] infoDictionary];
207        NSString *myVersion = [infoDict objectForKey:BundleVersionKey];
208       
209        [self setInstalledVersionString];
210        installStatus = [self installStatusForComponent:@"Perian.component" type:ComponentTypeQuickTime withMyVersion:myVersion];
211        if(currentInstallStatus(installStatus) == InstallStatusNotInstalled)
212        {
213                [textField_installStatus setStringValue:NSLocalizedString(@"Perian is not Installed", @"")];
214                [button_install setTitle:NSLocalizedString(@"Install Perian", @"")];
215        }
216        else if(currentInstallStatus(installStatus) == InstallStatusOutdated)
217        {
218                [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed, but Outdated", @"")];
219                [button_install setTitle:NSLocalizedString(@"Update Perian", @"")];
220        }
221        else
222        {
223                //Perian is fine, but check components
224                NSDictionary *myComponentsInfo = [infoDict objectForKey:ComponentInfoDictionaryKey];
225                if(myComponentsInfo != nil)
226                {
227                        NSEnumerator *componentEnum = [myComponentsInfo objectEnumerator];
228                        NSDictionary *componentInfo = nil;
229                        while((componentInfo = [componentEnum nextObject]) != nil)
230                        {
231                                InstallStatus tstatus = [self installStatusForComponent:[componentInfo objectForKey:ComponentNameKey] type:[[componentInfo objectForKey:ComponentTypeKey] intValue] withMyVersion:[componentInfo objectForKey:BundleVersionKey]];
232                                if(tstatus < installStatus)
233                                        installStatus = tstatus;
234                        }
235                        switch(installStatus)
236                        {
237                                case InstallStatusInstalledInWrongLocation:
238                                case InstallStatusNotInstalled:
239                                        [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed, but parts are Not Installed", @"")];
240                                        [button_install setTitle:NSLocalizedString(@"Install Perian", @"")];
241                                        break;
242                                case InstallStatusOutdatedWithAnotherInWrongLocation:
243                                case InstallStatusOutdated:
244                                        [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed, but parts are Outdated", @"")];
245                                        [button_install setTitle:NSLocalizedString(@"Update Perian", @"")];
246                                        break;
247                                case InstallStatusInstalledInBothLocations:
248                                        [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed Twice", @"")];
249                                        [button_install setTitle:NSLocalizedString(@"Correct Installation", @"")];
250                                        break;
251                                case InstallStatusInstalled:
252                                        [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed", @"")];
253                                        [button_install setTitle:NSLocalizedString(@"Remove Perian", @"")];
254                                        break;
255                        }
256                }
257                else if(isWrongLocationInstalled(installStatus))
258                {
259                        [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed Twice", @"")];
260                        [button_install setTitle:NSLocalizedString(@"Correct Installation", @"")];
261                }
262                else
263                {
264                        [textField_installStatus setStringValue:NSLocalizedString(@"Perian is Installed", @"")];
265                        [button_install setTitle:NSLocalizedString(@"Remove Perian", @"")];
266                }
267               
268        }
269}
270
271- (void)didSelect
272{
273        /* General */
274        [self checkForInstallation];
275    NSString *lastInstVersion = [self getStringFromKey:LastInstalledVersionKey forAppID:perianAppID];
276    NSString *myVersion = [[[self bundle] infoDictionary] objectForKey:BundleVersionKey];
277    if((lastInstVersion == nil || [lastInstVersion isVersionStringOlderThan:myVersion]) && installStatus != InstallStatusInstalled)
278    {
279        /*Check for temp after an update */
280        BOOL isDir = NO;
281        NSString *tempPrefPane = [NSTemporaryDirectory() stringByAppendingPathComponent:@"PerianPane.prefPane"];
282        int tag;
283       
284        if([[NSFileManager defaultManager] fileExistsAtPath:tempPrefPane isDirectory:&isDir] && isDir)
285            [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[tempPrefPane stringByDeletingLastPathComponent] destination:@"" files:[NSArray arrayWithObject:[tempPrefPane lastPathComponent]] tag:&tag];
286       
287        [self installUninstall:nil];
288        [self setKey:LastInstalledVersionKey forAppID:perianAppID fromString:myVersion];
289    }
290       
291        /* A52 Prefs */
292        if([self getBoolFromKey:AC3StereoOverDolbyKey forAppID:a52AppID withDefault:NO])
293        {
294                [popup_2ChannelMode selectItemAtIndex:0];
295        }
296        else if([self getBoolFromKey:AC3ProLogicIIKey forAppID:a52AppID withDefault:NO])
297        {
298                [popup_2ChannelMode selectItemAtIndex:2];
299        }
300        else
301        {
302                [popup_2ChannelMode selectItemAtIndex:1];               
303        }       
304    [self setAC3DynamicRange:[self getFloatFromKey:AC3DynamicRangeKey forAppID:a52AppID withDefault:1.0]];
305}
306
307- (void)didUnselect
308{
309        CFPreferencesAppSynchronize(perianAppID);
310        CFPreferencesAppSynchronize(a52AppID);
311}
312
313- (void) dealloc {
314        [perianForumURL release];
315        [perianDonateURL release];
316        [perianWebSiteURL release];
317        if(auth != nil)
318                AuthorizationFree(auth, 0);
319        [errorString release];
320        [super dealloc];
321}
322
323#pragma mark Install/Uninstall
324
325/* Shamelessly ripped from Sparkle */
326- (BOOL)_extractArchivePath:archivePath toDestination:(NSString *)destination
327{
328        BOOL ret = NO;
329        struct stat sb;
330        if(stat([destination fileSystemRepresentation], &sb) != 0)
331        {
332                [errorString appendFormat:NSLocalizedString(@"No such directory %@\n", @""), destination];
333                return FALSE;
334        }
335       
336        char *buf = NULL;
337        asprintf(&buf,
338                         "ditto -x -k --rsrc \"$SRC_ARCHIVE\" \"$DST_PATH\"");
339        if(!buf)
340        {
341                [errorString appendFormat:NSLocalizedString(@"Could not allocate memory for extraction command\n", @"")];
342                return FALSE;
343        }
344       
345        setenv("SRC_ARCHIVE", [archivePath fileSystemRepresentation], 1);
346        setenv("DST_PATH", [destination fileSystemRepresentation], 1);
347       
348        int status = system(buf);
349        if(WIFEXITED(status) && WEXITSTATUS(status) == 0)
350                ret = YES;
351        else
352                [errorString appendFormat:NSLocalizedString(@"Extraction for %@ failed\n", @""), archivePath];
353
354        free(buf);
355        unsetenv("SRC_ARCHIVE");
356        unsetenv("DST_PATH");
357        return ret;
358}
359
360- (BOOL)_authenticatedExtractArchivePath:(NSString *)archivePath toDestination:(NSString *)destination finalPath:(NSString *)finalPath
361{
362        BOOL ret = NO, oldExist = NO;
363        struct stat sb;
364        if(stat([finalPath fileSystemRepresentation], &sb) == 0)
365                oldExist = YES;
366       
367        if(stat([destination fileSystemRepresentation], &sb) != 0)
368        {
369                [errorString appendFormat:NSLocalizedString(@"No such directory %@\n", @""), destination];
370                return FALSE;
371        }
372       
373        char *buf = NULL;
374        if(oldExist)
375                asprintf(&buf,
376                                 "mv -f \"$DST_COMPONENT\" \"$TMP_PATH\" && "
377                                 "ditto -x -k --rsrc \"$SRC_ARCHIVE\" \"$DST_PATH\" && "
378                                 "rm -rf \"$TMP_PATH\" && "
379                                 "chown -R %d:%d \"$DST_COMPONENT\"",
380                                 sb.st_uid, sb.st_gid);
381        else
382                asprintf(&buf,
383                                 "ditto -x -k --rsrc \"$SRC_ARCHIVE\" \"$DST_PATH\" && "
384                                 "chown -R %d:%d \"$DST_COMPONENT\"",
385                                 sb.st_uid, sb.st_gid);
386        if(!buf)
387        {
388                [errorString appendFormat:NSLocalizedString(@"Could not allocate memory for extraction command\n", @"")];
389                return FALSE;
390        }
391       
392        setenv("SRC_ARCHIVE", [archivePath fileSystemRepresentation], 1);
393        setenv("DST_COMPONENT", [finalPath fileSystemRepresentation], 1);
394        setenv("TMP_PATH", [[finalPath stringByAppendingPathExtension:@"old"] fileSystemRepresentation], 1);
395        setenv("DST_PATH", [destination fileSystemRepresentation], 1);
396       
397        char* arguments[] = { "-c", buf, NULL };
398        if(AuthorizationExecuteWithPrivileges(auth, "/bin/sh", kAuthorizationFlagDefaults, arguments, NULL) == errAuthorizationSuccess)
399        {
400                int status;
401                int pid = wait(&status);
402                if(pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0)
403                        ret = YES;
404                else
405                        [errorString appendFormat:NSLocalizedString(@"Extraction for %@ failed\n", @""), archivePath];
406        }
407        else
408                [errorString appendFormat:NSLocalizedString(@"Authentication failed for extraction for %@\n", @""), archivePath];
409       
410        free(buf);
411        unsetenv("SRC_ARCHIVE");
412        unsetenv("$DST_COMPONENT");
413        unsetenv("TMP_PATH");
414        unsetenv("DST_PATH");
415        return ret;
416}
417
418- (BOOL)_authenticatedRemove:(NSString *)componentPath
419{
420        BOOL ret = NO;
421        struct stat sb;
422        if(stat([componentPath fileSystemRepresentation], &sb) != 0)
423                /* No error, just forget it */
424                return FALSE;
425       
426        char *buf = NULL;
427        asprintf(&buf,
428                         "rm -rf \"$COMP_PATH\"");
429        if(!buf)
430        {
431                [errorString appendFormat:NSLocalizedString(@"Could not allocate memory for removal command\n", @"")];
432                return FALSE;
433        }
434       
435        setenv("COMP_PATH", [componentPath fileSystemRepresentation], 1);
436       
437        char* arguments[] = { "-c", buf, NULL };
438        if(AuthorizationExecuteWithPrivileges(auth, "/bin/sh", kAuthorizationFlagDefaults, arguments, NULL) == errAuthorizationSuccess)
439        {
440                int status;
441                int pid = wait(&status);
442                if(pid != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0)
443                        ret = YES;
444                else
445                        [errorString appendFormat:NSLocalizedString(@"Removal for %@ failed\n", @""), componentPath];
446        }
447        else
448                [errorString appendFormat:NSLocalizedString(@"Authentication failed for removal for %@\n", @""), componentPath];
449        free(buf);
450        unsetenv("COMP_PATH");
451        return ret;
452}
453
454
455- (BOOL)installArchive:(NSString *)archivePath forPiece:(NSString *)component type:(ComponentType)type withMyVersion:(NSString *)myVersion
456{
457        NSString *containingDir = [self basePathForType:type user:userInstalled];
458        BOOL ret = YES;
459
460        InstallStatus pieceStatus = [self installStatusForComponent:component type:type withMyVersion:myVersion];
461        if(!userInstalled && currentInstallStatus(pieceStatus) != InstallStatusInstalled)
462        {
463                BOOL result = [self _authenticatedExtractArchivePath:archivePath toDestination:containingDir finalPath:[containingDir stringByAppendingPathComponent:component]];
464                if(result == NO)
465                        ret = NO;
466        }
467        else
468        {
469                //Not authenticated
470                if(currentInstallStatus(pieceStatus) == InstallStatusOutdated)
471                {
472                        //Remove the old one here
473                        int tag = 0;
474                        BOOL result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:containingDir destination:@"" files:[NSArray arrayWithObject:component] tag:&tag];
475                        if(result == NO)
476                                ret = NO;
477                }
478                if(currentInstallStatus(pieceStatus) != InstallStatusInstalled)
479                {
480                        //Decompress and install new one
481                        BOOL result = [self _extractArchivePath:archivePath toDestination:containingDir];
482                        if(result == NO)
483                                ret = NO;
484                }               
485        }
486        if(ret != NO && isWrongLocationInstalled(pieceStatus) != 0)
487        {
488                /* Let's try and remove the wrong one, if we can, but only if install succeeded */
489                containingDir = [self basePathForType:type user:!userInstalled];
490
491                if(userInstalled)
492                        [self _authenticatedRemove:[containingDir stringByAppendingPathComponent:component]];
493                else
494                {
495                        int tag = 0;
496                        [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:containingDir destination:@"" files:[NSArray arrayWithObject:component] tag:&tag];
497                }
498        }
499        return ret;
500}
501
502- (void)install:(id)sender
503{
504        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
505        NSDictionary *infoDict = [[self bundle] infoDictionary];
506        NSDictionary *myComponentsInfo = [infoDict objectForKey:ComponentInfoDictionaryKey];
507        NSString *componentPath = [[[self bundle] resourcePath] stringByAppendingPathComponent:@"Components"];
508        NSString *coreAudioComponentPath = [componentPath stringByAppendingPathComponent:@"CoreAudio"];
509        NSString *quickTimeComponentPath = [componentPath stringByAppendingPathComponent:@"QuickTime"];
510        NSString *frameworkComponentPath = [componentPath stringByAppendingPathComponent:@"Frameworks"];
511
512        [errorString release];
513        errorString = [[NSMutableString alloc] init];
514        /* This doesn't ask the user, so create it anyway.  If we don't need it, no problem */
515        if(AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &auth) != errAuthorizationSuccess)
516                /* Oh well, hope we don't need it */
517                auth = nil;
518       
519        [self installArchive:[componentPath stringByAppendingPathComponent:@"Perian.zip"] forPiece:@"Perian.component" type:ComponentTypeQuickTime withMyVersion:[infoDict objectForKey:BundleVersionKey]];
520       
521        NSEnumerator *componentEnum = [myComponentsInfo objectEnumerator];
522        NSDictionary *myComponent = nil;
523        while((myComponent = [componentEnum nextObject]) != nil)
524        {
525                NSString *archivePath = nil;
526                ComponentType type = [[myComponent objectForKey:ComponentTypeKey] intValue];
527                switch(type)
528                {
529                        case ComponentTypeCoreAudio:
530                                archivePath = [coreAudioComponentPath stringByAppendingPathComponent:[myComponent objectForKey:ComponentArchiveNameKey]];
531                                break;
532                        case ComponentTypeQuickTime:
533                                archivePath = [quickTimeComponentPath stringByAppendingPathComponent:[myComponent objectForKey:ComponentArchiveNameKey]];
534                                break;
535                        case ComponentTypeFramework:
536                                archivePath = [frameworkComponentPath stringByAppendingPathComponent:[myComponent objectForKey:ComponentArchiveNameKey]];
537                                break;
538                }
539                [self installArchive:archivePath forPiece:[myComponent objectForKey:ComponentNameKey] type:type withMyVersion:[myComponent objectForKey:BundleVersionKey]];
540        }
541        if(auth != nil)
542        {
543                AuthorizationFree(auth, 0);
544                auth = nil;
545        }
546        [self performSelectorOnMainThread:@selector(installComplete:) withObject:nil waitUntilDone:NO];
547        [pool release];
548}
549
550- (void)uninstall:(id)sender
551{
552        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
553        NSDictionary *infoDict = [[self bundle] infoDictionary];
554        NSDictionary *myComponentsInfo = [infoDict objectForKey:ComponentInfoDictionaryKey];
555
556        [errorString release];
557        errorString = [[NSMutableString alloc] init];
558        /* This doesn't ask the user, so create it anyway.  If we don't need it, no problem */
559        if(AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &auth) != errAuthorizationSuccess)
560                /* Oh well, hope we don't need it */
561                auth = nil;
562       
563        int tag = 0;
564        BOOL result = NO;
565        if(auth != nil)
566                [self _authenticatedRemove:[[self quickTimeComponentDir:userInstalled] stringByAppendingPathComponent:@"Perian.component"]];
567        else
568                result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:[self quickTimeComponentDir:userInstalled] destination:@"" files:[NSArray arrayWithObject:@"Perian.component"] tag:&tag];
569       
570        NSEnumerator *componentEnum = [myComponentsInfo objectEnumerator];
571        NSDictionary *myComponent = nil;
572        while((myComponent = [componentEnum nextObject]) != nil)
573        {
574                ComponentType type = [[myComponent objectForKey:ComponentTypeKey] intValue];
575                NSString *directory = [self basePathForType:type user:userInstalled];
576                if(auth != nil)
577                        [self _authenticatedRemove:[directory stringByAppendingPathComponent:[myComponent objectForKey:ComponentNameKey]]];
578                else
579                        result = [[NSWorkspace sharedWorkspace] performFileOperation:NSWorkspaceRecycleOperation source:directory destination:@"" files:[NSArray arrayWithObject:[myComponent objectForKey:ComponentNameKey]] tag:&tag];
580        }
581        if(auth != nil)
582        {
583                AuthorizationFree(auth, 0);
584                auth = nil;
585        }
586       
587        [self performSelectorOnMainThread:@selector(installComplete:) withObject:nil waitUntilDone:NO];
588        [pool release];
589}
590
591- (IBAction)installUninstall:(id)sender
592{
593        [progress_install startAnimation:sender];
594        if(installStatus == InstallStatusInstalled)
595                [NSThread detachNewThreadSelector:@selector(uninstall:) toTarget:self withObject:nil];
596        else
597                [NSThread detachNewThreadSelector:@selector(install:) toTarget:self withObject:nil];
598}
599
600- (void)installComplete:(id)sender
601{
602        [progress_install stopAnimation:sender];
603        [self checkForInstallation];
604}
605
606#pragma mark Check Updates
607- (IBAction)updateCheck:(id)sender
608{
609    FSRef updateCheckRef;
610   
611    OSStatus status = FSPathMakeRef((UInt8 *)[[[[self bundle] bundlePath] stringByAppendingPathComponent:@"Contents/Resources/PerianUpdateChecker.app"] fileSystemRepresentation], &updateCheckRef, NULL);
612    if(status != noErr)
613        return;
614   
615    LSOpenFSRef(&updateCheckRef, NULL);
616}
617
618- (IBAction)setAutoUpdateCheck:(id)sender
619{
620}
621
622
623#pragma mark AC3
624- (IBAction)setAC3DynamicRangePopup:(id)sender
625{
626        int selected = [popup_ac3DynamicRangeType indexOfSelectedItem];
627        switch(selected)
628        {
629                case 0:
630                        [self saveAC3DynamicRange:1.0];
631                        break;
632                case 1:
633                        [self saveAC3DynamicRange:2.0];
634                        break;
635                case 3:
636                        [NSApp beginSheet:window_dynRangeSheet modalForWindow:[[self mainView] window] modalDelegate:nil didEndSelector:nil contextInfo:NULL];
637                        break;
638                default:
639                        break;
640        }
641}
642
643- (IBAction)set2ChannelModePopup:(id)sender;
644{
645        int selected = [popup_2ChannelMode indexOfSelectedItem];
646        switch(selected)
647        {
648                case 0:
649                        [self setKey:AC3StereoOverDolbyKey forAppID:a52AppID fromBool:YES];
650                        [self setKey:AC3ProLogicIIKey forAppID:a52AppID fromBool:NO];
651                        break;
652                case 1:
653                        [self setKey:AC3StereoOverDolbyKey forAppID:a52AppID fromBool:NO];
654                        [self setKey:AC3ProLogicIIKey forAppID:a52AppID fromBool:NO];
655                        break;
656                case 2:
657                        [self setKey:AC3StereoOverDolbyKey forAppID:a52AppID fromBool:NO];
658                        [self setKey:AC3ProLogicIIKey forAppID:a52AppID fromBool:YES];
659                        break;
660                default:
661                        break;
662        }       
663}
664
665- (void)setAC3DynamicRange:(float)newVal
666{
667    if(newVal > 4.0)
668        newVal = 4.0;
669    if(newVal < 0.0)
670        newVal = 0.0;
671   
672        nextDynValue = newVal;
673    [textField_ac3DynamicRangeValue setFloatValue:newVal];
674    [slider_ac3DynamicRangeSlider setFloatValue:newVal];
675        if(newVal == 1.0)
676                [popup_ac3DynamicRangeType selectItemAtIndex:0];
677        else if(newVal == 2.0)
678                [popup_ac3DynamicRangeType selectItemAtIndex:1];
679        else
680                [popup_ac3DynamicRangeType selectItemAtIndex:3];
681}
682
683- (void)saveAC3DynamicRange:(float)newVal
684{
685        [self setKey:AC3DynamicRangeKey forAppID:a52AppID fromFloat:newVal];
686        [self setAC3DynamicRange:newVal];
687}
688
689- (IBAction)setAC3DynamicRangeValue:(id)sender
690{
691    float newVal = [textField_ac3DynamicRangeValue floatValue];
692   
693    [self setAC3DynamicRange:newVal];
694}
695
696- (IBAction)setAC3DynamicRangeSlider:(id)sender
697{
698    float newVal = [slider_ac3DynamicRangeSlider floatValue];
699   
700    [self setAC3DynamicRange:newVal];
701}
702
703- (IBAction)cancelDynRangeSheet:(id)sender
704{
705        [self setAC3DynamicRange:[self getFloatFromKey:AC3DynamicRangeKey forAppID:a52AppID withDefault:1.0]];
706        [NSApp endSheet:window_dynRangeSheet];
707        [window_dynRangeSheet orderOut:self];
708}
709
710- (IBAction)saveDynRangeSheet:(id)sender;
711{
712        [NSApp endSheet:window_dynRangeSheet];
713        [self saveAC3DynamicRange:nextDynValue];
714        [window_dynRangeSheet orderOut:self];
715}
716
717#pragma mark About
718- (IBAction)launchWebsite:(id)sender
719{
720        [[NSWorkspace sharedWorkspace] openURL:perianWebSiteURL];
721}
722
723- (IBAction)launchDonate:(id)sender
724{
725       
726        [[NSWorkspace sharedWorkspace] openURL:perianDonateURL];
727}
728
729- (IBAction)launchForum:(id)sender
730{
731       
732        [[NSWorkspace sharedWorkspace] openURL:perianForumURL];
733       
734}
735
736@end
Note: See TracBrowser for help on using the repository browser.