source: branches/CoreData/SapphireFrappliance/FRAppliance/SapphireApplianceController.m @ 608

Revision 608, 18.7 KB checked in by gbooker, 6 years ago (diff)

Added some debug info for later use
Correctly delete non-existing files/directories
When scanning directories, clear the filter predicate

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 "SapphireXMLFileDataImporter.h"
35#import "SapphireFileDataImporter.h"
36#import "SapphireTVShowImporter.h"
37#import "SapphireMovieImporter.h"
38#import "SapphireAllImporter.h"
39#import "SapphireImportHelper.h"
40#import "SapphireMetaDataSupport.h"
41#import "SapphireEntityDirectory.h"
42#import "SapphireTVShow.h"
43#import "SapphireMovieDirectory.h"
44
45NSString *SAPPHIRE_MANAGED_OBJECT_CONTEXT_CLOSING =     @"SapphireManagedObjectContextClosing";
46
47#define BROWSER_MENU_ITEM               BRLocalizedString(@"  Browse", @"Browser Menu Item")
48#define ALL_IMPORT_MENU_ITEM    BRLocalizedString(@"  Import All Data", @"All Importer Menu Item")
49#define SETTINGS_MENU_ITEM              BRLocalizedString(@"  Settings", @"Settings Menu Item")
50#define RESET_MENU_ITEM                 BRLocalizedString(@"  Reset the thing already", @"UI Quit")
51
52@interface SapphireApplianceController (private)
53- (void)setMenuFromSettings;
54- (void)recreateMenu;
55@end
56
57@implementation SapphireApplianceController
58
59static NSArray *predicates = nil;
60
61NSPredicate *unwatched = nil;
62NSPredicate *favorite = nil;
63NSPredicate *skipJoin = nil;
64NSPredicate *strictUnwatched = nil;
65NSPredicate *strictFavorite = nil;
66
67+ (void)initialize
68{
69        skipJoin = [[NSPredicate predicateWithFormat:@"joinedToFile == nil"] retain];
70        unwatched = [[NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:[NSPredicate predicateWithFormat:@"watched == NO"], skipJoin, nil]] retain];
71        favorite = [[NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:[NSPredicate predicateWithFormat:@"favorite == YES"], skipJoin, nil]] retain];
72//      NSPredicate *topShows = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:[NSPredicate predicateWithFormat:@"top == YES"], skipJoin, nil]];
73        predicates = [[NSArray alloc] initWithObjects:unwatched, favorite/*, topShows*/, nil];
74        strictUnwatched = [[NSPredicate predicateWithFormat:@"watched == NO"] retain];
75        strictFavorite = [[NSPredicate predicateWithFormat:@"favorite == YES"] retain];
76}
77
78+ (NSPredicate *)predicate
79{
80        SapphireSettings *settings = [SapphireSettings sharedSettings];
81        int index = [settings indexOfLastPredicate];
82        if(index == NSNotFound)
83                return skipJoin;
84        return [predicates objectAtIndex:index];
85}
86
87+ (NSPredicate *)nextPredicate
88{
89        SapphireSettings *settings = [SapphireSettings sharedSettings];
90        int index = [settings indexOfLastPredicate];
91        int newIndex;
92        switch(index)
93        {
94                case NSNotFound:
95                        newIndex = 0;
96                        if([settings displayUnwatched])
97                                break;
98                case 0:
99                        newIndex = 1;
100                        if([settings displayFavorites])
101                                break;
102//              case 1:
103//                      newIndex = 2;
104//                      if([settings displayTopShows])
105//                              break;
106                default:
107                        newIndex = NSNotFound;
108        }
109        [settings setIndexOfLastPredicate:newIndex];
110        if(newIndex == NSNotFound)
111                return skipJoin;
112        return [predicates objectAtIndex:newIndex];
113}
114
115+ (PredicateType)predicateType
116{
117        return [[SapphireSettings sharedSettings] indexOfLastPredicate];
118}
119
120+ (void)setPredicateType:(PredicateType)type
121{
122        [[SapphireSettings sharedSettings] setIndexOfLastPredicate:type];
123}
124
125+ (NSPredicate *)unfilteredPredicate
126{
127        return skipJoin;
128}
129
130+ (NSPredicate *)unwatchedPredicate
131{
132        return strictUnwatched;
133}
134
135+ (NSPredicate *)favoritePredicate
136{
137        return strictFavorite;
138}
139
140+ (BRTexture *)gemForPredicate:(NSPredicate *)predicate
141{
142        SapphireTheme *theme = [SapphireTheme sharedTheme];
143        if(predicate == nil)
144                return [theme gem:RED_GEM_KEY];
145        int index = [predicates indexOfObject:predicate];
146        switch (index) {
147                case 0:
148                        return [theme gem:BLUE_GEM_KEY];
149                case 1:
150                        return [theme gem:YELLOW_GEM_KEY];
151                case 2:
152                        return [theme gem:GREEN_GEM_KEY];
153        }
154        return [theme gem:RED_GEM_KEY];
155}
156
157+ (NSString *)keyForFilterPredicate:(NSPredicate *)filter andCheckPredicate:(NSPredicate *)check
158{
159        int found = 0;
160        if(filter == skipJoin)
161                found = 1;
162        else if (filter == unwatched)
163                found = 2;
164        else if (filter == favorite)
165                found = 4;
166        else if (filter != nil)
167                return [[filter description] stringByAppendingString:[check description]];
168       
169        if(check == strictUnwatched)
170                found |= 2;
171        else if (check == strictFavorite)
172                found |= 4;
173        else if (check != nil)
174                return [[filter description] stringByAppendingString:[check description]];
175       
176        switch (found) {
177                case 0:
178                        return @"nil";
179                case 1:
180                        return @"S";
181                case 2:
182                        return @"W";
183                case 3:
184                        return @"SW";
185                case 4:
186                        return @"F";
187                case 5:
188                        return @"SF";
189                case 6:
190                        return @"WF";
191                case 7:
192                        return @"SWF";
193        }
194        return nil;
195}
196
197+ (void)logException:(NSException *)e
198{
199        NSMutableString *ret = [NSMutableString stringWithFormat:@"Exception: %@ %@\n", [e name], [e reason]];
200        if([e respondsToSelector:@selector(backtrace)])
201        {
202                [ret appendFormat:@"%@\n%@", e, [(BRBacktracingException *)e backtrace]];
203                Dl_info info;
204                if(dladdr(&predicates, &info))
205                        [ret appendFormat:@"Sapphire is at 0x%X", info.dli_fbase];
206        }
207        else
208        {
209                NSArray *addrs = [SapphireFrontRowCompat callStackReturnAddressesForException:e];
210                int i, count = [addrs count];
211                NSMutableDictionary *mapping = [NSMutableDictionary dictionary];
212                for(i=0; i<count; i++)
213                {
214                        Dl_info info;
215                        const void *addr = [[addrs objectAtIndex:i] pointerValue];
216                        if(dladdr(addr, &info))
217                                [mapping setObject:[NSString stringWithCString:info.dli_fname] forKey:[NSValue valueWithPointer:info.dli_fbase]];
218                        [ret appendFormat:@" 0x%X", addr];
219                }
220                NSEnumerator *mappingEnum = [mapping keyEnumerator];
221                NSValue *key = nil;
222                while((key = [mappingEnum nextObject]) != nil)
223                        [ret appendFormat:@"\n0x%X\t%@", [key pointerValue], [mapping objectForKey:key]];
224        }
225        NSLog(@"%@", ret);     
226}
227
228+ (NSString *) rootMenuLabel
229{
230        return (@"net.pmerrill.Sapphire" );
231}
232
233+ (BOOL)upgradeNeeded
234{
235        NSFileManager *fm = [NSFileManager defaultManager];
236        NSString *storeFile = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire/metaData.sapphireData"];
237        BOOL exists = [fm fileExistsAtPath:storeFile];
238        NSString *plistFile = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire/metaData.plist"];
239        BOOL oldExists = [fm fileExistsAtPath:plistFile];
240        return !exists && oldExists;
241}
242
243- (id) initWithScene: (BRRenderScene *) scene
244{
245        self = [super initWithScene:scene];
246       
247        //Setup the theme's scene
248        SapphireTheme *theme = [SapphireTheme sharedTheme];
249        [theme setScene:[self scene]];
250       
251        NSString *storeFile = [NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire/metaData.sapphireData"];
252        moc = [[NSManagedObjectContext alloc] init];
253        [moc setUndoManager:nil];
254        NSString *mopath = [[NSBundle bundleForClass:[self class]] pathForResource:@"Sapphire" ofType:@"mom"];
255        NSURL *mourl = [NSURL fileURLWithPath:mopath];
256        NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:mourl];
257        NSPersistentStoreCoordinator *coord = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:model];
258        [moc setPersistentStoreCoordinator:coord];
259        [coord release];
260       
261        NSURL *storeUrl = [NSURL fileURLWithPath:storeFile];
262        NSError *error = nil;
263        [coord addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:nil error:&error];
264        [SapphireDirectoryMetaData createDirectoryWithPath:@"/" parent:nil inContext:moc];
265       
266        settings                                                                = [[SapphireSettings alloc] initWithScene:[self scene] settingsPath:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire/settings.plist"] context:moc];
267        [self setListTitle:                                             BRLocalizedString(@"Main Menu", @"")];
268        [settings setListTitle:                                 BRLocalizedString(@" Settings", @"Settings Menu Item")] ;
269        [settings setListIcon:                                  [theme gem:GEAR_GEM_KEY]];
270        [[self list] setDatasource:self];
271        if([SapphireFrontRowCompat usingFrontRow] && ![SapphireFrontRowCompat usingTakeTwo])
272        {
273                NSString *myBundlePath = [[NSBundle bundleForClass:[self class]] bundlePath] ;
274                NSString *onlyPath = [myBundlePath stringByAppendingPathComponent:@"/Contents/Frameworks/LeopardOnly.framework"];
275                NSBundle *only = [NSBundle bundleWithPath:onlyPath];
276                Class onlyClass = [only principalClass];
277                leoOnly = [[onlyClass alloc] initWithContext:moc];
278        }
279        mountsOnly = NO;
280       
281        return self;
282}
283
284- (void)dealloc
285{
286        [leoOnly release];
287        [names release];
288        [controllers release];
289        [masterNames release];
290        [masterControllers release];
291        [moc release];
292        [SapphireSettings relinquishSettings];
293        [settings release];
294        [SapphireImportHelper relinquishHelper];
295        [super dealloc];
296}
297
298- (void)recreateMenu
299{
300        names = [[NSMutableArray alloc] init];
301        controllers = [[NSMutableArray alloc] init];
302        if(mountsOnly)
303        {
304                masterNames = [[NSArray alloc] init];
305                masterControllers = [[NSArray alloc] init];
306        }
307        else
308        {
309                SapphireImporterDataMenu *allImporter   = [self allImporter];
310                NSMutableArray *mutableMasterNames = [[NSMutableArray alloc] init];
311                NSMutableArray *mutableMasterControllers = [[NSMutableArray alloc] init];
312               
313                SapphireBrowser *tvBrowser = [self tvBrowser];
314                [mutableMasterNames addObject:BRLocalizedString(@"  TV Shows", nil)];
315                [mutableMasterControllers addObject:tvBrowser];
316               
317                SapphireBrowser *movieBrowser = [self movieBrowser];
318                [mutableMasterNames addObject:BRLocalizedString(@"  Movies", nil)];
319                [mutableMasterControllers addObject:movieBrowser];
320               
321                [mutableMasterNames addObjectsFromArray:[NSArray arrayWithObjects:
322                                                                                                 ALL_IMPORT_MENU_ITEM,
323                                                                                                 SETTINGS_MENU_ITEM,
324                                                                                                 RESET_MENU_ITEM,
325                                                                                                 nil]];
326                [mutableMasterControllers addObjectsFromArray:[NSArray arrayWithObjects:
327                                                                                                           allImporter,
328                                                                                                           settings,
329                                                                                                           nil]];
330                masterNames = [[NSArray alloc] initWithArray:mutableMasterNames];
331                masterControllers = [[NSArray alloc] initWithArray:mutableMasterControllers];
332                [mutableMasterNames release];
333                [mutableMasterControllers release];             
334        }
335        [self setMenuFromSettings];
336}
337
338- (SapphireBrowser *)tvBrowser
339{
340        BRTexture *predicateGem = [SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]];
341        SapphireEntityDirectory *tvDir = [[SapphireEntityDirectory alloc] initWithEntityName:SapphireTVShowName usingFilter:nil inContext:moc];
342        [tvDir setMetaFileFetchPredicate:[NSPredicate predicateWithFormat:@"tvEpisode != nil"]];
343        SapphireBrowser *tvBrowser = [[SapphireBrowser alloc] initWithScene:[self scene] metaData:tvDir];
344        [tvDir release];
345        [tvBrowser setListTitle:BRLocalizedString(@" TV Shows", nil)];
346        [tvBrowser setListIcon:predicateGem];
347        return [tvBrowser autorelease];
348}
349
350- (SapphireBrowser *)movieBrowser
351{
352        BRTexture *predicateGem = [SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]];
353        SapphireMovieDirectory *movieDir = [[SapphireMovieDirectory alloc] initWithContext:moc];
354        SapphireBrowser *movieBrowser = [[SapphireBrowser alloc] initWithScene:[self scene] metaData:movieDir];
355        [movieDir release];
356        [movieBrowser setListTitle:BRLocalizedString(@" Movies", nil)];
357        [movieBrowser setListIcon:predicateGem];
358        return [movieBrowser autorelease];     
359}
360
361- (void)setToMountsOnly
362{
363        [self setListTitle:BRLocalizedString(@"Collections", @"")];
364        mountsOnly = YES;
365}
366
367- (SapphireImporterDataMenu *)allImporter
368{
369        SapphireXMLFileDataImporter *xmlImpr = [[SapphireXMLFileDataImporter alloc] init];
370        SapphireFileDataImporter *fileImp = [[SapphireFileDataImporter alloc] init];
371        SapphireTVShowImporter *tvImp = [[SapphireTVShowImporter alloc] initWithContext:moc];
372        SapphireMovieImporter *movImp = [[SapphireMovieImporter alloc] initWithContext:moc];
373        SapphireAllImporter *allImp = [[SapphireAllImporter alloc] initWithImporters:[NSArray arrayWithObjects:xmlImpr,tvImp,movImp,fileImp,nil]];
374        [xmlImpr release];
375        [fileImp release];
376        [tvImp release];
377        [movImp release];
378        SapphireImporterDataMenu *ret = [[SapphireImporterDataMenu alloc] initWithScene:[self scene] context:moc importer:allImp];
379        [allImp release];
380        return [ret autorelease];
381}
382
383- (SapphireSettings *)settings
384{
385        return settings;
386}
387
388- (void)setMenuFromSettings
389{
390        [names removeAllObjects];
391        [controllers removeAllObjects];
392        [names addObjectsFromArray:masterNames];
393        [controllers addObjectsFromArray:masterControllers];
394        NSMutableDictionary *dvds = [NSMutableDictionary dictionary];
395        NSEnumerator *dvdEnum = [[NSClassFromString(@"BRDiskArbHandler") mountedDVDs] objectEnumerator];
396        BRDiskInfo *dvdInfo;
397        while((dvdInfo = [dvdEnum nextObject]) != nil)
398        {
399                NSString *mountpoint = [dvdInfo mountpoint];
400                [dvds setObject:dvdInfo forKey:mountpoint];
401        }
402       
403        BRTexture *predicateGem = [SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]];
404        NSEnumerator *browserPointsEnum = [[SapphireCollectionDirectory availableCollectionDirectoriesInContext:moc] objectEnumerator];
405        SapphireCollectionDirectory *browserPoint = nil;
406        int index = 2;
407        if(mountsOnly)
408                index = 0;
409        while((browserPoint = [browserPointsEnum nextObject]) != nil)
410        {
411                if([browserPoint hiddenValue])
412                        continue;
413                id controller = nil;
414                if((dvdInfo = [dvds objectForKey:browserPoint]) != nil)
415                {
416                        BRDVDMediaAsset *asset = [BRDVDMediaAsset assetFromDiskInfo:dvdInfo];
417                        controller = [[SapphireDVDLoadingController alloc] initWithScene:[self scene] forAsset:asset];
418                        [controller retain];
419                }
420                else
421                {
422                        SapphireDirectoryMetaData *meta = [browserPoint directory];
423                        controller = [[SapphireBrowser alloc] initWithScene:[self scene] metaData:meta];
424                        [controller setListTitle:[NSString stringWithFormat:@" %@",[[meta path] lastPathComponent]]];
425                        [controller setListIcon:predicateGem];
426                }
427                if(controller != nil)
428                {
429                        [names insertObject:[NSString stringWithFormat:@"  %@", [[browserPoint directory] path]] atIndex:index];
430                        [controllers insertObject:controller atIndex:index];
431                        [controller release];
432                        index++;
433                }
434        }       
435       
436        if([settings disableUIQuit] && !mountsOnly)
437                [names removeLastObject];
438}
439
440- (void) willBePushed
441{
442    // We're about to be placed on screen, but we're not yet there
443    [self recreateMenu];
444        [[self list] reload];
445    // always call super
446    [super willBePushed];
447}
448
449- (void) wasPushed
450{
451    // We've just been put on screen, the user can see this controller's content now
452   
453    // always call super
454    [super wasPushed];
455}
456
457- (void) willBePopped
458{
459    // The user pressed Menu, but we've not been removed from the screen yet
460   
461    // always call super
462    [super willBePopped];
463}
464
465- (void) wasPopped
466{
467    // The user pressed Menu, removing us from the screen
468   
469    // always call super
470    [super wasPopped];
471}
472
473- (void) willBeBuried
474{
475    // The user just chose an option, and we will be taken off the screen
476   
477    // always call super
478    [super willBeBuried];
479}
480
481- (void) wasBuriedByPushingController: (BRLayerController *) controller
482{
483    // The user chose an option and this controller os no longer on screen
484   
485    // always call super
486    [super wasBuriedByPushingController: controller];
487}
488
489- (void) willBeExhumed
490{
491    // the user pressed Menu, but we've not been revealed yet
492   
493    // always call super
494    [super willBeExhumed];
495        [self setMenuFromSettings];
496        [[self list] reload];
497        [SapphireFrontRowCompat renderScene:[self scene]];
498}
499
500- (void) wasExhumedByPoppingController: (BRLayerController *) controller
501{
502    // handle being revealed when the user presses Menu
503   
504    // always call super
505    [super wasExhumedByPoppingController: controller];
506}
507
508- (long) itemCount
509{
510    // return the number of items in your menu list here
511        return ( [ names count]);
512}
513
514- (id<BRMenuItemLayer>) itemForRow: (long) row
515{
516/*
517    // build a BRTextMenuItemLayer or a BRAdornedMenuItemLayer, etc. here
518    // return that object, it will be used to display the list item.
519*/
520        if( row > [names count] ) return ( nil ) ;
521       
522        BRAdornedMenuItemLayer * result = nil ;
523        NSString *name = [names objectAtIndex:row];
524        result = [SapphireFrontRowCompat textMenuItemForScene:[self scene] folder:YES];
525       
526        SapphireTheme *theme = [SapphireTheme sharedTheme];
527        if([name isEqual: ALL_IMPORT_MENU_ITEM]) [SapphireFrontRowCompat setLeftIcon:[theme gem:IMPORT_GEM_KEY] forMenu:result];
528        else if([name isEqual: SETTINGS_MENU_ITEM]) [SapphireFrontRowCompat setLeftIcon:[theme gem:GEAR_GEM_KEY] forMenu:result];
529        else if([name isEqual: RESET_MENU_ITEM]) [SapphireFrontRowCompat setLeftIcon:[theme gem:FRONTROW_GEM_KEY] forMenu:result];
530        else if([name isEqual: @"  TV Shows"]) [SapphireFrontRowCompat setLeftIcon:[theme gem:TV_GEM_KEY] forMenu:result];
531        else if([name isEqual: @"  Movies"]) [SapphireFrontRowCompat setLeftIcon:[theme gem:MOV_GEM_KEY] forMenu:result];
532        else [SapphireFrontRowCompat setLeftIcon:[SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]] forMenu:result];
533       
534        // add text
535        [SapphireFrontRowCompat setTitle:name forMenu:result];
536                               
537        return ( result ) ;
538}
539
540- (NSString *) titleForRow: (long) row
541{
542
543        if ( row > [ names count] ) return ( nil );
544       
545        NSString *result = [ names objectAtIndex: row] ;
546        return ( result ) ;
547/*
548    // return the title for the list item at the given index here
549    return ( @"Sapphire" );
550*/
551}
552
553- (long) rowForTitle: (NSString *) title
554{
555    long result = -1;
556    long i, count = [self itemCount];
557    for ( i = 0; i < count; i++ )
558    {
559        if ( [title isEqualToString: [self titleForRow: i]] )
560        {
561            result = i;
562            break;
563        }
564    }
565   
566    return ( result );
567}
568
569- (void) itemSelected: (long) row
570{
571    // This is called when the user presses play/pause on a list item
572        if(row == [controllers count])
573                [[NSApplication sharedApplication] terminate:self];
574        id controller = [controllers objectAtIndex:row];
575       
576        // This if statement needs to be done in a much more elegant way
577        [[self stack] pushController:controller];
578}
579
580- (id<BRMediaPreviewController>) previewControllerForItem: (long) item
581{
582    // If subclassing BRMediaMenuController, this function is called when the selection cursor
583    // passes over an item.
584    return ( nil );
585}
586
587@end
Note: See TracBrowser for help on using the repository browser.