]> granicus.if.org Git - handbrake/commitdiff
MacGui: Implemented a configuration panel similar to the win/lin gui one for the...
authorritsuka <damiog@gmail.com>
Tue, 29 Jul 2014 18:38:01 +0000 (18:38 +0000)
committerritsuka <damiog@gmail.com>
Tue, 29 Jul 2014 18:38:01 +0000 (18:38 +0000)
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

13 files changed:
macosx/Controller.m
macosx/English.lproj/Subtitles.xib
macosx/English.lproj/SubtitlesDefaults.xib [new file with mode: 0644]
macosx/HBLanguagesSelection.h [new file with mode: 0644]
macosx/HBLanguagesSelection.m [new file with mode: 0644]
macosx/HBQueueController.mm
macosx/HBSubtitlesController.h
macosx/HBSubtitlesController.m
macosx/HBSubtitlesDefaultsController.h [new file with mode: 0644]
macosx/HBSubtitlesDefaultsController.m [new file with mode: 0644]
macosx/HBSubtitlesSettings.h [new file with mode: 0644]
macosx/HBSubtitlesSettings.m [new file with mode: 0644]
macosx/HandBrake.xcodeproj/project.pbxproj

index f7a30d903c452a0cbc4ec65b7e497bd879b4dd60..195911615d229603685037c2d71b8fcae454d641 100644 (file)
@@ -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;
index 924881f8072260cd8c955944a0352080a39cb107..d9662e04c2c89efe568a1feb0da841c345467992 100644 (file)
@@ -7,7 +7,7 @@
     <objects>
         <customObject id="-2" userLabel="File's Owner" customClass="HBSubtitlesController">
             <connections>
-                <outlet property="fBrowseSrtFileButton" destination="Q4r-2h-9cA" id="wSH-Hb-eot"/>
+                <outlet property="actionsPopUp" destination="2Tb-KC-Ugi" id="VMz-bu-7bQ"/>
                 <outlet property="fTableView" destination="0yM-wE-D2x" id="0vq-y5-Ubi"/>
                 <outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
             </connections>
             <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
             <subviews>
                 <scrollView autohidesScrollers="YES" horizontalLineScroll="27" horizontalPageScroll="10" verticalLineScroll="27" verticalPageScroll="10" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" id="Syo-rH-vof">
-                    <rect key="frame" x="20" y="20" width="886" height="258"/>
+                    <rect key="frame" x="20" y="20" width="886" height="266"/>
                     <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                     <clipView key="contentView" id="ljc-nW-Cnc">
-                        <rect key="frame" x="1" y="17" width="884" height="240"/>
+                        <rect key="frame" x="1" y="17" width="884" height="248"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                             <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="25" headerView="IiW-3a-Drv" id="0yM-wE-D2x">
-                                <rect key="frame" x="0.0" y="0.0" width="884" height="240"/>
+                                <rect key="frame" x="0.0" y="0.0" width="884" height="248"/>
                                 <autoresizingMask key="autoresizingMask"/>
                                 <size key="intercellSpacing" width="3" height="2"/>
                                 <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                                 <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
                                 <tableColumns>
-                                    <tableColumn identifier="track" editable="NO" width="323" minWidth="40" maxWidth="1000" id="N3S-st-yGv">
+                                    <tableColumn identifier="track" editable="NO" width="322" minWidth="40" maxWidth="1000" id="N3S-st-yGv">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Track">
                                             <font key="font" metaFont="smallSystem"/>
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/>
                                         </tableHeaderCell>
-                                        <popUpButtonCell key="dataCell" type="bevel" title="Pop Up" bezelStyle="rounded" alignment="left" controlSize="mini" lineBreakMode="truncatingTail" state="on" borderStyle="bezel" imageScaling="proportionallyDown" inset="2" preferredEdge="minX" selectedItem="T2a-d2-cIn" id="I4m-dX-JtL">
-                                            <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
-                                            <font key="font" metaFont="miniSystem"/>
-                                            <menu key="menu" title="OtherViews" id="aJW-QB-1Tq">
+                                        <popUpButtonCell key="dataCell" type="push" bezelStyle="rounded" alignment="left" controlSize="small" lineBreakMode="truncatingTail" borderStyle="border" imageScaling="proportionallyDown" inset="2" arrowPosition="arrowAtCenter" preferredEdge="maxY" id="kzn-6s-3Ka">
+                                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                                            <font key="font" metaFont="smallSystem"/>
+                                            <menu key="menu" title="OtherViews" id="Umu-1b-U1Z">
                                                 <items>
