source: branches/CoreData/SapphireFrappliance/Browser/SapphireMarkMenu.m @ 636

Revision 636, 18.3 KB checked in by gbooker, 6 years ago (diff)

Correct an Apple bug just like [635]

Line 
1/*
2 * SapphireMarkMenu.m
3 * Sapphire
4 *
5 * Created by Graham Booker on Jun. 25, 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 "SapphireMarkMenu.h"
22#import "SapphireDirectoryMetaData.h"
23#import "SapphireCollectionDirectory.h"
24#import "SapphireFileMetaData.h"
25#import "SapphireJoinedFile.h"
26#import "SapphireMetaDataSupport.h"
27#import "SapphireMediaPreview.h"
28#import <SapphireCompatClasses/SapphireFrontRowCompat.h>
29#import <QTKit/QTKit.h>
30
31@implementation SapphireMarkMenu
32
33typedef enum {
34        COMMAND_TOGGLE_WATCHED,
35        COMMAND_TOGGLE_FAVORITE,
36        COMMAND_MARK_TO_REFETCH_TV,
37        COMMAND_MARK_TO_REFETCH_MOVIE,
38        COMMAND_MARK_TO_DELETE_METADATA,
39        COMMAND_MARK_TO_JOIN,
40        COMMAND_MARK_AND_JOIN,
41        COMMAND_CLEAR_JOIN_MARK,
42        COMMAND_JOIN,
43        //Directory commands
44        COMMAND_MARK_WATCHED,
45        COMMAND_MARK_UNWATCHED,
46        COMMAND_MARK_FAVORITE,
47        COMMAND_MARK_NOT_FAVORITE,
48        COMMAND_TOGGLE_SKIP,
49        COMMAND_TOGGLE_COLLECTION
50} MarkCommand;
51
52static NSMutableArray *joinList;
53
54+ (void)initialize
55{
56        joinList = [[NSMutableArray alloc] init];
57}
58
59- (id) initWithScene: (BRRenderScene *) scene metaData: (SapphireMetaData *)meta
60{
61        self = [super initWithScene:scene];
62        if(!self)
63                return nil;
64       
65        /*Check to see if it is directory or file*/
66        isDir = [meta conformsToProtocol:@protocol(SapphireDirectory)];
67        metaData = [meta retain];
68        commands = nil;
69        /*Create the menu*/
70        if(isDir)
71        {
72                names = [[NSMutableArray alloc] initWithObjects:
73                        BRLocalizedString(@"Mark All as Watched", @"Mark whole directory as watched"),
74                        BRLocalizedString(@"Mark All as Unwatched", @"Mark whole directory as unwatched"),
75                        BRLocalizedString(@"Mark All as Favorite", @"Mark whole directory as favorite"),
76                        BRLocalizedString(@"Mark All as Not Favorite", @"Mark whole directory as not favorite"),
77                        BRLocalizedString(@"Mark All to Refetch TV Data", @"Mark whole directory to re-fetch its tv data"),
78                        BRLocalizedString(@"Mark All to Refetch Movie Data", @"Mark whole directory to re-fetch its movie data"),
79                        BRLocalizedString(@"Mark All to Clear Metadata", @"Mark whole directory to delete the metadata"),
80                        nil];
81                markDescriptions = [[NSMutableArray alloc] initWithObjects:
82                        BRLocalizedString(@"Sapphire will save this directory as watched.", @"Mark directory watched description"),
83                        BRLocalizedString(@"Sapphire will save this directory as unwatched.", @"Mark directory as unwatched description"),
84                        BRLocalizedString(@"Sapphire will add this directory as favorite.", @"Mark directory as favorite description"),
85                        BRLocalizedString(@"Sapphire will remove this directory from favorites.", @"Mark directory as not favorite"),
86                        BRLocalizedString(@"Tells Sapphire to refetch TV Show metadata for this directory the next time an import is run.", @"Mark directory to refetch tv data description"),
87                        BRLocalizedString(@"Tells Sapphire to refetch Movie metadata for this directory the next time an import is run.", @"Mark whole directory to re-fetch its movie data"),
88                        BRLocalizedString(@"Tells Sapphire to remove all metadata for this directory.", @"Mark directory to delete metadata description"),
89                        nil];
90                commands = [[NSMutableArray alloc] initWithObjects:
91                                        [NSNumber numberWithInt:COMMAND_MARK_WATCHED],
92                                        [NSNumber numberWithInt:COMMAND_MARK_UNWATCHED],
93                                        [NSNumber numberWithInt:COMMAND_MARK_FAVORITE],
94                                        [NSNumber numberWithInt:COMMAND_MARK_NOT_FAVORITE],
95                                        [NSNumber numberWithInt:COMMAND_MARK_TO_REFETCH_TV],
96                                        [NSNumber numberWithInt:COMMAND_MARK_TO_REFETCH_MOVIE],
97                                        [NSNumber numberWithInt:COMMAND_MARK_TO_DELETE_METADATA],
98                                        nil];
99                id <SapphireDirectory> dirMeta = (id <SapphireDirectory>)meta;
100                if([dirMeta isKindOfClass:[SapphireDirectoryMetaData class]])
101                {
102                        SapphireCollectionDirectory *collection = [(SapphireDirectoryMetaData *)dirMeta collectionDirectory];
103                        if([collection skipValue])
104                        {
105                                [names addObject:BRLocalizedString(@"Mark Directory For Importing", @"Marks this directory to be no longer be skipped during import")];
106                                [markDescriptions addObject:BRLocalizedString(@"Tells Sapphire it's okay to import from this directory.", @"Mark Directory For Importing description")];
107                        }
108                        else
109                        {
110                                [names addObject:BRLocalizedString(@"Mark this Directory to Skip Import", @"Marks this directory to be skipped during import")];
111                                [markDescriptions addObject:BRLocalizedString(@"Tells Sapphire to skip this directory when importing.", @"Mark this Directory to Skip Import description")];
112                        }
113                        [commands addObject:[NSNumber numberWithInt:COMMAND_TOGGLE_SKIP]];
114                        if(![collection isMountValue])
115                        {
116                                if(collection != nil)
117                                {
118                                        [names addObject:BRLocalizedString(@"Mark this Directory to Not be a Collection", @"Marks the directory to no longer be a collection")];
119                                        [markDescriptions addObject:BRLocalizedString(@"Tells Sapphire to remove this directory from the Collections list.", @"Marks the directory to no longer be a collection description")];
120                                }
121                                else
122                                {
123                                        [names addObject:BRLocalizedString(@"Mark this Directory as a Collection", @"Marks the directory to be a collection")];
124                                        [markDescriptions addObject:BRLocalizedString(@"Tells Sapphire to add this directory to the Collections list.", @"Marks the directory to be a collection description")];
125                                }
126                                [commands addObject:[NSNumber numberWithInt:COMMAND_TOGGLE_COLLECTION]];
127                        }
128                }
129        }
130        else if([meta isKindOfClass:[SapphireFileMetaData class]])
131        {
132                SapphireFileMetaData *fileMeta = (SapphireFileMetaData *)metaData;
133                NSString *watched = nil;
134                NSString *watchedDesc = nil;
135                NSString *favorite = nil;
136                NSString *favoriteDesc = nil;
137               
138                if([fileMeta watchedValue])
139                {
140                        watched         = BRLocalizedString(@"Mark as Unwatched", @"Mark file as unwatched");
141                        watchedDesc = BRLocalizedString(@"Sapphire will save this file as unwatched.", @"Mark directory watched description");
142                }
143                else
144                {
145                        watched         = BRLocalizedString(@"Mark as Watched", @"Mark file as watched");
146                        watchedDesc = BRLocalizedString(@"Sapphire will save this file as watched.", @"Mark directory watched description");
147                }
148
149                if([fileMeta favoriteValue])
150                {
151                        favorite         = BRLocalizedString(@"Mark as Not Favorite", @"Mark file as a favorite");
152                        favoriteDesc = BRLocalizedString(@"Sapphire will remove this file from favorites.", @"Mark directory as not favorite");
153                }
154                else
155                {
156                        favorite         = BRLocalizedString(@"Mark as Favorite", @"Mark file as not a favorite");
157                        favoriteDesc = BRLocalizedString(@"Sapphire will add this file as a favorite.", @"Mark directory as favorite description");
158
159                }
160                names                    = [[NSMutableArray alloc] initWithObjects:watched, favorite, nil];
161                markDescriptions = [[NSMutableArray alloc] initWithObjects:watchedDesc, favoriteDesc, nil];
162                commands = [[NSMutableArray alloc] initWithObjects: [NSNumber numberWithInt:COMMAND_TOGGLE_WATCHED], [NSNumber numberWithInt:COMMAND_TOGGLE_FAVORITE], nil];
163                int importType = [fileMeta importTypeValue];
164                if(importType | IMPORT_TYPE_TVSHOW_MASK)
165                {
166                        [names addObject:BRLocalizedString(@"Mark to Refetch TV Data", @"Mark file to re-fetch its tv data")];
167                        [markDescriptions addObject:BRLocalizedString(@"Tells Sapphire to refetch TV Show metadata for this file the next time an import is run.", @"Mark file to refetch tv data description")];
168
169                        [commands addObject:[NSNumber numberWithInt:COMMAND_MARK_TO_REFETCH_TV]];
170                }
171                if(importType | IMPORT_TYPE_MOVIE_MASK)
172                {
173                        [names addObject:BRLocalizedString(@"Mark to Refetch Movie Data", @"Mark file to re-fetch its movie data")];
174                        [markDescriptions addObject:BRLocalizedString(@"Tells Sapphire to refetch Movie metadata for this file the next time an import is run.", @"Mark file to refetch movie description")];
175
176                        [commands addObject:[NSNumber numberWithInt:COMMAND_MARK_TO_REFETCH_MOVIE]];
177                }
178                if([fileMeta fileClass] != FILE_CLASS_UNKNOWN)
179                {
180                        [names addObject:BRLocalizedString(@"Mark to Clear Metadata", @"Mark a file to delete the metadata")];
181                        [markDescriptions addObject:BRLocalizedString(@"Tells Sapphire to remove all metadata for this file.", @"Mark file to delete metadata description")];
182
183                        [commands addObject:[NSNumber numberWithInt:COMMAND_MARK_TO_DELETE_METADATA]];
184                }
185                if(![joinList containsObject:fileMeta])
186                {
187                        [names addObject:BRLocalizedString(@"Mark This File to Be Joined", @"Mark This File to Be Joined")];
188                        [markDescriptions addObject:BRLocalizedString(@"Tells Sapphire you wish to add this file to a list of files to be joined. The files will be joined in the order they were added to the list.", @"Mark file to be joined description")];
189                        [commands addObject:[NSNumber numberWithInt:COMMAND_MARK_TO_JOIN]];
190                        [names addObject:BRLocalizedString(@"Mark This File and Join Group", @"Mark This File and Join Group")];
191                        [markDescriptions addObject:BRLocalizedString(@"Tells Sapphire to use this file to complete the joined list.", @"Mark file and join description")];
192                        [commands addObject:[NSNumber numberWithInt:COMMAND_MARK_AND_JOIN]];
193                }
194                if([joinList count])
195                {
196                        [names addObject:BRLocalizedString(@"Join Marked Files", @"Join Marked Files")];
197                        [markDescriptions addObject:BRLocalizedString(@"Tells Sapphire to complete the file join.", @"Join Marked Files description")];
198
199                        [commands addObject:[NSNumber numberWithInt:COMMAND_JOIN]];
200                        [names addObject:BRLocalizedString(@"Clear the Join List", @"Clear the Join List")];
201                        [markDescriptions addObject:BRLocalizedString(@"Tells Sapphire to clear the file join list.", @"clear file join list description")];
202
203                        [commands addObject:[NSNumber numberWithInt:COMMAND_CLEAR_JOIN_MARK]];
204                }
205        }
206        else
207        {
208                /*Neither, so just return nil*/
209                [self autorelease];
210                return nil;
211        }
212        [[self list] setDatasource:self];
213       
214        return self;
215}
216
217- (void) dealloc
218{
219        [commands release];
220        [names release];
221        [markDescriptions release];
222        [metaData release];
223        [names release];
224        [super dealloc];
225}
226
227- (void)doJoin
228{
229        if(![joinList count])
230                return;
231       
232        QTMovie *resultingMovie = [[QTMovie alloc] init];
233        [resultingMovie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute];
234       
235        NSString *savePath = [[joinList objectAtIndex:0] path];
236        BOOL hasmovExt = [[savePath pathExtension] isEqualToString:@"mov"];
237        NSString *base = [savePath stringByDeletingPathExtension];
238        if([[base lowercaseString] hasSuffix:@" part 1"])
239                base = [base substringToIndex:[base length] - 7];
240        if(hasmovExt)
241                savePath = [[base stringByAppendingString:@" Joined"] stringByAppendingPathExtension:@"mov"];
242        else
243                savePath = [base stringByAppendingPathExtension:@"mov"];
244
245        NSManagedObjectContext *moc = [[joinList objectAtIndex:0] managedObjectContext];
246        [SapphireFileMetaData createFileWithPath:savePath inContext:moc];
247        SapphireJoinedFile *joined = [SapphireJoinedFile joinedFileForPath:savePath inContext:moc];
248        int i, count=[joinList count];
249        for(i=0;i<count;i++)
250        {
251                SapphireFileMetaData *meta = [joinList objectAtIndex:i];
252                NSError *error = nil;
253                NSDictionary *openAttr = [NSDictionary dictionaryWithObjectsAndKeys:
254                                                                  [meta path], QTMovieFileNameAttribute,
255                                                                  [NSNumber numberWithBool:NO], QTMovieOpenAsyncOKAttribute,
256                                                                  nil];
257                QTMovie *current = [[QTMovie alloc] initWithAttributes:openAttr error:&error];
258                if(error == nil)
259                {
260                        QTTimeRange range;
261                        range.time = [current selectionStart];
262                        range.duration = [current duration];
263                        [current setSelection:range];
264                        [resultingMovie appendSelectionFromMovie:current];
265                        [meta setJoinedToFile:joined];
266                }
267                [current release];
268        }
269
270        [resultingMovie writeToFile:savePath withAttributes:[NSDictionary dictionary]];
271        [resultingMovie release];
272        [joinList removeAllObjects];
273        [SapphireMetaDataSupport save:moc];
274}
275
276- (void) willBePushed
277{
278    // We're about to be placed on screen, but we're not yet there
279   
280    // always call super
281    [super willBePushed];
282}
283
284- (void) wasPushed
285{
286    // We've just been put on screen, the user can see this controller's content now
287   
288    // always call super
289    [super wasPushed];
290}
291
292- (void) willBePopped
293{
294    // The user pressed Menu, but we've not been removed from the screen yet
295   
296    // always call super
297    [super willBePopped];
298}
299
300- (void) wasPopped
301{
302    // The user pressed Menu, removing us from the screen
303   
304    // always call super
305    [super wasPopped];
306}
307
308- (void) willBeBuried
309{
310    // The user just chose an option, and we will be taken off the screen
311   
312    // always call super
313    [super willBeBuried];
314}
315
316- (void) wasBuriedByPushingController: (BRLayerController *) controller
317{
318    // The user chose an option and this controller os no longer on screen
319   
320    // always call super
321    [super wasBuriedByPushingController: controller];
322}
323
324- (void) willBeExhumed
325{
326    // the user pressed Menu, but we've not been revealed yet
327   
328    // always call super
329    [super willBeExhumed];
330}
331
332- (void) wasExhumedByPoppingController: (BRLayerController *) controller
333{
334    // handle being revealed when the user presses Menu
335   
336    // always call super
337    [super wasExhumedByPoppingController: controller];
338}
339
340- (long) itemCount
341{
342    // return the number of items in your menu list here
343        return ( [ names count]);
344}
345
346- (id<BRMenuItemLayer>) itemForRow: (long) row
347{
348        /*
349         // build a BRTextMenuItemLayer or a BRAdornedMenuItemLayer, etc. here
350         // return that object, it will be used to display the list item.
351         return ( nil );
352         */
353        if( row >= [names count] ) return ( nil ) ;
354       
355        BRAdornedMenuItemLayer * result = nil ;
356        NSString *name = [names objectAtIndex:row];
357        result = [SapphireFrontRowCompat textMenuItemForScene:[self scene] folder:NO];
358       
359        // add text
360        [SapphireFrontRowCompat setTitle:name forMenu:result];
361                               
362        return ( result ) ;
363}
364
365- (NSString *) titleForRow: (long) row
366{
367       
368        if ( row >= [ names count] ) return ( nil );
369       
370        NSString *result = [ names objectAtIndex: row] ;
371        return ( result ) ;
372}
373
374- (long) rowForTitle: (NSString *) title
375{
376    long result = -1;
377    long i, count = [self itemCount];
378    for ( i = 0; i < count; i++ )
379    {
380        if ( [title isEqualToString: [self titleForRow: i]] )
381        {
382            result = i;
383            break;
384        }
385    }
386   
387    return ( result );
388}
389
390- (void) itemSelected: (long) row
391{
392    // This is called when the user presses play/pause on a list item
393        if(row >= [names count])
394                return;
395       
396        NSManagedObjectContext *moc = [metaData managedObjectContext];
397        /*Do action on dir or file*/
398        if(isDir)
399        {
400                id <SapphireDirectory> dirMeta = (id <SapphireDirectory>)metaData;
401                SapphireCollectionDirectory *collection = nil;
402                if([dirMeta isKindOfClass:[SapphireDirectoryMetaData class]])
403                        collection = [(SapphireDirectoryMetaData *)dirMeta collectionDirectory];
404                NSString *path = [dirMeta path];
405                switch([[commands objectAtIndex:row] intValue])
406                {
407                        case COMMAND_MARK_WATCHED:
408                                setSubtreeToWatched(dirMeta, YES);
409                                break;
410                        case COMMAND_MARK_UNWATCHED:
411                                setSubtreeToWatched(dirMeta, NO);
412                                break;
413                        case COMMAND_MARK_FAVORITE:
414                                setSubtreeToFavorite(dirMeta, YES);
415                                break;
416                        case COMMAND_MARK_NOT_FAVORITE:
417                                setSubtreeToFavorite(dirMeta, NO);
418                                break;
419                        case COMMAND_MARK_TO_REFETCH_TV:
420                                setSubtreeToReimportFromMask(dirMeta, IMPORT_TYPE_TVSHOW_MASK);
421                                break;
422                        case COMMAND_MARK_TO_REFETCH_MOVIE:
423                                setSubtreeToReimportFromMask(dirMeta, IMPORT_TYPE_MOVIE_MASK);
424                                break;
425                        case COMMAND_MARK_TO_DELETE_METADATA:
426                                setSubtreeToClearMetaData(dirMeta);
427                                break;
428                        case COMMAND_TOGGLE_SKIP:
429                                if(collection == nil)
430                                        collection = [SapphireCollectionDirectory collectionAtPath:path inContext:moc];
431                                [collection setSkipValue:![collection skipValue]];
432                                break;
433                        case COMMAND_TOGGLE_COLLECTION:
434                                if(collection == nil)
435                                        [SapphireCollectionDirectory collectionAtPath:path inContext:moc];
436                                else
437                                        [moc deleteObject:collection];
438                                break;
439                }
440        }
441        else
442        {
443                SapphireFileMetaData *fileMeta = (SapphireFileMetaData *)metaData;
444                switch([[commands objectAtIndex:row] intValue])
445                {
446                        case COMMAND_TOGGLE_WATCHED:
447                                [fileMeta setWatchedValue:![fileMeta watchedValue]];
448                                [fileMeta setResumeTime:0];
449                                break;
450                        case COMMAND_TOGGLE_FAVORITE:
451                                [fileMeta setFavoriteValue:![fileMeta favoriteValue]];
452                                break;
453                        case COMMAND_MARK_TO_REFETCH_TV:
454                                [fileMeta setToReimportFromMask:IMPORT_TYPE_TVSHOW_MASK];
455                                break;
456                        case COMMAND_MARK_TO_REFETCH_MOVIE:
457                                [fileMeta setToReimportFromMask:IMPORT_TYPE_MOVIE_MASK];
458                                break;
459                        case COMMAND_MARK_TO_DELETE_METADATA:
460                                [fileMeta clearMetaData];
461                                break;
462                        case COMMAND_MARK_TO_JOIN:
463                                [joinList addObject:fileMeta];
464                                break;
465                        case COMMAND_CLEAR_JOIN_MARK:
466                                [joinList removeAllObjects];
467                                break;
468                        case COMMAND_MARK_AND_JOIN:
469                                [joinList addObject:fileMeta];
470                        case COMMAND_JOIN:
471                                [self doJoin];
472                                break;
473                }
474        }
475        /*Save and exit*/
476        [SapphireMetaDataSupport save:moc];
477        [[self stack] popController];
478}
479
480- (id<BRMediaPreviewController>) previewControlForItem:(long)item
481{
482        return [self previewControllerForItem:item];
483}
484
485- (id<BRMediaPreviewController>) previewControllerForItem: (long) item
486{
487    // If subclassing BRMediaMenuController, this function is called when the selection cursor
488    // passes over an item.
489                if(item >= [names count])
490                return nil;
491        else
492        {
493                /* Get setting name & kill cushion  */
494                NSString *markName =[NSString stringWithFormat:@"%@ for \"%@\"",[names objectAtIndex:item],(NSString *)[self listTitle]];
495                NSString *markDescription=[markDescriptions objectAtIndex:item];
496                /* Construct a gerneric metadata asset for display */
497                NSMutableDictionary *markMeta=[[NSMutableDictionary alloc] init];
498                [markMeta setObject:markName forKey:META_TITLE_KEY];
499                [markMeta setObject:[NSNumber numberWithInt:FILE_CLASS_UTILITY] forKey:FILE_CLASS_KEY];
500                [markMeta setObject:markDescription forKey:META_DESCRIPTION_KEY];
501                SapphireMediaPreview *preview = [[SapphireMediaPreview alloc] initWithScene:[self scene]];
502                [preview setUtilityData:markMeta];
503                [preview setShowsMetadataImmediately:YES];
504                /*And go*/
505                return [preview autorelease];
506        }
507    return ( nil );
508}
509
510@end
Note: See TracBrowser for help on using the repository browser.