source: trunk/SapphireApplianceController.m @ 426

Revision 426, 15.4 KB checked in by gbooker, 6 years ago (diff)

Quit the helper when sapphire is released

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 "SapphireBrowser.h"
25#import "SapphireMetaData.h"
26#import "SapphirePredicates.h"
27#import "SapphireSettings.h"
28#import "SapphireTheme.h"
29#import "SapphireTVDirectory.h"
30#import "SapphireMovieDirectory.h"
31
32#import "SapphireImporterDataMenu.h"
33#import "SapphireFileDataImporter.h"
34#import "SapphireTVShowImporter.h"
35#import "SapphireMovieImporter.h"
36#import "SapphireAllImporter.h"
37#import "SapphireFrontRowCompat.h"
38#import "SapphireVirtualDirectoryLoading.h"
39#import "SapphireImportHelper.h"
40
41#define BROWSER_MENU_ITEM               BRLocalizedString(@"  Browse", @"Browser Menu Item")
42#define ALL_IMPORT_MENU_ITEM    BRLocalizedString(@"  Import All Data", @"All Importer Menu Item")
43#define SETTINGS_MENU_ITEM              BRLocalizedString(@"  Settings", @"Settings Menu Item")
44#define RESET_MENU_ITEM                 BRLocalizedString(@"  Reset the thing already", @"UI Quit")
45
46@interface SapphireApplianceController (private)
47- (void)setMenuFromSettings;
48- (void)recreateMenu;
49@end
50
51@implementation SapphireApplianceController
52
53static NSArray *predicates = nil;
54
55+ (void)initialize
56{
57        predicates = [[NSArray alloc] initWithObjects:[[SapphireUnwatchedPredicate alloc] init], [[SapphireFavoritePredicate alloc] init], [[SapphireTopShowPredicate alloc] init], nil];
58        [predicates makeObjectsPerformSelector:@selector(release)];
59        if([SapphireFrontRowCompat usingFrontRow])
60        {
61                NSString *myBundlePath = [[NSBundle bundleForClass:[self class]] bundlePath] ;
62                NSString *compatPath = [myBundlePath stringByAppendingString:@"/Contents/Frameworks/CompatClasses.framework"];
63                NSBundle *compat = [NSBundle bundleWithPath:compatPath];
64                [compat load];
65        }
66}
67
68+ (SapphirePredicate *)predicate
69{
70        SapphireSettings *settings = [SapphireSettings sharedSettings];
71        int index = [settings indexOfLastPredicate];
72        if(index == NSNotFound)
73                return nil;
74        return [predicates objectAtIndex:index];
75}
76
77+ (SapphirePredicate *)nextPredicate
78{
79        SapphireSettings *settings = [SapphireSettings sharedSettings];
80        int index = [settings indexOfLastPredicate];
81        int newIndex;
82        switch(index)
83        {
84                case NSNotFound:
85                        newIndex = 0;
86                        if([settings displayUnwatched])
87                                break;
88                case 0:
89                        newIndex = 1;
90                        if([settings displayFavorites])
91                                break;
92                case 1:
93                        newIndex = 2;
94                        if([settings displayTopShows])
95                                break;
96                default:
97                        newIndex = NSNotFound;
98        }
99        [settings setIndexOfLastPredicate:newIndex];
100        if(newIndex == NSNotFound)
101                return nil;
102        return [predicates objectAtIndex:newIndex];
103}
104
105+ (BRTexture *)gemForPredicate:(SapphirePredicate *)predicate
106{
107        SapphireTheme *theme = [SapphireTheme sharedTheme];
108        if(predicate == nil)
109                return [theme gem:RED_GEM_KEY];
110        if([predicate isKindOfClass:[SapphireUnwatchedPredicate class]])
111                return [theme gem:BLUE_GEM_KEY];
112        if([predicate isKindOfClass:[SapphireFavoritePredicate class]])
113                return [theme gem:YELLOW_GEM_KEY];
114        if([predicate isKindOfClass:[SapphireTopShowPredicate class]])
115                return [theme gem:GREEN_GEM_KEY];
116        return nil;
117}
118
119+ (void)logException:(NSException *)e
120{
121        NSMutableString *ret = [NSMutableString stringWithFormat:@"Exception:"];
122        if([e respondsToSelector:@selector(backtrace)])
123        {
124                [ret appendFormat:@"%@\n%@", e, [(BRBacktracingException *)e backtrace]];
125                Dl_info info;
126                if(dladdr(&predicates, &info))
127                        [ret appendFormat:@"Sapphire is at 0x%X", info.dli_fbase];
128        }
129        else
130        {
131                NSArray *addrs = [SapphireFrontRowCompat callStackReturnAddressesForException:e];
132                int i, count = [addrs count];
133                NSMutableDictionary *mapping = [NSMutableDictionary dictionary];
134                for(i=0; i<count; i++)
135                {
136                        Dl_info info;
137                        const void *addr = [[addrs objectAtIndex:i] pointerValue];
138                        if(dladdr(addr, &info))
139                                [mapping setObject:[NSString stringWithCString:info.dli_fname] forKey:[NSValue valueWithPointer:info.dli_fbase]];
140                        [ret appendFormat:@" 0x%X", addr];
141                }
142                NSEnumerator *mappingEnum = [mapping keyEnumerator];
143                NSValue *key = nil;
144                while((key = [mappingEnum nextObject]) != nil)
145                        [ret appendFormat:@"\n0x%X\t%@", [key pointerValue], [mapping objectForKey:key]];
146        }
147        NSLog(@"%@", ret);     
148}
149
150+ (NSString *) rootMenuLabel
151{
152        return (@"net.pmerrill.Sapphire" );
153}
154
155- (SapphireImporterDataMenu *)allImporterForCollection:(SapphireMetaDataCollection *)collection
156{
157        SapphireFileDataImporter *fileImp = [[SapphireFileDataImporter alloc] init];
158        SapphireTVShowImporter *tvImp = [[SapphireTVShowImporter alloc] initWithSavedSetting:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire/tvdata.plist"]];
159        SapphireMovieImporter *movImp = [[SapphireMovieImporter alloc] initWithSavedSetting:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire/movieData.plist"]];
160        SapphireAllImporter *allImp = [[SapphireAllImporter alloc] initWithImporters:[NSArray arrayWithObjects:tvImp,movImp,fileImp,nil]];
161        [fileImp release];
162        [tvImp release];
163        [movImp release];
164        SapphireImporterDataMenu *ret = [[SapphireImporterDataMenu alloc] initWithScene:[self scene] metaDataCollection:collection importer:allImp];
165        [allImp release];
166        return [ret autorelease];
167}
168
169- (id) initWithScene: (BRRenderScene *) scene
170{
171        self = [super initWithScene:scene];
172       
173        //Setup the theme's scene
174        SapphireTheme *theme = [SapphireTheme sharedTheme];
175        [theme setScene:[self scene]];
176       
177        metaCollection = [[SapphireMetaDataCollection alloc] initWithFile:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire/metaData.plist"]];
178       
179        settings                                                                = [[SapphireSettings alloc] initWithScene:[self scene] settingsPath:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire/settings.plist"] metaDataCollection:metaCollection] ;
180        [self setListTitle:                                             BRLocalizedString(@"Main Menu", @"")];
181        [settings setListTitle:                                 BRLocalizedString(@" Settings", @"Settings Menu Item")] ;
182        [settings setListIcon:                                  [theme gem:GEAR_GEM_KEY]];
183        [[self list] setDatasource:self];
184        if([SapphireFrontRowCompat usingFrontRow])
185        {
186                NSString *myBundlePath = [[NSBundle bundleForClass:[self class]] bundlePath] ;
187                NSString *onlyPath = [myBundlePath stringByAppendingPathComponent:@"/Contents/Frameworks/LeopardOnly.framework"];
188                NSBundle *only = [NSBundle bundleWithPath:onlyPath];
189                Class onlyClass = [only principalClass];
190                leoOnly = [[onlyClass alloc] initWithCollection:metaCollection];
191        }
192       
193        return self;
194}
195
196- (void)dealloc
197{
198        [leoOnly release];
199        [names release];
200        [controllers release];
201        [masterNames release];
202        [masterControllers release];
203        [metaCollection release];
204        [SapphireSettings relinquishSettings];
205        [settings release];
206        [SapphireImportHelper relinquishHelper];
207        [super dealloc];
208}
209
210- (void)recreateMenu
211{
212        SapphireImporterDataMenu *allImporter   = [self allImporterForCollection:metaCollection];
213        NSMutableArray *mutableMasterNames = [[NSMutableArray alloc] init];
214        NSMutableArray *mutableMasterControllers = [[NSMutableArray alloc] init];
215        BRTexture *predicateGem = [SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]];
216       
217        SapphireTVDirectory *tvDir = [[SapphireTVDirectory alloc] initWithCollection:metaCollection];
218        SapphireBrowser *tvBrowser = [[SapphireBrowser alloc] initWithScene:[self scene] metaData:tvDir];
219        [tvDir release];
220        [tvBrowser setListTitle:BRLocalizedString(@" TV Shows", nil)];
221        [tvBrowser setListIcon:predicateGem];
222        [mutableMasterNames addObject:BRLocalizedString(@"  TV Shows", nil)];
223        [mutableMasterControllers addObject:tvBrowser];
224//      [tvDir writeToFile:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire/virtualTVDir.plist"]];
225        [tvBrowser release];
226       
227        SapphireMovieDirectory *movieDir = [[SapphireMovieDirectory alloc] initWithCollection:metaCollection];
228        SapphireBrowser *movieBrowser = [[SapphireBrowser alloc] initWithScene:[self scene] metaData:movieDir];
229        [movieDir release];
230        [movieBrowser setListTitle:BRLocalizedString(@" Movies", nil)];
231        [movieBrowser setListIcon:predicateGem];
232        [mutableMasterNames addObject:BRLocalizedString(@"  Movies", nil)];
233        [mutableMasterControllers addObject:movieBrowser];
234//      [movieDir writeToFile:[NSHomeDirectory() stringByAppendingPathComponent:@"Library/Application Support/Sapphire/virtualMovieDir.plist"]];
235        [movieBrowser release];
236       
237        [[metaCollection directoryForPath:@"/"] loadMetaData];
238        [mutableMasterNames addObjectsFromArray:[NSArray arrayWithObjects:
239                ALL_IMPORT_MENU_ITEM,
240                SETTINGS_MENU_ITEM,
241                RESET_MENU_ITEM,
242                nil]];
243        [mutableMasterControllers addObjectsFromArray:[NSArray arrayWithObjects:
244                allImporter,
245                settings,
246                nil]];
247        masterNames = [[NSArray alloc] initWithArray:mutableMasterNames];
248        masterControllers = [[NSArray alloc] initWithArray:mutableMasterControllers];
249        [mutableMasterNames release];
250        [mutableMasterControllers release];
251       
252        names = [[NSMutableArray alloc] init];
253        controllers = [[NSMutableArray alloc] init];
254        [self setMenuFromSettings];
255}
256
257- (void)setMenuFromSettings
258{
259        [names removeAllObjects];
260        [controllers removeAllObjects];
261        [names addObjectsFromArray:masterNames];
262        [controllers addObjectsFromArray:masterControllers];
263       
264        BRTexture *predicateGem = [SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]];
265        NSEnumerator *browserPointsEnum = [[metaCollection collectionDirectories] objectEnumerator];
266        NSString *browserPoint = nil;
267        int index = 2;
268        while((browserPoint = [browserPointsEnum nextObject]) != nil)
269        {
270                if([metaCollection hideCollection:browserPoint])
271                        continue;
272                SapphireBrowser *browser = [[SapphireBrowser alloc] initWithScene:[self scene] metaData:[metaCollection directoryForPath:browserPoint]];
273                [browser setListTitle:[NSString stringWithFormat:@" %@",[browserPoint lastPathComponent]]];
274                [browser setListIcon:predicateGem];
275                [names insertObject:[NSString stringWithFormat:@"  %@", browserPoint] atIndex:index];
276                [controllers insertObject:browser atIndex:index];
277                [browser release];
278                index++;
279        }       
280       
281        if([settings disableUIQuit])
282                [names removeLastObject];
283}
284
285- (void) willBePushed
286{
287    // We're about to be placed on screen, but we're not yet there
288    [self recreateMenu];
289        [[self list] reload];
290    // always call super
291    [super willBePushed];
292}
293
294- (void) wasPushed
295{
296    // We've just been put on screen, the user can see this controller's content now
297   
298    // always call super
299    [super wasPushed];
300}
301
302- (void) willBePopped
303{
304    // The user pressed Menu, but we've not been removed from the screen yet
305   
306    // always call super
307    [super willBePopped];
308}
309
310- (void) wasPopped
311{
312    // The user pressed Menu, removing us from the screen
313   
314    // always call super
315    [super wasPopped];
316}
317
318- (void) willBeBuried
319{
320    // The user just chose an option, and we will be taken off the screen
321   
322    // always call super
323    [super willBeBuried];
324}
325
326- (void) wasBuriedByPushingController: (BRLayerController *) controller
327{
328    // The user chose an option and this controller os no longer on screen
329   
330    // always call super
331    [super wasBuriedByPushingController: controller];
332}
333
334- (void) willBeExhumed
335{
336    // the user pressed Menu, but we've not been revealed yet
337   
338    // always call super
339    [super willBeExhumed];
340        [self setMenuFromSettings];
341        [[self list] reload];
342        [SapphireFrontRowCompat renderScene:[self scene]];
343}
344
345- (void) wasExhumedByPoppingController: (BRLayerController *) controller
346{
347    // handle being revealed when the user presses Menu
348   
349    // always call super
350    [super wasExhumedByPoppingController: controller];
351}
352
353- (long) itemCount
354{
355    // return the number of items in your menu list here
356        return ( [ names count]);
357}
358
359- (id<BRMenuItemLayer>) itemForRow: (long) row
360{
361/*
362    // build a BRTextMenuItemLayer or a BRAdornedMenuItemLayer, etc. here
363    // return that object, it will be used to display the list item.
364*/
365        if( row > [names count] ) return ( nil ) ;
366       
367        BRAdornedMenuItemLayer * result = nil ;
368        NSString *name = [names objectAtIndex:row];
369        result = [SapphireFrontRowCompat textMenuItemForScene:[self scene] folder:YES];
370       
371        SapphireTheme *theme = [SapphireTheme sharedTheme];
372        if([name isEqual: ALL_IMPORT_MENU_ITEM]) [SapphireFrontRowCompat setLeftIcon:[theme gem:IMPORT_GEM_KEY] forMenu:result];
373        else if([name isEqual: SETTINGS_MENU_ITEM]) [SapphireFrontRowCompat setLeftIcon:[theme gem:GEAR_GEM_KEY] forMenu:result];
374        else if([name isEqual: RESET_MENU_ITEM]) [SapphireFrontRowCompat setLeftIcon:[theme gem:FRONTROW_GEM_KEY] forMenu:result];
375        else if([name isEqual: @"  TV Shows"]) [SapphireFrontRowCompat setLeftIcon:[theme gem:TV_GEM_KEY] forMenu:result];
376        else if([name isEqual: @"  Movies"]) [SapphireFrontRowCompat setLeftIcon:[theme gem:MOV_GEM_KEY] forMenu:result];
377        else [SapphireFrontRowCompat setLeftIcon:[SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]] forMenu:result];
378       
379        // add text
380        [SapphireFrontRowCompat setTitle:name forMenu:result];
381                               
382        return ( result ) ;
383}
384
385- (NSString *) titleForRow: (long) row
386{
387
388        if ( row > [ names count] ) return ( nil );
389       
390        NSString *result = [ names objectAtIndex: row] ;
391        return ( result ) ;
392/*
393    // return the title for the list item at the given index here
394    return ( @"Sapphire" );
395*/
396}
397
398- (long) rowForTitle: (NSString *) title
399{
400    long result = -1;
401    long i, count = [self itemCount];
402    for ( i = 0; i < count; i++ )
403    {
404        if ( [title isEqualToString: [self titleForRow: i]] )
405        {
406            result = i;
407            break;
408        }
409    }
410   
411    return ( result );
412}
413
414- (void) itemSelected: (long) row
415{
416    // This is called when the user presses play/pause on a list item
417        if(row == [controllers count])
418                [[NSApplication sharedApplication] terminate:self];
419        id controller = [controllers objectAtIndex:row];
420       
421        // This if statement needs to be done in a much more elegant way
422        if([controller isKindOfClass:[SapphireBrowser class]])
423        {
424                SapphireDirectoryMetaData *meta = [(SapphireBrowser *)controller metaData];
425                if([meta isKindOfClass:[SapphireVirtualDirectory class]])
426                {
427                        if(![(SapphireVirtualDirectory *)meta isLoaded])
428                        {
429                                SapphireVirtualDirectoryLoading *loader = [[SapphireVirtualDirectoryLoading alloc]
430                                                                                                                   initWithScene:[self scene]
431                                                                                                                   title:BRLocalizedString(@"Loading", @"Loading")
432                                                                                                                   text:BRLocalizedString(@"Virtual directory is still loading.\n  You may go back or wait for it to finish.", nil)
433                                                                                                                   showBack:YES];
434                                [loader setDirectory:(SapphireVirtualDirectory *)meta];
435                                [loader setBrowser:(SapphireBrowser *)controller];
436                                controller = loader;
437                        }
438                }
439        }
440        [[self stack] pushController:controller];
441}
442
443- (id<BRMediaPreviewController>) previewControllerForItem: (long) item
444{
445    // If subclassing BRMediaMenuController, this function is called when the selection cursor
446    // passes over an item.
447    return ( nil );
448}
449
450@end
Note: See TracBrowser for help on using the repository browser.