-                                                    <menuItem title="Pop Up" state="on" id="T2a-d2-cIn"/>
+                                                    <menuItem title="Pop Up" id="cSW-OC-qKA"/>
                                                 </items>
                                             </menu>
                                         </popUpButtonCell>
                                         <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                     </tableColumn>
-                                    <tableColumn identifier="forced" width="75" minWidth="10" maxWidth="3.4028229999999999e+38" id="klV-Gy-igk">
+                                    <tableColumn identifier="forced" width="76" minWidth="10" maxWidth="3.4028229999999999e+38" id="klV-Gy-igk">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="Forced Only">
                                             <font key="font" metaFont="smallSystem"/>
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
                                         </tableHeaderCell>
-                                        <buttonCell key="dataCell" type="check" title="Check" bezelStyle="regularSquare" imagePosition="only" alignment="left" controlSize="small" inset="2" id="JLr-Qi-X0X">
+                                        <buttonCell key="dataCell" type="check" title="Check" bezelStyle="regularSquare" imagePosition="only" alignment="left" controlSize="small" continuous="YES" inset="2" id="JLr-Qi-X0X">
                                             <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
                                             <font key="font" metaFont="smallSystem"/>
                                         </buttonCell>
-                                        <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                     </tableColumn>
-                                    <tableColumn identifier="burned" width="65" minWidth="10" maxWidth="3.4028229999999999e+38" id="fIe-Fg-ufj">
+                                    <tableColumn identifier="burned" width="64" minWidth="10" maxWidth="3.4028229999999999e+38" id="fIe-Fg-ufj">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="Burned In">
                                             <font key="font" metaFont="smallSystem"/>
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
                                         </tableHeaderCell>
-                                        <buttonCell key="dataCell" type="check" title="Check" bezelStyle="regularSquare" imagePosition="only" alignment="left" controlSize="small" inset="2" id="R9w-Bn-CCt">
+                                        <buttonCell key="dataCell" type="check" title="Check" bezelStyle="regularSquare" imagePosition="only" alignment="left" controlSize="small" continuous="YES" inset="2" id="R9w-Bn-CCt">
                                             <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
                                             <font key="font" metaFont="smallSystem"/>
                                         </buttonCell>
-                                        <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                     </tableColumn>
-                                    <tableColumn identifier="default" width="77" minWidth="10" maxWidth="3.4028229999999999e+38" id="fvq-pE-sOC">
+                                    <tableColumn identifier="default" width="51" minWidth="10" maxWidth="3.4028229999999999e+38" id="fvq-pE-sOC">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center" title="Default">
                                             <font key="font" metaFont="smallSystem"/>
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
                                         </tableHeaderCell>
-                                        <buttonCell key="dataCell" type="check" title="Check" bezelStyle="regularSquare" imagePosition="only" alignment="left" controlSize="small" inset="2" id="ooy-Sh-Edm">
+                                        <buttonCell key="dataCell" type="check" title="Check" bezelStyle="regularSquare" imagePosition="only" alignment="left" controlSize="small" continuous="YES" inset="2" id="ooy-Sh-Edm">
                                             <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
                                             <font key="font" metaFont="smallSystem"/>
                                         </buttonCell>
-                                        <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                     </tableColumn>
-                                    <tableColumn identifier="srt_lang" width="148" minWidth="10" maxWidth="3.4028229999999999e+38" id="9ka-9O-WDj">
+                                    <tableColumn identifier="srt_lang" width="173" minWidth="10" maxWidth="3.4028229999999999e+38" id="9ka-9O-WDj">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Srt Language">
                                             <font key="font" metaFont="smallSystem"/>
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
                                         </tableHeaderCell>
