root/trunk/SapphireFrappliance/FRAppliance/SapphireApplianceController.m @ 1088

Revision 1088, 23.5 KB (checked in by gbooker, 8 months ago)

The metadata store seems to be stable enough there's no need to log this anymore.

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