### Eclipse Workspace Patch 1.0 #P sapphire-svn Index: branches/CoreData/SapphireFrappliance/Sapphire.xcodeproj/project.pbxproj =================================================================== --- branches/CoreData/SapphireFrappliance/Sapphire.xcodeproj/project.pbxproj (revision 920) +++ branches/CoreData/SapphireFrappliance/Sapphire.xcodeproj/project.pbxproj (working copy) @@ -53,6 +53,8 @@ 38FAF9B60C0129E400853CFE /* BackRow.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38FAF9B50C0129E400853CFE /* BackRow.framework */; }; 38FAFC320C012A7800853CFE /* SapphireAppliance.m in Sources */ = {isa = PBXBuildFile; fileRef = 38FAFC2F0C012A7800853CFE /* SapphireAppliance.m */; }; 38FAFC330C012A7800853CFE /* SapphireBrowser.m in Sources */ = {isa = PBXBuildFile; fileRef = 38FAFC310C012A7800853CFE /* SapphireBrowser.m */; }; + 5941C04710786EB2004C887B /* SapphireMovieVirtualDirectory.m in Sources */ = {isa = PBXBuildFile; fileRef = 5941C03A10786DD5004C887B /* SapphireMovieVirtualDirectory.m */; }; + 5941C04810786ECA004C887B /* SapphireMovieVirtualDirectoryImporter.m in Sources */ = {isa = PBXBuildFile; fileRef = 5941C03C10786DD5004C887B /* SapphireMovieVirtualDirectoryImporter.m */; }; 805420AA0F94FA7E002D2DBF /* NSImage-Extensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 805420A90F94FA7E002D2DBF /* NSImage-Extensions.m */; }; 8D5B49B0048680CD000E48DA /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; }; F500400B0D1998B4003FEA08 /* SapphireLeopardOnly.h in Headers */ = {isa = PBXBuildFile; fileRef = F50040090D1998B4003FEA08 /* SapphireLeopardOnly.h */; }; @@ -360,6 +362,10 @@ 38FAFC2F0C012A7800853CFE /* SapphireAppliance.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = SapphireAppliance.m; sourceTree = ""; }; 38FAFC300C012A7800853CFE /* SapphireAppliance.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SapphireAppliance.h; sourceTree = ""; }; 38FAFC310C012A7800853CFE /* SapphireBrowser.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = SapphireBrowser.m; sourceTree = ""; }; + 5941C03910786DD5004C887B /* SapphireMovieVirtualDirectory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SapphireMovieVirtualDirectory.h; sourceTree = ""; }; + 5941C03A10786DD5004C887B /* SapphireMovieVirtualDirectory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SapphireMovieVirtualDirectory.m; sourceTree = ""; }; + 5941C03B10786DD5004C887B /* SapphireMovieVirtualDirectoryImporter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SapphireMovieVirtualDirectoryImporter.h; sourceTree = ""; }; + 5941C03C10786DD5004C887B /* SapphireMovieVirtualDirectoryImporter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SapphireMovieVirtualDirectoryImporter.m; sourceTree = ""; }; 805420A80F94FA7E002D2DBF /* NSImage-Extensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSImage-Extensions.h"; sourceTree = ""; }; 805420A90F94FA7E002D2DBF /* NSImage-Extensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSImage-Extensions.m"; sourceTree = ""; }; 8D5B49B6048680CD000E48DA /* Sapphire.frappliance */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Sapphire.frappliance; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -993,6 +999,10 @@ F5C55E9E0DE90F0D00661563 /* Support */ = { isa = PBXGroup; children = ( + 5941C03910786DD5004C887B /* SapphireMovieVirtualDirectory.h */, + 5941C03A10786DD5004C887B /* SapphireMovieVirtualDirectory.m */, + 5941C03B10786DD5004C887B /* SapphireMovieVirtualDirectoryImporter.h */, + 5941C03C10786DD5004C887B /* SapphireMovieVirtualDirectoryImporter.m */, F5C55EC20DE90F3900661563 /* CoreDataSupportFunctions.h */, F5C55EC30DE90F3900661563 /* CoreDataSupportFunctions.m */, F5C55EC50DE90F7000661563 /* SapphireBasicDirectoryFunctions.h */, @@ -1381,6 +1391,8 @@ F52E4EAA0F43B53F00AC6C52 /* SapphireConfirmPrompt.m in Sources */, 805420AA0F94FA7E002D2DBF /* NSImage-Extensions.m in Sources */, F5505DC71040864D0064D392 /* SapphireAudioNowPlayingController.m in Sources */, + 5941C04710786EB2004C887B /* SapphireMovieVirtualDirectory.m in Sources */, + 5941C04810786ECA004C887B /* SapphireMovieVirtualDirectoryImporter.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; Index: branches/CoreData/SapphireFrappliance/FRAppliance/SapphireApplianceController.m =================================================================== --- branches/CoreData/SapphireFrappliance/FRAppliance/SapphireApplianceController.m (revision 920) +++ branches/CoreData/SapphireFrappliance/FRAppliance/SapphireApplianceController.m (working copy) @@ -469,7 +469,7 @@ - (SapphireBrowser *)movieBrowser { BRTexture *predicateGem = [SapphireApplianceController gemForPredicate:[SapphireApplianceController predicate]]; - SapphireMovieDirectory *movieDir = [[SapphireMovieDirectory alloc] initWithContext:moc]; + SapphireMovieDirectory *movieDir = [[SapphireMovieDirectory alloc] initWithContext:moc appSupportDir:applicationSupportDir()]; SapphireBrowser *movieBrowser = [[SapphireBrowser alloc] initWithScene:[self scene] metaData:movieDir]; [movieDir release]; [movieBrowser setListTitle:BRLocalizedString(@" Movies", nil)]; Index: branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectory.m =================================================================== --- branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectory.m (revision 0) +++ branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectory.m (revision 0) @@ -0,0 +1,53 @@ +/* + * SapphireMovieVirtualDirectory.m + * Sapphire + * + * Created by mjacobsen on Oct. 2, 2009. + * Copyright 2007 Sapphire Development Team and/or www.nanopi.net + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation; either version 3 of the License, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#import "SapphireMovieVirtualDirectory.h" + +@implementation SapphireMovieVirtualDirectory +- (NSString *)getTitle +{ + return title; +} + +- (NSString *)getDesc +{ + return desc; +} + +- (NSPredicate *)getPredicate +{ + return predicate; +} + +- (void)setTitle:(NSString*)v +{ + title = v; +} + +- (void)setDesc:(NSString*)v +{ + desc = v; +} + +- (void)setPredicate:(NSPredicate*)v +{ + predicate = v; +} +@end Index: branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieDirectory.h =================================================================== --- branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieDirectory.h (revision 920) +++ branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieDirectory.h (working copy) @@ -28,8 +28,8 @@ */ @interface SapphireMovieDirectory : NSObject { NSManagedObjectContext *moc; /*!< @brief The context*/ - NSArray *subDirs; /*!< @brief The sub-directory objects*/ - NSArray *names; /*!< @brief The sub-directory names*/ + NSMutableArray *subDirs; /*!< @brief The sub-directory objects*/ + NSMutableArray *names; /*!< @brief The sub-directory names*/ Basic_Directory_Function_Instance_Variables } @@ -39,6 +39,6 @@ * @param context The context which stores the movies * @return The movie directory */ -- (id)initWithContext:(NSManagedObjectContext *)context; +- (id)initWithContext:(NSManagedObjectContext *)context appSupportDir:(NSString *)appSupportDir; @end Index: branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectoryImporter.h =================================================================== --- branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectoryImporter.h (revision 0) +++ branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectoryImporter.h (revision 0) @@ -0,0 +1,37 @@ +/* + * SapphireMovieVirtualDirectoryImporter.h + * Sapphire + * + * Created by mjacobsen on Oct. 2, 2009. + * Copyright 2007 Sapphire Development Team and/or www.nanopi.net + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation; either version 3 of the License, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*! + * @brief The importer of movie virtual directory data + * + * This class is a for importing xml movie virtual directory data. It will read in data stored in XML files for defining custom movie virtual directories. + */ +@interface SapphireMovieVirtualDirectoryImporter : NSObject { +} +- (void)importVirtualDirectories:(NSMutableArray *)virtualDirs path:(NSString *)path; +- (NSPredicate *)createPredicate:(NSXMLElement *)elem; +- (NSPredicate *)createAllPredicate:(NSXMLElement *)elem; +- (NSPredicate *)createAnyPredicate:(NSXMLElement *)elem; +- (NSPredicate *)createNotPredicate:(NSXMLElement *)elem; +- (NSMutableArray *)createPredicateArray:(NSXMLElement *)elem; +- (BOOL)isRegexMatch:(NSXMLElement *)elem; +- (BOOL)isCaseInsensitiveMatch:(NSXMLElement *)elem; + +@end Index: branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieDirectory.m =================================================================== --- branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieDirectory.m (revision 920) +++ branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieDirectory.m (working copy) @@ -26,7 +26,8 @@ #import "CoreDataSupportFunctions.h" #import "SapphireBasicDirectoryFunctionsImports.h" #import "SapphireFileSorter.h" - +#import "SapphireMovieVirtualDirectoryImporter.h" +#import "SapphireMovieVirtualDirectory.h" #import "SapphireMovie.h" #import "SapphireCast.h" #import "SapphireDirector.h" @@ -81,14 +82,15 @@ @implementation SapphireMovieDirectory -- (id)initWithContext:(NSManagedObjectContext *)context +- (id)initWithContext:(NSManagedObjectContext *)context appSupportDir:(NSString *)appSupportDir { self = [super init]; if(self == nil) return self; moc = [context retain]; - + + /*Define the static virtual directories*/ NSPredicate *allPred = [NSPredicate predicateWithFormat:@"movie != nil"]; SapphireFilteredFileDirectory *all = [[SapphireFilteredFileDirectory alloc] initWithPredicate:allPred Context:moc]; SapphireEntityDirectory *cast = [[SapphireEntityDirectory alloc] initWithEntityFetch:castEntityFetch inContext:moc]; @@ -98,24 +100,23 @@ SapphireFilteredFileDirectory *top250 = [[SapphireFilteredFileDirectory alloc] initWithPredicate:top250Pred Context:moc]; NSPredicate *oscarPred = [NSPredicate predicateWithFormat:@"movie.oscarsWon != 0"]; SapphireFilteredFileDirectory *oscar = [[SapphireFilteredFileDirectory alloc] initWithPredicate:oscarPred Context:moc]; - - subDirs = [[NSArray alloc] initWithObjects: - all, - cast, - director, - genre, - top250, - oscar, - nil]; - names = [[NSArray alloc] initWithObjects: - BRLocalizedString( @"All Movies", @"Select all movies" ), - BRLocalizedString( @"By Cast", @"Select movies based on cast members" ), - BRLocalizedString( @"By Director", @"Select movies based on director" ), - BRLocalizedString( @"By Genre", @"Select movies based on genre" ), - BRLocalizedString( @"IMDB Top 250", @"Show movies in IMDb Top 250 only" ), - BRLocalizedString( @"Academy Award Winning", @"Show Oscar winning movies only" ), - nil]; + + subDirs = [[NSMutableArray alloc] init]; + [subDirs addObject:all]; + [subDirs addObject:cast]; + [subDirs addObject:director]; + [subDirs addObject:genre]; + [subDirs addObject:top250]; + [subDirs addObject:oscar]; + names = [[NSMutableArray alloc] init]; + [names addObject:BRLocalizedString( @"All Movies", @"Select all movies" )]; + [names addObject:BRLocalizedString( @"By Cast", @"Select movies based on cast members" )]; + [names addObject:BRLocalizedString( @"By Director", @"Select movies based on director" )]; + [names addObject:BRLocalizedString( @"By Genre", @"Select movies based on genre" )]; + [names addObject:BRLocalizedString( @"IMDB Top 250", @"Show movies in IMDb Top 250 only" )]; + [names addObject:BRLocalizedString( @"Academy Award Winning", @"Show Oscar winning movies only" )]; + SapphireFileSorter *titleSort = [SapphireMovieTitleSorter sharedInstance]; SapphireFileSorter *imdbRankSort = [SapphireMovieIMDBTop250RankSorter sharedInstance]; SapphireFileSorter *awardSort = [SapphireMovieAcademyAwardSorter sharedInstance]; @@ -124,6 +125,24 @@ NSString *moviePath = [[NSBundle bundleForClass:[self class]] pathForResource:@"video_H" ofType:@"png"]; + /*Import any defined movie virtual directories*/ + SapphireMovieVirtualDirectoryImporter *mvdImp = [[SapphireMovieVirtualDirectoryImporter alloc] init]; + NSMutableArray *virtualDirs = [[NSMutableArray alloc] init]; + appSupportDir = [appSupportDir stringByAppendingPathComponent:@"virtualDirs.xml"]; + [mvdImp importVirtualDirectories:virtualDirs path:appSupportDir]; + NSEnumerator *mvdEnum = [virtualDirs objectEnumerator]; + SapphireMovieVirtualDirectory *virtualDir; + while((virtualDir = [mvdEnum nextObject]) != nil) + { + SapphireFilteredFileDirectory *custom = [[SapphireFilteredFileDirectory alloc] initWithPredicate:[virtualDir getPredicate] Context:moc]; + [subDirs addObject:custom]; + [names addObject:BRLocalizedString([virtualDir getTitle], [virtualDir getDesc])]; + [custom setPath:[[VIRTUAL_DIR_ROOT_PATH stringByAppendingString:@"/"] stringByAppendingString:[virtualDir getDesc]]]; + [custom setCoverArtPath:moviePath]; // Change this to be part of the XML? + [custom setFileSorters:[NSArray arrayWithObjects:titleSort, dateSort, imdbRatingSort, nil]]; + } + + /*Finish the static directory setup*/ [all setPath:VIRTUAL_DIR_ALL_PATH]; [all setCoverArtPath:moviePath]; [all setFileSorters:[NSArray arrayWithObjects:titleSort, dateSort, imdbRatingSort, nil]]; @@ -151,6 +170,8 @@ [genre release]; [top250 release]; [oscar release]; + [mvdImp release]; + [virtualDirs release]; return self; } Index: branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectory.h =================================================================== --- branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectory.h (revision 0) +++ branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectory.h (revision 0) @@ -0,0 +1,39 @@ +/* + * SapphireMovieVirtualDirectory.h + * Sapphire + * + * Created by mjacobsen on Oct. 2, 2009. + * Copyright 2007 Sapphire Development Team and/or www.nanopi.net + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation; either version 3 of the License, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +/*! + * @brief The simple object to hold movie virtual directory data + * + * This class is a value object for holding imported xml movie virtual directory data. + */ +@interface SapphireMovieVirtualDirectory : NSObject { + NSString *title; + NSString *desc; + NSPredicate *predicate; +} +- (NSString *)getTitle; +- (NSString *)getDesc; +- (NSPredicate *)getPredicate; +- (void)setTitle:(NSString*)v; +- (void)setDesc:(NSString*)v; +- (void)setPredicate:(NSPredicate*)v; +@end + Index: branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectoryImporter.m =================================================================== --- branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectoryImporter.m (revision 0) +++ branches/CoreData/SapphireFrappliance/MetaData/Support/SapphireMovieVirtualDirectoryImporter.m (revision 0) @@ -0,0 +1,265 @@ +/* + * SapphireMovieVirtualDirectoryImporter.m + * Sapphire + * + * Created by mjacobsen on Oct. 2, 2009. + * Copyright 2007 Sapphire Development Team and/or www.nanopi.net + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it under the terms of the GNU + * General Public License as published by the Free Software Foundation; either version 3 of the License, + * or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even + * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if not, + * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#import "SapphireMovieVirtualDirectoryImporter.h" +#import "SapphireMovieVirtualDirectory.h" +#import "SapphireLogging.h" + +//Attributes +#define MOVIE_MATCH_ELEM_QUERY @"/virtualDirs/movieMatch" +#define MOVIE_MATCH_NAME_ATTRIB @"name" +#define MOVIE_MATCH_DESCRIPTION_ATTRIB @"description" +#define ELEM_TYPE_ATTRIB @"type" +#define ELEM_TYPE_ATTRIB_CASE_INSENSITIVE @"i" +#define ELEM_TYPE_ATTRIB_REGEX @"regex" +#define ALL_ELEM @"all" +#define ANY_ELEM @"any" +// in minutes (db stores in seconds) (at least the value specified) +#define DURATION_ELEM @"duration" +// t, f, y, n, 1, 0 +#define WATCHED_ELEM @"watched" +// MPEG-2, NTSC, 720x480 (16:9), or DivX 5 (Perian, 448 x352, Millions, etc. +#define VIDEO_DESCRIPTION_ELEM @"videoDescription" +// English, Spanish, or MPEG Layer3, Stereo, 44.100 kHz +#define AUDIO_DESCRIPTION_ELEM @"audioDescription" +// English, Spanish, etc. +#define SUBTITLES_ELEM @"subtitles" +#define TITLE_ELEM @"title" +#define PLOT_ELEM @"plot" +// standard data format (db stores in unknown int format -- must convert) +#define RELEASE_DATE_ELEM @"releaseDate" +// float 0 - 10 (at least the value specified) +#define IMDB_USER_RATING_ELEM @"imdbUserRating" +// int 1 - 250 (at most the value specified) +#define IMDB_TOP_250_ELEM @"imdbTop250" +// t, f, y, n, 1, 0 +#define WON_OSCARS_ELEM @"wonOscars" +// PG, PG-13, R, G +#define MPAA_RATING_ELEM @"mpaaRating" +#define CAST_ELEM @"cast" +#define GENRE_ELEM @"genre" +#define DIRECTOR_ELEM @"director" +#define NOT_ELEM @"not" + +@implementation SapphireMovieVirtualDirectoryImporter + +- (void)importVirtualDirectories:(NSMutableArray *)virtualDirs path:(NSString *)path +{ + /*Check for XML file*/ + SapphireLog(SAPPHIRE_LOG_ALL, SAPPHIRE_LOG_LEVEL_ERROR, @"Looking for file: %@", path); + NSFileManager *fm = [NSFileManager defaultManager]; + BOOL xmlPathIsDir = NO; + if(![fm fileExistsAtPath:path isDirectory:&xmlPathIsDir] || xmlPathIsDir) + return; + + /*Read the XML document*/ + NSURL *url = [NSURL fileURLWithPath:path]; + NSError *error = nil; + NSXMLDocument *document = [[[NSXMLDocument alloc] initWithContentsOfURL:url options:NSXMLDocumentTidyXML error:&error] autorelease]; + NSXMLElement *root = [document rootElement]; + if(!root) + return; + + /*For each movie virtual directory*/ + NSArray *movieMatchNodes = [root nodesForXPath:MOVIE_MATCH_ELEM_QUERY error:&error]; + NSEnumerator *nodeEnum = [movieMatchNodes objectEnumerator]; + NSXMLElement *matchElem; + NSXMLNode *tmpNode; + while((matchElem = [nodeEnum nextObject]) != nil) + { + /*Create the virtual directory*/ + SapphireMovieVirtualDirectory *virtualDir = [[SapphireMovieVirtualDirectory alloc] init]; + tmpNode = [matchElem attributeForName:MOVIE_MATCH_NAME_ATTRIB]; + if (tmpNode) + [virtualDir setTitle:[tmpNode stringValue]]; + tmpNode = [matchElem attributeForName:MOVIE_MATCH_DESCRIPTION_ATTRIB]; + if (tmpNode) + [virtualDir setDesc:[tmpNode stringValue]]; + + /*Build the query recursively (assume every child in the is grouped in an implicit ). */ + NSPredicate *matchPred = [self createAllPredicate:matchElem]; + if (matchPred != nil) + { + NSPredicate *moviePred = [NSPredicate predicateWithFormat:@"movie != nil"]; + matchPred = [NSCompoundPredicate andPredicateWithSubpredicates:[NSArray arrayWithObjects:moviePred, matchPred, nil]]; + SapphireLog(SAPPHIRE_LOG_ALL, SAPPHIRE_LOG_LEVEL_INFO, @"Creating virtual directory with filter: %@", matchPred); + [virtualDir setPredicate:matchPred]; + [virtualDirs addObject:virtualDir]; + } + } +} + +- (NSPredicate *)createPredicate:(NSXMLElement *)elem +{ + /*NOTE: regex MATCHES operators are not officially supported against core data objects -- though + * some have posted success when using regex MATCHES with simple (non-many-to-one) relationships. + * We'll leave it commented out for now.*/ + if ([[elem name] caseInsensitiveCompare:ALL_ELEM] == NSOrderedSame) + return [self createAllPredicate:elem]; + else if ([[elem name] caseInsensitiveCompare:ANY_ELEM] == NSOrderedSame) + return [self createAnyPredicate:elem]; + else if ([[elem name] caseInsensitiveCompare:NOT_ELEM] == NSOrderedSame) + return [self createNotPredicate:elem]; +// else if (([[elem name] caseInsensitiveCompare:TITLE_ELEM] == NSOrderedSame) && ([self isRegexMatch:elem])) +// return [NSPredicate predicateWithFormat:@"(movie.title matches %@)", [elem stringValue]]; + else if (([[elem name] caseInsensitiveCompare:TITLE_ELEM] == NSOrderedSame) && ([self isCaseInsensitiveMatch:elem])) + return [NSPredicate predicateWithFormat:@"(movie.title like[cd] %@)", [elem stringValue]]; + else if ([[elem name] caseInsensitiveCompare:TITLE_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(movie.title like %@)", [elem stringValue]]; +// else if (([[elem name] caseInsensitiveCompare:PLOT_ELEM] == NSOrderedSame) && ([self isRegexMatch:elem])) +// return [NSPredicate predicateWithFormat:@"(movie.plot matches %@)", [elem stringValue]]; + else if (([[elem name] caseInsensitiveCompare:PLOT_ELEM] == NSOrderedSame) && ([self isCaseInsensitiveMatch:elem])) + return [NSPredicate predicateWithFormat:@"(movie.plot like[cd] %@)", [elem stringValue]]; + else if ([[elem name] caseInsensitiveCompare:PLOT_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(movie.plot like %@)", [elem stringValue]]; +// else if (([[elem name] caseInsensitiveCompare:VIDEO_DESCRIPTION_ELEM] == NSOrderedSame) && ([self isRegexMatch:elem])) +// return [NSPredicate predicateWithFormat:@"(movie.videoDescription matches %@)", [elem stringValue]]; + else if (([[elem name] caseInsensitiveCompare:VIDEO_DESCRIPTION_ELEM] == NSOrderedSame) && ([self isCaseInsensitiveMatch:elem])) + return [NSPredicate predicateWithFormat:@"(movie.videoDescription like[cd] %@)", [elem stringValue]]; + else if ([[elem name] caseInsensitiveCompare:VIDEO_DESCRIPTION_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(movie.videoDescription like %@)", [elem stringValue]]; +// else if (([[elem name] caseInsensitiveCompare:AUDIO_DESCRIPTION_ELEM] == NSOrderedSame) && ([self isRegexMatch:elem])) +// return [NSPredicate predicateWithFormat:@"(movie.audioDescription matches %@)", [elem stringValue]]; + else if (([[elem name] caseInsensitiveCompare:AUDIO_DESCRIPTION_ELEM] == NSOrderedSame) && ([self isCaseInsensitiveMatch:elem])) + return [NSPredicate predicateWithFormat:@"(movie.audioDescription like[cd] %@)", [elem stringValue]]; + else if ([[elem name] caseInsensitiveCompare:AUDIO_DESCRIPTION_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(movie.audioDescription like %@)", [elem stringValue]]; +// else if (([[elem name] caseInsensitiveCompare:SUBTITLES_ELEM] == NSOrderedSame) && ([self isRegexMatch:elem])) +// return [NSPredicate predicateWithFormat:@"(movie.subtitlesDescription matches %@)", [elem stringValue]]; + else if (([[elem name] caseInsensitiveCompare:SUBTITLES_ELEM] == NSOrderedSame) && ([self isCaseInsensitiveMatch:elem])) + return [NSPredicate predicateWithFormat:@"(movie.subtitlesDescription like[cd] %@)", [elem stringValue]]; + else if ([[elem name] caseInsensitiveCompare:SUBTITLES_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(movie.subtitlesDescription like %@)", [elem stringValue]]; +// else if (([[elem name] caseInsensitiveCompare:MPAA_RATING_ELEM] == NSOrderedSame) && ([self isRegexMatch:elem])) +// return [NSPredicate predicateWithFormat:@"(movie.MPAARating matches %@)", [elem stringValue]]; + else if (([[elem name] caseInsensitiveCompare:MPAA_RATING_ELEM] == NSOrderedSame) && ([self isCaseInsensitiveMatch:elem])) + return [NSPredicate predicateWithFormat:@"(movie.MPAARating like[cd] %@)", [elem stringValue]]; + else if ([[elem name] caseInsensitiveCompare:MPAA_RATING_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(movie.MPAARating like %@)", [elem stringValue]]; +// else if (([[elem name] caseInsensitiveCompare:CAST_ELEM] == NSOrderedSame) && ([self isRegexMatch:elem])) +// return [NSPredicate predicateWithFormat:@"(ANY movie.#cast.name matches %@)", [elem stringValue]]; + else if (([[elem name] caseInsensitiveCompare:CAST_ELEM] == NSOrderedSame) && ([self isCaseInsensitiveMatch:elem])) + return [NSPredicate predicateWithFormat:@"(ANY movie.#cast.name like[cd] %@)", [elem stringValue]]; + else if ([[elem name] caseInsensitiveCompare:CAST_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(ANY movie.#cast.name like %@)", [elem stringValue]]; +// else if (([[elem name] caseInsensitiveCompare:GENRE_ELEM] == NSOrderedSame) && ([self isRegexMatch:elem])) +// return [NSPredicate predicateWithFormat:@"(ANY movie.genres.name matches %@)", [elem stringValue]]; + else if (([[elem name] caseInsensitiveCompare:GENRE_ELEM] == NSOrderedSame) && ([self isCaseInsensitiveMatch:elem])) + return [NSPredicate predicateWithFormat:@"(ANY movie.genres.name like[cd] %@)", [elem stringValue]]; + else if ([[elem name] caseInsensitiveCompare:GENRE_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(ANY movie.genres.name like %@)", [elem stringValue]]; +// else if (([[elem name] caseInsensitiveCompare:DIRECTOR_ELEM] == NSOrderedSame) && ([self isRegexMatch:elem])) +// return [NSPredicate predicateWithFormat:@"(ANY movie.directors.name matches %@)", [elem stringValue]]; + else if (([[elem name] caseInsensitiveCompare:DIRECTOR_ELEM] == NSOrderedSame) && ([self isCaseInsensitiveMatch:elem])) + return [NSPredicate predicateWithFormat:@"(ANY movie.directors.name like[cd] %@)", [elem stringValue]]; + else if ([[elem name] caseInsensitiveCompare:DIRECTOR_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(ANY movie.directors.name like %@)", [elem stringValue]]; + else if (([[elem name] caseInsensitiveCompare:WON_OSCARS_ELEM] == NSOrderedSame) && ([[elem stringValue] boolValue])) + return [NSPredicate predicateWithFormat:@"(movie.oscarsWon != 0)"]; + else if (([[elem name] caseInsensitiveCompare:WON_OSCARS_ELEM] == NSOrderedSame) && !([[elem stringValue] boolValue])) + return [NSPredicate predicateWithFormat:@"(movie.oscarsWon == 0)"]; + else if (([[elem name] caseInsensitiveCompare:WATCHED_ELEM] == NSOrderedSame) && ([[elem stringValue] boolValue])) + return [NSPredicate predicateWithFormat:@"(movie.watched != 0)"]; + else if (([[elem name] caseInsensitiveCompare:WATCHED_ELEM] == NSOrderedSame) && !([[elem stringValue] boolValue])) + return [NSPredicate predicateWithFormat:@"(movie.watched == 0)"]; + else if ([[elem name] caseInsensitiveCompare:IMDB_TOP_250_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(movie.imdbTop250Ranking <= %d AND movie.imdbTop250Ranking > 0)", [[elem stringValue] intValue]]; + else if ([[elem name] caseInsensitiveCompare:IMDB_USER_RATING_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(movie.imdbRating >= %f)", [[elem stringValue] floatValue]]; + else if ([[elem name] caseInsensitiveCompare:DURATION_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(movie.duration >= %f)", [[elem stringValue] floatValue]*60]; + else if ([[elem name] caseInsensitiveCompare:RELEASE_DATE_ELEM] == NSOrderedSame) + return [NSPredicate predicateWithFormat:@"(movie.releaseDate >= %@)", [NSDate dateWithNaturalLanguageString:[elem stringValue]]]; + else + return nil; +} + +- (NSPredicate *)createAllPredicate:(NSXMLElement *)elem +{ + NSMutableArray *preds = [self createPredicateArray:elem]; + + /*Now set the returned predicates to an AND predicate*/ + if ([preds count]) + return [NSCompoundPredicate andPredicateWithSubpredicates:preds]; + else + return nil; +} + +- (NSPredicate *)createAnyPredicate:(NSXMLElement *)elem +{ + NSMutableArray *preds = [self createPredicateArray:elem]; + + /*Now set the returned predicates to an ANY predicate*/ + if ([preds count]) + return [NSCompoundPredicate orPredicateWithSubpredicates:preds]; + else + return nil; +} + +- (NSPredicate *)createNotPredicate:(NSXMLElement *)elem +{ + NSMutableArray *preds = [self createPredicateArray:elem]; + + /*Now set the returned predicate to a NOT predicate*/ + if ([preds count]) + return [NSCompoundPredicate notPredicateWithSubpredicate:(NSPredicate *)[preds objectAtIndex:0]]; + else + return nil; +} + +- (NSMutableArray *)createPredicateArray:(NSXMLElement *)elem +{ + NSMutableArray *preds = [[NSMutableArray alloc] init]; + NSEnumerator *nodeEnum = [[elem children] objectEnumerator]; + NSXMLNode *node; + while((node = [nodeEnum nextObject]) != nil) + { + /*Check for type of node*/ + if ([node kind] == NSXMLElementKind) + { + /*Create a predicate and add it our array*/ + NSPredicate *pred = [self createPredicate:(NSXMLElement *)node]; + if (pred != nil) + [preds addObject:pred]; + } + } + return preds; +} + +- (BOOL)isRegexMatch:(NSXMLElement *)elem +{ + /* Need to check if this is a regex match. Default to wildcard (NO). + * Only return YES if attribute type="regex" exists. */ + NSString *type = [[elem attributeForName:ELEM_TYPE_ATTRIB] stringValue]; + if(type!=nil) + return ([type caseInsensitiveCompare:ELEM_TYPE_ATTRIB_REGEX] == NSOrderedSame); + return NO; +} + +- (BOOL)isCaseInsensitiveMatch:(NSXMLElement *)elem +{ + /* Need to check if this is a case insensitive match. Default to case sensitive (NO). + * Only return YES if attribute type="i" exists. */ + NSString *type = [[elem attributeForName:ELEM_TYPE_ATTRIB] stringValue]; + if(type!=nil) + return ([type caseInsensitiveCompare:ELEM_TYPE_ATTRIB_CASE_INSENSITIVE] == NSOrderedSame); + return NO; +} + +@end \ No newline at end of file