-                                        <popUpButtonCell key="dataCell" type="bevel" title="Pop Up" bezelStyle="rounded" alignment="left" controlSize="small" lineBreakMode="truncatingTail" state="on" borderStyle="bezel" imageScaling="proportionallyDown" inset="2" arrowPosition="arrowAtCenter" preferredEdge="maxY" selectedItem="vHW-fn-RSG" id="2Qz-Lh-O8g">
+                                        <popUpButtonCell key="dataCell" type="bevel" title="Pop Up" bezelStyle="rounded" alignment="left" controlSize="small" lineBreakMode="truncatingTail" continuous="YES" state="on" borderStyle="bezel" imageScaling="proportionallyDown" inset="2" arrowPosition="arrowAtCenter" preferredEdge="maxY" selectedItem="vHW-fn-RSG" id="2Qz-Lh-O8g">
                                             <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
                                             <font key="font" metaFont="smallSystem"/>
                                             <menu key="menu" title="OtherViews" id="UOP-xa-WpP">
                                         </popUpButtonCell>
                                         <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                     </tableColumn>
-                                    <tableColumn identifier="srt_charcode" width="104" minWidth="10" maxWidth="3.4028229999999999e+38" id="1Qg-We-ltR">
+                                    <tableColumn identifier="srt_charcode" width="113" minWidth="10" maxWidth="3.4028229999999999e+38" id="1Qg-We-ltR">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Srt Char Code">
                                             <font key="font" metaFont="smallSystem"/>
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
                                         </tableHeaderCell>
-                                        <popUpButtonCell key="dataCell" type="bevel" title="Pop Up" bezelStyle="rounded" alignment="left" controlSize="small" lineBreakMode="truncatingTail" state="on" borderStyle="bezel" imageScaling="proportionallyDown" inset="2" arrowPosition="arrowAtCenter" preferredEdge="maxY" selectedItem="xt1-a1-JhF" id="AdJ-Mv-JI2">
+                                        <popUpButtonCell key="dataCell" type="bevel" title="Pop Up" bezelStyle="rounded" alignment="left" controlSize="small" lineBreakMode="truncatingTail" continuous="YES" state="on" borderStyle="bezel" imageScaling="proportionallyDown" inset="2" arrowPosition="arrowAtCenter" preferredEdge="maxY" selectedItem="xt1-a1-JhF" id="AdJ-Mv-JI2">
                                             <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
                                             <font key="font" metaFont="smallSystem"/>
                                             <menu key="menu" title="OtherViews" id="ABd-Ec-K2L">
                                         </popUpButtonCell>
                                         <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
                                     </tableColumn>
-                                    <tableColumn identifier="srt_offset" width="71" minWidth="10" maxWidth="3.4028229999999999e+38" id="Fgh-pZ-6uu">
+                                    <tableColumn identifier="srt_offset" width="64" minWidth="10" maxWidth="3.4028229999999999e+38" id="Fgh-pZ-6uu">
                                         <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Srt Offset">
                                             <font key="font" metaFont="smallSystem"/>
                                             <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
                                         </tableHeaderCell>
-                                        <textFieldCell key="dataCell" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" title="Text" id="QRj-KI-a03">
-                                            <font key="font" metaFont="system"/>
+                                        <textFieldCell key="dataCell" controlSize="small" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" continuous="YES" sendsActionOnEndEditing="YES" alignment="center" title="Text" id="QRj-KI-a03">
+                                            <font key="font" metaFont="smallSystem"/>
                                             <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
                                             <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
                                         </textFieldCell>
                                 <connections>
                                     <outlet property="dataSource" destination="-2" id="DH5-v0-2ba"/>
                                     <outlet property="delegate" destination="-2" id="Dfm-tw-89m"/>
+                                    <outlet property="menu" destination="KgC-dn-Hq2" id="Iff-7t-kdg"/>
                                 </connections>
                             </tableView>
                         </subviews>
                         <autoresizingMask key="autoresizingMask"/>
                     </tableHeaderView>
                 </scrollView>
-                <button verticalHuggingPriority="750" id="Q4r-2h-9cA">
-                    <rect key="frame" x="19" y="286" width="116" height="16"/>
+                <popUpButton verticalHuggingPriority="750" id="2Tb-KC-Ugi">
+                    <rect key="frame" x="17" y="291" width="89" height="22"/>
                     <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
