From 56680a9b967772ca6eb9112ac6f2a9e9bbe7244b Mon Sep 17 00:00:00 2001 From: ritsuka Date: Tue, 29 Jul 2014 18:38:01 +0000 Subject: MacGui: Implemented a configuration panel similar to the win/lin gui one for the subtitles defaults, and added some more options from the other guis (add all, remove all). The SubtitleAddForeignAudioSubtitle setting will be added later after the automatic audio selection is done. Fixed a bug where HandBrake used 50% of cpu time if the subtitles table view was selected. Refactored a big part of HBSubtitlesController to make it works with the new automatic options and to cleaned the table view data source. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6241 b64f7644-9d1e-0410-96f1-a4d463321fa5 --- macosx/Controller.m | 408 ++++----- macosx/English.lproj/Subtitles.xib | 131 ++- macosx/English.lproj/SubtitlesDefaults.xib | 192 ++++ macosx/HBLanguagesSelection.h | 50 ++ macosx/HBLanguagesSelection.m | 123 +++ macosx/HBQueueController.mm | 38 +- macosx/HBSubtitlesController.h | 19 +- macosx/HBSubtitlesController.m | 1341 +++++++++++++++------------- macosx/HBSubtitlesDefaultsController.h | 17 + macosx/HBSubtitlesDefaultsController.m | 68 ++ macosx/HBSubtitlesSettings.h | 27 + macosx/HBSubtitlesSettings.m | 61 ++ macosx/HandBrake.xcodeproj/project.pbxproj | 58 +- 13 files changed, 1584 insertions(+), 949 deletions(-) create mode 100644 macosx/English.lproj/SubtitlesDefaults.xib create mode 100644 macosx/HBLanguagesSelection.h create mode 100644 macosx/HBLanguagesSelection.m create mode 100644 macosx/HBSubtitlesDefaultsController.h create mode 100644 macosx/HBSubtitlesDefaultsController.m create mode 100644 macosx/HBSubtitlesSettings.h create mode 100644 macosx/HBSubtitlesSettings.m diff --git a/macosx/Controller.m b/macosx/Controller.m index f7a30d903..195911615 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -2613,7 +2613,7 @@ fWorkingCount = 0; [fAudioController prepareAudioForQueueFileJob: queueFileJob]; /* Subtitles */ - NSMutableArray *subtitlesArray = [[NSMutableArray alloc] initWithArray:[fSubtitlesViewController subtitleArray] copyItems:YES]; + NSMutableArray *subtitlesArray = [[NSMutableArray alloc] initWithArray:[fSubtitlesViewController subtitles] copyItems:YES]; [queueFileJob setObject:[NSArray arrayWithArray: subtitlesArray] forKey:@"SubtitleList"]; [subtitlesArray autorelease]; @@ -3097,131 +3097,95 @@ fWorkingCount = 0; [fVideoController prepareVideoForJobPreview:job andTitle:title]; /* Subtitle settings */ - NSMutableArray *subtitlesArray = [[NSMutableArray alloc] initWithArray:fSubtitlesViewController.subtitleArray copyItems:YES]; - -int subtitle; -int force; -int burned; -int def; -bool one_burned = FALSE; - + BOOL one_burned = NO; int i = 0; - NSEnumerator *enumerator = [subtitlesArray objectEnumerator]; - id tempObject; - while (tempObject = [enumerator nextObject]) + + for (id subtitleDict in fSubtitlesViewController.subtitles) { - - subtitle = [[tempObject objectForKey:@"subtitleSourceTrackNum"] intValue]; - force = [[tempObject objectForKey:@"subtitleTrackForced"] intValue]; - burned = [[tempObject objectForKey:@"subtitleTrackBurned"] intValue]; - def = [[tempObject objectForKey:@"subtitleTrackDefault"] intValue]; - - /* since the subtitleSourceTrackNum 0 is "None" in our array of the subtitle popups, - * we want to ignore it for display as well as encoding. - */ - if (subtitle > 0) + int subtitle = [subtitleDict[keySubTrackIndex] intValue]; + int force = [subtitleDict[keySubTrackForced] intValue]; + int burned = [subtitleDict[keySubTrackBurned] intValue]; + int def = [subtitleDict[keySubTrackDefault] intValue]; + + // if i is 0, then we are in the first item of the subtitles which we need to + // check for the "Foreign Audio Search" which would be keySubTrackIndex of -1 + + /* if we are on the first track and using "Foreign Audio Search" */ + if (i == 0 && subtitle == -1) { - /* if i is 0, then we are in the first item of the subtitles which we need to - * check for the "Foreign Audio Search" which would be subtitleSourceTrackNum of 1 - * bearing in mind that for all tracks subtitleSourceTrackNum of 0 is None. - */ - - /* if we are on the first track and using "Foreign Audio Search" */ - if (i == 0 && subtitle == 1) + [HBUtilities writeToActivityLog: "Foreign Language Search: %d", 1]; + + job->indepth_scan = 1; + + if (burned != 1) { - /* NOTE: Currently foreign language search is borked for preview. - * Commented out but left in for initial commit. */ - - - [HBUtilities writeToActivityLog: "Foreign Language Search: %d", 1]; - - job->indepth_scan = 1; - - if (burned != 1) - { - job->select_subtitle_config.dest = PASSTHRUSUB; - } - else - { - job->select_subtitle_config.dest = RENDERSUB; - } - - job->select_subtitle_config.force = force; - job->select_subtitle_config.default_track = def; + job->select_subtitle_config.dest = PASSTHRUSUB; } else { - /* if we are getting the subtitles from an external srt file */ - if ([[tempObject objectForKey:@"subtitleSourceTrackType"] intValue] == SRTSUB) - { - hb_subtitle_config_t sub_config; - - sub_config.offset = [[tempObject objectForKey:@"subtitleTrackSrtOffset"] intValue]; - - /* we need to srncpy file path and char code */ - strncpy(sub_config.src_filename, [[tempObject objectForKey:@"subtitleSourceSrtFilePath"] UTF8String], 255); - sub_config.src_filename[255] = 0; - strncpy(sub_config.src_codeset, [[tempObject objectForKey:@"subtitleTrackSrtCharCode"] UTF8String], 39); - sub_config.src_codeset[39] = 0; - - if( !burned && hb_subtitle_can_pass( SRTSUB, job->mux ) ) - { - sub_config.dest = PASSTHRUSUB; - } - else if( hb_subtitle_can_burn( SRTSUB ) ) - { - // Only allow one subtitle to be burned into the video - if( one_burned ) - continue; - one_burned = TRUE; - sub_config.dest = RENDERSUB; - } + job->select_subtitle_config.dest = RENDERSUB; + } - sub_config.force = 0; - sub_config.default_track = def; - hb_srt_add( job, &sub_config, [[tempObject objectForKey:@"subtitleTrackSrtLanguageIso3"] UTF8String]); - continue; + job->select_subtitle_config.force = force; + job->select_subtitle_config.default_track = def; + } + else + { + /* if we are getting the subtitles from an external srt file */ + if ([subtitleDict[keySubTrackType] intValue] == SRTSUB) + { + hb_subtitle_config_t sub_config; + + sub_config.offset = [subtitleDict[keySubTrackSrtOffset] intValue]; + + /* we need to srncpy file name and codeset */ + strncpy(sub_config.src_filename, [subtitleDict[keySubTrackSrtFilePath] UTF8String], 255); + sub_config.src_filename[255] = 0; + strncpy(sub_config.src_codeset, [subtitleDict[keySubTrackSrtCharCode] UTF8String], 39); + sub_config.src_codeset[39] = 0; + + if( !burned && hb_subtitle_can_pass( SRTSUB, job->mux ) ) + { + sub_config.dest = PASSTHRUSUB; } - - /* for the actual source tracks, we must subtract the non source entries so - * that the menu index matches the source subtitle_list index for convenience */ - if( i == 0 ) + else if( hb_subtitle_can_burn( SRTSUB ) ) { - /* for the first track, the source tracks start at menu index 2 ( None is 0, - * Foreign Language Search is 1) so subtract 2 */ - subtitle = subtitle - 2; + // Only allow one subtitle to be burned into the video + if( one_burned ) + continue; + one_burned = TRUE; + sub_config.dest = RENDERSUB; } - else + + sub_config.force = 0; + sub_config.default_track = def; + hb_srt_add( job, &sub_config, [subtitleDict[keySubTrackLanguageIsoCode] UTF8String]); + continue; + } + + /* We are setting a source subtitle so access the source subtitle info */ + hb_subtitle_t * subt = (hb_subtitle_t *) hb_list_item( title->list_subtitle, subtitle ); + + if( subt != NULL ) + { + hb_subtitle_config_t sub_config = subt->config; + + if( !burned && hb_subtitle_can_pass( subt->source, job->mux ) ) { - /* for all other tracks, the source tracks start at menu index 1 (None is 0) - * so subtract 1. */ - subtitle = subtitle - 1; + sub_config.dest = PASSTHRUSUB; } - - /* We are setting a source subtitle so access the source subtitle info */ - hb_subtitle_t * subt = (hb_subtitle_t *) hb_list_item( title->list_subtitle, subtitle ); - - if( subt != NULL ) + else if( hb_subtitle_can_burn( subt->source ) ) { - hb_subtitle_config_t sub_config = subt->config; - - if( !burned && hb_subtitle_can_pass( subt->source, job->mux ) ) - { - sub_config.dest = PASSTHRUSUB; - } - else if( hb_subtitle_can_burn( subt->source ) ) - { - // Only allow one subtitle to be burned into the video - if( one_burned ) - continue; - one_burned = TRUE; - sub_config.dest = RENDERSUB; - } - - sub_config.force = force; - sub_config.default_track = def; - hb_subtitle_add( job, &sub_config, subtitle ); + // Only allow one subtitle to be burned into the video + if( one_burned ) + continue; + one_burned = TRUE; + sub_config.dest = RENDERSUB; } + + sub_config.force = force; + sub_config.default_track = def; + hb_subtitle_add( job, &sub_config, subtitle ); } } i++; @@ -3230,15 +3194,10 @@ bool one_burned = FALSE; { filter = hb_filter_init( HB_FILTER_RENDER_SUB ); hb_add_filter( job, filter, [[NSString stringWithFormat:@"%d:%d:%d:%d", - job->crop[0], job->crop[1], - job->crop[2], job->crop[3]] UTF8String] ); + job->crop[0], job->crop[1], + job->crop[2], job->crop[3]] UTF8String] ); } - - - -[subtitlesArray autorelease]; - - + /* Auto Passthru */ job->acodec_copy_mask = 0; if (fAudioController.allowAACPassCheck) @@ -3641,141 +3600,100 @@ bool one_burned = FALSE; job->vbitrate = 0; } - + job->grayscale = [[queueToApply objectForKey:@"VideoGrayScale"] intValue]; - + // Map the settings in the dictionaries for the SubtitleList array to match title->list_subtitle + BOOL one_burned = NO; + int i = 0; -#pragma mark - -#pragma mark Process Subtitles to libhb - -/* Map the settings in the dictionaries for the SubtitleList array to match title->list_subtitle - * which means that we need to account for the offset of non source language settings in from - * the NSPopUpCell menu. For all of the objects in the SubtitleList array this means 0 is "None" - * from the popup menu, additionally the first track has "Foreign Audio Search" at 1. So we use - * an int to offset the index number for the objectForKey:@"subtitleSourceTrackNum" to map that - * to the source tracks position in title->list_subtitle. - */ + NSArray *subtitles = [queueToApply objectForKey:@"SubtitleList"]; + for (id subtitleDict in subtitles) + { + int subtitle = [subtitleDict[keySubTrackIndex] intValue]; + int force = [subtitleDict[keySubTrackForced] intValue]; + int burned = [subtitleDict[keySubTrackBurned] intValue]; + int def = [subtitleDict[keySubTrackDefault] intValue]; -int subtitle; -int force; -int burned; -int def; -bool one_burned = FALSE; + // if i is 0, then we are in the first item of the subtitles which we need to + // check for the "Foreign Audio Search" which would be keySubTrackIndex of -1 - int i = 0; - NSEnumerator *enumerator = [[queueToApply objectForKey:@"SubtitleList"] objectEnumerator]; - id tempObject; - while (tempObject = [enumerator nextObject]) - { - - subtitle = [[tempObject objectForKey:@"subtitleSourceTrackNum"] intValue]; - force = [[tempObject objectForKey:@"subtitleTrackForced"] intValue]; - burned = [[tempObject objectForKey:@"subtitleTrackBurned"] intValue]; - def = [[tempObject objectForKey:@"subtitleTrackDefault"] intValue]; - - /* since the subtitleSourceTrackNum 0 is "None" in our array of the subtitle popups, - * we want to ignore it for display as well as encoding. - */ - if (subtitle > 0) + // if we are on the first track and using "Foreign Audio Search" + if (i == 0 && subtitle == -1) { - /* if i is 0, then we are in the first item of the subtitles which we need to - * check for the "Foreign Audio Search" which would be subtitleSourceTrackNum of 1 - * bearing in mind that for all tracks subtitleSourceTrackNum of 0 is None. - */ - - /* if we are on the first track and using "Foreign Audio Search" */ - if (i == 0 && subtitle == 1) + [HBUtilities writeToActivityLog: "Foreign Language Search: %d", 1]; + + job->indepth_scan = 1; + + if (burned != 1) { - [HBUtilities writeToActivityLog: "Foreign Language Search: %d", 1]; - - job->indepth_scan = 1; - - if (burned != 1) - { - job->select_subtitle_config.dest = PASSTHRUSUB; - } - else - { - job->select_subtitle_config.dest = RENDERSUB; - } - - job->select_subtitle_config.force = force; - job->select_subtitle_config.default_track = def; + job->select_subtitle_config.dest = PASSTHRUSUB; } else { - /* if we are getting the subtitles from an external srt file */ - if ([[tempObject objectForKey:@"subtitleSourceTrackType"] intValue] == SRTSUB) - { - hb_subtitle_config_t sub_config; - - sub_config.offset = [[tempObject objectForKey:@"subtitleTrackSrtOffset"] intValue]; - - /* we need to srncpy file name and codeset */ - strncpy(sub_config.src_filename, [[tempObject objectForKey:@"subtitleSourceSrtFilePath"] UTF8String], 255); - sub_config.src_filename[255] = 0; - strncpy(sub_config.src_codeset, [[tempObject objectForKey:@"subtitleTrackSrtCharCode"] UTF8String], 39); - sub_config.src_codeset[39] = 0; - - if( !burned && hb_subtitle_can_pass( SRTSUB, job->mux ) ) - { - sub_config.dest = PASSTHRUSUB; - } - else if( hb_subtitle_can_burn( SRTSUB ) ) - { - // Only allow one subtitle to be burned into the video - if( one_burned ) - continue; - one_burned = TRUE; - sub_config.dest = RENDERSUB; - } + job->select_subtitle_config.dest = RENDERSUB; + } + + job->select_subtitle_config.force = force; + job->select_subtitle_config.default_track = def; + } + else + { + // if we are getting the subtitles from an external srt file + if ([subtitleDict[keySubTrackType] intValue] == SRTSUB) + { + hb_subtitle_config_t sub_config; + + sub_config.offset = [subtitleDict[keySubTrackSrtOffset] intValue]; + + // we need to srncpy file name and codeset + strncpy(sub_config.src_filename, [subtitleDict[keySubTrackSrtFilePath] UTF8String], 255); + sub_config.src_filename[255] = 0; + strncpy(sub_config.src_codeset, [subtitleDict[keySubTrackSrtCharCode] UTF8String], 39); + sub_config.src_codeset[39] = 0; - sub_config.force = 0; - sub_config.default_track = def; - hb_srt_add( job, &sub_config, [[tempObject objectForKey:@"subtitleTrackSrtLanguageIso3"] UTF8String]); - continue; + if( !burned && hb_subtitle_can_pass( SRTSUB, job->mux ) ) + { + sub_config.dest = PASSTHRUSUB; } - - /* for the actual source tracks, we must subtract the non source entries so - * that the menu index matches the source subtitle_list index for convenience */ - if( i == 0 ) + else if( hb_subtitle_can_burn( SRTSUB ) ) { - /* for the first track, the source tracks start at menu index 2 ( None is 0, - * Foreign Language Search is 1) so subtract 2 */ - subtitle = subtitle - 2; + // Only allow one subtitle to be burned into the video + if( one_burned ) + continue; + one_burned = TRUE; + sub_config.dest = RENDERSUB; } - else + + sub_config.force = 0; + sub_config.default_track = def; + hb_srt_add( job, &sub_config, [subtitleDict[keySubTrackLanguageIsoCode] UTF8String]); + continue; + } + + /* We are setting a source subtitle so access the source subtitle info */ + hb_subtitle_t * subt = (hb_subtitle_t *) hb_list_item( title->list_subtitle, subtitle ); + + if( subt != NULL ) + { + hb_subtitle_config_t sub_config = subt->config; + + if( !burned && hb_subtitle_can_pass( subt->source, job->mux ) ) { - /* for all other tracks, the source tracks start at menu index 1 (None is 0) - * so subtract 1. */ - subtitle = subtitle - 1; + sub_config.dest = PASSTHRUSUB; } - - /* We are setting a source subtitle so access the source subtitle info */ - hb_subtitle_t * subt = (hb_subtitle_t *) hb_list_item( title->list_subtitle, subtitle ); - - if( subt != NULL ) + else if( hb_subtitle_can_burn( subt->source ) ) { - hb_subtitle_config_t sub_config = subt->config; - - if( !burned && hb_subtitle_can_pass( subt->source, job->mux ) ) - { - sub_config.dest = PASSTHRUSUB; - } - else if( hb_subtitle_can_burn( subt->source ) ) - { - // Only allow one subtitle to be burned into the video - if( one_burned ) - continue; - one_burned = TRUE; - sub_config.dest = RENDERSUB; - } - - sub_config.force = force; - sub_config.default_track = def; - hb_subtitle_add( job, &sub_config, subtitle ); + // Only allow one subtitle to be burned into the video + if( one_burned ) + continue; + one_burned = TRUE; + sub_config.dest = RENDERSUB; } + + sub_config.force = force; + sub_config.default_track = def; + hb_subtitle_add( job, &sub_config, subtitle ); } } i++; @@ -3788,8 +3706,6 @@ bool one_burned = FALSE; job->crop[2], job->crop[3]] UTF8String] ); } -#pragma mark - - /* Auto Passthru */ job->acodec_copy_mask = 0; if( [[queueToApply objectForKey: @"AudioAllowAACPass"] intValue] == 1 ) @@ -5410,11 +5326,8 @@ return YES; [fAudioController addTracksFromPreset: chosenPreset]; /*Subtitles*/ - // To be fixed in the automatic subtitles changes - //[fSubPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Subtitles"]]; - /* Forced Subtitles */ - //[fSubForcedCheck setState:[[chosenPreset objectForKey:@"SubtitlesForced"] intValue]]; - + [fSubtitlesViewController applySettingsFromPreset:chosenPreset]; + /* Picture Settings */ /* Note: objectForKey:@"UsesPictureSettings" refers to picture size, which encompasses: * height, width, keep ar, anamorphic and crop settings. @@ -5901,13 +5814,8 @@ return YES; [preset setObject:[NSMutableArray arrayWithArray: audioListArray] forKey:@"AudioList"]; [audioListArray release]; - - /* Temporarily remove subtitles from creating a new preset as it has to be converted over to use the new - * subititle array code. */ - /* Subtitles*/ - //[preset setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"]; - /* Forced Subtitles */ - //[preset setObject:[NSNumber numberWithInt:[fSubForcedCheck state]] forKey:@"SubtitlesForced"]; + /* Subtitles */ + [fSubtitlesViewController prepareSubtitlesForPreset:preset]; } [preset autorelease]; return preset; diff --git a/macosx/English.lproj/Subtitles.xib b/macosx/English.lproj/Subtitles.xib index 924881f80..d9662e04c 100644 --- a/macosx/English.lproj/Subtitles.xib +++ b/macosx/English.lproj/Subtitles.xib @@ -7,7 +7,7 @@ - + @@ -19,79 +19,76 @@ - + - + - + - + - - - - + + + + - + - + - + - - + - + - - + - + - - + - + @@ -102,13 +99,13 @@ - + - + @@ -119,14 +116,14 @@ - + - - + + @@ -136,6 +133,7 @@ + @@ -154,18 +152,79 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/macosx/English.lproj/SubtitlesDefaults.xib b/macosx/English.lproj/SubtitlesDefaults.xib new file mode 100644 index 000000000..4cf0471a4 --- /dev/null +++ b/macosx/English.lproj/SubtitlesDefaults.xib @@ -0,0 +1,192 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + language + isSelected + + + + + + + diff --git a/macosx/HBLanguagesSelection.h b/macosx/HBLanguagesSelection.h new file mode 100644 index 000000000..725fdf9d9 --- /dev/null +++ b/macosx/HBLanguagesSelection.h @@ -0,0 +1,50 @@ +/* HBLanguagesSelection.h $ + + This file is part of the HandBrake source code. + Homepage: . + It may be used under the terms of the GNU General Public License. */ + +#import +#import + +/** + * A collection of KVO enabled model and controllers class + * used to populate the languages selection table view + */ + +/** + * HBLang + */ +@interface HBLang : NSObject + +@property (nonatomic, readwrite) BOOL isSelected; +@property (nonatomic, readonly) NSString *language; +@property (nonatomic, readonly) NSString *iso639_2; + +- (instancetype)initWithLanguage:(NSString *)value iso639_2code:(NSString *)code; + +@end; + +/** + * HBLanguagesSelection + */ +@interface HBLanguagesSelection : NSObject + +@property (nonatomic, readonly) NSMutableArray *languagesArray; +@property (nonatomic, readonly) NSArray *selectedLanguages; + +- (instancetype)initWithLanguages:(NSArray *)languages; + +@end + +/** + * HBLanguageArrayController + */ +@interface HBLanguageArrayController : NSArrayController + +/** + * Set whether to show only the selected languages or all languages + */ +@property (nonatomic, readwrite) BOOL showSelectedOnly; + +@end diff --git a/macosx/HBLanguagesSelection.m b/macosx/HBLanguagesSelection.m new file mode 100644 index 000000000..8a27ad9c1 --- /dev/null +++ b/macosx/HBLanguagesSelection.m @@ -0,0 +1,123 @@ +/* HBLanguagesSelection.m $ + + This file is part of the HandBrake source code. + Homepage: . + It may be used under the terms of the GNU General Public License. */ + +#import "HBLanguagesSelection.h" +#include "lang.h" + +@implementation HBLang + +- (instancetype)initWithLanguage:(NSString *)value iso639_2code:(NSString *)code +{ + self = [super init]; + if (self) + { + _language = [value retain]; + _iso639_2 = [code retain]; + } + return self; +} + +- (void)dealloc +{ + [super dealloc]; + [_language release]; +} + +@end + +@implementation HBLanguagesSelection + +- (instancetype)initWithLanguages:(NSArray *)languages +{ + self = [super init]; + if (self) + { + NSMutableArray *internal = [[NSMutableArray alloc] init]; + + int insertedItems = 0; + const iso639_lang_t *lang = lang_get_next(NULL); + for (lang = lang_get_next(lang); lang != NULL; lang = lang_get_next(lang)) + { + HBLang *item = [[[HBLang alloc] initWithLanguage:@(lang->eng_name) + iso639_2code:@(lang->iso639_2)] autorelease]; + if ([languages containsObject:item.iso639_2]) + { + item.isSelected = YES; + [internal insertObject:item atIndex:insertedItems++]; + } + else + { + [internal addObject:item]; + } + } + + // Add the (Any) item. + HBLang *item = [[[HBLang alloc] initWithLanguage:@"(Any)" + iso639_2code:@"und"] autorelease]; + if ([languages containsObject:item.iso639_2]) + { + item.isSelected = YES; + } + [internal insertObject:item atIndex:0]; + + _languagesArray = internal; + } + + return self; +} + +- (NSArray *)selectedLanguages +{ + NSMutableArray *selected = [[[NSMutableArray alloc] init] autorelease]; + for (HBLang *lang in self.languagesArray) + { + if (lang.isSelected) + { + [selected addObject:lang.iso639_2]; + } + } + + return [[selected copy] autorelease]; +} + +- (void)dealloc +{ + [super dealloc]; + [_languagesArray release]; +} + +@end + +NSString *kHBLanguagesDragRowsType = @"kHBLanguagesDragRowsType"; + +@implementation HBLanguageArrayController + +- (void)setShowSelectedOnly:(BOOL)showSelectedOnly +{ + _showSelectedOnly = showSelectedOnly; + [self rearrangeObjects]; +} + +- (NSArray *)arrangeObjects:(NSArray *)objects +{ + if (!self.showSelectedOnly) { + return [super arrangeObjects:objects]; + } + + // Returns a filtered array with only the selected items + NSMutableArray *filteredObjects = [NSMutableArray arrayWithCapacity:[objects count]]; + for (id item in objects) + { + if ([[item valueForKeyPath:@"isSelected"] boolValue]) + { + [filteredObjects addObject:item]; + } + } + + return [super arrangeObjects:filteredObjects]; +} + +@end diff --git a/macosx/HBQueueController.mm b/macosx/HBQueueController.mm index 120afbda6..5bb1d9a1d 100644 --- a/macosx/HBQueueController.mm +++ b/macosx/HBQueueController.mm @@ -896,7 +896,7 @@ return ![(HBQueueOutlineView*)outlineView isDragging]; NSString * passesString = @""; /* check to see if our first subtitle track is Foreign Language Search, in which case there is an in depth scan */ - if ([item objectForKey:@"SubtitleList"] && [[[[item objectForKey:@"SubtitleList"] objectAtIndex:0] objectForKey:@"subtitleSourceTrackNum"] intValue] == 1) + if ([[item objectForKey:@"SubtitleList"] count] && [[[[item objectForKey:@"SubtitleList"] objectAtIndex:0] objectForKey:@"keySubTrackIndex"] intValue] == -1) { passesString = [passesString stringByAppendingString:@"1 Foreign Language Search Pass - "]; } @@ -1204,28 +1204,22 @@ return ![(HBQueueOutlineView*)outlineView isDragging]; id tempObject; while (tempObject = [enumerator nextObject]) { - /* since the subtitleSourceTrackNum 0 is "None" in our array of the subtitle popups, - * we want to ignore it for display as well as encoding. - */ - if ([[tempObject objectForKey:@"subtitleSourceTrackNum"] intValue] > 0) - { - /* remember that index 0 of Subtitles can contain "Foreign Audio Search*/ - [finalString appendString: @"Subtitle: " withAttributes:detailBoldAttr]; - [finalString appendString: [tempObject objectForKey:@"subtitleSourceTrackName"] withAttributes:detailAttr]; - if ([[tempObject objectForKey:@"subtitleTrackForced"] intValue] == 1) - { - [finalString appendString: @" - Forced Only" withAttributes:detailAttr]; - } - if ([[tempObject objectForKey:@"subtitleTrackBurned"] intValue] == 1) - { - [finalString appendString: @" - Burned In" withAttributes:detailAttr]; - } - if ([[tempObject objectForKey:@"subtitleTrackDefault"] intValue] == 1) - { - [finalString appendString: @" - Default" withAttributes:detailAttr]; - } - [finalString appendString:@"\n" withAttributes:detailAttr]; + /* remember that index 0 of Subtitles can contain "Foreign Audio Search*/ + [finalString appendString: @"Subtitle: " withAttributes:detailBoldAttr]; + [finalString appendString: [tempObject objectForKey:@"keySubTrackName"] withAttributes:detailAttr]; + if ([[tempObject objectForKey:@"keySubTrackForced"] intValue] == 1) + { + [finalString appendString: @" - Forced Only" withAttributes:detailAttr]; + } + if ([[tempObject objectForKey:@"keySubTrackBurned"] intValue] == 1) + { + [finalString appendString: @" - Burned In" withAttributes:detailAttr]; } + if ([[tempObject objectForKey:@"keySubTrackDefault"] intValue] == 1) + { + [finalString appendString: @" - Default" withAttributes:detailAttr]; + } + [finalString appendString:@"\n" withAttributes:detailAttr]; i++; } diff --git a/macosx/HBSubtitlesController.h b/macosx/HBSubtitlesController.h index 66428bf39..71bafe868 100644 --- a/macosx/HBSubtitlesController.h +++ b/macosx/HBSubtitlesController.h @@ -6,6 +6,20 @@ #import +extern NSString *keySubTrackName; +extern NSString *keySubTrackIndex; +extern NSString *keySubTrackLanguage; +extern NSString *keySubTrackLanguageIsoCode; +extern NSString *keySubTrackType; + +extern NSString *keySubTrackForced; +extern NSString *keySubTrackBurned; +extern NSString *keySubTrackDefault; + +extern NSString *keySubTrackSrtOffset; +extern NSString *keySubTrackSrtFilePath; +extern NSString *keySubTrackSrtCharCode; + /** * HBSubtitlesController * Responds to HBContainerChangedNotification and HBTitleChangedNotification notifications. @@ -15,7 +29,10 @@ - (void)enableUI:(BOOL)b; - (void)addTracksFromQueue:(NSMutableArray *)newSubtitleArray; +- (void)applySettingsFromPreset:(NSDictionary *)preset; +- (void)prepareSubtitlesForPreset:(NSMutableDictionary *)preset; + // Get the list of subtitles tracks -@property (readonly, nonatomic) NSArray *subtitleArray; +@property (readonly, nonatomic, copy) NSArray *subtitles; @end diff --git a/macosx/HBSubtitlesController.m b/macosx/HBSubtitlesController.m index 43bed5034..a804de748 100644 --- a/macosx/HBSubtitlesController.m +++ b/macosx/HBSubtitlesController.m @@ -5,24 +5,60 @@ It may be used under the terms of the GNU General Public License. */ #import "HBSubtitlesController.h" +#import "HBSubtitlesDefaultsController.h" +#import "HBSubtitlesSettings.h" + #import "Controller.h" #include "hb.h" #include "lang.h" +NSString *keySubTrackSelectionIndex = @"keySubTrackSelectionIndex"; +NSString *keySubTrackName = @"keySubTrackName"; +NSString *keySubTrackIndex = @"keySubTrackIndex"; +NSString *keySubTrackLanguage = @"keySubTrackLanguage"; +NSString *keySubTrackLanguageIsoCode = @"keySubTrackLanguageIsoCode"; +NSString *keySubTrackType = @"keySubTrackType"; + +NSString *keySubTrackForced = @"keySubTrackForced"; +NSString *keySubTrackBurned = @"keySubTrackBurned"; +NSString *keySubTrackDefault = @"keySubTrackDefault"; + +NSString *keySubTrackSrtOffset = @"keySubTrackSrtOffset"; +NSString *keySubTrackSrtFilePath = @"keySubTrackSrtFilePath"; +NSString *keySubTrackSrtCharCode = @"keySubTrackSrtCharCode"; +NSString *keySubTrackSrtCharCodeIndex = @"keySubTrackSrtCharCodeIndex"; +NSString *keySubTrackLanguageIndex = @"keySubTrackLanguageIndex"; + +#define CHAR_CODE_DEFAULT_INDEX 11 + @interface HBSubtitlesController () -{ - NSMutableArray *subtitleArray; // contains the output subtitle track info - NSMutableArray *subtitleSourceArray;// contains the source subtitle track info - NSString *foreignAudioSearchTrackName; - NSMutableArray *languagesArray; // array of languages taken from lang.c - NSInteger languagesArrayDefIndex; - NSMutableArray *charCodeArray; // array of character codes - int charCodeArrayDefIndex; - int container; -} -@property (assign) IBOutlet NSButton *fBrowseSrtFileButton; +// IBOutles +@property (assign) IBOutlet NSPopUpButton *actionsPopUp; @property (assign) IBOutlet NSTableView *fTableView; +@property (nonatomic, readwrite) BOOL enabled; + +// Subtitles arrays +@property (nonatomic, readonly) NSMutableArray *subtitleArray; +@property (nonatomic, readonly) NSMutableArray *subtitleSourceArray; + +@property (nonatomic, readwrite, retain) NSString *foreignAudioSearchTrackName; +@property (nonatomic, readwrite) int container; + +// Defaults +@property (nonatomic, readwrite, retain) HBSubtitlesDefaultsController *defaultsController; +@property (nonatomic, readwrite, retain) HBSubtitlesSettings *settings; + +// Table view cells models +@property (nonatomic, readonly) NSArray *charCodeArray; +@property (nonatomic, readwrite) BOOL foreignAudioSearchSelected; + +@property (nonatomic, readonly) NSArray *languagesArray; +@property (nonatomic, readonly) NSInteger languagesArrayDefIndex; + +// Cached table view's cells +@property (nonatomic, readonly) NSPopUpButtonCell *languagesCell; +@property (nonatomic, readonly) NSPopUpButtonCell *encodingsCell; @end @@ -33,127 +69,79 @@ self = [super initWithNibName:@"Subtitles" bundle:nil]; if (self) { - /* setup our array of languages */ - const iso639_lang_t *lang; - languagesArray = [[NSMutableArray alloc] init]; - for (lang = lang_get_next(NULL); lang != NULL; lang = lang_get_next(lang)) - { - [languagesArray addObject:[NSArray arrayWithObjects: - [NSString stringWithUTF8String:lang->eng_name], - [NSString stringWithUTF8String:lang->iso639_2], - nil]]; - if (!strcasecmp(lang->eng_name, "English")) - { - languagesArrayDefIndex = [languagesArray count] - 1; - } - } - - /* populate the charCodeArray */ - charCodeArray = [[NSMutableArray alloc] init]; - [charCodeArray addObject:@"ANSI_X3.4-1968"]; - [charCodeArray addObject:@"ANSI_X3.4-1986"]; - [charCodeArray addObject:@"ANSI_X3.4"]; - [charCodeArray addObject:@"ANSI_X3.110-1983"]; - [charCodeArray addObject:@"ANSI_X3.110"]; - [charCodeArray addObject:@"ASCII"]; - [charCodeArray addObject:@"ECMA-114"]; - [charCodeArray addObject:@"ECMA-118"]; - [charCodeArray addObject:@"ECMA-128"]; - [charCodeArray addObject:@"ECMA-CYRILLIC"]; - [charCodeArray addObject:@"IEC_P27-1"]; - [charCodeArray addObject:@"ISO-8859-1"]; - [charCodeArray addObject:@"ISO-8859-2"]; - [charCodeArray addObject:@"ISO-8859-3"]; - [charCodeArray addObject:@"ISO-8859-4"]; - [charCodeArray addObject:@"ISO-8859-5"]; - [charCodeArray addObject:@"ISO-8859-6"]; - [charCodeArray addObject:@"ISO-8859-7"]; - [charCodeArray addObject:@"ISO-8859-8"]; - [charCodeArray addObject:@"ISO-8859-9"]; - [charCodeArray addObject:@"ISO-8859-9E"]; - [charCodeArray addObject:@"ISO-8859-10"]; - [charCodeArray addObject:@"ISO-8859-11"]; - [charCodeArray addObject:@"ISO-8859-13"]; - [charCodeArray addObject:@"ISO-8859-14"]; - [charCodeArray addObject:@"ISO-8859-15"]; - [charCodeArray addObject:@"ISO-8859-16"]; - [charCodeArray addObject:@"UTF-7"]; - [charCodeArray addObject:@"UTF-8"]; - [charCodeArray addObject:@"UTF-16"]; - [charCodeArray addObject:@"UTF-16LE"]; - [charCodeArray addObject:@"UTF-16BE"]; - [charCodeArray addObject:@"UTF-32"]; - [charCodeArray addObject:@"UTF-32LE"]; - [charCodeArray addObject:@"UTF-32BE"]; - - charCodeArrayDefIndex = 11; - + _subtitleSourceArray = [[NSMutableArray alloc] init]; + _subtitleArray = [[NSMutableArray alloc] init]; + _languagesArray = [[self populateLanguageArray] retain]; + + // populate the charCodeArray. + _charCodeArray = [@[@"ANSI_X3.4-1968", @"ANSI_X3.4-1986", @"ANSI_X3.4", @"ANSI_X3.110-1983", @"ANSI_X3.110", @"ASCII", + @"ECMA-114", @"ECMA-118", @"ECMA-128", @"ECMA-CYRILLIC", @"IEC_P27-1", @"ISO-8859-1", @"ISO-8859-2", + @"ISO-8859-3", @"ISO-8859-4", @"ISO-8859-5", @"ISO-8859-6", @"ISO-8859-7", @"ISO-8859-8", @"ISO-8859-9", + @"ISO-8859-9E", @"ISO-8859-10", @"ISO-8859-11", @"ISO-8859-13", @"ISO-8859-14", @"ISO-8859-15", @"ISO-8859-16", + @"UTF-7", @"UTF-8", @"UTF-16", @"UTF-16LE", @"UTF-16BE", @"UTF-32", @"UTF-32LE", @"UTF-32BE"] retain]; + + // Register as observer for the HBController notifications. [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(containerChanged:) name: HBContainerChangedNotification object: nil]; - [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(titleChanged:) name: HBTitleChangedNotification object: nil]; + [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(titleChanged:) name: HBTitleChangedNotification object: nil]; } return self; } +- (void)enableUI:(BOOL)b +{ + [self.actionsPopUp setEnabled:b]; + [self.fTableView setEnabled:b]; + self.enabled = b; +} + - (void)titleChanged:(NSNotification *)aNotification { NSDictionary *notDict = [aNotification userInfo]; - NSData *theData = [notDict objectForKey: keyTitleTag]; + NSData *theData = notDict[keyTitleTag]; hb_title_t *title = NULL; - [theData getBytes: &title length: sizeof(title)]; + + /* reset the subtitles arrays */ + [self.subtitleArray removeAllObjects]; + [self.subtitleSourceArray removeAllObjects]; + if (title) { - /* reset the subtitle source array */ - if (subtitleSourceArray) - { - [subtitleSourceArray release]; - } - subtitleSourceArray = [[NSMutableArray alloc] init]; - /* now populate the array with the source subtitle track info */ - int i; - hb_subtitle_t *subtitle; NSMutableArray *forcedSourceNamesArray = [[NSMutableArray alloc] init]; - for (i = 0; i < hb_list_count(title->list_subtitle); i++) + for (int i = 0; i < hb_list_count(title->list_subtitle); i++) { - subtitle = (hb_subtitle_t*)hb_list_item(title->list_subtitle, i); + hb_subtitle_t *subtitle = (hb_subtitle_t *)hb_list_item(title->list_subtitle, i); /* Human-readable representation of subtitle->source */ NSString *bitmapOrText = subtitle->format == PICTURESUB ? @"Bitmap" : @"Text"; - NSString *subSourceName = [NSString stringWithUTF8String:hb_subsource_name(subtitle->source)]; + NSString *subSourceName = @(hb_subsource_name(subtitle->source)); + /* if the subtitle track can be forced, add its source name to the array */ - if (hb_subtitle_can_force(subtitle->source) && - [forcedSourceNamesArray containsObject:subSourceName] == NO) + if (hb_subtitle_can_force(subtitle->source) && [forcedSourceNamesArray containsObject:subSourceName] == NO) { [forcedSourceNamesArray addObject:subSourceName]; } /* create a dictionary of source subtitle information to store in our array */ - NSMutableDictionary *newSubtitleSourceTrack = [[NSMutableDictionary alloc] init]; - /* Subtitle Source track name */ - [newSubtitleSourceTrack setObject:[NSString stringWithFormat:@"%d - %@ - (%@) (%@)", - i, [NSString stringWithUTF8String:subtitle->lang], - bitmapOrText,subSourceName] - forKey:@"sourceTrackName"]; - /* Subtitle Source track number, type and features */ - [newSubtitleSourceTrack setObject:[NSNumber numberWithInt:i] forKey:@"sourceTrackNum"]; - [newSubtitleSourceTrack setObject:[NSNumber numberWithInt:subtitle->source] forKey:@"sourceTrackType"]; - [subtitleSourceArray addObject:newSubtitleSourceTrack]; - [newSubtitleSourceTrack autorelease]; + [self.subtitleSourceArray addObject:@{keySubTrackName: [NSString stringWithFormat:@"%d: %@ (%@) (%@)", i, @(subtitle->lang), bitmapOrText, subSourceName], + keySubTrackIndex: @(i), + keySubTrackType: @(subtitle->source), + keySubTrackLanguage: @(subtitle->lang), + keySubTrackLanguageIsoCode: @(subtitle->iso639_2)}]; } /* now set the name of the Foreign Audio Search track */ if ([forcedSourceNamesArray count]) { [forcedSourceNamesArray sortUsingComparator:^(id obj1, id obj2) - { - return [((NSString*)obj1) compare:((NSString*)obj2)]; - }]; - NSString *tempString; - NSString *tempList = @""; - NSEnumerator *enumerator = [forcedSourceNamesArray objectEnumerator]; - while (tempString = (NSString*)[enumerator nextObject]) + { + return [((NSString *)obj1) compare:((NSString *)obj2)]; + }]; + + NSString *tempList = @""; + for (NSString *tempString in forcedSourceNamesArray) { if ([tempList length]) { @@ -161,521 +149,542 @@ } tempList = [tempList stringByAppendingString:tempString]; } - [foreignAudioSearchTrackName release]; - foreignAudioSearchTrackName = [[NSString stringWithFormat:@"Foreign Audio Search - (Bitmap) (%@)", tempList] - retain]; + self.foreignAudioSearchTrackName = [NSString stringWithFormat:@"Foreign Audio Search (Bitmap) (%@)", tempList]; } else { - [foreignAudioSearchTrackName release]; - foreignAudioSearchTrackName = @"Foreign Audio Search - (Bitmap)"; + self.foreignAudioSearchTrackName = @"Foreign Audio Search (Bitmap)"; } [forcedSourceNamesArray release]; - - /* reset the subtitle output array */ - if (subtitleArray) - { - [subtitleArray release]; - } - subtitleArray = [[NSMutableArray alloc] init]; - [self addSubtitleTrack]; - } - else - { - [subtitleArray removeAllObjects]; - [subtitleSourceArray removeAllObjects]; + + // Append an empty track at the end + // to display a "None" row in the table view + [self.subtitleArray addObject:[self createSubtitleTrack]]; } [self.fTableView reloadData]; } -- (void)enableUI:(BOOL)b +- (void)containerChanged:(NSNotification *)aNotification { - [self.fBrowseSrtFileButton setEnabled:b]; - [self.fTableView setEnabled:b]; -} + NSDictionary *notDict = [aNotification userInfo]; + self.container = [notDict[keyContainerTag] intValue]; -#pragma mark - -#pragma mark Create new Subtitles + [self validatePassthru]; -- (void)addSubtitleTrack -{ - [subtitleArray addObject:[self createSubtitleTrack]]; + [self.fTableView reloadData]; } -/* Creates a new subtitle track and stores it in an NSMutableDictionary */ -- (NSDictionary *)createSubtitleTrack +- (NSArray *)subtitles { - NSMutableDictionary *newSubtitleTrack = [[NSMutableDictionary alloc] init]; - /* Subtitle Source track popup index */ - [newSubtitleTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleSourceTrackNum"]; - /* Subtitle Source track popup language */ - [newSubtitleTrack setObject:@"None" forKey:@"subtitleSourceTrackName"]; - /* Subtitle track forced state */ - [newSubtitleTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackForced"]; - /* Subtitle track burned state */ - [newSubtitleTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackBurned"]; - /* Subtitle track default state */ - [newSubtitleTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackDefault"]; - - [newSubtitleTrack autorelease]; - return newSubtitleTrack; + NSMutableArray *ret = [self.subtitleArray mutableCopy]; + [ret removeLastObject]; + return [ret autorelease]; } -- (void)createSubtitleSrtTrack:(NSURL *)fileURL +- (void)addTracksFromQueue:(NSMutableArray *)newSubtitleArray { - /* Create a new entry for the subtitle source array so it shows up in our subtitle source list */ - NSString *displayname = [fileURL lastPathComponent];// grok an appropriate display name from the srt subtitle */ - /* create a dictionary of source subtitle information to store in our array */ - NSMutableDictionary *newSubtitleSourceTrack = [[NSMutableDictionary alloc] init]; - /* Subtitle Source track popup index */ - [newSubtitleSourceTrack setObject:[NSNumber numberWithInteger:[subtitleSourceArray count]+1] forKey:@"sourceTrackNum"]; - /* Subtitle Source track name */ - [newSubtitleSourceTrack setObject:displayname forKey:@"sourceTrackName"]; - /* Subtitle Source track type (VobSub, Srt, etc.) */ - [newSubtitleSourceTrack setObject:[NSNumber numberWithInt:SRTSUB] forKey:@"sourceTrackType"]; - [newSubtitleSourceTrack setObject:[NSNumber numberWithInt:SRTSUB] forKey:@"subtitleSourceTrackType"]; - /* Subtitle Source file path */ - [newSubtitleSourceTrack setObject:[fileURL path] forKey:@"sourceSrtFilePath"]; - - [subtitleSourceArray addObject:newSubtitleSourceTrack]; - [newSubtitleSourceTrack autorelease]; - - /* Now create a new srt subtitle dictionary assuming the user wants to add it to their list - * Note: the subtitle array always has last entry for "None", so we need to replace its - * position in the array and tack a "None" track back on the end of the list */ - [subtitleArray removeObjectAtIndex:[subtitleArray count] - 1]; - - - NSMutableDictionary *newSubtitleSrtTrack = [[NSMutableDictionary alloc] init]; - /* Subtitle Source track popup index */ - if ([subtitleArray count] == 0) // we now have an empty array so this will be our first track - { - [newSubtitleSrtTrack setObject:[NSNumber numberWithInteger:[subtitleSourceArray count] + 1] forKey:@"subtitleSourceTrackNum"]; - } - else + /* Note: we need to look for external subtitles so it can be added to the source array track. + * Remember the source container subs are already loaded with resetTitle which is already called + * so any external sub sources need to be added to our source subs here + */ + for (id tempObject in newSubtitleArray) { - [newSubtitleSrtTrack setObject:[NSNumber numberWithInteger:[subtitleSourceArray count]] forKey:@"subtitleSourceTrackNum"]; + /* We have an srt track */ + if ([tempObject[keySubTrackType] intValue] == SRTSUB) + { + NSString *filePath = tempObject[keySubTrackSrtFilePath]; + /* create a dictionary of source subtitle information to store in our array */ + [self.subtitleSourceArray addObject:@{keySubTrackIndex: @(self.subtitleSourceArray.count + 1), + keySubTrackName: [filePath lastPathComponent], + keySubTrackType: @(SRTSUB), + keySubTrackSrtFilePath: filePath}]; + } } - [newSubtitleSrtTrack setObject:[NSNumber numberWithInt:SRTSUB] forKey:@"sourceTrackType"]; - [newSubtitleSrtTrack setObject:[NSNumber numberWithInt:SRTSUB] forKey:@"subtitleSourceTrackType"]; - /* Subtitle Source track popup language */ - [newSubtitleSrtTrack setObject:displayname forKey:@"subtitleSourceTrackName"]; - /* Subtitle track forced state */ - [newSubtitleSrtTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackForced"]; - /* Subtitle track burned state */ - [newSubtitleSrtTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackBurned"]; - /* Subtitle track default state */ - [newSubtitleSrtTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackDefault"]; - - /* now the srt only info, Language, Chart Code and offset */ - [newSubtitleSrtTrack setObject:[fileURL path] forKey:@"subtitleSourceSrtFilePath"]; - [newSubtitleSrtTrack setObject:[NSNumber numberWithInteger:languagesArrayDefIndex] forKey:@"subtitleTrackSrtLanguageIndex"]; - [newSubtitleSrtTrack setObject:[[languagesArray objectAtIndex:languagesArrayDefIndex] objectAtIndex:0] forKey:@"subtitleTrackSrtLanguageLong"]; - [newSubtitleSrtTrack setObject:[[languagesArray objectAtIndex:languagesArrayDefIndex] objectAtIndex:1] forKey:@"subtitleTrackSrtLanguageIso3"]; - - [newSubtitleSrtTrack setObject:[NSNumber numberWithInt:charCodeArrayDefIndex] forKey:@"subtitleTrackSrtCharCodeIndex"]; - [newSubtitleSrtTrack setObject:[charCodeArray objectAtIndex:charCodeArrayDefIndex] forKey:@"subtitleTrackSrtCharCode"]; - - [newSubtitleSrtTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackSrtOffset"]; + [newSubtitleArray addObject:[self createSubtitleTrack]]; + // Set the subtitleArray to the newSubtitleArray + [self.subtitleArray setArray:newSubtitleArray]; + [self.fTableView reloadData]; +} - [subtitleArray addObject:newSubtitleSrtTrack]; - [newSubtitleSrtTrack release]; +- (void)applySettingsFromPreset:(NSDictionary *)preset +{ + self.settings = [[[HBSubtitlesSettings alloc] init] autorelease]; + [self.settings applySettingsFromPreset:preset]; - /* now add back the none track to the end of the array */ - [self addSubtitleTrack]; + [self addTracksFromDefaults:self]; } -/* used to return the current subtitleArray to controller.m */ -- (NSMutableArray *) subtitleArray +- (void)prepareSubtitlesForPreset:(NSMutableDictionary *)preset { - return subtitleArray; + [self.settings prepareSubtitlesForPreset:preset]; } -// This gets called whenever the video container changes. -- (void) containerChanged: (NSNotification *) aNotification +#pragma mark - Actions +- (BOOL)validateUserInterfaceItem:(id < NSValidatedUserInterfaceItem >)anItem { - NSDictionary *notDict = [aNotification userInfo]; - - container = [[notDict objectForKey: keyContainerTag] intValue]; - [self.fTableView reloadData]; + return self.enabled; } -- (void)addTracksFromQueue:(NSMutableArray *)newSubtitleArray +/** + * Add every subtitles track that still isn't in the subtitles array. + */ +- (IBAction)addAll:(id)sender { - /* Note: we need to look for external subtitles so it can be added to the source array track. - * Remember the source container subs are already loaded with resetTitle which is already called - * so any external sub sources need to be added to our source subs here - */ + [self.subtitleArray removeAllObjects]; + + // Add the foreign audio search pass + [self addTrack:[self trackFromSourceTrackIndex:-1]]; - int i = 0; - for ( id tempObject in newSubtitleArray ) + // Add the remainings tracks + for (NSDictionary *track in self.subtitleSourceArray) { - /* We have an srt track */ - if ([[tempObject objectForKey:@"subtitleSourceTrackType"] intValue] == SRTSUB) - { - NSString *filePath = [tempObject objectForKey:@"subtitleSourceSrtFilePath"]; - /* Start replicate the add new srt code above */ - /* Create a new entry for the subtitle source array so it shows up in our subtitle source list */ - NSString *displayname = [filePath lastPathComponent];// grok an appropriate display name from the srt subtitle */ - /* create a dictionary of source subtitle information to store in our array */ - NSMutableDictionary *newSubtitleSourceTrack = [[NSMutableDictionary alloc] init]; - /* Subtitle Source track popup index */ - [newSubtitleSourceTrack setObject:[NSNumber numberWithInteger:[subtitleSourceArray count]+1] forKey:@"sourceTrackNum"]; - /* Subtitle Source track name */ - [newSubtitleSourceTrack setObject:displayname forKey:@"sourceTrackName"]; - /* Subtitle Source track type (VobSub, Srt, etc.) */ - [newSubtitleSourceTrack setObject:[NSNumber numberWithInt:SRTSUB] forKey:@"sourceTrackType"]; - [newSubtitleSourceTrack setObject:[NSNumber numberWithInt:SRTSUB] forKey:@"subtitleSourceTrackType"]; - /* Subtitle Source file path */ - [newSubtitleSourceTrack setObject:filePath forKey:@"sourceSrtFilePath"]; - - [subtitleSourceArray addObject:newSubtitleSourceTrack]; - [newSubtitleSourceTrack autorelease]; - /* END replicate the add new srt code above */ - } - i++; - } - - /*Set the subtitleArray to the newSubtitleArray */ - [subtitleArray setArray:newSubtitleArray]; + NSInteger sourceIndex = [track[keySubTrackIndex] integerValue]; + [self addTrack:[self trackFromSourceTrackIndex:sourceIndex]]; + } + + [self.subtitleArray addObject:[self createSubtitleTrack]]; + [self validatePassthru]; [self.fTableView reloadData]; } -#pragma mark - Srt import +/** + * Remove all the subtitles tracks. + */ +- (IBAction)removeAll:(id)sender +{ + [self.subtitleArray removeAllObjects]; + [self.subtitleArray addObject:[self createSubtitleTrack]]; + [self.fTableView reloadData]; +} -- (IBAction)browseImportSrtFile:(id)sender +/** + * Remove all the subtitles tracks and + * add new ones based on the defaults settings + */ +- (IBAction)addTracksFromDefaults:(id)sender { - NSOpenPanel *panel = [NSOpenPanel openPanel]; - [panel setAllowsMultipleSelection:NO]; - [panel setCanChooseFiles:YES]; - [panel setCanChooseDirectories:NO]; + [self.subtitleArray removeAllObjects]; - NSURL *sourceDirectory; - if ([[NSUserDefaults standardUserDefaults] URLForKey:@"LastSrtImportDirectoryURL"]) - { - sourceDirectory = [[NSUserDefaults standardUserDefaults] URLForKey:@"LastSrtImportDirectoryURL"]; - } - else - { - sourceDirectory = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"]; - } + // Add the foreign audio search pass + if (self.settings.addForeignAudioSearch) + { + [self addTrack:[self trackFromSourceTrackIndex:-1]]; + } - /* we open up the browse srt sheet here and call for browseImportSrtFileDone after the sheet is closed */ - NSArray *fileTypes = [NSArray arrayWithObjects:@"plist", @"srt", nil]; - [panel setDirectoryURL:sourceDirectory]; - [panel setAllowedFileTypes:fileTypes]; - [panel beginSheetModalForWindow:[[self view] window] completionHandler:^(NSInteger result) { - if (result == NSOKButton) + // If the languages list contains the "(Any)" language, remove all the others + NSArray *languages = nil; + if ([self.settings.trackSelectionLanguages containsObject:@"und"]) + { + languages = @[@"und"]; + } + else + { + languages = self.settings.trackSelectionLanguages; + } + + // Add the tracks for the selected languages + if (self.settings.trackSelectionBehavior != HBSubtitleTrackSelectionBehaviorNone) + { + for (NSString *lang in languages) { - NSURL *importSrtFileURL = [panel URL]; - NSURL *importSrtDirectory = [importSrtFileURL URLByDeletingLastPathComponent]; - [[NSUserDefaults standardUserDefaults] setURL:importSrtDirectory forKey:@"LastSrtImportDirectoryURL"]; + NSInteger sourceIndex = 0; + for (NSDictionary *track in self.subtitleSourceArray) + { + if ([lang isEqualToString:@"und"] || [track[keySubTrackLanguageIsoCode] isEqualToString:lang]) + { + [self addTrack:[self trackFromSourceTrackIndex:sourceIndex]]; - /* now pass the string off to fSubtitlesDelegate to add the srt file to the dropdown */ - [self createSubtitleSrtTrack:importSrtFileURL]; + if (self.settings.trackSelectionBehavior == HBSubtitleTrackSelectionBehaviorFirst) + { + break; + } + } + sourceIndex++; + } + } + } - [self.fTableView reloadData]; + // Add the closed captions track if there is one. + if (self.settings.addCC) + { + NSInteger sourceIndex = 0; + for (NSDictionary *track in self.subtitleSourceArray) + { + if ([track[keySubTrackType] intValue] == CC608SUB) + { + [self addTrack:[self trackFromSourceTrackIndex:sourceIndex]]; + break; + } + sourceIndex++; } - }]; + } + + [self.subtitleArray addObject:[self createSubtitleTrack]]; + [self validatePassthru]; + [self.fTableView reloadData]; } -#pragma mark - -#pragma mark Subtitle Table Delegate Methods -/* Table View delegate methods */ -/* Returns the number of tracks displayed - * NOTE: we return one more than the actual number of tracks - * specified as we always keep one track set to "None" which is ignored - * for setting up tracks, but is used to add tracks. +- (IBAction)showSettingsSheet:(id)sender +{ + self.defaultsController = [[[HBSubtitlesDefaultsController alloc] initWithSettings:self.settings] autorelease]; + self.defaultsController.delegate = self; + + [NSApp beginSheet:[self.defaultsController window] + modalForWindow:[[self view] window] + modalDelegate:self + didEndSelector:NULL + contextInfo:NULL]; +} + +- (void)sheetDidEnd +{ + self.defaultsController = nil; +} + +#pragma mark - Subtitles tracks creation and validation + +/** + * Convenience method to add a track to subtitlesArray. + * It calculates the keySubTrackSelectionIndex. + * + * @param track the track to add. */ -- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView +- (void)addTrack:(NSMutableDictionary *)newTrack { - return [subtitleArray count]; + newTrack[keySubTrackSelectionIndex] = @([newTrack[keySubTrackIndex] integerValue] + 1 + (self.subtitleArray.count == 0)); + [self.subtitleArray addObject:newTrack]; } -/* Used to tell the Table view which information is to be displayed per item */ -- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex +/** + * Creates a new subtitle track. + */ +- (NSMutableDictionary *)createSubtitleTrack { - NSString *cellEntry = @"__DATA ERROR__"; + NSMutableDictionary *newSubtitleTrack = [[NSMutableDictionary alloc] init]; + newSubtitleTrack[keySubTrackIndex] = @0; + newSubtitleTrack[keySubTrackSelectionIndex] = @0; + newSubtitleTrack[keySubTrackName] = @"None"; + newSubtitleTrack[keySubTrackForced] = @0; + newSubtitleTrack[keySubTrackBurned] = @0; + newSubtitleTrack[keySubTrackDefault] = @0; + + return [newSubtitleTrack autorelease]; +} - /* we setup whats displayed given the column identifier */ - if ([[aTableColumn identifier] isEqualToString:@"track"]) +/** + * Creates a new track dictionary from a source track. + * + * @param index the index of the source track in the subtitlesSourceArray, + * -1 means a Foreign Audio Search pass. + * + * @return a new mutable track dictionary. + */ +- (NSMutableDictionary *)trackFromSourceTrackIndex:(NSInteger)index +{ + NSMutableDictionary *track = [self createSubtitleTrack]; + + if (index == -1) { - /* 'track' is a popup of all available source subtitle tracks for the given title */ - NSPopUpButtonCell *cellTrackPopup = [[NSPopUpButtonCell alloc] init]; - [cellTrackPopup autorelease]; - /* Set the Popups properties */ - [cellTrackPopup setControlSize:NSSmallControlSize]; - [cellTrackPopup setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; + /* + * we are foreign lang search, which is inherently bitmap + * + * since it can be either VOBSUB or PGS and the latter can't be + * passed through to MP4, we need to know whether there are any + * PGS tracks in the source - otherwise we can just set the + * source track type to VOBSUB + */ + int subtitleTrackType = VOBSUB; + if ([self.foreignAudioSearchTrackName rangeOfString:@(hb_subsource_name(PGSSUB))].location != NSNotFound) + { + subtitleTrackType = PGSSUB; + } + // Use -1 to indicate the foreign lang search + track[keySubTrackIndex] = @(-1); + track[keySubTrackName] = self.foreignAudioSearchTrackName; + track[keySubTrackType] = @(subtitleTrackType); + // foreign lang search is most useful when combined w/Forced Only - make it default + track[keySubTrackForced] = @1; + } + else + { + NSDictionary *sourceTrack = self.subtitleSourceArray[index]; + track[keySubTrackIndex] = @(index); + track[keySubTrackName] = sourceTrack[keySubTrackName]; - /* Add our initial "None" track which we use to add source tracks or remove tracks. - * "None" is always index 0. - */ - [[cellTrackPopup menu] addItemWithTitle: @"None" action: NULL keyEquivalent: @""]; + /* check to see if we are an srt, in which case set our file path and source track type kvp's*/ + if ([self.subtitleSourceArray[index][keySubTrackType] intValue] == SRTSUB) + { + track[keySubTrackType] = @(SRTSUB); + track[keySubTrackSrtFilePath] = sourceTrack[keySubTrackSrtFilePath]; - /* Foreign Audio Search (index 1 in the popup) is only available for the first track */ - if (rowIndex == 0) + track[keySubTrackLanguageIndex] = @(self.languagesArrayDefIndex); + track[keySubTrackLanguageIsoCode] = self.languagesArray[self.languagesArrayDefIndex][1]; + + track[keySubTrackSrtCharCodeIndex] = @(CHAR_CODE_DEFAULT_INDEX); + track[keySubTrackSrtCharCode] = self.charCodeArray[CHAR_CODE_DEFAULT_INDEX]; + } + else + { + track[keySubTrackType] = sourceTrack[keySubTrackType]; + } + } + + if (!hb_subtitle_can_burn([track[keySubTrackType] intValue])) + { + /* the source track cannot be burned in, so uncheck the widget */ + track[keySubTrackBurned] = @0; + } + + if (!hb_subtitle_can_force([track[keySubTrackType] intValue])) + { + /* the source track does not support forced flags, so uncheck the widget */ + track[keySubTrackForced] = @0; + } + + return track; +} + +/** + * Checks whether any subtitles in the list cannot be passed through. + * Set the first of any such subtitles to burned-in, remove the others. + */ +- (void)validatePassthru +{ + int subtitleTrackType; + BOOL convertToBurnInUsed = NO; + NSMutableArray *tracksToDelete = [[NSMutableArray alloc] init]; + + // convert any non-None incompatible tracks to burn-in or remove them + for (id tempObject in self.subtitleArray) + { + if (tempObject[keySubTrackType] == nil) { - // TODO: hide the track when no force-able subtitles are present in the source - [[cellTrackPopup menu] addItemWithTitle:foreignAudioSearchTrackName - action:NULL - keyEquivalent:@""]; + continue; } - int i; - for(i = 0; i < [subtitleSourceArray count]; i++ ) + subtitleTrackType = [tempObject[keySubTrackType] intValue]; + if (!hb_subtitle_can_pass(subtitleTrackType, self.container)) { - [[cellTrackPopup menu] addItemWithTitle: [[subtitleSourceArray objectAtIndex:i] objectForKey: @"sourceTrackName"] action: NULL keyEquivalent: @""]; + if (convertToBurnInUsed == NO) + { + //we haven't set any track to burned-in yet, so we can + tempObject[keySubTrackBurned] = @1; + convertToBurnInUsed = YES; //remove any additional tracks + } + else + { + //we already have a burned-in track, we must remove others + [tracksToDelete addObject:tempObject]; + } } + } + //if we converted a track to burned-in, unset it for tracks that support passthru + if (convertToBurnInUsed == YES) + { + for (id tempObject in self.subtitleArray) + { + if (tempObject[keySubTrackType] == nil) + { + continue; + } + subtitleTrackType = [tempObject[keySubTrackType] intValue]; + if (hb_subtitle_can_pass(subtitleTrackType, self.container)) + { + tempObject[keySubTrackBurned] = @0; + } + } + } - [aTableColumn setDataCell:cellTrackPopup]; + if (tracksToDelete.count) + { + [self.subtitleArray removeObjectsInArray:tracksToDelete]; + [self.fTableView reloadData]; + } + [tracksToDelete release]; +} + +- (void)validateBurned:(NSInteger)index +{ + [self.subtitleArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) + { + if (idx != index) + { + obj[keySubTrackBurned] = @0; + } + }]; + [self validatePassthru]; +} + +- (void)validateDefault:(NSInteger)index +{ + [self.subtitleArray enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) + { + if (idx != index) + { + obj[keySubTrackDefault] = @0; + } + }]; +} + +#pragma mark - +#pragma mark Subtitle Table Data Source Methods + +- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView +{ + return self.subtitleArray.count; +} + +- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex +{ + NSDictionary *track = self.subtitleArray[rowIndex]; + + if ([[aTableColumn identifier] isEqualToString:@"track"]) + { + NSNumber *index = track[keySubTrackSelectionIndex]; + if (index) + return index; + else + return @0; } else if ([[aTableColumn identifier] isEqualToString:@"forced"]) { - /* 'forced' is a checkbox to determine if a given source track is only to be forced */ - NSButtonCell *cellForcedCheckBox = [[NSButtonCell alloc] init]; - [cellForcedCheckBox autorelease]; - [cellForcedCheckBox setButtonType:NSSwitchButton]; - [cellForcedCheckBox setImagePosition:NSImageOnly]; - [cellForcedCheckBox setAllowsMixedState:NO]; - [aTableColumn setDataCell:cellForcedCheckBox]; - + return track[keySubTrackForced]; } else if ([[aTableColumn identifier] isEqualToString:@"burned"]) { - /* 'burned' is a checkbox to determine if a given source track is only to be burned */ - NSButtonCell *cellBurnedCheckBox = [[NSButtonCell alloc] init]; - [cellBurnedCheckBox autorelease]; - [cellBurnedCheckBox setButtonType:NSSwitchButton]; - [cellBurnedCheckBox setImagePosition:NSImageOnly]; - [cellBurnedCheckBox setAllowsMixedState:NO]; - [aTableColumn setDataCell:cellBurnedCheckBox]; + return track[keySubTrackBurned]; } else if ([[aTableColumn identifier] isEqualToString:@"default"]) { - NSButtonCell *cellDefaultCheckBox = [[NSButtonCell alloc] init]; - [cellDefaultCheckBox autorelease]; - [cellDefaultCheckBox setButtonType:NSSwitchButton]; - [cellDefaultCheckBox setImagePosition:NSImageOnly]; - [cellDefaultCheckBox setAllowsMixedState:NO]; - [aTableColumn setDataCell:cellDefaultCheckBox]; + return track[keySubTrackDefault]; } /* These next three columns only apply to srt's. they are disabled for source subs */ else if ([[aTableColumn identifier] isEqualToString:@"srt_lang"]) { - /* 'srt_lang' is a popup of commonly used languages to be matched to the source srt file */ - NSPopUpButtonCell *cellSrtLangPopup = [[NSPopUpButtonCell alloc] init]; - [cellSrtLangPopup autorelease]; - /* Set the Popups properties */ - [cellSrtLangPopup setControlSize:NSSmallControlSize]; - [cellSrtLangPopup setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; - /* list our languages as per the languagesArray */ - int i; - for(i = 0; i < [languagesArray count]; i++ ) + if ([track[keySubTrackType] intValue] == SRTSUB) + { + return track[keySubTrackLanguageIndex]; + } + else { - [[cellSrtLangPopup menu] addItemWithTitle: [[languagesArray objectAtIndex:i] objectAtIndex:0] action: NULL keyEquivalent: @""]; + return @0; } - [aTableColumn setDataCell:cellSrtLangPopup]; } else if ([[aTableColumn identifier] isEqualToString:@"srt_charcode"]) { - /* 'srt_charcode' is a popup of commonly used character codes to be matched to the source srt file */ - NSPopUpButtonCell *cellSrtCharCodePopup = [[NSPopUpButtonCell alloc] init]; - [cellSrtCharCodePopup autorelease]; - /* Set the Popups properties */ - [cellSrtCharCodePopup setControlSize:NSSmallControlSize]; - [cellSrtCharCodePopup setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; - /* list our character codes, as per charCodeArray */ - - int i; - for(i = 0; i < [charCodeArray count]; i++ ) + if ([track[keySubTrackType] intValue] == SRTSUB) { - [[cellSrtCharCodePopup menu] addItemWithTitle: [charCodeArray objectAtIndex:i] action: NULL keyEquivalent: @""]; + return track[keySubTrackSrtCharCodeIndex]; + } + else + { + return @0; } - [aTableColumn setDataCell:cellSrtCharCodePopup]; - } else if ([[aTableColumn identifier] isEqualToString:@"srt_offset"]) { - if ([[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackSrtOffset"]) + if (track[keySubTrackSrtOffset]) { - cellEntry = [NSString stringWithFormat:@"%d",[[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackSrtOffset"] intValue]]; + return [track[keySubTrackSrtOffset] stringValue]; } else { - cellEntry = [NSString stringWithFormat:@"%d",0]; + return @"0"; } } - else - { - cellEntry = nil; - } - return cellEntry; + return nil; } -/* Called whenever a widget in the table is edited or changed, we use it to record the change in the controlling array - * including removing and adding new tracks via the "None" ("track" index of 0) */ +/** + * Called whenever a widget in the table is edited or changed, we use it to record the change in the controlling array + * including removing and adding new tracks via the "None" ("track" index of 0) + */ - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { - if ([[aTableColumn identifier] isEqualToString:@"track"]) { - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:[anObject intValue]] forKey:@"subtitleSourceTrackNum"]; /* Set the array to track if we are vobsub (picture sub) */ - if ([anObject intValue] != 0) + if ([anObject intValue] > 0) { - /* The first row has an additional track (Foreign Audio Search) */ - int sourceSubtitleIndex = [anObject intValue] - 1 - (rowIndex == 0); - - if(rowIndex == 0 && [anObject intValue] == 1) - { - /* - * we are foreign lang search, which is inherently bitmap - * - * since it can be either VOBSUB or PGS and the latter can't be - * passed through to MP4, we need to know whether there are any - * PGS tracks in the source - otherwise we can just set the - * source track type to VOBSUB - */ - int subtitleTrackType = VOBSUB; - if ([foreignAudioSearchTrackName rangeOfString: - [NSString stringWithUTF8String: - hb_subsource_name(PGSSUB)]].location != NSNotFound) - { - subtitleTrackType = PGSSUB; - } - // now set the track type - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:subtitleTrackType] forKey:@"subtitleSourceTrackType"]; - // foreign lang search is most useful when combined w/Forced Only - make it default - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:1] forKey:@"subtitleTrackForced"]; - } - /* check to see if we are an srt, in which case set our file path and source track type kvp's*/ - else if ([[[subtitleSourceArray objectAtIndex:sourceSubtitleIndex] objectForKey:@"sourceTrackType"] intValue] == SRTSUB) - { - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:SRTSUB] - forKey:@"subtitleSourceTrackType"]; - [[subtitleArray objectAtIndex:rowIndex] setObject:[[subtitleSourceArray objectAtIndex:sourceSubtitleIndex] objectForKey:@"sourceSrtFilePath"] - forKey:@"subtitleSourceSrtFilePath"]; - } - else - { - [[subtitleArray objectAtIndex:rowIndex] setObject:[[subtitleSourceArray objectAtIndex:sourceSubtitleIndex] objectForKey:@"sourceTrackType"] - forKey:@"subtitleSourceTrackType"]; - } - - if (!hb_subtitle_can_burn([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] intValue])) - { - /* the source track cannot be burned in, so uncheck the widget */ - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackBurned"]; - } - - if (!hb_subtitle_can_force([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] intValue])) - { - /* the source track does not support forced flags, so uncheck the widget */ - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackForced"]; - } + NSMutableDictionary *newTrack = [self trackFromSourceTrackIndex:[anObject integerValue] - 1 - (rowIndex == 0)]; + // Selection index calculation + newTrack[keySubTrackSelectionIndex] = @([anObject integerValue]); + self.subtitleArray[rowIndex] = newTrack; } } else if ([[aTableColumn identifier] isEqualToString:@"forced"]) { - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:[anObject intValue]] forKey:@"subtitleTrackForced"]; + self.subtitleArray[rowIndex][keySubTrackForced] = @([anObject intValue]); } else if ([[aTableColumn identifier] isEqualToString:@"burned"]) { - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:[anObject intValue]] forKey:@"subtitleTrackBurned"]; + self.subtitleArray[rowIndex][keySubTrackBurned] = @([anObject intValue]); if([anObject intValue] == 1) { /* Burned In and Default are mutually exclusive */ - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackDefault"]; + self.subtitleArray[rowIndex][keySubTrackDefault] = @0; } /* now we need to make sure no other tracks are set to burned if we have set burned */ if ([anObject intValue] == 1) { - int i = 0; - NSEnumerator *enumerator = [subtitleArray objectEnumerator]; - id tempObject; - while ( tempObject = [enumerator nextObject] ) - { - if (i != rowIndex ) - { - [tempObject setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackBurned"]; - } - i++; - } + [self validateBurned:rowIndex]; } } else if ([[aTableColumn identifier] isEqualToString:@"default"]) { - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:[anObject intValue]] forKey:@"subtitleTrackDefault"]; + self.subtitleArray[rowIndex][keySubTrackDefault] = @([anObject intValue]); if([anObject intValue] == 1) { /* Burned In and Default are mutually exclusive */ - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackBurned"]; + self.subtitleArray[rowIndex][keySubTrackBurned] = @0; } /* now we need to make sure no other tracks are set to default */ if ([anObject intValue] == 1) { - int i = 0; - NSEnumerator *enumerator = [subtitleArray objectEnumerator]; - id tempObject; - while ( tempObject = [enumerator nextObject] ) - { - if (i != rowIndex) - { - [tempObject setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackDefault"]; - } - i++; - } + [self validateDefault:rowIndex]; } - } /* These next three columns only apply to srt's. they are disabled for source subs */ else if ([[aTableColumn identifier] isEqualToString:@"srt_lang"]) { - - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:[anObject intValue]] forKey:@"subtitleTrackSrtLanguageIndex"]; - [[subtitleArray objectAtIndex:rowIndex] setObject:[[languagesArray objectAtIndex:[anObject intValue]] objectAtIndex:0] forKey:@"subtitleTrackSrtLanguageLong"]; - [[subtitleArray objectAtIndex:rowIndex] setObject:[[languagesArray objectAtIndex:[anObject intValue]] objectAtIndex:1] forKey:@"subtitleTrackSrtLanguageIso3"]; - + self.subtitleArray[rowIndex][keySubTrackLanguageIndex] = @([anObject intValue]); + self.subtitleArray[rowIndex][keySubTrackLanguageIsoCode] = self.languagesArray[[anObject intValue]][1]; } else if ([[aTableColumn identifier] isEqualToString:@"srt_charcode"]) { /* charCodeArray */ - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:[anObject intValue]] forKey:@"subtitleTrackSrtCharCodeIndex"]; - [[subtitleArray objectAtIndex:rowIndex] setObject:[charCodeArray objectAtIndex:[anObject intValue]] forKey:@"subtitleTrackSrtCharCode"]; + self.subtitleArray[rowIndex][keySubTrackSrtCharCodeIndex] = @([anObject intValue]); + self.subtitleArray[rowIndex][keySubTrackSrtCharCode] = self.charCodeArray[[anObject intValue]]; } else if ([[aTableColumn identifier] isEqualToString:@"srt_offset"]) { - [[subtitleArray objectAtIndex:rowIndex] setObject:anObject forKey:@"subtitleTrackSrtOffset"]; + self.subtitleArray[rowIndex][keySubTrackSrtOffset] = @([anObject integerValue]); } - /* now lets do a bit of logic to add / remove tracks as necessary via the "None" track (index 0) */ if ([[aTableColumn identifier] isEqualToString:@"track"]) { - /* Since currently no quicktime based playback devices support soft vobsubs in mp4, we make sure "burned in" is specified * by default to avoid massive confusion and anarchy. However we also want to guard against multiple burned in subtitle tracks * as libhb would ignore all but the first one anyway. Plus it would probably be stupid. */ - if ((container & HB_MUX_MASK_MP4) && ([anObject intValue] != 0)) + if ((self.container & HB_MUX_MASK_MP4) && ([anObject intValue] != 0)) { - if ([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] intValue] == VOBSUB) + if ([self.subtitleArray[rowIndex][keySubTrackType] intValue] == VOBSUB) { /* lets see if there are currently any burned in subs specified */ - NSEnumerator *enumerator = [subtitleArray objectEnumerator]; - id tempObject; BOOL subtrackBurnedInFound = NO; - while ( tempObject = [enumerator nextObject] ) + for (id tempObject in self.subtitleArray) { - if ([[tempObject objectForKey:@"subtitleTrackBurned"] intValue] == 1) + if ([tempObject[keySubTrackBurned] intValue] == 1) { subtrackBurnedInFound = YES; } @@ -683,9 +692,9 @@ /* if we have no current vobsub set to burn it in ... burn it in by default */ if (!subtrackBurnedInFound) { - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:1] forKey:@"subtitleTrackBurned"]; + self.subtitleArray[rowIndex][keySubTrackBurned] = @1; /* Burned In and Default are mutually exclusive */ - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackDefault"]; + self.subtitleArray[rowIndex][keySubTrackDefault] = @0; } } } @@ -694,235 +703,295 @@ * to determine whether to 1 modify an existing track, 2. add a new empty "None" track or 3. remove an existing track. */ - if ([anObject intValue] != 0 && rowIndex == [subtitleArray count] - 1) // if we have a last track which != "None" + if ([anObject intValue] != 0 && rowIndex == [self.subtitleArray count] - 1) // if we have a last track which != "None" { /* add a new empty None track */ - [self addSubtitleTrack]; - + [self.subtitleArray addObject:[self createSubtitleTrack]]; } - else if ([anObject intValue] == 0 && rowIndex != ([subtitleArray count] -1))// if this track is set to "None" and not the last track displayed + else if ([anObject intValue] == 0 && rowIndex != ([self.subtitleArray count] -1))// if this track is set to "None" and not the last track displayed { /* we know the user chose to remove this track by setting it to None, so remove it from the array */ /* However,if this is the first track we have to reset the selected index of the next track by + 1, since it will now become * the first track, which has to account for the extra "Foreign Language Search" index. */ - if (rowIndex == 0 && [[[subtitleArray objectAtIndex: 1] objectForKey: @"subtitleSourceTrackNum"] intValue] != 0) + if (rowIndex == 0 && [self.subtitleArray[1][keySubTrackSelectionIndex] intValue] != 0) { /* get the index of the selection in row one (which is track two) */ - int trackOneSelectedIndex = [[[subtitleArray objectAtIndex: 1] objectForKey: @"subtitleSourceTrackNum"] intValue]; + int trackOneSelectedIndex = [self.subtitleArray[1][keySubTrackSelectionIndex] intValue]; /* increment the index of the subtitle menu item by one, to account for Foreign Language Search which is unique to the first track */ - [[subtitleArray objectAtIndex: 1] setObject:[NSNumber numberWithInt:trackOneSelectedIndex + 1] forKey:@"subtitleSourceTrackNum"]; + self.subtitleArray[1][keySubTrackSelectionIndex] = @(trackOneSelectedIndex + 1); } /* now that we have made the adjustment for track one (index 0) go ahead and delete the track */ - [subtitleArray removeObjectAtIndex: rowIndex]; + [self.subtitleArray removeObjectAtIndex: rowIndex]; } - - + // Validate the current passthru tracks. + [self validatePassthru]; } [aTableView reloadData]; } +#pragma mark - +#pragma mark Subtitle Table Delegate Methods + +- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex +{ + if ([[tableColumn identifier] isEqualToString:@"track"]) + { + // 'track' is a popup of all available source subtitle tracks for the given title + NSPopUpButtonCell *cellTrackPopup = [[NSPopUpButtonCell alloc] init]; + [cellTrackPopup setControlSize:NSSmallControlSize]; + [cellTrackPopup setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; + + // Add our initial "None" track which we use to add source tracks or remove tracks. + // "None" is always index 0. + [[cellTrackPopup menu] addItemWithTitle:@"None" action:NULL keyEquivalent:@""]; + + // Foreign Audio Search (index 1 in the popup) is only available for the first track + if (rowIndex == 0) + { + [[cellTrackPopup menu] addItemWithTitle:self.foreignAudioSearchTrackName action:NULL keyEquivalent:@""]; + } + + for (NSDictionary *track in self.subtitleSourceArray) + { + [[cellTrackPopup menu] addItemWithTitle:track[keySubTrackName] action:NULL keyEquivalent:@""]; + } + + return [cellTrackPopup autorelease]; + } + else if ([[tableColumn identifier] isEqualToString:@"srt_lang"]) + { + return self.languagesCell; + } + else if ([[tableColumn identifier] isEqualToString:@"srt_charcode"]) + { + return self.encodingsCell; + } -/* Gives fine grained control over the final drawing of the widget, including widget status via the controlling array */ + return nil; +} + +/** + * Enables/Disables the table view cells. + */ - (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { - /* we setup whats displayed given the column identifier */ if ([[aTableColumn identifier] isEqualToString:@"track"]) { - /* Set the index of the recorded source track here */ - [aCell selectItemAtIndex:[[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackNum"] intValue]]; - /* now that we have actually selected our track, we can grok the titleOfSelectedItem for that track */ - [[subtitleArray objectAtIndex:rowIndex] setObject:[[aTableColumn dataCellForRow:rowIndex] titleOfSelectedItem] forKey:@"subtitleSourceTrackName"]; + return; + } + // If the Track is None, we disable the other cells as None is an empty track + if ([self.subtitleArray[rowIndex][keySubTrackSelectionIndex] intValue] == 0) + { + [aCell setEnabled:NO]; } else { + // Since we have a valid track, we go ahead and enable the rest of the widgets and set them according to the controlling array */ + [aCell setEnabled:YES]; + } - [aCell setAlignment:NSCenterTextAlignment]; - /* If the Track is None, we disable the other cells as None is an empty track */ - if ([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackNum"] intValue] == 0) + if ([[aTableColumn identifier] isEqualToString:@"forced"]) + { + // Disable the "Forced Only" checkbox if a) the track is "None" or b) the subtitle track doesn't support forced flags + if (![self.subtitleArray[rowIndex][keySubTrackSelectionIndex] intValue] || + !hb_subtitle_can_force([self.subtitleArray[rowIndex][keySubTrackType] intValue])) { - [aCell setState:0]; [aCell setEnabled:NO]; } else { - /* Since we have a valid track, we go ahead and enable the rest of the widgets and set them according to the controlling array */ [aCell setEnabled:YES]; } - - if ([[aTableColumn identifier] isEqualToString:@"forced"]) + } + else if ([[aTableColumn identifier] isEqualToString:@"burned"]) + { + /* + * Disable the "Burned In" checkbox if: + * a) the track is "None" OR + * b) the subtitle track can't be burned in OR + * c) the subtitle track can't be passed through (e.g. PGS w/MP4) + */ + int subtitleTrackType = [self.subtitleArray[rowIndex][keySubTrackType] intValue]; + if (![self.subtitleArray[rowIndex][keySubTrackSelectionIndex] intValue] || + !hb_subtitle_can_burn(subtitleTrackType) || !hb_subtitle_can_pass(subtitleTrackType, self.container)) { - [aCell setState:[[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackForced"] intValue]]; - /* Disable the "Forced Only" checkbox if a) the track is "None" or b) the subtitle track doesn't support forced flags */ - if (![[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackNum"] intValue] || - !hb_subtitle_can_force([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] intValue])) - { - [aCell setEnabled:NO]; - } - else - { - [aCell setEnabled:YES]; - } + [aCell setEnabled:NO]; } - else if ([[aTableColumn identifier] isEqualToString:@"burned"]) - { - [aCell setState:[[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackBurned"] intValue]]; - /* - * Disable the "Burned In" checkbox if: - * a) the track is "None" OR - * b) the subtitle track can't be burned in OR - * c) the subtitle track can't be passed through (e.g. PGS w/MP4) - */ - int subtitleTrackType = [[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] intValue]; - if (![[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackNum"] intValue] || - !hb_subtitle_can_burn(subtitleTrackType) || !hb_subtitle_can_pass(subtitleTrackType, container)) - { - [aCell setEnabled:NO]; - } - else - { - [aCell setEnabled:YES]; - } + else + { + [aCell setEnabled:YES]; } - else if ([[aTableColumn identifier] isEqualToString:@"default"]) + } + else if ([[aTableColumn identifier] isEqualToString:@"default"]) + { + /* + * Disable the "Default" checkbox if: + * a) the track is "None" OR + * b) the subtitle track can't be passed through (e.g. PGS w/MP4) + */ + if (![self.subtitleArray[rowIndex][keySubTrackSelectionIndex] intValue] || + !hb_subtitle_can_pass([self.subtitleArray[rowIndex][keySubTrackType] intValue], self.container)) { - /* - * Disable the "Default" checkbox if: - * a) the track is "None" OR - * b) the subtitle track can't be passed through (e.g. PGS w/MP4) - */ - if (![[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackNum"] intValue] || - !hb_subtitle_can_pass([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] intValue], container)) - { - [aCell setState:NSOffState]; - [aCell setEnabled:NO]; - } - else - { - [aCell setState:[[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackDefault"] intValue]]; - [aCell setEnabled:YES]; - } + [aCell setEnabled:NO]; } - /* These next three columns only apply to srt's. they are disabled for source subs */ - else if ([[aTableColumn identifier] isEqualToString:@"srt_lang"]) + else { - /* We have an srt file so set the track type (Source or SRT, and the srt file path ) kvp's*/ - if ([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] intValue] == SRTSUB) - { - [aCell setEnabled:YES]; - if([[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackSrtLanguageIndex"]) - { - [aCell selectItemAtIndex:[[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackSrtLanguageIndex"] intValue]]; - } - else - { - [aCell selectItemAtIndex:languagesArrayDefIndex]; // English - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInteger:languagesArrayDefIndex] forKey:@"subtitleTrackSrtLanguageIndex"]; - [[subtitleArray objectAtIndex:rowIndex] setObject:[[languagesArray objectAtIndex:languagesArrayDefIndex] objectAtIndex:0] forKey:@"subtitleTrackSrtLanguageLong"]; - [[subtitleArray objectAtIndex:rowIndex] setObject:[[languagesArray objectAtIndex:languagesArrayDefIndex] objectAtIndex:1] forKey:@"subtitleTrackSrtLanguageIso3"]; - - } - } - else - { - [aCell setEnabled:NO]; - } + [aCell setEnabled:YES]; } - else if ([[aTableColumn identifier] isEqualToString:@"srt_charcode"]) + } + /* These next three columns only apply to srt's. they are disabled for source subs */ + else if ([[aTableColumn identifier] isEqualToString:@"srt_lang"]) + { + /* We have an srt file so set the track type (Source or SRT, and the srt file path ) kvp's*/ + if ([self.subtitleArray[rowIndex][keySubTrackType] intValue] == SRTSUB) { - /* We have an srt file so set the track type (Source or SRT, and the srt file path ) kvp's*/ - if ([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] intValue] == SRTSUB) - { - [aCell setEnabled:YES]; - if ([[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackSrtCharCodeIndex"]) - { - [aCell selectItemAtIndex:[[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackSrtCharCodeIndex"] intValue]]; - } - else - { - [aCell selectItemAtIndex:charCodeArrayDefIndex]; // ISO-8859-1 - [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:charCodeArrayDefIndex] forKey:@"subtitleTrackSrtCharCodeIndex"]; - [[subtitleArray objectAtIndex:rowIndex] setObject:[charCodeArray objectAtIndex:charCodeArrayDefIndex] forKey:@"subtitleTrackSrtCharCode"]; - } - } - else - { - [aCell setEnabled:NO]; - } + [aCell setEnabled:YES]; } - else if ([[aTableColumn identifier] isEqualToString:@"srt_offset"]) + else { - if ([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackType"] intValue] == SRTSUB) - { - [aCell setEnabled:YES]; - } - else - { - [aCell setEnabled:NO]; - } + [aCell setEnabled:NO]; + } + } + else if ([[aTableColumn identifier] isEqualToString:@"srt_charcode"]) + { + /* We have an srt file so set the track type (Source or SRT, and the srt file path ) kvp's*/ + if ([self.subtitleArray[rowIndex][keySubTrackType] intValue] == SRTSUB) + { + [aCell setEnabled:YES]; } + else + { + [aCell setEnabled:NO]; + } + } + else if ([[aTableColumn identifier] isEqualToString:@"srt_offset"]) + { + if ([self.subtitleArray[rowIndex][keySubTrackType] intValue] == SRTSUB) + { + [aCell setEnabled:YES]; + } + else + { + [aCell setEnabled:NO]; + } + } +} - /* - * Let's check whether any subtitles in the list cannot be passed through. - * Set the first of any such subtitles to burned-in, remove the others. - */ - id tempObject; - int subtitleTrackType; - BOOL convertToBurnInUsed = NO; - NSMutableArray *tracksToDelete = [[NSMutableArray alloc] init]; - NSEnumerator *enumerator = [subtitleArray objectEnumerator]; - /* convert any non-None incompatible tracks to burn-in or remove them */ - while ((tempObject = [enumerator nextObject]) && - [tempObject objectForKey:@"subtitleSourceTrackType"]) - { - subtitleTrackType = [[tempObject objectForKey:@"subtitleSourceTrackType"] intValue]; - if (!hb_subtitle_can_pass(subtitleTrackType, container)) - { - if (convertToBurnInUsed == NO) - { - /* we haven't set any track to burned-in yet, so we can */ - [tempObject setObject:[NSNumber numberWithInt:1] forKey:@"subtitleTrackBurned"]; - convertToBurnInUsed = YES; //remove any additional tracks - } - else - { - /* we already have a burned-in track, we must remove others */ - [tracksToDelete addObject:tempObject]; - } - } +#pragma mark - Srt import + +/** + * Imports a srt file. + * + * @param sender + */ +- (IBAction)browseImportSrtFile:(id)sender +{ + NSOpenPanel *panel = [NSOpenPanel openPanel]; + [panel setAllowsMultipleSelection:NO]; + [panel setCanChooseFiles:YES]; + [panel setCanChooseDirectories:NO]; + + NSURL *sourceDirectory; + if ([[NSUserDefaults standardUserDefaults] URLForKey:@"LastSrtImportDirectoryURL"]) + { + sourceDirectory = [[NSUserDefaults standardUserDefaults] URLForKey:@"LastSrtImportDirectoryURL"]; + } + else + { + sourceDirectory = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"]; + } + + /* we open up the browse srt sheet here and call for browseImportSrtFileDone after the sheet is closed */ + NSArray *fileTypes = @[@"plist", @"srt"]; + [panel setDirectoryURL:sourceDirectory]; + [panel setAllowedFileTypes:fileTypes]; + [panel beginSheetModalForWindow:[[self view] window] completionHandler:^(NSInteger result) { + if (result == NSOKButton) + { + NSURL *importSrtFileURL = [panel URL]; + NSURL *importSrtDirectory = [importSrtFileURL URLByDeletingLastPathComponent]; + [[NSUserDefaults standardUserDefaults] setURL:importSrtDirectory forKey:@"LastSrtImportDirectoryURL"]; + + /* Create a new entry for the subtitle source array so it shows up in our subtitle source list */ + NSString *displayname = [importSrtFileURL lastPathComponent];// grok an appropriate display name from the srt subtitle */ + + /* create a dictionary of source subtitle information to store in our array */ + [self.subtitleSourceArray addObject:@{keySubTrackIndex: @(self.subtitleSourceArray.count), + keySubTrackName: displayname, + keySubTrackType: @(SRTSUB), + keySubTrackSrtFilePath: importSrtFileURL.path}]; + + // Now create a new srt subtitle dictionary assuming the user wants to add it to their list + NSMutableDictionary *newSubtitleSrtTrack = [self trackFromSourceTrackIndex:self.subtitleSourceArray.count - 1]; + // Calculate the pop up selection index + newSubtitleSrtTrack[keySubTrackSelectionIndex] = @(self.subtitleSourceArray.count + (self.subtitleArray.count == 1)); + [self.subtitleArray insertObject:newSubtitleSrtTrack atIndex:self.subtitleArray.count - 1]; + + [self.fTableView reloadData]; } - /* if we converted a track to burned-in, unset it for tracks that support passthru */ - if (convertToBurnInUsed == YES) + }]; +} + +#pragma mark - UI cells + +- (NSArray *)populateLanguageArray +{ + NSMutableArray *languages = [[[NSMutableArray alloc] init] autorelease]; + + for (const iso639_lang_t * lang = lang_get_next(NULL); lang != NULL; lang = lang_get_next(lang)) + { + [languages addObject:@[@(lang->eng_name), + @(lang->iso639_2)]]; + if (!strcasecmp(lang->eng_name, "English")) { - enumerator = [subtitleArray objectEnumerator]; - while ((tempObject = [enumerator nextObject]) && - [tempObject objectForKey:@"subtitleSourceTrackType"]) - { - subtitleTrackType = [[tempObject objectForKey:@"subtitleSourceTrackType"] intValue]; - if (hb_subtitle_can_pass(subtitleTrackType, container)) - { - [tempObject setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackBurned"]; - } - } + _languagesArrayDefIndex = [languages count] - 1; + } + } + return [[languages copy] autorelease]; +} + +@synthesize languagesCell = _languagesCell; + +- (NSPopUpButtonCell *)languagesCell +{ + if (!_languagesCell) + { + // 'srt_lang' is a popup of commonly used languages to be matched to the source srt file + _languagesCell = [[NSPopUpButtonCell alloc] init]; + // Set the Popups properties + [_languagesCell setControlSize:NSSmallControlSize]; + [_languagesCell setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; + + // list our languages as per the languagesArray + for (NSArray *lang in self.languagesArray) + { + [[_languagesCell menu] addItemWithTitle:lang[0] action:NULL keyEquivalent:@""]; } - /* this is where the actual removal takes place */ - if ([tracksToDelete count] > 0) + } + return _languagesCell; +} + +@synthesize encodingsCell = _encodingsCell; + +- (NSPopUpButtonCell *)encodingsCell +{ + if (!_encodingsCell) { + // 'srt_charcode' is a popup of commonly used character codes to be matched to the source srt file + _encodingsCell = [[NSPopUpButtonCell alloc] init]; + // Set the Popups properties + [_encodingsCell setControlSize:NSSmallControlSize]; + [_encodingsCell setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; + + // list our character codes, as per charCodeArray + for (NSString *charCode in self.charCodeArray) { - [subtitleArray removeObjectsInArray:tracksToDelete]; - [aTableView reloadData]; - /* this must be called after reloadData so as to not block the UI */ - [[NSAlert alertWithMessageText:@"Subtitle tack(s) removed" - defaultButton:@"OK" - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"%lu subtitle %@ could neither be converted to burn-in nor passed through", - (unsigned long)[tracksToDelete count], - [tracksToDelete count] > 1 ? @"tracks" : @"track"] runModal]; + [[_encodingsCell menu] addItemWithTitle:charCode action: NULL keyEquivalent: @""]; } - [tracksToDelete release]; } + return _encodingsCell; } @end diff --git a/macosx/HBSubtitlesDefaultsController.h b/macosx/HBSubtitlesDefaultsController.h new file mode 100644 index 000000000..12056a021 --- /dev/null +++ b/macosx/HBSubtitlesDefaultsController.h @@ -0,0 +1,17 @@ +/* HBSubtitlesDefaultsController.h $ + + This file is part of the HandBrake source code. + Homepage: . + It may be used under the terms of the GNU General Public License. */ + +#import + +@class HBSubtitlesSettings; + +@interface HBSubtitlesDefaultsController : NSWindowController + +- (instancetype)initWithSettings:(HBSubtitlesSettings *)settings; + +@property (nonatomic, readwrite, assign) id delegate; + +@end diff --git a/macosx/HBSubtitlesDefaultsController.m b/macosx/HBSubtitlesDefaultsController.m new file mode 100644 index 000000000..f529798d4 --- /dev/null +++ b/macosx/HBSubtitlesDefaultsController.m @@ -0,0 +1,68 @@ +/* HBSubtitlesDefaultsController.m $ + + This file is part of the HandBrake source code. + Homepage: . + It may be used under the terms of the GNU General Public License. */ + +#import "HBSubtitlesDefaultsController.h" +#import "HBSubtitlesSettings.h" +#import "HBLanguagesSelection.h" + +@interface HBSubtitlesDefaultsController () + +@property (nonatomic, readonly) HBSubtitlesSettings *settings; + +@property (nonatomic, readonly) HBLanguagesSelection *languagesList; +@property (assign) IBOutlet HBLanguageArrayController *tableController; +@property (assign) IBOutlet NSButton *showAllButton; + +@end + +@implementation HBSubtitlesDefaultsController + +- (instancetype)initWithSettings:(HBSubtitlesSettings *)settings +{ + self = [super initWithWindowNibName:@"SubtitlesDefaults"]; + if (self) + { + _settings = [settings retain]; + _languagesList = [[HBLanguagesSelection alloc] initWithLanguages:_settings.trackSelectionLanguages]; + } + return self; +} + +- (void)windowDidLoad +{ + if (self.settings.trackSelectionLanguages.count) + { + self.tableController.showSelectedOnly = YES; + [self.showAllButton setState:NSOffState]; + } +} + +- (IBAction)edit:(id)sender +{ + self.tableController.showSelectedOnly = !self.tableController.showSelectedOnly; +} + +- (IBAction)done:(id)sender +{ + [[self window] orderOut:nil]; + [NSApp endSheet:[self window]]; + + [self.settings.trackSelectionLanguages removeAllObjects]; + [self.settings.trackSelectionLanguages addObjectsFromArray:self.languagesList.selectedLanguages]; + + if ([self.delegate respondsToSelector:@selector(sheetDidEnd)]) + { + [self.delegate performSelector:@selector(sheetDidEnd)]; + } +} + +- (void)dealloc +{ + [super dealloc]; + [_settings release]; +} + +@end diff --git a/macosx/HBSubtitlesSettings.h b/macosx/HBSubtitlesSettings.h new file mode 100644 index 000000000..a2cda1fb8 --- /dev/null +++ b/macosx/HBSubtitlesSettings.h @@ -0,0 +1,27 @@ +/* HBSubtitlesSettings.h $ + + This file is part of the HandBrake source code. + Homepage: . + It may be used under the terms of the GNU General Public License. */ + +#import + +typedef NS_ENUM(NSUInteger, HBSubtitleTrackSelectionBehavior) { + HBSubtitleTrackSelectionBehaviorNone, + HBSubtitleTrackSelectionBehaviorFirst, + HBSubtitleTrackSelectionBehaviorAll, +}; + +@interface HBSubtitlesSettings : NSObject + +@property (nonatomic, readwrite) HBSubtitleTrackSelectionBehavior trackSelectionBehavior; +@property (nonatomic, readwrite, retain) NSMutableArray *trackSelectionLanguages; + +@property (nonatomic, readwrite) BOOL addForeignAudioSearch; +@property (nonatomic, readwrite) BOOL addForeignAudioSubtitle; +@property (nonatomic, readwrite) BOOL addCC; + +- (void)applySettingsFromPreset:(NSDictionary *)preset; +- (void)prepareSubtitlesForPreset:(NSMutableDictionary *)preset; + +@end diff --git a/macosx/HBSubtitlesSettings.m b/macosx/HBSubtitlesSettings.m new file mode 100644 index 000000000..fd85dcfcb --- /dev/null +++ b/macosx/HBSubtitlesSettings.m @@ -0,0 +1,61 @@ +/* HBSubtitlesSettings.m $ + + This file is part of the HandBrake source code. + Homepage: . + It may be used under the terms of the GNU General Public License. */ + +#import "HBSubtitlesSettings.h" + +@implementation HBSubtitlesSettings + +- (instancetype)init +{ + self = [super init]; + if (self) + { + _trackSelectionLanguages = [[NSMutableArray alloc] init]; + } + return self; +} + +- (void)applySettingsFromPreset:(NSDictionary *)preset +{ + if ([preset[@"SubtitleTrackSelectionBehavior"] isEqualToString:@"first"]) + { + self.trackSelectionBehavior = HBSubtitleTrackSelectionBehaviorFirst; + } + else if ([preset[@"SubtitleTrackSelectionBehavior"] isEqualToString:@"all"]) + { + self.trackSelectionBehavior = HBSubtitleTrackSelectionBehaviorAll; + } + else + { + self.trackSelectionBehavior = HBSubtitleTrackSelectionBehaviorNone; + } + self.trackSelectionLanguages = [NSMutableArray arrayWithArray:preset[@"SubtitleLanguageList"]]; + self.addCC = [preset[@"SubtitleAddCC"] boolValue]; + self.addForeignAudioSearch = [preset[@"SubtitleAddForeignAudioSearch"] boolValue]; + self.addForeignAudioSubtitle = [preset[@"SubtitleAddForeignAudioSubtitle"] boolValue]; +} + +- (void)prepareSubtitlesForPreset:(NSMutableDictionary *)preset +{ + if (self.trackSelectionBehavior == HBSubtitleTrackSelectionBehaviorFirst) + { + preset[@"SubtitleTrackSelectionBehavior"] = @"first"; + } + else if (self.trackSelectionBehavior == HBSubtitleTrackSelectionBehaviorAll) + { + preset[@"SubtitleTrackSelectionBehavior"] = @"all"; + } + else + { + preset[@"SubtitleTrackSelectionBehavior"] = @"none"; + } + preset[@"SubtitleLanguageList"] = self.trackSelectionLanguages; + preset[@"SubtitleAddCC"] = @(self.addCC); + preset[@"SubtitleAddForeignAudioSearch"] = @(self.addForeignAudioSearch); + preset[@"SubtitleAddForeignAudioSubtitle"] = @(self.addForeignAudioSubtitle); +} + +@end diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index ae8038976..c229f3f94 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -119,9 +119,11 @@ A91726E7197291BC00D1AFEF /* HBChapterTitlesController.m in Sources */ = {isa = PBXBuildFile; fileRef = A91726E6197291BC00D1AFEF /* HBChapterTitlesController.m */; }; A93E0ED31972957000FD67FB /* HBVideoController.m in Sources */ = {isa = PBXBuildFile; fileRef = A93E0ED11972957000FD67FB /* HBVideoController.m */; }; A93E0ED71972958C00FD67FB /* Video.xib in Resources */ = {isa = PBXBuildFile; fileRef = A93E0ED51972958C00FD67FB /* Video.xib */; }; + A98C29C41977B10600AF5DED /* HBLanguagesSelection.m in Sources */ = {isa = PBXBuildFile; fileRef = A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */; }; A9935213196F38A70069C6B7 /* ChaptersTitles.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9935211196F38A70069C6B7 /* ChaptersTitles.xib */; }; A9AA447A1970664A00D7DEFC /* HBUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = A9AA44791970664A00D7DEFC /* HBUtilities.m */; }; A9B34D75197696FE00871B7D /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9B34D74197696FE00871B7D /* DiskArbitration.framework */; }; + A9C0DB85197E7B0000DF55B3 /* SubtitlesDefaults.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9C0DB83197E7B0000DF55B3 /* SubtitlesDefaults.xib */; }; A9D1E41718262364002F6424 /* HBPreviewGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1E41618262364002F6424 /* HBPreviewGenerator.m */; }; A9DC6C52196F04F6002AE6B4 /* HBSubtitlesController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9DC6C50196F04F6002AE6B4 /* HBSubtitlesController.m */; }; A9DC6C56196F0517002AE6B4 /* Subtitles.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9DC6C54196F0517002AE6B4 /* Subtitles.xib */; }; @@ -131,6 +133,8 @@ A9E1468216BC2AD800C307BC /* play-p.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467E16BC2AD800C307BC /* play-p.pdf */; }; A9E1468316BC2AD800C307BC /* prev-p.pdf in Resources */ = {isa = PBXBuildFile; fileRef = A9E1467F16BC2AD800C307BC /* prev-p.pdf */; }; A9F2EB6F196F12C800066546 /* Audio.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9F2EB6D196F12C800066546 /* Audio.xib */; }; + A9F472891976B7F30009EC65 /* HBSubtitlesDefaultsController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F472871976B7F30009EC65 /* HBSubtitlesDefaultsController.m */; }; + A9F4728D1976BAA70009EC65 /* HBSubtitlesSettings.m in Sources */ = {isa = PBXBuildFile; fileRef = A9F4728C1976BAA70009EC65 /* HBSubtitlesSettings.m */; }; D2BCB10916F5152C0084604C /* activity.png in Resources */ = {isa = PBXBuildFile; fileRef = D2BCB0F616F515230084604C /* activity.png */; }; D2BCB10A16F5152C0084604C /* activity@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = D2BCB0F716F515230084604C /* activity@2x.png */; }; D2BCB10B16F5152C0084604C /* addqueue.png in Resources */ = {isa = PBXBuildFile; fileRef = D2BCB0F816F515240084604C /* addqueue.png */; }; @@ -318,6 +322,8 @@ A93E0ED01972957000FD67FB /* HBVideoController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBVideoController.h; sourceTree = ""; }; A93E0ED11972957000FD67FB /* HBVideoController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBVideoController.m; sourceTree = ""; }; A93E0ED61972958C00FD67FB /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Video.xib; sourceTree = ""; }; + A98C29C21977B10600AF5DED /* HBLanguagesSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBLanguagesSelection.h; sourceTree = ""; }; + A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBLanguagesSelection.m; sourceTree = ""; }; A9935212196F38A70069C6B7 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = ChaptersTitles.xib; sourceTree = ""; }; A9AA44781970664A00D7DEFC /* HBUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBUtilities.h; sourceTree = ""; }; A9AA44791970664A00D7DEFC /* HBUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBUtilities.m; sourceTree = ""; }; @@ -325,6 +331,7 @@ A9AA447C1970726500D7DEFC /* HBQueueController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBQueueController.h; sourceTree = ""; }; A9AA447D1970729300D7DEFC /* HBPreviewGenerator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBPreviewGenerator.h; sourceTree = ""; }; A9B34D74197696FE00871B7D /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = System/Library/Frameworks/DiskArbitration.framework; sourceTree = SDKROOT; }; + A9C0DB84197E7B0000DF55B3 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = SubtitlesDefaults.xib; sourceTree = ""; }; A9D1E41618262364002F6424 /* HBPreviewGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPreviewGenerator.m; sourceTree = ""; }; A9DC6C4F196F04F6002AE6B4 /* HBSubtitlesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBSubtitlesController.h; sourceTree = SOURCE_ROOT; }; A9DC6C50196F04F6002AE6B4 /* HBSubtitlesController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBSubtitlesController.m; sourceTree = SOURCE_ROOT; }; @@ -335,6 +342,10 @@ A9E1467E16BC2AD800C307BC /* play-p.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "play-p.pdf"; sourceTree = ""; }; A9E1467F16BC2AD800C307BC /* prev-p.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "prev-p.pdf"; sourceTree = ""; }; A9F2EB6E196F12C800066546 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Audio.xib; sourceTree = ""; }; + A9F472861976B7F30009EC65 /* HBSubtitlesDefaultsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBSubtitlesDefaultsController.h; sourceTree = ""; }; + A9F472871976B7F30009EC65 /* HBSubtitlesDefaultsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBSubtitlesDefaultsController.m; sourceTree = ""; }; + A9F4728B1976BAA70009EC65 /* HBSubtitlesSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBSubtitlesSettings.h; sourceTree = ""; }; + A9F4728C1976BAA70009EC65 /* HBSubtitlesSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBSubtitlesSettings.m; sourceTree = ""; }; D2BCB0F616F515230084604C /* activity.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = activity.png; sourceTree = ""; }; D2BCB0F716F515230084604C /* activity@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "activity@2x.png"; sourceTree = ""; }; D2BCB0F816F515240084604C /* addqueue.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = addqueue.png; sourceTree = ""; }; @@ -547,10 +558,9 @@ isa = PBXGroup; children = ( A9B34D6F197683FE00871B7D /* Controllers */, + A98C29C51977C00000AF5DED /* Model */, A9AA447D1970729300D7DEFC /* HBPreviewGenerator.h */, A9D1E41618262364002F6424 /* HBPreviewGenerator.m */, - 273F20A114ADBE670021BE6D /* HBPresets.h */, - 273F20A214ADBE670021BE6D /* HBPresets.m */, A9AA44781970664A00D7DEFC /* HBUtilities.h */, A9AA44791970664A00D7DEFC /* HBUtilities.m */, 273F209714ADBE670021BE6D /* HBDVDDetector.h */, @@ -648,6 +658,7 @@ A93E0ED51972958C00FD67FB /* Video.xib */, A9F2EB6D196F12C800066546 /* Audio.xib */, A9DC6C54196F0517002AE6B4 /* Subtitles.xib */, + A9C0DB83197E7B0000DF55B3 /* SubtitlesDefaults.xib */, 273F217A14ADDDA10021BE6D /* AdvancedView.xib */, A9935211196F38A70069C6B7 /* ChaptersTitles.xib */, 273F218014ADDDA10021BE6D /* OutputPanel.xib */, @@ -712,6 +723,19 @@ name = "Products (external)"; sourceTree = ""; }; + A98C29C51977C00000AF5DED /* Model */ = { + isa = PBXGroup; + children = ( + 273F20A114ADBE670021BE6D /* HBPresets.h */, + 273F20A214ADBE670021BE6D /* HBPresets.m */, + A9F4728B1976BAA70009EC65 /* HBSubtitlesSettings.h */, + A9F4728C1976BAA70009EC65 /* HBSubtitlesSettings.m */, + A98C29C21977B10600AF5DED /* HBLanguagesSelection.h */, + A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */, + ); + name = Model; + sourceTree = ""; + }; A9B34D6F197683FE00871B7D /* Controllers */ = { isa = PBXGroup; children = ( @@ -737,14 +761,15 @@ children = ( A93E0ED01972957000FD67FB /* HBVideoController.h */, A93E0ED11972957000FD67FB /* HBVideoController.m */, - 273F209114ADBE670021BE6D /* HBAudio.h */, - 273F209214ADBE670021BE6D /* HBAudio.m */, A9AA447B1970724D00D7DEFC /* HBAdvancedController.h */, 273F209014ADBE670021BE6D /* HBAdvancedController.m */, + 273F209114ADBE670021BE6D /* HBAudio.h */, + 273F209214ADBE670021BE6D /* HBAudio.m */, 273F209314ADBE670021BE6D /* HBAudioController.h */, 273F209414ADBE670021BE6D /* HBAudioController.m */, A9DC6C4F196F04F6002AE6B4 /* HBSubtitlesController.h */, A9DC6C50196F04F6002AE6B4 /* HBSubtitlesController.m */, + A9F472851976B7AA0009EC65 /* Subtitles Defaults */, A91726E5197291BC00D1AFEF /* HBChapterTitlesController.h */, A91726E6197291BC00D1AFEF /* HBChapterTitlesController.m */, ); @@ -762,6 +787,15 @@ name = "UI Views"; sourceTree = ""; }; + A9F472851976B7AA0009EC65 /* Subtitles Defaults */ = { + isa = PBXGroup; + children = ( + A9F472861976B7F30009EC65 /* HBSubtitlesDefaultsController.h */, + A9F472871976B7F30009EC65 /* HBSubtitlesDefaultsController.m */, + ); + name = "Subtitles Defaults"; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXLegacyTarget section */ @@ -892,6 +926,7 @@ D2BCB10B16F5152C0084604C /* addqueue.png in Resources */, D2BCB10C16F5152C0084604C /* addqueue@2x.png in Resources */, D2BCB10D16F5152C0084604C /* advanced.png in Resources */, + A9C0DB85197E7B0000DF55B3 /* SubtitlesDefaults.xib in Resources */, D2BCB10E16F5152C0084604C /* advanced@2x.png in Resources */, D2BCB10F16F5152C0084604C /* audio.png in Resources */, D2BCB11016F5152C0084604C /* audio@2x.png in Resources */, @@ -936,6 +971,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + A98C29C41977B10600AF5DED /* HBLanguagesSelection.m in Sources */, A9AA447A1970664A00D7DEFC /* HBUtilities.m in Sources */, 273F20AC14ADBE670021BE6D /* Controller.m in Sources */, 273F20AD14ADBE670021BE6D /* HBAdvancedController.m in Sources */, @@ -947,6 +983,8 @@ 273F20B414ADBE670021BE6D /* HBOutputRedirect.m in Sources */, 273F20B514ADBE670021BE6D /* HBPreferencesController.m in Sources */, A9DC6C52196F04F6002AE6B4 /* HBSubtitlesController.m in Sources */, + A9F472891976B7F30009EC65 /* HBSubtitlesDefaultsController.m in Sources */, + A9F4728D1976BAA70009EC65 /* HBSubtitlesSettings.m in Sources */, A93E0ED31972957000FD67FB /* HBVideoController.m in Sources */, 273F20B614ADBE670021BE6D /* HBPresets.m in Sources */, 273F20B714ADBE670021BE6D /* HBPreviewController.m in Sources */, @@ -1055,6 +1093,14 @@ name = ChaptersTitles.xib; sourceTree = ""; }; + A9C0DB83197E7B0000DF55B3 /* SubtitlesDefaults.xib */ = { + isa = PBXVariantGroup; + children = ( + A9C0DB84197E7B0000DF55B3 /* English */, + ); + name = SubtitlesDefaults.xib; + sourceTree = ""; + }; A9DC6C54196F0517002AE6B4 /* Subtitles.xib */ = { isa = PBXVariantGroup; children = ( @@ -1096,10 +1142,12 @@ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.6; OTHER_LDFLAGS = ( "-filelist", "$(EXTERNAL_BUILD)/macosx/osl.filelist.txt", ); + SDKROOT = macosx; SHARED_PRECOMPS_DIR = "$(CONFIGURATION_TEMP_DIR)/PrecompiledHeaders"; STRIP_INSTALLED_PRODUCT = NO; }; @@ -1123,10 +1171,12 @@ GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.6; OTHER_LDFLAGS = ( "-filelist", "$(EXTERNAL_BUILD)/macosx/osl.filelist.txt", ); + SDKROOT = macosx; SHARED_PRECOMPS_DIR = "$(CONFIGURATION_TEMP_DIR)/PrecompiledHeaders"; STRIP_INSTALLED_PRODUCT = YES; }; -- cgit v1.2.3