OSDN Git Service

MacGui: Remove legacy preferences since they are now controlled via the presets.
[handbrake-jp/handbrake-jp-git.git] / macosx / Controller.mm
1 /* $Id: Controller.mm,v 1.79 2005/11/04 19:41:32 titer Exp $
2
3    This file is part of the HandBrake source code.
4    Homepage: <http://handbrake.fr/>.
5    It may be used under the terms of the GNU General Public License. */
6
7 #import "Controller.h"
8 #import "HBOutputPanelController.h"
9 #import "HBPreferencesController.h"
10 #import "HBDVDDetector.h"
11 #import "HBPresets.h"
12
13 #define DragDropSimplePboardType        @"MyCustomOutlineViewPboardType"
14
15 /* We setup the toolbar values here */
16 static NSString *        ToggleDrawerIdentifier             = @"Toggle Drawer Item Identifier";
17 static NSString *        StartEncodingIdentifier            = @"Start Encoding Item Identifier";
18 static NSString *        PauseEncodingIdentifier            = @"Pause Encoding Item Identifier";
19 static NSString *        ShowQueueIdentifier                = @"Show Queue Item Identifier";
20 static NSString *        AddToQueueIdentifier               = @"Add to Queue Item Identifier";
21 static NSString *        ShowActivityIdentifier             = @"Debug Output Item Identifier";
22 static NSString *        ChooseSourceIdentifier             = @"Choose Source Item Identifier";
23
24
25 /*******************************
26  * HBController implementation *
27  *******************************/
28 @implementation HBController
29
30 - (id)init
31 {
32     self = [super init];
33     if( !self )
34     {
35         return nil;
36     }
37
38     [HBPreferencesController registerUserDefaults];
39     fHandle = NULL;
40
41     /* Check for check for the app support directory here as
42      * outputPanel needs it right away, as may other future methods
43      */
44     NSString *libraryDir = [NSSearchPathForDirectoriesInDomains( NSLibraryDirectory,
45                                                                  NSUserDomainMask,
46                                                                  YES ) objectAtIndex:0];
47     AppSupportDirectory = [[libraryDir stringByAppendingPathComponent:@"Application Support"]
48                                        stringByAppendingPathComponent:@"HandBrake"];
49     if( ![[NSFileManager defaultManager] fileExistsAtPath:AppSupportDirectory] )
50     {
51         [[NSFileManager defaultManager] createDirectoryAtPath:AppSupportDirectory
52                                                    attributes:nil];
53     }
54
55     outputPanel = [[HBOutputPanelController alloc] init];
56     fPictureController = [[PictureController alloc] initWithDelegate:self];
57     fQueueController = [[HBQueueController alloc] init];
58     fAdvancedOptions = [[HBAdvancedController alloc] init];
59     /* we init the HBPresets class which currently is only used
60     * for updating built in presets, may move more functionality
61     * there in the future
62     */
63     fPresetsBuiltin = [[HBPresets alloc] init];
64     fPreferencesController = [[HBPreferencesController alloc] init];
65     /* Lets report the HandBrake version number here to the activity log and text log file */
66     NSString *versionStringFull = [[NSString stringWithFormat: @"Handbrake Version: %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleGetInfoString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]];
67     [self writeToActivityLog: "%s", [versionStringFull UTF8String]];    
68     
69     return self;
70 }
71
72
73 - (void) applicationDidFinishLaunching: (NSNotification *) notification
74 {
75     /* Init libhb with check for updates libhb style set to "0" so its ignored and lets sparkle take care of it */
76     fHandle = hb_init(HB_DEBUG_ALL, 0);
77
78         // Set the Growl Delegate
79     [GrowlApplicationBridge setGrowlDelegate: self];
80     /* Init others controllers */
81     [fPictureController SetHandle: fHandle];
82     [fQueueController   setHandle: fHandle];
83     [fQueueController   setHBController: self];
84
85     fChapterTitlesDelegate = [[ChapterTitles alloc] init];
86     [fChapterTable setDataSource:fChapterTitlesDelegate];
87     [fChapterTable setDelegate:fChapterTitlesDelegate];
88
89     /* Call UpdateUI every 1/2 sec */
90     [[NSRunLoop currentRunLoop] addTimer:[NSTimer
91                                           scheduledTimerWithTimeInterval:0.5 target:self
92                                           selector:@selector(updateUI:) userInfo:nil repeats:YES]
93                                  forMode:NSEventTrackingRunLoopMode];
94
95     // Open debug output window now if it was visible when HB was closed
96     if ([[NSUserDefaults standardUserDefaults] boolForKey:@"OutputPanelIsOpen"])
97         [self showDebugOutputPanel:nil];
98
99     // Open queue window now if it was visible when HB was closed
100     if ([[NSUserDefaults standardUserDefaults] boolForKey:@"QueueWindowIsOpen"])
101         [self showQueueWindow:nil];
102
103         [self openMainWindow:nil];
104
105     /* Show Browse Sources Window ASAP */
106     [self performSelectorOnMainThread:@selector(browseSources:)
107                            withObject:nil waitUntilDone:NO];
108 }
109
110 - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) app
111 {
112     // Warn if encoding a movie
113     hb_state_t s;
114     hb_get_state( fHandle, &s );
115     HBJobGroup * jobGroup = [fQueueController currentJobGroup];
116     if ( jobGroup && ( s.state != HB_STATE_IDLE ) )
117     {
118         int result = NSRunCriticalAlertPanel(
119                 NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil),
120                 NSLocalizedString(@"%@ is currently encoding. If you quit HandBrake, your movie will be lost. Do you want to quit anyway?", nil),
121                 NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil,
122                 jobGroup ? [jobGroup name] : @"A movie" );
123         
124         if (result == NSAlertDefaultReturn)
125         {
126             [self doCancelCurrentJob];
127             return NSTerminateNow;
128         }
129         else
130             return NSTerminateCancel;
131     }
132     
133     // Warn if items still in the queue
134     else if ( hb_count( fHandle ) > 0 )
135     {
136         int result = NSRunCriticalAlertPanel(
137                 NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil),
138                 NSLocalizedString(@"One or more encodes are queued for encoding. Do you want to quit anyway?", nil),
139                 NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil);
140         
141         if ( result == NSAlertDefaultReturn )
142             return NSTerminateNow;
143         else
144             return NSTerminateCancel;
145     }
146     
147     return NSTerminateNow;
148 }
149
150 - (void)applicationWillTerminate:(NSNotification *)aNotification
151 {
152         [browsedSourceDisplayName release];
153     [outputPanel release];
154         [fQueueController release];
155         hb_close(&fHandle);
156 }
157
158
159 - (void) awakeFromNib
160 {
161     [fWindow center];
162     [fWindow setExcludedFromWindowsMenu:YES];
163     [fAdvancedOptions setView:fAdvancedView];
164
165     /* lets setup our presets drawer for drag and drop here */
166     [fPresetsOutlineView registerForDraggedTypes: [NSArray arrayWithObject:DragDropSimplePboardType] ];
167     [fPresetsOutlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
168     [fPresetsOutlineView setVerticalMotionCanBeginDrag: YES];
169
170     /* Initialize currentScanCount so HB can use it to
171                 evaluate successive scans */
172         currentScanCount = 0;
173
174     /* Init UserPresets .plist */
175         [self loadPresets];
176
177         fRipIndicatorShown = NO;  // initially out of view in the nib
178
179         /* Show/Dont Show Presets drawer upon launch based
180                 on user preference DefaultPresetsDrawerShow*/
181         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPresetsDrawerShow"] > 0)
182         {
183                 [fPresetDrawer open];
184         }
185         
186         
187     
188     /* Destination box*/
189     NSMenuItem *menuItem;
190     [fDstFormatPopUp removeAllItems];
191     // MP4 file
192     menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MP4 file" action: NULL keyEquivalent: @""];
193     [menuItem setTag: HB_MUX_MP4];
194         // MKV file
195     menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MKV file" action: NULL keyEquivalent: @""];
196     [menuItem setTag: HB_MUX_MKV];
197     // AVI file
198     menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"AVI file" action: NULL keyEquivalent: @""];
199     [menuItem setTag: HB_MUX_AVI];
200     // OGM file
201     menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"OGM file" action: NULL keyEquivalent: @""];
202     [menuItem setTag: HB_MUX_OGM];
203     [fDstFormatPopUp selectItemAtIndex: 0];
204
205     [self formatPopUpChanged:nil];
206
207         /* We enable the create chapters checkbox here since we are .mp4 */
208         [fCreateChapterMarkers setEnabled: YES];
209         if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultChapterMarkers"] > 0)
210         {
211                 [fCreateChapterMarkers setState: NSOnState];
212         }
213
214
215
216
217     [fDstFile2Field setStringValue: [NSString stringWithFormat:
218         @"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
219
220     /* Video encoder */
221     [fVidEncoderPopUp removeAllItems];
222     [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
223     [fVidEncoderPopUp addItemWithTitle: @"XviD"];
224
225
226
227     /* Video quality */
228     [fVidTargetSizeField setIntValue: 700];
229         [fVidBitrateField    setIntValue: 1000];
230
231     [fVidQualityMatrix   selectCell: fVidBitrateCell];
232     [self videoMatrixChanged:nil];
233
234     /* Video framerate */
235     [fVidRatePopUp removeAllItems];
236         [fVidRatePopUp addItemWithTitle: NSLocalizedString( @"Same as source", @"" )];
237     for( int i = 0; i < hb_video_rates_count; i++ )
238     {
239         if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.3f",23.976]])
240                 {
241                         [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
242                                 [NSString stringWithCString: hb_video_rates[i].string], @" (NTSC Film)"]];
243                 }
244                 else if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%d",25]])
245                 {
246                         [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
247                                 [NSString stringWithCString: hb_video_rates[i].string], @" (PAL Film/Video)"]];
248                 }
249                 else if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.2f",29.97]])
250                 {
251                         [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
252                                 [NSString stringWithCString: hb_video_rates[i].string], @" (NTSC Video)"]];
253                 }
254                 else
255                 {
256                         [fVidRatePopUp addItemWithTitle:
257                                 [NSString stringWithCString: hb_video_rates[i].string]];
258                 }
259     }
260     [fVidRatePopUp selectItemAtIndex: 0];
261         
262         /* Set Auto Crop to On at launch */
263     [fPictureController setAutoCrop:YES];
264         
265         /* Audio bitrate */
266     [fAudTrack1BitratePopUp removeAllItems];
267     for( int i = 0; i < hb_audio_bitrates_count; i++ )
268     {
269         [fAudTrack1BitratePopUp addItemWithTitle:
270                                 [NSString stringWithCString: hb_audio_bitrates[i].string]];
271
272     }
273     [fAudTrack1BitratePopUp selectItemAtIndex: hb_audio_bitrates_default];
274         
275     /* Audio samplerate */
276     [fAudTrack1RatePopUp removeAllItems];
277     for( int i = 0; i < hb_audio_rates_count; i++ )
278     {
279         [fAudTrack1RatePopUp addItemWithTitle:
280             [NSString stringWithCString: hb_audio_rates[i].string]];
281     }
282     [fAudTrack1RatePopUp selectItemAtIndex: hb_audio_rates_default];
283         
284     /* Bottom */
285     [fStatusField setStringValue: @""];
286
287     [self enableUI: NO];
288         [self setupToolbar];
289
290         /* We disable the Turbo 1st pass checkbox since we are not x264 */
291         [fVidTurboPassCheck setEnabled: NO];
292         [fVidTurboPassCheck setState: NSOffState];
293
294
295         /* lets get our default prefs here */
296         [self getDefaultPresets:nil];
297         /* lets initialize the current successful scancount here to 0 */
298         currentSuccessfulScanCount = 0;
299 }
300
301 - (void) enableUI: (bool) b
302 {
303     NSControl * controls[] =
304       { fSrcTitleField, fSrcTitlePopUp,
305         fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField,
306         fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field,
307         fDstFormatField, fDstFormatPopUp, fDstFile1Field, fDstFile2Field,
308         fDstBrowseButton, fVidRateField, fVidRatePopUp,
309         fVidEncoderField, fVidEncoderPopUp, fVidQualityField,
310         fVidQualityMatrix, fVidGrayscaleCheck, fSubField, fSubPopUp,
311         fAudSourceLabel, fAudCodecLabel, fAudMixdownLabel, fAudSamplerateLabel, fAudBitrateLabel,
312         fAudTrack1Label, fAudTrack2Label, fAudTrack3Label, fAudTrack4Label,
313         fAudLang1PopUp, fAudLang2PopUp, fAudLang3PopUp, fAudLang4PopUp,
314         fAudTrack1CodecPopUp, fAudTrack2CodecPopUp, fAudTrack3CodecPopUp, fAudTrack4CodecPopUp,
315         fAudTrack1MixPopUp, fAudTrack2MixPopUp, fAudTrack3MixPopUp, fAudTrack4MixPopUp,
316         fAudTrack1RatePopUp, fAudTrack2RatePopUp, fAudTrack3RatePopUp, fAudTrack4RatePopUp,
317         fAudTrack1BitratePopUp, fAudTrack2BitratePopUp, fAudTrack3BitratePopUp, fAudTrack4BitratePopUp,
318         fAudDrcLabel, fAudTrack1DrcSlider, fAudTrack1DrcField, fAudTrack2DrcSlider,
319         fAudTrack2DrcField, fAudTrack3DrcSlider, fAudTrack3DrcField, fAudTrack4DrcSlider,fAudTrack4DrcField,
320         fPictureButton,fQueueStatus,fPicSettingARkeep, fPicSettingDeinterlace,fPicLabelSettings,fPicLabelSrc,
321         fPicLabelOutp,fPicSettingsSrc,fPicSettingsOutp,fPicSettingsAnamorphic,
322                 fPicLabelAr,fPicLabelDeinterlace,fPicSettingPAR,fPicLabelAnamorphic,fPresetsAdd,fPresetsDelete,
323                 fCreateChapterMarkers,fVidTurboPassCheck,fDstMp4LargeFileCheck,fPicLabelAutoCrop,
324                 fPicSettingAutoCrop,fPicSettingDetelecine,fPicLabelDetelecine,fPicLabelDenoise,fPicSettingDenoise,
325         fSubForcedCheck,fPicSettingDeblock,fPicLabelDeblock,fPicLabelDecomb,fPicSettingDecomb,fPresetsOutlineView,
326         fAudDrcLabel,fDstMp4HttpOptFileCheck,fDstMp4iPodFileCheck};
327
328     for( unsigned i = 0;
329          i < sizeof( controls ) / sizeof( NSControl * ); i++ )
330     {
331         if( [[controls[i] className] isEqualToString: @"NSTextField"] )
332         {
333             NSTextField * tf = (NSTextField *) controls[i];
334             if( ![tf isBezeled] )
335             {
336                 [tf setTextColor: b ? [NSColor controlTextColor] :
337                     [NSColor disabledControlTextColor]];
338                 continue;
339             }
340         }
341         [controls[i] setEnabled: b];
342
343     }
344
345         if (b) {
346
347         /* if we're enabling the interface, check if the audio mixdown controls need to be enabled or not */
348         /* these will have been enabled by the mass control enablement above anyway, so we're sense-checking it here */
349         [self setEnabledStateOfAudioMixdownControls:nil];
350         /* we also call calculatePictureSizing here to sense check if we already have vfr selected */
351         [self calculatePictureSizing:nil];
352         [self shouldEnableHttpMp4CheckBox: nil];
353
354         } else {
355
356                 [fPresetsOutlineView setEnabled: NO];
357
358         }
359
360     [self videoMatrixChanged:nil];
361     [fAdvancedOptions enableUI:b];
362 }
363
364
365 /***********************************************************************
366  * UpdateDockIcon
367  ***********************************************************************
368  * Shows a progression bar on the dock icon, filled according to
369  * 'progress' (0.0 <= progress <= 1.0).
370  * Called with progress < 0.0 or progress > 1.0, restores the original
371  * icon.
372  **********************************************************************/
373 - (void) UpdateDockIcon: (float) progress
374 {
375     NSImage * icon;
376     NSData * tiff;
377     NSBitmapImageRep * bmp;
378     uint32_t * pen;
379     uint32_t black = htonl( 0x000000FF );
380     uint32_t red   = htonl( 0xFF0000FF );
381     uint32_t white = htonl( 0xFFFFFFFF );
382     int row_start, row_end;
383     int i, j;
384
385     /* Get application original icon */
386     icon = [NSImage imageNamed: @"NSApplicationIcon"];
387
388     if( progress < 0.0 || progress > 1.0 )
389     {
390         [NSApp setApplicationIconImage: icon];
391         return;
392     }
393
394     /* Get it in a raw bitmap form */
395     tiff = [icon TIFFRepresentationUsingCompression:
396             NSTIFFCompressionNone factor: 1.0];
397     bmp = [NSBitmapImageRep imageRepWithData: tiff];
398     
399     /* Draw the progression bar */
400     /* It's pretty simple (ugly?) now, but I'm no designer */
401
402     row_start = 3 * (int) [bmp size].height / 4;
403     row_end   = 7 * (int) [bmp size].height / 8;
404
405     for( i = row_start; i < row_start + 2; i++ )
406     {
407         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
408         for( j = 0; j < (int) [bmp size].width; j++ )
409         {
410             pen[j] = black;
411         }
412     }
413     for( i = row_start + 2; i < row_end - 2; i++ )
414     {
415         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
416         pen[0] = black;
417         pen[1] = black;
418         for( j = 2; j < (int) [bmp size].width - 2; j++ )
419         {
420             if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
421             {
422                 pen[j] = red;
423             }
424             else
425             {
426                 pen[j] = white;
427             }
428         }
429         pen[j]   = black;
430         pen[j+1] = black;
431     }
432     for( i = row_end - 2; i < row_end; i++ )
433     {
434         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
435         for( j = 0; j < (int) [bmp size].width; j++ )
436         {
437             pen[j] = black;
438         }
439     }
440
441     /* Now update the dock icon */
442     tiff = [bmp TIFFRepresentationUsingCompression:
443             NSTIFFCompressionNone factor: 1.0];
444     icon = [[NSImage alloc] initWithData: tiff];
445     [NSApp setApplicationIconImage: icon];
446     [icon release];
447 }
448
449 - (void) updateUI: (NSTimer *) timer
450 {
451     hb_list_t  * list;
452     list = hb_get_titles( fHandle );
453     /* check to see if there has been a new scan done
454         this bypasses the constraints of HB_STATE_WORKING
455         not allowing setting a newly scanned source */
456         int checkScanCount = hb_get_scancount( fHandle );
457         if( checkScanCount > currentScanCount )
458         {
459                 currentScanCount = checkScanCount;
460         [fScanIndicator setIndeterminate: NO];
461         [fScanIndicator setDoubleValue: 0.0];
462         [fScanIndicator setHidden: YES];
463                 [self showNewScan:nil];
464         }
465
466     hb_state_t s;
467     hb_get_state( fHandle, &s );
468
469     switch( s.state )
470     {
471         case HB_STATE_IDLE:
472                 break;
473 #define p s.param.scanning
474         case HB_STATE_SCANNING:
475                 {
476             [fSrcDVD2Field setStringValue: [NSString stringWithFormat:
477                                             NSLocalizedString( @"Scanning title %d of %d...", @"" ),
478                                             p.title_cur, p.title_count]];
479             [fScanIndicator setHidden: NO];
480             [fScanIndicator setDoubleValue: 100.0 * ( p.title_cur - 1 ) / p.title_count];
481             break;
482                 }
483 #undef p
484
485 #define p s.param.scandone
486         case HB_STATE_SCANDONE:
487         {
488             [fScanIndicator setIndeterminate: NO];
489             [fScanIndicator setDoubleValue: 0.0];
490             [fScanIndicator setHidden: YES];
491                         [self showNewScan:nil];
492             [[fWindow toolbar] validateVisibleItems];
493                         break;
494         }
495 #undef p
496
497 #define p s.param.working
498         case HB_STATE_WORKING:
499         {
500             float progress_total;
501             NSMutableString * string;
502                         /* Currently, p.job_cur and p.job_count get screwed up when adding
503                                 jobs during encoding, if they cannot be fixed in libhb, will implement a
504                                 nasty but working cocoa solution */
505                         /* Update text field */
506                         string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding: task %d of %d, %.2f %%", @"" ), p.job_cur, p.job_count, 100.0 * p.progress];
507
508                         if( p.seconds > -1 )
509             {
510                 [string appendFormat:
511                     NSLocalizedString( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", @"" ),
512                     p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
513             }
514
515             [fStatusField setStringValue: string];
516
517             /* Update slider */
518                         progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
519             [fRipIndicator setIndeterminate: NO];
520             [fRipIndicator setDoubleValue: 100.0 * progress_total];
521
522             // If progress bar hasn't been revealed at the bottom of the window, do
523             // that now. This code used to be in doRip. I moved it to here to handle
524             // the case where hb_start is called by HBQueueController and not from
525             // HBController.
526             if( !fRipIndicatorShown )
527             {
528                 NSRect frame = [fWindow frame];
529                 if( frame.size.width <= 591 )
530                     frame.size.width = 591;
531                 frame.size.height += 36;
532                 frame.origin.y -= 36;
533                 [fWindow setFrame:frame display:YES animate:YES];
534                 fRipIndicatorShown = YES;
535                 /* We check to see if we need to warn the user that the computer will go to sleep
536                    or shut down when encoding is finished */
537                 [self remindUserOfSleepOrShutdown];
538             }
539
540             /* Update dock icon */
541             [self UpdateDockIcon: progress_total];
542
543             // Has current job changed? That means the queue has probably changed as
544                         // well so update it
545             [fQueueController libhbStateChanged: s];
546
547             break;
548         }
549 #undef p
550
551 #define p s.param.muxing
552         case HB_STATE_MUXING:
553         {
554             /* Update text field */
555             [fStatusField setStringValue: NSLocalizedString( @"Muxing...", @"" )];
556
557             /* Update slider */
558             [fRipIndicator setIndeterminate: YES];
559             [fRipIndicator startAnimation: nil];
560
561             /* Update dock icon */
562             [self UpdateDockIcon: 1.0];
563
564                         // Pass along the info to HBQueueController
565             [fQueueController libhbStateChanged: s];
566
567             break;
568         }
569 #undef p
570
571         case HB_STATE_PAUSED:
572                     [fStatusField setStringValue: NSLocalizedString( @"Paused", @"" )];
573
574                         // Pass along the info to HBQueueController
575             [fQueueController libhbStateChanged: s];
576
577             break;
578
579         case HB_STATE_WORKDONE:
580         {
581             // HB_STATE_WORKDONE happpens as a result of libhb finishing all its jobs
582             // or someone calling hb_stop. In the latter case, hb_stop does not clear
583             // out the remaining passes/jobs in the queue. We'll do that here.
584
585             // Delete all remaining jobs of this encode.
586             hb_job_t * job;
587             while( ( job = hb_job( fHandle, 0 ) ) && ( !IsFirstPass(job->sequence_id) ) )
588                 hb_rem( fHandle, job );
589
590             [fStatusField setStringValue: NSLocalizedString( @"Done.", @"" )];
591             [fRipIndicator setIndeterminate: NO];
592             [fRipIndicator setDoubleValue: 0.0];
593             [[fWindow toolbar] validateVisibleItems];
594
595             /* Restore dock icon */
596             [self UpdateDockIcon: -1.0];
597
598             if( fRipIndicatorShown )
599             {
600                 NSRect frame = [fWindow frame];
601                 if( frame.size.width <= 591 )
602                                     frame.size.width = 591;
603                 frame.size.height += -36;
604                 frame.origin.y -= -36;
605                 [fWindow setFrame:frame display:YES animate:YES];
606                                 fRipIndicatorShown = NO;
607                         }
608
609                         // Pass along the info to HBQueueController
610             [fQueueController libhbStateChanged: s];
611
612             /* Check to see if the encode state has not been cancelled
613                                 to determine if we should check for encode done notifications */
614                         if( fEncodeState != 2 )
615             {
616                 /* If Alert Window or Window and Growl has been selected */
617                                 if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window"] ||
618                                         [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"] )
619                 {
620                                         /*On Screen Notification*/
621                                         int status;
622                                         NSBeep();
623                                         status = NSRunAlertPanel(@"Put down that cocktail...",@"Your HandBrake encode is done!", @"OK", nil, nil);
624                                         [NSApp requestUserAttention:NSCriticalRequest];
625                 }
626                 /* If sleep has been selected */
627                 if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Put Computer To Sleep"] )
628                 {
629                     /* Sleep */
630                     NSDictionary* errorDict;
631                     NSAppleEventDescriptor* returnDescriptor = nil;
632                     NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
633                             @"tell application \"Finder\" to sleep"];
634                     returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
635                     [scriptObject release];
636                 }
637                 /* If Shutdown has been selected */
638                 if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Shut Down Computer"] )
639                 {
640                     /* Shut Down */
641                     NSDictionary* errorDict;
642                     NSAppleEventDescriptor* returnDescriptor = nil;
643                     NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
644                             @"tell application \"Finder\" to shut down"];
645                     returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
646                     [scriptObject release];
647                 }
648             }
649             break;
650         }
651     }
652
653     /* Lets show the queue status here in the main window */
654         int queue_count = [fQueueController pendingCount];
655         if( queue_count == 1 )
656                 [fQueueStatus setStringValue: NSLocalizedString( @"1 encode queued", @"" ) ];
657     else if( queue_count > 1 )
658                 [fQueueStatus setStringValue: [NSString stringWithFormat: NSLocalizedString( @"%d encodes queued", @"" ), queue_count]];
659         else
660                 [fQueueStatus setStringValue: @""];
661 }
662
663 /* We use this to write messages to stderr from the macgui which show up in the activity window and log*/
664 - (void) writeToActivityLog:(char *) format, ...
665 {
666     va_list args;
667     va_start(args, format);
668     if (format != nil)
669     {
670         char str[1024];
671         vsnprintf( str, 1024, format, args );
672
673         time_t _now = time( NULL );
674         struct tm * now  = localtime( &_now );
675         fprintf(stderr, "[%02d:%02d:%02d] macgui: %s\n", now->tm_hour, now->tm_min, now->tm_sec, str );
676     }
677     va_end(args);
678 }
679
680 #pragma mark -
681 #pragma mark Toolbar
682 // ============================================================
683 // NSToolbar Related Methods
684 // ============================================================
685
686 - (void) setupToolbar {
687     NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier: @"HandBrake Toolbar"] autorelease];
688
689     [toolbar setAllowsUserCustomization: YES];
690     [toolbar setAutosavesConfiguration: YES];
691     [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
692
693     [toolbar setDelegate: self];
694
695     [fWindow setToolbar: toolbar];
696 }
697
698 - (NSToolbarItem *) toolbar: (NSToolbar *)toolbar itemForItemIdentifier:
699     (NSString *) itemIdent willBeInsertedIntoToolbar:(BOOL) willBeInserted {
700     NSToolbarItem * item = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdent] autorelease];
701
702     if ([itemIdent isEqualToString: ToggleDrawerIdentifier])
703     {
704         [item setLabel: @"Toggle Presets"];
705         [item setPaletteLabel: @"Toggler Presets"];
706         [item setToolTip: @"Open/Close Preset Drawer"];
707         [item setImage: [NSImage imageNamed: @"Drawer"]];
708         [item setTarget: self];
709         [item setAction: @selector(toggleDrawer:)];
710         [item setAutovalidates: NO];
711     }
712     else if ([itemIdent isEqualToString: StartEncodingIdentifier])
713     {
714         [item setLabel: @"Start"];
715         [item setPaletteLabel: @"Start Encoding"];
716         [item setToolTip: @"Start Encoding"];
717         [item setImage: [NSImage imageNamed: @"Play"]];
718         [item setTarget: self];
719         [item setAction: @selector(Rip:)];
720     }
721     else if ([itemIdent isEqualToString: ShowQueueIdentifier])
722     {
723         [item setLabel: @"Show Queue"];
724         [item setPaletteLabel: @"Show Queue"];
725         [item setToolTip: @"Show Queue"];
726         [item setImage: [NSImage imageNamed: @"Queue"]];
727         [item setTarget: self];
728         [item setAction: @selector(showQueueWindow:)];
729         [item setAutovalidates: NO];
730     }
731     else if ([itemIdent isEqualToString: AddToQueueIdentifier])
732     {
733         [item setLabel: @"Add to Queue"];
734         [item setPaletteLabel: @"Add to Queue"];
735         [item setToolTip: @"Add to Queue"];
736         [item setImage: [NSImage imageNamed: @"AddToQueue"]];
737         [item setTarget: self];
738         [item setAction: @selector(addToQueue:)];
739     }
740     else if ([itemIdent isEqualToString: PauseEncodingIdentifier])
741     {
742         [item setLabel: @"Pause"];
743         [item setPaletteLabel: @"Pause Encoding"];
744         [item setToolTip: @"Pause Encoding"];
745         [item setImage: [NSImage imageNamed: @"Pause"]];
746         [item setTarget: self];
747         [item setAction: @selector(Pause:)];
748     }
749     else if ([itemIdent isEqualToString: ShowActivityIdentifier]) {
750         [item setLabel: @"Activity Window"];
751         [item setPaletteLabel: @"Show Activity Window"];
752         [item setToolTip: @"Show Activity Window"];
753         [item setImage: [NSImage imageNamed: @"ActivityWindow"]];
754         [item setTarget: self];
755         [item setAction: @selector(showDebugOutputPanel:)];
756         [item setAutovalidates: NO];
757     }
758     else if ([itemIdent isEqualToString: ChooseSourceIdentifier])
759     {
760         [item setLabel: @"Source"];
761         [item setPaletteLabel: @"Source"];
762         [item setToolTip: @"Choose Video Source"];
763         [item setImage: [NSImage imageNamed: @"Source"]];
764         [item setTarget: self];
765         [item setAction: @selector(browseSources:)];
766     }
767     else
768     {
769         return nil;
770     }
771
772     return item;
773 }
774
775 - (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
776 {
777     return [NSArray arrayWithObjects: ChooseSourceIdentifier, NSToolbarSeparatorItemIdentifier, StartEncodingIdentifier,
778         PauseEncodingIdentifier, AddToQueueIdentifier, ShowQueueIdentifier, NSToolbarFlexibleSpaceItemIdentifier, 
779                 NSToolbarSpaceItemIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier, nil];
780 }
781
782 - (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
783 {
784     return [NSArray arrayWithObjects:  StartEncodingIdentifier, PauseEncodingIdentifier, AddToQueueIdentifier,
785         ChooseSourceIdentifier, ShowQueueIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier,
786         NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier,
787         NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
788 }
789
790 - (BOOL) validateToolbarItem: (NSToolbarItem *) toolbarItem
791 {
792     NSString * ident = [toolbarItem itemIdentifier];
793         
794     if (fHandle)
795     {
796         hb_state_t s;
797         hb_get_state2( fHandle, &s );
798         
799         if (s.state == HB_STATE_WORKING || s.state == HB_STATE_MUXING)
800         {
801             if ([ident isEqualToString: StartEncodingIdentifier])
802             {
803                 [toolbarItem setImage: [NSImage imageNamed: @"Stop"]];
804                 [toolbarItem setLabel: @"Stop"];
805                 [toolbarItem setPaletteLabel: @"Stop"];
806                 [toolbarItem setToolTip: @"Stop Encoding"];
807                 return YES;
808             }
809             if ([ident isEqualToString: PauseEncodingIdentifier])
810             {
811                 [toolbarItem setImage: [NSImage imageNamed: @"Pause"]];
812                 [toolbarItem setLabel: @"Pause"];
813                 [toolbarItem setPaletteLabel: @"Pause Encoding"];
814                 [toolbarItem setToolTip: @"Pause Encoding"];
815                 return YES;
816             }
817             if (SuccessfulScan)
818                 if ([ident isEqualToString: AddToQueueIdentifier])
819                     return YES;
820         }
821         else if (s.state == HB_STATE_PAUSED)
822         {
823             if ([ident isEqualToString: PauseEncodingIdentifier])
824             {
825                 [toolbarItem setImage: [NSImage imageNamed: @"Play"]];
826                 [toolbarItem setLabel: @"Resume"];
827                 [toolbarItem setPaletteLabel: @"Resume Encoding"];
828                 [toolbarItem setToolTip: @"Resume Encoding"];
829                 return YES;
830             }
831             if ([ident isEqualToString: StartEncodingIdentifier])
832                 return YES;
833             if ([ident isEqualToString: AddToQueueIdentifier])
834                 return YES;
835         }
836         else if (s.state == HB_STATE_SCANNING)
837             return NO;
838         else if (s.state == HB_STATE_WORKDONE || s.state == HB_STATE_SCANDONE || SuccessfulScan)
839         {
840             if ([ident isEqualToString: StartEncodingIdentifier])
841             {
842                 [toolbarItem setImage: [NSImage imageNamed: @"Play"]];
843                 if (hb_count(fHandle) > 0)
844                     [toolbarItem setLabel: @"Start Queue"];
845                 else
846                     [toolbarItem setLabel: @"Start"];
847                 [toolbarItem setPaletteLabel: @"Start Encoding"];
848                 [toolbarItem setToolTip: @"Start Encoding"];
849                 return YES;
850             }
851             if ([ident isEqualToString: AddToQueueIdentifier])
852                 return YES;
853         }
854
855     }
856     
857     if ([ident isEqualToString: ShowQueueIdentifier])
858         return YES;
859     if ([ident isEqualToString: ToggleDrawerIdentifier])
860         return YES;
861     if ([ident isEqualToString: ChooseSourceIdentifier])
862         return YES;
863     if ([ident isEqualToString: ShowActivityIdentifier])
864         return YES;
865     
866     return NO;
867 }
868
869 - (BOOL) validateMenuItem: (NSMenuItem *) menuItem
870 {
871     SEL action = [menuItem action];
872     
873     hb_state_t s;
874     hb_get_state2( fHandle, &s );
875     
876     if (fHandle)
877     {
878         if (action == @selector(addToQueue:) || action == @selector(showPicturePanel:) || action == @selector(showAddPresetPanel:))
879             return SuccessfulScan && [fWindow attachedSheet] == nil;
880         
881         if (action == @selector(browseSources:))
882         {
883             if (s.state == HB_STATE_SCANNING)
884                 return NO;
885             else
886                 return [fWindow attachedSheet] == nil;
887         }
888         if (action == @selector(selectDefaultPreset:))
889             return [fPresetsOutlineView selectedRow] >= 0 && [fWindow attachedSheet] == nil;
890         if (action == @selector(Pause:))
891         {
892             if (s.state == HB_STATE_WORKING)
893             {
894                 if(![[menuItem title] isEqualToString:@"Pause Encoding"])
895                     [menuItem setTitle:@"Pause Encoding"];
896                 return YES;
897             }
898             else if (s.state == HB_STATE_PAUSED)
899             {
900                 if(![[menuItem title] isEqualToString:@"Resume Encoding"])
901                     [menuItem setTitle:@"Resume Encoding"];
902                 return YES;
903             }
904             else
905                 return NO;
906         }
907         if (action == @selector(Rip:))
908         {
909             if (s.state == HB_STATE_WORKING || s.state == HB_STATE_MUXING || s.state == HB_STATE_PAUSED)
910             {
911                 if(![[menuItem title] isEqualToString:@"Stop Encoding"])
912                     [menuItem setTitle:@"Stop Encoding"];
913                 return YES;
914             }
915             else if (SuccessfulScan)
916             {
917                 if(![[menuItem title] isEqualToString:@"Start Encoding"])
918                     [menuItem setTitle:@"Start Encoding"];
919                 return [fWindow attachedSheet] == nil;
920             }
921             else
922                 return NO;
923         }
924     }
925     if( action == @selector(setDefaultPreset:) )
926     {
927         return [fPresetsOutlineView selectedRow] != -1;
928     }
929
930     return YES;
931 }
932
933 #pragma mark -
934 #pragma mark Encode Done Actions
935 // register a test notification and make
936 // it enabled by default
937 #define SERVICE_NAME @"Encode Done"
938 - (NSDictionary *)registrationDictionaryForGrowl 
939
940     NSDictionary *registrationDictionary = [NSDictionary dictionaryWithObjectsAndKeys: 
941     [NSArray arrayWithObjects:SERVICE_NAME,nil], GROWL_NOTIFICATIONS_ALL, 
942     [NSArray arrayWithObjects:SERVICE_NAME,nil], GROWL_NOTIFICATIONS_DEFAULT, 
943     nil]; 
944
945     return registrationDictionary; 
946
947
948 -(void)showGrowlDoneNotification:(NSString *) filePath
949 {
950     /* This is called from HBQueueController as jobs roll off of the queue in currentJobChanged */
951     NSString * finishedEncode = filePath;
952     /* strip off the path to just show the file name */
953     finishedEncode = [finishedEncode lastPathComponent];
954     if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Growl Notification"] || 
955         [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"])
956     {
957         NSString * growlMssg = [NSString stringWithFormat: @"your HandBrake encode %@ is done!",finishedEncode];
958         [GrowlApplicationBridge 
959          notifyWithTitle:@"Put down that cocktail..." 
960          description:growlMssg 
961          notificationName:SERVICE_NAME
962          iconData:nil 
963          priority:0 
964          isSticky:1 
965          clickContext:nil];
966     }
967     
968 }
969 -(void)sendToMetaX:(NSString *) filePath
970 {
971     /* This is called from HBQueueController as jobs roll off of the queue in currentJobChanged */
972     if([[NSUserDefaults standardUserDefaults] boolForKey: @"sendToMetaX"] == YES)
973     {
974         NSAppleScript *myScript = [[NSAppleScript alloc] initWithSource: [NSString stringWithFormat: @"%@%@%@", @"tell application \"MetaX\" to open (POSIX file \"", filePath, @"\")"]];
975         [myScript executeAndReturnError: nil];
976         [myScript release];
977     }
978 }
979 #pragma mark -
980 #pragma mark Get New Source
981
982 /*Opens the source browse window, called from Open Source widgets */
983 - (IBAction) browseSources: (id) sender
984 {
985     NSOpenPanel * panel;
986         
987     panel = [NSOpenPanel openPanel];
988     [panel setAllowsMultipleSelection: NO];
989     [panel setCanChooseFiles: YES];
990     [panel setCanChooseDirectories: YES ];
991     NSString * sourceDirectory;
992         if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastSourceDirectory"])
993         {
994                 sourceDirectory = [[NSUserDefaults standardUserDefaults] stringForKey:@"LastSourceDirectory"];
995         }
996         else
997         {
998                 sourceDirectory = @"~/Desktop";
999                 sourceDirectory = [sourceDirectory stringByExpandingTildeInPath];
1000         }
1001     /* we open up the browse sources sheet here and call for browseSourcesDone after the sheet is closed
1002         * to evaluate whether we want to specify a title, we pass the sender in the contextInfo variable
1003         */
1004     [panel beginSheetForDirectory: sourceDirectory file: nil types: nil
1005                    modalForWindow: fWindow modalDelegate: self
1006                    didEndSelector: @selector( browseSourcesDone:returnCode:contextInfo: )
1007                       contextInfo: sender]; 
1008 }
1009
1010 - (void) browseSourcesDone: (NSOpenPanel *) sheet
1011                 returnCode: (int) returnCode contextInfo: (void *) contextInfo
1012 {
1013     /* we convert the sender content of contextInfo back into a variable called sender
1014      * mostly just for consistency for evaluation later
1015      */
1016     id sender = (id)contextInfo;
1017     /* User selected a file to open */
1018         if( returnCode == NSOKButton )
1019     {
1020             /* Free display name allocated previously by this code */
1021         [browsedSourceDisplayName release];
1022        
1023         NSString *scanPath = [[sheet filenames] objectAtIndex: 0];
1024         /* we set the last searched source directory in the prefs here */
1025         NSString *sourceDirectory = [scanPath stringByDeletingLastPathComponent];
1026         [[NSUserDefaults standardUserDefaults] setObject:sourceDirectory forKey:@"LastSourceDirectory"];
1027         /* we order out sheet, which is the browse window as we need to open
1028          * the title selection sheet right away
1029          */
1030         [sheet orderOut: self];
1031         
1032         if (sender == fOpenSourceTitleMMenu)
1033         {
1034             /* We put the chosen source path in the source display text field for the
1035              * source title selection sheet in which the user specifies the specific title to be
1036              * scanned  as well as the short source name in fSrcDsplyNameTitleScan just for display
1037              * purposes in the title panel
1038              */
1039             /* Full Path */
1040             [fScanSrcTitlePathField setStringValue:scanPath];
1041             NSString *displayTitlescanSourceName;
1042
1043             if ([[scanPath lastPathComponent] isEqualToString: @"VIDEO_TS"])
1044             {
1045                 /* If VIDEO_TS Folder is chosen, choose its parent folder for the source display name
1046                  we have to use the title->dvd value so we get the proper name of the volume if a physical dvd is the source*/
1047                 displayTitlescanSourceName = [[scanPath stringByDeletingLastPathComponent] lastPathComponent];
1048             }
1049             else
1050             {
1051                 /* if not the VIDEO_TS Folder, we can assume the chosen folder is the source name */
1052                 displayTitlescanSourceName = [scanPath lastPathComponent];
1053             }
1054             /* we set the source display name in the title selection dialogue */
1055             [fSrcDsplyNameTitleScan setStringValue:displayTitlescanSourceName];
1056             /* we set the attempted scans display name for main window to displayTitlescanSourceName*/
1057             browsedSourceDisplayName = [displayTitlescanSourceName retain];
1058             /* We show the actual sheet where the user specifies the title to be scanned
1059              * as we are going to do a title specific scan
1060              */
1061             [self showSourceTitleScanPanel:nil];
1062         }
1063         else
1064         {
1065             /* We are just doing a standard full source scan, so we specify "0" to libhb */
1066             NSString *path = [[sheet filenames] objectAtIndex: 0];
1067             
1068             /* We check to see if the chosen file at path is a package */
1069             if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:path])
1070             {
1071                 [self writeToActivityLog: "trying to open a package at: %s", [path UTF8String]];
1072                 /* We check to see if this is an .eyetv package */
1073                 if ([[path pathExtension] isEqualToString: @"eyetv"])
1074                 {
1075                     [self writeToActivityLog:"trying to open eyetv package"];
1076                     /* We're looking at an EyeTV package - try to open its enclosed
1077                      .mpg media file */
1078                      browsedSourceDisplayName = [[[path stringByDeletingPathExtension] lastPathComponent] retain];
1079                     NSString *mpgname;
1080                     int n = [[path stringByAppendingString: @"/"]
1081                              completePathIntoString: &mpgname caseSensitive: NO
1082                              matchesIntoArray: nil
1083                              filterTypes: [NSArray arrayWithObject: @"mpg"]];
1084                     if (n > 0)
1085                     {
1086                         /* Found an mpeg inside the eyetv package, make it our scan path 
1087                         and call performScan on the enclosed mpeg */
1088                         path = mpgname;
1089                         [self writeToActivityLog:"found mpeg in eyetv package"];
1090                         [self performScan:path scanTitleNum:0];
1091                     }
1092                     else
1093                     {
1094                         /* We did not find an mpeg file in our package, so we do not call performScan */
1095                         [self writeToActivityLog:"no valid mpeg in eyetv package"];
1096                     }
1097                 }
1098                 /* We check to see if this is a .dvdmedia package */
1099                 else if ([[path pathExtension] isEqualToString: @"dvdmedia"])
1100                 {
1101                     /* path IS a package - but dvdmedia packages can be treaded like normal directories */
1102                     browsedSourceDisplayName = [[[path stringByDeletingPathExtension] lastPathComponent] retain];
1103                     [self writeToActivityLog:"trying to open dvdmedia package"];
1104                     [self performScan:path scanTitleNum:0];
1105                 }
1106                 else
1107                 {
1108                     /* The package is not an eyetv package, so we do not call performScan */
1109                     [self writeToActivityLog:"unable to open package"];
1110                 }
1111             }
1112             else // path is not a package, so we treat it as a dvd parent folder or VIDEO_TS folder
1113             {
1114                 /* path is not a package, so we call perform scan directly on our file */
1115                 if ([[path lastPathComponent] isEqualToString: @"VIDEO_TS"])
1116                 {
1117                     [self writeToActivityLog:"trying to open video_ts folder (video_ts folder chosen)"];
1118                     /* If VIDEO_TS Folder is chosen, choose its parent folder for the source display name*/
1119                     browsedSourceDisplayName = [[[path stringByDeletingLastPathComponent] lastPathComponent] retain];
1120                 }
1121                 else
1122                 {
1123                     [self writeToActivityLog:"trying to open video_ts folder (parent directory chosen)"];
1124                     /* if not the VIDEO_TS Folder, we can assume the chosen folder is the source name */
1125                     /* make sure we remove any path extension as this can also be an '.mpg' file */
1126                     browsedSourceDisplayName = [[path lastPathComponent] retain];
1127                 }
1128                 [self performScan:path scanTitleNum:0];
1129             }
1130
1131         }
1132
1133     }
1134 }
1135
1136 /* Here we open the title selection sheet where we can specify an exact title to be scanned */
1137 - (IBAction) showSourceTitleScanPanel: (id) sender
1138 {
1139     /* We default the title number to be scanned to "0" which results in a full source scan, unless the
1140     * user changes it
1141     */
1142     [fScanSrcTitleNumField setStringValue: @"0"];
1143         /* Show the panel */
1144         [NSApp beginSheet:fScanSrcTitlePanel modalForWindow:fWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
1145 }
1146
1147 - (IBAction) closeSourceTitleScanPanel: (id) sender
1148 {
1149     [NSApp endSheet: fScanSrcTitlePanel];
1150     [fScanSrcTitlePanel orderOut: self];
1151
1152     if(sender == fScanSrcTitleOpenButton)
1153     {
1154         /* We setup the scan status in the main window to indicate a source title scan */
1155         [fSrcDVD2Field setStringValue: @"Opening a new source title ..."];
1156                 [fScanIndicator setHidden: NO];
1157         [fScanIndicator setIndeterminate: YES];
1158         [fScanIndicator startAnimation: nil];
1159                 
1160         /* We use the performScan method to actually perform the specified scan passing the path and the title
1161             * to be scanned
1162             */
1163         [self performScan:[fScanSrcTitlePathField stringValue] scanTitleNum:[fScanSrcTitleNumField intValue]];
1164     }
1165 }
1166
1167 /* Here we actually tell hb_scan to perform the source scan, using the path to source and title number*/
1168 - (void) performScan:(NSString *) scanPath scanTitleNum: (int) scanTitleNum
1169 {
1170     /* use a bool to determine whether or not we can decrypt using vlc */
1171     BOOL cancelScanDecrypt = 0;
1172     NSString *path = scanPath;
1173     HBDVDDetector *detector = [HBDVDDetector detectorForPath:path];
1174
1175     // Notify ChapterTitles that there's no title
1176     [fChapterTitlesDelegate resetWithTitle:nil];
1177     [fChapterTable reloadData];
1178
1179     [self enableUI: NO];
1180
1181     if( [detector isVideoDVD] )
1182     {
1183         // The chosen path was actually on a DVD, so use the raw block
1184         // device path instead.
1185         path = [detector devicePath];
1186         [self writeToActivityLog: "trying to open a physical dvd at: %s", [scanPath UTF8String]];
1187
1188         /* lets check for vlc here to make sure we have a dylib available to use for decrypting */
1189         NSString *vlcPath = @"/Applications/VLC.app";
1190         NSFileManager * fileManager = [NSFileManager defaultManager];
1191             if ([fileManager fileExistsAtPath:vlcPath] == 0) 
1192             {
1193             /*vlc not found in /Applications so we set the bool to cancel scanning to 1 */
1194             cancelScanDecrypt = 1;
1195             [self writeToActivityLog: "VLC app not found for decrypting physical dvd"];
1196             int status;
1197             status = NSRunAlertPanel(@"HandBrake could not find VLC.",@"Please download and install VLC media player in your /Applications folder if you wish to read encrypted DVDs.", @"Get VLC", @"Cancel Scan", @"Attempt Scan Anyway");
1198             [NSApp requestUserAttention:NSCriticalRequest];
1199             
1200             if (status == NSAlertDefaultReturn)
1201             {
1202                 /* User chose to go download vlc (as they rightfully should) so we send them to the vlc site */
1203                 [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.videolan.org/"]];
1204             }
1205             else if (status == NSAlertAlternateReturn)
1206             {
1207             /* User chose to cancel the scan */
1208             [self writeToActivityLog: "cannot open physical dvd , scan cancelled"];
1209             }
1210             else
1211             {
1212             /* User chose to override our warning and scan the physical dvd anyway, at their own peril. on an encrypted dvd this produces massive log files and fails */
1213             cancelScanDecrypt = 0;
1214             [self writeToActivityLog: "user overrode vlc warning -trying to open physical dvd without decryption"];
1215             }
1216
1217         }
1218         else
1219         {
1220             /* VLC was found in /Applications so all is well, we can carry on using vlc's libdvdcss.dylib for decrypting if needed */
1221             [self writeToActivityLog: "VLC app found for decrypting physical dvd"];
1222         }
1223     }
1224
1225     if (cancelScanDecrypt == 0)
1226     {
1227         /* we actually pass the scan off to libhb here */
1228         /* If there is no title number passed to scan, we use "0"
1229          * which causes the default behavior of a full source scan
1230          */
1231         if (!scanTitleNum)
1232         {
1233             scanTitleNum = 0;
1234         }
1235         if (scanTitleNum > 0)
1236         {
1237             [self writeToActivityLog: "scanning specifically for title: %d", scanTitleNum];
1238         }
1239
1240         hb_scan( fHandle, [path UTF8String], scanTitleNum );
1241         [fSrcDVD2Field setStringValue:@"Scanning new source ..."];
1242     }
1243 }
1244
1245 - (IBAction) showNewScan:(id)sender
1246 {
1247     hb_list_t  * list;
1248         hb_title_t * title;
1249         int indxpri=0;    // Used to search the longuest title (default in combobox)
1250         int longuestpri=0; // Used to search the longuest title (default in combobox)
1251
1252         list = hb_get_titles( fHandle );
1253
1254         if( !hb_list_count( list ) )
1255         {
1256                 /* We display a message if a valid dvd source was not chosen */
1257                 [fSrcDVD2Field setStringValue: @"No Valid Source Found"];
1258         SuccessfulScan = NO;
1259
1260         // Notify ChapterTitles that there's no title
1261         [fChapterTitlesDelegate resetWithTitle:nil];
1262         [fChapterTable reloadData];
1263         }
1264         else
1265         {
1266         /* We increment the successful scancount here by one,
1267         which we use at the end of this function to tell the gui
1268         if this is the first successful scan since launch and whether
1269         or not we should set all settings to the defaults */
1270
1271         currentSuccessfulScanCount++;
1272
1273         [[fWindow toolbar] validateVisibleItems];
1274
1275                 [fSrcTitlePopUp removeAllItems];
1276                 for( int i = 0; i < hb_list_count( list ); i++ )
1277                 {
1278                         title = (hb_title_t *) hb_list_item( list, i );
1279
1280             currentSource = [NSString stringWithUTF8String: title->name];
1281
1282             /*Set DVD Name at top of window with the browsedSourceDisplayName grokked right before -performScan */
1283                         [fSrcDVD2Field setStringValue:browsedSourceDisplayName];
1284
1285                         /* Use the dvd name in the default output field here
1286                                 May want to add code to remove blank spaces for some dvd names*/
1287                         /* Check to see if the last destination has been set,use if so, if not, use Desktop */
1288             if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"])
1289                         {
1290                                 [fDstFile2Field setStringValue: [NSString stringWithFormat:
1291                                         @"%@/%@.mp4", [[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"],[browsedSourceDisplayName stringByDeletingPathExtension]]];
1292                         }
1293                         else
1294                         {
1295                                 [fDstFile2Field setStringValue: [NSString stringWithFormat:
1296                                         @"%@/Desktop/%@.mp4", NSHomeDirectory(),[browsedSourceDisplayName stringByDeletingPathExtension]]];
1297                         }
1298                         
1299                         if (longuestpri < title->hours*60*60 + title->minutes *60 + title->seconds)
1300                         {
1301                                 longuestpri=title->hours*60*60 + title->minutes *60 + title->seconds;
1302                                 indxpri=i;
1303                         }
1304                         /* Leave this here for now for reference. Keep it commented out or the macgui will crash in a
1305             * fiery wreck if you change sources.
1306             */
1307                         //[self formatPopUpChanged:NULL];
1308                         
1309             [fSrcTitlePopUp addItemWithTitle: [NSString
1310                 stringWithFormat: @"%d - %02dh%02dm%02ds",
1311                 title->index, title->hours, title->minutes,
1312                 title->seconds]];
1313                 }
1314
1315                 // Select the longuest title
1316                 [fSrcTitlePopUp selectItemAtIndex: indxpri];
1317                 [self titlePopUpChanged:nil];
1318
1319         SuccessfulScan = YES;
1320                 [self enableUI: YES];
1321
1322                 /* if its the initial successful scan after awakeFromNib */
1323         if (currentSuccessfulScanCount == 1)
1324         {
1325             [self selectDefaultPreset:nil];
1326             /* initially set deinterlace to 0, will be overridden reset by the default preset anyway */
1327             //[fPictureController setDeinterlace:0];
1328
1329             /* lets set Denoise to index 0 or "None" since this is the first scan */
1330             //[fPictureController setDenoise:0];
1331             
1332             [fPictureController setInitialPictureFilters];
1333         }
1334         
1335         }
1336 }
1337
1338
1339 #pragma mark -
1340 #pragma mark New Output Destination
1341
1342 - (IBAction) browseFile: (id) sender
1343 {
1344     /* Open a panel to let the user choose and update the text field */
1345     NSSavePanel * panel = [NSSavePanel savePanel];
1346         /* We get the current file name and path from the destination field here */
1347         [panel beginSheetForDirectory: [[fDstFile2Field stringValue] stringByDeletingLastPathComponent] file: [[fDstFile2Field stringValue] lastPathComponent]
1348                                    modalForWindow: fWindow modalDelegate: self
1349                                    didEndSelector: @selector( browseFileDone:returnCode:contextInfo: )
1350                                           contextInfo: NULL];
1351 }
1352
1353 - (void) browseFileDone: (NSSavePanel *) sheet
1354     returnCode: (int) returnCode contextInfo: (void *) contextInfo
1355 {
1356     if( returnCode == NSOKButton )
1357     {
1358         [fDstFile2Field setStringValue: [sheet filename]];
1359     }
1360 }
1361
1362
1363 #pragma mark -
1364 #pragma mark Main Window Control
1365
1366 - (IBAction) openMainWindow: (id) sender
1367 {
1368     [fWindow  makeKeyAndOrderFront:nil];
1369 }
1370
1371 - (BOOL) windowShouldClose: (id) sender
1372 {
1373     return YES;
1374 }
1375
1376 - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
1377 {
1378     if( !flag ) {
1379         [fWindow  makeKeyAndOrderFront:nil];
1380                 
1381         return YES;
1382     }
1383     
1384     return NO;
1385 }
1386
1387 #pragma mark -
1388 #pragma mark Job Handling
1389
1390
1391 - (void) prepareJob
1392 {
1393     hb_list_t  * list  = hb_get_titles( fHandle );
1394     hb_title_t * title = (hb_title_t *) hb_list_item( list,
1395             [fSrcTitlePopUp indexOfSelectedItem] );
1396     hb_job_t * job = title->job;
1397     hb_audio_config_t * audio;
1398
1399     /* Chapter selection */
1400     job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1;
1401     job->chapter_end   = [fSrcChapterEndPopUp   indexOfSelectedItem] + 1;
1402         
1403     /* Format (Muxer) and Video Encoder */
1404     job->mux = [[fDstFormatPopUp selectedItem] tag];
1405     job->vcodec = [[fVidEncoderPopUp selectedItem] tag];
1406
1407
1408     /* If mpeg-4, then set mpeg-4 specific options like chapters and > 4gb file sizes */
1409         if( [fDstFormatPopUp indexOfSelectedItem] == 0 )
1410         {
1411         /* We set the largeFileSize (64 bit formatting) variable here to allow for > 4gb files based on the format being
1412                 mpeg4 and the checkbox being checked 
1413                 *Note: this will break compatibility with some target devices like iPod, etc.!!!!*/
1414                 if( [fDstMp4LargeFileCheck state] == NSOnState )
1415                 {
1416                         job->largeFileSize = 1;
1417                 }
1418                 else
1419                 {
1420                         job->largeFileSize = 0;
1421                 }
1422         /* We set http optimized mp4 here */
1423         if( [fDstMp4HttpOptFileCheck state] == NSOnState && [fDstMp4HttpOptFileCheck isEnabled] )
1424                 {
1425         job->mp4_optimize = 1;
1426         }
1427         else
1428         {
1429         job->mp4_optimize = 0;
1430         }
1431     }
1432         if( [fDstFormatPopUp indexOfSelectedItem] == 0 || [fDstFormatPopUp indexOfSelectedItem] == 1 )
1433         {
1434           /* We set the chapter marker extraction here based on the format being
1435                 mpeg4 or mkv and the checkbox being checked */
1436                 if ([fCreateChapterMarkers state] == NSOnState)
1437                 {
1438                         job->chapter_markers = 1;
1439                 }
1440                 else
1441                 {
1442                         job->chapter_markers = 0;
1443                 }
1444         }
1445         
1446     if( job->vcodec & HB_VCODEC_X264 )
1447     {
1448                 if ([fDstMp4iPodFileCheck state] == NSOnState)
1449             {
1450             job->ipod_atom = 1;
1451                 }
1452         else
1453         {
1454         job->ipod_atom = 0;
1455         }
1456                 
1457                 /* Set this flag to switch from Constant Quantizer(default) to Constant Rate Factor Thanks jbrjake
1458          Currently only used with Constant Quality setting*/
1459                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0 && [fVidQualityMatrix selectedRow] == 2)
1460                 {
1461                 job->crf = 1;
1462                 }
1463                 
1464                 /* Below Sends x264 options to the core library if x264 is selected*/
1465                 /* Lets use this as per Nyx, Thanks Nyx!*/
1466                 job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */
1467                 /* Turbo first pass if two pass and Turbo First pass is selected */
1468                 if( [fVidTwoPassCheck state] == NSOnState && [fVidTurboPassCheck state] == NSOnState )
1469                 {
1470                         /* pass the "Turbo" string to be appended to the existing x264 opts string into a variable for the first pass */
1471                         NSString *firstPassOptStringTurbo = @":ref=1:subme=1:me=dia:analyse=none:trellis=0:no-fast-pskip=0:8x8dct=0:weightb=0";
1472                         /* append the "Turbo" string variable to the existing opts string.
1473              Note: the "Turbo" string must be appended, not prepended to work properly*/
1474                         NSString *firstPassOptStringCombined = [[fAdvancedOptions optionsString] stringByAppendingString:firstPassOptStringTurbo];
1475                         strcpy(job->x264opts, [firstPassOptStringCombined UTF8String]);
1476                 }
1477                 else
1478                 {
1479                         strcpy(job->x264opts, [[fAdvancedOptions optionsString] UTF8String]);
1480                 }
1481         
1482     }
1483
1484     /* Video settings */
1485     if( [fVidRatePopUp indexOfSelectedItem] > 0 )
1486     {
1487         job->vrate      = 27000000;
1488         job->vrate_base = hb_video_rates[[fVidRatePopUp
1489             indexOfSelectedItem]-1].rate;
1490         /* We are not same as source so we set job->cfr to 1 
1491          * to enable constant frame rate since user has specified
1492          * a specific framerate*/
1493         job->cfr = 1;
1494     }
1495     else
1496     {
1497         job->vrate      = title->rate;
1498         job->vrate_base = title->rate_base;
1499         /* We are same as source so we set job->cfr to 0 
1500          * to enable true same as source framerate */
1501         job->cfr = 0;
1502     }
1503
1504     switch( [fVidQualityMatrix selectedRow] )
1505     {
1506         case 0:
1507             /* Target size.
1508                Bitrate should already have been calculated and displayed
1509                in fVidBitrateField, so let's just use it */
1510         case 1:
1511             job->vquality = -1.0;
1512             job->vbitrate = [fVidBitrateField intValue];
1513             break;
1514         case 2:
1515             job->vquality = [fVidQualitySlider floatValue];
1516             job->vbitrate = 0;
1517             break;
1518     }
1519
1520     job->grayscale = ( [fVidGrayscaleCheck state] == NSOnState );
1521
1522     /* Subtitle settings */
1523     job->subtitle = [fSubPopUp indexOfSelectedItem] - 2;
1524
1525     /* Audio tracks and mixdowns */
1526     /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty*/
1527     int audiotrack_count = hb_list_count(job->list_audio);
1528     for( int i = 0; i < audiotrack_count;i++)
1529     {
1530         hb_audio_t * temp_audio = (hb_audio_t*) hb_list_item( job->list_audio, 0 );
1531         hb_list_rem(job->list_audio, temp_audio);
1532     }
1533     /* Now lets add our new tracks to the audio list here */
1534     if ([fAudLang1PopUp indexOfSelectedItem] > 0)
1535     {
1536         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
1537         hb_audio_config_init(audio);
1538         audio->in.track = [fAudLang1PopUp indexOfSelectedItem] - 1;
1539         /* We go ahead and assign values to our audio->out.<properties> */
1540         audio->out.track = [fAudLang1PopUp indexOfSelectedItem] - 1;
1541         audio->out.codec = [[fAudTrack1CodecPopUp selectedItem] tag];
1542         audio->out.mixdown = [[fAudTrack1MixPopUp selectedItem] tag];
1543         audio->out.bitrate = [[fAudTrack1BitratePopUp selectedItem] tag];
1544         audio->out.samplerate = [[fAudTrack1RatePopUp selectedItem] tag];
1545         audio->out.dynamic_range_compression = [fAudTrack1DrcField floatValue];
1546         
1547         hb_audio_add( job, audio );
1548         free(audio);
1549     }  
1550     if ([fAudLang2PopUp indexOfSelectedItem] > 0)
1551     {
1552         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
1553         hb_audio_config_init(audio);
1554         audio->in.track = [fAudLang2PopUp indexOfSelectedItem] - 1;
1555         /* We go ahead and assign values to our audio->out.<properties> */
1556         audio->out.track = [fAudLang2PopUp indexOfSelectedItem] - 1;
1557         audio->out.codec = [[fAudTrack2CodecPopUp selectedItem] tag];
1558         audio->out.mixdown = [[fAudTrack2MixPopUp selectedItem] tag];
1559         audio->out.bitrate = [[fAudTrack2BitratePopUp selectedItem] tag];
1560         audio->out.samplerate = [[fAudTrack2RatePopUp selectedItem] tag];
1561         audio->out.dynamic_range_compression = [fAudTrack2DrcField floatValue];
1562         
1563         hb_audio_add( job, audio );
1564         free(audio);
1565         
1566     }
1567     
1568     if ([fAudLang3PopUp indexOfSelectedItem] > 0)
1569     {
1570         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
1571         hb_audio_config_init(audio);
1572         audio->in.track = [fAudLang3PopUp indexOfSelectedItem] - 1;
1573         /* We go ahead and assign values to our audio->out.<properties> */
1574         audio->out.track = [fAudLang3PopUp indexOfSelectedItem] - 1;
1575         audio->out.codec = [[fAudTrack3CodecPopUp selectedItem] tag];
1576         audio->out.mixdown = [[fAudTrack3MixPopUp selectedItem] tag];
1577         audio->out.bitrate = [[fAudTrack3BitratePopUp selectedItem] tag];
1578         audio->out.samplerate = [[fAudTrack3RatePopUp selectedItem] tag];
1579         audio->out.dynamic_range_compression = [fAudTrack3DrcField floatValue];
1580         
1581         hb_audio_add( job, audio );
1582         free(audio);
1583         
1584     }
1585
1586     if ([fAudLang4PopUp indexOfSelectedItem] > 0)
1587     {
1588         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
1589         hb_audio_config_init(audio);
1590         audio->in.track = [fAudLang4PopUp indexOfSelectedItem] - 1;
1591         /* We go ahead and assign values to our audio->out.<properties> */
1592         audio->out.track = [fAudLang4PopUp indexOfSelectedItem] - 1;
1593         audio->out.codec = [[fAudTrack4CodecPopUp selectedItem] tag];
1594         audio->out.mixdown = [[fAudTrack4MixPopUp selectedItem] tag];
1595         audio->out.bitrate = [[fAudTrack4BitratePopUp selectedItem] tag];
1596         audio->out.samplerate = [[fAudTrack4RatePopUp selectedItem] tag];
1597         audio->out.dynamic_range_compression = [fAudTrack4DrcField floatValue];
1598         
1599         hb_audio_add( job, audio );
1600         free(audio);
1601         
1602     }
1603
1604     /* set vfr according to the Picture Window */
1605     if ([fPictureController vfr])
1606     {
1607         job->vfr = 1;
1608     }
1609     else
1610     {
1611         job->vfr = 0;
1612     }
1613     
1614     /* Filters */ 
1615     job->filters = hb_list_init();
1616     
1617     /* Now lets call the filters if applicable.
1618     * The order of the filters is critical
1619     */
1620     
1621         /* Detelecine */
1622     if ([fPictureController detelecine])
1623     {
1624         hb_list_add( job->filters, &hb_filter_detelecine );
1625     }
1626     
1627     /* Decomb */
1628     if ([fPictureController decomb] > 0)
1629     {
1630         /* Run old deinterlacer fd by default */
1631         //fPicSettingDecomb
1632         hb_filter_decomb.settings = (char *) [[fPicSettingDecomb stringValue] UTF8String];
1633         //hb_filter_decomb.settings = "4:10:15:9:10:35:9"; // <-- jbrjakes recommended parameters as of 5/23/08
1634         hb_list_add( job->filters, &hb_filter_decomb );
1635     }
1636
1637     
1638     /* Deinterlace */
1639     if ([fPictureController deinterlace] == 1)
1640     {
1641         /* Run old deinterlacer fd by default */
1642         hb_filter_deinterlace.settings = "-1"; 
1643         hb_list_add( job->filters, &hb_filter_deinterlace );
1644     }
1645     else if ([fPictureController deinterlace] == 2)
1646     {
1647         /* Yadif mode 0 (without spatial deinterlacing.) */
1648         hb_filter_deinterlace.settings = "2"; 
1649         hb_list_add( job->filters, &hb_filter_deinterlace );            
1650     }
1651     else if ([fPictureController deinterlace] == 3)
1652     {
1653         /* Yadif (with spatial deinterlacing) */
1654         hb_filter_deinterlace.settings = "0"; 
1655         hb_list_add( job->filters, &hb_filter_deinterlace );            
1656     }
1657         
1658     /* Denoise */
1659         if ([fPictureController denoise] == 1) // Weak in popup
1660         {
1661                 hb_filter_denoise.settings = "2:1:2:3"; 
1662         hb_list_add( job->filters, &hb_filter_denoise );        
1663         }
1664         else if ([fPictureController denoise] == 2) // Medium in popup
1665         {
1666                 hb_filter_denoise.settings = "3:2:2:3"; 
1667         hb_list_add( job->filters, &hb_filter_denoise );        
1668         }
1669         else if ([fPictureController denoise] == 3) // Strong in popup
1670         {
1671                 hb_filter_denoise.settings = "7:7:5:5"; 
1672         hb_list_add( job->filters, &hb_filter_denoise );        
1673         }
1674     
1675     /* Deblock  (uses pp7 default) */
1676     if ([fPictureController deblock])
1677     {
1678         hb_list_add( job->filters, &hb_filter_deblock );
1679     }
1680
1681 }
1682
1683
1684
1685 /* addToQueue: puts up an alert before ultimately calling doAddToQueue
1686 */
1687 - (IBAction) addToQueue: (id) sender
1688 {
1689         /* We get the destination directory from the destination field here */
1690         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
1691         /* We check for a valid destination here */
1692         if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) 
1693         {
1694                 NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil);
1695         return;
1696         }
1697
1698     /* We check for duplicate name here */
1699         if( [[NSFileManager defaultManager] fileExistsAtPath:
1700             [fDstFile2Field stringValue]] )
1701     {
1702         NSBeginCriticalAlertSheet( NSLocalizedString( @"File already exists", @"" ),
1703             NSLocalizedString( @"Cancel", @"" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self,
1704             @selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ),
1705             NULL, NULL, [NSString stringWithFormat:
1706             NSLocalizedString( @"Do you want to overwrite %@?", @"" ),
1707             [fDstFile2Field stringValue]] );
1708         // overwriteAddToQueueAlertDone: will be called when the alert is dismissed.
1709     }
1710
1711     // Warn if another pending job in the queue has the same destination path
1712     else if ( ([fQueueController pendingJobGroupWithDestinationPath:[fDstFile2Field stringValue]] != nil)
1713             || ([[[fQueueController currentJobGroup] destinationPath] isEqualToString: [fDstFile2Field stringValue]]) )
1714     {
1715         NSBeginCriticalAlertSheet( NSLocalizedString( @"Another queued encode has specified the same destination.", @"" ),
1716             NSLocalizedString( @"Cancel", @"" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self,
1717             @selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ),
1718             NULL, NULL, [NSString stringWithFormat:
1719             NSLocalizedString( @"Do you want to overwrite %@?", @"" ),
1720             [fDstFile2Field stringValue]] );
1721         // overwriteAddToQueueAlertDone: will be called when the alert is dismissed.
1722     }
1723     
1724     else
1725     {
1726         [self doAddToQueue];
1727     }
1728 }
1729
1730 /* overwriteAddToQueueAlertDone: called from the alert posted by addToQueue that asks
1731    the user if they want to overwrite an exiting movie file.
1732 */
1733 - (void) overwriteAddToQueueAlertDone: (NSWindow *) sheet
1734     returnCode: (int) returnCode contextInfo: (void *) contextInfo
1735 {
1736     if( returnCode == NSAlertAlternateReturn )
1737         [self doAddToQueue];
1738 }
1739
1740 - (void) doAddToQueue
1741 {
1742     hb_list_t  * list  = hb_get_titles( fHandle );
1743     hb_title_t * title = (hb_title_t *) hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
1744     hb_job_t * job = title->job;
1745
1746     // Create a Queue Controller job group. Each job that we submit to libhb will also
1747     // get added to the job group so that the queue can track the jobs.
1748    HBJobGroup * jobGroup = [HBJobGroup jobGroup];
1749     // The job group can maintain meta data that libhb can not...
1750    [jobGroup setPresetName: [fPresetSelectedDisplay stringValue]];
1751
1752     // Job groups require that each job within the group be assigned a unique id so
1753     // that the queue can xref between itself and the private jobs that libhb
1754     // maintains. The ID is composed a group id number and a "sequence" number. libhb
1755     // does not use this id.
1756    static int jobGroupID = 0;
1757    jobGroupID++;
1758     
1759     // A sequence number, starting at zero, is used to identifiy to each pass. This is
1760     // used by the queue UI to determine if a pass if the first pass of an encode.
1761     int sequenceNum = -1;
1762     
1763     [self prepareJob];
1764
1765     /* Destination file */
1766     job->file = [[fDstFile2Field stringValue] UTF8String];
1767
1768     if( [fSubForcedCheck state] == NSOnState )
1769         job->subtitle_force = 1;
1770     else
1771         job->subtitle_force = 0;
1772
1773     /*
1774     * subtitle of -1 is a scan
1775     */
1776     if( job->subtitle == -1 )
1777     {
1778         char *x264opts_tmp;
1779
1780         /*
1781         * When subtitle scan is enabled do a fast pre-scan job
1782         * which will determine which subtitles to enable, if any.
1783         */
1784         job->pass = -1;
1785         x264opts_tmp = job->x264opts;
1786         job->subtitle = -1;
1787
1788         job->x264opts = NULL;
1789
1790         job->indepth_scan = 1;  
1791
1792         job->select_subtitle = (hb_subtitle_t**)malloc(sizeof(hb_subtitle_t*));
1793         *(job->select_subtitle) = NULL;
1794
1795         /*
1796         * Add the pre-scan job
1797         */
1798         job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum);
1799         hb_add( fHandle, job );
1800         [jobGroup addJob:[HBJob jobWithLibhbJob:job]];     // add this pass to the job group
1801
1802         job->x264opts = x264opts_tmp;
1803     }
1804     else
1805         job->select_subtitle = NULL;
1806
1807     /* No subtitle were selected, so reset the subtitle to -1 (which before
1808     * this point meant we were scanning
1809     */
1810     if( job->subtitle == -2 )
1811         job->subtitle = -1;
1812
1813     if( [fVidTwoPassCheck state] == NSOnState )
1814     {
1815         hb_subtitle_t **subtitle_tmp = job->select_subtitle;
1816         job->indepth_scan = 0;
1817
1818         /*
1819          * Do not autoselect subtitles on the first pass of a two pass
1820          */
1821         job->select_subtitle = NULL;
1822         
1823         job->pass = 1;
1824         job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum);
1825         hb_add( fHandle, job );
1826         [jobGroup addJob:[HBJob jobWithLibhbJob:job]];     // add this pass to the job group
1827
1828         job->pass = 2;
1829         job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum);
1830
1831         job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */  
1832         strcpy(job->x264opts, [[fAdvancedOptions optionsString] UTF8String]);
1833
1834         job->select_subtitle = subtitle_tmp;
1835
1836         hb_add( fHandle, job );
1837         [jobGroup addJob:[HBJob jobWithLibhbJob:job]];     // add this pass to the job group
1838     }
1839     else
1840     {
1841         job->indepth_scan = 0;
1842         job->pass = 0;
1843         job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum);
1844         hb_add( fHandle, job );
1845         [jobGroup addJob:[HBJob jobWithLibhbJob:job]];     // add this pass to the job group
1846     }
1847         
1848     NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
1849         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
1850         
1851     // Let the queue controller know about the job group
1852     [fQueueController addJobGroup:jobGroup];
1853 }
1854
1855 /* Rip: puts up an alert before ultimately calling doRip
1856 */
1857 - (IBAction) Rip: (id) sender
1858 {
1859     /* Rip or Cancel ? */
1860     hb_state_t s;
1861     hb_get_state2( fHandle, &s );
1862
1863     if(s.state == HB_STATE_WORKING || s.state == HB_STATE_PAUSED)
1864         {
1865         [self Cancel: sender];
1866         return;
1867     }
1868     
1869     // If there are jobs in the queue, then this is a rip the queue
1870     
1871     if (hb_count( fHandle ) > 0)
1872     {
1873         [self doRip];
1874         return;
1875     }
1876
1877     // Before adding jobs to the queue, check for a valid destination.
1878
1879     NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
1880     if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) 
1881     {
1882         NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil);
1883         return;
1884     }
1885
1886     /* We check for duplicate name here */
1887     if( [[NSFileManager defaultManager] fileExistsAtPath:[fDstFile2Field stringValue]] )
1888     {
1889         NSBeginCriticalAlertSheet( NSLocalizedString( @"File already exists", @"" ),
1890             NSLocalizedString( @"Cancel", "" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self,
1891             @selector( overWriteAlertDone:returnCode:contextInfo: ),
1892             NULL, NULL, [NSString stringWithFormat:
1893             NSLocalizedString( @"Do you want to overwrite %@?", @"" ),
1894             [fDstFile2Field stringValue]] );
1895
1896         // overWriteAlertDone: will be called when the alert is dismissed. It will call doRip.
1897     }
1898     else
1899     {
1900         /* if there are no jobs in the queue, then add this one to the queue and rip
1901         otherwise, just rip the queue */
1902         if( hb_count( fHandle ) == 0)
1903         {
1904             [self doAddToQueue];
1905         }
1906
1907         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
1908         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
1909         [self doRip];
1910     }
1911 }
1912
1913 /* overWriteAlertDone: called from the alert posted by Rip: that asks the user if they
1914    want to overwrite an exiting movie file.
1915 */
1916 - (void) overWriteAlertDone: (NSWindow *) sheet
1917     returnCode: (int) returnCode contextInfo: (void *) contextInfo
1918 {
1919     if( returnCode == NSAlertAlternateReturn )
1920     {
1921         /* if there are no jobs in the queue, then add this one to the queue and rip 
1922         otherwise, just rip the queue */
1923         if( hb_count( fHandle ) == 0 )
1924         {
1925             [self doAddToQueue];
1926         }
1927
1928         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
1929         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
1930         [self doRip];
1931     }
1932 }
1933
1934 - (void) remindUserOfSleepOrShutdown
1935 {
1936        if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Put Computer To Sleep"])
1937        {
1938                /*Warn that computer will sleep after encoding*/
1939                int reminduser;
1940                NSBeep();
1941                reminduser = NSRunAlertPanel(@"The computer will sleep after encoding is done.",@"You have selected to sleep the computer after encoding. To turn off sleeping, go to the HandBrake preferences.", @"OK", @"Preferences...", nil);
1942                [NSApp requestUserAttention:NSCriticalRequest];
1943                if ( reminduser == NSAlertAlternateReturn )
1944                {
1945                        [self showPreferencesWindow:nil];
1946                }
1947        }
1948        else if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Shut Down Computer"])
1949        {
1950                /*Warn that computer will shut down after encoding*/
1951                int reminduser;
1952                NSBeep();
1953                reminduser = NSRunAlertPanel(@"The computer will shut down after encoding is done.",@"You have selected to shut down the computer after encoding. To turn off shut down, go to the HandBrake preferences.", @"OK", @"Preferences...", nil);
1954                [NSApp requestUserAttention:NSCriticalRequest];
1955                if ( reminduser == NSAlertAlternateReturn )
1956                {
1957                        [self showPreferencesWindow:nil];
1958                }
1959        }
1960
1961 }
1962
1963
1964 - (void) doRip
1965 {
1966     /* Let libhb do the job */
1967     hb_start( fHandle );
1968         /*set the fEncodeState State */
1969         fEncodeState = 1;
1970 }
1971
1972
1973
1974
1975 //------------------------------------------------------------------------------------
1976 // Removes all jobs from the queue. Does not cancel the current processing job.
1977 //------------------------------------------------------------------------------------
1978 - (void) doDeleteQueuedJobs
1979 {
1980     hb_job_t * job;
1981     while( ( job = hb_job( fHandle, 0 ) ) )
1982         hb_rem( fHandle, job );
1983 }
1984
1985 //------------------------------------------------------------------------------------
1986 // Cancels and deletes the current job and stops libhb from processing the remaining
1987 // encodes.
1988 //------------------------------------------------------------------------------------
1989 - (void) doCancelCurrentJob
1990 {
1991     // Stop the current job. hb_stop will only cancel the current pass and then set
1992     // its state to HB_STATE_WORKDONE. It also does this asynchronously. So when we
1993     // see the state has changed to HB_STATE_WORKDONE (in updateUI), we'll delete the
1994     // remaining passes of the job and then start the queue back up if there are any
1995     // remaining jobs.
1996      
1997     [fQueueController libhbWillStop];
1998     hb_stop( fHandle );
1999     fEncodeState = 2;   // don't alert at end of processing since this was a cancel
2000     
2001 }
2002
2003 //------------------------------------------------------------------------------------
2004 // Displays an alert asking user if the want to cancel encoding of current job.
2005 // Cancel: returns immediately after posting the alert. Later, when the user
2006 // acknowledges the alert, doCancelCurrentJob is called.
2007 //------------------------------------------------------------------------------------
2008 - (IBAction)Cancel: (id)sender
2009 {
2010     if (!fHandle) return;
2011     
2012     HBJobGroup * jobGroup = [fQueueController currentJobGroup];
2013     if (!jobGroup) return;
2014
2015     NSString * alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Stop encoding %@?", nil),
2016             [jobGroup name]];
2017     
2018     // Which window to attach the sheet to?
2019     NSWindow * docWindow;
2020     if ([sender respondsToSelector: @selector(window)])
2021         docWindow = [sender window];
2022     else
2023         docWindow = fWindow;
2024         
2025     NSBeginCriticalAlertSheet(
2026             alertTitle,
2027             NSLocalizedString(@"Keep Encoding", nil),
2028             nil,
2029             NSLocalizedString(@"Stop Encoding", nil),
2030             docWindow, self,
2031             nil, @selector(didDimissCancelCurrentJob:returnCode:contextInfo:), nil,
2032             NSLocalizedString(@"Your movie will be lost if you don't continue encoding.", nil));
2033     
2034     // didDimissCancelCurrentJob:returnCode:contextInfo: will be called when the dialog is dismissed
2035 }
2036
2037 - (void) didDimissCancelCurrentJob: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
2038 {
2039     if (returnCode == NSAlertOtherReturn)
2040         [self doCancelCurrentJob];  // <- this also stops libhb
2041 }
2042
2043 - (IBAction) Pause: (id) sender
2044 {
2045     hb_state_t s;
2046     hb_get_state2( fHandle, &s );
2047
2048     if( s.state == HB_STATE_PAUSED )
2049     {
2050         hb_resume( fHandle );
2051     }
2052     else
2053     {
2054         hb_pause( fHandle );
2055     }
2056 }
2057
2058 #pragma mark -
2059 #pragma mark GUI Controls Changed Methods
2060
2061 - (IBAction) titlePopUpChanged: (id) sender
2062 {
2063     hb_list_t  * list  = hb_get_titles( fHandle );
2064     hb_title_t * title = (hb_title_t*)
2065         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
2066
2067     /* If Auto Naming is on. We create an output filename of dvd name - title number */
2068     if( [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultAutoNaming"] > 0 && ( hb_list_count( list ) > 1 ) )
2069         {
2070                 [fDstFile2Field setStringValue: [NSString stringWithFormat:
2071                         @"%@/%@-%d.%@", [[fDstFile2Field stringValue] stringByDeletingLastPathComponent],
2072                         [browsedSourceDisplayName stringByDeletingPathExtension],
2073             title->index,
2074                         [[fDstFile2Field stringValue] pathExtension]]]; 
2075         }
2076
2077     /* Update chapter popups */
2078     [fSrcChapterStartPopUp removeAllItems];
2079     [fSrcChapterEndPopUp   removeAllItems];
2080     for( int i = 0; i < hb_list_count( title->list_chapter ); i++ )
2081     {
2082         [fSrcChapterStartPopUp addItemWithTitle: [NSString
2083             stringWithFormat: @"%d", i + 1]];
2084         [fSrcChapterEndPopUp addItemWithTitle: [NSString
2085             stringWithFormat: @"%d", i + 1]];
2086     }
2087
2088     [fSrcChapterStartPopUp selectItemAtIndex: 0];
2089     [fSrcChapterEndPopUp   selectItemAtIndex:
2090         hb_list_count( title->list_chapter ) - 1];
2091     [self chapterPopUpChanged:nil];
2092
2093     /* Start Get and set the initial pic size for display */
2094         hb_job_t * job = title->job;
2095         fTitle = title;
2096
2097         /*Set Source Size Field Here */
2098     [fPicSettingsSrc setStringValue: [NSString stringWithFormat: @"%d x %d", fTitle->width, fTitle->height]];
2099         
2100         /* Set Auto Crop to on upon selecting a new title */
2101     [fPictureController setAutoCrop:YES];
2102     
2103         /* We get the originial output picture width and height and put them
2104         in variables for use with some presets later on */
2105         PicOrigOutputWidth = job->width;
2106         PicOrigOutputHeight = job->height;
2107         AutoCropTop = job->crop[0];
2108         AutoCropBottom = job->crop[1];
2109         AutoCropLeft = job->crop[2];
2110         AutoCropRight = job->crop[3];
2111
2112         /* Run Through encoderPopUpChanged to see if there
2113                 needs to be any pic value modifications based on encoder settings */
2114         //[self encoderPopUpChanged: NULL];
2115         /* END Get and set the initial pic size for display */ 
2116
2117     /* Update subtitle popups */
2118     hb_subtitle_t * subtitle;
2119     [fSubPopUp removeAllItems];
2120     [fSubPopUp addItemWithTitle: @"None"];
2121     [fSubPopUp addItemWithTitle: @"Autoselect"];
2122     for( int i = 0; i < hb_list_count( title->list_subtitle ); i++ )
2123     {
2124         subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, i );
2125
2126         /* We cannot use NSPopUpButton's addItemWithTitle because
2127            it checks for duplicate entries */
2128         [[fSubPopUp menu] addItemWithTitle: [NSString stringWithCString:
2129             subtitle->lang] action: NULL keyEquivalent: @""];
2130     }
2131     [fSubPopUp selectItemAtIndex: 0];
2132
2133         [self subtitleSelectionChanged:nil];
2134
2135     /* Update chapter table */
2136     [fChapterTitlesDelegate resetWithTitle:title];
2137     [fChapterTable reloadData];
2138
2139    /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty*/
2140     int audiotrack_count = hb_list_count(job->list_audio);
2141     for( int i = 0; i < audiotrack_count;i++)
2142     {
2143         hb_audio_t * temp_audio = (hb_audio_t*) hb_list_item( job->list_audio, 0 );
2144         hb_list_rem(job->list_audio, temp_audio);
2145     }
2146
2147     /* Update audio popups */
2148     [self addAllAudioTracksToPopUp: fAudLang1PopUp];
2149     [self addAllAudioTracksToPopUp: fAudLang2PopUp];
2150     [self addAllAudioTracksToPopUp: fAudLang3PopUp];
2151     [self addAllAudioTracksToPopUp: fAudLang4PopUp];
2152     /* search for the first instance of our prefs default language for track 1, and set track 2 to "none" */
2153         NSString * audioSearchPrefix = [[NSUserDefaults standardUserDefaults] stringForKey:@"DefaultLanguage"];
2154         [self selectAudioTrackInPopUp: fAudLang1PopUp searchPrefixString: audioSearchPrefix selectIndexIfNotFound: 1];
2155     [self selectAudioTrackInPopUp:fAudLang2PopUp searchPrefixString:nil selectIndexIfNotFound:0];
2156     [self selectAudioTrackInPopUp:fAudLang3PopUp searchPrefixString:nil selectIndexIfNotFound:0];
2157     [self selectAudioTrackInPopUp:fAudLang4PopUp searchPrefixString:nil selectIndexIfNotFound:0];
2158
2159         /* changing the title may have changed the audio channels on offer, */
2160         /* so call audioTrackPopUpChanged for both audio tracks to update the mixdown popups */
2161         [self audioTrackPopUpChanged: fAudLang1PopUp];
2162         [self audioTrackPopUpChanged: fAudLang2PopUp];
2163     [self audioTrackPopUpChanged: fAudLang3PopUp];
2164     [self audioTrackPopUpChanged: fAudLang4PopUp];
2165
2166     [fVidRatePopUp selectItemAtIndex: 0];
2167
2168     /* we run the picture size values through calculatePictureSizing to get all picture setting information*/
2169         [self calculatePictureSizing:nil];
2170
2171    /* lets call tableViewSelected to make sure that any preset we have selected is enforced after a title change */
2172         [self selectPreset:nil];
2173 }
2174
2175 - (IBAction) chapterPopUpChanged: (id) sender
2176 {
2177
2178         /* If start chapter popup is greater than end chapter popup,
2179         we set the end chapter popup to the same as start chapter popup */
2180         if ([fSrcChapterStartPopUp indexOfSelectedItem] > [fSrcChapterEndPopUp indexOfSelectedItem])
2181         {
2182                 [fSrcChapterEndPopUp selectItemAtIndex: [fSrcChapterStartPopUp indexOfSelectedItem]];
2183     }
2184
2185                 
2186         hb_list_t  * list  = hb_get_titles( fHandle );
2187     hb_title_t * title = (hb_title_t *)
2188         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
2189
2190     hb_chapter_t * chapter;
2191     int64_t        duration = 0;
2192     for( int i = [fSrcChapterStartPopUp indexOfSelectedItem];
2193          i <= [fSrcChapterEndPopUp indexOfSelectedItem]; i++ )
2194     {
2195         chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i );
2196         duration += chapter->duration;
2197     }
2198     
2199     duration /= 90000; /* pts -> seconds */
2200     [fSrcDuration2Field setStringValue: [NSString stringWithFormat:
2201         @"%02lld:%02lld:%02lld", duration / 3600, ( duration / 60 ) % 60,
2202         duration % 60]];
2203
2204     [self calculateBitrate: sender];
2205 }
2206
2207 - (IBAction) formatPopUpChanged: (id) sender
2208 {
2209     NSString * string = [fDstFile2Field stringValue];
2210     int format = [fDstFormatPopUp indexOfSelectedItem];
2211     char * ext = NULL;
2212         /* Initially set the large file (64 bit formatting) output checkbox to hidden */
2213     [fDstMp4LargeFileCheck setHidden: YES];
2214     [fDstMp4HttpOptFileCheck setHidden: YES];
2215     [fDstMp4iPodFileCheck setHidden: YES];
2216     
2217     /* Update the Video Codec PopUp */
2218     /* Note: we now store the video encoder int values from common.c in the tags of each popup for easy retrieval later */
2219     [fVidEncoderPopUp removeAllItems];
2220     NSMenuItem *menuItem;
2221     /* These video encoders are available to all of our current muxers, so lets list them once here */
2222     menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"MPEG-4 (FFmpeg)" action: NULL keyEquivalent: @""];
2223     [menuItem setTag: HB_VCODEC_FFMPEG];
2224     
2225     menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"MPEG-4 (XviD)" action: NULL keyEquivalent: @""];
2226     [menuItem setTag: HB_VCODEC_XVID];
2227     switch( format )
2228     {
2229         case 0:
2230                         /*Get Default MP4 File Extension*/
2231                         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0)
2232                         {
2233                                 ext = "m4v";
2234                         }
2235                         else
2236                         {
2237                                 ext = "mp4";
2238                         }
2239             /* Add additional video encoders here */
2240             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"H.264 (x264)" action: NULL keyEquivalent: @""];
2241             [menuItem setTag: HB_VCODEC_X264];
2242             /* We show the mp4 option checkboxes here since we are mp4 */
2243             [fCreateChapterMarkers setEnabled: YES];
2244                         [fDstMp4LargeFileCheck setHidden: NO];
2245                         [fDstMp4HttpOptFileCheck setHidden: NO];
2246             [fDstMp4iPodFileCheck setHidden: NO];
2247             break;
2248             
2249             case 1:
2250             ext = "mkv";
2251             /* Add additional video encoders here */
2252             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"H.264 (x264)" action: NULL keyEquivalent: @""];
2253             [menuItem setTag: HB_VCODEC_X264];
2254             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"VP3 (Theora)" action: NULL keyEquivalent: @""];
2255             [menuItem setTag: HB_VCODEC_THEORA];
2256             /* We enable the create chapters checkbox here */
2257                         [fCreateChapterMarkers setEnabled: YES];
2258                         break;
2259             
2260             case 2: 
2261             ext = "avi";
2262             /* Add additional video encoders here */
2263             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"H.264 (x264)" action: NULL keyEquivalent: @""];
2264             [menuItem setTag: HB_VCODEC_X264];
2265             /* We disable the create chapters checkbox here and make sure it is unchecked*/
2266                         [fCreateChapterMarkers setEnabled: NO];
2267                         [fCreateChapterMarkers setState: NSOffState];
2268                         break;
2269             
2270             case 3:
2271             ext = "ogm";
2272             /* Add additional video encoders here */
2273             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"VP3 (Theora)" action: NULL keyEquivalent: @""];
2274             [menuItem setTag: HB_VCODEC_THEORA];
2275             /* We disable the create chapters checkbox here and make sure it is unchecked*/
2276                         [fCreateChapterMarkers setEnabled: NO];
2277                         [fCreateChapterMarkers setState: NSOffState];
2278                         break;
2279     }
2280     [fVidEncoderPopUp selectItemAtIndex: 0];
2281
2282     [self audioAddAudioTrackCodecs: fAudTrack1CodecPopUp];
2283     [self audioAddAudioTrackCodecs: fAudTrack2CodecPopUp];
2284     [self audioAddAudioTrackCodecs: fAudTrack3CodecPopUp];
2285     [self audioAddAudioTrackCodecs: fAudTrack4CodecPopUp];
2286
2287     if( format == 0 )
2288         [self autoSetM4vExtension: sender];
2289     else
2290         [fDstFile2Field setStringValue: [NSString stringWithFormat:@"%@.%s", [string stringByDeletingPathExtension], ext]];
2291
2292     if( SuccessfulScan )
2293     {
2294         /* Add/replace to the correct extension */
2295         [self audioTrackPopUpChanged: fAudLang1PopUp];
2296         [self audioTrackPopUpChanged: fAudLang2PopUp];
2297         [self audioTrackPopUpChanged: fAudLang3PopUp];
2298         [self audioTrackPopUpChanged: fAudLang4PopUp];
2299
2300         if( [fVidEncoderPopUp selectedItem] == nil )
2301         {
2302
2303             [fVidEncoderPopUp selectItemAtIndex:0];
2304             [self videoEncoderPopUpChanged:nil];
2305
2306             /* changing the format may mean that we can / can't offer mono or 6ch, */
2307             /* so call audioTrackPopUpChanged for both audio tracks to update the mixdown popups */
2308
2309             /* We call the method to properly enable/disable turbo 2 pass */
2310             [self twoPassCheckboxChanged: sender];
2311             /* We call method method to change UI to reflect whether a preset is used or not*/
2312         }
2313     }
2314         [self customSettingUsed: sender];
2315 }
2316
2317 - (IBAction) autoSetM4vExtension: (id) sender
2318 {
2319     if ( [fDstFormatPopUp indexOfSelectedItem] )
2320         return;
2321
2322     NSString * extension = @"mp4";
2323
2324     if( [[fAudTrack1CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack2CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
2325                                                         [[fAudTrack3CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
2326                                                         [[fAudTrack4CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
2327                                                         [fCreateChapterMarkers state] == NSOnState ||
2328                                                         [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0 )
2329     {
2330         extension = @"m4v";
2331     }
2332
2333     if( [extension isEqualTo: [[fDstFile2Field stringValue] pathExtension]] )
2334         return;
2335     else
2336         [fDstFile2Field setStringValue: [NSString stringWithFormat:@"%@.%@",
2337                                     [[fDstFile2Field stringValue] stringByDeletingPathExtension], extension]];
2338 }
2339
2340 - (void) shouldEnableHttpMp4CheckBox: (id) sender
2341 {
2342     if( [[fAudTrack1CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack2CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
2343                                                         [[fAudTrack3CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
2344                                                         [[fAudTrack4CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 )
2345         [fDstMp4HttpOptFileCheck setEnabled: NO];
2346     else
2347         [fDstMp4HttpOptFileCheck setEnabled: YES];
2348 }
2349         
2350 /* Method to determine if we should change the UI
2351 To reflect whether or not a Preset is being used or if
2352 the user is using "Custom" settings by determining the sender*/
2353 - (IBAction) customSettingUsed: (id) sender
2354 {
2355         if ([sender stringValue])
2356         {
2357                 /* Deselect the currently selected Preset if there is one*/
2358                 [fPresetsOutlineView deselectRow:[fPresetsOutlineView selectedRow]];
2359                 /* Change UI to show "Custom" settings are being used */
2360                 [fPresetSelectedDisplay setStringValue: @"Custom"];
2361
2362                 curUserPresetChosenNum = nil;
2363         }
2364 }
2365
2366
2367 #pragma mark -
2368 #pragma mark - Video
2369
2370 - (IBAction) videoEncoderPopUpChanged: (id) sender
2371 {
2372     hb_job_t * job = fTitle->job;
2373     int videoEncoder = [[fVidEncoderPopUp selectedItem] tag];
2374     
2375     [fAdvancedOptions setHidden:YES];
2376     /* If we are using x264 then show the x264 advanced panel*/
2377     if (videoEncoder == HB_VCODEC_X264)
2378     {
2379         [fAdvancedOptions setHidden:NO];
2380         [self autoSetM4vExtension: sender];
2381     }
2382     
2383     /* We need to set loose anamorphic as available depending on whether or not the ffmpeg encoder
2384     is being used as it borks up loose anamorphic .
2385     For convenience lets use the titleOfSelected index. Probably should revisit whether or not we want
2386     to use the index itself but this is easier */
2387     if (videoEncoder == HB_VCODEC_FFMPEG)
2388     {
2389         if (job->pixel_ratio == 2)
2390         {
2391             job->pixel_ratio = 0;
2392         }
2393         [fPictureController setAllowLooseAnamorphic:NO];
2394         /* We set the iPod atom checkbox to disabled and uncheck it as its only for x264 in the mp4
2395          container. Format is taken care of in formatPopUpChanged method by hiding and unchecking
2396          anything other than MP4.
2397          */ 
2398         [fDstMp4iPodFileCheck setEnabled: NO];
2399         [fDstMp4iPodFileCheck setState: NSOffState];
2400     }
2401     else
2402     {
2403         [fPictureController setAllowLooseAnamorphic:YES];
2404         [fDstMp4iPodFileCheck setEnabled: YES];
2405     }
2406     
2407         [self calculatePictureSizing: sender];
2408         [self twoPassCheckboxChanged: sender];
2409 }
2410
2411
2412 - (IBAction) twoPassCheckboxChanged: (id) sender
2413 {
2414         /* check to see if x264 is chosen */
2415         if([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_X264)
2416     {
2417                 if( [fVidTwoPassCheck state] == NSOnState)
2418                 {
2419                         [fVidTurboPassCheck setHidden: NO];
2420                 }
2421                 else
2422                 {
2423                         [fVidTurboPassCheck setHidden: YES];
2424                         [fVidTurboPassCheck setState: NSOffState];
2425                 }
2426                 /* Make sure Two Pass is checked if Turbo is checked */
2427                 if( [fVidTurboPassCheck state] == NSOnState)
2428                 {
2429                         [fVidTwoPassCheck setState: NSOnState];
2430                 }
2431         }
2432         else
2433         {
2434                 [fVidTurboPassCheck setHidden: YES];
2435                 [fVidTurboPassCheck setState: NSOffState];
2436         }
2437         
2438         /* We call method method to change UI to reflect whether a preset is used or not*/
2439         [self customSettingUsed: sender];
2440 }
2441
2442 - (IBAction ) videoFrameRateChanged: (id) sender
2443 {
2444     /* We call method method to calculatePictureSizing to error check detelecine*/
2445     [self calculatePictureSizing: sender];
2446
2447     /* We call method method to change UI to reflect whether a preset is used or not*/
2448         [self customSettingUsed: sender];
2449 }
2450 - (IBAction) videoMatrixChanged: (id) sender;
2451 {
2452     bool target, bitrate, quality;
2453
2454     target = bitrate = quality = false;
2455     if( [fVidQualityMatrix isEnabled] )
2456     {
2457         switch( [fVidQualityMatrix selectedRow] )
2458         {
2459             case 0:
2460                 target = true;
2461                 break;
2462             case 1:
2463                 bitrate = true;
2464                 break;
2465             case 2:
2466                 quality = true;
2467                 break;
2468         }
2469     }
2470     [fVidTargetSizeField  setEnabled: target];
2471     [fVidBitrateField     setEnabled: bitrate];
2472     [fVidQualitySlider    setEnabled: quality];
2473     [fVidTwoPassCheck     setEnabled: !quality &&
2474         [fVidQualityMatrix isEnabled]];
2475     if( quality )
2476     {
2477         [fVidTwoPassCheck setState: NSOffState];
2478                 [fVidTurboPassCheck setHidden: YES];
2479                 [fVidTurboPassCheck setState: NSOffState];
2480     }
2481
2482     [self qualitySliderChanged: sender];
2483     [self calculateBitrate: sender];
2484         [self customSettingUsed: sender];
2485 }
2486
2487 - (IBAction) qualitySliderChanged: (id) sender
2488 {
2489     [fVidConstantCell setTitle: [NSString stringWithFormat:
2490         NSLocalizedString( @"Constant quality: %.0f %%", @"" ), 100.0 *
2491         [fVidQualitySlider floatValue]]];
2492                 [self customSettingUsed: sender];
2493 }
2494
2495 - (void) controlTextDidChange: (NSNotification *) notification
2496 {
2497     [self calculateBitrate:nil];
2498 }
2499
2500 - (IBAction) calculateBitrate: (id) sender
2501 {
2502     if( !fHandle || [fVidQualityMatrix selectedRow] != 0 || !SuccessfulScan )
2503     {
2504         return;
2505     }
2506
2507     hb_list_t  * list  = hb_get_titles( fHandle );
2508     hb_title_t * title = (hb_title_t *) hb_list_item( list,
2509             [fSrcTitlePopUp indexOfSelectedItem] );
2510     hb_job_t * job = title->job;
2511
2512     [self prepareJob];
2513
2514     [fVidBitrateField setIntValue: hb_calc_bitrate( job,
2515             [fVidTargetSizeField intValue] )];
2516 }
2517
2518 #pragma mark -
2519 #pragma mark - Picture
2520
2521 /* lets set the picture size back to the max from right after title scan
2522    Lets use an IBAction here as down the road we could always use a checkbox
2523    in the gui to easily take the user back to max. Remember, the compiler
2524    resolves IBActions down to -(void) during compile anyway */
2525 - (IBAction) revertPictureSizeToMax: (id) sender
2526 {
2527         hb_job_t * job = fTitle->job;
2528         /* We use the output picture width and height
2529      as calculated from libhb right after title is set
2530      in TitlePopUpChanged */
2531         job->width = PicOrigOutputWidth;
2532         job->height = PicOrigOutputHeight;
2533     [fPictureController setAutoCrop:YES];
2534         /* Here we use the auto crop values determined right after scan */
2535         job->crop[0] = AutoCropTop;
2536         job->crop[1] = AutoCropBottom;
2537         job->crop[2] = AutoCropLeft;
2538         job->crop[3] = AutoCropRight;
2539     
2540     
2541     [self calculatePictureSizing: sender];
2542     /* We call method to change UI to reflect whether a preset is used or not*/    
2543     [self customSettingUsed: sender];
2544 }
2545
2546 /**
2547  * Registers changes made in the Picture Settings Window.
2548  */
2549
2550 - (void)pictureSettingsDidChange {
2551         [self calculatePictureSizing:nil];
2552 }
2553
2554 /* Get and Display Current Pic Settings in main window */
2555 - (IBAction) calculatePictureSizing: (id) sender
2556 {
2557         [fPicSettingsOutp setStringValue: [NSString stringWithFormat:@"%d x %d", fTitle->job->width, fTitle->job->height]];
2558         
2559     if (fTitle->job->pixel_ratio == 1)
2560         {
2561         int titlewidth = fTitle->width-fTitle->job->crop[2]-fTitle->job->crop[3];
2562         int arpwidth = fTitle->job->pixel_aspect_width;
2563         int arpheight = fTitle->job->pixel_aspect_height;
2564         int displayparwidth = titlewidth * arpwidth / arpheight;
2565         int displayparheight = fTitle->height-fTitle->job->crop[0]-fTitle->job->crop[1];
2566         [fPicSettingsOutp setStringValue: [NSString stringWithFormat:@"%d x %d", titlewidth, displayparheight]];
2567         [fPicSettingsAnamorphic setStringValue: [NSString stringWithFormat:@"%d x %d Strict", displayparwidth, displayparheight]];
2568         fTitle->job->keep_ratio = 0;
2569         }
2570     else if (fTitle->job->pixel_ratio == 2)
2571     {
2572         hb_job_t * job = fTitle->job;
2573         int output_width, output_height, output_par_width, output_par_height;
2574         hb_set_anamorphic_size(job, &output_width, &output_height, &output_par_width, &output_par_height);
2575         int display_width;
2576         display_width = output_width * output_par_width / output_par_height;
2577
2578         [fPicSettingsOutp setStringValue: [NSString stringWithFormat:@"%d x %d", output_width, output_height]];
2579         [fPicSettingsAnamorphic setStringValue: [NSString stringWithFormat:@"%d x %d Loose", display_width, output_height]];
2580
2581         fTitle->job->keep_ratio = 0;
2582     }
2583         else
2584         {
2585         [fPicSettingsAnamorphic setStringValue:@"Off"];
2586         }
2587
2588         /* Set ON/Off values for the deinterlace/keep aspect ratio according to boolean */
2589         if (fTitle->job->keep_ratio > 0)
2590         {
2591                 [fPicSettingARkeep setStringValue: @"On"];
2592         }
2593         else
2594         {
2595                 [fPicSettingARkeep setStringValue: @"Off"];
2596         }       
2597     
2598     /* Detelecine */
2599     if ([fPictureController detelecine]) {
2600         [fPicSettingDetelecine setStringValue: @"Yes"];
2601     }
2602     else {
2603         [fPicSettingDetelecine setStringValue: @"No"];
2604     }
2605     
2606     /* Decomb */
2607         if ([fPictureController decomb] == 0)
2608         {
2609                 [fPicSettingDecomb setStringValue: @"Off"];
2610         }
2611         else if ([fPictureController decomb] == 1)
2612         {
2613                 [fPicSettingDecomb setStringValue: @"1:2:6:9:80:16:16"];
2614         }
2615     else if ([fPictureController decomb] == 2)
2616     {
2617         [fPicSettingDecomb setStringValue:[[NSUserDefaults standardUserDefaults] stringForKey:@"DecombCustomString"]];
2618     }
2619
2620     /* VFR (Variable Frame Rate) */
2621     if ([fPictureController vfr]) {
2622         /* We change the string of the fps popup to warn that vfr is on Framerate (FPS): */
2623         [fVidRateField setStringValue: @"Framerate (VFR On):"]; 
2624         /* for VFR we select same as source (or title framerate) and disable the popup.
2625         * We know its index 0 as that is determined in titlePopUpChanged */
2626         [fVidRatePopUp selectItemAtIndex: 0];
2627         [fVidRatePopUp setEnabled: NO];  
2628         
2629     }
2630     else {
2631         /* make sure the label for framerate is set to its default */  
2632         [fVidRateField setStringValue: @"Framerate (FPS):"];
2633         [fVidRatePopUp setEnabled: YES];
2634     }
2635     
2636         /* Deinterlace */
2637         if ([fPictureController deinterlace] == 0)
2638         {
2639                 [fPicSettingDeinterlace setStringValue: @"Off"];
2640         }
2641         else if ([fPictureController deinterlace] == 1)
2642         {
2643                 [fPicSettingDeinterlace setStringValue: @"Fast"];
2644         }
2645         else if ([fPictureController deinterlace] == 2)
2646         {
2647                 [fPicSettingDeinterlace setStringValue: @"Slow"];
2648         }
2649         else if ([fPictureController deinterlace] == 3)
2650         {
2651                 [fPicSettingDeinterlace setStringValue: @"Slower"];
2652         }
2653                 
2654     /* Denoise */
2655         if ([fPictureController denoise] == 0)
2656         {
2657                 [fPicSettingDenoise setStringValue: @"Off"];
2658         }
2659         else if ([fPictureController denoise] == 1)
2660         {
2661                 [fPicSettingDenoise setStringValue: @"Weak"];
2662         }
2663         else if ([fPictureController denoise] == 2)
2664         {
2665                 [fPicSettingDenoise setStringValue: @"Medium"];
2666         }
2667         else if ([fPictureController denoise] == 3)
2668         {
2669                 [fPicSettingDenoise setStringValue: @"Strong"];
2670         }
2671     
2672     /* Deblock */
2673     if ([fPictureController deblock]) {
2674         [fPicSettingDeblock setStringValue: @"Yes"];
2675     }
2676     else {
2677         [fPicSettingDeblock setStringValue: @"No"];
2678     }
2679         
2680         if (fTitle->job->pixel_ratio > 0)
2681         {
2682                 [fPicSettingPAR setStringValue: @""];
2683         }
2684         else
2685         {
2686                 [fPicSettingPAR setStringValue: @"Off"];
2687         }
2688         
2689     /* Set the display field for crop as per boolean */
2690         if (![fPictureController autoCrop])
2691         {
2692             [fPicSettingAutoCrop setStringValue: @"Custom"];
2693         }
2694         else
2695         {
2696                 [fPicSettingAutoCrop setStringValue: @"Auto"];
2697         }       
2698         
2699     
2700 }
2701
2702
2703 #pragma mark -
2704 #pragma mark - Audio and Subtitles
2705 - (IBAction) audioCodecsPopUpChanged: (id) sender
2706 {
2707     
2708     NSPopUpButton * audiotrackPopUp;
2709     NSPopUpButton * sampleratePopUp;
2710     NSPopUpButton * bitratePopUp;
2711     NSPopUpButton * audiocodecPopUp;
2712     if (sender == fAudTrack1CodecPopUp)
2713     {
2714         audiotrackPopUp = fAudLang1PopUp;
2715         audiocodecPopUp = fAudTrack1CodecPopUp;
2716         sampleratePopUp = fAudTrack1RatePopUp;
2717         bitratePopUp = fAudTrack1BitratePopUp;
2718     }
2719     else if (sender == fAudTrack2CodecPopUp)
2720     {
2721         audiotrackPopUp = fAudLang2PopUp;
2722         audiocodecPopUp = fAudTrack2CodecPopUp;
2723         sampleratePopUp = fAudTrack2RatePopUp;
2724         bitratePopUp = fAudTrack2BitratePopUp;
2725     }
2726     else if (sender == fAudTrack3CodecPopUp)
2727     {
2728         audiotrackPopUp = fAudLang3PopUp;
2729         audiocodecPopUp = fAudTrack3CodecPopUp;
2730         sampleratePopUp = fAudTrack3RatePopUp;
2731         bitratePopUp = fAudTrack3BitratePopUp;
2732     }
2733     else
2734     {
2735         audiotrackPopUp = fAudLang4PopUp;
2736         audiocodecPopUp = fAudTrack4CodecPopUp;
2737         sampleratePopUp = fAudTrack4RatePopUp;
2738         bitratePopUp = fAudTrack4BitratePopUp;
2739     }
2740         
2741     /* changing the codecs on offer may mean that we can / can't offer mono or 6ch, */
2742         /* so call audioTrackPopUpChanged for both audio tracks to update the mixdown popups */
2743     [self audioTrackPopUpChanged: audiotrackPopUp];
2744     
2745 }
2746
2747 - (IBAction) setEnabledStateOfAudioMixdownControls: (id) sender
2748 {
2749     /* We will be setting the enabled/disabled state of each tracks audio controls based on
2750      * the settings of the source audio for that track. We leave the samplerate and bitrate
2751      * to audiotrackMixdownChanged
2752      */
2753     
2754     /* We will first verify that a lower track number has been selected before enabling each track
2755      * for example, make sure a track is selected for track 1 before enabling track 2, etc.
2756      */
2757     if ([fAudLang1PopUp indexOfSelectedItem] == 0)
2758     {
2759         [fAudLang2PopUp setEnabled: NO];
2760         [fAudLang2PopUp selectItemAtIndex: 0];
2761     }
2762     else
2763     {
2764         [fAudLang2PopUp setEnabled: YES];
2765     }
2766     
2767     if ([fAudLang2PopUp indexOfSelectedItem] == 0)
2768     {
2769         [fAudLang3PopUp setEnabled: NO];
2770         [fAudLang3PopUp selectItemAtIndex: 0];
2771     }
2772     else
2773     {
2774         [fAudLang3PopUp setEnabled: YES];
2775     }
2776     if ([fAudLang3PopUp indexOfSelectedItem] == 0)
2777     {
2778         [fAudLang4PopUp setEnabled: NO];
2779         [fAudLang4PopUp selectItemAtIndex: 0];
2780     }
2781     else
2782     {
2783         [fAudLang4PopUp setEnabled: YES];
2784     }
2785     /* enable/disable the mixdown text and popupbutton for audio track 1 */
2786     [fAudTrack1CodecPopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
2787     [fAudTrack1MixPopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
2788     [fAudTrack1RatePopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
2789     [fAudTrack1BitratePopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
2790     [fAudTrack1DrcSlider setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
2791     [fAudTrack1DrcField setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
2792     if ([fAudLang1PopUp indexOfSelectedItem] == 0)
2793     {
2794         [fAudTrack1CodecPopUp removeAllItems];
2795         [fAudTrack1MixPopUp removeAllItems];
2796         [fAudTrack1RatePopUp removeAllItems];
2797         [fAudTrack1BitratePopUp removeAllItems];
2798         [fAudTrack1DrcSlider setFloatValue: 1.00];
2799         [self audioDRCSliderChanged: fAudTrack1DrcSlider];
2800     }
2801     else if ([[fAudTrack1MixPopUp selectedItem] tag] == HB_ACODEC_AC3)
2802     {
2803         [fAudTrack1RatePopUp setEnabled: NO];
2804         [fAudTrack1BitratePopUp setEnabled: NO];
2805         [fAudTrack1DrcSlider setEnabled: NO];
2806         [fAudTrack1DrcField setEnabled: NO];
2807     }
2808     
2809     /* enable/disable the mixdown text and popupbutton for audio track 2 */
2810     [fAudTrack2CodecPopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
2811     [fAudTrack2MixPopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
2812     [fAudTrack2RatePopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
2813     [fAudTrack2BitratePopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
2814     [fAudTrack2DrcSlider setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
2815     [fAudTrack2DrcField setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
2816     if ([fAudLang2PopUp indexOfSelectedItem] == 0)
2817     {
2818         [fAudTrack2CodecPopUp removeAllItems];
2819         [fAudTrack2MixPopUp removeAllItems];
2820         [fAudTrack2RatePopUp removeAllItems];
2821         [fAudTrack2BitratePopUp removeAllItems];
2822         [fAudTrack2DrcSlider setFloatValue: 1.00];
2823         [self audioDRCSliderChanged: fAudTrack2DrcSlider];
2824     }
2825     else if ([[fAudTrack2MixPopUp selectedItem] tag] == HB_ACODEC_AC3)
2826     {
2827         [fAudTrack2RatePopUp setEnabled: NO];
2828         [fAudTrack2BitratePopUp setEnabled: NO];
2829         [fAudTrack2DrcSlider setEnabled: NO];
2830         [fAudTrack2DrcField setEnabled: NO];
2831     }
2832     
2833     /* enable/disable the mixdown text and popupbutton for audio track 3 */
2834     [fAudTrack3CodecPopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
2835     [fAudTrack3MixPopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
2836     [fAudTrack3RatePopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
2837     [fAudTrack3BitratePopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
2838     [fAudTrack3DrcSlider setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
2839     [fAudTrack3DrcField setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
2840     if ([fAudLang3PopUp indexOfSelectedItem] == 0)
2841     {
2842         [fAudTrack3CodecPopUp removeAllItems];
2843         [fAudTrack3MixPopUp removeAllItems];
2844         [fAudTrack3RatePopUp removeAllItems];
2845         [fAudTrack3BitratePopUp removeAllItems];
2846         [fAudTrack3DrcSlider setFloatValue: 1.00];
2847         [self audioDRCSliderChanged: fAudTrack3DrcSlider];
2848     }
2849     else if ([[fAudTrack3MixPopUp selectedItem] tag] == HB_ACODEC_AC3)
2850     {
2851         [fAudTrack3RatePopUp setEnabled: NO];
2852         [fAudTrack3BitratePopUp setEnabled: NO];
2853         [fAudTrack3DrcSlider setEnabled: NO];
2854         [fAudTrack3DrcField setEnabled: NO];
2855     }
2856     
2857     /* enable/disable the mixdown text and popupbutton for audio track 4 */
2858     [fAudTrack4CodecPopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
2859     [fAudTrack4MixPopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
2860     [fAudTrack4RatePopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
2861     [fAudTrack4BitratePopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
2862     [fAudTrack4DrcSlider setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
2863     [fAudTrack4DrcField setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
2864     if ([fAudLang4PopUp indexOfSelectedItem] == 0)
2865     {
2866         [fAudTrack4CodecPopUp removeAllItems];
2867         [fAudTrack4MixPopUp removeAllItems];
2868         [fAudTrack4RatePopUp removeAllItems];
2869         [fAudTrack4BitratePopUp removeAllItems];
2870         [fAudTrack4DrcSlider setFloatValue: 1.00];
2871         [self audioDRCSliderChanged: fAudTrack4DrcSlider];
2872     }
2873     else if ([[fAudTrack4MixPopUp selectedItem] tag] == HB_ACODEC_AC3)
2874     {
2875         [fAudTrack4RatePopUp setEnabled: NO];
2876         [fAudTrack4BitratePopUp setEnabled: NO];
2877         [fAudTrack4DrcSlider setEnabled: NO];
2878         [fAudTrack4DrcField setEnabled: NO];
2879     }
2880     
2881 }
2882
2883 - (IBAction) addAllAudioTracksToPopUp: (id) sender
2884 {
2885
2886     hb_list_t  * list  = hb_get_titles( fHandle );
2887     hb_title_t * title = (hb_title_t*)
2888         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
2889
2890         hb_audio_config_t * audio;
2891
2892     [sender removeAllItems];
2893     [sender addItemWithTitle: NSLocalizedString( @"None", @"" )];
2894     for( int i = 0; i < hb_list_count( title->list_audio ); i++ )
2895     {
2896         audio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, i );
2897         [[sender menu] addItemWithTitle:
2898             [NSString stringWithCString: audio->lang.description]
2899             action: NULL keyEquivalent: @""];
2900     }
2901     [sender selectItemAtIndex: 0];
2902
2903 }
2904
2905 - (IBAction) selectAudioTrackInPopUp: (id) sender searchPrefixString: (NSString *) searchPrefixString selectIndexIfNotFound: (int) selectIndexIfNotFound
2906 {
2907
2908     /* this method can be used to find a language, or a language-and-source-format combination, by passing in the appropriate string */
2909     /* e.g. to find the first French track, pass in an NSString * of "Francais" */
2910     /* e.g. to find the first English 5.1 AC3 track, pass in an NSString * of "English (AC3) (5.1 ch)" */
2911     /* if no matching track is found, then selectIndexIfNotFound is used to choose which track to select instead */
2912
2913         if (searchPrefixString)
2914         {
2915
2916         for( int i = 0; i < [sender numberOfItems]; i++ )
2917         {
2918             /* Try to find the desired search string */
2919             if ([[[sender itemAtIndex: i] title] hasPrefix:searchPrefixString])
2920             {
2921                 [sender selectItemAtIndex: i];
2922                 return;
2923             }
2924         }
2925         /* couldn't find the string, so select the requested "search string not found" item */
2926         /* index of 0 means select the "none" item */
2927         /* index of 1 means select the first audio track */
2928         [sender selectItemAtIndex: selectIndexIfNotFound];
2929         }
2930     else
2931     {
2932         /* if no search string is provided, then select the selectIndexIfNotFound item */
2933         [sender selectItemAtIndex: selectIndexIfNotFound];
2934     }
2935
2936 }
2937 - (IBAction) audioAddAudioTrackCodecs: (id)sender
2938 {
2939     int format = [fDstFormatPopUp indexOfSelectedItem];
2940     
2941     /* setup pointers to the appropriate popups for the correct track */
2942     NSPopUpButton * audiocodecPopUp;
2943     NSPopUpButton * audiotrackPopUp;
2944     if (sender == fAudTrack1CodecPopUp)
2945     {
2946         audiotrackPopUp = fAudLang1PopUp;
2947         audiocodecPopUp = fAudTrack1CodecPopUp;
2948     }
2949     else if (sender == fAudTrack2CodecPopUp)
2950     {
2951         audiotrackPopUp = fAudLang2PopUp;
2952         audiocodecPopUp = fAudTrack2CodecPopUp;
2953     }
2954     else if (sender == fAudTrack3CodecPopUp)
2955     {
2956         audiotrackPopUp = fAudLang3PopUp;
2957         audiocodecPopUp = fAudTrack3CodecPopUp;
2958     }
2959     else
2960     {
2961         audiotrackPopUp = fAudLang4PopUp;
2962         audiocodecPopUp = fAudTrack4CodecPopUp;
2963     }
2964     
2965     [audiocodecPopUp removeAllItems];
2966     /* Make sure "None" isnt selected in the source track */
2967     if ([audiotrackPopUp indexOfSelectedItem] > 0)
2968     {
2969         [audiocodecPopUp setEnabled:YES];
2970         NSMenuItem *menuItem;
2971         /* We setup our appropriate popups for codecs and put the int value in the popup tag for easy retrieval */
2972         switch( format )
2973         {
2974             case 0:
2975                 /* MP4 */
2976                 // AAC
2977                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""];
2978                 [menuItem setTag: HB_ACODEC_FAAC];
2979                 
2980                 // AC3 Passthru
2981                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""];
2982                 [menuItem setTag: HB_ACODEC_AC3];
2983                 break;
2984                 
2985             case 1:
2986                 /* MKV */
2987                 // AAC
2988                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""];
2989                 [menuItem setTag: HB_ACODEC_FAAC];
2990                 // AC3 Passthru
2991                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""];
2992                 [menuItem setTag: HB_ACODEC_AC3];
2993                 // MP3
2994                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""];
2995                 [menuItem setTag: HB_ACODEC_LAME];
2996                 // Vorbis
2997                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"Vorbis (vorbis)" action: NULL keyEquivalent: @""];
2998                 [menuItem setTag: HB_ACODEC_VORBIS];
2999                 break;
3000                 
3001             case 2: 
3002                 /* AVI */
3003                 // MP3
3004                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""];
3005                 [menuItem setTag: HB_ACODEC_LAME];
3006                 // AC3 Passthru
3007                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""];
3008                 [menuItem setTag: HB_ACODEC_AC3];
3009                 break;
3010                 
3011             case 3:
3012                 /* OGM */
3013                 // Vorbis
3014                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"Vorbis (vorbis)" action: NULL keyEquivalent: @""];
3015                 [menuItem setTag: HB_ACODEC_VORBIS];
3016                 // MP3
3017                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""];
3018                 [menuItem setTag: HB_ACODEC_LAME];
3019                 break;
3020         }
3021         [audiocodecPopUp selectItemAtIndex:0];
3022     }
3023     else
3024     {
3025         [audiocodecPopUp setEnabled:NO];
3026     }
3027 }
3028
3029 - (IBAction) audioTrackPopUpChanged: (id) sender
3030 {
3031     /* utility function to call audioTrackPopUpChanged without passing in a mixdown-to-use */
3032     [self audioTrackPopUpChanged: sender mixdownToUse: 0];
3033 }
3034
3035 - (IBAction) audioTrackPopUpChanged: (id) sender mixdownToUse: (int) mixdownToUse
3036 {
3037     
3038     /* make sure we have a selected title before continuing */
3039     if (fTitle == NULL) return;
3040     /* if the sender is the lanaguage popup and there is nothing in the codec popup, lets call
3041     * audioAddAudioTrackCodecs on the codec popup to populate it properly before moving on
3042     */
3043     if (sender == fAudLang1PopUp && [[fAudTrack1CodecPopUp menu] numberOfItems] == 0)
3044     {
3045         [self audioAddAudioTrackCodecs: fAudTrack1CodecPopUp];
3046     }
3047     if (sender == fAudLang2PopUp && [[fAudTrack2CodecPopUp menu] numberOfItems] == 0)
3048     {
3049         [self audioAddAudioTrackCodecs: fAudTrack2CodecPopUp];
3050     }
3051     if (sender == fAudLang3PopUp && [[fAudTrack3CodecPopUp menu] numberOfItems] == 0)
3052     {
3053         [self audioAddAudioTrackCodecs: fAudTrack3CodecPopUp];
3054     }
3055     if (sender == fAudLang4PopUp && [[fAudTrack4CodecPopUp menu] numberOfItems] == 0)
3056     {
3057         [self audioAddAudioTrackCodecs: fAudTrack4CodecPopUp];
3058     }
3059     
3060     /* Now lets make the sender the appropriate Audio Track popup from this point on */
3061     if (sender == fAudTrack1CodecPopUp || sender == fAudTrack1MixPopUp)
3062     {
3063         sender = fAudLang1PopUp;
3064     }
3065     if (sender == fAudTrack2CodecPopUp || sender == fAudTrack2MixPopUp)
3066     {
3067         sender = fAudLang2PopUp;
3068     }
3069     if (sender == fAudTrack3CodecPopUp || sender == fAudTrack3MixPopUp)
3070     {
3071         sender = fAudLang3PopUp;
3072     }
3073     if (sender == fAudTrack4CodecPopUp || sender == fAudTrack4MixPopUp)
3074     {
3075         sender = fAudLang4PopUp;
3076     }
3077     
3078     /* pointer to this track's mixdown, codec, sample rate and bitrate NSPopUpButton's */
3079     NSPopUpButton * mixdownPopUp;
3080     NSPopUpButton * audiocodecPopUp;
3081     NSPopUpButton * sampleratePopUp;
3082     NSPopUpButton * bitratePopUp;
3083     if (sender == fAudLang1PopUp)
3084     {
3085         mixdownPopUp = fAudTrack1MixPopUp;
3086         audiocodecPopUp = fAudTrack1CodecPopUp;
3087         sampleratePopUp = fAudTrack1RatePopUp;
3088         bitratePopUp = fAudTrack1BitratePopUp;
3089     }
3090     else if (sender == fAudLang2PopUp)
3091     {
3092         mixdownPopUp = fAudTrack2MixPopUp;
3093         audiocodecPopUp = fAudTrack2CodecPopUp;
3094         sampleratePopUp = fAudTrack2RatePopUp;
3095         bitratePopUp = fAudTrack2BitratePopUp;
3096     }
3097     else if (sender == fAudLang3PopUp)
3098     {
3099         mixdownPopUp = fAudTrack3MixPopUp;
3100         audiocodecPopUp = fAudTrack3CodecPopUp;
3101         sampleratePopUp = fAudTrack3RatePopUp;
3102         bitratePopUp = fAudTrack3BitratePopUp;
3103     }
3104     else
3105     {
3106         mixdownPopUp = fAudTrack4MixPopUp;
3107         audiocodecPopUp = fAudTrack4CodecPopUp;
3108         sampleratePopUp = fAudTrack4RatePopUp;
3109         bitratePopUp = fAudTrack4BitratePopUp;
3110     }
3111
3112     /* get the index of the selected audio Track*/
3113     int thisAudioIndex = [sender indexOfSelectedItem] - 1;
3114
3115     /* pointer for the hb_audio_s struct we will use later on */
3116     hb_audio_config_t * audio;
3117
3118     int acodec;
3119     /* check if the audio mixdown controls need their enabled state changing */
3120     [self setEnabledStateOfAudioMixdownControls:nil];
3121
3122     if (thisAudioIndex != -1)
3123     {
3124
3125         /* get the audio */
3126         audio = (hb_audio_config_t *) hb_list_audio_config_item( fTitle->list_audio, thisAudioIndex );// Should "fTitle" be title and be setup ?
3127
3128         /* actually manipulate the proper mixdowns here */
3129         /* delete the previous audio mixdown options */
3130         [mixdownPopUp removeAllItems];
3131
3132         acodec = [[audiocodecPopUp selectedItem] tag];
3133
3134         if (audio != NULL)
3135         {
3136
3137             /* find out if our selected output audio codec supports mono and / or 6ch */
3138             /* we also check for an input codec of AC3 or DCA,
3139              as they are the only libraries able to do the mixdown to mono / conversion to 6-ch */
3140             /* audioCodecsSupportMono and audioCodecsSupport6Ch are the same for now,
3141              but this may change in the future, so they are separated for flexibility */
3142             int audioCodecsSupportMono =
3143                     (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
3144                     (acodec != HB_ACODEC_LAME);
3145             int audioCodecsSupport6Ch =
3146                     (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
3147                     (acodec != HB_ACODEC_LAME);
3148             
3149             /* check for AC-3 passthru */
3150             if (audio->in.codec == HB_ACODEC_AC3 && acodec == HB_ACODEC_AC3)
3151             {
3152                 
3153             NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
3154                  [NSString stringWithCString: "AC3 Passthru"]
3155                                                action: NULL keyEquivalent: @""];
3156              [menuItem setTag: HB_ACODEC_AC3];   
3157             }
3158             else
3159             {
3160                 
3161                 /* add the appropriate audio mixdown menuitems to the popupbutton */
3162                 /* in each case, we set the new menuitem's tag to be the amixdown value for that mixdown,
3163                  so that we can reference the mixdown later */
3164                 
3165                 /* keep a track of the min and max mixdowns we used, so we can select the best match later */
3166                 int minMixdownUsed = 0;
3167                 int maxMixdownUsed = 0;
3168                 
3169                 /* get the input channel layout without any lfe channels */
3170                 int layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
3171                 
3172                 /* do we want to add a mono option? */
3173                 if (audioCodecsSupportMono == 1)
3174                 {
3175                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
3176                                             [NSString stringWithCString: hb_audio_mixdowns[0].human_readable_name]
3177                                                                           action: NULL keyEquivalent: @""];
3178                     [menuItem setTag: hb_audio_mixdowns[0].amixdown];
3179                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[0].amixdown;
3180                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[0].amixdown);
3181                 }
3182                 
3183                 /* do we want to add a stereo option? */
3184                 /* offer stereo if we have a mono source and non-mono-supporting codecs, as otherwise we won't have a mixdown at all */
3185                 /* also offer stereo if we have a stereo-or-better source */
3186                 if ((layout == HB_INPUT_CH_LAYOUT_MONO && audioCodecsSupportMono == 0) || layout >= HB_INPUT_CH_LAYOUT_STEREO)
3187                 {
3188                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
3189                                             [NSString stringWithCString: hb_audio_mixdowns[1].human_readable_name]
3190                                                                           action: NULL keyEquivalent: @""];
3191                     [menuItem setTag: hb_audio_mixdowns[1].amixdown];
3192                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[1].amixdown;
3193                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[1].amixdown);
3194                 }
3195                 
3196                 /* do we want to add a dolby surround (DPL1) option? */
3197                 if (layout == HB_INPUT_CH_LAYOUT_3F1R || layout == HB_INPUT_CH_LAYOUT_3F2R || layout == HB_INPUT_CH_LAYOUT_DOLBY)
3198                 {
3199                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
3200                                             [NSString stringWithCString: hb_audio_mixdowns[2].human_readable_name]
3201                                                                           action: NULL keyEquivalent: @""];
3202                     [menuItem setTag: hb_audio_mixdowns[2].amixdown];
3203                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[2].amixdown;
3204                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[2].amixdown);
3205                 }
3206                 
3207                 /* do we want to add a dolby pro logic 2 (DPL2) option? */
3208                 if (layout == HB_INPUT_CH_LAYOUT_3F2R)
3209                 {
3210                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
3211                                             [NSString stringWithCString: hb_audio_mixdowns[3].human_readable_name]
3212                                                                           action: NULL keyEquivalent: @""];
3213                     [menuItem setTag: hb_audio_mixdowns[3].amixdown];
3214                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[3].amixdown;
3215                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[3].amixdown);
3216                 }
3217                 
3218                 /* do we want to add a 6-channel discrete option? */
3219                 if (audioCodecsSupport6Ch == 1 && layout == HB_INPUT_CH_LAYOUT_3F2R && (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE))
3220                 {
3221                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
3222                                             [NSString stringWithCString: hb_audio_mixdowns[4].human_readable_name]
3223                                                                           action: NULL keyEquivalent: @""];
3224                     [menuItem setTag: hb_audio_mixdowns[4].amixdown];
3225                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[4].amixdown;
3226                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[4].amixdown);
3227                 }
3228                 
3229                 /* do we want to add an AC-3 passthrough option? */
3230                 if (audio->in.codec == HB_ACODEC_AC3 && acodec == HB_ACODEC_AC3) 
3231                 {
3232                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
3233                                             [NSString stringWithCString: hb_audio_mixdowns[5].human_readable_name]
3234                                                                           action: NULL keyEquivalent: @""];
3235                     [menuItem setTag: HB_ACODEC_AC3];
3236                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[5].amixdown;
3237                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[5].amixdown);
3238                 }
3239                 
3240                 /* auto-select the best mixdown based on our saved mixdown preference */
3241                 
3242                 /* for now, this is hard-coded to a "best" mixdown of HB_AMIXDOWN_DOLBYPLII */
3243                 /* ultimately this should be a prefs option */
3244                 int useMixdown;
3245                 
3246                 /* if we passed in a mixdown to use - in order to load a preset - then try and use it */
3247                 if (mixdownToUse > 0)
3248                 {
3249                     useMixdown = mixdownToUse;
3250                 }
3251                 else
3252                 {
3253                     useMixdown = HB_AMIXDOWN_DOLBYPLII;
3254                 }
3255                 
3256                 /* if useMixdown > maxMixdownUsed, then use maxMixdownUsed */
3257                 if (useMixdown > maxMixdownUsed)
3258                 { 
3259                     useMixdown = maxMixdownUsed;
3260                 }
3261                 
3262                 /* if useMixdown < minMixdownUsed, then use minMixdownUsed */
3263                 if (useMixdown < minMixdownUsed)
3264                 { 
3265                     useMixdown = minMixdownUsed;
3266                 }
3267                 
3268                 /* select the (possibly-amended) preferred mixdown */
3269                 [mixdownPopUp selectItemWithTag: useMixdown];
3270
3271             }
3272             /* In the case of a source track that is not AC3 and the user tries to use AC3 Passthru (which does not work)
3273              * we force the Audio Codec choice back to a workable codec. We use MP3 for avi and aac for all
3274              * other containers.
3275              */
3276             if (audio->in.codec != HB_ACODEC_AC3 && [[audiocodecPopUp selectedItem] tag] == HB_ACODEC_AC3)
3277             {
3278                 /* If we are using the avi container, we select MP3 as there is no aac available*/
3279                 if ([[fDstFormatPopUp selectedItem] tag] == HB_MUX_AVI)
3280                 {
3281                     [audiocodecPopUp selectItemWithTag: HB_ACODEC_LAME];
3282                 }
3283                 else
3284                 {
3285                     [audiocodecPopUp selectItemWithTag: HB_ACODEC_FAAC];
3286                 }
3287             }
3288             /* Setup our samplerate and bitrate popups we will need based on mixdown */
3289             [self audioTrackMixdownChanged: mixdownPopUp];             
3290         }
3291     
3292     }
3293     if( [fDstFormatPopUp indexOfSelectedItem] == 0 )
3294     {
3295         [self autoSetM4vExtension: sender];
3296         [self shouldEnableHttpMp4CheckBox: sender];
3297     }
3298 }
3299
3300 - (IBAction) audioTrackMixdownChanged: (id) sender
3301 {
3302     
3303     int acodec;
3304     /* setup pointers to all of the other audio track controls
3305     * we will need later
3306     */
3307     NSPopUpButton * mixdownPopUp;
3308     NSPopUpButton * sampleratePopUp;
3309     NSPopUpButton * bitratePopUp;
3310     NSPopUpButton * audiocodecPopUp;
3311     NSPopUpButton * audiotrackPopUp;
3312     NSSlider * drcSlider;
3313     NSTextField * drcField;
3314     if (sender == fAudTrack1MixPopUp)
3315     {
3316         audiotrackPopUp = fAudLang1PopUp;
3317         audiocodecPopUp = fAudTrack1CodecPopUp;
3318         mixdownPopUp = fAudTrack1MixPopUp;
3319         sampleratePopUp = fAudTrack1RatePopUp;
3320         bitratePopUp = fAudTrack1BitratePopUp;
3321         drcSlider = fAudTrack1DrcSlider;
3322         drcField = fAudTrack1DrcField;
3323     }
3324     else if (sender == fAudTrack2MixPopUp)
3325     {
3326         audiotrackPopUp = fAudLang2PopUp;
3327         audiocodecPopUp = fAudTrack2CodecPopUp;
3328         mixdownPopUp = fAudTrack2MixPopUp;
3329         sampleratePopUp = fAudTrack2RatePopUp;
3330         bitratePopUp = fAudTrack2BitratePopUp;
3331         drcSlider = fAudTrack2DrcSlider;
3332         drcField = fAudTrack2DrcField;
3333     }
3334     else if (sender == fAudTrack3MixPopUp)
3335     {
3336         audiotrackPopUp = fAudLang3PopUp;
3337         audiocodecPopUp = fAudTrack3CodecPopUp;
3338         mixdownPopUp = fAudTrack3MixPopUp;
3339         sampleratePopUp = fAudTrack3RatePopUp;
3340         bitratePopUp = fAudTrack3BitratePopUp;
3341         drcSlider = fAudTrack3DrcSlider;
3342         drcField = fAudTrack3DrcField;
3343     }
3344     else
3345     {
3346         audiotrackPopUp = fAudLang4PopUp;
3347         audiocodecPopUp = fAudTrack4CodecPopUp;
3348         mixdownPopUp = fAudTrack4MixPopUp;
3349         sampleratePopUp = fAudTrack4RatePopUp;
3350         bitratePopUp = fAudTrack4BitratePopUp;
3351         drcSlider = fAudTrack4DrcSlider;
3352         drcField = fAudTrack4DrcField;
3353     }
3354     acodec = [[audiocodecPopUp selectedItem] tag];
3355     /* storage variable for the min and max bitrate allowed for this codec */
3356     int minbitrate;
3357     int maxbitrate;
3358     
3359     switch( acodec )
3360     {
3361         case HB_ACODEC_FAAC:
3362             /* check if we have a 6ch discrete conversion in either audio track */
3363             if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
3364             {
3365                 /* FAAC is happy using our min bitrate of 32 kbps, even for 6ch */
3366                 minbitrate = 32;
3367                 /* If either mixdown popup includes 6-channel discrete, then allow up to 384 kbps */
3368                 maxbitrate = 384;
3369                 break;
3370             }
3371             else
3372             {
3373                 /* FAAC is happy using our min bitrate of 32 kbps for stereo or mono */
3374                 minbitrate = 32;
3375                 /* FAAC won't honour anything more than 160 for stereo, so let's not offer it */
3376                 /* note: haven't dealt with mono separately here, FAAC will just use the max it can */
3377                 maxbitrate = 160;
3378                 break;
3379             }
3380             
3381             case HB_ACODEC_LAME:
3382             /* Lame is happy using our min bitrate of 32 kbps */
3383             minbitrate = 32;
3384             /* Lame won't encode if the bitrate is higher than 320 kbps */
3385             maxbitrate = 320;
3386             break;
3387             
3388             case HB_ACODEC_VORBIS:
3389             if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
3390             {
3391                 /* Vorbis causes a crash if we use a bitrate below 192 kbps with 6 channel */
3392                 minbitrate = 192;
3393                 /* If either mixdown popup includes 6-channel discrete, then allow up to 384 kbps */
3394                 maxbitrate = 384;
3395                 break;
3396             }
3397             else
3398             {
3399                 /* Vorbis causes a crash if we use a bitrate below 48 kbps */
3400                 minbitrate = 48;
3401                 /* Vorbis can cope with 384 kbps quite happily, even for stereo */
3402                 maxbitrate = 384;
3403                 break;
3404             }
3405             
3406             default:
3407             /* AC3 passthru disables the bitrate dropdown anyway, so we might as well just use the min and max bitrate */
3408             minbitrate = 32;
3409             maxbitrate = 384;
3410             
3411     }
3412     
3413     /* make sure we have a selected title before continuing */
3414     if (fTitle == NULL) return;
3415     /* get the audio so we can find out what input rates are*/
3416     hb_audio_config_t * audio;
3417     audio = (hb_audio_config_t *) hb_list_audio_config_item( fTitle->list_audio, [audiotrackPopUp indexOfSelectedItem] - 1 );
3418     int inputbitrate = audio->in.bitrate / 1000;
3419     int inputsamplerate = audio->in.samplerate;
3420     
3421     if ([[mixdownPopUp selectedItem] tag] != HB_ACODEC_AC3)
3422     {
3423         [bitratePopUp removeAllItems];
3424         
3425         for( int i = 0; i < hb_audio_bitrates_count; i++ )
3426         {
3427             if (hb_audio_bitrates[i].rate >= minbitrate && hb_audio_bitrates[i].rate <= maxbitrate)
3428             {
3429                 /* add a new menuitem for this bitrate */
3430                 NSMenuItem *menuItem = [[bitratePopUp menu] addItemWithTitle:
3431                                         [NSString stringWithCString: hb_audio_bitrates[i].string]
3432                                                                       action: NULL keyEquivalent: @""];
3433                 /* set its tag to be the actual bitrate as an integer, so we can retrieve it later */
3434                 [menuItem setTag: hb_audio_bitrates[i].rate];
3435             }
3436         }
3437         
3438         /* select the default bitrate (but use 384 for 6-ch AAC) */
3439         if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
3440         {
3441             [bitratePopUp selectItemWithTag: 384];
3442         }
3443         else
3444         {
3445             [bitratePopUp selectItemWithTag: hb_audio_bitrates[hb_audio_bitrates_default].rate];
3446         }
3447     }
3448     /* populate and set the sample rate popup */
3449     /* Audio samplerate */
3450     [sampleratePopUp removeAllItems];
3451     /* we create a same as source selection (Auto) so that we can choose to use the input sample rate */
3452     NSMenuItem *menuItem = [[sampleratePopUp menu] addItemWithTitle: @"Auto" action: NULL keyEquivalent: @""];
3453     [menuItem setTag: inputsamplerate];
3454     
3455     for( int i = 0; i < hb_audio_rates_count; i++ )
3456     {
3457         NSMenuItem *menuItem = [[sampleratePopUp menu] addItemWithTitle:
3458                                 [NSString stringWithCString: hb_audio_rates[i].string]
3459                                                                  action: NULL keyEquivalent: @""];
3460         [menuItem setTag: hb_audio_rates[i].rate];
3461     }
3462     /* We use the input sample rate as the default sample rate as downsampling just makes audio worse
3463     * and there is no compelling reason to use anything else as default, though the users default
3464     * preset will likely override any setting chosen here.
3465     */
3466     [sampleratePopUp selectItemWithTag: inputsamplerate];
3467     
3468     
3469     /* Since AC3 Pass Thru uses the input ac3 bitrate and sample rate, we get the input tracks
3470     * bitrate and dispay it in the bitrate popup even though libhb happily ignores any bitrate input from
3471     * the gui. We do this for better user feedback in the audio tab as well as the queue for the most part
3472     */
3473     if ([[mixdownPopUp selectedItem] tag] == HB_ACODEC_AC3)
3474     {
3475         
3476         /* lets also set the bitrate popup to the input bitrate as thats what passthru will use */
3477         [bitratePopUp removeAllItems];
3478         NSMenuItem *menuItem = [[bitratePopUp menu] addItemWithTitle:
3479                                 [NSString stringWithFormat:@"%d", inputbitrate]
3480                                                               action: NULL keyEquivalent: @""];
3481         [menuItem setTag: inputbitrate];
3482         /* For ac3 passthru we disable the sample rate and bitrate popups as well as the drc slider*/
3483         [bitratePopUp setEnabled: NO];
3484         [sampleratePopUp setEnabled: NO];
3485         
3486         [drcSlider setFloatValue: 1.00];
3487         [self audioDRCSliderChanged: drcSlider];
3488         [drcSlider setEnabled: NO];
3489         [drcField setEnabled: NO];
3490     }
3491     else
3492     {
3493         [sampleratePopUp setEnabled: YES];
3494         [bitratePopUp setEnabled: YES];
3495         [drcSlider setEnabled: YES];
3496         [drcField setEnabled: YES];
3497     }
3498     
3499 }
3500
3501 - (IBAction) audioDRCSliderChanged: (id) sender
3502 {
3503     NSSlider * drcSlider;
3504     NSTextField * drcField;
3505     if (sender == fAudTrack1DrcSlider)
3506     {
3507         drcSlider = fAudTrack1DrcSlider;
3508         drcField = fAudTrack1DrcField;
3509     }
3510     else if (sender == fAudTrack2DrcSlider)
3511     {
3512         drcSlider = fAudTrack2DrcSlider;
3513         drcField = fAudTrack2DrcField;
3514     }
3515     else if (sender == fAudTrack3DrcSlider)
3516     {
3517         drcSlider = fAudTrack3DrcSlider;
3518         drcField = fAudTrack3DrcField;
3519     }
3520     else
3521     {
3522         drcSlider = fAudTrack4DrcSlider;
3523         drcField = fAudTrack4DrcField;
3524     }
3525     [drcField setStringValue: [NSString stringWithFormat: @"%.2f", [drcSlider floatValue]]];
3526     /* For now, do not call this until we have an intelligent way to determine audio track selections
3527     * compared to presets
3528     */
3529     //[self customSettingUsed: sender];
3530 }
3531
3532 - (IBAction) subtitleSelectionChanged: (id) sender
3533 {
3534         if ([fSubPopUp indexOfSelectedItem] == 0)
3535         {
3536         [fSubForcedCheck setState: NSOffState];
3537         [fSubForcedCheck setEnabled: NO];       
3538         }
3539         else
3540         {
3541         [fSubForcedCheck setEnabled: YES];      
3542         }
3543         
3544 }
3545
3546
3547
3548
3549 #pragma mark -
3550 #pragma mark Open New Windows
3551
3552 - (IBAction) openHomepage: (id) sender
3553 {
3554     [[NSWorkspace sharedWorkspace] openURL: [NSURL
3555         URLWithString:@"http://handbrake.fr/"]];
3556 }
3557
3558 - (IBAction) openForums: (id) sender
3559 {
3560     [[NSWorkspace sharedWorkspace] openURL: [NSURL
3561         URLWithString:@"http://handbrake.fr/forum/"]];
3562 }
3563 - (IBAction) openUserGuide: (id) sender
3564 {
3565     [[NSWorkspace sharedWorkspace] openURL: [NSURL
3566         URLWithString:@"http://handbrake.fr/trac/wiki/HandBrakeGuide"]];
3567 }
3568
3569 /**
3570  * Shows debug output window.
3571  */
3572 - (IBAction)showDebugOutputPanel:(id)sender
3573 {
3574     [outputPanel showOutputPanel:sender];
3575 }
3576
3577 /**
3578  * Shows preferences window.
3579  */
3580 - (IBAction) showPreferencesWindow: (id) sender
3581 {
3582     NSWindow * window = [fPreferencesController window];
3583     if (![window isVisible])
3584         [window center];
3585
3586     [window makeKeyAndOrderFront: nil];
3587 }
3588
3589 /**
3590  * Shows queue window.
3591  */
3592 - (IBAction) showQueueWindow:(id)sender
3593 {
3594     [fQueueController showQueueWindow:sender];
3595 }
3596
3597
3598 - (IBAction) toggleDrawer:(id)sender {
3599     [fPresetDrawer toggle:self];
3600 }
3601
3602 /**
3603  * Shows Picture Settings Window.
3604  */
3605
3606 - (IBAction) showPicturePanel: (id) sender
3607 {
3608         hb_list_t  * list  = hb_get_titles( fHandle );
3609     hb_title_t * title = (hb_title_t *) hb_list_item( list,
3610             [fSrcTitlePopUp indexOfSelectedItem] );
3611     [fPictureController showPanelInWindow:fWindow forTitle:title];
3612 }
3613
3614 #pragma mark -
3615 #pragma mark Preset Outline View Methods
3616 #pragma mark - Required
3617 /* These are required by the NSOutlineView Datasource Delegate */
3618 /* We use this to deterimine children of an item */
3619 - (id)outlineView:(NSOutlineView *)fPresetsOutlineView child:(NSInteger)index ofItem:(id)item
3620 {
3621 if (item == nil)
3622         return [UserPresets objectAtIndex:index];
3623     
3624     // We are only one level deep, so we can't be asked about children
3625     NSAssert (NO, @"Presets View outlineView:child:ofItem: currently can't handle nested items.");
3626     return nil;
3627 }
3628 /* We use this to determine if an item should be expandable */
3629 - (BOOL)outlineView:(NSOutlineView *)fPresetsOutlineView isItemExpandable:(id)item
3630 {
3631
3632     /* For now, we maintain one level, so set to no
3633     * when nested, we set to yes for any preset "folders"
3634     */
3635     return NO;
3636
3637 }
3638 /* used to specify the number of levels to show for each item */
3639 - (int)outlineView:(NSOutlineView *)fPresetsOutlineView numberOfChildrenOfItem:(id)item
3640 {
3641     /* currently use no levels to test outline view viability */
3642     if (item == nil)
3643         return [UserPresets count];
3644     else
3645         return 0;
3646 }
3647 /* Used to tell the outline view which information is to be displayed per item */
3648 - (id)outlineView:(NSOutlineView *)fPresetsOutlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
3649 {
3650         /* We have two columns right now, icon and PresetName */
3651         
3652     if ([[tableColumn identifier] isEqualToString:@"PresetName"])
3653     {
3654         return [item objectForKey:@"PresetName"];
3655     }
3656     else
3657     {
3658         return @"something";
3659     }
3660 }
3661
3662 #pragma mark - Added Functionality (optional)
3663 /* Use to customize the font and display characteristics of the title cell */
3664 - (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
3665 {
3666     if ([[tableColumn identifier] isEqualToString:@"PresetName"])
3667     {
3668         NSDictionary *userPresetDict = item;
3669         NSFont *txtFont;
3670         NSColor *fontColor;
3671         NSColor *shadowColor;
3672         txtFont = [NSFont systemFontOfSize: [NSFont smallSystemFontSize]];
3673         /*check to see if its a selected row */
3674         if ([fPresetsOutlineView selectedRow] == [fPresetsOutlineView rowForItem:item])
3675         {
3676             
3677             fontColor = [NSColor blackColor];
3678             shadowColor = [NSColor colorWithDeviceRed:(127.0/255.0) green:(140.0/255.0) blue:(160.0/255.0) alpha:1.0];
3679         }
3680         else
3681         {
3682             if ([[userPresetDict objectForKey:@"Type"] intValue] == 0)
3683             {
3684                 fontColor = [NSColor blueColor];
3685             }
3686             else // User created preset, use a black font
3687             {
3688                 fontColor = [NSColor blackColor];
3689             }
3690             shadowColor = nil;
3691         }
3692         /* We use Bold Text for the HB Default */
3693         if ([[userPresetDict objectForKey:@"Default"] intValue] == 1)// 1 is HB default
3694         {
3695             txtFont = [NSFont boldSystemFontOfSize: [NSFont smallSystemFontSize]];
3696         }
3697         /* We use Bold Text for the User Specified Default */
3698         if ([[userPresetDict objectForKey:@"Default"] intValue] == 2)// 2 is User default
3699         {
3700             txtFont = [NSFont boldSystemFontOfSize: [NSFont smallSystemFontSize]];
3701         }
3702         
3703         
3704         [cell setTextColor:fontColor];
3705         [cell setFont:txtFont];
3706         
3707     }
3708 }
3709
3710 /* We use this to edit the name field in the outline view */
3711 - (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
3712 {
3713     if ([[tableColumn identifier] isEqualToString:@"PresetName"])
3714     {
3715         id theRecord;
3716         
3717         theRecord = item;
3718         [theRecord setObject:object forKey:@"PresetName"];
3719         
3720         [self sortPresets];
3721         
3722         [fPresetsOutlineView reloadData];
3723         /* We save all of the preset data here */
3724         [self savePreset];
3725     }
3726 }
3727 /* We use this to provide tooltips for the items in the presets outline view */
3728 - (NSString *)outlineView:(NSOutlineView *)fPresetsOutlineView toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)tc item:(id)item mouseLocation:(NSPoint)mouseLocation
3729 {
3730     //if ([[tc identifier] isEqualToString:@"PresetName"])
3731     //{
3732         /* initialize the tooltip contents variable */
3733         NSString *loc_tip;
3734         /* if there is a description for the preset, we show it in the tooltip */
3735         if ([item objectForKey:@"PresetDescription"])
3736         {
3737             loc_tip = [item objectForKey:@"PresetDescription"];
3738             return (loc_tip);
3739         }
3740         else
3741         {
3742             loc_tip = @"No description available";
3743         }
3744         return (loc_tip);
3745     //}
3746 }
3747
3748 #pragma mark -
3749 #pragma mark Preset Outline View Methods (dragging related)
3750
3751
3752 - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard
3753 {
3754         // Dragging is only allowed for custom presets.
3755         if ([[[UserPresets objectAtIndex:[fPresetsOutlineView selectedRow]] objectForKey:@"Type"] intValue] == 0) // 0 is built in preset
3756     {
3757         return NO;
3758     }
3759     // Don't retain since this is just holding temporaral drag information, and it is
3760     //only used during a drag!  We could put this in the pboard actually.
3761     fDraggedNodes = items;
3762     // Provide data for our custom type, and simple NSStrings.
3763     [pboard declareTypes:[NSArray arrayWithObjects: DragDropSimplePboardType, nil] owner:self];
3764     
3765     // the actual data doesn't matter since DragDropSimplePboardType drags aren't recognized by anyone but us!.
3766     [pboard setData:[NSData data] forType:DragDropSimplePboardType]; 
3767     
3768     return YES;
3769 }
3770
3771 - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
3772 {
3773         // Don't allow dropping ONTO an item since they can't really contain any children.
3774     
3775     BOOL isOnDropTypeProposal = index == NSOutlineViewDropOnItemIndex;
3776     if (isOnDropTypeProposal)
3777         return NSDragOperationNone;
3778     
3779     
3780         // Don't allow dropping INTO an item since they can't really contain any children as of yet.
3781         
3782     if (item != nil)
3783         {
3784                 index = [fPresetsOutlineView rowForItem: item] + 1;
3785                 item = nil;
3786         }
3787     
3788     // Don't allow dropping into the Built In Presets.
3789     if (index < presetCurrentBuiltInCount)
3790     {
3791         return NSDragOperationNone;
3792         index = MAX (index, presetCurrentBuiltInCount);
3793         }
3794         
3795     [outlineView setDropItem:item dropChildIndex:index];
3796     return NSDragOperationGeneric;
3797 }
3798
3799
3800
3801 - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(int)index
3802 {
3803     NSMutableIndexSet *moveItems = [NSMutableIndexSet indexSet];
3804     
3805     id obj;
3806     NSEnumerator *enumerator = [fDraggedNodes objectEnumerator];
3807     while (obj = [enumerator nextObject])
3808     {
3809         [moveItems addIndex:[UserPresets indexOfObject:obj]];
3810     }
3811     // Successful drop, lets rearrange the view and save it all
3812     [self moveObjectsInPresetsArray:UserPresets fromIndexes:moveItems toIndex: index];
3813     [fPresetsOutlineView reloadData];
3814     [self savePreset];
3815     return YES;
3816 }
3817
3818 - (void)moveObjectsInPresetsArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(unsigned)insertIndex
3819 {
3820     unsigned index = [indexSet lastIndex];
3821     unsigned aboveInsertIndexCount = 0;
3822     
3823     while (index != NSNotFound)
3824     {
3825         unsigned removeIndex;
3826         
3827         if (index >= insertIndex)
3828         {
3829             removeIndex = index + aboveInsertIndexCount;
3830             aboveInsertIndexCount++;
3831         }
3832         else
3833         {
3834             removeIndex = index;
3835             insertIndex--;
3836         }
3837         
3838         id object = [[array objectAtIndex:removeIndex] retain];
3839         [array removeObjectAtIndex:removeIndex];
3840         [array insertObject:object atIndex:insertIndex];
3841         [object release];
3842         
3843         index = [indexSet indexLessThanIndex:index];
3844     }
3845 }
3846
3847
3848
3849 #pragma mark - Functional Preset NSOutlineView Methods
3850
3851 - (IBAction)selectPreset:(id)sender
3852 {
3853
3854     if ([fPresetsOutlineView selectedRow] >= 0)
3855     {
3856         chosenPreset = [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]];
3857         /* we set the preset display field in main window here */
3858         [fPresetSelectedDisplay setStringValue:[chosenPreset objectForKey:@"PresetName"]];
3859         if ([[chosenPreset objectForKey:@"Default"] intValue] == 1)
3860         {
3861             [fPresetSelectedDisplay setStringValue:[NSString stringWithFormat:@"%@ (Default)", [chosenPreset objectForKey:@"PresetName"]]];
3862         }
3863         else
3864         {
3865             [fPresetSelectedDisplay setStringValue:[chosenPreset objectForKey:@"PresetName"]];
3866         }
3867         /* File Format */
3868         [fDstFormatPopUp selectItemWithTitle:[chosenPreset objectForKey:@"FileFormat"]];
3869         [self formatPopUpChanged:nil];
3870
3871         /* Chapter Markers*/
3872         [fCreateChapterMarkers setState:[[chosenPreset objectForKey:@"ChapterMarkers"] intValue]];
3873         /* Allow Mpeg4 64 bit formatting +4GB file sizes */
3874         [fDstMp4LargeFileCheck setState:[[chosenPreset objectForKey:@"Mp4LargeFile"] intValue]];
3875         /* Mux mp4 with http optimization */
3876         [fDstMp4HttpOptFileCheck setState:[[chosenPreset objectForKey:@"Mp4HttpOptimize"] intValue]];
3877
3878         /* Video encoder */
3879         /* We set the advanced opt string here if applicable*/
3880         [fAdvancedOptions setOptions:[chosenPreset objectForKey:@"x264Option"]];
3881         /* We use a conditional to account for the new x264 encoder dropdown as well as presets made using legacy x264 settings*/
3882         if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264 (h.264 Main)"] ||
3883             [[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264 (h.264 iPod)"] ||
3884             [[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264"])
3885         {
3886             [fVidEncoderPopUp selectItemWithTitle:@"H.264 (x264)"];
3887             /* special case for legacy preset to check the new fDstMp4HttpOptFileCheck checkbox to set the ipod atom */
3888             if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"x264 (h.264 iPod)"])
3889             {
3890                 [fDstMp4iPodFileCheck setState:NSOnState];
3891                 /* We also need to add "level=30:" to the advanced opts string to set the correct level for the iPod when
3892                  encountering a legacy preset as it used to be handled separately from the opt string*/
3893                 [fAdvancedOptions setOptions:[@"level=30:" stringByAppendingString:[fAdvancedOptions optionsString]]];
3894             }
3895             else
3896             {
3897                 [fDstMp4iPodFileCheck setState:NSOffState];
3898             }
3899         }
3900         else if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"FFmpeg"])
3901         {
3902             [fVidEncoderPopUp selectItemWithTitle:@"MPEG-4 (FFmpeg)"];
3903         }
3904         else if ([[chosenPreset objectForKey:@"VideoEncoder"] isEqualToString:@"XviD"])
3905         {
3906             [fVidEncoderPopUp selectItemWithTitle:@"MPEG-4 (XviD)"];
3907         }
3908         else
3909         {
3910             [fVidEncoderPopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoEncoder"]];
3911         }
3912
3913         /* Lets run through the following functions to get variables set there */
3914         [self videoEncoderPopUpChanged:nil];
3915         /* Set the state of ipod compatible with Mp4iPodCompatible. Only for x264*/
3916         [fDstMp4iPodFileCheck setState:[[chosenPreset objectForKey:@"Mp4iPodCompatible"] intValue]];
3917         [self calculateBitrate:nil];
3918
3919         /* Video quality */
3920         [fVidQualityMatrix selectCellAtRow:[[chosenPreset objectForKey:@"VideoQualityType"] intValue] column:0];
3921
3922         [fVidTargetSizeField setStringValue:[chosenPreset objectForKey:@"VideoTargetSize"]];
3923         [fVidBitrateField setStringValue:[chosenPreset objectForKey:@"VideoAvgBitrate"]];
3924         [fVidQualitySlider setFloatValue:[[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue]];
3925
3926         [self videoMatrixChanged:nil];
3927
3928         /* Video framerate */
3929         /* For video preset video framerate, we want to make sure that Same as source does not conflict with the
3930          detected framerate in the fVidRatePopUp so we use index 0*/
3931         if ([[chosenPreset objectForKey:@"VideoFramerate"] isEqualToString:@"Same as source"])
3932         {
3933             [fVidRatePopUp selectItemAtIndex: 0];
3934         }
3935         else
3936         {
3937             [fVidRatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoFramerate"]];
3938         }
3939
3940         /* GrayScale */
3941         [fVidGrayscaleCheck setState:[[chosenPreset objectForKey:@"VideoGrayScale"] intValue]];
3942
3943         /* 2 Pass Encoding */
3944         [fVidTwoPassCheck setState:[[chosenPreset objectForKey:@"VideoTwoPass"] intValue]];
3945         [self twoPassCheckboxChanged:nil];
3946         /* Turbo 1st pass for 2 Pass Encoding */
3947         [fVidTurboPassCheck setState:[[chosenPreset objectForKey:@"VideoTurboTwoPass"] intValue]];
3948
3949         /*Audio*/
3950         if ([chosenPreset objectForKey:@"FileCodecs"])
3951         {
3952             /* We need to handle the audio codec popup by determining what was chosen from the deprecated Codecs PopUp for past presets*/
3953             if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString: @"AVC/H.264 Video / AAC + AC3 Audio"])
3954             {
3955                 /* We need to address setting languages etc. here in the new multi track audio panel */
3956                 /* Track One set here */
3957                 /*for track one though a track should be selected but lets check here anyway and use track one if its not.*/
3958                 if ([fAudLang1PopUp indexOfSelectedItem] == 0)
3959                 {
3960                     [fAudLang1PopUp selectItemAtIndex: 1];
3961                     [self audioTrackPopUpChanged: fAudLang1PopUp];
3962                 }
3963                 [fAudTrack1CodecPopUp selectItemWithTitle: @"AAC (faac)"];
3964                 [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
3965                 /* Track Two, set source same as track one */
3966                 [fAudLang2PopUp selectItemAtIndex: [fAudLang1PopUp indexOfSelectedItem]];
3967                 [self audioTrackPopUpChanged: fAudLang2PopUp];
3968                 [fAudTrack2CodecPopUp selectItemWithTitle: @"AC3 Passthru"];
3969                 [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
3970             }
3971             else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / AAC Audio"] ||
3972                      [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / AAC Audio"])
3973             {
3974                 if ([fAudLang1PopUp indexOfSelectedItem] > 0)
3975                 {
3976                     [fAudTrack1CodecPopUp selectItemWithTitle: @"AAC (faac)"];
3977                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
3978                 }
3979                 if ([fAudLang2PopUp indexOfSelectedItem] > 0)
3980                 {
3981                     [fAudTrack2CodecPopUp selectItemWithTitle: @"AAC (faac)"];
3982                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
3983                 }
3984                 if ([fAudLang3PopUp indexOfSelectedItem] > 0)
3985                 {
3986                     [fAudTrack3CodecPopUp selectItemWithTitle: @"AAC (faac)"];
3987                     [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
3988                 }
3989                 if ([fAudLang4PopUp indexOfSelectedItem] > 0)
3990                 {
3991                     [fAudTrack4CodecPopUp selectItemWithTitle: @"AAC (faac)"];
3992                     [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
3993                 }
3994             }
3995             else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / AC-3 Audio"] ||
3996                      [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / AC-3 Audio"])
3997             {
3998                 if ([fAudLang1PopUp indexOfSelectedItem] > 0)
3999                 {
4000                     [fAudTrack1CodecPopUp selectItemWithTitle: @"AC3 Passthru"];
4001                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
4002                 }
4003                 if ([fAudLang2PopUp indexOfSelectedItem] > 0)
4004                 {
4005                     [fAudTrack2CodecPopUp selectItemWithTitle: @"AC3 Passthru"];
4006                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
4007                 }
4008                 if ([fAudLang3PopUp indexOfSelectedItem] > 0)
4009                 {
4010                     [fAudTrack3CodecPopUp selectItemWithTitle: @"AC3 Passthru"];
4011                     [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
4012                 }
4013                 if ([fAudLang4PopUp indexOfSelectedItem] > 0)
4014                 {
4015                     [fAudTrack4CodecPopUp selectItemWithTitle: @"AC3 Passthru"];
4016                     [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
4017                 }
4018             }
4019             else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / MP3 Audio"] ||
4020                      [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / MP3 Audio"])
4021             {
4022                 if ([fAudLang1PopUp indexOfSelectedItem] > 0)
4023                 {
4024                     [fAudTrack1CodecPopUp selectItemWithTitle: @"MP3 (lame)"];
4025                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
4026                 }
4027                 if ([fAudLang2PopUp indexOfSelectedItem] > 0)
4028                 {
4029                     [fAudTrack2CodecPopUp selectItemWithTitle: @"MP3 (lame)"];
4030                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
4031                 }
4032                 if ([fAudLang3PopUp indexOfSelectedItem] > 0)
4033                 {
4034                     [fAudTrack3CodecPopUp selectItemWithTitle: @"MP3 (lame)"];
4035                     [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
4036                 }
4037                 if ([fAudLang4PopUp indexOfSelectedItem] > 0)
4038                 {
4039                     [fAudTrack4CodecPopUp selectItemWithTitle: @"MP3 (lame)"];
4040                     [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
4041                 }
4042             }
4043             else if ([[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"MPEG-4 Video / Vorbis Audio"])
4044             {
4045                 if ([fAudLang1PopUp indexOfSelectedItem] > 0)
4046                 {
4047                     [fAudTrack1CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"];
4048                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
4049                 }
4050                 if ([fAudLang2PopUp indexOfSelectedItem] > 0)
4051                 {
4052                     [fAudTrack2CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"];
4053                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
4054                 }
4055                 if ([fAudLang3PopUp indexOfSelectedItem] > 0)
4056                 {
4057                     [fAudTrack3CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"];
4058                     [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
4059                 }
4060                 if ([fAudLang4PopUp indexOfSelectedItem] > 0)
4061                 {
4062                     [fAudTrack4CodecPopUp selectItemWithTitle: @"Vorbis (vorbis)"];
4063                     [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
4064                 }
4065             }
4066             /* We detect here if we have the old audio sample rate and if so we apply samplerate and bitrate to the existing four tracks if chosen
4067             * UNLESS the CodecPopUp is AC3 in which case the preset values are ignored in favor of rates set in audioTrackMixdownChanged*/
4068             if ([chosenPreset objectForKey:@"AudioSampleRate"])
4069             {
4070                 if ([fAudLang1PopUp indexOfSelectedItem] > 0 && [fAudTrack1CodecPopUp titleOfSelectedItem] != @"AC3 Passthru")
4071                 {
4072                     [fAudTrack1RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]];
4073                     [fAudTrack1BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]];
4074                 }
4075                 if ([fAudLang2PopUp indexOfSelectedItem] > 0 && [fAudTrack2CodecPopUp titleOfSelectedItem] != @"AC3 Passthru")
4076                 {
4077                     [fAudTrack2RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]];
4078                     [fAudTrack2BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]];
4079                 }
4080                 if ([fAudLang3PopUp indexOfSelectedItem] > 0 && [fAudTrack3CodecPopUp titleOfSelectedItem] != @"AC3 Passthru")
4081                 {
4082                     [fAudTrack3RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]];
4083                     [fAudTrack3BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]];
4084                 }
4085                 if ([fAudLang4PopUp indexOfSelectedItem] > 0 && [fAudTrack4CodecPopUp titleOfSelectedItem] != @"AC3 Passthru")
4086                 {
4087                     [fAudTrack4RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioSampleRate"]];
4088                     [fAudTrack4BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"AudioBitRate"]];
4089                 }
4090             }
4091             /* We detect here if we have the old DRC Slider and if so we apply it to the existing four tracks if chosen */
4092             if ([chosenPreset objectForKey:@"AudioDRCSlider"])
4093             {
4094                 if ([fAudLang1PopUp indexOfSelectedItem] > 0)
4095                 {
4096                     [fAudTrack1DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]];
4097                     [self audioDRCSliderChanged: fAudTrack1DrcSlider];
4098                 }
4099                 if ([fAudLang2PopUp indexOfSelectedItem] > 0)
4100                 {
4101                     [fAudTrack2DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]];
4102                     [self audioDRCSliderChanged: fAudTrack2DrcSlider];
4103                 }
4104                 if ([fAudLang3PopUp indexOfSelectedItem] > 0)
4105                 {
4106                     [fAudTrack3DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]];
4107                     [self audioDRCSliderChanged: fAudTrack3DrcSlider];
4108                 }
4109                 if ([fAudLang4PopUp indexOfSelectedItem] > 0)
4110                 {
4111                     [fAudTrack4DrcSlider setFloatValue:[[chosenPreset objectForKey:@"AudioDRCSlider"] floatValue]];
4112                     [self audioDRCSliderChanged: fAudTrack4DrcSlider];
4113                 }
4114             }
4115         }
4116         else // since there was no codecs key in the preset we know we can use new multi-audio track presets
4117         {
4118             if ([chosenPreset objectForKey:@"Audio1Track"] > 0)
4119             {
4120                 if ([fAudLang1PopUp indexOfSelectedItem] == 0)
4121                 {
4122                     [fAudLang1PopUp selectItemAtIndex: 1];
4123                 }
4124                 [self audioTrackPopUpChanged: fAudLang1PopUp];
4125                 [fAudTrack1CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Encoder"]];
4126                 [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
4127                 [fAudTrack1MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Mixdown"]];
4128                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
4129                  * mixdown*/
4130                 if  ([fAudTrack1MixPopUp selectedItem] == nil)
4131                 {
4132                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
4133                 }
4134                 [fAudTrack1RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Samplerate"]];
4135                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
4136                 if (![[chosenPreset objectForKey:@"Audio1Encoder"] isEqualToString:@"AC3 Passthru"])
4137                 {
4138                     [fAudTrack1BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Bitrate"]];
4139                 }
4140                 [fAudTrack1DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio1TrackDRCSlider"] floatValue]];
4141                 [self audioDRCSliderChanged: fAudTrack1DrcSlider];
4142             }
4143             if ([chosenPreset objectForKey:@"Audio2Track"] > 0)
4144             {
4145                 if ([fAudLang2PopUp indexOfSelectedItem] == 0)
4146                 {
4147                     [fAudLang2PopUp selectItemAtIndex: 1];
4148                 }
4149                 [self audioTrackPopUpChanged: fAudLang2PopUp];
4150                 [fAudTrack2CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Encoder"]];
4151                 [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
4152                 [fAudTrack2MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Mixdown"]];
4153                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
4154                  * mixdown*/
4155                 if  ([fAudTrack2MixPopUp selectedItem] == nil)
4156                 {
4157                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
4158                 }
4159                 [fAudTrack2RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Samplerate"]];
4160                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
4161                 if (![[chosenPreset objectForKey:@"Audio2Encoder"] isEqualToString:@"AC3 Passthru"])
4162                 {
4163                     [fAudTrack2BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Bitrate"]];
4164                 }
4165                 [fAudTrack2DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio2TrackDRCSlider"] floatValue]];
4166                 [self audioDRCSliderChanged: fAudTrack2DrcSlider];
4167             }
4168             if ([chosenPreset objectForKey:@"Audio3Track"] > 0)
4169             {
4170                 if ([fAudLang3PopUp indexOfSelectedItem] == 0)
4171                 {
4172                     [fAudLang3PopUp selectItemAtIndex: 1];
4173                 }
4174                 [self audioTrackPopUpChanged: fAudLang3PopUp];
4175                 [fAudTrack3CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Encoder"]];
4176                 [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
4177                 [fAudTrack3MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Mixdown"]];
4178                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
4179                  * mixdown*/
4180                 if  ([fAudTrack3MixPopUp selectedItem] == nil)
4181                 {
4182                     [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
4183                 }
4184                 [fAudTrack3RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Samplerate"]];
4185                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
4186                 if (![[chosenPreset objectForKey:@"Audio3Encoder"] isEqualToString: @"AC3 Passthru"])
4187                 {
4188                     [fAudTrack3BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Bitrate"]];
4189                 }
4190                 [fAudTrack3DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio3TrackDRCSlider"] floatValue]];
4191                 [self audioDRCSliderChanged: fAudTrack3DrcSlider];
4192             }
4193             if ([chosenPreset objectForKey:@"Audio4Track"] > 0)
4194             {
4195                 if ([fAudLang4PopUp indexOfSelectedItem] == 0)
4196                 {
4197                     [fAudLang4PopUp selectItemAtIndex: 1];
4198                 }
4199                 [self audioTrackPopUpChanged: fAudLang4PopUp];
4200                 [fAudTrack4CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Encoder"]];
4201                 [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
4202                 [fAudTrack4MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Mixdown"]];
4203                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
4204                  * mixdown*/
4205                 if  ([fAudTrack4MixPopUp selectedItem] == nil)
4206                 {
4207                     [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
4208                 }
4209                 [fAudTrack4RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Samplerate"]];
4210                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
4211                 if (![[chosenPreset objectForKey:@"Audio4Encoder"] isEqualToString:@"AC3 Passthru"])
4212                 {
4213                     [fAudTrack4BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Bitrate"]];
4214                 }
4215                 [fAudTrack4DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio4TrackDRCSlider"] floatValue]];
4216                 [self audioDRCSliderChanged: fAudTrack4DrcSlider];
4217             }
4218
4219
4220         }
4221
4222         /* We now cleanup any extra audio tracks that may be previously set if we need to, we do it here so we don't have to
4223          * duplicate any code for legacy presets.*/
4224         /* First we handle the legacy Codecs crazy AVC/H.264 Video / AAC + AC3 Audio atv hybrid */
4225         if ([chosenPreset objectForKey:@"FileCodecs"] && [[chosenPreset objectForKey:@"FileCodecs"] isEqualToString:@"AVC/H.264 Video / AAC + AC3 Audio"])
4226         {
4227             [fAudLang3PopUp selectItemAtIndex: 0];
4228             [self audioTrackPopUpChanged: fAudLang3PopUp];
4229             [fAudLang4PopUp selectItemAtIndex: 0];
4230             [self audioTrackPopUpChanged: fAudLang4PopUp];
4231         }
4232         else
4233         {
4234             if (![chosenPreset objectForKey:@"Audio2Track"] || [chosenPreset objectForKey:@"Audio2Track"] == 0)
4235             {
4236                 [fAudLang2PopUp selectItemAtIndex: 0];
4237                 [self audioTrackPopUpChanged: fAudLang2PopUp];
4238             }
4239             if (![chosenPreset objectForKey:@"Audio3Track"] || [chosenPreset objectForKey:@"Audio3Track"] > 0)
4240             {
4241                 [fAudLang3PopUp selectItemAtIndex: 0];
4242                 [self audioTrackPopUpChanged: fAudLang3PopUp];
4243             }
4244             if (![chosenPreset objectForKey:@"Audio4Track"] || [chosenPreset objectForKey:@"Audio4Track"] > 0)
4245             {
4246                 [fAudLang4PopUp selectItemAtIndex: 0];
4247                 [self audioTrackPopUpChanged: fAudLang4PopUp];
4248             }
4249         }
4250
4251         /*Subtitles*/
4252         [fSubPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Subtitles"]];
4253         /* Forced Subtitles */
4254         [fSubForcedCheck setState:[[chosenPreset objectForKey:@"SubtitlesForced"] intValue]];
4255
4256         /* Picture Settings */
4257         /* Note: objectForKey:@"UsesPictureSettings" now refers to picture size, this encompasses:
4258          * height, width, keep ar, anamorphic and crop settings.
4259          * picture filters are now handled separately.
4260          * We will be able to actually change the key names for legacy preset keys when preset file
4261          * update code is done. But for now, lets hang onto the old legacy key name for backwards compatibility.
4262          */
4263         /* Check to see if the objectForKey:@"UsesPictureSettings is greater than 0, as 0 means use picture sizing "None" 
4264          * and the preset completely ignores any picture sizing values in the preset.
4265          */
4266         if ([[chosenPreset objectForKey:@"UsesPictureSettings"]  intValue] > 0)
4267         {
4268             hb_job_t * job = fTitle->job;
4269             /* Check to see if the objectForKey:@"UsesPictureSettings is 2 which is "Use Max for the source */
4270             if ([[chosenPreset objectForKey:@"UsesPictureSettings"]  intValue] == 2 || [[chosenPreset objectForKey:@"UsesMaxPictureSettings"]  intValue] == 1)
4271             {
4272                 /* Use Max Picture settings for whatever the dvd is.*/
4273                 [self revertPictureSizeToMax:nil];
4274                 job->keep_ratio = [[chosenPreset objectForKey:@"PictureKeepRatio"]  intValue];
4275                 if (job->keep_ratio == 1)
4276                 {
4277                     hb_fix_aspect( job, HB_KEEP_WIDTH );
4278                     if( job->height > fTitle->height )
4279                     {
4280                         job->height = fTitle->height;
4281                         hb_fix_aspect( job, HB_KEEP_HEIGHT );
4282                     }
4283                 }
4284                 job->pixel_ratio = [[chosenPreset objectForKey:@"PicturePAR"]  intValue];
4285             }
4286             else // /* If not 0 or 2 we assume objectForKey:@"UsesPictureSettings is 1 which is "Use picture sizing from when the preset was set" */
4287             {
4288                 /* we check to make sure the presets width/height does not exceed the sources width/height */
4289                 if (fTitle->width < [[chosenPreset objectForKey:@"PictureWidth"]  intValue] || fTitle->height < [[chosenPreset objectForKey:@"PictureHeight"]  intValue])
4290                 {
4291                     /* if so, then we use the sources height and width to avoid scaling up */
4292                     job->width = fTitle->width;
4293                     job->height = fTitle->height;
4294                 }
4295                 else // source width/height is >= the preset height/width
4296                 {
4297                     /* we can go ahead and use the presets values for height and width */
4298                     job->width = [[chosenPreset objectForKey:@"PictureWidth"]  intValue];
4299                     job->height = [[chosenPreset objectForKey:@"PictureHeight"]  intValue];
4300                 }
4301                 job->keep_ratio = [[chosenPreset objectForKey:@"PictureKeepRatio"]  intValue];
4302                 if (job->keep_ratio == 1)
4303                 {
4304                     hb_fix_aspect( job, HB_KEEP_WIDTH );
4305                     if( job->height > fTitle->height )
4306                     {
4307                         job->height = fTitle->height;
4308                         hb_fix_aspect( job, HB_KEEP_HEIGHT );
4309                     }
4310                 }
4311                 job->pixel_ratio = [[chosenPreset objectForKey:@"PicturePAR"]  intValue];
4312                 
4313                 
4314                 /* If Cropping is set to custom, then recall all four crop values from
4315                  when the preset was created and apply them */
4316                 if ([[chosenPreset objectForKey:@"PictureAutoCrop"]  intValue] == 0)
4317                 {
4318                     [fPictureController setAutoCrop:NO];
4319                     
4320                     /* Here we use the custom crop values saved at the time the preset was saved */
4321                     job->crop[0] = [[chosenPreset objectForKey:@"PictureTopCrop"]  intValue];
4322                     job->crop[1] = [[chosenPreset objectForKey:@"PictureBottomCrop"]  intValue];
4323                     job->crop[2] = [[chosenPreset objectForKey:@"PictureLeftCrop"]  intValue];
4324                     job->crop[3] = [[chosenPreset objectForKey:@"PictureRightCrop"]  intValue];
4325                     
4326                 }
4327                 else /* if auto crop has been saved in preset, set to auto and use post scan auto crop */
4328                 {
4329                     [fPictureController setAutoCrop:YES];
4330                     /* Here we use the auto crop values determined right after scan */
4331                     job->crop[0] = AutoCropTop;
4332                     job->crop[1] = AutoCropBottom;
4333                     job->crop[2] = AutoCropLeft;
4334                     job->crop[3] = AutoCropRight;
4335                     
4336                 }
4337                 /* If the preset has no objectForKey:@"UsesPictureFilters", then we know it is a legacy preset
4338                  * and handle the filters here as before.
4339                  * NOTE: This should be removed when the update presets code is done as we can be assured that legacy
4340                  * presets are updated to work properly with new keys.
4341                  */
4342                 if (![chosenPreset objectForKey:@"UsesPictureFilters"])
4343                 {
4344                     /* Filters */
4345                     /* Deinterlace */
4346                     if ([chosenPreset objectForKey:@"PictureDeinterlace"])
4347                     {
4348                         /* We check to see if the preset used the past fourth "Slowest" deinterlaceing and set that to "Slower
4349                          * since we no longer have a fourth "Slowest" deinterlacing due to the mcdeint bug */
4350                         if ([[chosenPreset objectForKey:@"PictureDeinterlace"] intValue] == 4)
4351                         {
4352                             [fPictureController setDeinterlace:3];
4353                         }
4354                         else
4355                         {
4356                             
4357                             [fPictureController setDeinterlace:[[chosenPreset objectForKey:@"PictureDeinterlace"] intValue]];
4358                         }
4359                     }
4360                     else
4361                     {
4362                         [fPictureController setDeinterlace:0];
4363                     }
4364                     /* VFR */
4365                     if ([[chosenPreset objectForKey:@"VFR"] intValue] == 1)
4366                     {
4367                         [fPictureController setVFR:[[chosenPreset objectForKey:@"VFR"] intValue]];
4368                     }
4369                     else
4370                     {
4371                         [fPictureController setVFR:0];
4372                     }
4373                     /* Detelecine */
4374                     if ([[chosenPreset objectForKey:@"PictureDetelecine"] intValue] == 1)
4375                     {
4376                         [fPictureController setDetelecine:[[chosenPreset objectForKey:@"PictureDetelecine"] intValue]];
4377                     }
4378                     else
4379                     {
4380                         [fPictureController setDetelecine:0];
4381                     }
4382                     /* Denoise */
4383                     if ([chosenPreset objectForKey:@"PictureDenoise"])
4384                     {
4385                         [fPictureController setDenoise:[[chosenPreset objectForKey:@"PictureDenoise"] intValue]];
4386                     }
4387                     else
4388                     {
4389                         [fPictureController setDenoise:0];
4390                     }   
4391                     /* Deblock */
4392                     if ([[chosenPreset objectForKey:@"PictureDeblock"] intValue] == 1)
4393                     {
4394                         [fPictureController setDeblock:[[chosenPreset objectForKey:@"PictureDeblock"] intValue]];
4395                     }
4396                     else
4397                     {
4398                         [fPictureController setDeblock:0];
4399                     }
4400
4401                    [self calculatePictureSizing:nil];
4402                 }
4403
4404             }
4405
4406
4407         }
4408         /* If the preset has an objectForKey:@"UsesPictureFilters", then we know it is a newer style filters preset
4409          * and handle the filters here depending on whether or not the preset specifies applying the filter.
4410          */
4411         if ([chosenPreset objectForKey:@"UsesPictureFilters"] && [[chosenPreset objectForKey:@"UsesPictureFilters"]  intValue] > 0)
4412         {
4413             /* Filters */
4414             /* Deinterlace */
4415             if ([chosenPreset objectForKey:@"PictureDeinterlace"])
4416             {
4417                 /* We check to see if the preset used the past fourth "Slowest" deinterlaceing and set that to "Slower
4418                  * since we no longer have a fourth "Slowest" deinterlacing due to the mcdeint bug */
4419                 if ([[chosenPreset objectForKey:@"PictureDeinterlace"] intValue] == 4)
4420                 {
4421                     [fPictureController setDeinterlace:3];
4422                 }
4423                 else
4424                 {
4425                     [fPictureController setDeinterlace:[[chosenPreset objectForKey:@"PictureDeinterlace"] intValue]];
4426                 }
4427             }
4428             else
4429             {
4430                 [fPictureController setDeinterlace:0];
4431             }
4432             /* VFR */
4433             if ([[chosenPreset objectForKey:@"VFR"] intValue] == 1)
4434             {
4435                 [fPictureController setVFR:[[chosenPreset objectForKey:@"VFR"] intValue]];
4436             }
4437             else
4438             {
4439                 [fPictureController setVFR:0];
4440             }
4441             /* Detelecine */
4442             if ([[chosenPreset objectForKey:@"PictureDetelecine"] intValue] == 1)
4443             {
4444                 [fPictureController setDetelecine:[[chosenPreset objectForKey:@"PictureDetelecine"] intValue]];
4445             }
4446             else
4447             {
4448                 [fPictureController setDetelecine:0];
4449             }
4450             /* Denoise */
4451             if ([chosenPreset objectForKey:@"PictureDenoise"])
4452             {
4453                 [fPictureController setDenoise:[[chosenPreset objectForKey:@"PictureDenoise"] intValue]];
4454             }
4455             else
4456             {
4457                 [fPictureController setDenoise:0];
4458             }   
4459             /* Deblock */
4460             if ([[chosenPreset objectForKey:@"PictureDeblock"] intValue] == 1)
4461             {
4462                 [fPictureController setDeblock:[[chosenPreset objectForKey:@"PictureDeblock"] intValue]];
4463             }
4464             else
4465             {
4466                 [fPictureController setDeblock:0];
4467             }
4468             /* Decomb */
4469             /* Even though we currently allow for a custom setting for decomb, ultimately it will only have Off and
4470              * Default so we just pay attention to anything greater than 0 as 1 (Default). 0 is Off. */
4471             if ([[chosenPreset objectForKey:@"PictureDecomb"] intValue] > 0)
4472             {
4473                 [fPictureController setDecomb:1];
4474             }
4475             else
4476             {
4477                 [fPictureController setDecomb:0];
4478             }
4479         }
4480         [self calculatePictureSizing:nil];
4481     }
4482 }
4483
4484
4485 #pragma mark -
4486 #pragma mark Manage Presets
4487
4488 - (void) loadPresets {
4489         /* We declare the default NSFileManager into fileManager */
4490         NSFileManager * fileManager = [NSFileManager defaultManager];
4491         /*We define the location of the user presets file */
4492     UserPresetsFile = @"~/Library/Application Support/HandBrake/UserPresets.plist";
4493         UserPresetsFile = [[UserPresetsFile stringByExpandingTildeInPath]retain];
4494     /* We check for the presets.plist */
4495         if ([fileManager fileExistsAtPath:UserPresetsFile] == 0)
4496         {
4497                 [fileManager createFileAtPath:UserPresetsFile contents:nil attributes:nil];
4498         }
4499
4500         UserPresets = [[NSMutableArray alloc] initWithContentsOfFile:UserPresetsFile];
4501         if (nil == UserPresets)
4502         {
4503                 UserPresets = [[NSMutableArray alloc] init];
4504                 [self addFactoryPresets:nil];
4505         }
4506         [fPresetsOutlineView reloadData];
4507 }
4508
4509
4510 - (IBAction) showAddPresetPanel: (id) sender
4511 {
4512     /* Deselect the currently selected Preset if there is one*/
4513     [fPresetsOutlineView deselectRow:[fPresetsOutlineView selectedRow]];
4514
4515     /* Populate the preset picture settings popup here */
4516     [fPresetNewPicSettingsPopUp removeAllItems];
4517     [fPresetNewPicSettingsPopUp addItemWithTitle:@"None"];
4518     [fPresetNewPicSettingsPopUp addItemWithTitle:@"Current"];
4519     [fPresetNewPicSettingsPopUp addItemWithTitle:@"Source Maximum (post source scan)"];
4520     [fPresetNewPicSettingsPopUp selectItemAtIndex: 0];  
4521     /* Uncheck the preset use filters checkbox */
4522     [fPresetNewPicFiltersCheck setState:NSOffState];
4523     /* Erase info from the input fields*/
4524         [fPresetNewName setStringValue: @""];
4525         [fPresetNewDesc setStringValue: @""];
4526         /* Show the panel */
4527         [NSApp beginSheet:fAddPresetPanel modalForWindow:fWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
4528 }
4529
4530 - (IBAction) closeAddPresetPanel: (id) sender
4531 {
4532     [NSApp endSheet: fAddPresetPanel];
4533     [fAddPresetPanel orderOut: self];
4534 }
4535
4536 - (IBAction)addUserPreset:(id)sender
4537 {
4538     if (![[fPresetNewName stringValue] length])
4539             NSRunAlertPanel(@"Warning!", @"You need to insert a name for the preset.", @"OK", nil , nil);
4540     else
4541     {
4542         /* Here we create a custom user preset */
4543         [UserPresets addObject:[self createPreset]];
4544         [self addPreset];
4545
4546         [self closeAddPresetPanel:nil];
4547     }
4548 }
4549 - (void)addPreset
4550 {
4551
4552         
4553         /* We Reload the New Table data for presets */
4554     [fPresetsOutlineView reloadData];
4555    /* We save all of the preset data here */
4556     [self savePreset];
4557 }
4558
4559 - (void)sortPresets
4560 {
4561
4562         
4563         /* We Sort the Presets By Factory or Custom */
4564         NSSortDescriptor * presetTypeDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"Type" 
4565                                                     ascending:YES] autorelease];
4566         /* We Sort the Presets Alphabetically by name  We do not use this now as we have drag and drop*/
4567         /*
4568     NSSortDescriptor * presetNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"PresetName" 
4569                                                     ascending:YES selector:@selector(caseInsensitiveCompare:)] autorelease];
4570         //NSArray *sortDescriptors=[NSArray arrayWithObjects:presetTypeDescriptor,presetNameDescriptor,nil];
4571     
4572     */
4573     /* Since we can drag and drop our custom presets, lets just sort by type and not name */
4574     NSArray *sortDescriptors=[NSArray arrayWithObjects:presetTypeDescriptor,nil];
4575         NSArray *sortedArray=[UserPresets sortedArrayUsingDescriptors:sortDescriptors];
4576         [UserPresets setArray:sortedArray];
4577         
4578
4579 }
4580
4581 - (IBAction)insertPreset:(id)sender
4582 {
4583     int index = [fPresetsOutlineView selectedRow];
4584     [UserPresets insertObject:[self createPreset] atIndex:index];
4585     [fPresetsOutlineView reloadData];
4586     [self savePreset];
4587 }
4588
4589 - (NSDictionary *)createPreset
4590 {
4591     NSMutableDictionary *preset = [[NSMutableDictionary alloc] init];
4592         /* Get the New Preset Name from the field in the AddPresetPanel */
4593     [preset setObject:[fPresetNewName stringValue] forKey:@"PresetName"];
4594         /*Set whether or not this is a user preset or factory 0 is factory, 1 is user*/
4595         [preset setObject:[NSNumber numberWithInt:1] forKey:@"Type"];
4596         /*Set whether or not this is default, at creation set to 0*/
4597         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Default"];
4598         /*Get the whether or not to apply pic Size and Cropping (includes Anamorphic)*/
4599         [preset setObject:[NSNumber numberWithInt:[fPresetNewPicSettingsPopUp indexOfSelectedItem]] forKey:@"UsesPictureSettings"];
4600     /* Get whether or not to use the current Picture Filter settings for the preset */
4601     [preset setObject:[NSNumber numberWithInt:[fPresetNewPicFiltersCheck state]] forKey:@"UsesPictureFilters"];
4602  
4603     /* Get New Preset Description from the field in the AddPresetPanel*/
4604         [preset setObject:[fPresetNewDesc stringValue] forKey:@"PresetDescription"];
4605         /* File Format */
4606     [preset setObject:[fDstFormatPopUp titleOfSelectedItem] forKey:@"FileFormat"];
4607         /* Chapter Markers fCreateChapterMarkers*/
4608         [preset setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"];
4609         /* Allow Mpeg4 64 bit formatting +4GB file sizes */
4610         [preset setObject:[NSNumber numberWithInt:[fDstMp4LargeFileCheck state]] forKey:@"Mp4LargeFile"];
4611     /* Mux mp4 with http optimization */
4612     [preset setObject:[NSNumber numberWithInt:[fDstMp4HttpOptFileCheck state]] forKey:@"Mp4HttpOptimize"];
4613     /* Add iPod uuid atom */
4614     [preset setObject:[NSNumber numberWithInt:[fDstMp4iPodFileCheck state]] forKey:@"Mp4iPodCompatible"];
4615
4616     /* Codecs */
4617         /* Video encoder */
4618         [preset setObject:[fVidEncoderPopUp titleOfSelectedItem] forKey:@"VideoEncoder"];
4619         /* x264 Option String */
4620         [preset setObject:[fAdvancedOptions optionsString] forKey:@"x264Option"];
4621
4622         [preset setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"];
4623         [preset setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
4624         [preset setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"];
4625         [preset setObject:[NSNumber numberWithFloat:[fVidQualitySlider floatValue]] forKey:@"VideoQualitySlider"];
4626
4627         /* Video framerate */
4628     if ([fVidRatePopUp indexOfSelectedItem] == 0) // Same as source is selected
4629         {
4630         [preset setObject:@"Same as source" forKey:@"VideoFramerate"];
4631     }
4632     else // we can record the actual titleOfSelectedItem
4633     {
4634     [preset setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"];
4635     }
4636         /* GrayScale */
4637         [preset setObject:[NSNumber numberWithInt:[fVidGrayscaleCheck state]] forKey:@"VideoGrayScale"];
4638         /* 2 Pass Encoding */
4639         [preset setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"];
4640         /* Turbo 2 pass Encoding fVidTurboPassCheck*/
4641         [preset setObject:[NSNumber numberWithInt:[fVidTurboPassCheck state]] forKey:@"VideoTurboTwoPass"];
4642         /*Picture Settings*/
4643         hb_job_t * job = fTitle->job;
4644         /* Picture Sizing */
4645         /* Use Max Picture settings for whatever the dvd is.*/
4646         [preset setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"];
4647         [preset setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"];
4648         [preset setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"];
4649         [preset setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"];
4650         [preset setObject:[NSNumber numberWithInt:fTitle->job->pixel_ratio] forKey:@"PicturePAR"];
4651     
4652     /* Set crop settings here */
4653         [preset setObject:[NSNumber numberWithInt:[fPictureController autoCrop]] forKey:@"PictureAutoCrop"];
4654     [preset setObject:[NSNumber numberWithInt:job->crop[0]] forKey:@"PictureTopCrop"];
4655     [preset setObject:[NSNumber numberWithInt:job->crop[1]] forKey:@"PictureBottomCrop"];
4656         [preset setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"];
4657         [preset setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"];
4658     
4659     /* Picture Filters */
4660     [preset setObject:[NSNumber numberWithInt:[fPictureController deinterlace]] forKey:@"PictureDeinterlace"];
4661         [preset setObject:[NSNumber numberWithInt:[fPictureController detelecine]] forKey:@"PictureDetelecine"];
4662     [preset setObject:[NSNumber numberWithInt:[fPictureController vfr]] forKey:@"VFR"];
4663         [preset setObject:[NSNumber numberWithInt:[fPictureController denoise]] forKey:@"PictureDenoise"];
4664     [preset setObject:[NSNumber numberWithInt:[fPictureController deblock]] forKey:@"PictureDeblock"]; 
4665     [preset setObject:[NSNumber numberWithInt:[fPictureController decomb]] forKey:@"PictureDecomb"];
4666     
4667     
4668     /*Audio*/
4669     if ([fAudLang1PopUp indexOfSelectedItem] > 0)
4670     {
4671         [preset setObject:[NSNumber numberWithInt:[fAudLang1PopUp indexOfSelectedItem]] forKey:@"Audio1Track"];
4672         [preset setObject:[fAudLang1PopUp titleOfSelectedItem] forKey:@"Audio1TrackDescription"];
4673         [preset setObject:[fAudTrack1CodecPopUp titleOfSelectedItem] forKey:@"Audio1Encoder"];
4674         [preset setObject:[fAudTrack1MixPopUp titleOfSelectedItem] forKey:@"Audio1Mixdown"];
4675         [preset setObject:[fAudTrack1RatePopUp titleOfSelectedItem] forKey:@"Audio1Samplerate"];
4676         [preset setObject:[fAudTrack1BitratePopUp titleOfSelectedItem] forKey:@"Audio1Bitrate"];
4677         [preset setObject:[NSNumber numberWithFloat:[fAudTrack1DrcSlider floatValue]] forKey:@"Audio1TrackDRCSlider"];
4678     }
4679     if ([fAudLang2PopUp indexOfSelectedItem] > 0)
4680     {
4681         [preset setObject:[NSNumber numberWithInt:[fAudLang2PopUp indexOfSelectedItem]] forKey:@"Audio2Track"];
4682         [preset setObject:[fAudLang2PopUp titleOfSelectedItem] forKey:@"Audio2TrackDescription"];
4683         [preset setObject:[fAudTrack2CodecPopUp titleOfSelectedItem] forKey:@"Audio2Encoder"];
4684         [preset setObject:[fAudTrack2MixPopUp titleOfSelectedItem] forKey:@"Audio2Mixdown"];
4685         [preset setObject:[fAudTrack2RatePopUp titleOfSelectedItem] forKey:@"Audio2Samplerate"];
4686         [preset setObject:[fAudTrack2BitratePopUp titleOfSelectedItem] forKey:@"Audio2Bitrate"];
4687         [preset setObject:[NSNumber numberWithFloat:[fAudTrack2DrcSlider floatValue]] forKey:@"Audio2TrackDRCSlider"];
4688     }
4689     if ([fAudLang3PopUp indexOfSelectedItem] > 0)
4690     {
4691         [preset setObject:[NSNumber numberWithInt:[fAudLang3PopUp indexOfSelectedItem]] forKey:@"Audio3Track"];
4692         [preset setObject:[fAudLang3PopUp titleOfSelectedItem] forKey:@"Audio3TrackDescription"];
4693         [preset setObject:[fAudTrack3CodecPopUp titleOfSelectedItem] forKey:@"Audio3Encoder"];
4694         [preset setObject:[fAudTrack3MixPopUp titleOfSelectedItem] forKey:@"Audio3Mixdown"];
4695         [preset setObject:[fAudTrack3RatePopUp titleOfSelectedItem] forKey:@"Audio3Samplerate"];
4696         [preset setObject:[fAudTrack3BitratePopUp titleOfSelectedItem] forKey:@"Audio3Bitrate"];
4697         [preset setObject:[NSNumber numberWithFloat:[fAudTrack3DrcSlider floatValue]] forKey:@"Audio3TrackDRCSlider"];
4698     }
4699     if ([fAudLang4PopUp indexOfSelectedItem] > 0)
4700     {
4701         [preset setObject:[NSNumber numberWithInt:[fAudLang4PopUp indexOfSelectedItem]] forKey:@"Audio4Track"];
4702         [preset setObject:[fAudLang4PopUp titleOfSelectedItem] forKey:@"Audio4TrackDescription"];
4703         [preset setObject:[fAudTrack4CodecPopUp titleOfSelectedItem] forKey:@"Audio4Encoder"];
4704         [preset setObject:[fAudTrack4MixPopUp titleOfSelectedItem] forKey:@"Audio4Mixdown"];
4705         [preset setObject:[fAudTrack4RatePopUp titleOfSelectedItem] forKey:@"Audio4Samplerate"];
4706         [preset setObject:[fAudTrack4BitratePopUp titleOfSelectedItem] forKey:@"Audio4Bitrate"];
4707         [preset setObject:[NSNumber numberWithFloat:[fAudTrack4DrcSlider floatValue]] forKey:@"Audio4TrackDRCSlider"];
4708     }
4709     
4710         /* Subtitles*/
4711         [preset setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"];
4712     /* Forced Subtitles */
4713         [preset setObject:[NSNumber numberWithInt:[fSubForcedCheck state]] forKey:@"SubtitlesForced"];
4714     
4715     [preset autorelease];
4716     return preset;
4717
4718 }
4719
4720 - (void)savePreset
4721 {
4722     [UserPresets writeToFile:UserPresetsFile atomically:YES];
4723         /* We get the default preset in case it changed */
4724         [self getDefaultPresets:nil];
4725
4726 }
4727
4728 - (IBAction)deletePreset:(id)sender
4729 {
4730     int status;
4731     NSEnumerator *enumerator;
4732     NSNumber *index;
4733     NSMutableArray *tempArray;
4734     id tempObject;
4735     
4736     if ( [fPresetsOutlineView numberOfSelectedRows] == 0 )
4737         return;
4738     /* Alert user before deleting preset */
4739         /* Comment out for now, tie to user pref eventually */
4740
4741     //NSBeep();
4742     status = NSRunAlertPanel(@"Warning!", @"Are you sure that you want to delete the selected preset?", @"OK", @"Cancel", nil);
4743     
4744     if ( status == NSAlertDefaultReturn ) {
4745         enumerator = [fPresetsOutlineView selectedRowEnumerator];
4746         tempArray = [NSMutableArray array];
4747         
4748         while ( (index = [enumerator nextObject]) ) {
4749             tempObject = [UserPresets objectAtIndex:[index intValue]];
4750             [tempArray addObject:tempObject];
4751         }
4752         
4753         [UserPresets removeObjectsInArray:tempArray];
4754         [fPresetsOutlineView reloadData];
4755         [self savePreset];   
4756     }
4757 }
4758
4759 #pragma mark -
4760 #pragma mark Manage Default Preset
4761
4762 - (IBAction)getDefaultPresets:(id)sender
4763 {
4764         int i = 0;
4765     presetCurrentBuiltInCount = 0;
4766     NSEnumerator *enumerator = [UserPresets objectEnumerator];
4767         id tempObject;
4768         while (tempObject = [enumerator nextObject])
4769         {
4770                 NSDictionary *thisPresetDict = tempObject;
4771                 if ([[thisPresetDict objectForKey:@"Default"] intValue] == 1) // 1 is HB default
4772                 {
4773                         presetHbDefault = i;    
4774                 }
4775                 if ([[thisPresetDict objectForKey:@"Default"] intValue] == 2) // 2 is User specified default
4776                 {
4777                         presetUserDefault = i;  
4778                 }
4779         if ([[thisPresetDict objectForKey:@"Type"] intValue] == 0) // Type 0 is a built in preset               
4780         {
4781                         presetCurrentBuiltInCount++; // <--increment the current number of built in presets     
4782                 }
4783                 i++;
4784         }
4785 }
4786
4787 - (IBAction)setDefaultPreset:(id)sender
4788 {
4789     int i = 0;
4790     NSEnumerator *enumerator = [UserPresets objectEnumerator];
4791         id tempObject;
4792         /* First make sure the old user specified default preset is removed */
4793         while (tempObject = [enumerator nextObject])
4794         {
4795                 /* make sure we are not removing the default HB preset */
4796                 if ([[[UserPresets objectAtIndex:i] objectForKey:@"Default"] intValue] != 1) // 1 is HB default
4797                 {
4798                         [[UserPresets objectAtIndex:i] setObject:[NSNumber numberWithInt:0] forKey:@"Default"];
4799                 }
4800                 i++;
4801         }
4802         /* Second, go ahead and set the appropriate user specfied preset */
4803         /* we get the chosen preset from the UserPresets array */
4804         if ([[[UserPresets objectAtIndex:[fPresetsOutlineView selectedRow]] objectForKey:@"Default"] intValue] != 1) // 1 is HB default
4805         {
4806                 [[UserPresets objectAtIndex:[fPresetsOutlineView selectedRow]] setObject:[NSNumber numberWithInt:2] forKey:@"Default"];
4807         }
4808         /*FIX ME: I think we now need to use the items not rows in NSOutlineView */
4809     presetUserDefault = [fPresetsOutlineView selectedRow];
4810         
4811         /* We save all of the preset data here */
4812     [self savePreset];
4813         /* We Reload the New Table data for presets */
4814     [fPresetsOutlineView reloadData];
4815 }
4816
4817 - (IBAction)selectDefaultPreset:(id)sender
4818 {
4819         /* if there is a user specified default, we use it */
4820         if (presetUserDefault)
4821         {
4822         [fPresetsOutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:presetUserDefault] byExtendingSelection:NO];
4823         [self selectPreset:nil];
4824         }
4825         else if (presetHbDefault) //else we use the built in default presetHbDefault
4826         {
4827         [fPresetsOutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:presetHbDefault] byExtendingSelection:NO];
4828         [self selectPreset:nil];
4829         }
4830 }
4831
4832
4833 #pragma mark -
4834 #pragma mark Manage Built In Presets
4835
4836
4837 - (IBAction)deleteFactoryPresets:(id)sender
4838 {
4839     //int status;
4840     NSEnumerator *enumerator = [UserPresets objectEnumerator];
4841         id tempObject;
4842     
4843         //NSNumber *index;
4844     NSMutableArray *tempArray;
4845
4846
4847         tempArray = [NSMutableArray array];
4848         /* we look here to see if the preset is we move on to the next one */
4849         while ( tempObject = [enumerator nextObject] )  
4850                 {
4851                         /* if the preset is "Factory" then we put it in the array of
4852                         presets to delete */
4853                         if ([[tempObject objectForKey:@"Type"] intValue] == 0)
4854                         {
4855                                 [tempArray addObject:tempObject];
4856                         }
4857         }
4858         
4859         [UserPresets removeObjectsInArray:tempArray];
4860         [fPresetsOutlineView reloadData];
4861         [self savePreset];   
4862
4863 }
4864
4865    /* We use this method to recreate new, updated factory
4866    presets */
4867 - (IBAction)addFactoryPresets:(id)sender
4868 {
4869    
4870    /* First, we delete any existing built in presets */
4871     [self deleteFactoryPresets: sender];
4872     /* Then we generate new built in presets programmatically with fPresetsBuiltin
4873     * which is all setup in HBPresets.h and  HBPresets.m*/
4874     [fPresetsBuiltin generateBuiltinPresets:UserPresets];
4875     [self sortPresets];
4876     [self addPreset];
4877     
4878 }
4879
4880
4881
4882
4883
4884 @end
4885
4886 /*******************************
4887  * Subclass of the HBPresetsOutlineView *
4888  *******************************/
4889
4890 @implementation HBPresetsOutlineView
4891 - (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray *)tableColumns event:(NSEvent*)dragEvent offset:(NSPointPointer)dragImageOffset
4892 {
4893     fIsDragging = YES;
4894
4895     // By default, NSTableView only drags an image of the first column. Change this to
4896     // drag an image of the queue's icon and PresetName columns.
4897     NSArray * cols = [NSArray arrayWithObjects: [self tableColumnWithIdentifier:@"icon"], [self tableColumnWithIdentifier:@"PresetName"], nil];
4898     return [super dragImageForRowsWithIndexes:dragRows tableColumns:cols event:dragEvent offset:dragImageOffset];
4899 }
4900
4901
4902
4903 - (void) mouseDown:(NSEvent *)theEvent
4904 {
4905     [super mouseDown:theEvent];
4906         fIsDragging = NO;
4907 }
4908
4909
4910
4911 - (BOOL) isDragging;
4912 {
4913     return fIsDragging;
4914 }
4915 @end
4916
4917
4918