-                    <buttonCell key="cell" type="push" title="Add External SRT ..." bezelStyle="rounded" alignment="center" controlSize="mini" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="iXi-me-brz">
-                        <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                        <font key="font" metaFont="miniSystem"/>
-                    </buttonCell>
-                    <connections>
-                        <action selector="browseImportSrtFile:" target="-2" id="kM6-n3-W2N"/>
-                    </connections>
-                </button>
+                    <popUpButtonCell key="cell" type="push" title="Actions" bezelStyle="rounded" alignment="left" controlSize="small" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" pullsDown="YES" id="8ZD-D6-TLA">
+                        <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
+                        <font key="font" metaFont="smallSystem"/>
+                        <menu key="menu" title="OtherViews" id="Fr7-eG-NuL">
+                            <items>
+                                <menuItem title="Actions" state="on" hidden="YES" id="TJO-RZ-jgb"/>
+                                <menuItem title="Add All" id="4PX-In-DpF">
+                                    <connections>
+                                        <action selector="addAll:" target="-2" id="tuS-uF-dje"/>
+                                    </connections>
+                                </menuItem>
+                                <menuItem title="Add External SRT…" id="HW0-PS-t0U">
+                                    <connections>
+                                        <action selector="browseImportSrtFile:" target="-2" id="dog-BP-my4"/>
+                                    </connections>
+                                </menuItem>
+                                <menuItem isSeparatorItem="YES" id="2hO-bG-5qB"/>
+                                <menuItem title="Remove All" id="mVi-zH-KUq">
+                                    <connections>
+                                        <action selector="removeAll:" target="-2" id="QsA-lb-0rD"/>
+                                    </connections>
+                                </menuItem>
+                                <menuItem isSeparatorItem="YES" id="ndj-S4-hj5"/>
+                                <menuItem title="Reload Defaults" id="Zlj-4G-jKI">
+                                    <connections>
+                                        <action selector="addTracksFromDefaults:" target="-2" id="7WM-Xh-1NG"/>
+                                    </connections>
+                                </menuItem>
+                                <menuItem title="Configure Defaults…" id="1LC-qX-pjQ">
+                                    <connections>
+                                        <action selector="showSettingsSheet:" target="-2" id="jqh-lz-3rr"/>
+                                    </connections>
+                                </menuItem>
+                            </items>
+                        </menu>
+                    </popUpButtonCell>
+                </popUpButton>
             </subviews>
         </customView>
+        <menu id="KgC-dn-Hq2">
+            <items>
+                <menuItem title="Add All" id="S2I-Jd-Lyg">
+                    <attributedString key="attributedTitle"/>
+                    <connections>
+                        <action selector="addAll:" target="-2" id="ojh-vi-2gX"/>
+                    </connections>
+                </menuItem>
+                <menuItem title="Add External SRT…" id="fXD-7h-jMl">
+                    <connections>
+                        <action selector="browseImportSrtFile:" target="-2" id="tEu-2l-wjN"/>
+                    </connections>
+                </menuItem>
+                <menuItem isSeparatorItem="YES" id="Pr7-iM-rgd"/>
+                <menuItem title="Remove All" id="R8a-qg-ASg">
+                    <connections>
+                        <action selector="removeAll:" target="-2" id="8yF-Gu-7bi"/>
+                    </connections>
+                </menuItem>
+                <menuItem isSeparatorItem="YES" id="eER-z8-aB9"/>
+                <menuItem title="Reload Defaults" id="jcM-HL-QJ6">
+                    <connections>
+                        <action selector="addTracksFromDefaults:" target="-2" id="IQq-bX-u1t"/>
+                    </connections>
+                </menuItem>
+                <menuItem title="Configure Defaults…" id="pwm-PV-1x4">
+                    <connections>
+                        <action selector="showSettingsSheet:" target="-2" id="aQq-Fi-0Ro"/>
+                    </connections>
+                </menuItem>
+            </items>
+        </menu>
     </objects>
 </document>
