root/branches/CoreData/SapphireFrappliance/FRAppliance/SapphireApplianceController.m @ 838

Revision 838, 23.7 KB (checked in by gbooker, 16 months ago)

Leak fixes

Line 
1/*
2 * SapphireApplianceController.m
3 * Sapphire
4 *
5 * Created by pnmerrill on Jun. 20, 2007.
6 * Copyright 2007 Sapphire Development Team and/or www.nanopi.net
7 * All rights reserved.
8 *
9 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
10 * General Public License as published by the Free Software Foundation; either version 3 of the License,
11 * or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
14 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
15 * Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along with this program; if not,
18 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 */
20
21#import "SapphireApplianceController.h"
22#import <BackRow/BackRow.h>
23#include <dlfcn.h>
24#import <SapphireCompatClasses/SapphireFrontRowCompat.h>
25#import <SapphireCompatClasses/SapphireDVDLoadingController.h>
26
27#import "SapphireBrowser.h"
28#import "SapphireDirectoryMetaData.h"
29#import "SapphireFileMetaData.h"
30#import "SapphireSettings.h"
31#import "SapphireTheme.h"
32#import "SapphireCollectionDirectory.h"
33#import "CoreDataSupportFunctions.h"
34#import "SapphireEpisode.h"
35
36#import "SapphireImporterDataMenu.h"
37#import "SapphireXMLFileDataImporter.h"
38#import "SapphireFileDataImporter.h"
39#import "SapphireTVShowImporter.h"
40#import "SapphireMovieImporter.h"
41#import "SapphireAllImporter.h"
42#import "SapphireImportHelper.h"
43#import "SapphireMetaDataSupport.h"
44#import "SapphireEntityDirectory.h"
45#import "SapphireTVShow.h"
46#import "SapphireMovieDirectory.h"
47#import "SapphireMarkMenu.h"
48#import "SapphireDisplayMenu.h"
49
50#import "NSFileManager-Extensions.h"
51
52NSString *SAPPHIRE_MANAGED_OBJECT_CONTEXT_CLOSING =     @"SapphireManagedObjectContextClosing";
53
54#define BROWSER_MENU_ITEM               BRLocalizedString(@"  Browse", @"Browser Menu Item")
55#define ALL_IMPORT_MENU_ITEM    BRLocalizedString(@"  Import All Data", @"All Importer Menu Item")
56#define SETTINGS_MENU_ITEM              BRLocalizedString(@"  Settings", @"Settings Menu Item")
57#define RESET_MENU_ITEM                 BRLocalizedString(@"  Reset the thing already", @"UI Quit")
58
59@interface SapphireDistributedMessagesReceiver : NSObject <SapphireDistributedMessagesProtocol>
60{
61        SapphireApplianceController *controller;
62        NSConnection                            *rescanConnection;
63}
64
65- (id)initWithController:(SapphireApplianceController *)cont;
66@end
67
68
69@interface SapphireApplianceController (private)
70- (void)setMenuFromSettings;
71- (void)recreateMenu;
72@end
73
74@implementation SapphireApplianceController
75
76static NSArray *predicates = nil;
77
78NSPredicate *unwatched = nil;
79NSPredicate *favorite = nil;
80NSPredicate *skipJoin = nil;
81NSPredicate *strictUnwatched = nil;
82NSPredicate *strictFavorite = nil;
83
84static NSString *overrideDir = nil;
85
86NSString *applicationSupportDir(void)
87{
88        NSString *ret = overrideDir;
89        if(ret == nil)
90                ret = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire"];
91        NSFileManager *fm = [NSFileManager defaultManager];
92        if(![fm isDirectory:ret])
93                [fm constructPath:ret];
94        return ret;
95}
96
97void overrideApplicationSupportdir(NSString *override)
98{
99        [overrideDir release];
100        overrideDir = [override retain];
101}
102
103+ (void)initialize
104{
105        skipJoin = [[NSPredicate predicateWithFormat:@"joinedToFile == nil"] retain];
106        unwatched = [[NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:[NSPredicate predicateWithFormat:@"watched == NO"], skipJoin, nil]] retain];
107        favorite = [[NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:[NSPredicate predicateWithFormat:@"favorite == YES"], skipJoin, nil]] retain];
108//      NSPredicate *topShows = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:[NSPredicate predicateWithFormat:@"top == YES"], skipJoin, nil]];
109        predicates = [[NSArray alloc] initWithObjects:unwatched, favorite/*, topShows*/, nil];
110        strictUnwatched = [[NSPredicate predicateWithFormat:@"watched == NO"] retain];
111        strictFavorite = [[NSPredicate predicateWithFormat:@"favorite == YES"] retain];
112}
113
114+ (NSPredicate *)predicate
115{
116        SapphireSettings *settings = [SapphireSettings sharedSettings];
117        int index = [settings indexOfLastPredicate];
118        if(index == NSNotFound)
119                return skipJoin;
120        return [predicates objectAtIndex:index];
121}
122
123+ (NSPredicate *)nextPredicate
124{
125        SapphireSettings *settings = [SapphireSettings sharedSettings];
126        int index = [settings indexOfLastPredicate];
127        int newIndex;
128        switch(index)
129        {
130                case NSNotFound:
131                        newIndex = 0;
132                        if([settings displayUnwatched])
133                                break;
134                case 0:
135                        newIndex = 1;
136                        if([settings displayFavorites])
137                                break;
138//              case 1:
139//                      newIndex = 2;
140//                      if([settings displayTopShows])
141//                              break;
142                default:
143                        newIndex = NSNotFound;
144        }
145        [settings setIndexOfLastPredicate:newIndex];
146        if(newIndex == NSNotFound)
147                return skipJoin;
148        return [predicates objectAtIndex:newIndex];
149}
150
151+ (PredicateType)predicateType
152{
153        return [[SapphireSettings sharedSettings] indexOfLastPredicate];
154}
155
156+ (void)setPredicateType:(PredicateType)type
157{
158        [[SapphireSettings sharedSettings] setIndexOfLastPredicate:type];
159}
160
161+ (NSPredicate *)unfilteredPredicate
162{
163        return skipJoin;
164}
165
166+ (NSPredicate *)unwatchedPredicate
167{
168        return strictUnwatched;
169}
170
171+ (NSPredicate *)favoritePredicate
172{
173        return strictFavorite;
174}
175
176+ (BRTexture *)gemForPredicate:(NSPredicate *)predicate
177{
178        SapphireTheme *theme = [SapphireTheme sharedTheme];
179        if(predicate == nil)
180                return [theme gem:RED_GEM_KEY];
181        int index = [predicates indexOfObject:predicate];
182        switch (index) {
183                case 0:
184                        return [theme gem:BLUE_GEM_KEY];
185                case 1:
186                        return [theme gem:YELLOW_GEM_KEY];
187                case 2:
188                        return [theme gem:GREEN_GEM_KEY];
189        }
190        return [theme gem:RED_GEM_KEY];
191}
192
193+ (NSString *)keyForFilterPredicate:(NSPredicate *)filter andCheckPredicate:(NSPredicate *)check
194{
195        int found = 0;
196        if(filter == skipJoin)
197                found = 1;
198        else if (filter == unwatched)
199                found = 2;
200        else if (filter == favorite)
201                found = 4;
202        else if (filter != nil)
203                return [[filter description] stringByAppendingString:[check description]];
204       
205        if(check == strictUnwatched)
206                found |= 2;
207        else if (check == strictFavorite)
208                found |= 4;
209        else if (check != nil)
210                return [[filter description] stringByAppendingString:[check description]];
211       
212        switch (found) {
213                case 0:
214                        return @"nil";
215                case 1:
216                        return @"S";
217                case 2:
218                        return @"W";
219                case 3:
220                        return @"SW";
221                case 4:
222                        return @"F";
223                case 5:
224                        return @"SF";
225                case 6:
226                        return @"WF";
227                case 7:
228                        return @"SWF";
229        }
230        return nil;
231}
232
233+ (void)logException:(NSException *)e
234{
235        NSMutableString *ret = [NSMutableString stringWithFormat:@"Exception: %@ %@\n", [e name], [e reason]];
236        if([e respondsToSelector:@selector(backtrace)])
237        {
238                [ret appendFormat:@"%@\n%@", e, [(BRBacktracingException *)e backtrace]];
239                Dl_info info;
240                if(dladdr(&predicates, &info))
241                        [ret appendFormat:@"Sapphire is at 0x%X", info.dli_fbase];
242        }
243        else
244        {
245                NSArray *addrs = [SapphireFrontRowCompat callStackReturnAddressesForException:e];
246                int i, count = [addrs count];
247                NSMutableDictionary *mapping = [NSMutableDictionary dictionary];
248                for(i=0; i<count; i++)
249                {
250                        Dl_info info;
251                        const void *addr = [[addrs objectAtIndex:i] pointerValue];
252                        if(dladdr(addr, &info))
253                                [mapping setObject:[NSString stringWithCString:info.dli_fname] forKey:[NSValue valueWithPointer:info.dli_fbase]];
254                        [ret appendFormat:@" 0x%X", addr];
255                }
256                NSEnumerator *mappingEnum = [mapping keyEnumerator];
257                NSValue *key = nil;
258                while((key = [mappingEnum nextObject]) != nil)
259                        [ret appendFormat:@"\n0x%X\t%@", [key pointerValue], [mapping objectForKey:key]];
260        }
261        SapphireLog(SAPPHIRE_LOG_GENERAL, SAPPHIRE_LOG_LEVEL_ERROR, @"%@", ret);       
262}
263
264+ (NSString *) rootMenuLabel
265{
266        return (@"net.pmerrill.Sapphire" );
267}
268
269+ (BOOL)upgradeNeeded
270{
271        NSFileManager *fm = [NSFileManager defaultManager];
272        NSString *storeFile = [applicationSupportDir() stringByAppendingPathComponent:@"metaData.sapphireDataV2"];
273        BOOL exists = [fm fileExistsAtPath:storeFile];
274        BOOL oldExists = [fm fileExistsAtPath:[applicationSupportDir() stringByAppendingPathComponent:@"metaData.sapphireData"]];
275        oldExists |= [fm fileExistsAtPath:[applicationSupportDir() stringByAppendingPathComponent:@"metaData.plist"]];
276        return !exists && oldExists;
277}
278
279
280+ (NSManagedObjectContext *)newManagedObjectContextForFile:(NSString *)storeFile
281{
282        if(storeFile == nil)
283                storeFile = [applicationSupportDir() stringByAppendingPathComponent:@"metaData.sapphireDataV2"];
284        NSFileManager *fm = [NSFileManager defaultManager];
285        [fm constructPath:[storeFile stringByDeletingLastPathComponent]];
286        NSURL *storeUrl = [NSURL fileURLWithPath:storeFile];
287        NSError *error = nil;
288       
289        NSString *mopath = [[NSBundle bundleForClass:[self class]] pathForResource:@"Sapphire" ofType:@"momd"];
290        mopath = [mopath stringByAppendingPathComponent:@"SapphireV2.mom"];
291        NSURL *mourl = [NSURL fileURLWithPath:mopath];
292        NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:mourl];
293       
294        NSPersistentStoreCoordinator *coord = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
295        if(![coord addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error])
296        {
297                SapphireLog(SAPPHIRE_LOG_ALL, SAPPHIRE_LOG_LEVEL_ERROR, @"Could not add store: %@", error);
298               
299                [coord release];
300                [model release];
301                return nil;
302        }
303       
304        NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
305        [moc setUndoManager:nil];
306        [moc setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
307        [moc setPersistentStoreCoordinator:coord];
308       
309        [model release];
310        [coord release];
311       
312        return moc;
313}
314
315- (id) initWithScene: (BRRenderScene *) scene
316{
317        self = [super initWithScene:scene];
318       
319        //Setup the theme's scene
320        SapphireTheme *theme = [SapphireTheme sharedTheme];
321        [theme setScene:[self scene]];
322       
323        moc = [SapphireApplianceController newManagedObjectContextForFile:nil];
324        [SapphireMetaDataSupport setMainContext:moc];
325        if(moc == nil)
326        {
327                [self autorelease];
328                return nil;
329        }
330       
331        [SapphireDirectoryMetaData createDirectoryWithPath:@"/" parent:nil inContext:moc];
332        [SapphireCollectionDirectory collectionAtPath:@"/" mount:YES skip:YES hidden:YES manual:NO inContext:moc];
333       
334        settings                                                                = [[SapphireSettings alloc] initWithScene:[self scene] settingsPath:[applicationSupportDir() stringByAppendingPathComponent:@"settings.plist"] context:moc];
335        [self setListTitle:                                             BRLocalizedString(@"Main Menu", @"")];
336        [settings setListTitle:                                 BRLocalizedString(@" Settings", @"Settings Menu Item")] ;
337        [settings setListIcon:                                  [theme gem:GEAR_GEM_KEY]];
338        [[self list] setDatasource:self];
339        if([SapphireFrontRowCompat usingFrontRow] && ![SapphireFrontRowCompat usingTakeTwo])
340        {
341                NSString *myBundlePath = [[NSBundle bundleForClass:[self class]] bundlePath] ;
342                NSString *onlyPath = [myBundlePath stringByAppendingPathComponent:@"/Contents/Frameworks/LeopardOnly.framework"];
343                NSBundle *only = [NSBundle bundleWithPath:onlyPath];
344                Class onlyClass = [only principalClass];
345                leoOnly = [[onlyClass alloc] initWithContext:moc];
346        }
347        mountsOnly = NO;
348       
349        SapphireSetLogLevel(SAPPHIRE_LOG_ALL, SAPPHIRE_LOG_LEVEL_ERROR);
350        SapphireSetLogLevel(SAPPHIRE_LOG_METADATA_STORE, SAPPHIRE_LOG_LEVEL_DEBUG);
351       
352        distributed = [[SapphireDistributedMessagesReceiver alloc] initWithController:self];
353       
354        return self;
355}
356
357- (void)dealloc
358{
359        [leoOnly release];
360        [names release];
361        [controllers release];
362        [masterNames release];
363        [masterControllers release];
364        [moc release];
365        [SapphireSettings relinquishSettings];
366        [settings release];
367        [SapphireImportHelper relinquishHelper];
368        [distributed release];
369        [super dealloc];
370}
371
372- (void)recreateMenu
373{
374        names = [[NSMutableArray alloc] init];
375        controllers = [[NSMutableArray alloc] init];
376        if(mountsOnly)
377        {
378                masterNames = [[NSArray alloc] init];
379                masterControllers = [[NSArray alloc] init];
380        }
381        else
382        {
383                SapphireImporterDataMenu *allImporter   = [self allImporter];
384                NSMutableArray *mutableMasterNames = [[NSMutableArray alloc] init];
385                NSMutableArray *mutableMasterControllers = [[NSMutableArray alloc] init];
386               
387                SapphireBrowser *tvBrowser = [self tvBrowser];
388                [mutableMasterNames addObject:BRLocalizedString(@"  TV Shows", nil)];
389                [mutableMasterControllers addObject:tvBrowser];
390               
391                SapphireBrowser *movieBrowser = [self movieBrowser];
392                [mutableMasterNames addObject:BRLocalizedString(@"  Movies", nil)];
393                [mutableMasterControllers addObject:movieBrowser];
394               
395                [mutableMasterNames addObjectsFromArray:[NSArray arrayWithObjects:
396                                                                                                 ALL_IMPORT_MENU_ITEM,
397                                                                                                 SETTINGS_MENU_ITEM,
398                                                                                                 RESET_MENU_ITEM,
399                                                                                                 nil]];
400                [mutableMasterControllers addObjectsFromArray:[NSArray arrayWithObjects:
401                                                                                                           allImporter,
402                                                                                                           settings,
403                                                                                                           nil]];
404                masterNames = [[NSArray alloc] initWithArray:mutableMasterNames];
405                masterControllers = [[NSArray alloc] initWithArray:mutableMasterControllers];
406                [mutableMasterNames release];
407                [mutableMasterControllers release];             
408        }
409        [self setMenuFromSettings];
410}
411
412NSArray *showEntityFetch(NSManagedObjectContext *moc, NSPredicate *filterPredicate)
413{
414        NSPredicate *fetchPredicate = [NSPredicate predicateWithFormat:@"tvEpisode != nil"];
415        NSPredicate *finalPred;
416        if(filterPredicate == nil)
417                finalPred = fetchPredicate;
418        else
419                finalPred = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:filterPredicate, fetchPredicate, nil]];
420        NSArray *files = doFetchRequest(SapphireFileMetaDataName, moc, finalPred);
421
422        NSSet *epIds = [NSSet setWithArray:[files valueForKeyPath:@"tvEpisode.objectID"]];
423        NSPredicate *epPred = [NSPredicate predicateWithFormat:@"SELF IN %@", epIds];
424        NSArray *episodes = doFetchRequest(SapphireEpisodeName, moc, epPred);
425
426        NSSet *showIds = [NSSet setWithArray:[episodes valueForKeyPath:@"tvShow.objectID"]];
427        NSPredicate *showPred = [NSPredicate predicateWithFormat:@"SELF IN %@", showIds];
428
429        return doFetchRequest(SapphireTVShowName, moc, showPred);
430}
431
432- (SapphireBrowser *)tvBrowser
433{
434        BRTexture *predicateGem = [SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]];
435        SapphireEntityDirectory *tvDir = [[SapphireEntityDirectory alloc] initWithEntityFetch:showEntityFetch inContext:moc];
436        [tvDir setMetaFileFetchPredicate:[NSPredicate predicateWithFormat:@"tvEpisode != nil"]];
437        SapphireBrowser *tvBrowser = [[SapphireBrowser alloc] initWithScene:[self scene] metaData:tvDir];
438        [tvDir release];
439        [tvBrowser setListTitle:BRLocalizedString(@" TV Shows", nil)];
440        [tvBrowser setListIcon:predicateGem];
441        return [tvBrowser autorelease];
442}
443
444- (SapphireBrowser *)movieBrowser
445{
446        BRTexture *predicateGem = [SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]];
447        SapphireMovieDirectory *movieDir = [[SapphireMovieDirectory alloc] initWithContext:moc];
448        SapphireBrowser *movieBrowser = [[SapphireBrowser alloc] initWithScene:[self scene] metaData:movieDir];
449        [movieDir release];
450        [movieBrowser setListTitle:BRLocalizedString(@" Movies", nil)];
451        [movieBrowser setListIcon:predicateGem];
452        return [movieBrowser autorelease];     
453}
454
455- (void)setToMountsOnly
456{
457        [self setListTitle:BRLocalizedString(@"Collections", @"")];
458        mountsOnly = YES;
459}
460
461- (SapphireImporterDataMenu *)allImporter
462{
463        SapphireXMLFileDataImporter *xmlImpr = [[SapphireXMLFileDataImporter alloc] init];
464        SapphireFileDataImporter *fileImp = [[SapphireFileDataImporter alloc] init];
465        SapphireTVShowImporter *tvImp = [[SapphireTVShowImporter alloc] initWithContext:moc];
466        SapphireMovieImporter *movImp = [[SapphireMovieImporter alloc] initWithContext:moc];
467        SapphireAllImporter *allImp = [[SapphireAllImporter alloc] initWithImporters:[NSArray arrayWithObjects:xmlImpr,tvImp,movImp,fileImp,nil]];
468        [xmlImpr release];
469        [fileImp release];
470        [tvImp release];
471        [movImp release];
472        SapphireImporterDataMenu *ret = [[SapphireImporterDataMenu alloc] initWithScene:[self scene] context:moc importer:allImp];
473        [allImp release];
474        return [ret autorelease];
475}
476
477- (SapphireSettings *)settings
478{
479        return settings;
480}
481
482- (void)setMenuFromSettings
483{
484        [names removeAllObjects];
485        [controllers removeAllObjects];
486        [names addObjectsFromArray:masterNames];
487        [controllers addObjectsFromArray:masterControllers];
488        NSMutableDictionary *dvds = [NSMutableDictionary dictionary];
489        NSEnumerator *dvdEnum = [[NSClassFromString(@"BRDiskArbHandler") mountedDVDs] objectEnumerator];
490        BRDiskInfo *dvdInfo;
491        while((dvdInfo = [dvdEnum nextObject]) != nil)
492        {
493                NSString *mountpoint = [dvdInfo mountpoint];
494                [dvds setObject:dvdInfo forKey:mountpoint];
495        }
496       
497        BRTexture *predicateGem = [SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]];
498        NSEnumerator *browserPointsEnum = [[SapphireCollectionDirectory availableCollectionDirectoriesInContext:moc] objectEnumerator];
499        SapphireCollectionDirectory *browserPoint = nil;
500        int index = 2;
501        if(mountsOnly)
502                index = 0;
503        while((browserPoint = [browserPointsEnum nextObject]) != nil)
504        {
505                if([browserPoint hiddenValue])
506                        continue;
507                id controller = nil;
508                if((dvdInfo = [dvds objectForKey:browserPoint]) != nil)
509                {
510                        BRDVDMediaAsset *asset = [BRDVDMediaAsset assetFromDiskInfo:dvdInfo];
511                        controller = [[SapphireDVDLoadingController alloc] initWithScene:[self scene] forAsset:asset];
512                }
513                else
514                {
515                        SapphireDirectoryMetaData *meta = [browserPoint directory];
516                        controller = [[SapphireBrowser alloc] initWithScene:[self scene] metaData:meta];
517                        [controller setListTitle:[NSString stringWithFormat:@" %@",[[meta path] lastPathComponent]]];
518                        [controller setListIcon:predicateGem];
519                }
520                if(controller != nil)
521                {
522                        [names insertObject:[NSString stringWithFormat:@"  %@", [browserPoint name]] atIndex:index];
523                        [controllers insertObject:controller atIndex:index];
524                        [controller release];
525                        index++;
526                }
527        }       
528       
529        if([settings disableUIQuit] && !mountsOnly)
530                [names removeLastObject];
531}
532
533- (void)completeRescanOfDir:(NSArray *)filePaths
534{
535        if(![filePaths count])
536                return;
537       
538        [SapphireMetaDataSupport save:moc];
539        NSString *dirPath = [[filePaths objectAtIndex:0] stringByDeletingLastPathComponent];
540        SapphireDirectoryMetaData *dir = [SapphireDirectoryMetaData directoryWithPath:dirPath inContext:moc];
541        [dir addImportFilePaths:filePaths];
542        [[dir delegate] directoryContentsChanged];
543        [dir resumeImport];
544}
545
546
547- (void)rescanDirectory:(NSString *)dirPath
548{
549        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
550        if(![[NSFileManager defaultManager] isDirectory:dirPath])
551        {
552                [pool release];
553                return;
554        }
555       
556        if(![dirPath isAbsolutePath])
557        {
558                [pool release];
559                return;
560        }
561       
562        dirPath = [dirPath stringByResolvingSymlinksInPath];
563       
564        NSManagedObjectContext *threadMoc = [SapphireApplianceController newManagedObjectContextForFile:nil];
565        SapphireDirectoryMetaData *dir = [SapphireDirectoryMetaData createDirectoryWithPath:dirPath inContext:threadMoc];
566        [dir reloadDirectoryContents];
567        NSArray *paths = [dir importFilePaths];
568        [SapphireMetaDataSupport applyChangesFromContext:threadMoc];
569        [threadMoc release];
570        [self performSelectorOnMainThread:@selector(completeRescanOfDir:) withObject:paths waitUntilDone:NO];
571        [pool drain];
572}
573
574- (void)doInitialPush
575{
576    // We've just been put on screen, the user can see this controller's content now
577    [self recreateMenu];
578        [[self list] reload];
579    // always call super
580    [super doInitialPush];
581}
582
583- (void)doInitialExhume
584{
585    // handle being revealed when the user presses Menu
586   
587        [self setMenuFromSettings];
588        [[self list] reload];
589        [SapphireFrontRowCompat renderScene:[self scene]];
590
591    // always call super
592    [super doInitialExhume];
593}
594
595- (long) itemCount
596{
597    // return the number of items in your menu list here
598        return ( [ names count]);
599}
600
601- (id<BRMenuItemLayer>) itemForRow: (long) row
602{
603/*
604    // build a BRTextMenuItemLayer or a BRAdornedMenuItemLayer, etc. here
605    // return that object, it will be used to display the list item.
606*/
607        if( row > [names count] ) return ( nil ) ;
608       
609        BRAdornedMenuItemLayer * result = nil ;
610        NSString *name = [names objectAtIndex:row];
611        result = [SapphireFrontRowCompat textMenuItemForScene:[self scene] folder:YES];
612       
613        SapphireTheme *theme = [SapphireTheme sharedTheme];
614        if([name isEqual: ALL_IMPORT_MENU_ITEM]) [SapphireFrontRowCompat setLeftIcon:[theme gem:IMPORT_GEM_KEY] forMenu:result];
615        else if([name isEqual: SETTINGS_MENU_ITEM]) [SapphireFrontRowCompat setLeftIcon:[theme gem:GEAR_GEM_KEY] forMenu:result];
616        else if([name isEqual: RESET_MENU_ITEM]) [SapphireFrontRowCompat setLeftIcon:[theme gem:FRONTROW_GEM_KEY] forMenu:result];
617        else if([name isEqual: @"  TV Shows"]) [SapphireFrontRowCompat setLeftIcon:[theme gem:TV_GEM_KEY] forMenu:result];
618        else if([name isEqual: @"  Movies"]) [SapphireFrontRowCompat setLeftIcon:[theme gem:MOV_GEM_KEY] forMenu:result];
619        else [SapphireFrontRowCompat setLeftIcon:[SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]] forMenu:result];
620       
621        // add text
622        [SapphireFrontRowCompat setTitle:name forMenu:result];
623                               
624        return ( result ) ;
625}
626
627- (NSString *) titleForRow: (long) row
628{
629
630        if ( row > [ names count] ) return ( nil );
631       
632        NSString *result = [ names objectAtIndex: row] ;
633        return ( result ) ;
634/*
635    // return the title for the list item at the given index here
636    return ( @"Sapphire" );
637*/
638}
639
640- (long) rowForTitle: (NSString *) title
641{
642    long result = -1;
643    long i, count = [self itemCount];
644    for ( i = 0; i < count; i++ )
645    {
646        if ( [title isEqualToString: [self titleForRow: i]] )
647        {
648            result = i;
649            break;
650        }
651    }
652   
653    return ( result );
654}
655
656- (void) itemSelected: (long) row
657{
658    // This is called when the user presses play/pause on a list item
659        if(row == [controllers count])
660                [[NSApplication sharedApplication] terminate:self];
661        id controller = [controllers objectAtIndex:row];
662       
663        // This if statement needs to be done in a much more elegant way
664        [[self stack] pushController:controller];
665}
666
667- (id<BRMediaPreviewController>) previewControlForItem:(long)item
668{
669        return [self previewControllerForItem:item];
670}
671
672- (id<BRMediaPreviewController>) previewControllerForItem: (long) item
673{
674    // If subclassing BRMediaMenuController, this function is called when the selection cursor
675    // passes over an item.
676    return ( nil );
677}
678
679- (BOOL)brEventAction:(BREvent *)event
680{
681        BREventPageUsageHash hashVal = (uint32_t)([event page] << 16 | [event usage]);
682        if ([(BRControllerStack *)[self stack] peekController] != self)
683                hashVal = 0;
684       
685        int row = [self getSelection];
686        if(row < [controllers count])
687        {
688                BRLayerController *controller = [controllers objectAtIndex:row];
689                id <SapphireDirectory> meta = nil;
690                if([controller isKindOfClass:[SapphireBrowser class]])
691                        meta = [(SapphireBrowser *)controller metaData];
692                switch (hashVal)
693                {
694                        case kBREventTapRight:
695                        {
696                                if(meta == nil)
697                                        break;
698                                /*Do mark menu*/
699                                SapphireMarkMenu *mark = [[SapphireMarkMenu alloc] initWithScene:[self scene] metaData:meta];
700                                [mark setListTitle:[names objectAtIndex:row]];
701                                [[self stack] pushController:mark];
702                                [mark release];
703                                return YES;
704                        }
705                        case kBREventTapLeft:
706                        {
707                                SapphireDisplayMenu *display = [[SapphireDisplayMenu alloc] initWithScene:[self scene] directory:meta];
708                                [display setListTitle:[names objectAtIndex:row]];
709                                [[self stack] pushController:display];
710                                [display release];
711                                return YES;
712                        }
713                }
714               
715        }
716        return [super brEventAction:event];
717}
718
719@end
720
721@implementation SapphireDistributedMessagesReceiver
722
723- (id)initWithController:(SapphireApplianceController *)cont
724{
725        self = [super init];
726        if(self == nil)
727                return nil;
728       
729        controller = cont;
730        NSPort *receivePort = [[NSSocketPort alloc] initWithTCPPort:DISTRIBUTED_MESSAGES_PORT];
731        rescanConnection = [[NSConnection alloc] initWithReceivePort:receivePort sendPort:nil];
732        [receivePort release];
733        [rescanConnection setRootObject:self];
734       
735        return self;
736}
737
738- (void) dealloc
739{
740        [rescanConnection release];
741        [super dealloc];
742}
743
744- (oneway void)rescanDirectory:(NSString *)dirPath
745{
746        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
747        [NSThread detachNewThreadSelector:@selector(rescanDirectory:) toTarget:controller withObject:dirPath];
748        [pool drain];
749}
750
751@end
Note: See TracBrowser for help on using the browser.