diff --git a/macosx/English.lproj/SubtitlesDefaults.xib b/macosx/English.lproj/SubtitlesDefaults.xib
new file mode 100644 (file)
index 0000000..4cf0471
--- /dev/null
@@ -0,0 +1,192 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13E28" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
+    </dependencies>
+    <objects>
+        <customObject id="-2" userLabel="File's Owner" customClass="HBSubtitlesDefaultsController">
+            <connections>
+                <outlet property="showAllButton" destination="QAt-5X-NBT" id="3IW-6r-piX"/>
+                <outlet property="tableController" destination="ZBe-aP-wvq" id="HBN-Z2-bbo"/>
+                <outlet property="window" destination="kwM-lz-5lG" id="rob-Fo-JhL"/>
+            </connections>
+        </customObject>
+        <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
+        <customObject id="-3" userLabel="Application"/>
+        <window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" restorable="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="kwM-lz-5lG">
+            <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
+            <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
+            <rect key="contentRect" x="283" y="305" width="427" height="304"/>
+            <rect key="screenRect" x="0.0" y="0.0" width="2560" height="1418"/>
+            <view key="contentView" id="ZP2-Cp-K5w">
+                <rect key="frame" x="0.0" y="0.0" width="427" height="304"/>
+                <autoresizingMask key="autoresizingMask"/>
+                <subviews>
+                    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="fPg-3n-1TN">
+                        <rect key="frame" x="18" y="268" width="137" height="14"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+                        <textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Track Selection Behavior:" id="GbM-vm-RC2">
+                            <font key="font" metaFont="smallSystem"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="Jsz-Er-bsF">
+                        <rect key="frame" x="90" y="244" width="65" height="14"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+                        <textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Languages:" id="mAT-Jp-SG1">
+                            <font key="font" metaFont="smallSystem"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                    <textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="Hqz-Lw-gAu">
+                        <rect key="frame" x="106" y="66" width="49" height="14"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                        <textFieldCell key="cell" controlSize="small" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Options:" id="NJl-q3-zXL">
+                            <font key="font" metaFont="smallSystem"/>
+                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
+                        </textFieldCell>
+                    </textField>
+                    <popUpButton verticalHuggingPriority="750" id="oiD-QI-wly">
+                        <rect key="frame" x="158" y="263" width="252" height="22"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+                        <popUpButtonCell key="cell" type="push" title="None" bezelStyle="rounded" alignment="left" controlSize="small" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="mvw-Hg-JFM" id="21e-KY-8TR">
+                            <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="smallSystem"/>
+                            <menu key="menu" title="OtherViews" id="Kwy-lU-VuU">
+                                <items>
+                                    <menuItem title="None" state="on" id="mvw-Hg-JFM"/>
+                                    <menuItem title="First Matching Selected Languages" id="jDd-Ji-7Sm"/>
+                                    <menuItem title="All Matching Selected Languages" id="GZP-q7-SYy"/>
+                                </items>
+                            </menu>
+                        </popUpButtonCell>
+                        <connections>
+                            <binding destination="-2" name="selectedIndex" keyPath="self.settings.trackSelectionBehavior" id="sKn-Mr-Hce"/>
+                        </connections>
+                    </popUpButton>
+                    <button id="uF5-6E-EIe">
+                        <rect key="frame" x="158" y="63" width="215" height="18"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                        <buttonCell key="cell" type="check" title="Add Closed Captions when available" bezelStyle="regularSquare" imagePosition="left" controlSize="small" state="on" inset="2" id="66v-2g-DHn">
+                            <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
+                            <font key="font" metaFont="smallSystem"/>
+                        </buttonCell>
+                        <connections>
+                            <binding destination="-2" name="value" keyPath="self.settings.addCC" id="JNz-WE-LD3"/>
+                        </connections>
+                    </button>
+                    <button id="OOC-GZ-OFA">
+                        <rect key="frame" x="158" y="45" width="169" height="18"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                        <buttonCell key="cell" type="check" title="Add &quot;Foreign Audio Search&quot;" bezelStyle="regularSquare" imagePosition="left" controlSize="small" state="on" inset="2" id="vNY-OC-hTJ">
+                            <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
+                            <font key="font" metaFont="smallSystem"/>
+                        </buttonCell>
+                        <connections>
+                            <binding destination="-2" name="value" keyPath="self.settings.addForeignAudioSearch" id="UZC-m0-Mco"/>
+                        </connections>
+                    </button>
+                    <scrollView autohidesScrollers="YES" horizontalLineScroll="16" horizontalPageScroll="10" verticalLineScroll="16" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="aTC-39-h6S">
+                        <rect key="frame" x="161" y="123" width="246" height="135"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" heightSizable="YES"/>
+                        <clipView key="contentView" id="TdE-Sh-NcS">
+                            <rect key="frame" x="1" y="1" width="244" height="133"/>
+                            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                            <subviews>
+                                <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" typeSelect="NO" rowHeight="14" id="Of7-71-Ci6">
+                                    <rect key="frame" x="0.0" y="0.0" width="244" height="133"/>
+                                    <autoresizingMask key="autoresizingMask"/>
+                                    <size key="intercellSpacing" width="3" height="2"/>
+                                    <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
+                                    <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
+                                    <tableColumns>
+                                        <tableColumn width="20" minWidth="20" maxWidth="20" id="G44-XP-6xE">
+                                            <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
+                                                <font key="font" metaFont="smallSystem"/>
+                                                <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+                                                <color key="backgroundColor" white="0.33333298560000002" alpha="1" colorSpace="calibratedWhite"/>
+                                            </tableHeaderCell>
+                                            <buttonCell key="dataCell" type="check" bezelStyle="regularSquare" imagePosition="left" controlSize="small" lineBreakMode="truncatingMiddle" inset="2" id="6by-yL-8VC">
+                                                <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
+                                                <font key="font" metaFont="smallSystem"/>
+                                            </buttonCell>
+                                            <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
+                                            <connections>
+                                                <binding destination="ZBe-aP-wvq" name="value" keyPath="arrangedObjects.isSelected" id="fRp-oC-H6C"/>
+                                            </connections>
+                                        </tableColumn>
+                                        <tableColumn width="210" minWidth="10" maxWidth="2000" id="IJ6-jx-Nba">
+                                            <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left">
+                                                <font key="font" metaFont="smallSystem"/>
+                                                <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
+                                                <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
+                                            </tableHeaderCell>
+                                            <textFieldCell key="dataCell" controlSize="small" lineBreakMode="truncatingMiddle" alignment="left" title="Text Cell" id="lY3-CN-AmZ">
+                                                <font key="font" metaFont="smallSystem"/>
+                                                <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
+                                                <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+                                            </textFieldCell>
+                                            <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
+                                            <connections>
+                                                <binding destination="ZBe-aP-wvq" name="value" keyPath="arrangedObjects.language" id="y6d-Rn-DIv"/>
+                                            </connections>
+                                        </tableColumn>
+                                    </tableColumns>
+                                    <connections>
+                                        <binding destination="ZBe-aP-wvq" name="content" keyPath="arrangedObjects" id="ak7-UG-Fqe"/>
+                                    </connections>
+                                </tableView>
+                            </subviews>
+                            <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
+                        </clipView>
+                        <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="bXf-U5-ogz">
+                            <rect key="frame" x="1" y="118" width="244" height="16"/>
+                            <autoresizingMask key="autoresizingMask"/>
+                        </scroller>
+                        <scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="BWM-rq-VTg">
+                            <rect key="frame" x="-15" y="1" width="16" height="0.0"/>
+                            <autoresizingMask key="autoresizingMask"/>
+                        </scroller>
+                    </scrollView>
+                    <button verticalHuggingPriority="750" id="QAt-5X-NBT">
+                        <rect key="frame" x="161" y="93" width="71" height="23"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                        <buttonCell key="cell" type="smallSquare" title="Show All" bezelStyle="smallSquare" imagePosition="overlaps" alignment="center" controlSize="small" state="on" borderStyle="border" inset="3" id="PiQ-bA-7P1">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES" changeBackground="YES" changeGray="YES"/>
+                            <font key="font" metaFont="smallSystem"/>
+                        </buttonCell>
+                        <connections>
+                            <action selector="edit:" target="-2" id="13y-nD-hEj"/>
+                        </connections>
+                    </button>
+                    <button verticalHuggingPriority="750" id="sC2-52-liU">
+                        <rect key="frame" x="358" y="14" width="54" height="28"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
+                        <buttonCell key="cell" type="push" title="Done" bezelStyle="rounded" alignment="center" controlSize="small" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="kDe-1L-VkD">
+                            <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
+                            <font key="font" metaFont="smallSystem"/>
+                            <string key="keyEquivalent" base64-UTF8="YES">
+DQ
+</string>
+                        </buttonCell>
+                        <connections>
+                            <action selector="done:" target="-2" id="Rdg-PN-7l6"/>
+                        </connections>
+                    </button>
+                </subviews>
+            </view>
+        </window>
+        <arrayController objectClassName="HBLang" id="ZBe-aP-wvq" userLabel="Table Controller" customClass="HBLanguageArrayController">
+            <declaredKeys>
+                <string>language</string>
+                <string>isSelected</string>
+            </declaredKeys>
+            <connections>
+                <binding destination="-2" name="contentArray" keyPath="languagesList.languagesArray" id="vKV-y3-Zbg"/>
+            </connections>
+        </arrayController>
+    </objects>
+</document>
diff --git a/macosx/HBLanguagesSelection.h b/macosx/HBLanguagesSelection.h
new file mode 100644 (file)
index 0000000..725fdf9
--- /dev/null
@@ -0,0 +1,50 @@
+/*  HBLanguagesSelection.h $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import <Foundation/Foundation.h>
+#import <Cocoa/Cocoa.h>
+
+/**
+ *  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 (file)
index 0000000..8a27ad9
--- /dev/null
@@ -0,0 +1,123 @@
+/*  HBLanguagesSelection.m $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ 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
index 120afbda6618f4560275769c3b6f0f6cb15dc3cf..5bb1d9a1d5c80be7383b351b4196b561a6bf3548 100644 (file)
@@ -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++;
         }
 
index 66428bf39746ff78fb2cacd30c56914db526d2e0..71bafe86816af49cd663c3624a7ade03930684f7 100644 (file)
@@ -6,6 +6,20 @@
 
 #import <Cocoa/Cocoa.h>
 
+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.
 - (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
index 43bed5034c48e18517109b8d230859f31ceeae0b..a804de74802cb99ce495126a734c1380144d794d 100644 (file)
@@ -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 () <NSTableViewDataSource, NSTableViewDelegate>
-{
-    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
 
     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])
                 {
                 }
                 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;
                     }
                 /* 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;
                 }
             }
         }
          * 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 (file)
index 0000000..12056a0
--- /dev/null
@@ -0,0 +1,17 @@
+/*  HBSubtitlesDefaultsController.h $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import <Cocoa/Cocoa.h>
+
+@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 (file)
index 0000000..f529798
--- /dev/null
@@ -0,0 +1,68 @@
+/*  HBSubtitlesDefaultsController.m $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ 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 (file)
index 0000000..a2cda1f
--- /dev/null
@@ -0,0 +1,27 @@
+/*  HBSubtitlesSettings.h $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+#import <Foundation/Foundation.h>
+
+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 (file)
index 0000000..fd85dcf
--- /dev/null
@@ -0,0 +1,61 @@
+/*  HBSubtitlesSettings.m $
+
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ 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
index ae8038976a6043c908f9d167379cad85f83576bc..c229f3f9495325409ca623c59bc5fdd428424cca 100644 (file)
                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 */; };
                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 */; };
                A93E0ED01972957000FD67FB /* HBVideoController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBVideoController.h; sourceTree = "<group>"; };
                A93E0ED11972957000FD67FB /* HBVideoController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBVideoController.m; sourceTree = "<group>"; };
                A93E0ED61972958C00FD67FB /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Video.xib; sourceTree = "<group>"; };
+               A98C29C21977B10600AF5DED /* HBLanguagesSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBLanguagesSelection.h; sourceTree = "<group>"; };
+               A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBLanguagesSelection.m; sourceTree = "<group>"; };
                A9935212196F38A70069C6B7 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = ChaptersTitles.xib; sourceTree = "<group>"; };
                A9AA44781970664A00D7DEFC /* HBUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBUtilities.h; sourceTree = "<group>"; };
                A9AA44791970664A00D7DEFC /* HBUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBUtilities.m; sourceTree = "<group>"; };
                A9AA447C1970726500D7DEFC /* HBQueueController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBQueueController.h; sourceTree = "<group>"; };
                A9AA447D1970729300D7DEFC /* HBPreviewGenerator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBPreviewGenerator.h; sourceTree = "<group>"; };
                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 = "<group>"; };
                A9D1E41618262364002F6424 /* HBPreviewGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPreviewGenerator.m; sourceTree = "<group>"; };
                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; };
                A9E1467E16BC2AD800C307BC /* play-p.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "play-p.pdf"; sourceTree = "<group>"; };
                A9E1467F16BC2AD800C307BC /* prev-p.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = "prev-p.pdf"; sourceTree = "<group>"; };
                A9F2EB6E196F12C800066546 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Audio.xib; sourceTree = "<group>"; };
+               A9F472861976B7F30009EC65 /* HBSubtitlesDefaultsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBSubtitlesDefaultsController.h; sourceTree = "<group>"; };
+               A9F472871976B7F30009EC65 /* HBSubtitlesDefaultsController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBSubtitlesDefaultsController.m; sourceTree = "<group>"; };
+               A9F4728B1976BAA70009EC65 /* HBSubtitlesSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBSubtitlesSettings.h; sourceTree = "<group>"; };
+               A9F4728C1976BAA70009EC65 /* HBSubtitlesSettings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBSubtitlesSettings.m; sourceTree = "<group>"; };
                D2BCB0F616F515230084604C /* activity.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = activity.png; sourceTree = "<group>"; };
                D2BCB0F716F515230084604C /* activity@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "activity@2x.png"; sourceTree = "<group>"; };
                D2BCB0F816F515240084604C /* addqueue.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = addqueue.png; sourceTree = "<group>"; };
                        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 */,
                                A93E0ED51972958C00FD67FB /* Video.xib */,
                                A9F2EB6D196F12C800066546 /* Audio.xib */,
                                A9DC6C54196F0517002AE6B4 /* Subtitles.xib */,
+                               A9C0DB83197E7B0000DF55B3 /* SubtitlesDefaults.xib */,
                                273F217A14ADDDA10021BE6D /* AdvancedView.xib */,
                                A9935211196F38A70069C6B7 /* ChaptersTitles.xib */,
                                273F218014ADDDA10021BE6D /* OutputPanel.xib */,
                        name = "Products (external)";
                        sourceTree = "<group>";
                };
+               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 = "<group>";
+               };
                A9B34D6F197683FE00871B7D /* Controllers */ = {
                        isa = PBXGroup;
                        children = (
                        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 */,
                        );
                        name = "UI Views";
                        sourceTree = "<group>";
                };
+               A9F472851976B7AA0009EC65 /* Subtitles Defaults */ = {
+                       isa = PBXGroup;
+                       children = (
+                               A9F472861976B7F30009EC65 /* HBSubtitlesDefaultsController.h */,
+                               A9F472871976B7F30009EC65 /* HBSubtitlesDefaultsController.m */,
+                       );
+                       name = "Subtitles Defaults";
+                       sourceTree = "<group>";
+               };
 /* End PBXGroup section */
 
 /* Begin PBXLegacyTarget section */
                                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 */,
                        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 */,
                                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 */,
                        name = ChaptersTitles.xib;
                        sourceTree = "<group>";
                };
+               A9C0DB83197E7B0000DF55B3 /* SubtitlesDefaults.xib */ = {
+                       isa = PBXVariantGroup;
+                       children = (
+                               A9C0DB84197E7B0000DF55B3 /* English */,
+                       );
+                       name = SubtitlesDefaults.xib;
+                       sourceTree = "<group>";
+               };
                A9DC6C54196F0517002AE6B4 /* Subtitles.xib */ = {
                        isa = PBXVariantGroup;
                        children = (
                                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;
                        };
                                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;
                        };