OSDN Git Service

LinGui: don't disable subme 10 when psy-rd is 0
[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 #import "HBPreviewController.h"
13
14 #define DragDropSimplePboardType        @"MyCustomOutlineViewPboardType"
15
16 /* We setup the toolbar values here ShowPreviewIdentifier */
17 static NSString *        ToggleDrawerIdentifier             = @"Toggle Drawer Item Identifier";
18 static NSString *        StartEncodingIdentifier            = @"Start Encoding Item Identifier";
19 static NSString *        PauseEncodingIdentifier            = @"Pause Encoding Item Identifier";
20 static NSString *        ShowQueueIdentifier                = @"Show Queue Item Identifier";
21 static NSString *        AddToQueueIdentifier               = @"Add to Queue Item Identifier";
22 static NSString *        ShowPictureIdentifier             = @"Show Picture Window Item Identifier";
23 static NSString *        ShowPreviewIdentifier             = @"Show Preview Window Item Identifier";
24 static NSString *        ShowActivityIdentifier             = @"Debug Output Item Identifier";
25 static NSString *        ChooseSourceIdentifier             = @"Choose Source Item Identifier";
26
27
28 /*******************************
29  * HBController implementation *
30  *******************************/
31 @implementation HBController
32
33 - (id)init
34 {
35     self = [super init];
36     if( !self )
37     {
38         return nil;
39     }
40
41     /* replace bundled app icon with one which is 32/64-bit savvy */
42 #if defined( __LP64__ )
43     fApplicationIcon = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:@"HandBrake-64.icns"]];
44 #else
45     fApplicationIcon = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:@"HandBrake.icns"]];
46 #endif
47     if( fApplicationIcon != nil )
48         [NSApp setApplicationIconImage:fApplicationIcon];
49     
50     [HBPreferencesController registerUserDefaults];
51     fHandle = NULL;
52     fQueueEncodeLibhb = NULL;
53     /* Check for check for the app support directory here as
54      * outputPanel needs it right away, as may other future methods
55      */
56     NSString *libraryDir = [NSSearchPathForDirectoriesInDomains( NSLibraryDirectory,
57                                                                 NSUserDomainMask,
58                                                                 YES ) objectAtIndex:0];
59     AppSupportDirectory = [[libraryDir stringByAppendingPathComponent:@"Application Support"]
60                            stringByAppendingPathComponent:@"HandBrake"];
61     if( ![[NSFileManager defaultManager] fileExistsAtPath:AppSupportDirectory] )
62     {
63         [[NSFileManager defaultManager] createDirectoryAtPath:AppSupportDirectory
64                                                    attributes:nil];
65     }
66     /* Check for and create the App Support Preview directory if necessary */
67     NSString *PreviewDirectory = [AppSupportDirectory stringByAppendingPathComponent:@"Previews"];
68     if( ![[NSFileManager defaultManager] fileExistsAtPath:PreviewDirectory] )
69     {
70         [[NSFileManager defaultManager] createDirectoryAtPath:PreviewDirectory
71                                                    attributes:nil];
72     }                                                            
73     outputPanel = [[HBOutputPanelController alloc] init];
74     fPictureController = [[PictureController alloc] init];
75     fQueueController = [[HBQueueController alloc] init];
76     fAdvancedOptions = [[HBAdvancedController alloc] init];
77     /* we init the HBPresets class which currently is only used
78      * for updating built in presets, may move more functionality
79      * there in the future
80      */
81     fPresetsBuiltin = [[HBPresets alloc] init];
82     fPreferencesController = [[HBPreferencesController alloc] init];
83     /* Lets report the HandBrake version number here to the activity log and text log file */
84     NSString *versionStringFull = [[NSString stringWithFormat: @"Handbrake Version: %@", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]] stringByAppendingString: [NSString stringWithFormat: @" (%@)", [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"]]];
85     [self writeToActivityLog: "%s", [versionStringFull UTF8String]];    
86     
87     return self;
88 }
89
90
91 - (void) applicationDidFinishLaunching: (NSNotification *) notification
92 {
93     /* Init libhb with check for updates libhb style set to "0" so its ignored and lets sparkle take care of it */
94     int loggingLevel = [[[NSUserDefaults standardUserDefaults] objectForKey:@"LoggingLevel"] intValue];
95     fHandle = hb_init(loggingLevel, 0);
96     /* Optional dvd nav UseDvdNav*/
97     hb_dvd_set_dvdnav([[[NSUserDefaults standardUserDefaults] objectForKey:@"UseDvdNav"] boolValue]);
98     /* Init a separate instance of libhb for user scanning and setting up jobs */
99     fQueueEncodeLibhb = hb_init(loggingLevel, 0);
100     
101         // Set the Growl Delegate
102     [GrowlApplicationBridge setGrowlDelegate: self];
103     /* Init others controllers */
104     [fPictureController SetHandle: fHandle];
105     [fPictureController   setHBController: self];
106     
107     [fQueueController   setHandle: fQueueEncodeLibhb];
108     [fQueueController   setHBController: self];
109
110     fChapterTitlesDelegate = [[ChapterTitles alloc] init];
111     [fChapterTable setDataSource:fChapterTitlesDelegate];
112     [fChapterTable setDelegate:fChapterTitlesDelegate];
113     
114     /* setup the subtitles delegate and connections to table */
115     fSubtitlesDelegate = [[HBSubtitles alloc] init];
116     [fSubtitlesTable setDataSource:fSubtitlesDelegate];
117     [fSubtitlesTable setDelegate:fSubtitlesDelegate];
118     [fSubtitlesTable setRowHeight:25.0];
119     
120     [fPresetsOutlineView setAutosaveName:@"Presets View"];
121     [fPresetsOutlineView setAutosaveExpandedItems:YES];
122     
123     dockIconProgress = 0;
124
125     /* Call UpdateUI every 1/2 sec */
126     [[NSRunLoop currentRunLoop] addTimer:[NSTimer
127                                           scheduledTimerWithTimeInterval:0.5 target:self
128                                           selector:@selector(updateUI:) userInfo:nil repeats:YES]
129                                  forMode:NSDefaultRunLoopMode];
130
131     // Open debug output window now if it was visible when HB was closed
132     if ([[NSUserDefaults standardUserDefaults] boolForKey:@"OutputPanelIsOpen"])
133         [self showDebugOutputPanel:nil];
134
135     // Open queue window now if it was visible when HB was closed
136     if ([[NSUserDefaults standardUserDefaults] boolForKey:@"QueueWindowIsOpen"])
137         [self showQueueWindow:nil];
138
139         [self openMainWindow:nil];
140     
141     /* We have to set the bool to tell hb what to do after a scan
142      * Initially we set it to NO until we start processing the queue
143      */
144      applyQueueToScan = NO;
145     
146     /* Now we re-check the queue array to see if there are
147      * any remaining encodes to be done in it and ask the
148      * user if they want to reload the queue */
149     if ([QueueFileArray count] > 0)
150         {
151         /* run  getQueueStats to see whats in the queue file */
152         [self getQueueStats];
153         /* this results in these values
154          * fEncodingQueueItem = 0;
155          * fPendingCount = 0;
156          * fCompletedCount = 0;
157          * fCanceledCount = 0;
158          * fWorkingCount = 0;
159          */
160         
161         /*On Screen Notification*/
162         NSString * alertTitle;
163         
164         /* We check to see if there is already another instance of hb running.
165          * Note: hbInstances == 1 means we are the only instance of HandBrake.app
166          */
167         if ([self hbInstances] > 1)
168         {
169         alertTitle = [NSString stringWithFormat:
170                          NSLocalizedString(@"There is already an instance of HandBrake running.", @"")];
171         NSBeginCriticalAlertSheet(
172                                       alertTitle,
173                                       NSLocalizedString(@"Reload Queue", nil),
174                                       nil,
175                                       nil,
176                                       fWindow, self,
177                                       nil, @selector(didDimissReloadQueue:returnCode:contextInfo:), nil,
178                                       NSLocalizedString(@" HandBrake will now load up the existing queue.", nil));    
179         }
180         else
181         {
182             if (fWorkingCount > 0)
183             {
184                 alertTitle = [NSString stringWithFormat:
185                               NSLocalizedString(@"HandBrake Has Detected %d Previously Encoding Item and %d Pending Item(s) In Your Queue.", @""),
186                               fWorkingCount,fPendingCount];
187             }
188             else
189             {
190                 alertTitle = [NSString stringWithFormat:
191                               NSLocalizedString(@"HandBrake Has Detected %d Pending Item(s) In Your Queue.", @""),
192                               fPendingCount];
193             }
194             
195             NSBeginCriticalAlertSheet(
196                                       alertTitle,
197                                       NSLocalizedString(@"Reload Queue", nil),
198                                       nil,
199                                       NSLocalizedString(@"Empty Queue", nil),
200                                       fWindow, self,
201                                       nil, @selector(didDimissReloadQueue:returnCode:contextInfo:), nil,
202                                       NSLocalizedString(@" Do you want to reload them ?", nil));
203         }
204         
205         // call didDimissReloadQueue: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
206         // right below to either clear the old queue or keep it loaded up.
207     }
208     else
209     {
210         /* We show whichever open source window specified in LaunchSourceBehavior preference key */
211         if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source"])
212         {
213             [self browseSources:nil];
214         }
215         
216         if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source (Title Specific)"])
217         {
218             [self browseSources:(id)fOpenSourceTitleMMenu];
219         }
220     }
221 }
222
223 - (int) hbInstances
224 {
225     /* check to see if another instance of HandBrake.app is running */
226     NSArray *runningAppDictionaries = [[NSWorkspace sharedWorkspace] launchedApplications];
227     NSDictionary *aDictionary;
228     int hbInstances = 0;
229     for (aDictionary in runningAppDictionaries)
230         {
231         //      NSLog(@"Open App: %@", [aDictionary valueForKey:@"NSApplicationName"]);
232         
233         if ([[aDictionary valueForKey:@"NSApplicationName"] isEqualToString:@"HandBrake"])
234                 {
235             hbInstances++;
236                 }
237         }
238     return hbInstances;
239 }
240
241 - (void) didDimissReloadQueue: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
242 {
243     if (returnCode == NSAlertOtherReturn)
244     {
245         [self clearQueueAllItems];
246         /* We show whichever open source window specified in LaunchSourceBehavior preference key */
247         if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source"])
248         {
249             [self browseSources:nil];
250         }
251         
252         if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"LaunchSourceBehavior"] isEqualToString: @"Open Source (Title Specific)"])
253         {
254             [self browseSources:(id)fOpenSourceTitleMMenu];
255         }
256     }
257     else
258     {
259         if ([self hbInstances] == 1)
260         {
261             [self setQueueEncodingItemsAsPending];
262         }
263         [self showQueueWindow:NULL];
264     }
265 }
266
267 - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) app
268 {
269     /* if we are in preview full screen mode, we need to go to
270      * windowed mode and release the display before we terminate.
271      * We do it here (instead of applicationWillTerminate) so we 
272      * release the displays and can then see the alerts below.
273      */
274     if ([fPictureController previewFullScreenMode] == YES)
275     {
276         [fPictureController previewGoWindowed:nil];
277     }
278     
279     hb_state_t s;
280     hb_get_state( fQueueEncodeLibhb, &s );
281     
282     if ( s.state != HB_STATE_IDLE )
283     {
284         int result = NSRunCriticalAlertPanel(
285                                              NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil),
286                                              NSLocalizedString(@"If you quit HandBrake your current encode will be reloaded into your queue at next launch. Do you want to quit anyway?", nil),
287                                              NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil, @"A movie" );
288         
289         if (result == NSAlertDefaultReturn)
290         {
291             return NSTerminateNow;
292         }
293         else
294             return NSTerminateCancel;
295     }
296     
297     // Warn if items still in the queue
298     else if ( fPendingCount > 0 )
299     {
300         int result = NSRunCriticalAlertPanel(
301                                              NSLocalizedString(@"Are you sure you want to quit HandBrake?", nil),
302                                              NSLocalizedString(@"There are pending encodes in your queue. Do you want to quit anyway?",nil),
303                                              NSLocalizedString(@"Quit", nil), NSLocalizedString(@"Don't Quit", nil), nil);
304         
305         if ( result == NSAlertDefaultReturn )
306             return NSTerminateNow;
307         else
308             return NSTerminateCancel;
309     }
310     
311     return NSTerminateNow;
312 }
313
314 - (void)applicationWillTerminate:(NSNotification *)aNotification
315 {
316     
317     [browsedSourceDisplayName release];
318     [outputPanel release];
319         [fQueueController release];
320     [fPreviewController release];
321     [fPictureController release];
322     [fApplicationIcon release];
323
324         hb_close(&fHandle);
325     hb_close(&fQueueEncodeLibhb);
326 }
327
328
329 - (void) awakeFromNib
330 {
331     [fWindow center];
332     [fWindow setExcludedFromWindowsMenu:YES];
333     [fAdvancedOptions setView:fAdvancedView];
334     
335     /* lets setup our presets drawer for drag and drop here */
336     [fPresetsOutlineView registerForDraggedTypes: [NSArray arrayWithObject:DragDropSimplePboardType] ];
337     [fPresetsOutlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
338     [fPresetsOutlineView setVerticalMotionCanBeginDrag: YES];
339     
340     /* Initialize currentScanCount so HB can use it to
341      evaluate successive scans */
342         currentScanCount = 0;
343     
344     
345     /* Init UserPresets .plist */
346         [self loadPresets];
347     
348     /* Init QueueFile .plist */
349     [self loadQueueFile];
350         
351     fRipIndicatorShown = NO;  // initially out of view in the nib
352     
353     /* For 64 bit builds, the threaded animation in the progress
354      * indicators conflicts with the animation in the advanced tab
355      * for reasons not completely clear. jbrjake found a note in the
356      * 10.5 dev notes regarding this possiblility. It was also noted
357      * that unless specified, setUsesThreadedAnimation defaults to true.
358      * So, at least for now we set the indicator animation to NO for
359      * both the scan and regular progress indicators for both 32 and 64 bit
360      * as it test out fine on both and there is no reason our progress indicators
361      * should require their own thread.
362      */
363
364     [fScanIndicator setUsesThreadedAnimation:NO];
365     [fRipIndicator setUsesThreadedAnimation:NO];
366   
367     
368     
369         /* Show/Dont Show Presets drawer upon launch based
370      on user preference DefaultPresetsDrawerShow*/
371         if( [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPresetsDrawerShow"] > 0 )
372         {
373         [fPresetDrawer setDelegate:self];
374         NSSize drawerSize = NSSizeFromString( [[NSUserDefaults standardUserDefaults] 
375                                                stringForKey:@"Drawer Size"] );
376         if( drawerSize.width )
377             [fPresetDrawer setContentSize: drawerSize];
378                 [fPresetDrawer open];
379         }
380     
381     /* Initially set the dvd angle widgets to hidden (dvdnav only) */
382     [fSrcAngleLabel setHidden:YES];
383     [fSrcAnglePopUp setHidden:YES];
384     
385     /* Destination box*/
386     NSMenuItem *menuItem;
387     [fDstFormatPopUp removeAllItems];
388     // MP4 file
389     menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MP4 file" action: NULL keyEquivalent: @""];
390     [menuItem setTag: HB_MUX_MP4];
391         // MKV file
392     menuItem = [[fDstFormatPopUp menu] addItemWithTitle:@"MKV file" action: NULL keyEquivalent: @""];
393     [menuItem setTag: HB_MUX_MKV];
394     
395     [fDstFormatPopUp selectItemAtIndex: 0];
396     
397     [self formatPopUpChanged:nil];
398     
399         /* We enable the create chapters checkbox here since we are .mp4 */
400         [fCreateChapterMarkers setEnabled: YES];
401         if ([fDstFormatPopUp indexOfSelectedItem] == 0 && [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultChapterMarkers"] > 0)
402         {
403                 [fCreateChapterMarkers setState: NSOnState];
404         }
405     
406     
407     
408     
409     [fDstFile2Field setStringValue: [NSString stringWithFormat:
410                                      @"%@/Desktop/Movie.mp4", NSHomeDirectory()]];
411     
412     /* Video encoder */
413     [fVidEncoderPopUp removeAllItems];
414     [fVidEncoderPopUp addItemWithTitle: @"FFmpeg"];
415     
416     
417     
418     /* Video quality */
419     [fVidTargetSizeField setIntValue: 700];
420         [fVidBitrateField    setIntValue: 1000];
421     
422     [fVidQualityMatrix   selectCell: fVidBitrateCell];
423     [self videoMatrixChanged:nil];
424     
425     /* Video framerate */
426     [fVidRatePopUp removeAllItems];
427         [fVidRatePopUp addItemWithTitle: NSLocalizedString( @"Same as source", @"" )];
428     for( int i = 0; i < hb_video_rates_count; i++ )
429     {
430         if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.3f",23.976]])
431                 {
432                         [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
433                                              [NSString stringWithCString: hb_video_rates[i].string], @" (NTSC Film)"]];
434                 }
435                 else if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%d",25]])
436                 {
437                         [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
438                                              [NSString stringWithCString: hb_video_rates[i].string], @" (PAL Film/Video)"]];
439                 }
440                 else if ([[NSString stringWithCString: hb_video_rates[i].string] isEqualToString: [NSString stringWithFormat: @"%.2f",29.97]])
441                 {
442                         [fVidRatePopUp addItemWithTitle:[NSString stringWithFormat: @"%@%@",
443                                              [NSString stringWithCString: hb_video_rates[i].string], @" (NTSC Video)"]];
444                 }
445                 else
446                 {
447                         [fVidRatePopUp addItemWithTitle:
448              [NSString stringWithCString: hb_video_rates[i].string]];
449                 }
450     }
451     [fVidRatePopUp selectItemAtIndex: 0];
452         
453         /* Set Auto Crop to On at launch */
454     [fPictureController setAutoCrop:YES];
455         
456         /* Audio bitrate */
457     [fAudTrack1BitratePopUp removeAllItems];
458     for( int i = 0; i < hb_audio_bitrates_count; i++ )
459     {
460         [fAudTrack1BitratePopUp addItemWithTitle:
461          [NSString stringWithCString: hb_audio_bitrates[i].string]];
462         
463     }
464     [fAudTrack1BitratePopUp selectItemAtIndex: hb_audio_bitrates_default];
465         
466     /* Audio samplerate */
467     [fAudTrack1RatePopUp removeAllItems];
468     for( int i = 0; i < hb_audio_rates_count; i++ )
469     {
470         [fAudTrack1RatePopUp addItemWithTitle:
471          [NSString stringWithCString: hb_audio_rates[i].string]];
472     }
473     [fAudTrack1RatePopUp selectItemAtIndex: hb_audio_rates_default];
474         
475     /* Bottom */
476     [fStatusField setStringValue: @""];
477     
478     [self enableUI: NO];
479         [self setupToolbar];
480     
481         /* We disable the Turbo 1st pass checkbox since we are not x264 */
482         [fVidTurboPassCheck setEnabled: NO];
483         [fVidTurboPassCheck setState: NSOffState];
484     
485     
486         /* lets get our default prefs here */
487         [self getDefaultPresets:nil];
488         /* lets initialize the current successful scancount here to 0 */
489         currentSuccessfulScanCount = 0;
490     
491     
492 }
493
494 - (void) enableUI: (bool) b
495 {
496     NSControl * controls[] =
497     { fSrcTitleField, fSrcTitlePopUp,
498         fSrcChapterField, fSrcChapterStartPopUp, fSrcChapterToField,
499         fSrcChapterEndPopUp, fSrcDuration1Field, fSrcDuration2Field,
500         fDstFormatField, fDstFormatPopUp, fDstFile1Field, fDstFile2Field,
501         fDstBrowseButton, fVidRateField, fVidRatePopUp,fVidEncoderField, fVidEncoderPopUp, fVidQualityField,
502         fPictureSizeField,fPictureCroppingField, fVideoFiltersField,fVidQualityMatrix, fSubField, fSubPopUp,
503         fAudSourceLabel, fAudCodecLabel, fAudMixdownLabel, fAudSamplerateLabel, fAudBitrateLabel,
504         fAudTrack1Label, fAudTrack2Label, fAudTrack3Label, fAudTrack4Label,
505         fAudLang1PopUp, fAudLang2PopUp, fAudLang3PopUp, fAudLang4PopUp,
506         fAudTrack1CodecPopUp, fAudTrack2CodecPopUp, fAudTrack3CodecPopUp, fAudTrack4CodecPopUp,
507         fAudTrack1MixPopUp, fAudTrack2MixPopUp, fAudTrack3MixPopUp, fAudTrack4MixPopUp,
508         fAudTrack1RatePopUp, fAudTrack2RatePopUp, fAudTrack3RatePopUp, fAudTrack4RatePopUp,
509         fAudTrack1BitratePopUp, fAudTrack2BitratePopUp, fAudTrack3BitratePopUp, fAudTrack4BitratePopUp,
510         fAudDrcLabel, fAudTrack1DrcSlider, fAudTrack1DrcField, fAudTrack2DrcSlider,
511         fAudTrack2DrcField, fAudTrack3DrcSlider, fAudTrack3DrcField, fAudTrack4DrcSlider,fAudTrack4DrcField,
512         fQueueStatus,fPresetsAdd,fPresetsDelete,fSrcAngleLabel,fSrcAnglePopUp,
513                 fCreateChapterMarkers,fVidTurboPassCheck,fDstMp4LargeFileCheck,fSubForcedCheck,fPresetsOutlineView,
514     fAudDrcLabel,fDstMp4HttpOptFileCheck,fDstMp4iPodFileCheck,fVidQualityRFField,fVidQualityRFLabel};
515     
516     for( unsigned i = 0;
517         i < sizeof( controls ) / sizeof( NSControl * ); i++ )
518     {
519         if( [[controls[i] className] isEqualToString: @"NSTextField"] )
520         {
521             NSTextField * tf = (NSTextField *) controls[i];
522             if( ![tf isBezeled] )
523             {
524                 [tf setTextColor: b ? [NSColor controlTextColor] :
525                  [NSColor disabledControlTextColor]];
526                 continue;
527             }
528         }
529         [controls[i] setEnabled: b];
530         
531     }
532     
533         if (b) {
534         
535         /* if we're enabling the interface, check if the audio mixdown controls need to be enabled or not */
536         /* these will have been enabled by the mass control enablement above anyway, so we're sense-checking it here */
537         [self setEnabledStateOfAudioMixdownControls:nil];
538         /* we also call calculatePictureSizing here to sense check if we already have vfr selected */
539         [self calculatePictureSizing:nil];
540         
541         } else {
542         
543                 [fPresetsOutlineView setEnabled: NO];
544         
545         }
546     
547     [self videoMatrixChanged:nil];
548     [fAdvancedOptions enableUI:b];
549 }
550
551
552 /***********************************************************************
553  * UpdateDockIcon
554  ***********************************************************************
555  * Shows a progression bar on the dock icon, filled according to
556  * 'progress' (0.0 <= progress <= 1.0).
557  * Called with progress < 0.0 or progress > 1.0, restores the original
558  * icon.
559  **********************************************************************/
560 - (void) UpdateDockIcon: (float) progress
561 {
562     NSData * tiff;
563     NSBitmapImageRep * bmp;
564     uint32_t * pen;
565     uint32_t black = htonl( 0x000000FF );
566     uint32_t red   = htonl( 0xFF0000FF );
567     uint32_t white = htonl( 0xFFFFFFFF );
568     int row_start, row_end;
569     int i, j;
570
571     if( progress < 0.0 || progress > 1.0 )
572     {
573         [NSApp setApplicationIconImage: fApplicationIcon];
574         return;
575     }
576
577     /* Get it in a raw bitmap form */
578     tiff = [fApplicationIcon TIFFRepresentationUsingCompression:
579             NSTIFFCompressionNone factor: 1.0];
580     bmp = [NSBitmapImageRep imageRepWithData: tiff];
581     
582     /* Draw the progression bar */
583     /* It's pretty simple (ugly?) now, but I'm no designer */
584
585     row_start = 3 * (int) [bmp size].height / 4;
586     row_end   = 7 * (int) [bmp size].height / 8;
587
588     for( i = row_start; i < row_start + 2; i++ )
589     {
590         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
591         for( j = 0; j < (int) [bmp size].width; j++ )
592         {
593             pen[j] = black;
594         }
595     }
596     for( i = row_start + 2; i < row_end - 2; i++ )
597     {
598         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
599         pen[0] = black;
600         pen[1] = black;
601         for( j = 2; j < (int) [bmp size].width - 2; j++ )
602         {
603             if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
604             {
605                 pen[j] = red;
606             }
607             else
608             {
609                 pen[j] = white;
610             }
611         }
612         pen[j]   = black;
613         pen[j+1] = black;
614     }
615     for( i = row_end - 2; i < row_end; i++ )
616     {
617         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
618         for( j = 0; j < (int) [bmp size].width; j++ )
619         {
620             pen[j] = black;
621         }
622     }
623
624     /* Now update the dock icon */
625     tiff = [bmp TIFFRepresentationUsingCompression:
626             NSTIFFCompressionNone factor: 1.0];
627     NSImage* icon = [[NSImage alloc] initWithData: tiff];
628     [NSApp setApplicationIconImage: icon];
629     [icon release];
630 }
631
632 - (void) updateUI: (NSTimer *) timer
633 {
634     
635     /* Update UI for fHandle (user scanning instance of libhb ) */
636     
637     hb_list_t  * list;
638     list = hb_get_titles( fHandle );
639     /* check to see if there has been a new scan done
640      this bypasses the constraints of HB_STATE_WORKING
641      not allowing setting a newly scanned source */
642         int checkScanCount = hb_get_scancount( fHandle );
643         if( checkScanCount > currentScanCount )
644         {
645                 currentScanCount = checkScanCount;
646         [fScanIndicator setIndeterminate: NO];
647         [fScanIndicator setDoubleValue: 0.0];
648         [fScanIndicator setHidden: YES];
649                 [self showNewScan:nil];
650         }
651     
652     hb_state_t s;
653     hb_get_state( fHandle, &s );
654     
655     switch( s.state )
656     {
657         case HB_STATE_IDLE:
658             break;
659 #define p s.param.scanning
660         case HB_STATE_SCANNING:
661                 {
662             [fSrcDVD2Field setStringValue: [NSString stringWithFormat:
663                                             NSLocalizedString( @"Scanning title %d of %d...", @"" ),
664                                             p.title_cur, p.title_count]];
665             [fScanIndicator setHidden: NO];
666             [fScanIndicator setDoubleValue: 100.0 * ((double)( p.title_cur - 1 ) / p.title_count)];
667             break;
668                 }
669 #undef p
670             
671 #define p s.param.scandone
672         case HB_STATE_SCANDONE:
673         {
674             [fScanIndicator setIndeterminate: NO];
675             [fScanIndicator setDoubleValue: 0.0];
676             [fScanIndicator setHidden: YES];
677                         [self writeToActivityLog:"ScanDone state received from fHandle"];
678             [self showNewScan:nil];
679             [[fWindow toolbar] validateVisibleItems];
680             
681                         break;
682         }
683 #undef p
684             
685 #define p s.param.working
686         case HB_STATE_WORKING:
687         {
688             
689             break;
690         }
691 #undef p
692             
693 #define p s.param.muxing
694         case HB_STATE_MUXING:
695         {
696             
697             break;
698         }
699 #undef p
700             
701         case HB_STATE_PAUSED:
702             break;
703             
704         case HB_STATE_WORKDONE:
705         {
706             break;
707         }
708     }
709     
710     
711     /* Update UI for fQueueEncodeLibhb */
712     // hb_list_t  * list;
713     // list = hb_get_titles( fQueueEncodeLibhb ); //fQueueEncodeLibhb
714     /* check to see if there has been a new scan done
715      this bypasses the constraints of HB_STATE_WORKING
716      not allowing setting a newly scanned source */
717         
718     checkScanCount = hb_get_scancount( fQueueEncodeLibhb );
719         if( checkScanCount > currentScanCount )
720         {
721                 currentScanCount = checkScanCount;
722         }
723     
724     //hb_state_t s;
725     hb_get_state( fQueueEncodeLibhb, &s );
726     
727     switch( s.state )
728     {
729         case HB_STATE_IDLE:
730             break;
731 #define p s.param.scanning
732         case HB_STATE_SCANNING:
733                 {
734             [fStatusField setStringValue: [NSString stringWithFormat:
735                                            NSLocalizedString( @"Queue Scanning title %d of %d...", @"" ),
736                                            p.title_cur, p.title_count]];
737             
738             /* Set the status string in fQueueController as well */                               
739             [fQueueController setQueueStatusString: [NSString stringWithFormat:
740                                                      NSLocalizedString( @"Queue Scanning title %d of %d...", @"" ),
741                                                      p.title_cur, p.title_count]];
742             break;
743                 }
744 #undef p
745             
746 #define p s.param.scandone
747         case HB_STATE_SCANDONE:
748         {
749                         [self writeToActivityLog:"ScanDone state received from fQueueEncodeLibhb"];
750             [self processNewQueueEncode];
751             [[fWindow toolbar] validateVisibleItems];
752             
753                         break;
754         }
755 #undef p
756             
757 #define p s.param.working
758         case HB_STATE_WORKING:
759         {
760             NSMutableString * string;
761             NSString * pass_desc;
762                         /* Update text field */
763             if (p.job_cur == 1 && p.job_count > 1)
764             {
765                 if ([[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SubtitleList"] && [[[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex]objectForKey:@"SubtitleList"] objectAtIndex:0] objectForKey:@"subtitleSourceTrackNum"] intValue] == 1)
766                 {
767                     pass_desc = @"(subtitle scan)";   
768                 }
769                 else
770                 {
771                     pass_desc = @"";
772                 }
773             }
774             else
775             {
776                 pass_desc = @"";
777             }
778             
779                         string = [NSMutableString stringWithFormat: NSLocalizedString( @"Encoding: pass %d %@ of %d, %.2f %%", @"" ), p.job_cur, pass_desc, p.job_count, 100.0 * p.progress];
780             
781                         if( p.seconds > -1 )
782             {
783                 [string appendFormat:
784                  NSLocalizedString( @" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", @"" ),
785                  p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
786             }
787             
788             [fStatusField setStringValue: string];
789             /* Set the status string in fQueueController as well */
790             [fQueueController setQueueStatusString: string];
791             /* Update slider */
792             CGFloat progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
793             [fRipIndicator setIndeterminate: NO];
794             [fRipIndicator setDoubleValue:100.0 * progress_total];
795             
796             // If progress bar hasn't been revealed at the bottom of the window, do
797             // that now. This code used to be in doRip. I moved it to here to handle
798             // the case where hb_start is called by HBQueueController and not from
799             // HBController.
800             if( !fRipIndicatorShown )
801             {
802                 NSRect frame = [fWindow frame];
803                 if( frame.size.width <= 591 )
804                     frame.size.width = 591;
805                 frame.size.height += 36;
806                 frame.origin.y -= 36;
807                 [fWindow setFrame:frame display:YES animate:YES];
808                 fRipIndicatorShown = YES;
809                 
810             }
811
812             /* Update dock icon */
813             if( dockIconProgress < 100.0 * progress_total )
814             {
815                 [self UpdateDockIcon: progress_total];
816                 dockIconProgress += 5;
817             }
818
819             break;
820         }
821 #undef p
822             
823 #define p s.param.muxing
824         case HB_STATE_MUXING:
825         {
826             /* Update text field */
827             [fStatusField setStringValue: NSLocalizedString( @"Muxing...", @"" )];
828             /* Set the status string in fQueueController as well */
829             [fQueueController setQueueStatusString: NSLocalizedString( @"Muxing...", @"" )];
830             /* Update slider */
831             [fRipIndicator setIndeterminate: YES];
832             [fRipIndicator startAnimation: nil];
833             
834             /* Update dock icon */
835             [self UpdateDockIcon: 1.0];
836             
837                         break;
838         }
839 #undef p
840             
841         case HB_STATE_PAUSED:
842                     [fStatusField setStringValue: NSLocalizedString( @"Paused", @"" )];
843             [fQueueController setQueueStatusString: NSLocalizedString( @"Paused", @"" )];
844             
845                         break;
846             
847         case HB_STATE_WORKDONE:
848         {
849             // HB_STATE_WORKDONE happpens as a result of libhb finishing all its jobs
850             // or someone calling hb_stop. In the latter case, hb_stop does not clear
851             // out the remaining passes/jobs in the queue. We'll do that here.
852             
853             // Delete all remaining jobs of this encode.
854             [fStatusField setStringValue: NSLocalizedString( @"Encode Finished.", @"" )];
855             /* Set the status string in fQueueController as well */
856             [fQueueController setQueueStatusString: NSLocalizedString( @"Encode Finished.", @"" )];
857             [fRipIndicator setIndeterminate: NO];
858             [fRipIndicator stopAnimation: nil];
859             [fRipIndicator setDoubleValue: 0.0];
860             [[fWindow toolbar] validateVisibleItems];
861             
862             /* Restore dock icon */
863             [self UpdateDockIcon: -1.0];
864             dockIconProgress = 0;
865             
866             if( fRipIndicatorShown )
867             {
868                 NSRect frame = [fWindow frame];
869                 if( frame.size.width <= 591 )
870                                     frame.size.width = 591;
871                 frame.size.height += -36;
872                 frame.origin.y -= -36;
873                 [fWindow setFrame:frame display:YES animate:YES];
874                                 fRipIndicatorShown = NO;
875                         }
876             /* Since we are done with this encode, tell output to stop writing to the
877              * individual encode log
878              */
879                         [outputPanel endEncodeLog];
880             /* Check to see if the encode state has not been cancelled
881              to determine if we should check for encode done notifications */
882                         if( fEncodeState != 2 )
883             {
884                 NSString *pathOfFinishedEncode;
885                 /* Get the output file name for the finished encode */
886                 pathOfFinishedEncode = [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"];
887                 
888                 /* Both the Growl Alert and Sending to MetaX can be done as encodes roll off the queue */
889                 /* Growl alert */
890                 [self showGrowlDoneNotification:pathOfFinishedEncode];
891                 /* Send to MetaX */
892                 [self sendToMetaX:pathOfFinishedEncode];
893                 
894                 /* since we have successfully completed an encode, we increment the queue counter */
895                 [self incrementQueueItemDone:nil]; 
896                 
897                 /* all end of queue actions below need to be done after all queue encodes have finished 
898                  * and there are no pending jobs left to process
899                  */
900                 if (fPendingCount == 0)
901                 {
902                     /* If Alert Window or Window and Growl has been selected */
903                     if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window"] ||
904                        [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"] )
905                     {
906                         /*On Screen Notification*/
907                         int status;
908                         NSBeep();
909                         status = NSRunAlertPanel(@"Put down that cocktail...",@"Your HandBrake queue is done!", @"OK", nil, nil);
910                         [NSApp requestUserAttention:NSCriticalRequest];
911                     }
912                     
913                     /* If sleep has been selected */
914                     if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Put Computer To Sleep"] )
915                     {
916                         /* Sleep */
917                         NSDictionary* errorDict;
918                         NSAppleEventDescriptor* returnDescriptor = nil;
919                         NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
920                                                        @"tell application \"Finder\" to sleep"];
921                         returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
922                         [scriptObject release];
923                     }
924                     /* If Shutdown has been selected */
925                     if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Shut Down Computer"] )
926                     {
927                         /* Shut Down */
928                         NSDictionary* errorDict;
929                         NSAppleEventDescriptor* returnDescriptor = nil;
930                         NSAppleScript* scriptObject = [[NSAppleScript alloc] initWithSource:
931                                                        @"tell application \"Finder\" to shut down"];
932                         returnDescriptor = [scriptObject executeAndReturnError: &errorDict];
933                         [scriptObject release];
934                     }
935                     
936                 }
937                 
938                 
939             }
940             
941             break;
942         }
943     }
944     
945 }
946
947 /* We use this to write messages to stderr from the macgui which show up in the activity window and log*/
948 - (void) writeToActivityLog:(const char *) format, ...
949 {
950     va_list args;
951     va_start(args, format);
952     if (format != nil)
953     {
954         char str[1024];
955         vsnprintf( str, 1024, format, args );
956
957         time_t _now = time( NULL );
958         struct tm * now  = localtime( &_now );
959         fprintf(stderr, "[%02d:%02d:%02d] macgui: %s\n", now->tm_hour, now->tm_min, now->tm_sec, str );
960     }
961     va_end(args);
962 }
963
964 #pragma mark -
965 #pragma mark Toolbar
966 // ============================================================
967 // NSToolbar Related Methods
968 // ============================================================
969
970 - (void) setupToolbar {
971     NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier: @"HandBrake Toolbar"] autorelease];
972
973     [toolbar setAllowsUserCustomization: YES];
974     [toolbar setAutosavesConfiguration: YES];
975     [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
976
977     [toolbar setDelegate: self];
978
979     [fWindow setToolbar: toolbar];
980 }
981
982 - (NSToolbarItem *) toolbar: (NSToolbar *)toolbar itemForItemIdentifier:
983     (NSString *) itemIdent willBeInsertedIntoToolbar:(BOOL) willBeInserted {
984     NSToolbarItem * item = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdent] autorelease];
985
986     if ([itemIdent isEqualToString: ToggleDrawerIdentifier])
987     {
988         [item setLabel: @"Toggle Presets"];
989         [item setPaletteLabel: @"Toggler Presets"];
990         [item setToolTip: @"Open/Close Preset Drawer"];
991         [item setImage: [NSImage imageNamed: @"Drawer"]];
992         [item setTarget: self];
993         [item setAction: @selector(toggleDrawer:)];
994         [item setAutovalidates: NO];
995     }
996     else if ([itemIdent isEqualToString: StartEncodingIdentifier])
997     {
998         [item setLabel: @"Start"];
999         [item setPaletteLabel: @"Start Encoding"];
1000         [item setToolTip: @"Start Encoding"];
1001         [item setImage: [NSImage imageNamed: @"Play"]];
1002         [item setTarget: self];
1003         [item setAction: @selector(Rip:)];
1004     }
1005     else if ([itemIdent isEqualToString: ShowQueueIdentifier])
1006     {
1007         [item setLabel: @"Show Queue"];
1008         [item setPaletteLabel: @"Show Queue"];
1009         [item setToolTip: @"Show Queue"];
1010         [item setImage: [NSImage imageNamed: @"Queue"]];
1011         [item setTarget: self];
1012         [item setAction: @selector(showQueueWindow:)];
1013         [item setAutovalidates: NO];
1014     }
1015     else if ([itemIdent isEqualToString: AddToQueueIdentifier])
1016     {
1017         [item setLabel: @"Add to Queue"];
1018         [item setPaletteLabel: @"Add to Queue"];
1019         [item setToolTip: @"Add to Queue"];
1020         [item setImage: [NSImage imageNamed: @"AddToQueue"]];
1021         [item setTarget: self];
1022         [item setAction: @selector(addToQueue:)];
1023     }
1024     else if ([itemIdent isEqualToString: PauseEncodingIdentifier])
1025     {
1026         [item setLabel: @"Pause"];
1027         [item setPaletteLabel: @"Pause Encoding"];
1028         [item setToolTip: @"Pause Encoding"];
1029         [item setImage: [NSImage imageNamed: @"Pause"]];
1030         [item setTarget: self];
1031         [item setAction: @selector(Pause:)];
1032     }
1033     else if ([itemIdent isEqualToString: ShowPictureIdentifier])
1034     {
1035         [item setLabel: @"Picture Settings"];
1036         [item setPaletteLabel: @"Show Picture Settings"];
1037         [item setToolTip: @"Show Picture Settings"];
1038         [item setImage: [NSImage imageNamed: @"pref-picture"]];
1039         [item setTarget: self];
1040         [item setAction: @selector(showPicturePanel:)];
1041     }
1042     else if ([itemIdent isEqualToString: ShowPreviewIdentifier])
1043     {
1044         [item setLabel: @"Preview Window"];
1045         [item setPaletteLabel: @"Show Preview"];
1046         [item setToolTip: @"Show Preview"];
1047         //[item setImage: [NSImage imageNamed: @"pref-picture"]];
1048         [item setImage: [NSImage imageNamed: @"Brushed_Window"]];
1049         [item setTarget: self];
1050         [item setAction: @selector(showPreviewWindow:)];
1051     }
1052     else if ([itemIdent isEqualToString: ShowActivityIdentifier]) 
1053     {
1054         [item setLabel: @"Activity Window"];
1055         [item setPaletteLabel: @"Show Activity Window"];
1056         [item setToolTip: @"Show Activity Window"];
1057         [item setImage: [NSImage imageNamed: @"ActivityWindow"]];
1058         [item setTarget: self];
1059         [item setAction: @selector(showDebugOutputPanel:)];
1060         [item setAutovalidates: NO];
1061     }
1062     else if ([itemIdent isEqualToString: ChooseSourceIdentifier])
1063     {
1064         [item setLabel: @"Source"];
1065         [item setPaletteLabel: @"Source"];
1066         [item setToolTip: @"Choose Video Source"];
1067         [item setImage: [NSImage imageNamed: @"Source"]];
1068         [item setTarget: self];
1069         [item setAction: @selector(browseSources:)];
1070     }
1071     else
1072     {
1073         return nil;
1074     }
1075
1076     return item;
1077 }
1078
1079 - (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
1080 {
1081     return [NSArray arrayWithObjects: ChooseSourceIdentifier, NSToolbarSeparatorItemIdentifier, StartEncodingIdentifier,
1082         PauseEncodingIdentifier, AddToQueueIdentifier, ShowQueueIdentifier, NSToolbarFlexibleSpaceItemIdentifier, 
1083                 NSToolbarSpaceItemIdentifier, ShowPictureIdentifier, ShowPreviewIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier, nil];
1084 }
1085
1086 - (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
1087 {
1088     return [NSArray arrayWithObjects:  StartEncodingIdentifier, PauseEncodingIdentifier, AddToQueueIdentifier,
1089         ChooseSourceIdentifier, ShowQueueIdentifier, ShowPictureIdentifier, ShowPreviewIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier,
1090         NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier,
1091         NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil];
1092 }
1093
1094 - (BOOL) validateToolbarItem: (NSToolbarItem *) toolbarItem
1095 {
1096     NSString * ident = [toolbarItem itemIdentifier];
1097         
1098     if (fHandle)
1099     {
1100         hb_state_t s;
1101         hb_get_state2( fQueueEncodeLibhb, &s );
1102         
1103         if (s.state == HB_STATE_WORKING || s.state == HB_STATE_MUXING)
1104         {
1105             if ([ident isEqualToString: StartEncodingIdentifier])
1106             {
1107                 [toolbarItem setImage: [NSImage imageNamed: @"Stop"]];
1108                 [toolbarItem setLabel: @"Stop"];
1109                 [toolbarItem setPaletteLabel: @"Stop"];
1110                 [toolbarItem setToolTip: @"Stop Encoding"];
1111                 return YES;
1112             }
1113             if ([ident isEqualToString: PauseEncodingIdentifier])
1114             {
1115                 [toolbarItem setImage: [NSImage imageNamed: @"Pause"]];
1116                 [toolbarItem setLabel: @"Pause"];
1117                 [toolbarItem setPaletteLabel: @"Pause Encoding"];
1118                 [toolbarItem setToolTip: @"Pause Encoding"];
1119                 return YES;
1120             }
1121             if (SuccessfulScan)
1122             {
1123                 if ([ident isEqualToString: AddToQueueIdentifier])
1124                     return YES;
1125                 if ([ident isEqualToString: ShowPictureIdentifier])
1126                     return YES;
1127                 if ([ident isEqualToString: ShowPreviewIdentifier])
1128                     return YES;
1129             }
1130         }
1131         else if (s.state == HB_STATE_PAUSED)
1132         {
1133             if ([ident isEqualToString: PauseEncodingIdentifier])
1134             {
1135                 [toolbarItem setImage: [NSImage imageNamed: @"Play"]];
1136                 [toolbarItem setLabel: @"Resume"];
1137                 [toolbarItem setPaletteLabel: @"Resume Encoding"];
1138                 [toolbarItem setToolTip: @"Resume Encoding"];
1139                 return YES;
1140             }
1141             if ([ident isEqualToString: StartEncodingIdentifier])
1142                 return YES;
1143             if ([ident isEqualToString: AddToQueueIdentifier])
1144                 return YES;
1145             if ([ident isEqualToString: ShowPictureIdentifier])
1146                 return YES;
1147             if ([ident isEqualToString: ShowPreviewIdentifier])
1148                 return YES;
1149         }
1150         else if (s.state == HB_STATE_SCANNING)
1151             return NO;
1152         else if (s.state == HB_STATE_WORKDONE || s.state == HB_STATE_SCANDONE || SuccessfulScan)
1153         {
1154             if ([ident isEqualToString: StartEncodingIdentifier])
1155             {
1156                 [toolbarItem setImage: [NSImage imageNamed: @"Play"]];
1157                 if (hb_count(fHandle) > 0)
1158                     [toolbarItem setLabel: @"Start Queue"];
1159                 else
1160                     [toolbarItem setLabel: @"Start"];
1161                 [toolbarItem setPaletteLabel: @"Start Encoding"];
1162                 [toolbarItem setToolTip: @"Start Encoding"];
1163                 return YES;
1164             }
1165             if ([ident isEqualToString: AddToQueueIdentifier])
1166                 return YES;
1167             if ([ident isEqualToString: ShowPictureIdentifier])
1168                 return YES;
1169             if ([ident isEqualToString: ShowPreviewIdentifier])
1170                 return YES;
1171         }
1172
1173     }
1174     /* If there are any pending queue items, make sure the start/stop button is active */
1175     if ([ident isEqualToString: StartEncodingIdentifier] && fPendingCount > 0)
1176         return YES;
1177     if ([ident isEqualToString: ShowQueueIdentifier])
1178         return YES;
1179     if ([ident isEqualToString: ToggleDrawerIdentifier])
1180         return YES;
1181     if ([ident isEqualToString: ChooseSourceIdentifier])
1182         return YES;
1183     if ([ident isEqualToString: ShowActivityIdentifier])
1184         return YES;
1185     
1186     return NO;
1187 }
1188
1189 - (BOOL) validateMenuItem: (NSMenuItem *) menuItem
1190 {
1191     SEL action = [menuItem action];
1192     
1193     hb_state_t s;
1194     hb_get_state2( fHandle, &s );
1195     
1196     if (fHandle)
1197     {
1198         if (action == @selector(addToQueue:) || action == @selector(showPicturePanel:) || action == @selector(showAddPresetPanel:))
1199             return SuccessfulScan && [fWindow attachedSheet] == nil;
1200         
1201         if (action == @selector(browseSources:))
1202         {
1203             if (s.state == HB_STATE_SCANNING)
1204                 return NO;
1205             else
1206                 return [fWindow attachedSheet] == nil;
1207         }
1208         if (action == @selector(selectDefaultPreset:))
1209             return [fPresetsOutlineView selectedRow] >= 0 && [fWindow attachedSheet] == nil;
1210         if (action == @selector(Pause:))
1211         {
1212             if (s.state == HB_STATE_WORKING)
1213             {
1214                 if(![[menuItem title] isEqualToString:@"Pause Encoding"])
1215                     [menuItem setTitle:@"Pause Encoding"];
1216                 return YES;
1217             }
1218             else if (s.state == HB_STATE_PAUSED)
1219             {
1220                 if(![[menuItem title] isEqualToString:@"Resume Encoding"])
1221                     [menuItem setTitle:@"Resume Encoding"];
1222                 return YES;
1223             }
1224             else
1225                 return NO;
1226         }
1227         if (action == @selector(Rip:))
1228         {
1229             if (s.state == HB_STATE_WORKING || s.state == HB_STATE_MUXING || s.state == HB_STATE_PAUSED)
1230             {
1231                 if(![[menuItem title] isEqualToString:@"Stop Encoding"])
1232                     [menuItem setTitle:@"Stop Encoding"];
1233                 return YES;
1234             }
1235             else if (SuccessfulScan)
1236             {
1237                 if(![[menuItem title] isEqualToString:@"Start Encoding"])
1238                     [menuItem setTitle:@"Start Encoding"];
1239                 return [fWindow attachedSheet] == nil;
1240             }
1241             else
1242                 return NO;
1243         }
1244     }
1245     if( action == @selector(setDefaultPreset:) )
1246     {
1247         return [fPresetsOutlineView selectedRow] != -1;
1248     }
1249
1250     return YES;
1251 }
1252
1253 #pragma mark -
1254 #pragma mark Encode Done Actions
1255 // register a test notification and make
1256 // it enabled by default
1257 #define SERVICE_NAME @"Encode Done"
1258 - (NSDictionary *)registrationDictionaryForGrowl 
1259
1260     NSDictionary *registrationDictionary = [NSDictionary dictionaryWithObjectsAndKeys: 
1261     [NSArray arrayWithObjects:SERVICE_NAME,nil], GROWL_NOTIFICATIONS_ALL, 
1262     [NSArray arrayWithObjects:SERVICE_NAME,nil], GROWL_NOTIFICATIONS_DEFAULT, 
1263     nil]; 
1264
1265     return registrationDictionary; 
1266
1267
1268 -(void)showGrowlDoneNotification:(NSString *) filePath
1269 {
1270     /* This end of encode action is called as each encode rolls off of the queue */
1271     NSString * finishedEncode = filePath;
1272     /* strip off the path to just show the file name */
1273     finishedEncode = [finishedEncode lastPathComponent];
1274     if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Growl Notification"] || 
1275         [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"])
1276     {
1277         NSString * growlMssg = [NSString stringWithFormat: @"your HandBrake encode %@ is done!",finishedEncode];
1278         [GrowlApplicationBridge 
1279          notifyWithTitle:@"Put down that cocktail..." 
1280          description:growlMssg 
1281          notificationName:SERVICE_NAME
1282          iconData:nil 
1283          priority:0 
1284          isSticky:1 
1285          clickContext:nil];
1286     }
1287     
1288 }
1289 -(void)sendToMetaX:(NSString *) filePath
1290 {
1291     /* This end of encode action is called as each encode rolls off of the queue */
1292     if([[NSUserDefaults standardUserDefaults] boolForKey: @"sendToMetaX"] == YES)
1293     {
1294         NSAppleScript *myScript = [[NSAppleScript alloc] initWithSource: [NSString stringWithFormat: @"%@%@%@", @"tell application \"MetaX\" to open (POSIX file \"", filePath, @"\")"]];
1295         [myScript executeAndReturnError: nil];
1296         [myScript release];
1297     }
1298 }
1299 #pragma mark -
1300 #pragma mark Get New Source
1301
1302 /*Opens the source browse window, called from Open Source widgets */
1303 - (IBAction) browseSources: (id) sender
1304 {
1305     NSOpenPanel * panel;
1306         
1307     panel = [NSOpenPanel openPanel];
1308     [panel setAllowsMultipleSelection: NO];
1309     [panel setCanChooseFiles: YES];
1310     [panel setCanChooseDirectories: YES ];
1311     NSString * sourceDirectory;
1312         if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastSourceDirectory"])
1313         {
1314                 sourceDirectory = [[NSUserDefaults standardUserDefaults] stringForKey:@"LastSourceDirectory"];
1315         }
1316         else
1317         {
1318                 sourceDirectory = @"~/Desktop";
1319                 sourceDirectory = [sourceDirectory stringByExpandingTildeInPath];
1320         }
1321     /* we open up the browse sources sheet here and call for browseSourcesDone after the sheet is closed
1322         * to evaluate whether we want to specify a title, we pass the sender in the contextInfo variable
1323         */
1324     [panel beginSheetForDirectory: sourceDirectory file: nil types: nil
1325                    modalForWindow: fWindow modalDelegate: self
1326                    didEndSelector: @selector( browseSourcesDone:returnCode:contextInfo: )
1327                       contextInfo: sender]; 
1328 }
1329
1330 - (void) browseSourcesDone: (NSOpenPanel *) sheet
1331                 returnCode: (int) returnCode contextInfo: (void *) contextInfo
1332 {
1333     /* we convert the sender content of contextInfo back into a variable called sender
1334      * mostly just for consistency for evaluation later
1335      */
1336     id sender = (id)contextInfo;
1337     /* User selected a file to open */
1338         if( returnCode == NSOKButton )
1339     {
1340             /* Free display name allocated previously by this code */
1341         [browsedSourceDisplayName release];
1342        
1343         NSString *scanPath = [[sheet filenames] objectAtIndex: 0];
1344         /* we set the last searched source directory in the prefs here */
1345         NSString *sourceDirectory = [scanPath stringByDeletingLastPathComponent];
1346         [[NSUserDefaults standardUserDefaults] setObject:sourceDirectory forKey:@"LastSourceDirectory"];
1347         /* we order out sheet, which is the browse window as we need to open
1348          * the title selection sheet right away
1349          */
1350         [sheet orderOut: self];
1351         
1352         if (sender == fOpenSourceTitleMMenu)
1353         {
1354             /* We put the chosen source path in the source display text field for the
1355              * source title selection sheet in which the user specifies the specific title to be
1356              * scanned  as well as the short source name in fSrcDsplyNameTitleScan just for display
1357              * purposes in the title panel
1358              */
1359             /* Full Path */
1360             [fScanSrcTitlePathField setStringValue:scanPath];
1361             NSString *displayTitlescanSourceName;
1362
1363             if ([[scanPath lastPathComponent] isEqualToString: @"VIDEO_TS"])
1364             {
1365                 /* If VIDEO_TS Folder is chosen, choose its parent folder for the source display name
1366                  we have to use the title->dvd value so we get the proper name of the volume if a physical dvd is the source*/
1367                 displayTitlescanSourceName = [[scanPath stringByDeletingLastPathComponent] lastPathComponent];
1368             }
1369             else
1370             {
1371                 /* if not the VIDEO_TS Folder, we can assume the chosen folder is the source name */
1372                 displayTitlescanSourceName = [scanPath lastPathComponent];
1373             }
1374             /* we set the source display name in the title selection dialogue */
1375             [fSrcDsplyNameTitleScan setStringValue:displayTitlescanSourceName];
1376             /* we set the attempted scans display name for main window to displayTitlescanSourceName*/
1377             browsedSourceDisplayName = [displayTitlescanSourceName retain];
1378             /* We show the actual sheet where the user specifies the title to be scanned
1379              * as we are going to do a title specific scan
1380              */
1381             [self showSourceTitleScanPanel:nil];
1382         }
1383         else
1384         {
1385             /* We are just doing a standard full source scan, so we specify "0" to libhb */
1386             NSString *path = [[sheet filenames] objectAtIndex: 0];
1387             
1388             /* We check to see if the chosen file at path is a package */
1389             if ([[NSWorkspace sharedWorkspace] isFilePackageAtPath:path])
1390             {
1391                 [self writeToActivityLog: "trying to open a package at: %s", [path UTF8String]];
1392                 /* We check to see if this is an .eyetv package */
1393                 if ([[path pathExtension] isEqualToString: @"eyetv"])
1394                 {
1395                     [self writeToActivityLog:"trying to open eyetv package"];
1396                     /* We're looking at an EyeTV package - try to open its enclosed
1397                      .mpg media file */
1398                      browsedSourceDisplayName = [[[path stringByDeletingPathExtension] lastPathComponent] retain];
1399                     NSString *mpgname;
1400                     int n = [[path stringByAppendingString: @"/"]
1401                              completePathIntoString: &mpgname caseSensitive: NO
1402                              matchesIntoArray: nil
1403                              filterTypes: [NSArray arrayWithObject: @"mpg"]];
1404                     if (n > 0)
1405                     {
1406                         /* Found an mpeg inside the eyetv package, make it our scan path 
1407                         and call performScan on the enclosed mpeg */
1408                         path = mpgname;
1409                         [self writeToActivityLog:"found mpeg in eyetv package"];
1410                         [self performScan:path scanTitleNum:0];
1411                     }
1412                     else
1413                     {
1414                         /* We did not find an mpeg file in our package, so we do not call performScan */
1415                         [self writeToActivityLog:"no valid mpeg in eyetv package"];
1416                     }
1417                 }
1418                 /* We check to see if this is a .dvdmedia package */
1419                 else if ([[path pathExtension] isEqualToString: @"dvdmedia"])
1420                 {
1421                     /* path IS a package - but dvdmedia packages can be treaded like normal directories */
1422                     browsedSourceDisplayName = [[[path stringByDeletingPathExtension] lastPathComponent] retain];
1423                     [self writeToActivityLog:"trying to open dvdmedia package"];
1424                     [self performScan:path scanTitleNum:0];
1425                 }
1426                 else
1427                 {
1428                     /* The package is not an eyetv package, so we do not call performScan */
1429                     [self writeToActivityLog:"unable to open package"];
1430                 }
1431             }
1432             else // path is not a package, so we treat it as a dvd parent folder or VIDEO_TS folder
1433             {
1434                 /* path is not a package, so we call perform scan directly on our file */
1435                 if ([[path lastPathComponent] isEqualToString: @"VIDEO_TS"])
1436                 {
1437                     [self writeToActivityLog:"trying to open video_ts folder (video_ts folder chosen)"];
1438                     /* If VIDEO_TS Folder is chosen, choose its parent folder for the source display name*/
1439                     browsedSourceDisplayName = [[[path stringByDeletingLastPathComponent] lastPathComponent] retain];
1440                 }
1441                 else
1442                 {
1443                     [self writeToActivityLog:"trying to open video_ts folder (parent directory chosen)"];
1444                     /* if not the VIDEO_TS Folder, we can assume the chosen folder is the source name */
1445                     /* make sure we remove any path extension as this can also be an '.mpg' file */
1446                     browsedSourceDisplayName = [[path lastPathComponent] retain];
1447                 }
1448                 [self performScan:path scanTitleNum:0];
1449             }
1450
1451         }
1452
1453     }
1454 }
1455
1456 - (IBAction)showAboutPanel:(id)sender
1457 {
1458     NSMutableDictionary* d = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
1459         fApplicationIcon, @"ApplicationIcon",
1460         nil ];
1461     [NSApp orderFrontStandardAboutPanelWithOptions:d];
1462     [d release];
1463 }
1464
1465 /* Here we open the title selection sheet where we can specify an exact title to be scanned */
1466 - (IBAction) showSourceTitleScanPanel: (id) sender
1467 {
1468     /* We default the title number to be scanned to "0" which results in a full source scan, unless the
1469     * user changes it
1470     */
1471     [fScanSrcTitleNumField setStringValue: @"0"];
1472         /* Show the panel */
1473         [NSApp beginSheet:fScanSrcTitlePanel modalForWindow:fWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
1474 }
1475
1476 - (IBAction) closeSourceTitleScanPanel: (id) sender
1477 {
1478     [NSApp endSheet: fScanSrcTitlePanel];
1479     [fScanSrcTitlePanel orderOut: self];
1480
1481     if(sender == fScanSrcTitleOpenButton)
1482     {
1483         /* We setup the scan status in the main window to indicate a source title scan */
1484         [fSrcDVD2Field setStringValue: @"Opening a new source title ..."];
1485                 [fScanIndicator setHidden: NO];
1486         [fScanIndicator setIndeterminate: YES];
1487         [fScanIndicator startAnimation: nil];
1488                 
1489         /* We use the performScan method to actually perform the specified scan passing the path and the title
1490             * to be scanned
1491             */
1492         [self performScan:[fScanSrcTitlePathField stringValue] scanTitleNum:[fScanSrcTitleNumField intValue]];
1493     }
1494 }
1495
1496 /* Here we actually tell hb_scan to perform the source scan, using the path to source and title number*/
1497 - (void) performScan:(NSString *) scanPath scanTitleNum: (int) scanTitleNum
1498 {
1499     /* set the bool applyQueueToScan so that we dont apply a queue setting to the final scan */
1500     applyQueueToScan = NO;
1501     /* use a bool to determine whether or not we can decrypt using vlc */
1502     BOOL cancelScanDecrypt = 0;
1503     NSString *path = scanPath;
1504     HBDVDDetector *detector = [HBDVDDetector detectorForPath:path];
1505     
1506     // Notify ChapterTitles that there's no title
1507     [fChapterTitlesDelegate resetWithTitle:nil];
1508     [fChapterTable reloadData];
1509     
1510     // Notify Subtitles that there's no title
1511     [fSubtitlesDelegate resetWithTitle:nil];
1512     [fSubtitlesTable reloadData];
1513     
1514     [self enableUI: NO];
1515     
1516     if( [detector isVideoDVD] )
1517     {
1518         // The chosen path was actually on a DVD, so use the raw block
1519         // device path instead.
1520         path = [detector devicePath];
1521         [self writeToActivityLog: "trying to open a physical dvd at: %s", [scanPath UTF8String]];
1522         
1523 #if defined( __LP64__ )
1524         /* If we are 64 bit, we cannot read encrypted dvd's as vlc is 32 bit only */
1525         cancelScanDecrypt = 1;
1526         [self writeToActivityLog: "64 bit mode cannot read dvd's, scan cancelled"];
1527         /*On Screen Notification*/
1528         int status;
1529         NSBeep();
1530         status = NSRunAlertPanel(@"64-bit HandBrake cannot read encrypted dvds!",@"", @"Cancel Scan", @"Attempt Scan Anyway", nil);
1531         [NSApp requestUserAttention:NSCriticalRequest];
1532         
1533         if (status == NSAlertDefaultReturn)
1534         {
1535             /* User chose to cancel the scan */
1536             [self writeToActivityLog: "cannot open physical dvd , scan cancelled"];
1537             cancelScanDecrypt = 1;
1538         }
1539         else
1540         {
1541             [self writeToActivityLog: "user overrode 64-bit warning trying to open physical dvd without decryption"];
1542             cancelScanDecrypt = 0;
1543         }
1544
1545 #else
1546         /* lets check for vlc here to make sure we have a dylib available to use for decrypting */
1547         NSString *vlcPath = @"/Applications/VLC.app/Contents/MacOS/lib/libdvdcss.2.dylib";
1548         NSFileManager * fileManager = [NSFileManager defaultManager];
1549             if ([fileManager fileExistsAtPath:vlcPath] == 0) 
1550             {
1551             /*vlc not found in /Applications so we set the bool to cancel scanning to 1 */
1552             cancelScanDecrypt = 1;
1553             [self writeToActivityLog: "VLC app not found for decrypting physical dvd"];
1554             int status;
1555             status = NSRunAlertPanel(@"HandBrake could not find VLC or your VLC is out of date.",@"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");
1556             [NSApp requestUserAttention:NSCriticalRequest];
1557             
1558             if (status == NSAlertDefaultReturn)
1559             {
1560                 /* User chose to go download vlc (as they rightfully should) so we send them to the vlc site */
1561                 [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.videolan.org/"]];
1562             }
1563             else if (status == NSAlertAlternateReturn)
1564             {
1565                 /* User chose to cancel the scan */
1566                 [self writeToActivityLog: "cannot open physical dvd , scan cancelled"];
1567             }
1568             else
1569             {
1570                 /* 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 */
1571                 cancelScanDecrypt = 0;
1572                 [self writeToActivityLog: "user overrode vlc warning -trying to open physical dvd without decryption"];
1573             }
1574             
1575         }
1576         else
1577         {
1578             /* VLC was found in /Applications so all is well, we can carry on using vlc's libdvdcss.dylib for decrypting if needed */
1579             [self writeToActivityLog: "VLC app found for decrypting physical dvd"];
1580         }
1581 #endif 
1582     }
1583     
1584     if (cancelScanDecrypt == 0)
1585     {
1586         /* we actually pass the scan off to libhb here */
1587         /* If there is no title number passed to scan, we use "0"
1588          * which causes the default behavior of a full source scan
1589          */
1590         if (!scanTitleNum)
1591         {
1592             scanTitleNum = 0;
1593         }
1594         if (scanTitleNum > 0)
1595         {
1596             [self writeToActivityLog: "scanning specifically for title: %d", scanTitleNum];
1597         }
1598         /* We use our advance pref to determine how many previews to scan */
1599         int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue];
1600         /* set title to NULL */
1601         //fTitle = NULL;
1602         hb_scan( fHandle, [path UTF8String], scanTitleNum, hb_num_previews, 1 );
1603         [fSrcDVD2Field setStringValue:@"Scanning new source ..."];
1604     }
1605 }
1606
1607 - (IBAction) showNewScan:(id)sender
1608 {
1609     hb_list_t  * list;
1610         hb_title_t * title;
1611         int indxpri=0;    // Used to search the longuest title (default in combobox)
1612         int longuestpri=0; // Used to search the longuest title (default in combobox)
1613     
1614
1615         list = hb_get_titles( fHandle );
1616         
1617         if( !hb_list_count( list ) )
1618         {
1619             /* We display a message if a valid dvd source was not chosen */
1620             [fSrcDVD2Field setStringValue: @"No Valid Source Found"];
1621             SuccessfulScan = NO;
1622             
1623             // Notify ChapterTitles that there's no title
1624             [fSubtitlesDelegate resetWithTitle:nil];
1625             [fSubtitlesTable reloadData];
1626             
1627             // Notify Subtitles that there's no title
1628             [fChapterTitlesDelegate resetWithTitle:nil];
1629             [fChapterTable reloadData];
1630         }
1631         else
1632         {
1633             /* We increment the successful scancount here by one,
1634              which we use at the end of this function to tell the gui
1635              if this is the first successful scan since launch and whether
1636              or not we should set all settings to the defaults */
1637             
1638             currentSuccessfulScanCount++;
1639             
1640             [[fWindow toolbar] validateVisibleItems];
1641             
1642             [fSrcTitlePopUp removeAllItems];
1643             for( int i = 0; i < hb_list_count( list ); i++ )
1644             {
1645                 title = (hb_title_t *) hb_list_item( list, i );
1646                 
1647                 currentSource = [NSString stringWithUTF8String: title->name];
1648                 /*Set DVD Name at top of window with the browsedSourceDisplayName grokked right before -performScan */
1649                 [fSrcDVD2Field setStringValue:browsedSourceDisplayName];
1650                 
1651                 /* Use the dvd name in the default output field here
1652                  May want to add code to remove blank spaces for some dvd names*/
1653                 /* Check to see if the last destination has been set,use if so, if not, use Desktop */
1654                 if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"])
1655                 {
1656                     [fDstFile2Field setStringValue: [NSString stringWithFormat:
1657                                                      @"%@/%@.mp4", [[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"],[browsedSourceDisplayName stringByDeletingPathExtension]]];
1658                 }
1659                 else
1660                 {
1661                     [fDstFile2Field setStringValue: [NSString stringWithFormat:
1662                                                      @"%@/Desktop/%@.mp4", NSHomeDirectory(),[browsedSourceDisplayName stringByDeletingPathExtension]]];
1663                 }
1664                 
1665                 
1666                 if (longuestpri < title->hours*60*60 + title->minutes *60 + title->seconds)
1667                 {
1668                     longuestpri=title->hours*60*60 + title->minutes *60 + title->seconds;
1669                     indxpri=i;
1670                 }
1671                 
1672                 [fSrcTitlePopUp addItemWithTitle: [NSString
1673                                                    stringWithFormat: @"%d - %02dh%02dm%02ds",
1674                                                    title->index, title->hours, title->minutes,
1675                                                    title->seconds]];
1676             }
1677             
1678             // Select the longuest title
1679             [fSrcTitlePopUp selectItemAtIndex: indxpri];
1680             [self titlePopUpChanged:nil];
1681             
1682             SuccessfulScan = YES;
1683             [self enableUI: YES];
1684
1685             /* if its the initial successful scan after awakeFromNib */
1686             if (currentSuccessfulScanCount == 1)
1687             {
1688                 [self selectDefaultPreset:nil];
1689                 
1690                 // Open preview window now if it was visible when HB was closed
1691                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"PreviewWindowIsOpen"])
1692                     [self showPreviewWindow:nil];
1693                 
1694                 // Open picture sizing window now if it was visible when HB was closed
1695                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"PictureSizeWindowIsOpen"])
1696                     [self showPicturePanel:nil];
1697                 
1698             }
1699
1700             
1701         }
1702
1703 }
1704
1705
1706 #pragma mark -
1707 #pragma mark New Output Destination
1708
1709 - (IBAction) browseFile: (id) sender
1710 {
1711     /* Open a panel to let the user choose and update the text field */
1712     NSSavePanel * panel = [NSSavePanel savePanel];
1713         /* We get the current file name and path from the destination field here */
1714         [panel beginSheetForDirectory: [[fDstFile2Field stringValue] stringByDeletingLastPathComponent] file: [[fDstFile2Field stringValue] lastPathComponent]
1715                                    modalForWindow: fWindow modalDelegate: self
1716                                    didEndSelector: @selector( browseFileDone:returnCode:contextInfo: )
1717                                           contextInfo: NULL];
1718 }
1719
1720 - (void) browseFileDone: (NSSavePanel *) sheet
1721              returnCode: (int) returnCode contextInfo: (void *) contextInfo
1722 {
1723     if( returnCode == NSOKButton )
1724     {
1725         [fDstFile2Field setStringValue: [sheet filename]];
1726         /* Save this path to the prefs so that on next browse destination window it opens there */
1727         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
1728         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];   
1729     }
1730 }
1731
1732
1733 #pragma mark -
1734 #pragma mark Main Window Control
1735
1736 - (IBAction) openMainWindow: (id) sender
1737 {
1738     [fWindow  makeKeyAndOrderFront:nil];
1739 }
1740
1741 - (BOOL) windowShouldClose: (id) sender
1742 {
1743     return YES;
1744 }
1745
1746 - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
1747 {
1748     if( !flag ) {
1749         [fWindow  makeKeyAndOrderFront:nil];
1750                 
1751         return YES;
1752     }
1753     
1754     return NO;
1755 }
1756
1757 - (NSSize) drawerWillResizeContents:(NSDrawer *) drawer toSize:(NSSize) contentSize {
1758         [[NSUserDefaults standardUserDefaults] setObject:NSStringFromSize( contentSize ) forKey:@"Drawer Size"];
1759         return contentSize;
1760 }
1761
1762 #pragma mark -
1763 #pragma mark Queue File
1764
1765 - (void) loadQueueFile {
1766         /* We declare the default NSFileManager into fileManager */
1767         NSFileManager * fileManager = [NSFileManager defaultManager];
1768         /*We define the location of the user presets file */
1769     QueueFile = @"~/Library/Application Support/HandBrake/Queue.plist";
1770         QueueFile = [[QueueFile stringByExpandingTildeInPath]retain];
1771     /* We check for the presets.plist */
1772         if ([fileManager fileExistsAtPath:QueueFile] == 0)
1773         {
1774                 [fileManager createFileAtPath:QueueFile contents:nil attributes:nil];
1775         }
1776
1777         QueueFileArray = [[NSMutableArray alloc] initWithContentsOfFile:QueueFile];
1778         /* lets check to see if there is anything in the queue file .plist */
1779     if (nil == QueueFileArray)
1780         {
1781         /* if not, then lets initialize an empty array */
1782                 QueueFileArray = [[NSMutableArray alloc] init];
1783         
1784      /* Initialize our curQueueEncodeIndex to 0
1785      * so we can use it to track which queue
1786      * item is to be used to track our encodes */
1787      /* NOTE: this should be changed if and when we
1788       * are able to get the last unfinished encode
1789       * in the case of a crash or shutdown */
1790     
1791         }
1792     else
1793     {
1794     [self clearQueueEncodedItems];
1795     }
1796     currentQueueEncodeIndex = 0;
1797 }
1798
1799 - (void)addQueueFileItem
1800 {
1801         [QueueFileArray addObject:[self createQueueFileItem]];
1802         [self saveQueueFileItem];
1803
1804 }
1805
1806 - (void) removeQueueFileItem:(int) queueItemToRemove
1807 {
1808    
1809    /* Find out if the item we are removing is a cancelled (3) or a finished (0) item*/
1810    if ([[[QueueFileArray objectAtIndex:queueItemToRemove] objectForKey:@"Status"] intValue] == 3 || [[[QueueFileArray objectAtIndex:queueItemToRemove] objectForKey:@"Status"] intValue] == 0)
1811     {
1812     /* Since we are removing a cancelled or finished item, WE need to decrement the currentQueueEncodeIndex
1813      * by one to keep in sync with the queue array
1814      */
1815     currentQueueEncodeIndex--;
1816     [self writeToActivityLog: "removeQueueFileItem: Removing a cancelled/finished encode, decrement currentQueueEncodeIndex to %d", currentQueueEncodeIndex];
1817     }
1818     [QueueFileArray removeObjectAtIndex:queueItemToRemove];
1819     [self saveQueueFileItem];
1820
1821 }
1822
1823 - (void)saveQueueFileItem
1824 {
1825     [QueueFileArray writeToFile:QueueFile atomically:YES];
1826     [fQueueController setQueueArray: QueueFileArray];
1827     [self getQueueStats];
1828 }
1829
1830 - (void)getQueueStats
1831 {
1832 /* lets get the stats on the status of the queue array */
1833
1834 fEncodingQueueItem = 0;
1835 fPendingCount = 0;
1836 fCompletedCount = 0;
1837 fCanceledCount = 0;
1838 fWorkingCount = 0;
1839
1840     /* We use a number system to set the encode status of the queue item
1841      * in controller.mm
1842      * 0 == already encoded
1843      * 1 == is being encoded
1844      * 2 == is yet to be encoded
1845      * 3 == cancelled
1846      */
1847
1848         int i = 0;
1849     NSEnumerator *enumerator = [QueueFileArray objectEnumerator];
1850         id tempObject;
1851         while (tempObject = [enumerator nextObject])
1852         {
1853                 NSDictionary *thisQueueDict = tempObject;
1854                 if ([[thisQueueDict objectForKey:@"Status"] intValue] == 0) // Completed
1855                 {
1856                         fCompletedCount++;      
1857                 }
1858                 if ([[thisQueueDict objectForKey:@"Status"] intValue] == 1) // being encoded
1859                 {
1860                         fWorkingCount++;
1861             fEncodingQueueItem = i;     
1862                 }
1863         if ([[thisQueueDict objectForKey:@"Status"] intValue] == 2) // pending          
1864         {
1865                         fPendingCount++;
1866                 }
1867         if ([[thisQueueDict objectForKey:@"Status"] intValue] == 3) // cancelled                
1868         {
1869                         fCanceledCount++;
1870                 }
1871                 i++;
1872         }
1873
1874     /* Set the queue status field in the main window */
1875     NSMutableString * string;
1876     if (fPendingCount == 1)
1877     {
1878         string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encode pending in the queue", @"" ), fPendingCount];
1879     }
1880     else
1881     {
1882         string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encode(s) pending in the queue", @"" ), fPendingCount];
1883     }
1884     [fQueueStatus setStringValue:string];
1885 }
1886
1887 /* This method will set any item marked as encoding back to pending
1888  * currently used right after a queue reload
1889  */
1890 - (void) setQueueEncodingItemsAsPending
1891 {
1892     NSEnumerator *enumerator = [QueueFileArray objectEnumerator];
1893         id tempObject;
1894     NSMutableArray *tempArray;
1895     tempArray = [NSMutableArray array];
1896     /* we look here to see if the preset is we move on to the next one */
1897     while ( tempObject = [enumerator nextObject] )  
1898     {
1899         /* If the queue item is marked as "encoding" (1)
1900          * then change its status back to pending (2) which effectively
1901          * puts it back into the queue to be encoded
1902          */
1903         if ([[tempObject objectForKey:@"Status"] intValue] == 1)
1904         {
1905             [tempObject setObject:[NSNumber numberWithInt: 2] forKey:@"Status"];
1906         }
1907         [tempArray addObject:tempObject];
1908     }
1909     
1910     [QueueFileArray setArray:tempArray];
1911     [self saveQueueFileItem];
1912 }
1913
1914
1915 /* This method will clear the queue of any encodes that are not still pending
1916  * this includes both successfully completed encodes as well as cancelled encodes */
1917 - (void) clearQueueEncodedItems
1918 {
1919     NSEnumerator *enumerator = [QueueFileArray objectEnumerator];
1920         id tempObject;
1921     NSMutableArray *tempArray;
1922     tempArray = [NSMutableArray array];
1923     /* we look here to see if the preset is we move on to the next one */
1924     while ( tempObject = [enumerator nextObject] )  
1925     {
1926         /* If the queue item is either completed (0) or cancelled (3) from the
1927          * last session, then we put it in tempArray to be deleted from QueueFileArray.
1928          * NOTE: this means we retain pending (2) and also an item that is marked as
1929          * still encoding (1). If the queue has an item that is still marked as encoding
1930          * from a previous session, we can conlude that HB was either shutdown, or crashed
1931          * during the encodes so we keep it and tell the user in the "Load Queue Alert"
1932          */
1933         if ([[tempObject objectForKey:@"Status"] intValue] == 0 || [[tempObject objectForKey:@"Status"] intValue] == 3)
1934         {
1935             [tempArray addObject:tempObject];
1936         }
1937     }
1938     
1939     [QueueFileArray removeObjectsInArray:tempArray];
1940     [self saveQueueFileItem];
1941 }
1942
1943 /* This method will clear the queue of all encodes. effectively creating an empty queue */
1944 - (void) clearQueueAllItems
1945 {
1946     NSEnumerator *enumerator = [QueueFileArray objectEnumerator];
1947         id tempObject;
1948     NSMutableArray *tempArray;
1949     tempArray = [NSMutableArray array];
1950     /* we look here to see if the preset is we move on to the next one */
1951     while ( tempObject = [enumerator nextObject] )  
1952     {
1953         [tempArray addObject:tempObject];
1954     }
1955     
1956     [QueueFileArray removeObjectsInArray:tempArray];
1957     [self saveQueueFileItem];
1958 }
1959
1960 /* This method will duplicate prepareJob however into the
1961  * queue .plist instead of into the job structure so it can
1962  * be recalled later */
1963 - (NSDictionary *)createQueueFileItem
1964 {
1965     NSMutableDictionary *queueFileJob = [[NSMutableDictionary alloc] init];
1966     
1967        hb_list_t  * list  = hb_get_titles( fHandle );
1968     hb_title_t * title = (hb_title_t *) hb_list_item( list,
1969             [fSrcTitlePopUp indexOfSelectedItem] );
1970     hb_job_t * job = title->job;
1971     
1972     
1973     
1974     /* We use a number system to set the encode status of the queue item
1975      * 0 == already encoded
1976      * 1 == is being encoded
1977      * 2 == is yet to be encoded
1978      * 3 == cancelled
1979      */
1980     [queueFileJob setObject:[NSNumber numberWithInt:2] forKey:@"Status"];
1981     /* Source and Destination Information */
1982     
1983     [queueFileJob setObject:[NSString stringWithUTF8String: title->dvd] forKey:@"SourcePath"];
1984     [queueFileJob setObject:[fSrcDVD2Field stringValue] forKey:@"SourceName"];
1985     [queueFileJob setObject:[NSNumber numberWithInt:title->index] forKey:@"TitleNumber"];
1986     [queueFileJob setObject:[NSNumber numberWithInt:[fSrcAnglePopUp indexOfSelectedItem] + 1] forKey:@"TitleAngle"];
1987     [queueFileJob setObject:[NSNumber numberWithInt:[fSrcChapterStartPopUp indexOfSelectedItem] + 1] forKey:@"ChapterStart"];
1988     
1989     [queueFileJob setObject:[NSNumber numberWithInt:[fSrcChapterEndPopUp indexOfSelectedItem] + 1] forKey:@"ChapterEnd"];
1990     
1991     [queueFileJob setObject:[fDstFile2Field stringValue] forKey:@"DestinationPath"];
1992     
1993     /* Lets get the preset info if there is any */
1994     [queueFileJob setObject:[fPresetSelectedDisplay stringValue] forKey:@"PresetName"];
1995     [queueFileJob setObject:[NSNumber numberWithInt:[fPresetsOutlineView selectedRow]] forKey:@"PresetIndexNum"];
1996     
1997     [queueFileJob setObject:[fDstFormatPopUp titleOfSelectedItem] forKey:@"FileFormat"];
1998     /* Chapter Markers*/
1999     /* If we have only one chapter or a title without chapters, set chapter markers to off */
2000     if ([fSrcChapterStartPopUp indexOfSelectedItem] ==  [fSrcChapterEndPopUp indexOfSelectedItem])
2001     {
2002         [queueFileJob setObject:[NSNumber numberWithInt:0] forKey:@"ChapterMarkers"];
2003     }
2004     else
2005     {
2006         [queueFileJob setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"];
2007     }
2008         
2009     /* We need to get the list of chapter names to put into an array and store 
2010      * in our queue, so they can be reapplied in prepareJob when this queue
2011      * item comes up if Chapter Markers is set to on.
2012      */
2013      int i;
2014      NSMutableArray *ChapterNamesArray = [[NSMutableArray alloc] init];
2015      int chaptercount = hb_list_count( fTitle->list_chapter );
2016      for( i = 0; i < chaptercount; i++ )
2017     {
2018         hb_chapter_t *chapter = (hb_chapter_t *) hb_list_item( fTitle->list_chapter, i );
2019         if( chapter != NULL )
2020         {
2021           [ChapterNamesArray addObject:[NSString stringWithCString:chapter->title encoding:NSUTF8StringEncoding]];
2022         }
2023     }
2024     [queueFileJob setObject:[NSMutableArray arrayWithArray: ChapterNamesArray] forKey:@"ChapterNames"];
2025     [ChapterNamesArray autorelease];
2026     
2027     /* Allow Mpeg4 64 bit formatting +4GB file sizes */
2028         [queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4LargeFileCheck state]] forKey:@"Mp4LargeFile"];
2029     /* Mux mp4 with http optimization */
2030     [queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4HttpOptFileCheck state]] forKey:@"Mp4HttpOptimize"];
2031     /* Add iPod uuid atom */
2032     [queueFileJob setObject:[NSNumber numberWithInt:[fDstMp4iPodFileCheck state]] forKey:@"Mp4iPodCompatible"];
2033     
2034     /* Codecs */
2035         /* Video encoder */
2036         [queueFileJob setObject:[fVidEncoderPopUp titleOfSelectedItem] forKey:@"VideoEncoder"];
2037         /* x264 Option String */
2038         [queueFileJob setObject:[fAdvancedOptions optionsString] forKey:@"x264Option"];
2039
2040         [queueFileJob setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"];
2041         [queueFileJob setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
2042         [queueFileJob setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"];
2043         [queueFileJob setObject:[NSNumber numberWithFloat:[fVidQualityRFField floatValue]] forKey:@"VideoQualitySlider"];
2044     /* Framerate */
2045     [queueFileJob setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"];
2046     
2047         /* 2 Pass Encoding */
2048         [queueFileJob setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"];
2049         /* Turbo 2 pass Encoding fVidTurboPassCheck*/
2050         [queueFileJob setObject:[NSNumber numberWithInt:[fVidTurboPassCheck state]] forKey:@"VideoTurboTwoPass"];
2051     
2052         /* Picture Sizing */
2053         /* Use Max Picture settings for whatever the dvd is.*/
2054         [queueFileJob setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"];
2055         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"];
2056         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"];
2057         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"];
2058         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.mode] forKey:@"PicturePAR"];
2059     /* if we are custom anamorphic, store the exact storage, par and display dims */
2060     if (fTitle->job->anamorphic.mode == 3)
2061     {
2062         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PicturePARStorageWidth"];
2063         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PicturePARStorageHeight"];
2064         
2065         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.par_width] forKey:@"PicturePARPixelWidth"];
2066         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.par_height] forKey:@"PicturePARPixelHeight"];
2067         
2068         [queueFileJob setObject:[NSNumber numberWithFloat:fTitle->job->anamorphic.dar_width] forKey:@"PicturePARDisplayWidth"];
2069         [queueFileJob setObject:[NSNumber numberWithFloat:fTitle->job->anamorphic.dar_height] forKey:@"PicturePARDisplayHeight"];
2070
2071     }
2072     NSString * pictureSummary;
2073     pictureSummary = [fPictureSizeField stringValue];
2074     [queueFileJob setObject:pictureSummary forKey:@"PictureSizingSummary"];                 
2075     /* Set crop settings here */
2076         [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController autoCrop]] forKey:@"PictureAutoCrop"];
2077     [queueFileJob setObject:[NSNumber numberWithInt:job->crop[0]] forKey:@"PictureTopCrop"];
2078     [queueFileJob setObject:[NSNumber numberWithInt:job->crop[1]] forKey:@"PictureBottomCrop"];
2079         [queueFileJob setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"];
2080         [queueFileJob setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"];
2081     
2082     /* Picture Filters */
2083     [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController detelecine]] forKey:@"PictureDetelecine"];
2084     [queueFileJob setObject:[fPictureController detelecineCustomString] forKey:@"PictureDetelecineCustom"];
2085     
2086     [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController useDecomb]] forKey:@"PictureDecombDeinterlace"];
2087     [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController decomb]] forKey:@"PictureDecomb"];
2088     [queueFileJob setObject:[fPictureController decombCustomString] forKey:@"PictureDecombCustom"];
2089     
2090     [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController deinterlace]] forKey:@"PictureDeinterlace"];
2091     [queueFileJob setObject:[fPictureController deinterlaceCustomString] forKey:@"PictureDeinterlaceCustom"];
2092     
2093     [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController denoise]] forKey:@"PictureDenoise"];
2094     [queueFileJob setObject:[fPictureController denoiseCustomString] forKey:@"PictureDenoiseCustom"];
2095     
2096     [queueFileJob setObject:[NSString stringWithFormat:@"%d",[fPictureController deblock]] forKey:@"PictureDeblock"];
2097     
2098     [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController grayscale]] forKey:@"VideoGrayScale"];
2099     
2100     /*Audio*/
2101     if ([fAudLang1PopUp indexOfSelectedItem] > 0)
2102     {
2103         [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang1PopUp indexOfSelectedItem]] forKey:@"Audio1Track"];
2104         [queueFileJob setObject:[fAudLang1PopUp titleOfSelectedItem] forKey:@"Audio1TrackDescription"];
2105         [queueFileJob setObject:[fAudTrack1CodecPopUp titleOfSelectedItem] forKey:@"Audio1Encoder"];
2106         [queueFileJob setObject:[fAudTrack1MixPopUp titleOfSelectedItem] forKey:@"Audio1Mixdown"];
2107         [queueFileJob setObject:[fAudTrack1RatePopUp titleOfSelectedItem] forKey:@"Audio1Samplerate"];
2108         [queueFileJob setObject:[fAudTrack1BitratePopUp titleOfSelectedItem] forKey:@"Audio1Bitrate"];
2109         [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack1DrcSlider floatValue]] forKey:@"Audio1TrackDRCSlider"];
2110     }
2111     if ([fAudLang2PopUp indexOfSelectedItem] > 0)
2112     {
2113         [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang2PopUp indexOfSelectedItem]] forKey:@"Audio2Track"];
2114         [queueFileJob setObject:[fAudLang2PopUp titleOfSelectedItem] forKey:@"Audio2TrackDescription"];
2115         [queueFileJob setObject:[fAudTrack2CodecPopUp titleOfSelectedItem] forKey:@"Audio2Encoder"];
2116         [queueFileJob setObject:[fAudTrack2MixPopUp titleOfSelectedItem] forKey:@"Audio2Mixdown"];
2117         [queueFileJob setObject:[fAudTrack2RatePopUp titleOfSelectedItem] forKey:@"Audio2Samplerate"];
2118         [queueFileJob setObject:[fAudTrack2BitratePopUp titleOfSelectedItem] forKey:@"Audio2Bitrate"];
2119         [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack2DrcSlider floatValue]] forKey:@"Audio2TrackDRCSlider"];
2120     }
2121     if ([fAudLang3PopUp indexOfSelectedItem] > 0)
2122     {
2123         [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang3PopUp indexOfSelectedItem]] forKey:@"Audio3Track"];
2124         [queueFileJob setObject:[fAudLang3PopUp titleOfSelectedItem] forKey:@"Audio3TrackDescription"];
2125         [queueFileJob setObject:[fAudTrack3CodecPopUp titleOfSelectedItem] forKey:@"Audio3Encoder"];
2126         [queueFileJob setObject:[fAudTrack3MixPopUp titleOfSelectedItem] forKey:@"Audio3Mixdown"];
2127         [queueFileJob setObject:[fAudTrack3RatePopUp titleOfSelectedItem] forKey:@"Audio3Samplerate"];
2128         [queueFileJob setObject:[fAudTrack3BitratePopUp titleOfSelectedItem] forKey:@"Audio3Bitrate"];
2129         [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack3DrcSlider floatValue]] forKey:@"Audio3TrackDRCSlider"];
2130     }
2131     if ([fAudLang4PopUp indexOfSelectedItem] > 0)
2132     {
2133         [queueFileJob setObject:[NSNumber numberWithInt:[fAudLang4PopUp indexOfSelectedItem]] forKey:@"Audio4Track"];
2134         [queueFileJob setObject:[fAudLang4PopUp titleOfSelectedItem] forKey:@"Audio4TrackDescription"];
2135         [queueFileJob setObject:[fAudTrack4CodecPopUp titleOfSelectedItem] forKey:@"Audio4Encoder"];
2136         [queueFileJob setObject:[fAudTrack4MixPopUp titleOfSelectedItem] forKey:@"Audio4Mixdown"];
2137         [queueFileJob setObject:[fAudTrack4RatePopUp titleOfSelectedItem] forKey:@"Audio4Samplerate"];
2138         [queueFileJob setObject:[fAudTrack4BitratePopUp titleOfSelectedItem] forKey:@"Audio4Bitrate"];
2139         [queueFileJob setObject:[NSNumber numberWithFloat:[fAudTrack4DrcSlider floatValue]] forKey:@"Audio4TrackDRCSlider"];
2140     }
2141     
2142         /* Subtitles*/
2143     NSMutableArray *subtitlesArray = [[NSMutableArray alloc] init];
2144     [queueFileJob setObject:[NSArray arrayWithArray: [fSubtitlesDelegate getSubtitleArray: subtitlesArray]] forKey:@"SubtitleList"];
2145     [subtitlesArray autorelease];
2146
2147     /* Now we go ahead and set the "job->values in the plist for passing right to fQueueEncodeLibhb */
2148      
2149     [queueFileJob setObject:[NSNumber numberWithInt:[fSrcChapterStartPopUp indexOfSelectedItem] + 1] forKey:@"JobChapterStart"];
2150     
2151     [queueFileJob setObject:[NSNumber numberWithInt:[fSrcChapterEndPopUp indexOfSelectedItem] + 1] forKey:@"JobChapterEnd"];
2152     
2153     
2154     [queueFileJob setObject:[NSNumber numberWithInt:[[fDstFormatPopUp selectedItem] tag]] forKey:@"JobFileFormatMux"];
2155     
2156     /* Codecs */
2157         /* Video encoder */
2158         [queueFileJob setObject:[NSNumber numberWithInt:[[fVidEncoderPopUp selectedItem] tag]] forKey:@"JobVideoEncoderVcodec"];
2159         
2160     /* Framerate */
2161     [queueFileJob setObject:[NSNumber numberWithInt:[fVidRatePopUp indexOfSelectedItem]] forKey:@"JobIndexVideoFramerate"];
2162     [queueFileJob setObject:[NSNumber numberWithInt:title->rate] forKey:@"JobVrate"];
2163     [queueFileJob setObject:[NSNumber numberWithInt:title->rate_base] forKey:@"JobVrateBase"];
2164         
2165     /* Picture Sizing */
2166         /* Use Max Picture settings for whatever the dvd is.*/
2167         [queueFileJob setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"];
2168         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"];
2169         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"];
2170         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"];
2171         [queueFileJob setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.mode] forKey:@"PicturePAR"];
2172     
2173     /* Set crop settings here */
2174         [queueFileJob setObject:[NSNumber numberWithInt:[fPictureController autoCrop]] forKey:@"PictureAutoCrop"];
2175     [queueFileJob setObject:[NSNumber numberWithInt:job->crop[0]] forKey:@"PictureTopCrop"];
2176     [queueFileJob setObject:[NSNumber numberWithInt:job->crop[1]] forKey:@"PictureBottomCrop"];
2177         [queueFileJob setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"];
2178         [queueFileJob setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"];
2179     
2180     
2181     /*Audio*/
2182     if ([fAudLang1PopUp indexOfSelectedItem] > 0)
2183     {
2184         //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio1Encoder"];
2185         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1CodecPopUp selectedItem] tag]] forKey:@"JobAudio1Encoder"];
2186         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1MixPopUp selectedItem] tag]] forKey:@"JobAudio1Mixdown"];
2187         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1RatePopUp selectedItem] tag]] forKey:@"JobAudio1Samplerate"];
2188         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1BitratePopUp selectedItem] tag]] forKey:@"JobAudio1Bitrate"];
2189      }
2190     if ([fAudLang2PopUp indexOfSelectedItem] > 0)
2191     {
2192         //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio2Encoder"];
2193         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2CodecPopUp selectedItem] tag]] forKey:@"JobAudio2Encoder"];
2194         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2MixPopUp selectedItem] tag]] forKey:@"JobAudio2Mixdown"];
2195         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2RatePopUp selectedItem] tag]] forKey:@"JobAudio2Samplerate"];
2196         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2BitratePopUp selectedItem] tag]] forKey:@"JobAudio2Bitrate"];
2197     }
2198     if ([fAudLang3PopUp indexOfSelectedItem] > 0)
2199     {
2200         //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio3Encoder"];
2201         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3CodecPopUp selectedItem] tag]] forKey:@"JobAudio3Encoder"];
2202         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3MixPopUp selectedItem] tag]] forKey:@"JobAudio3Mixdown"];
2203         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3RatePopUp selectedItem] tag]] forKey:@"JobAudio3Samplerate"];
2204         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3BitratePopUp selectedItem] tag]] forKey:@"JobAudio3Bitrate"];
2205     }
2206     if ([fAudLang4PopUp indexOfSelectedItem] > 0)
2207     {
2208         //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio4Encoder"];
2209         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4CodecPopUp selectedItem] tag]] forKey:@"JobAudio4Encoder"];
2210         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4MixPopUp selectedItem] tag]] forKey:@"JobAudio4Mixdown"];
2211         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4RatePopUp selectedItem] tag]] forKey:@"JobAudio4Samplerate"];
2212         [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4BitratePopUp selectedItem] tag]] forKey:@"JobAudio4Bitrate"];
2213     }
2214
2215  
2216     /* we need to auto relase the queueFileJob and return it */
2217     [queueFileJob autorelease];
2218     return queueFileJob;
2219
2220 }
2221
2222 /* this is actually called from the queue controller to modify the queue array and return it back to the queue controller */
2223 - (void)moveObjectsInQueueArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex
2224 {
2225     NSUInteger index = [indexSet lastIndex];
2226     NSUInteger aboveInsertIndexCount = 0;
2227     
2228     
2229     NSUInteger removeIndex;
2230         
2231     if (index >= insertIndex)
2232     {
2233         removeIndex = index + aboveInsertIndexCount;
2234         aboveInsertIndexCount++;
2235     }
2236     else
2237     {
2238         removeIndex = index;
2239         insertIndex--;
2240     }
2241
2242     id object = [[QueueFileArray objectAtIndex:removeIndex] retain];
2243     [QueueFileArray removeObjectAtIndex:removeIndex];
2244     [QueueFileArray insertObject:object atIndex:insertIndex];
2245     [object release];
2246         
2247     index = [indexSet indexLessThanIndex:index];
2248
2249    /* We save all of the Queue data here 
2250     * and it also gets sent back to the queue controller*/
2251     [self saveQueueFileItem]; 
2252     
2253 }
2254
2255
2256 #pragma mark -
2257 #pragma mark Queue Job Processing
2258
2259 - (void) incrementQueueItemDone:(int) queueItemDoneIndexNum
2260 {
2261     int i = currentQueueEncodeIndex;
2262     [[QueueFileArray objectAtIndex:i] setObject:[NSNumber numberWithInt:0] forKey:@"Status"];
2263         
2264     /* We save all of the Queue data here */
2265     [self saveQueueFileItem];
2266         /* We Reload the New Table data for presets */
2267     //[fPresetsOutlineView reloadData];
2268
2269     /* Since we have now marked a queue item as done
2270      * we can go ahead and increment currentQueueEncodeIndex 
2271      * so that if there is anything left in the queue we can
2272      * go ahead and move to the next item if we want to */
2273     currentQueueEncodeIndex++ ;
2274     [self writeToActivityLog: "incrementQueueItemDone currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex];
2275     int queueItems = [QueueFileArray count];
2276     /* If we still have more items in our queue, lets go to the next one */
2277     if (currentQueueEncodeIndex < queueItems)
2278     {
2279     [self writeToActivityLog: "incrementQueueItemDone currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex];
2280     [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]];
2281     }
2282     else
2283     {
2284         [self writeToActivityLog: "incrementQueueItemDone the %d item queue is complete", currentQueueEncodeIndex - 1];
2285     }
2286 }
2287
2288 /* Here we actually tell hb_scan to perform the source scan, using the path to source and title number*/
2289 - (void) performNewQueueScan:(NSString *) scanPath scanTitleNum: (int) scanTitleNum
2290 {
2291    /* Tell HB to output a new activity log file for this encode */
2292     [outputPanel startEncodeLog:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"]];
2293     
2294     
2295      /* use a bool to determine whether or not we can decrypt using vlc */
2296     BOOL cancelScanDecrypt = 0;
2297     /* set the bool so that showNewScan knows to apply the appropriate queue
2298     * settings as this is a queue rescan
2299     */
2300     applyQueueToScan = YES;
2301     NSString *path = scanPath;
2302     HBDVDDetector *detector = [HBDVDDetector detectorForPath:path];
2303
2304         /*On Screen Notification*/
2305         //int status;
2306         //status = NSRunAlertPanel(@"HandBrake is now loading up a new queue item...",@"Would You Like to wait until you add another encode?", @"Cancel", @"Okay", nil);
2307         //[NSApp requestUserAttention:NSCriticalRequest];
2308
2309     if( [detector isVideoDVD] )
2310     {
2311         // The chosen path was actually on a DVD, so use the raw block
2312         // device path instead.
2313         path = [detector devicePath];
2314         [self writeToActivityLog: "trying to open a physical dvd at: %s", [scanPath UTF8String]];
2315
2316         /* lets check for vlc here to make sure we have a dylib available to use for decrypting */
2317         NSString *vlcPath = @"/Applications/VLC.app";
2318         NSFileManager * fileManager = [NSFileManager defaultManager];
2319             if ([fileManager fileExistsAtPath:vlcPath] == 0) 
2320             {
2321             /*vlc not found in /Applications so we set the bool to cancel scanning to 1 */
2322             cancelScanDecrypt = 1;
2323             [self writeToActivityLog: "VLC app not found for decrypting physical dvd"];
2324             int status;
2325             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");
2326             [NSApp requestUserAttention:NSCriticalRequest];
2327             
2328             if (status == NSAlertDefaultReturn)
2329             {
2330                 /* User chose to go download vlc (as they rightfully should) so we send them to the vlc site */
2331                 [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.videolan.org/"]];
2332             }
2333             else if (status == NSAlertAlternateReturn)
2334             {
2335             /* User chose to cancel the scan */
2336             [self writeToActivityLog: "cannot open physical dvd , scan cancelled"];
2337             }
2338             else
2339             {
2340             /* 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 */
2341             cancelScanDecrypt = 0;
2342             [self writeToActivityLog: "user overrode vlc warning -trying to open physical dvd without decryption"];
2343             }
2344
2345         }
2346         else
2347         {
2348             /* VLC was found in /Applications so all is well, we can carry on using vlc's libdvdcss.dylib for decrypting if needed */
2349             [self writeToActivityLog: "VLC app found for decrypting physical dvd"];
2350         }
2351     }
2352
2353     if (cancelScanDecrypt == 0)
2354     {
2355         /* we actually pass the scan off to libhb here */
2356         /* If there is no title number passed to scan, we use "0"
2357          * which causes the default behavior of a full source scan
2358          */
2359         if (!scanTitleNum)
2360         {
2361             scanTitleNum = 0;
2362         }
2363         if (scanTitleNum > 0)
2364         {
2365             [self writeToActivityLog: "scanning specifically for title: %d", scanTitleNum];
2366         }
2367         
2368         [self writeToActivityLog: "performNewQueueScan currentQueueEncodeIndex is: %d", currentQueueEncodeIndex];
2369         /* We use our advance pref to determine how many previews to scan */
2370         int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue];
2371         hb_scan( fQueueEncodeLibhb, [path UTF8String], scanTitleNum, hb_num_previews, 0 );
2372     }
2373 }
2374
2375 /* This method was originally used to load up a new queue item in the gui and
2376  * then start processing it. However we now have modified -prepareJob and use a second
2377  * instance of libhb to do our actual encoding, therefor right now it is not required. 
2378  * Nonetheless I want to leave this in here
2379  * because basically its everything we need to be able to actually modify a pending queue
2380  * item in the gui and resave it. At least for now - dynaflash
2381  */
2382
2383 - (IBAction)applyQueueSettings:(id)sender
2384 {
2385     NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex];
2386     hb_job_t * job = fTitle->job;
2387     
2388     /* Set title number and chapters */
2389     /* since the queue only scans a single title, we really don't need to pick a title */
2390     //[fSrcTitlePopUp selectItemAtIndex: [[queueToApply objectForKey:@"TitleNumber"] intValue] - 1];
2391     
2392     [fSrcChapterStartPopUp selectItemAtIndex: [[queueToApply objectForKey:@"ChapterStart"] intValue] - 1];
2393     [fSrcChapterEndPopUp selectItemAtIndex: [[queueToApply objectForKey:@"ChapterEnd"] intValue] - 1];
2394     
2395     /* File Format */
2396     [fDstFormatPopUp selectItemWithTitle:[queueToApply objectForKey:@"FileFormat"]];
2397     [self formatPopUpChanged:nil];
2398     
2399     /* Chapter Markers*/
2400     [fCreateChapterMarkers setState:[[queueToApply objectForKey:@"ChapterMarkers"] intValue]];
2401     /* Allow Mpeg4 64 bit formatting +4GB file sizes */
2402     [fDstMp4LargeFileCheck setState:[[queueToApply objectForKey:@"Mp4LargeFile"] intValue]];
2403     /* Mux mp4 with http optimization */
2404     [fDstMp4HttpOptFileCheck setState:[[queueToApply objectForKey:@"Mp4HttpOptimize"] intValue]];
2405     
2406     /* Video encoder */
2407     /* We set the advanced opt string here if applicable*/
2408     [fVidEncoderPopUp selectItemWithTitle:[queueToApply objectForKey:@"VideoEncoder"]];
2409     [fAdvancedOptions setOptions:[queueToApply objectForKey:@"x264Option"]];
2410     
2411     /* Lets run through the following functions to get variables set there */
2412     [self videoEncoderPopUpChanged:nil];
2413     /* Set the state of ipod compatible with Mp4iPodCompatible. Only for x264*/
2414     [fDstMp4iPodFileCheck setState:[[queueToApply objectForKey:@"Mp4iPodCompatible"] intValue]];
2415     [self calculateBitrate:nil];
2416     
2417     /* Video quality */
2418     [fVidQualityMatrix selectCellAtRow:[[queueToApply objectForKey:@"VideoQualityType"] intValue] column:0];
2419     
2420     [fVidTargetSizeField setStringValue:[queueToApply objectForKey:@"VideoTargetSize"]];
2421     [fVidBitrateField setStringValue:[queueToApply objectForKey:@"VideoAvgBitrate"]];
2422     [fVidQualitySlider setFloatValue:[[queueToApply objectForKey:@"VideoQualitySlider"] floatValue]];
2423     
2424     [self videoMatrixChanged:nil];
2425     
2426     /* Video framerate */
2427     /* For video preset video framerate, we want to make sure that Same as source does not conflict with the
2428      detected framerate in the fVidRatePopUp so we use index 0*/
2429     if ([[queueToApply objectForKey:@"VideoFramerate"] isEqualToString:@"Same as source"])
2430     {
2431         [fVidRatePopUp selectItemAtIndex: 0];
2432     }
2433     else
2434     {
2435         [fVidRatePopUp selectItemWithTitle:[queueToApply objectForKey:@"VideoFramerate"]];
2436     }
2437     
2438     /* 2 Pass Encoding */
2439     [fVidTwoPassCheck setState:[[queueToApply objectForKey:@"VideoTwoPass"] intValue]];
2440     [self twoPassCheckboxChanged:nil];
2441     /* Turbo 1st pass for 2 Pass Encoding */
2442     [fVidTurboPassCheck setState:[[queueToApply objectForKey:@"VideoTurboTwoPass"] intValue]];
2443     
2444     /*Audio*/
2445     if ([queueToApply objectForKey:@"Audio1Track"] > 0)
2446     {
2447         if ([fAudLang1PopUp indexOfSelectedItem] == 0)
2448         {
2449             [fAudLang1PopUp selectItemAtIndex: 1];
2450         }
2451         [self audioTrackPopUpChanged: fAudLang1PopUp];
2452         [fAudTrack1CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio1Encoder"]];
2453         [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
2454         [fAudTrack1MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio1Mixdown"]];
2455         /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
2456          * mixdown*/
2457         if  ([fAudTrack1MixPopUp selectedItem] == nil)
2458         {
2459             [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
2460         }
2461         [fAudTrack1RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Samplerate"]];
2462         /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
2463         if (![[queueToApply objectForKey:@"Audio1Encoder"] isEqualToString:@"AC3 Passthru"])
2464         {
2465             [fAudTrack1BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio1Bitrate"]];
2466         }
2467         [fAudTrack1DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio1TrackDRCSlider"] floatValue]];
2468         [self audioDRCSliderChanged: fAudTrack1DrcSlider];
2469     }
2470     if ([queueToApply objectForKey:@"Audio2Track"] > 0)
2471     {
2472         if ([fAudLang2PopUp indexOfSelectedItem] == 0)
2473         {
2474             [fAudLang2PopUp selectItemAtIndex: 1];
2475         }
2476         [self audioTrackPopUpChanged: fAudLang2PopUp];
2477         [fAudTrack2CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Encoder"]];
2478         [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
2479         [fAudTrack2MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Mixdown"]];
2480         /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
2481          * mixdown*/
2482         if  ([fAudTrack2MixPopUp selectedItem] == nil)
2483         {
2484             [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
2485         }
2486         [fAudTrack2RatePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Samplerate"]];
2487         /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
2488         if (![[queueToApply objectForKey:@"Audio2Encoder"] isEqualToString:@"AC3 Passthru"])
2489         {
2490             [fAudTrack2BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio2Bitrate"]];
2491         }
2492         [fAudTrack2DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio2TrackDRCSlider"] floatValue]];
2493         [self audioDRCSliderChanged: fAudTrack2DrcSlider];
2494     }
2495     if ([queueToApply objectForKey:@"Audio3Track"] > 0)
2496     {
2497         if ([fAudLang3PopUp indexOfSelectedItem] == 0)
2498         {
2499             [fAudLang3PopUp selectItemAtIndex: 1];
2500         }
2501         [self audioTrackPopUpChanged: fAudLang3PopUp];
2502         [fAudTrack3CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Encoder"]];
2503         [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
2504         [fAudTrack3MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Mixdown"]];
2505         /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
2506          * mixdown*/
2507         if  ([fAudTrack3MixPopUp selectedItem] == nil)
2508         {
2509             [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
2510         }
2511         [fAudTrack3RatePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Samplerate"]];
2512         /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
2513         if (![[queueToApply objectForKey:@"Audio3Encoder"] isEqualToString: @"AC3 Passthru"])
2514         {
2515             [fAudTrack3BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio3Bitrate"]];
2516         }
2517         [fAudTrack3DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio3TrackDRCSlider"] floatValue]];
2518         [self audioDRCSliderChanged: fAudTrack3DrcSlider];
2519     }
2520     if ([queueToApply objectForKey:@"Audio4Track"] > 0)
2521     {
2522         if ([fAudLang4PopUp indexOfSelectedItem] == 0)
2523         {
2524             [fAudLang4PopUp selectItemAtIndex: 1];
2525         }
2526         [self audioTrackPopUpChanged: fAudLang4PopUp];
2527         [fAudTrack4CodecPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Encoder"]];
2528         [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
2529         [fAudTrack4MixPopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Mixdown"]];
2530         /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
2531          * mixdown*/
2532         if  ([fAudTrack4MixPopUp selectedItem] == nil)
2533         {
2534             [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
2535         }
2536         [fAudTrack4RatePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Samplerate"]];
2537         /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
2538         if (![[chosenPreset objectForKey:@"Audio4Encoder"] isEqualToString:@"AC3 Passthru"])
2539         {
2540             [fAudTrack4BitratePopUp selectItemWithTitle:[queueToApply objectForKey:@"Audio4Bitrate"]];
2541         }
2542         [fAudTrack4DrcSlider setFloatValue:[[queueToApply objectForKey:@"Audio4TrackDRCSlider"] floatValue]];
2543         [self audioDRCSliderChanged: fAudTrack4DrcSlider];
2544     }
2545     
2546     
2547     /*Subtitles*/
2548     [fSubPopUp selectItemWithTitle:[queueToApply objectForKey:@"Subtitles"]];
2549     /* Forced Subtitles */
2550     [fSubForcedCheck setState:[[queueToApply objectForKey:@"SubtitlesForced"] intValue]];
2551     
2552     /* Picture Settings */
2553     /* we check to make sure the presets width/height does not exceed the sources width/height */
2554     if (fTitle->width < [[queueToApply objectForKey:@"PictureWidth"]  intValue] || fTitle->height < [[queueToApply objectForKey:@"PictureHeight"]  intValue])
2555     {
2556         /* if so, then we use the sources height and width to avoid scaling up */
2557         job->width = fTitle->width;
2558         job->height = fTitle->height;
2559     }
2560     else // source width/height is >= the preset height/width
2561     {
2562         /* we can go ahead and use the presets values for height and width */
2563         job->width = [[queueToApply objectForKey:@"PictureWidth"]  intValue];
2564         job->height = [[queueToApply objectForKey:@"PictureHeight"]  intValue];
2565     }
2566     job->keep_ratio = [[queueToApply objectForKey:@"PictureKeepRatio"]  intValue];
2567     if (job->keep_ratio == 1)
2568     {
2569         hb_fix_aspect( job, HB_KEEP_WIDTH );
2570         if( job->height > fTitle->height )
2571         {
2572             job->height = fTitle->height;
2573             hb_fix_aspect( job, HB_KEEP_HEIGHT );
2574         }
2575     }
2576     job->anamorphic.mode = [[queueToApply objectForKey:@"PicturePAR"]  intValue];
2577     
2578     
2579     /* If Cropping is set to custom, then recall all four crop values from
2580      when the preset was created and apply them */
2581     if ([[queueToApply objectForKey:@"PictureAutoCrop"]  intValue] == 0)
2582     {
2583         [fPictureController setAutoCrop:NO];
2584         
2585         /* Here we use the custom crop values saved at the time the preset was saved */
2586         job->crop[0] = [[queueToApply objectForKey:@"PictureTopCrop"]  intValue];
2587         job->crop[1] = [[queueToApply objectForKey:@"PictureBottomCrop"]  intValue];
2588         job->crop[2] = [[queueToApply objectForKey:@"PictureLeftCrop"]  intValue];
2589         job->crop[3] = [[queueToApply objectForKey:@"PictureRightCrop"]  intValue];
2590         
2591     }
2592     else /* if auto crop has been saved in preset, set to auto and use post scan auto crop */
2593     {
2594         [fPictureController setAutoCrop:YES];
2595         /* Here we use the auto crop values determined right after scan */
2596         job->crop[0] = AutoCropTop;
2597         job->crop[1] = AutoCropBottom;
2598         job->crop[2] = AutoCropLeft;
2599         job->crop[3] = AutoCropRight;
2600         
2601     }
2602     
2603     /* Filters */
2604     /* Deinterlace */
2605     [fPictureController setDeinterlace:[[queueToApply objectForKey:@"PictureDeinterlace"] intValue]];
2606     
2607     /* Detelecine */
2608     [fPictureController setDetelecine:[[queueToApply objectForKey:@"PictureDetelecine"] intValue]];
2609     /* Denoise */
2610     [fPictureController setDenoise:[[queueToApply objectForKey:@"PictureDenoise"] intValue]];
2611     /* Deblock */
2612     [fPictureController setDeblock:[[queueToApply objectForKey:@"PictureDeblock"] intValue]];
2613     /* Decomb */
2614     [fPictureController setDecomb:[[queueToApply objectForKey:@"PictureDecomb"] intValue]];
2615     /* Grayscale */
2616     [fPictureController setGrayscale:[[queueToApply objectForKey:@"VideoGrayScale"] intValue]];
2617     
2618     [self calculatePictureSizing:nil];
2619     
2620     
2621     /* somehow we need to figure out a way to tie the queue item to a preset if it used one */
2622     //[queueFileJob setObject:[fPresetSelectedDisplay stringValue] forKey:@"PresetName"];
2623     //    [queueFileJob setObject:[NSNumber numberWithInt:[fPresetsOutlineView selectedRow]] forKey:@"PresetIndexNum"];
2624     if ([queueToApply objectForKey:@"PresetIndexNum"]) // This item used a preset so insert that info
2625         {
2626                 /* Deselect the currently selected Preset if there is one*/
2627         //[fPresetsOutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:[[queueToApply objectForKey:@"PresetIndexNum"] intValue]] byExtendingSelection:NO];
2628         //[self selectPreset:nil];
2629                 
2630         //[fPresetsOutlineView selectRow:[[queueToApply objectForKey:@"PresetIndexNum"] intValue]];
2631                 /* Change UI to show "Custom" settings are being used */
2632                 //[fPresetSelectedDisplay setStringValue: [[queueToApply objectForKey:@"PresetName"] stringValue]];
2633         
2634                 curUserPresetChosenNum = nil;
2635         }
2636     else
2637     {
2638         /* Deselect the currently selected Preset if there is one*/
2639                 [fPresetsOutlineView deselectRow:[fPresetsOutlineView selectedRow]];
2640                 /* Change UI to show "Custom" settings are being used */
2641                 [fPresetSelectedDisplay setStringValue: @"Custom"];
2642         
2643                 //curUserPresetChosenNum = nil;
2644     }
2645     
2646     /* We need to set this bool back to NO, in case the user wants to do a scan */
2647     //applyQueueToScan = NO;
2648     
2649     /* so now we go ahead and process the new settings */
2650     [self processNewQueueEncode];
2651 }
2652
2653
2654
2655 /* This assumes that we have re-scanned and loaded up a new queue item to send to libhb as fQueueEncodeLibhb */
2656 - (void) processNewQueueEncode
2657 {
2658     hb_list_t  * list  = hb_get_titles( fQueueEncodeLibhb );
2659     hb_title_t * title = (hb_title_t *) hb_list_item( list,0 ); // is always zero since now its a single title scan
2660     hb_job_t * job = title->job;
2661     
2662     if( !hb_list_count( list ) )
2663     {
2664         [self writeToActivityLog: "processNewQueueEncode WARNING nothing found in the title list"];
2665     }
2666     
2667     NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex];
2668     [self writeToActivityLog: "Preset: %s", [[queueToApply objectForKey:@"PresetName"] UTF8String]];
2669     [self writeToActivityLog: "processNewQueueEncode number of passes expected is: %d", ([[queueToApply objectForKey:@"VideoTwoPass"] intValue] + 1)];
2670     job->file = [[queueToApply objectForKey:@"DestinationPath"] UTF8String];
2671     //[self writeToActivityLog: "processNewQueueEncode sending to prepareJob"];
2672     [self prepareJob];
2673     
2674     /*
2675      * If scanning we need to do some extra setup of the job.
2676      */
2677     if( job->indepth_scan == 1 )
2678     {
2679         char *x264opts_tmp;
2680         
2681         /*
2682          * When subtitle scan is enabled do a fast pre-scan job
2683          * which will determine which subtitles to enable, if any.
2684          */
2685         job->pass = -1;
2686         x264opts_tmp = job->x264opts;
2687         
2688         job->x264opts = NULL;
2689         
2690         job->indepth_scan = 1;  
2691
2692         
2693         /*
2694          * Add the pre-scan job
2695          */
2696         hb_add( fQueueEncodeLibhb, job );
2697         job->x264opts = x264opts_tmp;
2698     }
2699
2700     
2701     if( [[queueToApply objectForKey:@"VideoTwoPass"] intValue] == 1 )
2702     {
2703         job->indepth_scan = 0;
2704         
2705
2706         
2707         job->pass = 1;
2708         
2709         hb_add( fQueueEncodeLibhb, job );
2710         
2711         job->pass = 2;
2712         
2713         job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */  
2714         strcpy(job->x264opts, [[queueToApply objectForKey:@"x264Option"] UTF8String]);
2715         
2716         hb_add( fQueueEncodeLibhb, job );
2717         
2718     }
2719     else
2720     {
2721         job->indepth_scan = 0;
2722         job->pass = 0;
2723         
2724         hb_add( fQueueEncodeLibhb, job );
2725     }
2726         
2727     NSString *destinationDirectory = [[queueToApply objectForKey:@"DestinationPath"] stringByDeletingLastPathComponent];
2728         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
2729         /* Lets mark our new encode as 1 or "Encoding" */
2730     [queueToApply setObject:[NSNumber numberWithInt:1] forKey:@"Status"];
2731     [self saveQueueFileItem];
2732     
2733     /* we need to clean up the subtitle tracks after the job(s) have been set  */
2734     int num_subtitle_tracks = hb_list_count(job->list_subtitle);
2735     int ii;
2736     for(ii = 0; ii < num_subtitle_tracks; ii++)
2737     {
2738         hb_subtitle_t * subtitle;
2739         subtitle = (hb_subtitle_t *)hb_list_item(job->list_subtitle, 0);
2740         
2741
2742         hb_list_rem(job->list_subtitle, subtitle);
2743         free(subtitle);
2744     }
2745     
2746     
2747     /* We should be all setup so let 'er rip */   
2748     [self doRip];
2749 }
2750
2751 #pragma mark -
2752 #pragma mark Live Preview
2753 /* Note,this is much like prepareJob, but directly sets the job vars so Picture Preview
2754  * can encode to its temp preview directory and playback. This is *not* used for any actual user
2755  * encodes
2756  */
2757 - (void) prepareJobForPreview
2758 {
2759     hb_list_t  * list  = hb_get_titles( fHandle );
2760     hb_title_t * title = (hb_title_t *) hb_list_item( list,
2761             [fSrcTitlePopUp indexOfSelectedItem] );
2762     hb_job_t * job = title->job;
2763     hb_audio_config_t * audio;
2764     /* set job->angle for libdvdnav */
2765     job->angle = [fSrcAnglePopUp indexOfSelectedItem] + 1;
2766     /* Chapter selection */
2767     job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1;
2768     job->chapter_end   = [fSrcChapterEndPopUp   indexOfSelectedItem] + 1;
2769         
2770     /* Format (Muxer) and Video Encoder */
2771     job->mux = [[fDstFormatPopUp selectedItem] tag];
2772     job->vcodec = [[fVidEncoderPopUp selectedItem] tag];
2773
2774     job->chapter_markers = 0;
2775     
2776         if( job->vcodec & HB_VCODEC_X264 )
2777     {
2778                 /* Set this flag to switch from Constant Quantizer(default) to Constant Rate Factor Thanks jbrjake
2779          Currently only used with Constant Quality setting*/
2780                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0 && [fVidQualityMatrix selectedRow] == 2)
2781                 {
2782                 job->crf = 1;
2783                 }
2784                 
2785                 /* Below Sends x264 options to the core library if x264 is selected*/
2786                 /* Lets use this as per Nyx, Thanks Nyx!*/
2787                 job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */
2788                 /* For previews we ignore the turbo option for the first pass of two since we only use 1 pass */
2789                 strcpy(job->x264opts, [[fAdvancedOptions optionsString] UTF8String]);
2790
2791         
2792     }
2793
2794     /* Video settings */
2795    /* Set vfr to 0 as it's only on if using same as source in the framerate popup
2796      * and detelecine is on, so we handle that in the logic below
2797      */
2798     job->vfr = 0;
2799     if( [fVidRatePopUp indexOfSelectedItem] > 0 )
2800     {
2801         /* a specific framerate has been chosen */
2802         job->vrate      = 27000000;
2803         job->vrate_base = hb_video_rates[[fVidRatePopUp indexOfSelectedItem]-1].rate;
2804         /* We are not same as source so we set job->cfr to 1 
2805          * to enable constant frame rate since user has specified
2806          * a specific framerate*/
2807         job->cfr = 1;
2808     }
2809     else
2810     {
2811         /* We are same as source (variable) */
2812         job->vrate      = title->rate;
2813         job->vrate_base = title->rate_base;
2814         /* We are same as source so we set job->cfr to 0 
2815          * to enable true same as source framerate */
2816         job->cfr = 0;
2817         /* If we are same as source and we have detelecine on, we need to turn on
2818          * job->vfr
2819          */
2820         if ([fPictureController detelecine] == 1)
2821         {
2822             job->vfr = 1;
2823         }
2824     }
2825
2826     switch( [fVidQualityMatrix selectedRow] )
2827     {
2828         case 0:
2829             /* Target size.
2830                Bitrate should already have been calculated and displayed
2831                in fVidBitrateField, so let's just use it */
2832         case 1:
2833             job->vquality = -1.0;
2834             job->vbitrate = [fVidBitrateField intValue];
2835             break;
2836         case 2:
2837             job->vquality = [fVidQualityRFField floatValue];
2838             job->vbitrate = 0;
2839             break;
2840     }
2841
2842     /* Subtitle settings */
2843     NSMutableArray *subtitlesArray = nil;
2844     subtitlesArray = [[NSMutableArray alloc] initWithArray:[fSubtitlesDelegate getSubtitleArray: subtitlesArray]];
2845     
2846     
2847     
2848  int subtitle = nil;
2849 int force;
2850 int burned;
2851 int def;
2852 bool one_burned = FALSE;
2853
2854     int i = 0;
2855     NSEnumerator *enumerator = [subtitlesArray objectEnumerator];
2856     id tempObject;
2857     while (tempObject = [enumerator nextObject])
2858     {
2859         
2860         subtitle = [[tempObject objectForKey:@"subtitleSourceTrackNum"] intValue];
2861         force = [[tempObject objectForKey:@"subtitleTrackForced"] intValue];
2862         burned = [[tempObject objectForKey:@"subtitleTrackBurned"] intValue];
2863         def = [[tempObject objectForKey:@"subtitleTrackDefault"] intValue];
2864         
2865         /* since the subtitleSourceTrackNum 0 is "None" in our array of the subtitle popups,
2866          * we want to ignore it for display as well as encoding.
2867          */
2868         if (subtitle > 0)
2869         {
2870             /* if i is 0, then we are in the first item of the subtitles which we need to 
2871              * check for the "Foreign Audio Search" which would be subtitleSourceTrackNum of 1
2872              * bearing in mind that for all tracks subtitleSourceTrackNum of 0 is None.
2873              */
2874             
2875             /* if we are on the first track and using "Foreign Audio Search" */ 
2876             if (i == 0 && subtitle == 1)
2877             {
2878                 /* NOTE: Currently foreign language search is borked for preview.
2879                  * Commented out but left in for initial commit. */
2880                 
2881                 
2882                 [self writeToActivityLog: "Foreign Language Search: %d", 1];
2883                 
2884                 job->indepth_scan = 1;
2885                 if (burned == 1 || job->mux != HB_MUX_MP4)
2886                 {
2887                     if (burned != 1 && job->mux == HB_MUX_MKV)
2888                     {
2889                         job->select_subtitle_config.dest = hb_subtitle_config_s::PASSTHRUSUB;
2890                     }
2891                     else
2892                     {
2893                         job->select_subtitle_config.dest = hb_subtitle_config_s::RENDERSUB;
2894                     }
2895                     
2896                     job->select_subtitle_config.force = force;
2897                     job->select_subtitle_config.default_track = def;
2898                     
2899                 }
2900                 
2901                 
2902             }
2903             else
2904             {
2905                 
2906                 /* for the actual source tracks, we must subtract the non source entries so 
2907                  * that the menu index matches the source subtitle_list index for convenience */
2908                 if (i == 0)
2909                 {
2910                     /* for the first track, the source tracks start at menu index 2 ( None is 0,
2911                      * Foreign Language Search is 1) so subtract 2 */
2912                     subtitle = subtitle - 2;
2913                 }
2914                 else
2915                 {
2916                     /* for all other tracks, the source tracks start at menu index 1 (None is 0)
2917                      * so subtract 1. */
2918                     
2919                     subtitle = subtitle - 1;
2920                 }
2921                 
2922                 /* We are setting a source subtitle so access the source subtitle info */  
2923                 hb_subtitle_t * subt;
2924                 
2925                 subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle);
2926                 
2927                 /* if we are getting the subtitles from an external srt file */
2928                 if ([[tempObject objectForKey:@"subtitleSourceTrackType"] isEqualToString:@"SRT"])
2929                 {
2930                     hb_subtitle_config_t sub_config;
2931                     
2932                     sub_config.offset = [[tempObject objectForKey:@"subtitleTrackSrtOffset"] intValue];
2933                     
2934                     /* we need to srncpy file path and char code */
2935                     strncpy(sub_config.src_filename, [[tempObject objectForKey:@"subtitleSourceSrtFilePath"] UTF8String], 128);
2936                     strncpy(sub_config.src_codeset, [[tempObject objectForKey:@"subtitleTrackSrtCharCode"] UTF8String], 40);
2937                     
2938                     sub_config.force = 0;
2939                     sub_config.dest = hb_subtitle_config_s::PASSTHRUSUB;
2940                     sub_config.default_track = def;
2941                     
2942                     hb_srt_add( job, &sub_config, [[tempObject objectForKey:@"subtitleTrackSrtLanguageIso3"] UTF8String]);
2943                 }
2944                 
2945                 if (subt != NULL)
2946                 {
2947                     [self writeToActivityLog: "Setting Subtitle: %s", subt];
2948
2949                     hb_subtitle_config_t sub_config = subt->config;
2950                     
2951                     if (!burned && job->mux == HB_MUX_MKV && 
2952                         subt->format == hb_subtitle_s::PICTURESUB)
2953                     {
2954                         sub_config.dest = hb_subtitle_config_s::PASSTHRUSUB;
2955                     }
2956                     else if (!burned && job->mux == HB_MUX_MP4 && 
2957                              subt->format == hb_subtitle_s::PICTURESUB)
2958                     {
2959                         // Skip any non-burned vobsubs when output is mp4
2960                         continue;
2961                     }
2962                     else if ( burned && subt->format == hb_subtitle_s::PICTURESUB )
2963                     {
2964                         // Only allow one subtitle to be burned into the video
2965                         if (one_burned)
2966                             continue;
2967                         one_burned = TRUE;
2968                     }
2969                     sub_config.force = force;
2970                     sub_config.default_track = def;
2971                     hb_subtitle_add( job, &sub_config, subtitle );
2972                 }   
2973                 
2974             }
2975         }
2976         i++;
2977     }
2978    
2979     
2980     
2981 [subtitlesArray autorelease];    
2982     
2983     
2984     /* Audio tracks and mixdowns */
2985     /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty*/
2986     int audiotrack_count = hb_list_count(job->list_audio);
2987     for( int i = 0; i < audiotrack_count;i++)
2988     {
2989         hb_audio_t * temp_audio = (hb_audio_t*) hb_list_item( job->list_audio, 0 );
2990         hb_list_rem(job->list_audio, temp_audio);
2991     }
2992     /* Now lets add our new tracks to the audio list here */
2993     if ([fAudLang1PopUp indexOfSelectedItem] > 0)
2994     {
2995         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
2996         hb_audio_config_init(audio);
2997         audio->in.track = [fAudLang1PopUp indexOfSelectedItem] - 1;
2998         /* We go ahead and assign values to our audio->out.<properties> */
2999         audio->out.track = [fAudLang1PopUp indexOfSelectedItem] - 1;
3000         audio->out.codec = [[fAudTrack1CodecPopUp selectedItem] tag];
3001         audio->out.mixdown = [[fAudTrack1MixPopUp selectedItem] tag];
3002         audio->out.bitrate = [[fAudTrack1BitratePopUp selectedItem] tag];
3003         audio->out.samplerate = [[fAudTrack1RatePopUp selectedItem] tag];
3004         audio->out.dynamic_range_compression = [fAudTrack1DrcField floatValue];
3005         
3006         hb_audio_add( job, audio );
3007         free(audio);
3008     }  
3009     if ([fAudLang2PopUp indexOfSelectedItem] > 0)
3010     {
3011         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
3012         hb_audio_config_init(audio);
3013         audio->in.track = [fAudLang2PopUp indexOfSelectedItem] - 1;
3014         /* We go ahead and assign values to our audio->out.<properties> */
3015         audio->out.track = [fAudLang2PopUp indexOfSelectedItem] - 1;
3016         audio->out.codec = [[fAudTrack2CodecPopUp selectedItem] tag];
3017         audio->out.mixdown = [[fAudTrack2MixPopUp selectedItem] tag];
3018         audio->out.bitrate = [[fAudTrack2BitratePopUp selectedItem] tag];
3019         audio->out.samplerate = [[fAudTrack2RatePopUp selectedItem] tag];
3020         audio->out.dynamic_range_compression = [fAudTrack2DrcField floatValue];
3021         
3022         hb_audio_add( job, audio );
3023         free(audio);
3024         
3025     }
3026     
3027     if ([fAudLang3PopUp indexOfSelectedItem] > 0)
3028     {
3029         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
3030         hb_audio_config_init(audio);
3031         audio->in.track = [fAudLang3PopUp indexOfSelectedItem] - 1;
3032         /* We go ahead and assign values to our audio->out.<properties> */
3033         audio->out.track = [fAudLang3PopUp indexOfSelectedItem] - 1;
3034         audio->out.codec = [[fAudTrack3CodecPopUp selectedItem] tag];
3035         audio->out.mixdown = [[fAudTrack3MixPopUp selectedItem] tag];
3036         audio->out.bitrate = [[fAudTrack3BitratePopUp selectedItem] tag];
3037         audio->out.samplerate = [[fAudTrack3RatePopUp selectedItem] tag];
3038         audio->out.dynamic_range_compression = [fAudTrack3DrcField floatValue];
3039         
3040         hb_audio_add( job, audio );
3041         free(audio);
3042         
3043     }
3044
3045     if ([fAudLang4PopUp indexOfSelectedItem] > 0)
3046     {
3047         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
3048         hb_audio_config_init(audio);
3049         audio->in.track = [fAudLang4PopUp indexOfSelectedItem] - 1;
3050         /* We go ahead and assign values to our audio->out.<properties> */
3051         audio->out.track = [fAudLang4PopUp indexOfSelectedItem] - 1;
3052         audio->out.codec = [[fAudTrack4CodecPopUp selectedItem] tag];
3053         audio->out.mixdown = [[fAudTrack4MixPopUp selectedItem] tag];
3054         audio->out.bitrate = [[fAudTrack4BitratePopUp selectedItem] tag];
3055         audio->out.samplerate = [[fAudTrack4RatePopUp selectedItem] tag];
3056         audio->out.dynamic_range_compression = [fAudTrack4DrcField floatValue];
3057         
3058         hb_audio_add( job, audio );
3059         free(audio);
3060         
3061     }
3062
3063     
3064     
3065     /* Filters */
3066     
3067     /* Though Grayscale is not really a filter, per se
3068      * we put it here since its in the filters panel
3069      */
3070      
3071     if ([fPictureController grayscale])
3072     {
3073         job->grayscale = 1;
3074     }
3075     else
3076     {
3077         job->grayscale = 0;
3078     }
3079     
3080     /* Initialize the filters list */
3081     job->filters = hb_list_init();
3082     
3083     /* Now lets call the filters if applicable.
3084     * The order of the filters is critical
3085     */
3086     
3087         /* Detelecine */
3088     if ([fPictureController detelecine] == 1)
3089     {
3090         hb_list_add( job->filters, &hb_filter_detelecine );
3091     }
3092     if ([fPictureController detelecine] == 2)
3093     {
3094         /* use a custom detelecine string */
3095         hb_filter_detelecine.settings = (char *) [[fPictureController detelecineCustomString] UTF8String];
3096         hb_list_add( job->filters, &hb_filter_detelecine );
3097     }
3098     if ([fPictureController useDecomb] == 1)
3099     {
3100         /* Decomb */
3101         if ([fPictureController decomb] == 1)
3102         {
3103             /* Run old deinterlacer fd by default */
3104             //hb_filter_decomb.settings = (char *) [[fPicSettingDecomb stringValue] UTF8String];
3105             hb_list_add( job->filters, &hb_filter_decomb );
3106         }
3107         /* we add the custom string if present */
3108         if ([fPictureController decomb] == 2)
3109         {
3110             /* use a custom decomb string */
3111             hb_filter_decomb.settings = (char *) [[fPictureController decombCustomString] UTF8String];
3112             hb_list_add( job->filters, &hb_filter_decomb );
3113         }
3114     }
3115     else
3116     {
3117         
3118         /* Deinterlace */
3119         if ([fPictureController deinterlace] == 1)
3120         {
3121             /* Run old deinterlacer fd by default */
3122             hb_filter_deinterlace.settings = "-1"; 
3123             hb_list_add( job->filters, &hb_filter_deinterlace );
3124         }
3125         else if ([fPictureController deinterlace] == 2)
3126         {
3127             /* Yadif mode 0 (without spatial deinterlacing.) */
3128             hb_filter_deinterlace.settings = "2"; 
3129             hb_list_add( job->filters, &hb_filter_deinterlace );            
3130         }
3131         else if ([fPictureController deinterlace] == 3)
3132         {
3133             /* Yadif (with spatial deinterlacing) */
3134             hb_filter_deinterlace.settings = "0"; 
3135             hb_list_add( job->filters, &hb_filter_deinterlace );            
3136         }
3137         else if ([fPictureController deinterlace] == 4)
3138         {
3139             /* we add the custom string if present */
3140             hb_filter_deinterlace.settings = (char *) [[fPictureController deinterlaceCustomString] UTF8String];
3141             hb_list_add( job->filters, &hb_filter_deinterlace );            
3142         }
3143         }
3144     
3145     /* Denoise */
3146         if ([fPictureController denoise] == 1) // Weak in popup
3147         {
3148                 hb_filter_denoise.settings = "2:1:2:3"; 
3149         hb_list_add( job->filters, &hb_filter_denoise );        
3150         }
3151         else if ([fPictureController denoise] == 2) // Medium in popup
3152         {
3153                 hb_filter_denoise.settings = "3:2:2:3"; 
3154         hb_list_add( job->filters, &hb_filter_denoise );        
3155         }
3156         else if ([fPictureController denoise] == 3) // Strong in popup
3157         {
3158                 hb_filter_denoise.settings = "7:7:5:5"; 
3159         hb_list_add( job->filters, &hb_filter_denoise );        
3160         }
3161     else if ([fPictureController denoise] == 4) // custom in popup
3162         {
3163                 /* we add the custom string if present */
3164         hb_filter_denoise.settings = (char *) [[fPictureController denoiseCustomString] UTF8String]; 
3165         hb_list_add( job->filters, &hb_filter_denoise );        
3166         }
3167     
3168     /* Deblock  (uses pp7 default) */
3169     /* NOTE: even though there is a valid deblock setting of 0 for the filter, for 
3170      * the macgui's purposes a value of 0 actually means to not even use the filter
3171      * current hb_filter_deblock.settings valid ranges are from 5 - 15 
3172      */
3173     if ([fPictureController deblock] != 0)
3174     {
3175         NSString *deblockStringValue = [NSString stringWithFormat: @"%d",[fPictureController deblock]];
3176         hb_filter_deblock.settings = (char *) [deblockStringValue UTF8String];
3177         hb_list_add( job->filters, &hb_filter_deblock );
3178     }
3179
3180 }
3181
3182
3183 #pragma mark -
3184 #pragma mark Job Handling
3185
3186
3187 - (void) prepareJob
3188 {
3189     
3190     NSMutableDictionary * queueToApply = [QueueFileArray objectAtIndex:currentQueueEncodeIndex];
3191     hb_list_t  * list  = hb_get_titles( fQueueEncodeLibhb );
3192     hb_title_t * title = (hb_title_t *) hb_list_item( list,0 ); // is always zero since now its a single title scan
3193     hb_job_t * job = title->job;
3194     hb_audio_config_t * audio;
3195     /* Title Angle for dvdnav */
3196     job->angle = [[queueToApply objectForKey:@"TitleAngle"] intValue];
3197     /* Chapter selection */
3198     job->chapter_start = [[queueToApply objectForKey:@"JobChapterStart"] intValue];
3199     job->chapter_end   = [[queueToApply objectForKey:@"JobChapterEnd"] intValue];
3200         
3201     /* Format (Muxer) and Video Encoder */
3202     job->mux = [[queueToApply objectForKey:@"JobFileFormatMux"] intValue];
3203     job->vcodec = [[queueToApply objectForKey:@"JobVideoEncoderVcodec"] intValue];
3204     
3205     
3206     /* If mpeg-4, then set mpeg-4 specific options like chapters and > 4gb file sizes */
3207     if( [[queueToApply objectForKey:@"Mp4LargeFile"] intValue] == 1)
3208     {
3209         job->largeFileSize = 1;
3210     }
3211     else
3212     {
3213         job->largeFileSize = 0;
3214     }
3215     /* We set http optimized mp4 here */
3216     if( [[queueToApply objectForKey:@"Mp4HttpOptimize"] intValue] == 1 )
3217     {
3218         job->mp4_optimize = 1;
3219     }
3220     else
3221     {
3222         job->mp4_optimize = 0;
3223     }
3224
3225         
3226     /* We set the chapter marker extraction here based on the format being
3227      mpeg4 or mkv and the checkbox being checked */
3228     if ([[queueToApply objectForKey:@"ChapterMarkers"] intValue] == 1)
3229     {
3230         job->chapter_markers = 1;
3231         
3232         /* now lets get our saved chapter names out the array in the queue file
3233          * and insert them back into the title chapter list. We have it here,
3234          * because unless we are inserting chapter markers there is no need to
3235          * spend the overhead of iterating through the chapter names array imo
3236          * Also, note that if for some reason we don't apply chapter names, the
3237          * chapters just come out 001, 002, etc. etc.
3238          */
3239          
3240         NSMutableArray *ChapterNamesArray = [queueToApply objectForKey:@"ChapterNames"];
3241         int i = 0;
3242         NSEnumerator *enumerator = [ChapterNamesArray objectEnumerator];
3243         id tempObject;
3244         while (tempObject = [enumerator nextObject])
3245         {
3246             hb_chapter_t *chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i );
3247             if( chapter != NULL )
3248             {
3249                 strncpy( chapter->title, [tempObject UTF8String], 1023);
3250                 chapter->title[1023] = '\0';
3251             }
3252             i++;
3253         }
3254     }
3255     else
3256     {
3257         job->chapter_markers = 0;
3258     }
3259     
3260     if( job->vcodec & HB_VCODEC_X264 )
3261     {
3262                 if ([[queueToApply objectForKey:@"Mp4iPodCompatible"] intValue] == 1)
3263             {
3264             job->ipod_atom = 1;
3265                 }
3266         else
3267         {
3268             job->ipod_atom = 0;
3269         }
3270                 
3271                 /* Set this flag to switch from Constant Quantizer(default) to Constant Rate Factor Thanks jbrjake
3272          Currently only used with Constant Quality setting*/
3273                 if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0 && [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 2)
3274                 {
3275                 job->crf = 1;
3276                 }
3277                 /* Below Sends x264 options to the core library if x264 is selected*/
3278                 /* Lets use this as per Nyx, Thanks Nyx!*/
3279                 job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */
3280                 /* Turbo first pass if two pass and Turbo First pass is selected */
3281                 if( [[queueToApply objectForKey:@"VideoTwoPass"] intValue] == 1 && [[queueToApply objectForKey:@"VideoTurboTwoPass"] intValue] == 1 )
3282                 {
3283                         /* pass the "Turbo" string to be appended to the existing x264 opts string into a variable for the first pass */
3284                         NSString *firstPassOptStringTurbo = @":ref=1:subme=1:me=dia:analyse=none:trellis=0:no-fast-pskip=0:8x8dct=0:weightb=0";
3285                         /* append the "Turbo" string variable to the existing opts string.
3286              Note: the "Turbo" string must be appended, not prepended to work properly*/
3287                         NSString *firstPassOptStringCombined = [[queueToApply objectForKey:@"x264Option"] stringByAppendingString:firstPassOptStringTurbo];
3288                         strcpy(job->x264opts, [firstPassOptStringCombined UTF8String]);
3289                 }
3290                 else
3291                 {
3292                         strcpy(job->x264opts, [[queueToApply objectForKey:@"x264Option"] UTF8String]);
3293                 }
3294         
3295     }
3296     
3297     
3298     /* Picture Size Settings */
3299     job->width = [[queueToApply objectForKey:@"PictureWidth"]  intValue];
3300     job->height = [[queueToApply objectForKey:@"PictureHeight"]  intValue];
3301     
3302     job->keep_ratio = [[queueToApply objectForKey:@"PictureKeepRatio"]  intValue];
3303     job->anamorphic.mode = [[queueToApply objectForKey:@"PicturePAR"]  intValue];
3304     if ([[queueToApply objectForKey:@"PicturePAR"]  intValue] == 3)
3305     {
3306         /* insert our custom values here for capuj */
3307         job->width = [[queueToApply objectForKey:@"PicturePARStorageWidth"]  intValue];
3308         job->height = [[queueToApply objectForKey:@"PicturePARStorageHeight"]  intValue];
3309         
3310         job->anamorphic.par_width = [[queueToApply objectForKey:@"PicturePARPixelWidth"]  intValue];
3311         job->anamorphic.par_height = [[queueToApply objectForKey:@"PicturePARPixelHeight"]  intValue];
3312         
3313         job->anamorphic.dar_width = [[queueToApply objectForKey:@"PicturePARDisplayWidth"]  floatValue];
3314         job->anamorphic.dar_height = [[queueToApply objectForKey:@"PicturePARDisplayHeight"]  floatValue];
3315     }
3316     
3317     /* Here we use the crop values saved at the time the preset was saved */
3318     job->crop[0] = [[queueToApply objectForKey:@"PictureTopCrop"]  intValue];
3319     job->crop[1] = [[queueToApply objectForKey:@"PictureBottomCrop"]  intValue];
3320     job->crop[2] = [[queueToApply objectForKey:@"PictureLeftCrop"]  intValue];
3321     job->crop[3] = [[queueToApply objectForKey:@"PictureRightCrop"]  intValue];
3322     
3323     /* Video settings */
3324     /* Framerate */
3325     
3326     /* Set vfr to 0 as it's only on if using same as source in the framerate popup
3327      * and detelecine is on, so we handle that in the logic below
3328      */
3329     job->vfr = 0;
3330     if( [[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue] > 0 )
3331     {
3332         /* a specific framerate has been chosen */
3333         job->vrate      = 27000000;
3334         job->vrate_base = hb_video_rates[[[queueToApply objectForKey:@"JobIndexVideoFramerate"] intValue]-1].rate;
3335         /* We are not same as source so we set job->cfr to 1 
3336          * to enable constant frame rate since user has specified
3337          * a specific framerate*/
3338         job->cfr = 1;
3339     }
3340     else
3341     {
3342         /* We are same as source (variable) */
3343         job->vrate      = [[queueToApply objectForKey:@"JobVrate"] intValue];
3344         job->vrate_base = [[queueToApply objectForKey:@"JobVrateBase"] intValue];
3345         /* We are same as source so we set job->cfr to 0 
3346          * to enable true same as source framerate */
3347         job->cfr = 0;
3348         /* If we are same as source and we have detelecine on, we need to turn on
3349          * job->vfr
3350          */
3351         if ([[queueToApply objectForKey:@"PictureDetelecine"] intValue] == 1)
3352         {
3353             job->vfr = 1;
3354         }
3355     }
3356     
3357     if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] != 2 )
3358     {
3359         /* Target size.
3360          Bitrate should already have been calculated and displayed
3361          in fVidBitrateField, so let's just use it same as abr*/
3362         job->vquality = -1.0;
3363         job->vbitrate = [[queueToApply objectForKey:@"VideoAvgBitrate"] intValue];
3364     }
3365     if ( [[queueToApply objectForKey:@"VideoQualityType"] intValue] == 2 )
3366     {
3367         job->vquality = [[queueToApply objectForKey:@"VideoQualitySlider"] floatValue];
3368         job->vbitrate = 0;
3369         
3370     }
3371     
3372     job->grayscale = [[queueToApply objectForKey:@"VideoGrayScale"] intValue];
3373     
3374
3375
3376 #pragma mark -
3377 #pragma mark Process Subtitles to libhb
3378
3379 /* Map the settings in the dictionaries for the SubtitleList array to match title->list_subtitle
3380  * which means that we need to account for the offset of non source language settings in from
3381  * the NSPopUpCell menu. For all of the objects in the SubtitleList array this means 0 is "None"
3382  * from the popup menu, additionally the first track has "Foreign Audio Search" at 1. So we use
3383  * an int to offset the index number for the objectForKey:@"subtitleSourceTrackNum" to map that
3384  * to the source tracks position in title->list_subtitle.
3385  */
3386
3387 int subtitle = nil;
3388 int force;
3389 int burned;
3390 int def;
3391 bool one_burned = FALSE;
3392
3393     int i = 0;
3394     NSEnumerator *enumerator = [[queueToApply objectForKey:@"SubtitleList"] objectEnumerator];
3395     id tempObject;
3396     while (tempObject = [enumerator nextObject])
3397     {
3398         
3399         subtitle = [[tempObject objectForKey:@"subtitleSourceTrackNum"] intValue];
3400         force = [[tempObject objectForKey:@"subtitleTrackForced"] intValue];
3401         burned = [[tempObject objectForKey:@"subtitleTrackBurned"] intValue];
3402         def = [[tempObject objectForKey:@"subtitleTrackDefault"] intValue];
3403         
3404         /* since the subtitleSourceTrackNum 0 is "None" in our array of the subtitle popups,
3405          * we want to ignore it for display as well as encoding.
3406          */
3407         if (subtitle > 0)
3408         {
3409             /* if i is 0, then we are in the first item of the subtitles which we need to 
3410              * check for the "Foreign Audio Search" which would be subtitleSourceTrackNum of 1
3411              * bearing in mind that for all tracks subtitleSourceTrackNum of 0 is None.
3412              */
3413             
3414             /* if we are on the first track and using "Foreign Audio Search" */ 
3415             if (i == 0 && subtitle == 1)
3416             {
3417                 [self writeToActivityLog: "Foreign Language Search: %d", 1];
3418                 
3419                 job->indepth_scan = 1;
3420                 if (burned == 1 || job->mux != HB_MUX_MP4)
3421                 {
3422                     if (burned != 1 && job->mux == HB_MUX_MKV)
3423                     {
3424                         job->select_subtitle_config.dest = hb_subtitle_config_s::PASSTHRUSUB;
3425                     }
3426                     else
3427                     {
3428                         job->select_subtitle_config.dest = hb_subtitle_config_s::RENDERSUB;
3429                     }
3430                     
3431                     job->select_subtitle_config.force = force;
3432                     job->select_subtitle_config.default_track = def;
3433                 }
3434                 
3435                 
3436             }
3437             else
3438             {
3439                 
3440                 /* for the actual source tracks, we must subtract the non source entries so 
3441                  * that the menu index matches the source subtitle_list index for convenience */
3442                 if (i == 0)
3443                 {
3444                     /* for the first track, the source tracks start at menu index 2 ( None is 0,
3445                      * Foreign Language Search is 1) so subtract 2 */
3446                     subtitle = subtitle - 2;
3447                 }
3448                 else
3449                 {
3450                     /* for all other tracks, the source tracks start at menu index 1 (None is 0)
3451                      * so subtract 1. */
3452                     
3453                     subtitle = subtitle - 1;
3454                 }
3455                 
3456                 /* We are setting a source subtitle so access the source subtitle info */  
3457                 hb_subtitle_t * subt;
3458                 
3459                 subt = (hb_subtitle_t *)hb_list_item(title->list_subtitle, subtitle);
3460                 
3461                 /* if we are getting the subtitles from an external srt file */
3462                 if ([[tempObject objectForKey:@"subtitleSourceTrackType"] isEqualToString:@"SRT"])
3463                 {
3464                     hb_subtitle_config_t sub_config;
3465                     
3466                     sub_config.offset = [[tempObject objectForKey:@"subtitleTrackSrtOffset"] intValue];
3467                     
3468                     /* we need to srncpy file name and codeset */
3469                     //sub_config.src_filename = [[tempObject objectForKey:@"subtitleSourceSrtFilePath"] UTF8String];
3470                     strncpy(sub_config.src_filename, [[tempObject objectForKey:@"subtitleSourceSrtFilePath"] UTF8String], 128);
3471                     //sub_config.src_codeset = [[tempObject objectForKey:@"subtitleTrackSrtCharCode"] UTF8String];
3472                     strncpy(sub_config.src_codeset, [[tempObject objectForKey:@"subtitleTrackSrtCharCode"] UTF8String], 40);
3473                     
3474                     sub_config.force = 0;
3475                     sub_config.dest = hb_subtitle_config_s::PASSTHRUSUB;
3476                     sub_config.default_track = def;
3477                     
3478                     hb_srt_add( job, &sub_config, [[tempObject objectForKey:@"subtitleTrackSrtLanguageIso3"] UTF8String]);
3479                 }
3480                 
3481                 
3482                 if (subt != NULL)
3483                 {
3484                     [self writeToActivityLog: "Setting Subtitle: %s", subt];
3485
3486                     hb_subtitle_config_t sub_config = subt->config;
3487                     
3488                     if (!burned && job->mux == HB_MUX_MKV && 
3489                         subt->format == hb_subtitle_s::PICTURESUB)
3490                     {
3491                         sub_config.dest = hb_subtitle_config_s::PASSTHRUSUB;
3492                     }
3493                     else if (!burned && job->mux == HB_MUX_MP4 && 
3494                              subt->format == hb_subtitle_s::PICTURESUB)
3495                     {
3496                         // Skip any non-burned vobsubs when output is mp4
3497                         continue;
3498                     }
3499                     else if ( burned && subt->format == hb_subtitle_s::PICTURESUB )
3500                     {
3501                         // Only allow one subtitle to be burned into the video
3502                         if (one_burned)
3503                             continue;
3504                         one_burned = TRUE;
3505                     }
3506                     sub_config.force = force;
3507                     sub_config.default_track = def;
3508                     hb_subtitle_add( job, &sub_config, subtitle );
3509                 }   
3510                 
3511             }
3512         }
3513         i++;
3514     }
3515
3516 #pragma mark -
3517
3518    
3519     /* Audio tracks and mixdowns */
3520     /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty*/
3521     int audiotrack_count = hb_list_count(job->list_audio);
3522     for( int i = 0; i < audiotrack_count;i++)
3523     {
3524         hb_audio_t * temp_audio = (hb_audio_t*) hb_list_item( job->list_audio, 0 );
3525         hb_list_rem(job->list_audio, temp_audio);
3526     }
3527     /* Now lets add our new tracks to the audio list here */
3528     if ([[queueToApply objectForKey:@"Audio1Track"] intValue] > 0)
3529     {
3530         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
3531         hb_audio_config_init(audio);
3532         audio->in.track = [[queueToApply objectForKey:@"Audio1Track"] intValue] - 1;
3533         /* We go ahead and assign values to our audio->out.<properties> */
3534         audio->out.track = [[queueToApply objectForKey:@"Audio1Track"] intValue] - 1;
3535         audio->out.codec = [[queueToApply objectForKey:@"JobAudio1Encoder"] intValue];
3536         audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio1Mixdown"] intValue];
3537         audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio1Bitrate"] intValue];
3538         audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio1Samplerate"] intValue];
3539         audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio1TrackDRCSlider"] floatValue];
3540         
3541         hb_audio_add( job, audio );
3542         free(audio);
3543     }  
3544     if ([[queueToApply objectForKey:@"Audio2Track"] intValue] > 0)
3545     {
3546         
3547         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
3548         hb_audio_config_init(audio);
3549         audio->in.track = [[queueToApply objectForKey:@"Audio2Track"] intValue] - 1;
3550         [self writeToActivityLog: "prepareJob audiotrack 2 is: %d", audio->in.track];
3551         /* We go ahead and assign values to our audio->out.<properties> */
3552         audio->out.track = [[queueToApply objectForKey:@"Audio2Track"] intValue] - 1;
3553         audio->out.codec = [[queueToApply objectForKey:@"JobAudio2Encoder"] intValue];
3554         audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio2Mixdown"] intValue];
3555         audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio2Bitrate"] intValue];
3556         audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio2Samplerate"] intValue];
3557         audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio2TrackDRCSlider"] floatValue];
3558         
3559         hb_audio_add( job, audio );
3560         free(audio);
3561     }
3562     
3563     if ([[queueToApply objectForKey:@"Audio3Track"] intValue] > 0)
3564     {
3565         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
3566         hb_audio_config_init(audio);
3567         audio->in.track = [[queueToApply objectForKey:@"Audio3Track"] intValue] - 1;
3568         /* We go ahead and assign values to our audio->out.<properties> */
3569         audio->out.track = [[queueToApply objectForKey:@"Audio3Track"] intValue] - 1;
3570         audio->out.codec = [[queueToApply objectForKey:@"JobAudio3Encoder"] intValue];
3571         audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio3Mixdown"] intValue];
3572         audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio3Bitrate"] intValue];
3573         audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio3Samplerate"] intValue];
3574         audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio3TrackDRCSlider"] floatValue];
3575         
3576         hb_audio_add( job, audio );
3577         free(audio);        
3578     }
3579     
3580     if ([[queueToApply objectForKey:@"Audio4Track"] intValue] > 0)
3581     {
3582         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
3583         hb_audio_config_init(audio);
3584         audio->in.track = [[queueToApply objectForKey:@"Audio4Track"] intValue] - 1;
3585         /* We go ahead and assign values to our audio->out.<properties> */
3586         audio->out.track = [[queueToApply objectForKey:@"Audio4Track"] intValue] - 1;
3587         audio->out.codec = [[queueToApply objectForKey:@"JobAudio4Encoder"] intValue];
3588         audio->out.mixdown = [[queueToApply objectForKey:@"JobAudio4Mixdown"] intValue];
3589         audio->out.bitrate = [[queueToApply objectForKey:@"JobAudio4Bitrate"] intValue];
3590         audio->out.samplerate = [[queueToApply objectForKey:@"JobAudio4Samplerate"] intValue];
3591         audio->out.dynamic_range_compression = [[queueToApply objectForKey:@"Audio4TrackDRCSlider"] floatValue];
3592         
3593         hb_audio_add( job, audio );
3594         
3595
3596     }
3597     
3598     /* Filters */ 
3599     job->filters = hb_list_init();
3600     
3601     /* Now lets call the filters if applicable.
3602      * The order of the filters is critical
3603      */
3604     /* Detelecine */
3605     if ([[queueToApply objectForKey:@"PictureDetelecine"] intValue] == 1)
3606     {
3607         //if ([queueToApply objectForKey:@"PictureDetelecineCustom"])
3608         hb_list_add( job->filters, &hb_filter_detelecine );
3609     }
3610     if ([[queueToApply objectForKey:@"PictureDetelecine"] intValue] == 2)
3611     {
3612         /* use a custom detelecine string */
3613         hb_filter_detelecine.settings = (char *) [[queueToApply objectForKey:@"PictureDetelecineCustom"] UTF8String];
3614         hb_list_add( job->filters, &hb_filter_detelecine );
3615     }
3616     
3617     if ([[queueToApply objectForKey:@"PictureDecombDeinterlace"] intValue] == 1)
3618     {
3619         /* Decomb */
3620         if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 1)
3621         {
3622             /* Run old deinterlacer fd by default */
3623             hb_list_add( job->filters, &hb_filter_decomb );
3624         }
3625         /* we add the custom string if present */
3626         if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 2)
3627         {
3628             /* use a custom decomb string */
3629             hb_filter_decomb.settings = (char *) [[queueToApply objectForKey:@"PictureDecombCustom"] UTF8String];
3630             hb_list_add( job->filters, &hb_filter_decomb );
3631         }
3632         
3633     }
3634     else
3635     {
3636         
3637         /* Deinterlace */
3638         if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 1)
3639         {
3640             /* Run old deinterlacer fd by default */
3641             hb_filter_deinterlace.settings = "-1"; 
3642             hb_list_add( job->filters, &hb_filter_deinterlace );
3643         }
3644         else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 2)
3645         {
3646             /* Yadif mode 0 (without spatial deinterlacing.) */
3647             hb_filter_deinterlace.settings = "2"; 
3648             hb_list_add( job->filters, &hb_filter_deinterlace );            
3649         }
3650         else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 3)
3651         {
3652             /* Yadif (with spatial deinterlacing) */
3653             hb_filter_deinterlace.settings = "0"; 
3654             hb_list_add( job->filters, &hb_filter_deinterlace );            
3655         }
3656         else if ([[queueToApply objectForKey:@"PictureDeinterlace"] intValue] == 4)
3657         {
3658             /* we add the custom string if present */
3659             hb_filter_deinterlace.settings = (char *) [[queueToApply objectForKey:@"PictureDeinterlaceCustom"] UTF8String];
3660             hb_list_add( job->filters, &hb_filter_deinterlace );            
3661         }
3662         
3663         
3664     }
3665     /* Denoise */
3666         if ([[queueToApply objectForKey:@"PictureDenoise"] intValue] == 1) // Weak in popup
3667         {
3668                 hb_filter_denoise.settings = "2:1:2:3"; 
3669         hb_list_add( job->filters, &hb_filter_denoise );        
3670         }
3671         else if ([[queueToApply objectForKey:@"PictureDenoise"] intValue] == 2) // Medium in popup
3672         {
3673                 hb_filter_denoise.settings = "3:2:2:3"; 
3674         hb_list_add( job->filters, &hb_filter_denoise );        
3675         }
3676         else if ([[queueToApply objectForKey:@"PictureDenoise"] intValue] == 3) // Strong in popup
3677         {
3678                 hb_filter_denoise.settings = "7:7:5:5"; 
3679         hb_list_add( job->filters, &hb_filter_denoise );        
3680         }
3681     else if ([[queueToApply objectForKey:@"PictureDenoise"] intValue] == 4) // Custom in popup
3682         {
3683                 /* we add the custom string if present */
3684         hb_filter_denoise.settings = (char *) [[queueToApply objectForKey:@"PictureDenoiseCustom"] UTF8String];
3685         hb_list_add( job->filters, &hb_filter_denoise );        
3686         }
3687     
3688     /* Deblock  (uses pp7 default) */
3689     /* NOTE: even though there is a valid deblock setting of 0 for the filter, for 
3690      * the macgui's purposes a value of 0 actually means to not even use the filter
3691      * current hb_filter_deblock.settings valid ranges are from 5 - 15 
3692      */
3693     if ([[queueToApply objectForKey:@"PictureDeblock"] intValue] != 0)
3694     {
3695         hb_filter_deblock.settings = (char *) [[queueToApply objectForKey:@"PictureDeblock"] UTF8String];
3696         hb_list_add( job->filters, &hb_filter_deblock );
3697     }
3698 [self writeToActivityLog: "prepareJob exiting"];    
3699 }
3700
3701
3702
3703 /* addToQueue: puts up an alert before ultimately calling doAddToQueue
3704 */
3705 - (IBAction) addToQueue: (id) sender
3706 {
3707         /* We get the destination directory from the destination field here */
3708         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
3709         /* We check for a valid destination here */
3710         if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) 
3711         {
3712                 NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil);
3713         return;
3714         }
3715     
3716     BOOL fileExists;
3717     fileExists = NO;
3718     
3719     BOOL fileExistsInQueue;
3720     fileExistsInQueue = NO;
3721     
3722     /* We check for and existing file here */
3723     if([[NSFileManager defaultManager] fileExistsAtPath: [fDstFile2Field stringValue]])
3724     {
3725         fileExists = YES;
3726     }
3727     
3728     /* We now run through the queue and make sure we are not overwriting an exisiting queue item */
3729     int i = 0;
3730     NSEnumerator *enumerator = [QueueFileArray objectEnumerator];
3731         id tempObject;
3732         while (tempObject = [enumerator nextObject])
3733         {
3734                 NSDictionary *thisQueueDict = tempObject;
3735                 if ([[thisQueueDict objectForKey:@"DestinationPath"] isEqualToString: [fDstFile2Field stringValue]])
3736                 {
3737                         fileExistsInQueue = YES;        
3738                 }
3739         i++;
3740         }
3741     
3742     
3743         if(fileExists == YES)
3744     {
3745         NSBeginCriticalAlertSheet( NSLocalizedString( @"File already exists.", @"" ),
3746                                   NSLocalizedString( @"Cancel", @"" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self,
3747                                   @selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ),
3748                                   NULL, NULL, [NSString stringWithFormat:
3749                                                NSLocalizedString( @"Do you want to overwrite %@?", @"" ),
3750                                                [fDstFile2Field stringValue]] );
3751     }
3752     else if (fileExistsInQueue == YES)
3753     {
3754     NSBeginCriticalAlertSheet( NSLocalizedString( @"There is already a queue item for this destination.", @"" ),
3755                                   NSLocalizedString( @"Cancel", @"" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self,
3756                                   @selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ),
3757                                   NULL, NULL, [NSString stringWithFormat:
3758                                                NSLocalizedString( @"Do you want to overwrite %@?", @"" ),
3759                                                [fDstFile2Field stringValue]] );
3760     }
3761     else
3762     {
3763         [self doAddToQueue];
3764     }
3765 }
3766
3767 /* overwriteAddToQueueAlertDone: called from the alert posted by addToQueue that asks
3768    the user if they want to overwrite an exiting movie file.
3769 */
3770 - (void) overwriteAddToQueueAlertDone: (NSWindow *) sheet
3771     returnCode: (int) returnCode contextInfo: (void *) contextInfo
3772 {
3773     if( returnCode == NSAlertAlternateReturn )
3774         [self doAddToQueue];
3775 }
3776
3777 - (void) doAddToQueue
3778 {
3779     [self addQueueFileItem ];
3780 }
3781
3782
3783
3784 /* Rip: puts up an alert before ultimately calling doRip
3785 */
3786 - (IBAction) Rip: (id) sender
3787 {
3788     [self writeToActivityLog: "Rip: Pending queue count is %d", fPendingCount];
3789     /* Rip or Cancel ? */
3790     hb_state_t s;
3791     hb_get_state2( fQueueEncodeLibhb, &s );
3792     
3793     if(s.state == HB_STATE_WORKING || s.state == HB_STATE_PAUSED)
3794         {
3795         [self Cancel: sender];
3796         return;
3797     }
3798     
3799     /* We check to see if we need to warn the user that the computer will go to sleep
3800                  or shut down when encoding is finished */
3801                 [self remindUserOfSleepOrShutdown];
3802     
3803     // If there are pending jobs in the queue, then this is a rip the queue
3804     if (fPendingCount > 0)
3805     {
3806         /* here lets start the queue with the first pending item */
3807         [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; 
3808         
3809         return;
3810     }
3811     
3812     // Before adding jobs to the queue, check for a valid destination.
3813     
3814     NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
3815     if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) 
3816     {
3817         NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil);
3818         return;
3819     }
3820     
3821     /* We check for duplicate name here */
3822     if( [[NSFileManager defaultManager] fileExistsAtPath:[fDstFile2Field stringValue]] )
3823     {
3824         NSBeginCriticalAlertSheet( NSLocalizedString( @"File already exists", @"" ),
3825                                   NSLocalizedString( @"Cancel", "" ), NSLocalizedString( @"Overwrite", @"" ), nil, fWindow, self,
3826                                   @selector( overWriteAlertDone:returnCode:contextInfo: ),
3827                                   NULL, NULL, [NSString stringWithFormat:
3828                                                NSLocalizedString( @"Do you want to overwrite %@?", @"" ),
3829                                                [fDstFile2Field stringValue]] );
3830         
3831         // overWriteAlertDone: will be called when the alert is dismissed. It will call doRip.
3832     }
3833     else
3834     {
3835         /* if there are no pending jobs in the queue, then add this one to the queue and rip
3836          otherwise, just rip the queue */
3837         if(fPendingCount == 0)
3838         {
3839             [self writeToActivityLog: "Rip: No pending jobs, so sending this one to doAddToQueue"];
3840             [self doAddToQueue];
3841         }
3842         
3843         /* go right to processing the new queue encode */
3844         [self writeToActivityLog: "Rip: Going right to performNewQueueScan"];
3845         [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; 
3846         
3847     }
3848 }
3849
3850 /* overWriteAlertDone: called from the alert posted by Rip: that asks the user if they
3851    want to overwrite an exiting movie file.
3852 */
3853 - (void) overWriteAlertDone: (NSWindow *) sheet
3854     returnCode: (int) returnCode contextInfo: (void *) contextInfo
3855 {
3856     if( returnCode == NSAlertAlternateReturn )
3857     {
3858         /* if there are no jobs in the queue, then add this one to the queue and rip 
3859         otherwise, just rip the queue */
3860         if( fPendingCount == 0 )
3861         {
3862             [self doAddToQueue];
3863         }
3864
3865         NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent];
3866         [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"];
3867         [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; 
3868       
3869     }
3870 }
3871
3872 - (void) remindUserOfSleepOrShutdown
3873 {
3874        if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Put Computer To Sleep"])
3875        {
3876                /*Warn that computer will sleep after encoding*/
3877                int reminduser;
3878                NSBeep();
3879                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);
3880                [NSApp requestUserAttention:NSCriticalRequest];
3881                if ( reminduser == NSAlertAlternateReturn )
3882                {
3883                        [self showPreferencesWindow:nil];
3884                }
3885        }
3886        else if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Shut Down Computer"])
3887        {
3888                /*Warn that computer will shut down after encoding*/
3889                int reminduser;
3890                NSBeep();
3891                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);
3892                [NSApp requestUserAttention:NSCriticalRequest];
3893                if ( reminduser == NSAlertAlternateReturn )
3894                {
3895                        [self showPreferencesWindow:nil];
3896                }
3897        }
3898
3899 }
3900
3901
3902 - (void) doRip
3903 {
3904     /* Let libhb do the job */
3905     hb_start( fQueueEncodeLibhb );
3906     /*set the fEncodeState State */
3907         fEncodeState = 1;
3908 }
3909
3910
3911 //------------------------------------------------------------------------------------
3912 // Displays an alert asking user if the want to cancel encoding of current job.
3913 // Cancel: returns immediately after posting the alert. Later, when the user
3914 // acknowledges the alert, doCancelCurrentJob is called.
3915 //------------------------------------------------------------------------------------
3916 - (IBAction)Cancel: (id)sender
3917 {
3918     if (!fQueueController) return;
3919     
3920   hb_pause( fQueueEncodeLibhb );
3921     NSString * alertTitle = [NSString stringWithFormat:NSLocalizedString(@"You are currently encoding. What would you like to do ?", nil)];
3922    
3923     // Which window to attach the sheet to?
3924     NSWindow * docWindow;
3925     if ([sender respondsToSelector: @selector(window)])
3926         docWindow = [sender window];
3927     else
3928         docWindow = fWindow;
3929         
3930     NSBeginCriticalAlertSheet(
3931             alertTitle,
3932             NSLocalizedString(@"Continue Encoding", nil),
3933             NSLocalizedString(@"Cancel Current and Stop", nil),
3934             NSLocalizedString(@"Cancel Current and Continue", nil),
3935             docWindow, self,
3936             nil, @selector(didDimissCancel:returnCode:contextInfo:), nil,
3937             NSLocalizedString(@"Your encode will be cancelled if you don't continue encoding.", nil));
3938     
3939     // didDimissCancelCurrentJob:returnCode:contextInfo: will be called when the dialog is dismissed
3940 }
3941
3942 - (void) didDimissCancel: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
3943 {
3944    hb_resume( fQueueEncodeLibhb );
3945      if (returnCode == NSAlertOtherReturn)
3946     {
3947         [self doCancelCurrentJob];  // <- this also stops libhb
3948     }
3949     if (returnCode == NSAlertAlternateReturn)
3950     {
3951     [self doCancelCurrentJobAndStop];
3952     }
3953 }
3954
3955 //------------------------------------------------------------------------------------
3956 // Cancels and deletes the current job and stops libhb from processing the remaining
3957 // encodes.
3958 //------------------------------------------------------------------------------------
3959 - (void) doCancelCurrentJob
3960 {
3961     // Stop the current job. hb_stop will only cancel the current pass and then set
3962     // its state to HB_STATE_WORKDONE. It also does this asynchronously. So when we
3963     // see the state has changed to HB_STATE_WORKDONE (in updateUI), we'll delete the
3964     // remaining passes of the job and then start the queue back up if there are any
3965     // remaining jobs.
3966      
3967     
3968     hb_stop( fQueueEncodeLibhb );
3969     
3970     // Delete all remaining jobs since libhb doesn't do this on its own.
3971             hb_job_t * job;
3972             while( ( job = hb_job(fQueueEncodeLibhb, 0) ) )
3973                 hb_rem( fQueueEncodeLibhb, job );
3974                 
3975     fEncodeState = 2;   // don't alert at end of processing since this was a cancel
3976     
3977     // now that we've stopped the currently encoding job, lets mark it as cancelled
3978     [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:3] forKey:@"Status"];
3979     // and as always, save it in the queue .plist...
3980     /* We save all of the Queue data here */
3981     [self saveQueueFileItem];
3982     // so now lets move to 
3983     currentQueueEncodeIndex++ ;
3984     // ... and see if there are more items left in our queue
3985     int queueItems = [QueueFileArray count];
3986     /* If we still have more items in our queue, lets go to the next one */
3987     if (currentQueueEncodeIndex < queueItems)
3988     {
3989     [self writeToActivityLog: "doCancelCurrentJob currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex];
3990     [self writeToActivityLog: "doCancelCurrentJob moving to the next job"];
3991     
3992     [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]];
3993     }
3994     else
3995     {
3996         [self writeToActivityLog: "doCancelCurrentJob the item queue is complete"];
3997     }
3998
3999 }
4000
4001 - (void) doCancelCurrentJobAndStop
4002 {
4003     hb_stop( fQueueEncodeLibhb );
4004     
4005     // Delete all remaining jobs since libhb doesn't do this on its own.
4006             hb_job_t * job;
4007             while( ( job = hb_job(fQueueEncodeLibhb, 0) ) )
4008                 hb_rem( fQueueEncodeLibhb, job );
4009                 
4010                 
4011     fEncodeState = 2;   // don't alert at end of processing since this was a cancel
4012     
4013     // now that we've stopped the currently encoding job, lets mark it as cancelled
4014     [[QueueFileArray objectAtIndex:currentQueueEncodeIndex] setObject:[NSNumber numberWithInt:3] forKey:@"Status"];
4015     // and as always, save it in the queue .plist...
4016     /* We save all of the Queue data here */
4017     [self saveQueueFileItem];
4018     // so now lets move to 
4019     currentQueueEncodeIndex++ ;
4020     [self writeToActivityLog: "cancelling current job and stopping the queue"];
4021 }
4022 - (IBAction) Pause: (id) sender
4023 {
4024     hb_state_t s;
4025     hb_get_state2( fQueueEncodeLibhb, &s );
4026
4027     if( s.state == HB_STATE_PAUSED )
4028     {
4029         hb_resume( fQueueEncodeLibhb );
4030     }
4031     else
4032     {
4033         hb_pause( fQueueEncodeLibhb );
4034     }
4035 }
4036
4037 #pragma mark -
4038 #pragma mark GUI Controls Changed Methods
4039
4040 - (IBAction) titlePopUpChanged: (id) sender
4041 {
4042     hb_list_t  * list  = hb_get_titles( fHandle );
4043     hb_title_t * title = (hb_title_t*)
4044         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
4045
4046     /* If Auto Naming is on. We create an output filename of dvd name - title number */
4047     if( [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultAutoNaming"] > 0 && ( hb_list_count( list ) > 1 ) )
4048         {
4049                 [fDstFile2Field setStringValue: [NSString stringWithFormat:
4050                         @"%@/%@-%d.%@", [[fDstFile2Field stringValue] stringByDeletingLastPathComponent],
4051                         [browsedSourceDisplayName stringByDeletingPathExtension],
4052             title->index,
4053                         [[fDstFile2Field stringValue] pathExtension]]]; 
4054         }
4055
4056     /* Update chapter popups */
4057     [fSrcChapterStartPopUp removeAllItems];
4058     [fSrcChapterEndPopUp   removeAllItems];
4059     for( int i = 0; i < hb_list_count( title->list_chapter ); i++ )
4060     {
4061         [fSrcChapterStartPopUp addItemWithTitle: [NSString
4062             stringWithFormat: @"%d", i + 1]];
4063         [fSrcChapterEndPopUp addItemWithTitle: [NSString
4064             stringWithFormat: @"%d", i + 1]];
4065     }
4066
4067     [fSrcChapterStartPopUp selectItemAtIndex: 0];
4068     [fSrcChapterEndPopUp   selectItemAtIndex:
4069         hb_list_count( title->list_chapter ) - 1];
4070     [self chapterPopUpChanged:nil];
4071     
4072     /* if using dvd nav, show the angle widget */
4073     if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"UseDvdNav"] boolValue])
4074     {
4075         [fSrcAngleLabel setHidden:NO];
4076         [fSrcAnglePopUp setHidden:NO];
4077         
4078         [fSrcAnglePopUp removeAllItems];
4079         for( int i = 0; i < title->angle_count; i++ )
4080         {
4081             [fSrcAnglePopUp addItemWithTitle: [NSString stringWithFormat: @"%d", i + 1]];
4082         }
4083         [fSrcAnglePopUp selectItemAtIndex: 0];
4084     }
4085     else
4086     {
4087         [fSrcAngleLabel setHidden:YES];
4088         [fSrcAnglePopUp setHidden:YES];
4089     }
4090     
4091     /* Start Get and set the initial pic size for display */
4092         hb_job_t * job = title->job;
4093         fTitle = title;
4094     
4095     /* Set Auto Crop to on upon selecting a new title  */
4096     [fPictureController setAutoCrop:YES];
4097     
4098         /* We get the originial output picture width and height and put them
4099         in variables for use with some presets later on */
4100         PicOrigOutputWidth = job->width;
4101         PicOrigOutputHeight = job->height;
4102         AutoCropTop = job->crop[0];
4103         AutoCropBottom = job->crop[1];
4104         AutoCropLeft = job->crop[2];
4105         AutoCropRight = job->crop[3];
4106
4107         /* Reset the new title in fPictureController &&  fPreviewController*/
4108     [fPictureController SetTitle:title];
4109
4110         
4111     /* Update Subtitle Table */
4112     [fSubtitlesDelegate resetWithTitle:title];
4113     [fSubtitlesTable reloadData];
4114     
4115
4116     /* Update chapter table */
4117     [fChapterTitlesDelegate resetWithTitle:title];
4118     [fChapterTable reloadData];
4119
4120    /* Lets make sure there arent any erroneous audio tracks in the job list, so lets make sure its empty*/
4121     int audiotrack_count = hb_list_count(job->list_audio);
4122     for( int i = 0; i < audiotrack_count;i++)
4123     {
4124         hb_audio_t * temp_audio = (hb_audio_t*) hb_list_item( job->list_audio, 0 );
4125         hb_list_rem(job->list_audio, temp_audio);
4126     }
4127
4128     /* Update audio popups */
4129     [self addAllAudioTracksToPopUp: fAudLang1PopUp];
4130     [self addAllAudioTracksToPopUp: fAudLang2PopUp];
4131     [self addAllAudioTracksToPopUp: fAudLang3PopUp];
4132     [self addAllAudioTracksToPopUp: fAudLang4PopUp];
4133     /* search for the first instance of our prefs default language for track 1, and set track 2 to "none" */
4134         NSString * audioSearchPrefix = [[NSUserDefaults standardUserDefaults] stringForKey:@"DefaultLanguage"];
4135         [self selectAudioTrackInPopUp: fAudLang1PopUp searchPrefixString: audioSearchPrefix selectIndexIfNotFound: 1];
4136     [self selectAudioTrackInPopUp:fAudLang2PopUp searchPrefixString:nil selectIndexIfNotFound:0];
4137     [self selectAudioTrackInPopUp:fAudLang3PopUp searchPrefixString:nil selectIndexIfNotFound:0];
4138     [self selectAudioTrackInPopUp:fAudLang4PopUp searchPrefixString:nil selectIndexIfNotFound:0];
4139
4140         /* changing the title may have changed the audio channels on offer, */
4141         /* so call audioTrackPopUpChanged for both audio tracks to update the mixdown popups */
4142         [self audioTrackPopUpChanged: fAudLang1PopUp];
4143         [self audioTrackPopUpChanged: fAudLang2PopUp];
4144     [self audioTrackPopUpChanged: fAudLang3PopUp];
4145     [self audioTrackPopUpChanged: fAudLang4PopUp];
4146
4147     [fVidRatePopUp selectItemAtIndex: 0];
4148
4149     /* we run the picture size values through calculatePictureSizing to get all picture setting information*/
4150         [self calculatePictureSizing:nil];
4151
4152    /* lets call tableViewSelected to make sure that any preset we have selected is enforced after a title change */
4153     [self selectPreset:nil];
4154 }
4155
4156 - (IBAction) chapterPopUpChanged: (id) sender
4157 {
4158
4159         /* If start chapter popup is greater than end chapter popup,
4160         we set the end chapter popup to the same as start chapter popup */
4161         if ([fSrcChapterStartPopUp indexOfSelectedItem] > [fSrcChapterEndPopUp indexOfSelectedItem])
4162         {
4163                 [fSrcChapterEndPopUp selectItemAtIndex: [fSrcChapterStartPopUp indexOfSelectedItem]];
4164     }
4165
4166                 
4167         hb_list_t  * list  = hb_get_titles( fHandle );
4168     hb_title_t * title = (hb_title_t *)
4169         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
4170
4171     hb_chapter_t * chapter;
4172     int64_t        duration = 0;
4173     for( int i = [fSrcChapterStartPopUp indexOfSelectedItem];
4174          i <= [fSrcChapterEndPopUp indexOfSelectedItem]; i++ )
4175     {
4176         chapter = (hb_chapter_t *) hb_list_item( title->list_chapter, i );
4177         duration += chapter->duration;
4178     }
4179     
4180     duration /= 90000; /* pts -> seconds */
4181     [fSrcDuration2Field setStringValue: [NSString stringWithFormat:
4182         @"%02lld:%02lld:%02lld", duration / 3600, ( duration / 60 ) % 60,
4183         duration % 60]];
4184
4185     [self calculateBitrate: sender];
4186     
4187     if ( [fSrcChapterStartPopUp indexOfSelectedItem] ==  [fSrcChapterEndPopUp indexOfSelectedItem] )
4188     {
4189     /* Disable chapter markers for any source with less than two chapters as it makes no sense. */
4190     [fCreateChapterMarkers setEnabled: NO];
4191     [fCreateChapterMarkers setState: NSOffState];
4192     }
4193     else
4194     {
4195     [fCreateChapterMarkers setEnabled: YES];
4196     }
4197 }
4198
4199 - (IBAction) formatPopUpChanged: (id) sender
4200 {
4201     NSString * string = [fDstFile2Field stringValue];
4202     int format = [fDstFormatPopUp indexOfSelectedItem];
4203     char * ext = NULL;
4204         /* Initially set the large file (64 bit formatting) output checkbox to hidden */
4205     [fDstMp4LargeFileCheck setHidden: YES];
4206     [fDstMp4HttpOptFileCheck setHidden: YES];
4207     [fDstMp4iPodFileCheck setHidden: YES];
4208     
4209     /* Update the Video Codec PopUp */
4210     /* lets get the tag of the currently selected item first so we might reset it later */
4211     int selectedVidEncoderTag;
4212     selectedVidEncoderTag = [[fVidEncoderPopUp selectedItem] tag];
4213     
4214     /* Note: we now store the video encoder int values from common.c in the tags of each popup for easy retrieval later */
4215     [fVidEncoderPopUp removeAllItems];
4216     NSMenuItem *menuItem;
4217     /* These video encoders are available to all of our current muxers, so lets list them once here */
4218     menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"MPEG-4 (FFmpeg)" action: NULL keyEquivalent: @""];
4219     [menuItem setTag: HB_VCODEC_FFMPEG];
4220     
4221     switch( format )
4222     {
4223         case 0:
4224                         /*Get Default MP4 File Extension*/
4225                         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0)
4226                         {
4227                                 ext = "m4v";
4228                         }
4229                         else
4230                         {
4231                                 ext = "mp4";
4232                         }
4233             /* Add additional video encoders here */
4234             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"H.264 (x264)" action: NULL keyEquivalent: @""];
4235             [menuItem setTag: HB_VCODEC_X264];
4236             /* We show the mp4 option checkboxes here since we are mp4 */
4237             [fCreateChapterMarkers setEnabled: YES];
4238                         [fDstMp4LargeFileCheck setHidden: NO];
4239                         [fDstMp4HttpOptFileCheck setHidden: NO];
4240             [fDstMp4iPodFileCheck setHidden: NO];
4241             break;
4242             
4243             case 1:
4244             ext = "mkv";
4245             /* Add additional video encoders here */
4246             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"H.264 (x264)" action: NULL keyEquivalent: @""];
4247             [menuItem setTag: HB_VCODEC_X264];
4248             menuItem = [[fVidEncoderPopUp menu] addItemWithTitle:@"VP3 (Theora)" action: NULL keyEquivalent: @""];
4249             [menuItem setTag: HB_VCODEC_THEORA];
4250             /* We enable the create chapters checkbox here */
4251                         [fCreateChapterMarkers setEnabled: YES];
4252                         break;
4253             
4254
4255     }
4256     /* tell fSubtitlesDelegate we have a new video container */
4257     
4258     [fSubtitlesDelegate containerChanged:[[fDstFormatPopUp selectedItem] tag]];
4259     [fSubtitlesTable reloadData];
4260     /* if we have a previously selected vid encoder tag, then try to select it */
4261     if (selectedVidEncoderTag)
4262     {
4263         [fVidEncoderPopUp selectItemWithTag: selectedVidEncoderTag];
4264     }
4265     else
4266     {
4267         [fVidEncoderPopUp selectItemAtIndex: 0];
4268     }
4269
4270     [self audioAddAudioTrackCodecs: fAudTrack1CodecPopUp];
4271     [self audioAddAudioTrackCodecs: fAudTrack2CodecPopUp];
4272     [self audioAddAudioTrackCodecs: fAudTrack3CodecPopUp];
4273     [self audioAddAudioTrackCodecs: fAudTrack4CodecPopUp];
4274
4275     if( format == 0 )
4276         [self autoSetM4vExtension: sender];
4277     else
4278         [fDstFile2Field setStringValue: [NSString stringWithFormat:@"%@.%s", [string stringByDeletingPathExtension], ext]];
4279
4280     if( SuccessfulScan )
4281     {
4282         /* Add/replace to the correct extension */
4283         [self audioTrackPopUpChanged: fAudLang1PopUp];
4284         [self audioTrackPopUpChanged: fAudLang2PopUp];
4285         [self audioTrackPopUpChanged: fAudLang3PopUp];
4286         [self audioTrackPopUpChanged: fAudLang4PopUp];
4287
4288         if( [fVidEncoderPopUp selectedItem] == nil )
4289         {
4290
4291             [fVidEncoderPopUp selectItemAtIndex:0];
4292             [self videoEncoderPopUpChanged:nil];
4293
4294             /* changing the format may mean that we can / can't offer mono or 6ch, */
4295             /* so call audioTrackPopUpChanged for both audio tracks to update the mixdown popups */
4296
4297             /* We call the method to properly enable/disable turbo 2 pass */
4298             [self twoPassCheckboxChanged: sender];
4299             /* We call method method to change UI to reflect whether a preset is used or not*/
4300         }
4301     }
4302         [self customSettingUsed: sender];
4303 }
4304
4305 - (IBAction) autoSetM4vExtension: (id) sender
4306 {
4307     if ( [fDstFormatPopUp indexOfSelectedItem] )
4308         return;
4309
4310     NSString * extension = @"mp4";
4311
4312     if( [[fAudTrack1CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack2CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
4313                                                         [[fAudTrack3CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
4314                                                         [[fAudTrack4CodecPopUp selectedItem] tag] == HB_ACODEC_AC3 ||
4315                                                         [fCreateChapterMarkers state] == NSOnState ||
4316                                                         [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultMpegName"] > 0 )
4317     {
4318         extension = @"m4v";
4319     }
4320
4321     if( [extension isEqualTo: [[fDstFile2Field stringValue] pathExtension]] )
4322         return;
4323     else
4324         [fDstFile2Field setStringValue: [NSString stringWithFormat:@"%@.%@",
4325                                     [[fDstFile2Field stringValue] stringByDeletingPathExtension], extension]];
4326 }
4327
4328 /* Method to determine if we should change the UI
4329 To reflect whether or not a Preset is being used or if
4330 the user is using "Custom" settings by determining the sender*/
4331 - (IBAction) customSettingUsed: (id) sender
4332 {
4333         if ([sender stringValue])
4334         {
4335                 /* Deselect the currently selected Preset if there is one*/
4336                 [fPresetsOutlineView deselectRow:[fPresetsOutlineView selectedRow]];
4337                 /* Change UI to show "Custom" settings are being used */
4338                 [fPresetSelectedDisplay setStringValue: @"Custom"];
4339
4340                 curUserPresetChosenNum = nil;
4341         }
4342 [self calculateBitrate:nil];
4343 }
4344
4345
4346 #pragma mark -
4347 #pragma mark - Video
4348
4349 - (IBAction) videoEncoderPopUpChanged: (id) sender
4350 {
4351     hb_job_t * job = fTitle->job;
4352     int videoEncoder = [[fVidEncoderPopUp selectedItem] tag];
4353     
4354     [fAdvancedOptions setHidden:YES];
4355     /* If we are using x264 then show the x264 advanced panel*/
4356     if (videoEncoder == HB_VCODEC_X264)
4357     {
4358         [fAdvancedOptions setHidden:NO];
4359         [self autoSetM4vExtension: sender];
4360     }
4361     
4362     /* We need to set loose anamorphic as available depending on whether or not the ffmpeg encoder
4363     is being used as it borks up loose anamorphic .
4364     For convenience lets use the titleOfSelected index. Probably should revisit whether or not we want
4365     to use the index itself but this is easier */
4366     if (videoEncoder == HB_VCODEC_FFMPEG)
4367     {
4368         if (job->anamorphic.mode == 2)
4369         {
4370             job->anamorphic.mode = 0;
4371         }
4372         [fPictureController setAllowLooseAnamorphic:NO];
4373         /* We set the iPod atom checkbox to disabled and uncheck it as its only for x264 in the mp4
4374          container. Format is taken care of in formatPopUpChanged method by hiding and unchecking
4375          anything other than MP4.
4376          */ 
4377         [fDstMp4iPodFileCheck setEnabled: NO];
4378         [fDstMp4iPodFileCheck setState: NSOffState];
4379     }
4380     else
4381     {
4382         [fPictureController setAllowLooseAnamorphic:YES];
4383         [fDstMp4iPodFileCheck setEnabled: YES];
4384     }
4385     [self setupQualitySlider];
4386         [self calculatePictureSizing: sender];
4387         [self twoPassCheckboxChanged: sender];
4388 }
4389
4390
4391 - (IBAction) twoPassCheckboxChanged: (id) sender
4392 {
4393         /* check to see if x264 is chosen */
4394         if([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_X264)
4395     {
4396                 if( [fVidTwoPassCheck state] == NSOnState)
4397                 {
4398                         [fVidTurboPassCheck setHidden: NO];
4399                 }
4400                 else
4401                 {
4402                         [fVidTurboPassCheck setHidden: YES];
4403                         [fVidTurboPassCheck setState: NSOffState];
4404                 }
4405                 /* Make sure Two Pass is checked if Turbo is checked */
4406                 if( [fVidTurboPassCheck state] == NSOnState)
4407                 {
4408                         [fVidTwoPassCheck setState: NSOnState];
4409                 }
4410         }
4411         else
4412         {
4413                 [fVidTurboPassCheck setHidden: YES];
4414                 [fVidTurboPassCheck setState: NSOffState];
4415         }
4416         
4417         /* We call method method to change UI to reflect whether a preset is used or not*/
4418         [self customSettingUsed: sender];
4419 }
4420
4421 - (IBAction ) videoFrameRateChanged: (id) sender
4422 {
4423     /* We call method method to calculatePictureSizing to error check detelecine*/
4424     [self calculatePictureSizing: sender];
4425
4426     /* We call method method to change UI to reflect whether a preset is used or not*/
4427         [self customSettingUsed: sender];
4428 }
4429 - (IBAction) videoMatrixChanged: (id) sender;
4430 {
4431     bool target, bitrate, quality;
4432
4433     target = bitrate = quality = false;
4434     if( [fVidQualityMatrix isEnabled] )
4435     {
4436         switch( [fVidQualityMatrix selectedRow] )
4437         {
4438             case 0:
4439                 target = true;
4440                 break;
4441             case 1:
4442                 bitrate = true;
4443                 break;
4444             case 2:
4445                 quality = true;
4446                 break;
4447         }
4448     }
4449     [fVidTargetSizeField  setEnabled: target];
4450     [fVidBitrateField     setEnabled: bitrate];
4451     [fVidQualitySlider    setEnabled: quality];
4452     [fVidQualityRFField   setEnabled: quality];
4453     [fVidQualityRFLabel    setEnabled: quality];
4454     [fVidTwoPassCheck     setEnabled: !quality &&
4455         [fVidQualityMatrix isEnabled]];
4456     if( quality )
4457     {
4458         [fVidTwoPassCheck setState: NSOffState];
4459                 [fVidTurboPassCheck setHidden: YES];
4460                 [fVidTurboPassCheck setState: NSOffState];
4461     }
4462
4463     [self qualitySliderChanged: sender];
4464     [self calculateBitrate: sender];
4465         [self customSettingUsed: sender];
4466 }
4467
4468 /* Use this method to setup the quality slider for cq/rf values depending on
4469  * the video encoder selected.
4470  */
4471 - (void) setupQualitySlider
4472 {
4473     /* Get the current slider maxValue to check for a change in slider scale later
4474      * so that we can choose a new similar value on the new slider scale */
4475     float previousMaxValue = [fVidQualitySlider maxValue];
4476     float previousPercentOfSliderScale = [fVidQualitySlider floatValue] / ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue] + 1);
4477     NSString * qpRFLabelString = @"QP:";
4478     /* x264 0-51 */
4479     if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_X264)
4480     {
4481         [fVidQualitySlider setMinValue:0.0];
4482         [fVidQualitySlider setMaxValue:51.0];
4483         /* As x264 allows for qp/rf values that are fractional, we get the value from the preferences */
4484         int fractionalGranularity = 1 / [[NSUserDefaults standardUserDefaults] floatForKey:@"x264CqSliderFractional"];
4485         [fVidQualitySlider setNumberOfTickMarks:(([fVidQualitySlider maxValue] - [fVidQualitySlider minValue]) * fractionalGranularity) + 1];
4486         if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultCrf"] > 0)
4487         {
4488             qpRFLabelString = @"RF:";
4489         }
4490     }
4491     /* ffmpeg  1-31 */
4492     if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_FFMPEG )
4493     {
4494         [fVidQualitySlider setMinValue:1.0];
4495         [fVidQualitySlider setMaxValue:31.0];
4496         [fVidQualitySlider setNumberOfTickMarks:31];
4497     }
4498     /* Theora 0-63 */
4499     if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_THEORA)
4500     {
4501         [fVidQualitySlider setMinValue:0.0];
4502         [fVidQualitySlider setMaxValue:63.0];
4503         [fVidQualitySlider setNumberOfTickMarks:64];
4504     }
4505     [fVidQualityRFLabel setStringValue:qpRFLabelString];
4506     
4507     /* check to see if we have changed slider scales */
4508     if (previousMaxValue != [fVidQualitySlider maxValue])
4509     {
4510         /* if so, convert the old setting to the new scale as close as possible based on percentages */
4511         float rf =  ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue] + 1) * previousPercentOfSliderScale;
4512         [fVidQualitySlider setFloatValue:rf];
4513     }
4514     
4515     [self qualitySliderChanged:nil];
4516 }
4517
4518 - (IBAction) qualitySliderChanged: (id) sender
4519 {
4520     /* Our constant quality slider is in a range based
4521      * on each encoders qp/rf values. The range depends
4522      * on the encoder. Also, the range is inverse of quality
4523      * for all of the encoders *except* for theora
4524      * (ie. as the "quality" goes up, the cq or rf value
4525      * actually goes down). Since the IB sliders always set
4526      * their max value at the right end of the slider, we
4527      * will calculate the inverse, so as the slider floatValue
4528      * goes up, we will show the inverse in the rf field
4529      * so, the floatValue at the right for x264 would be 51
4530      * and our rf field needs to show 0 and vice versa.
4531      */
4532     
4533     float sliderRfInverse = ([fVidQualitySlider maxValue] - [fVidQualitySlider floatValue]) + [fVidQualitySlider minValue];
4534     /* If the encoder is theora, use the float, otherwise use the inverse float*/
4535     float sliderRfToPercent;
4536     if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_THEORA)
4537     {
4538         [fVidQualityRFField setStringValue: [NSString stringWithFormat: @"%.2f", [fVidQualitySlider floatValue]]];
4539         sliderRfToPercent = [fVidQualityRFField floatValue] / ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue]);   
4540     }
4541     else
4542     {
4543         [fVidQualityRFField setStringValue: [NSString stringWithFormat: @"%.2f", sliderRfInverse]];
4544         sliderRfToPercent = ( ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue])  - ([fVidQualityRFField floatValue] - [fVidQualitySlider minValue])) / ([fVidQualitySlider maxValue] - [fVidQualitySlider minValue]);
4545     }
4546     [fVidConstantCell setTitle: [NSString stringWithFormat:
4547                                  NSLocalizedString( @"Constant quality: %.2f %%", @"" ), 100 * sliderRfToPercent]];
4548     
4549     [self customSettingUsed: sender];
4550 }
4551
4552 - (void) controlTextDidChange: (NSNotification *) notification
4553 {
4554     [self calculateBitrate:nil];
4555 }
4556
4557 - (IBAction) calculateBitrate: (id) sender
4558 {
4559     if( !fHandle || [fVidQualityMatrix selectedRow] != 0 || !SuccessfulScan )
4560     {
4561         return;
4562     }
4563
4564     hb_list_t  * list  = hb_get_titles( fHandle );
4565     hb_title_t * title = (hb_title_t *) hb_list_item( list,
4566             [fSrcTitlePopUp indexOfSelectedItem] );
4567     hb_job_t * job = title->job;
4568     hb_audio_config_t * audio;
4569     /* For  hb_calc_bitrate in addition to the Target Size in MB out of the
4570      * Target Size Field, we also need the job info for the Muxer, the Chapters
4571      * as well as all of the audio track info.
4572      * This used to be accomplished by simply calling prepareJob here, however
4573      * since the resilient queue sets the queue array values instead of the job
4574      * values directly, we duplicate the old prepareJob code here for the variables
4575      * needed
4576      */
4577     job->chapter_start = [fSrcChapterStartPopUp indexOfSelectedItem] + 1;
4578     job->chapter_end = [fSrcChapterEndPopUp indexOfSelectedItem] + 1; 
4579     job->mux = [[fDstFormatPopUp selectedItem] tag];
4580     
4581     /* Audio goes here */
4582     int audiotrack_count = hb_list_count(job->list_audio);
4583     for( int i = 0; i < audiotrack_count;i++)
4584     {
4585         hb_audio_t * temp_audio = (hb_audio_t*) hb_list_item( job->list_audio, 0 );
4586         hb_list_rem(job->list_audio, temp_audio);
4587     }
4588     /* Now we need our audio info here for each track if applicable */
4589     if ([fAudLang1PopUp indexOfSelectedItem] > 0)
4590     {
4591         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
4592         hb_audio_config_init(audio);
4593         audio->in.track = [fAudLang1PopUp indexOfSelectedItem] - 1;
4594         /* We go ahead and assign values to our audio->out.<properties> */
4595         audio->out.track = [fAudLang1PopUp indexOfSelectedItem] - 1;
4596         audio->out.codec = [[fAudTrack1CodecPopUp selectedItem] tag];
4597         audio->out.mixdown = [[fAudTrack1MixPopUp selectedItem] tag];
4598         audio->out.bitrate = [[fAudTrack1BitratePopUp selectedItem] tag];
4599         audio->out.samplerate = [[fAudTrack1RatePopUp selectedItem] tag];
4600         audio->out.dynamic_range_compression = [fAudTrack1DrcField floatValue];
4601         
4602         hb_audio_add( job, audio );
4603         free(audio);
4604     }  
4605     if ([fAudLang2PopUp indexOfSelectedItem] > 0)
4606     {
4607         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
4608         hb_audio_config_init(audio);
4609         audio->in.track = [fAudLang2PopUp indexOfSelectedItem] - 1;
4610         /* We go ahead and assign values to our audio->out.<properties> */
4611         audio->out.track = [fAudLang2PopUp indexOfSelectedItem] - 1;
4612         audio->out.codec = [[fAudTrack2CodecPopUp selectedItem] tag];
4613         audio->out.mixdown = [[fAudTrack2MixPopUp selectedItem] tag];
4614         audio->out.bitrate = [[fAudTrack2BitratePopUp selectedItem] tag];
4615         audio->out.samplerate = [[fAudTrack2RatePopUp selectedItem] tag];
4616         audio->out.dynamic_range_compression = [fAudTrack2DrcField floatValue];
4617         
4618         hb_audio_add( job, audio );
4619         free(audio);
4620         
4621     }
4622     
4623     if ([fAudLang3PopUp indexOfSelectedItem] > 0)
4624     {
4625         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
4626         hb_audio_config_init(audio);
4627         audio->in.track = [fAudLang3PopUp indexOfSelectedItem] - 1;
4628         /* We go ahead and assign values to our audio->out.<properties> */
4629         audio->out.track = [fAudLang3PopUp indexOfSelectedItem] - 1;
4630         audio->out.codec = [[fAudTrack3CodecPopUp selectedItem] tag];
4631         audio->out.mixdown = [[fAudTrack3MixPopUp selectedItem] tag];
4632         audio->out.bitrate = [[fAudTrack3BitratePopUp selectedItem] tag];
4633         audio->out.samplerate = [[fAudTrack3RatePopUp selectedItem] tag];
4634         audio->out.dynamic_range_compression = [fAudTrack3DrcField floatValue];
4635         
4636         hb_audio_add( job, audio );
4637         free(audio);
4638         
4639     }
4640
4641     if ([fAudLang4PopUp indexOfSelectedItem] > 0)
4642     {
4643         audio = (hb_audio_config_t *) calloc(1, sizeof(*audio));
4644         hb_audio_config_init(audio);
4645         audio->in.track = [fAudLang4PopUp indexOfSelectedItem] - 1;
4646         /* We go ahead and assign values to our audio->out.<properties> */
4647         audio->out.track = [fAudLang4PopUp indexOfSelectedItem] - 1;
4648         audio->out.codec = [[fAudTrack4CodecPopUp selectedItem] tag];
4649         audio->out.mixdown = [[fAudTrack4MixPopUp selectedItem] tag];
4650         audio->out.bitrate = [[fAudTrack4BitratePopUp selectedItem] tag];
4651         audio->out.samplerate = [[fAudTrack4RatePopUp selectedItem] tag];
4652         audio->out.dynamic_range_compression = [fAudTrack4DrcField floatValue];
4653         
4654         hb_audio_add( job, audio );
4655         free(audio);
4656         
4657     }
4658        
4659 [fVidBitrateField setIntValue: hb_calc_bitrate( job, [fVidTargetSizeField intValue] )];
4660 }
4661
4662 #pragma mark -
4663 #pragma mark - Picture
4664
4665 /* lets set the picture size back to the max from right after title scan
4666    Lets use an IBAction here as down the road we could always use a checkbox
4667    in the gui to easily take the user back to max. Remember, the compiler
4668    resolves IBActions down to -(void) during compile anyway */
4669 - (IBAction) revertPictureSizeToMax: (id) sender
4670 {
4671         hb_job_t * job = fTitle->job;
4672         /* Here we apply the title source and height */
4673     job->width = fTitle->width;
4674     job->height = fTitle->height;
4675     
4676     [self calculatePictureSizing: sender];
4677     /* We call method to change UI to reflect whether a preset is used or not*/    
4678     [self customSettingUsed: sender];
4679 }
4680
4681 /**
4682  * Registers changes made in the Picture Settings Window.
4683  */
4684
4685 - (void)pictureSettingsDidChange 
4686 {
4687         [self calculatePictureSizing:nil];
4688 }
4689
4690 /* Get and Display Current Pic Settings in main window */
4691 - (IBAction) calculatePictureSizing: (id) sender
4692 {
4693         if (fTitle->job->anamorphic.mode > 0)
4694         {
4695         fTitle->job->keep_ratio = 0;
4696         }
4697     
4698     [fPictureSizeField setStringValue: [NSString stringWithFormat:@"Picture Size: %@", [fPictureController getPictureSizeInfoString]]];
4699     
4700     NSString *picCropping;
4701     /* Set the display field for crop as per boolean */
4702         if (![fPictureController autoCrop])
4703         {
4704         picCropping =  @"Custom";
4705         }
4706         else
4707         {
4708                 picCropping =  @"Auto";
4709         }
4710     picCropping = [picCropping stringByAppendingString:[NSString stringWithFormat:@" %d/%d/%d/%d",fTitle->job->crop[0],fTitle->job->crop[1],fTitle->job->crop[2],fTitle->job->crop[3]]];
4711     
4712     [fPictureCroppingField setStringValue: [NSString stringWithFormat:@"Picture Cropping: %@",picCropping]];
4713     
4714     NSString *videoFilters;
4715     videoFilters = @"";
4716     /* Detelecine */
4717     if ([fPictureController detelecine] == 1) 
4718     {
4719         videoFilters = [videoFilters stringByAppendingString:@" - Detelecine (Default)"];
4720     }
4721     else if ([fPictureController detelecine] == 2) 
4722     {
4723         videoFilters = [videoFilters stringByAppendingString:[NSString stringWithFormat:@" - Detelecine (%@)",[fPictureController detelecineCustomString]]];
4724     }
4725     
4726     
4727     if ([fPictureController useDecomb] == 1)
4728     {
4729         /* Decomb */
4730         if ([fPictureController decomb] == 1)
4731         {
4732             videoFilters = [videoFilters stringByAppendingString:@" - Decomb (Default)"];
4733         }
4734         else if ([fPictureController decomb] == 2)
4735         {
4736             videoFilters = [videoFilters stringByAppendingString:[NSString stringWithFormat:@" - Decomb (%@)",[fPictureController decombCustomString]]];
4737         }
4738     }
4739     else
4740     {
4741         /* Deinterlace */
4742         if ([fPictureController deinterlace] > 0)
4743         {
4744             fTitle->job->deinterlace  = 1;
4745         }
4746         else
4747         {
4748             fTitle->job->deinterlace  = 0;
4749         }
4750         
4751         if ([fPictureController deinterlace] == 1)
4752         {
4753             videoFilters = [videoFilters stringByAppendingString:@" - Deinterlace (Fast)"];
4754         }
4755         else if ([fPictureController deinterlace] == 2)
4756         {
4757             videoFilters = [videoFilters stringByAppendingString:@" - Deinterlace (Slow)"];
4758         }
4759         else if ([fPictureController deinterlace] == 3)
4760         {
4761             videoFilters = [videoFilters stringByAppendingString:@" - Deinterlace (Slower)"];
4762         }
4763         else if ([fPictureController deinterlace] == 4)
4764         {
4765             videoFilters = [videoFilters stringByAppendingString:[NSString stringWithFormat:@" - Deinterlace (%@)",[fPictureController deinterlaceCustomString]]];
4766         }
4767         }
4768     
4769     
4770     /* Denoise */
4771         if ([fPictureController denoise] == 1)
4772         {
4773                 videoFilters = [videoFilters stringByAppendingString:@" - Denoise (Weak)"];
4774     }
4775         else if ([fPictureController denoise] == 2)
4776         {
4777                 videoFilters = [videoFilters stringByAppendingString:@" - Denoise (Medium)"];
4778     }
4779         else if ([fPictureController denoise] == 3)
4780         {
4781                 videoFilters = [videoFilters stringByAppendingString:@" - Denoise (Strong)"];
4782         }
4783     else if ([fPictureController denoise] == 4)
4784         {
4785                 videoFilters = [videoFilters stringByAppendingString:[NSString stringWithFormat:@" - Denoise (%@)",[fPictureController denoiseCustomString]]];
4786         }
4787     
4788     /* Deblock */
4789     if ([fPictureController deblock] > 0) 
4790     {
4791         videoFilters = [videoFilters stringByAppendingString:[NSString stringWithFormat:@" - Deblock (%d)",[fPictureController deblock]]];
4792     }
4793         
4794     /* Grayscale */
4795     if ([fPictureController grayscale]) 
4796     {
4797         videoFilters = [videoFilters stringByAppendingString:@" - Grayscale"];
4798     }
4799     [fVideoFiltersField setStringValue: [NSString stringWithFormat:@"Video Filters: %@", videoFilters]];
4800     
4801     //[fPictureController reloadStillPreview]; 
4802 }
4803
4804
4805 #pragma mark -
4806 #pragma mark - Audio and Subtitles
4807 - (IBAction) audioCodecsPopUpChanged: (id) sender
4808 {
4809     
4810     NSPopUpButton * audiotrackPopUp;
4811     NSPopUpButton * sampleratePopUp;
4812     NSPopUpButton * bitratePopUp;
4813     NSPopUpButton * audiocodecPopUp;
4814     if (sender == fAudTrack1CodecPopUp)
4815     {
4816         audiotrackPopUp = fAudLang1PopUp;
4817         audiocodecPopUp = fAudTrack1CodecPopUp;
4818         sampleratePopUp = fAudTrack1RatePopUp;
4819         bitratePopUp = fAudTrack1BitratePopUp;
4820     }
4821     else if (sender == fAudTrack2CodecPopUp)
4822     {
4823         audiotrackPopUp = fAudLang2PopUp;
4824         audiocodecPopUp = fAudTrack2CodecPopUp;
4825         sampleratePopUp = fAudTrack2RatePopUp;
4826         bitratePopUp = fAudTrack2BitratePopUp;
4827     }
4828     else if (sender == fAudTrack3CodecPopUp)
4829     {
4830         audiotrackPopUp = fAudLang3PopUp;
4831         audiocodecPopUp = fAudTrack3CodecPopUp;
4832         sampleratePopUp = fAudTrack3RatePopUp;
4833         bitratePopUp = fAudTrack3BitratePopUp;
4834     }
4835     else
4836     {
4837         audiotrackPopUp = fAudLang4PopUp;
4838         audiocodecPopUp = fAudTrack4CodecPopUp;
4839         sampleratePopUp = fAudTrack4RatePopUp;
4840         bitratePopUp = fAudTrack4BitratePopUp;
4841     }
4842         
4843     /* changing the codecs on offer may mean that we can / can't offer mono or 6ch, */
4844         /* so call audioTrackPopUpChanged for both audio tracks to update the mixdown popups */
4845     [self audioTrackPopUpChanged: audiotrackPopUp];
4846     
4847 }
4848
4849 - (IBAction) setEnabledStateOfAudioMixdownControls: (id) sender
4850 {
4851     /* We will be setting the enabled/disabled state of each tracks audio controls based on
4852      * the settings of the source audio for that track. We leave the samplerate and bitrate
4853      * to audiotrackMixdownChanged
4854      */
4855     
4856     /* We will first verify that a lower track number has been selected before enabling each track
4857      * for example, make sure a track is selected for track 1 before enabling track 2, etc.
4858      */
4859     if ([fAudLang1PopUp indexOfSelectedItem] == 0)
4860     {
4861         [fAudLang2PopUp setEnabled: NO];
4862         [fAudLang2PopUp selectItemAtIndex: 0];
4863     }
4864     else
4865     {
4866         [fAudLang2PopUp setEnabled: YES];
4867     }
4868     
4869     if ([fAudLang2PopUp indexOfSelectedItem] == 0)
4870     {
4871         [fAudLang3PopUp setEnabled: NO];
4872         [fAudLang3PopUp selectItemAtIndex: 0];
4873     }
4874     else
4875     {
4876         [fAudLang3PopUp setEnabled: YES];
4877     }
4878     if ([fAudLang3PopUp indexOfSelectedItem] == 0)
4879     {
4880         [fAudLang4PopUp setEnabled: NO];
4881         [fAudLang4PopUp selectItemAtIndex: 0];
4882     }
4883     else
4884     {
4885         [fAudLang4PopUp setEnabled: YES];
4886     }
4887     /* enable/disable the mixdown text and popupbutton for audio track 1 */
4888     [fAudTrack1CodecPopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
4889     [fAudTrack1MixPopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
4890     [fAudTrack1RatePopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
4891     [fAudTrack1BitratePopUp setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
4892     [fAudTrack1DrcSlider setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
4893     [fAudTrack1DrcField setEnabled: ([fAudLang1PopUp indexOfSelectedItem] == 0) ? NO : YES];
4894     if ([fAudLang1PopUp indexOfSelectedItem] == 0)
4895     {
4896         [fAudTrack1CodecPopUp removeAllItems];
4897         [fAudTrack1MixPopUp removeAllItems];
4898         [fAudTrack1RatePopUp removeAllItems];
4899         [fAudTrack1BitratePopUp removeAllItems];
4900         [fAudTrack1DrcSlider setFloatValue: 1.00];
4901         [self audioDRCSliderChanged: fAudTrack1DrcSlider];
4902     }
4903     else if ([[fAudTrack1MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack1MixPopUp selectedItem] tag] == HB_ACODEC_DCA)
4904     {
4905         [fAudTrack1RatePopUp setEnabled: NO];
4906         [fAudTrack1BitratePopUp setEnabled: NO];
4907         [fAudTrack1DrcSlider setEnabled: NO];
4908         [fAudTrack1DrcField setEnabled: NO];
4909     }
4910     
4911     /* enable/disable the mixdown text and popupbutton for audio track 2 */
4912     [fAudTrack2CodecPopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
4913     [fAudTrack2MixPopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
4914     [fAudTrack2RatePopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
4915     [fAudTrack2BitratePopUp setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
4916     [fAudTrack2DrcSlider setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
4917     [fAudTrack2DrcField setEnabled: ([fAudLang2PopUp indexOfSelectedItem] == 0) ? NO : YES];
4918     if ([fAudLang2PopUp indexOfSelectedItem] == 0)
4919     {
4920         [fAudTrack2CodecPopUp removeAllItems];
4921         [fAudTrack2MixPopUp removeAllItems];
4922         [fAudTrack2RatePopUp removeAllItems];
4923         [fAudTrack2BitratePopUp removeAllItems];
4924         [fAudTrack2DrcSlider setFloatValue: 1.00];
4925         [self audioDRCSliderChanged: fAudTrack2DrcSlider];
4926     }
4927     else if ([[fAudTrack2MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack2MixPopUp selectedItem] tag] == HB_ACODEC_DCA)
4928     {
4929         [fAudTrack2RatePopUp setEnabled: NO];
4930         [fAudTrack2BitratePopUp setEnabled: NO];
4931         [fAudTrack2DrcSlider setEnabled: NO];
4932         [fAudTrack2DrcField setEnabled: NO];
4933     }
4934     
4935     /* enable/disable the mixdown text and popupbutton for audio track 3 */
4936     [fAudTrack3CodecPopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
4937     [fAudTrack3MixPopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
4938     [fAudTrack3RatePopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
4939     [fAudTrack3BitratePopUp setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
4940     [fAudTrack3DrcSlider setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
4941     [fAudTrack3DrcField setEnabled: ([fAudLang3PopUp indexOfSelectedItem] == 0) ? NO : YES];
4942     if ([fAudLang3PopUp indexOfSelectedItem] == 0)
4943     {
4944         [fAudTrack3CodecPopUp removeAllItems];
4945         [fAudTrack3MixPopUp removeAllItems];
4946         [fAudTrack3RatePopUp removeAllItems];
4947         [fAudTrack3BitratePopUp removeAllItems];
4948         [fAudTrack3DrcSlider setFloatValue: 1.00];
4949         [self audioDRCSliderChanged: fAudTrack3DrcSlider];
4950     }
4951     else if ([[fAudTrack3MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack3MixPopUp selectedItem] tag] == HB_ACODEC_DCA)
4952     {
4953         [fAudTrack3RatePopUp setEnabled: NO];
4954         [fAudTrack3BitratePopUp setEnabled: NO];
4955         [fAudTrack3DrcSlider setEnabled: NO];
4956         [fAudTrack3DrcField setEnabled: NO];
4957     }
4958     
4959     /* enable/disable the mixdown text and popupbutton for audio track 4 */
4960     [fAudTrack4CodecPopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
4961     [fAudTrack4MixPopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
4962     [fAudTrack4RatePopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
4963     [fAudTrack4BitratePopUp setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
4964     [fAudTrack4DrcSlider setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
4965     [fAudTrack4DrcField setEnabled: ([fAudLang4PopUp indexOfSelectedItem] == 0) ? NO : YES];
4966     if ([fAudLang4PopUp indexOfSelectedItem] == 0)
4967     {
4968         [fAudTrack4CodecPopUp removeAllItems];
4969         [fAudTrack4MixPopUp removeAllItems];
4970         [fAudTrack4RatePopUp removeAllItems];
4971         [fAudTrack4BitratePopUp removeAllItems];
4972         [fAudTrack4DrcSlider setFloatValue: 1.00];
4973         [self audioDRCSliderChanged: fAudTrack4DrcSlider];
4974     }
4975     else if ([[fAudTrack4MixPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[fAudTrack4MixPopUp selectedItem] tag] == HB_ACODEC_DCA)
4976     {
4977         [fAudTrack4RatePopUp setEnabled: NO];
4978         [fAudTrack4BitratePopUp setEnabled: NO];
4979         [fAudTrack4DrcSlider setEnabled: NO];
4980         [fAudTrack4DrcField setEnabled: NO];
4981     }
4982     
4983 }
4984
4985 - (IBAction) addAllAudioTracksToPopUp: (id) sender
4986 {
4987
4988     hb_list_t  * list  = hb_get_titles( fHandle );
4989     hb_title_t * title = (hb_title_t*)
4990         hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] );
4991
4992         hb_audio_config_t * audio;
4993
4994     [sender removeAllItems];
4995     [sender addItemWithTitle: NSLocalizedString( @"None", @"" )];
4996     for( int i = 0; i < hb_list_count( title->list_audio ); i++ )
4997     {
4998         audio = (hb_audio_config_t *) hb_list_audio_config_item( title->list_audio, i );
4999         [[sender menu] addItemWithTitle:
5000             [NSString stringWithCString: audio->lang.description]
5001             action: NULL keyEquivalent: @""];
5002     }
5003     [sender selectItemAtIndex: 0];
5004
5005 }
5006
5007 - (IBAction) selectAudioTrackInPopUp: (id) sender searchPrefixString: (NSString *) searchPrefixString selectIndexIfNotFound: (int) selectIndexIfNotFound
5008 {
5009
5010     /* this method can be used to find a language, or a language-and-source-format combination, by passing in the appropriate string */
5011     /* e.g. to find the first French track, pass in an NSString * of "Francais" */
5012     /* e.g. to find the first English 5.1 AC3 track, pass in an NSString * of "English (AC3) (5.1 ch)" */
5013     /* if no matching track is found, then selectIndexIfNotFound is used to choose which track to select instead */
5014
5015         if (searchPrefixString)
5016         {
5017
5018         for( int i = 0; i < [sender numberOfItems]; i++ )
5019         {
5020             /* Try to find the desired search string */
5021             if ([[[sender itemAtIndex: i] title] hasPrefix:searchPrefixString])
5022             {
5023                 [sender selectItemAtIndex: i];
5024                 return;
5025             }
5026         }
5027         /* couldn't find the string, so select the requested "search string not found" item */
5028         /* index of 0 means select the "none" item */
5029         /* index of 1 means select the first audio track */
5030         [sender selectItemAtIndex: selectIndexIfNotFound];
5031         }
5032     else
5033     {
5034         /* if no search string is provided, then select the selectIndexIfNotFound item */
5035         [sender selectItemAtIndex: selectIndexIfNotFound];
5036     }
5037
5038 }
5039 - (IBAction) audioAddAudioTrackCodecs: (id)sender
5040 {
5041     int format = [fDstFormatPopUp indexOfSelectedItem];
5042     
5043     /* setup pointers to the appropriate popups for the correct track */
5044     NSPopUpButton * audiocodecPopUp;
5045     NSPopUpButton * audiotrackPopUp;
5046     if (sender == fAudTrack1CodecPopUp)
5047     {
5048         audiotrackPopUp = fAudLang1PopUp;
5049         audiocodecPopUp = fAudTrack1CodecPopUp;
5050     }
5051     else if (sender == fAudTrack2CodecPopUp)
5052     {
5053         audiotrackPopUp = fAudLang2PopUp;
5054         audiocodecPopUp = fAudTrack2CodecPopUp;
5055     }
5056     else if (sender == fAudTrack3CodecPopUp)
5057     {
5058         audiotrackPopUp = fAudLang3PopUp;
5059         audiocodecPopUp = fAudTrack3CodecPopUp;
5060     }
5061     else
5062     {
5063         audiotrackPopUp = fAudLang4PopUp;
5064         audiocodecPopUp = fAudTrack4CodecPopUp;
5065     }
5066     
5067     [audiocodecPopUp removeAllItems];
5068     /* Make sure "None" isnt selected in the source track */
5069     if ([audiotrackPopUp indexOfSelectedItem] > 0)
5070     {
5071         [audiocodecPopUp setEnabled:YES];
5072         NSMenuItem *menuItem;
5073         /* We setup our appropriate popups for codecs and put the int value in the popup tag for easy retrieval */
5074         switch( format )
5075         {
5076             case 0:
5077                 /* MP4 */
5078                 // FAAC
5079                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""];
5080                 [menuItem setTag: HB_ACODEC_FAAC];
5081
5082                 // CA_AAC
5083                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (CoreAudio)" action: NULL keyEquivalent: @""];
5084                 [menuItem setTag: HB_ACODEC_CA_AAC];
5085
5086                 // AC3 Passthru
5087                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""];
5088                 [menuItem setTag: HB_ACODEC_AC3];
5089                 break;
5090                 
5091             case 1:
5092                 /* MKV */
5093                 // FAAC
5094                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""];
5095                 [menuItem setTag: HB_ACODEC_FAAC];
5096                 // CA_AAC
5097                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (CoreAudio)" action: NULL keyEquivalent: @""];
5098                 [menuItem setTag: HB_ACODEC_CA_AAC];
5099                 // AC3 Passthru
5100                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""];
5101                 [menuItem setTag: HB_ACODEC_AC3];
5102                 // DTS Passthru
5103                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"DTS Passthru" action: NULL keyEquivalent: @""];
5104                 [menuItem setTag: HB_ACODEC_DCA];
5105                 // MP3
5106                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""];
5107                 [menuItem setTag: HB_ACODEC_LAME];
5108                 // Vorbis
5109                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"Vorbis (vorbis)" action: NULL keyEquivalent: @""];
5110                 [menuItem setTag: HB_ACODEC_VORBIS];
5111                 break;
5112                 
5113             case 2: 
5114                 /* AVI */
5115                 // MP3
5116                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""];
5117                 [menuItem setTag: HB_ACODEC_LAME];
5118                 // AC3 Passthru
5119                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""];
5120                 [menuItem setTag: HB_ACODEC_AC3];
5121                 break;
5122                 
5123             case 3:
5124                 /* OGM */
5125                 // Vorbis
5126                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"Vorbis (vorbis)" action: NULL keyEquivalent: @""];
5127                 [menuItem setTag: HB_ACODEC_VORBIS];
5128                 // MP3
5129                 menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""];
5130                 [menuItem setTag: HB_ACODEC_LAME];
5131                 break;
5132         }
5133         [audiocodecPopUp selectItemAtIndex:0];
5134     }
5135     else
5136     {
5137         [audiocodecPopUp setEnabled:NO];
5138     }
5139 }
5140
5141 - (IBAction) audioTrackPopUpChanged: (id) sender
5142 {
5143     /* utility function to call audioTrackPopUpChanged without passing in a mixdown-to-use */
5144     [self audioTrackPopUpChanged: sender mixdownToUse: 0];
5145 }
5146
5147 - (IBAction) audioTrackPopUpChanged: (id) sender mixdownToUse: (int) mixdownToUse
5148 {
5149     
5150     /* make sure we have a selected title before continuing */
5151     if (fTitle == NULL) return;
5152     /* if the sender is the lanaguage popup and there is nothing in the codec popup, lets call
5153     * audioAddAudioTrackCodecs on the codec popup to populate it properly before moving on
5154     */
5155     if (sender == fAudLang1PopUp && [[fAudTrack1CodecPopUp menu] numberOfItems] == 0)
5156     {
5157         [self audioAddAudioTrackCodecs: fAudTrack1CodecPopUp];
5158     }
5159     if (sender == fAudLang2PopUp && [[fAudTrack2CodecPopUp menu] numberOfItems] == 0)
5160     {
5161         [self audioAddAudioTrackCodecs: fAudTrack2CodecPopUp];
5162     }
5163     if (sender == fAudLang3PopUp && [[fAudTrack3CodecPopUp menu] numberOfItems] == 0)
5164     {
5165         [self audioAddAudioTrackCodecs: fAudTrack3CodecPopUp];
5166     }
5167     if (sender == fAudLang4PopUp && [[fAudTrack4CodecPopUp menu] numberOfItems] == 0)
5168     {
5169         [self audioAddAudioTrackCodecs: fAudTrack4CodecPopUp];
5170     }
5171     
5172     /* Now lets make the sender the appropriate Audio Track popup from this point on */
5173     if (sender == fAudTrack1CodecPopUp || sender == fAudTrack1MixPopUp)
5174     {
5175         sender = fAudLang1PopUp;
5176     }
5177     if (sender == fAudTrack2CodecPopUp || sender == fAudTrack2MixPopUp)
5178     {
5179         sender = fAudLang2PopUp;
5180     }
5181     if (sender == fAudTrack3CodecPopUp || sender == fAudTrack3MixPopUp)
5182     {
5183         sender = fAudLang3PopUp;
5184     }
5185     if (sender == fAudTrack4CodecPopUp || sender == fAudTrack4MixPopUp)
5186     {
5187         sender = fAudLang4PopUp;
5188     }
5189     
5190     /* pointer to this track's mixdown, codec, sample rate and bitrate NSPopUpButton's */
5191     NSPopUpButton * mixdownPopUp;
5192     NSPopUpButton * audiocodecPopUp;
5193     NSPopUpButton * sampleratePopUp;
5194     NSPopUpButton * bitratePopUp;
5195     if (sender == fAudLang1PopUp)
5196     {
5197         mixdownPopUp = fAudTrack1MixPopUp;
5198         audiocodecPopUp = fAudTrack1CodecPopUp;
5199         sampleratePopUp = fAudTrack1RatePopUp;
5200         bitratePopUp = fAudTrack1BitratePopUp;
5201     }
5202     else if (sender == fAudLang2PopUp)
5203     {
5204         mixdownPopUp = fAudTrack2MixPopUp;
5205         audiocodecPopUp = fAudTrack2CodecPopUp;
5206         sampleratePopUp = fAudTrack2RatePopUp;
5207         bitratePopUp = fAudTrack2BitratePopUp;
5208     }
5209     else if (sender == fAudLang3PopUp)
5210     {
5211         mixdownPopUp = fAudTrack3MixPopUp;
5212         audiocodecPopUp = fAudTrack3CodecPopUp;
5213         sampleratePopUp = fAudTrack3RatePopUp;
5214         bitratePopUp = fAudTrack3BitratePopUp;
5215     }
5216     else
5217     {
5218         mixdownPopUp = fAudTrack4MixPopUp;
5219         audiocodecPopUp = fAudTrack4CodecPopUp;
5220         sampleratePopUp = fAudTrack4RatePopUp;
5221         bitratePopUp = fAudTrack4BitratePopUp;
5222     }
5223
5224     /* get the index of the selected audio Track*/
5225     int thisAudioIndex = [sender indexOfSelectedItem] - 1;
5226
5227     /* pointer for the hb_audio_s struct we will use later on */
5228     hb_audio_config_t * audio;
5229
5230     int acodec;
5231     /* check if the audio mixdown controls need their enabled state changing */
5232     [self setEnabledStateOfAudioMixdownControls:nil];
5233
5234     if (thisAudioIndex != -1)
5235     {
5236
5237         /* get the audio */
5238         audio = (hb_audio_config_t *) hb_list_audio_config_item( fTitle->list_audio, thisAudioIndex );// Should "fTitle" be title and be setup ?
5239
5240         /* actually manipulate the proper mixdowns here */
5241         /* delete the previous audio mixdown options */
5242         [mixdownPopUp removeAllItems];
5243
5244         acodec = [[audiocodecPopUp selectedItem] tag];
5245
5246         if (audio != NULL)
5247         {
5248
5249             /* find out if our selected output audio codec supports mono and / or 6ch */
5250             /* we also check for an input codec of AC3 or DCA,
5251              as they are the only libraries able to do the mixdown to mono / conversion to 6-ch */
5252             /* audioCodecsSupportMono and audioCodecsSupport6Ch are the same for now,
5253              but this may change in the future, so they are separated for flexibility */
5254             int audioCodecsSupportMono =
5255                     (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
5256                     (acodec != HB_ACODEC_LAME);
5257             int audioCodecsSupport6Ch =
5258                     (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) &&
5259                     (acodec != HB_ACODEC_LAME);
5260             
5261             /* check for AC-3 passthru */
5262             if (audio->in.codec == HB_ACODEC_AC3 && acodec == HB_ACODEC_AC3)
5263             {
5264                 
5265             NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
5266                  [NSString stringWithCString: "AC3 Passthru"]
5267                                                action: NULL keyEquivalent: @""];
5268              [menuItem setTag: HB_ACODEC_AC3];   
5269             }
5270             else if (audio->in.codec == HB_ACODEC_DCA && acodec == HB_ACODEC_DCA)
5271             {
5272             NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
5273                  [NSString stringWithCString: "DTS Passthru"]
5274                                                action: NULL keyEquivalent: @""];
5275              [menuItem setTag: HB_ACODEC_DCA]; 
5276             }
5277             else
5278             {
5279                 
5280                 /* add the appropriate audio mixdown menuitems to the popupbutton */
5281                 /* in each case, we set the new menuitem's tag to be the amixdown value for that mixdown,
5282                  so that we can reference the mixdown later */
5283                 
5284                 /* keep a track of the min and max mixdowns we used, so we can select the best match later */
5285                 int minMixdownUsed = 0;
5286                 int maxMixdownUsed = 0;
5287                 
5288                 /* get the input channel layout without any lfe channels */
5289                 int layout = audio->in.channel_layout & HB_INPUT_CH_LAYOUT_DISCRETE_NO_LFE_MASK;
5290                 
5291                 /* do we want to add a mono option? */
5292                 if (audioCodecsSupportMono == 1)
5293                 {
5294                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
5295                                             [NSString stringWithCString: hb_audio_mixdowns[0].human_readable_name]
5296                                                                           action: NULL keyEquivalent: @""];
5297                     [menuItem setTag: hb_audio_mixdowns[0].amixdown];
5298                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[0].amixdown;
5299                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[0].amixdown);
5300                 }
5301                 
5302                 /* do we want to add a stereo option? */
5303                 /* offer stereo if we have a mono source and non-mono-supporting codecs, as otherwise we won't have a mixdown at all */
5304                 /* also offer stereo if we have a stereo-or-better source */
5305                 if ((layout == HB_INPUT_CH_LAYOUT_MONO && audioCodecsSupportMono == 0) || layout >= HB_INPUT_CH_LAYOUT_STEREO)
5306                 {
5307                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
5308                                             [NSString stringWithCString: hb_audio_mixdowns[1].human_readable_name]
5309                                                                           action: NULL keyEquivalent: @""];
5310                     [menuItem setTag: hb_audio_mixdowns[1].amixdown];
5311                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[1].amixdown;
5312                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[1].amixdown);
5313                 }
5314                 
5315                 /* do we want to add a dolby surround (DPL1) option? */
5316                 if (layout == HB_INPUT_CH_LAYOUT_3F1R || layout == HB_INPUT_CH_LAYOUT_3F2R || layout == HB_INPUT_CH_LAYOUT_DOLBY)
5317                 {
5318                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
5319                                             [NSString stringWithCString: hb_audio_mixdowns[2].human_readable_name]
5320                                                                           action: NULL keyEquivalent: @""];
5321                     [menuItem setTag: hb_audio_mixdowns[2].amixdown];
5322                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[2].amixdown;
5323                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[2].amixdown);
5324                 }
5325                 
5326                 /* do we want to add a dolby pro logic 2 (DPL2) option? */
5327                 if (layout == HB_INPUT_CH_LAYOUT_3F2R)
5328                 {
5329                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
5330                                             [NSString stringWithCString: hb_audio_mixdowns[3].human_readable_name]
5331                                                                           action: NULL keyEquivalent: @""];
5332                     [menuItem setTag: hb_audio_mixdowns[3].amixdown];
5333                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[3].amixdown;
5334                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[3].amixdown);
5335                 }
5336                 
5337                 /* do we want to add a 6-channel discrete option? */
5338                 if (audioCodecsSupport6Ch == 1 && layout == HB_INPUT_CH_LAYOUT_3F2R && (audio->in.channel_layout & HB_INPUT_CH_LAYOUT_HAS_LFE))
5339                 {
5340                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
5341                                             [NSString stringWithCString: hb_audio_mixdowns[4].human_readable_name]
5342                                                                           action: NULL keyEquivalent: @""];
5343                     [menuItem setTag: hb_audio_mixdowns[4].amixdown];
5344                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[4].amixdown;
5345                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[4].amixdown);
5346                 }
5347                 
5348                 /* do we want to add an AC-3 passthrough option? */
5349                 if (audio->in.codec == HB_ACODEC_AC3 && acodec == HB_ACODEC_AC3) 
5350                 {
5351                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
5352                                             [NSString stringWithCString: hb_audio_mixdowns[5].human_readable_name]
5353                                                                           action: NULL keyEquivalent: @""];
5354                     [menuItem setTag: HB_ACODEC_AC3];
5355                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[5].amixdown;
5356                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[5].amixdown);
5357                 }
5358                 
5359                 /* do we want to add a DTS Passthru option ? HB_ACODEC_DCA*/
5360                 if (audio->in.codec == HB_ACODEC_DCA && acodec == HB_ACODEC_DCA) 
5361                 {
5362                     NSMenuItem *menuItem = [[mixdownPopUp menu] addItemWithTitle:
5363                                             [NSString stringWithCString: hb_audio_mixdowns[5].human_readable_name]
5364                                                                           action: NULL keyEquivalent: @""];
5365                     [menuItem setTag: HB_ACODEC_DCA];
5366                     if (minMixdownUsed == 0) minMixdownUsed = hb_audio_mixdowns[5].amixdown;
5367                     maxMixdownUsed = MAX(maxMixdownUsed, hb_audio_mixdowns[5].amixdown);
5368                 }
5369                 
5370                 /* auto-select the best mixdown based on our saved mixdown preference */
5371                 
5372                 /* for now, this is hard-coded to a "best" mixdown of HB_AMIXDOWN_DOLBYPLII */
5373                 /* ultimately this should be a prefs option */
5374                 int useMixdown;
5375                 
5376                 /* if we passed in a mixdown to use - in order to load a preset - then try and use it */
5377                 if (mixdownToUse > 0)
5378                 {
5379                     useMixdown = mixdownToUse;
5380                 }
5381                 else
5382                 {
5383                     useMixdown = HB_AMIXDOWN_DOLBYPLII;
5384                 }
5385                 
5386                 /* if useMixdown > maxMixdownUsed, then use maxMixdownUsed */
5387                 if (useMixdown > maxMixdownUsed)
5388                 { 
5389                     useMixdown = maxMixdownUsed;
5390                 }
5391                 
5392                 /* if useMixdown < minMixdownUsed, then use minMixdownUsed */
5393                 if (useMixdown < minMixdownUsed)
5394                 { 
5395                     useMixdown = minMixdownUsed;
5396                 }
5397                 
5398                 /* select the (possibly-amended) preferred mixdown */
5399                 [mixdownPopUp selectItemWithTag: useMixdown];
5400
5401             }
5402             /* In the case of a source track that is not AC3 and the user tries to use AC3 Passthru (which does not work)
5403              * we force the Audio Codec choice back to a workable codec. We use MP3 for avi and aac for all
5404              * other containers.
5405              */
5406             if (audio->in.codec != HB_ACODEC_AC3 && [[audiocodecPopUp selectedItem] tag] == HB_ACODEC_AC3)
5407             {
5408                 /* If we are using the avi container, we select MP3 as there is no aac available*/
5409                 if ([[fDstFormatPopUp selectedItem] tag] == HB_MUX_AVI)
5410                 {
5411                     [audiocodecPopUp selectItemWithTag: HB_ACODEC_LAME];
5412                 }
5413                 else
5414                 {
5415                     [audiocodecPopUp selectItemWithTag: HB_ACODEC_FAAC];
5416                 }
5417             }
5418             
5419             /* In the case of a source track that is not DTS and the user tries to use DTS Passthru (which does not work)
5420              * we force the Audio Codec choice back to a workable codec. We use MP3 for avi and aac for all
5421              * other containers.
5422              */
5423             if (audio->in.codec != HB_ACODEC_DCA && [[audiocodecPopUp selectedItem] tag] == HB_ACODEC_DCA)
5424             {
5425                 /* If we are using the avi container, we select MP3 as there is no aac available*/
5426                 if ([[fDstFormatPopUp selectedItem] tag] == HB_MUX_AVI)
5427                 {
5428                     [audiocodecPopUp selectItemWithTag: HB_ACODEC_LAME];
5429                 }
5430                 else
5431                 {
5432                     [audiocodecPopUp selectItemWithTag: HB_ACODEC_FAAC];
5433                 }
5434             }
5435             
5436             /* Setup our samplerate and bitrate popups we will need based on mixdown */
5437             [self audioTrackMixdownChanged: mixdownPopUp];             
5438         }
5439     
5440     }
5441     if( [fDstFormatPopUp indexOfSelectedItem] == 0 )
5442     {
5443         [self autoSetM4vExtension: sender];
5444     }
5445 }
5446
5447 - (IBAction) audioTrackMixdownChanged: (id) sender
5448 {
5449     
5450     int acodec;
5451     /* setup pointers to all of the other audio track controls
5452     * we will need later
5453     */
5454     NSPopUpButton * mixdownPopUp;
5455     NSPopUpButton * sampleratePopUp;
5456     NSPopUpButton * bitratePopUp;
5457     NSPopUpButton * audiocodecPopUp;
5458     NSPopUpButton * audiotrackPopUp;
5459     NSSlider * drcSlider;
5460     NSTextField * drcField;
5461     if (sender == fAudTrack1MixPopUp)
5462     {
5463         audiotrackPopUp = fAudLang1PopUp;
5464         audiocodecPopUp = fAudTrack1CodecPopUp;
5465         mixdownPopUp = fAudTrack1MixPopUp;
5466         sampleratePopUp = fAudTrack1RatePopUp;
5467         bitratePopUp = fAudTrack1BitratePopUp;
5468         drcSlider = fAudTrack1DrcSlider;
5469         drcField = fAudTrack1DrcField;
5470     }
5471     else if (sender == fAudTrack2MixPopUp)
5472     {
5473         audiotrackPopUp = fAudLang2PopUp;
5474         audiocodecPopUp = fAudTrack2CodecPopUp;
5475         mixdownPopUp = fAudTrack2MixPopUp;
5476         sampleratePopUp = fAudTrack2RatePopUp;
5477         bitratePopUp = fAudTrack2BitratePopUp;
5478         drcSlider = fAudTrack2DrcSlider;
5479         drcField = fAudTrack2DrcField;
5480     }
5481     else if (sender == fAudTrack3MixPopUp)
5482     {
5483         audiotrackPopUp = fAudLang3PopUp;
5484         audiocodecPopUp = fAudTrack3CodecPopUp;
5485         mixdownPopUp = fAudTrack3MixPopUp;
5486         sampleratePopUp = fAudTrack3RatePopUp;
5487         bitratePopUp = fAudTrack3BitratePopUp;
5488         drcSlider = fAudTrack3DrcSlider;
5489         drcField = fAudTrack3DrcField;
5490     }
5491     else
5492     {
5493         audiotrackPopUp = fAudLang4PopUp;
5494         audiocodecPopUp = fAudTrack4CodecPopUp;
5495         mixdownPopUp = fAudTrack4MixPopUp;
5496         sampleratePopUp = fAudTrack4RatePopUp;
5497         bitratePopUp = fAudTrack4BitratePopUp;
5498         drcSlider = fAudTrack4DrcSlider;
5499         drcField = fAudTrack4DrcField;
5500     }
5501     acodec = [[audiocodecPopUp selectedItem] tag];
5502     /* storage variable for the min and max bitrate allowed for this codec */
5503     int minbitrate;
5504     int maxbitrate;
5505     
5506     switch( acodec )
5507     {
5508         case HB_ACODEC_FAAC:
5509             /* check if we have a 6ch discrete conversion in either audio track */
5510             if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
5511             {
5512                 /* FAAC is happy using our min bitrate of 32 kbps, even for 6ch */
5513                 minbitrate = 32;
5514                 /* If either mixdown popup includes 6-channel discrete, then allow up to 384 kbps */
5515                 maxbitrate = 384;
5516                 break;
5517             }
5518             else
5519             {
5520                 /* FAAC is happy using our min bitrate of 32 kbps for stereo or mono */
5521                 minbitrate = 32;
5522                 /* FAAC won't honour anything more than 160 for stereo, so let's not offer it */
5523                 /* note: haven't dealt with mono separately here, FAAC will just use the max it can */
5524                 maxbitrate = 160;
5525                 break;
5526             }
5527
5528         case HB_ACODEC_CA_AAC:
5529             /* check if we have a 6ch discrete conversion in either audio track */
5530             if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
5531             {
5532                 minbitrate = 128;
5533                 maxbitrate = 768;
5534                 break;
5535             }
5536             else
5537             {
5538                 minbitrate = 64;
5539                 maxbitrate = 320;
5540                 break;
5541             }
5542
5543             case HB_ACODEC_LAME:
5544             /* Lame is happy using our min bitrate of 32 kbps */
5545             minbitrate = 32;
5546             /* Lame won't encode if the bitrate is higher than 320 kbps */
5547             maxbitrate = 320;
5548             break;
5549             
5550             case HB_ACODEC_VORBIS:
5551             if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
5552             {
5553                 /* Vorbis causes a crash if we use a bitrate below 192 kbps with 6 channel */
5554                 minbitrate = 192;
5555                 /* If either mixdown popup includes 6-channel discrete, then allow up to 384 kbps */
5556                 maxbitrate = 384;
5557                 break;
5558             }
5559             else
5560             {
5561                 /* Vorbis causes a crash if we use a bitrate below 48 kbps */
5562                 minbitrate = 48;
5563                 /* Vorbis can cope with 384 kbps quite happily, even for stereo */
5564                 maxbitrate = 384;
5565                 break;
5566             }
5567             
5568             default:
5569             /* AC3 passthru disables the bitrate dropdown anyway, so we might as well just use the min and max bitrate */
5570             minbitrate = 32;
5571             maxbitrate = 384;
5572             
5573     }
5574     
5575     /* make sure we have a selected title before continuing */
5576     if (fTitle == NULL) return;
5577     /* get the audio so we can find out what input rates are*/
5578     hb_audio_config_t * audio;
5579     audio = (hb_audio_config_t *) hb_list_audio_config_item( fTitle->list_audio, [audiotrackPopUp indexOfSelectedItem] - 1 );
5580     int inputbitrate = audio->in.bitrate / 1000;
5581     int inputsamplerate = audio->in.samplerate;
5582     
5583     if ([[mixdownPopUp selectedItem] tag] != HB_ACODEC_AC3 && [[mixdownPopUp selectedItem] tag] != HB_ACODEC_DCA)
5584     {
5585         [bitratePopUp removeAllItems];
5586         
5587         for( int i = 0; i < hb_audio_bitrates_count; i++ )
5588         {
5589             if (hb_audio_bitrates[i].rate >= minbitrate && hb_audio_bitrates[i].rate <= maxbitrate)
5590             {
5591                 /* add a new menuitem for this bitrate */
5592                 NSMenuItem *menuItem = [[bitratePopUp menu] addItemWithTitle:
5593                                         [NSString stringWithCString: hb_audio_bitrates[i].string]
5594                                                                       action: NULL keyEquivalent: @""];
5595                 /* set its tag to be the actual bitrate as an integer, so we can retrieve it later */
5596                 [menuItem setTag: hb_audio_bitrates[i].rate];
5597             }
5598         }
5599         
5600         /* select the default bitrate (but use 384 for 6-ch AAC) */
5601         if ([[mixdownPopUp selectedItem] tag] == HB_AMIXDOWN_6CH)
5602         {
5603             [bitratePopUp selectItemWithTag: 384];
5604         }
5605         else
5606         {
5607             [bitratePopUp selectItemWithTag: hb_audio_bitrates[hb_audio_bitrates_default].rate];
5608         }
5609     }
5610     /* populate and set the sample rate popup */
5611     /* Audio samplerate */
5612     [sampleratePopUp removeAllItems];
5613     /* we create a same as source selection (Auto) so that we can choose to use the input sample rate */
5614     NSMenuItem *menuItem = [[sampleratePopUp menu] addItemWithTitle: @"Auto" action: NULL keyEquivalent: @""];
5615     [menuItem setTag: inputsamplerate];
5616     
5617     for( int i = 0; i < hb_audio_rates_count; i++ )
5618     {
5619         NSMenuItem *menuItem = [[sampleratePopUp menu] addItemWithTitle:
5620                                 [NSString stringWithCString: hb_audio_rates[i].string]
5621                                                                  action: NULL keyEquivalent: @""];
5622         [menuItem setTag: hb_audio_rates[i].rate];
5623     }
5624     /* We use the input sample rate as the default sample rate as downsampling just makes audio worse
5625     * and there is no compelling reason to use anything else as default, though the users default
5626     * preset will likely override any setting chosen here.
5627     */
5628     [sampleratePopUp selectItemWithTag: inputsamplerate];
5629     
5630     
5631     /* Since AC3 Pass Thru and DTS Pass Thru uses the input bitrate and sample rate, we get the input tracks
5632     * bitrate and display it in the bitrate popup even though libhb happily ignores any bitrate input from
5633     * the gui. We do this for better user feedback in the audio tab as well as the queue for the most part
5634     */
5635     if ([[mixdownPopUp selectedItem] tag] == HB_ACODEC_AC3 || [[mixdownPopUp selectedItem] tag] == HB_ACODEC_DCA)
5636     {
5637         
5638         /* lets also set the bitrate popup to the input bitrate as thats what passthru will use */
5639         [bitratePopUp removeAllItems];
5640         NSMenuItem *menuItem = [[bitratePopUp menu] addItemWithTitle:
5641                                 [NSString stringWithFormat:@"%d", inputbitrate]
5642                                                               action: NULL keyEquivalent: @""];
5643         [menuItem setTag: inputbitrate];
5644         /* For ac3 passthru we disable the sample rate and bitrate popups as well as the drc slider*/
5645         [bitratePopUp setEnabled: NO];
5646         [sampleratePopUp setEnabled: NO];
5647         
5648         [drcSlider setFloatValue: 1.00];
5649         [self audioDRCSliderChanged: drcSlider];
5650         [drcSlider setEnabled: NO];
5651         [drcField setEnabled: NO];
5652     }
5653     else
5654     {
5655         [sampleratePopUp setEnabled: YES];
5656         [bitratePopUp setEnabled: YES];
5657         [drcSlider setEnabled: YES];
5658         [drcField setEnabled: YES];
5659     }
5660 [self calculateBitrate:nil];    
5661 }
5662
5663 - (IBAction) audioDRCSliderChanged: (id) sender
5664 {
5665     NSSlider * drcSlider;
5666     NSTextField * drcField;
5667     if (sender == fAudTrack1DrcSlider)
5668     {
5669         drcSlider = fAudTrack1DrcSlider;
5670         drcField = fAudTrack1DrcField;
5671     }
5672     else if (sender == fAudTrack2DrcSlider)
5673     {
5674         drcSlider = fAudTrack2DrcSlider;
5675         drcField = fAudTrack2DrcField;
5676     }
5677     else if (sender == fAudTrack3DrcSlider)
5678     {
5679         drcSlider = fAudTrack3DrcSlider;
5680         drcField = fAudTrack3DrcField;
5681     }
5682     else
5683     {
5684         drcSlider = fAudTrack4DrcSlider;
5685         drcField = fAudTrack4DrcField;
5686     }
5687     
5688     /* If we are between 0.0 and 1.0 on the slider, snap it to 1.0 */
5689     if ([drcSlider floatValue] > 0.0 && [drcSlider floatValue] < 1.0)
5690     {
5691         [drcSlider setFloatValue:1.0];
5692     }
5693     
5694     
5695     [drcField setStringValue: [NSString stringWithFormat: @"%.2f", [drcSlider floatValue]]];
5696     /* For now, do not call this until we have an intelligent way to determine audio track selections
5697     * compared to presets
5698     */
5699     //[self customSettingUsed: sender];
5700 }
5701
5702 #pragma mark -
5703
5704 - (IBAction) browseImportSrtFile: (id) sender
5705 {
5706
5707     NSOpenPanel * panel;
5708         
5709     panel = [NSOpenPanel openPanel];
5710     [panel setAllowsMultipleSelection: NO];
5711     [panel setCanChooseFiles: YES];
5712     [panel setCanChooseDirectories: NO ];
5713     NSString * sourceDirectory;
5714         if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastSrtImportDirectory"])
5715         {
5716                 sourceDirectory = [[NSUserDefaults standardUserDefaults] stringForKey:@"LastSrtImportDirectory"];
5717         }
5718         else
5719         {
5720                 sourceDirectory = @"~/Desktop";
5721                 sourceDirectory = [sourceDirectory stringByExpandingTildeInPath];
5722         }
5723     /* we open up the browse srt sheet here and call for browseImportSrtFileDone after the sheet is closed */
5724     NSArray *fileTypes = [NSArray arrayWithObjects:@"plist", @"srt", nil];
5725     [panel beginSheetForDirectory: sourceDirectory file: nil types: fileTypes
5726                    modalForWindow: fWindow modalDelegate: self
5727                    didEndSelector: @selector( browseImportSrtFileDone:returnCode:contextInfo: )
5728                       contextInfo: sender];
5729 }
5730
5731 - (void) browseImportSrtFileDone: (NSSavePanel *) sheet
5732                      returnCode: (int) returnCode contextInfo: (void *) contextInfo
5733 {
5734     if( returnCode == NSOKButton )
5735     {
5736         NSString *importSrtDirectory = [[sheet filename] stringByDeletingLastPathComponent];
5737         NSString *importSrtFilePath = [sheet filename];
5738         [[NSUserDefaults standardUserDefaults] setObject:importSrtDirectory forKey:@"LastSrtImportDirectory"];
5739         
5740         /* now pass the string off to fSubtitlesDelegate to add the srt file to the dropdown */
5741         [fSubtitlesDelegate createSubtitleSrtTrack:importSrtFilePath];
5742         
5743         [fSubtitlesTable reloadData];
5744         
5745     }
5746 }                                           
5747
5748 #pragma mark -
5749 #pragma mark Open New Windows
5750
5751 - (IBAction) openHomepage: (id) sender
5752 {
5753     [[NSWorkspace sharedWorkspace] openURL: [NSURL
5754         URLWithString:@"http://handbrake.fr/"]];
5755 }
5756
5757 - (IBAction) openForums: (id) sender
5758 {
5759     [[NSWorkspace sharedWorkspace] openURL: [NSURL
5760         URLWithString:@"http://handbrake.fr/forum/"]];
5761 }
5762 - (IBAction) openUserGuide: (id) sender
5763 {
5764     [[NSWorkspace sharedWorkspace] openURL: [NSURL
5765         URLWithString:@"http://handbrake.fr/trac/wiki/HandBrakeGuide"]];
5766 }
5767
5768 /**
5769  * Shows debug output window.
5770  */
5771 - (IBAction)showDebugOutputPanel:(id)sender
5772 {
5773     [outputPanel showOutputPanel:sender];
5774 }
5775
5776 /**
5777  * Shows preferences window.
5778  */
5779 - (IBAction) showPreferencesWindow: (id) sender
5780 {
5781     NSWindow * window = [fPreferencesController window];
5782     if (![window isVisible])
5783         [window center];
5784
5785     [window makeKeyAndOrderFront: nil];
5786 }
5787
5788 /**
5789  * Shows queue window.
5790  */
5791 - (IBAction) showQueueWindow:(id)sender
5792 {
5793     [fQueueController showQueueWindow:sender];
5794 }
5795
5796
5797 - (IBAction) toggleDrawer:(id)sender {
5798     [fPresetDrawer toggle:self];
5799 }
5800
5801 /**
5802  * Shows Picture Settings Window.
5803  */
5804
5805 - (IBAction) showPicturePanel: (id) sender
5806 {
5807         [fPictureController showPictureWindow:sender];
5808 }
5809
5810 - (void) picturePanelFullScreen
5811 {
5812         [fPictureController setToFullScreenMode];
5813 }
5814
5815 - (void) picturePanelWindowed
5816 {
5817         [fPictureController setToWindowedMode];
5818 }
5819
5820 - (IBAction) showPreviewWindow: (id) sender
5821 {
5822         [fPictureController showPreviewWindow:sender];
5823 }
5824
5825 #pragma mark -
5826 #pragma mark Preset Outline View Methods
5827 #pragma mark - Required
5828 /* These are required by the NSOutlineView Datasource Delegate */
5829
5830
5831 /* used to specify the number of levels to show for each item */
5832 - (int)outlineView:(NSOutlineView *)fPresetsOutlineView numberOfChildrenOfItem:(id)item
5833 {
5834     /* currently use no levels to test outline view viability */
5835     if (item == nil) // for an outline view the root level of the hierarchy is always nil
5836     {
5837         return [UserPresets count];
5838     }
5839     else
5840     {
5841         /* we need to return the count of the array in ChildrenArray for this folder */
5842         NSArray *children = nil;
5843         children = [item objectForKey:@"ChildrenArray"];
5844         if ([children count] > 0)
5845         {
5846             return [children count];
5847         }
5848         else
5849         {
5850             return 0;
5851         }
5852     }
5853 }
5854
5855 /* We use this to deterimine children of an item */
5856 - (id)outlineView:(NSOutlineView *)fPresetsOutlineView child:(NSInteger)index ofItem:(id)item
5857 {
5858     
5859     /* we need to return the count of the array in ChildrenArray for this folder */
5860     NSArray *children = nil;
5861     if (item == nil)
5862     {
5863         children = UserPresets;
5864     }
5865     else
5866     {
5867         if ([item objectForKey:@"ChildrenArray"])
5868         {
5869             children = [item objectForKey:@"ChildrenArray"];
5870         }
5871     }   
5872     if ((children == nil) || ( [children count] <= (NSUInteger) index))
5873     {
5874         return nil;
5875     }
5876     else
5877     {
5878         return [children objectAtIndex:index];
5879     }
5880     
5881     
5882     // We are only one level deep, so we can't be asked about children
5883     //NSAssert (NO, @"Presets View outlineView:child:ofItem: currently can't handle nested items.");
5884     //return nil;
5885 }
5886
5887 /* We use this to determine if an item should be expandable */
5888 - (BOOL)outlineView:(NSOutlineView *)fPresetsOutlineView isItemExpandable:(id)item
5889 {
5890     
5891     /* we need to return the count of the array in ChildrenArray for this folder */
5892     NSArray *children= nil;
5893     if (item == nil)
5894     {
5895         children = UserPresets;
5896     }
5897     else
5898     {
5899         if ([item objectForKey:@"ChildrenArray"])
5900         {
5901             children = [item objectForKey:@"ChildrenArray"];
5902         }
5903     }   
5904     
5905     /* To deterimine if an item should show a disclosure triangle
5906      * we could do it by the children count as so:
5907      * if ([children count] < 1)
5908      * However, lets leave the triangle show even if there are no
5909      * children to help indicate a folder, just like folder in the
5910      * finder can show a disclosure triangle even when empty
5911      */
5912     
5913     /* We need to determine if the item is a folder */
5914    if ([[item objectForKey:@"Folder"] intValue] == 1)
5915    {
5916         return YES;
5917     }
5918     else
5919     {
5920         return NO;
5921     }
5922     
5923 }
5924
5925 - (BOOL)outlineView:(NSOutlineView *)outlineView shouldExpandItem:(id)item
5926 {
5927     // Our outline view has no levels, but we can still expand every item. Doing so
5928     // just makes the row taller. See heightOfRowByItem below.
5929 //return ![(HBQueueOutlineView*)outlineView isDragging];
5930
5931 return YES;
5932 }
5933
5934
5935 /* Used to tell the outline view which information is to be displayed per item */
5936 - (id)outlineView:(NSOutlineView *)fPresetsOutlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
5937 {
5938         /* We have two columns right now, icon and PresetName */
5939         
5940     if ([[tableColumn identifier] isEqualToString:@"PresetName"])
5941     {
5942         return [item objectForKey:@"PresetName"];
5943     }
5944     else
5945     {
5946         //return @"";
5947         return nil;
5948     }
5949 }
5950
5951 - (id)outlineView:(NSOutlineView *)outlineView itemForPersistentObject:(id)object
5952 {
5953     return [NSKeyedUnarchiver unarchiveObjectWithData:object];
5954 }
5955 - (id)outlineView:(NSOutlineView *)outlineView persistentObjectForItem:(id)item
5956 {
5957     return [NSKeyedArchiver archivedDataWithRootObject:item];
5958 }
5959
5960 #pragma mark - Added Functionality (optional)
5961 /* Use to customize the font and display characteristics of the title cell */
5962 - (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
5963 {
5964     if ([[tableColumn identifier] isEqualToString:@"PresetName"])
5965     {
5966         NSFont *txtFont;
5967         NSColor *fontColor;
5968         NSColor *shadowColor;
5969         txtFont = [NSFont systemFontOfSize: [NSFont smallSystemFontSize]];
5970         /*check to see if its a selected row */
5971         if ([fPresetsOutlineView selectedRow] == [fPresetsOutlineView rowForItem:item])
5972         {
5973             
5974             fontColor = [NSColor blackColor];
5975             shadowColor = [NSColor colorWithDeviceRed:(127.0/255.0) green:(140.0/255.0) blue:(160.0/255.0) alpha:1.0];
5976         }
5977         else
5978         {
5979             if ([[item objectForKey:@"Type"] intValue] == 0)
5980             {
5981                 fontColor = [NSColor blueColor];
5982             }
5983             else // User created preset, use a black font
5984             {
5985                 fontColor = [NSColor blackColor];
5986             }
5987             /* check to see if its a folder */
5988             //if ([[item objectForKey:@"Folder"] intValue] == 1)
5989             //{
5990             //fontColor = [NSColor greenColor];
5991             //}
5992             
5993             
5994         }
5995         /* We use Bold Text for the HB Default */
5996         if ([[item objectForKey:@"Default"] intValue] == 1)// 1 is HB default
5997         {
5998             txtFont = [NSFont boldSystemFontOfSize: [NSFont smallSystemFontSize]];
5999         }
6000         /* We use Bold Text for the User Specified Default */
6001         if ([[item objectForKey:@"Default"] intValue] == 2)// 2 is User default
6002         {
6003             txtFont = [NSFont boldSystemFontOfSize: [NSFont smallSystemFontSize]];
6004         }
6005         
6006         
6007         [cell setTextColor:fontColor];
6008         [cell setFont:txtFont];
6009         
6010     }
6011 }
6012
6013 /* We use this to edit the name field in the outline view */
6014 - (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
6015 {
6016     if ([[tableColumn identifier] isEqualToString:@"PresetName"])
6017     {
6018         id theRecord;
6019         
6020         theRecord = item;
6021         [theRecord setObject:object forKey:@"PresetName"];
6022         
6023         [self sortPresets];
6024         
6025         [fPresetsOutlineView reloadData];
6026         /* We save all of the preset data here */
6027         [self savePreset];
6028     }
6029 }
6030 /* We use this to provide tooltips for the items in the presets outline view */
6031 - (NSString *)outlineView:(NSOutlineView *)fPresetsOutlineView toolTipForCell:(NSCell *)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn *)tc item:(id)item mouseLocation:(NSPoint)mouseLocation
6032 {
6033     //if ([[tc identifier] isEqualToString:@"PresetName"])
6034     //{
6035         /* initialize the tooltip contents variable */
6036         NSString *loc_tip;
6037         /* if there is a description for the preset, we show it in the tooltip */
6038         if ([item objectForKey:@"PresetDescription"])
6039         {
6040             loc_tip = [item objectForKey:@"PresetDescription"];
6041             return (loc_tip);
6042         }
6043         else
6044         {
6045             loc_tip = @"No description available";
6046         }
6047         return (loc_tip);
6048     //}
6049 }
6050
6051 #pragma mark -
6052 #pragma mark Preset Outline View Methods (dragging related)
6053
6054
6055 - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard
6056 {
6057         // Dragging is only allowed for custom presets.
6058     //[[[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]] objectForKey:@"Default"] intValue] != 1
6059         if ([[[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]] objectForKey:@"Type"] intValue] == 0) // 0 is built in preset
6060     {
6061         return NO;
6062     }
6063     // Don't retain since this is just holding temporaral drag information, and it is
6064     //only used during a drag!  We could put this in the pboard actually.
6065     fDraggedNodes = items;
6066     // Provide data for our custom type, and simple NSStrings.
6067     [pboard declareTypes:[NSArray arrayWithObjects: DragDropSimplePboardType, nil] owner:self];
6068     
6069     // the actual data doesn't matter since DragDropSimplePboardType drags aren't recognized by anyone but us!.
6070     [pboard setData:[NSData data] forType:DragDropSimplePboardType]; 
6071     
6072     return YES;
6073 }
6074
6075 - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
6076 {
6077         
6078         // Don't allow dropping ONTO an item since they can't really contain any children.
6079     
6080     BOOL isOnDropTypeProposal = index == NSOutlineViewDropOnItemIndex;
6081     if (isOnDropTypeProposal)
6082         return NSDragOperationNone;
6083     
6084     // Don't allow dropping INTO an item since they can't really contain any children as of yet.
6085         if (item != nil)
6086         {
6087                 index = [fPresetsOutlineView rowForItem: item] + 1;
6088                 item = nil;
6089         }
6090     
6091     // Don't allow dropping into the Built In Presets.
6092     if (index < presetCurrentBuiltInCount)
6093     {
6094         return NSDragOperationNone;
6095         index = MAX (index, presetCurrentBuiltInCount);
6096         }    
6097         
6098     [outlineView setDropItem:item dropChildIndex:index];
6099     return NSDragOperationGeneric;
6100 }
6101
6102
6103
6104 - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index
6105 {
6106     /* first, lets see if we are dropping into a folder */
6107     if ([[fPresetsOutlineView itemAtRow:index] objectForKey:@"Folder"] && [[[fPresetsOutlineView itemAtRow:index] objectForKey:@"Folder"] intValue] == 1) // if its a folder
6108         {
6109     NSMutableArray *childrenArray = [[NSMutableArray alloc] init];
6110     childrenArray = [[fPresetsOutlineView itemAtRow:index] objectForKey:@"ChildrenArray"];
6111     [childrenArray addObject:item];
6112     [[fPresetsOutlineView itemAtRow:index] setObject:[NSMutableArray arrayWithArray: childrenArray] forKey:@"ChildrenArray"];
6113     [childrenArray autorelease];
6114     }
6115     else // We are not, so we just move the preset into the existing array 
6116     {
6117         NSMutableIndexSet *moveItems = [NSMutableIndexSet indexSet];
6118         id obj;
6119         NSEnumerator *enumerator = [fDraggedNodes objectEnumerator];
6120         while (obj = [enumerator nextObject])
6121         {
6122             [moveItems addIndex:[UserPresets indexOfObject:obj]];
6123         }
6124         // Successful drop, lets rearrange the view and save it all
6125         [self moveObjectsInPresetsArray:UserPresets fromIndexes:moveItems toIndex: index];
6126     }
6127     [fPresetsOutlineView reloadData];
6128     [self savePreset];
6129     return YES;
6130 }
6131
6132 - (void)moveObjectsInPresetsArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex
6133 {
6134     NSUInteger index = [indexSet lastIndex];
6135     NSUInteger aboveInsertIndexCount = 0;
6136     
6137     NSUInteger removeIndex;
6138
6139     if (index >= insertIndex)
6140     {
6141         removeIndex = index + aboveInsertIndexCount;
6142         aboveInsertIndexCount++;
6143     }
6144     else
6145     {
6146         removeIndex = index;
6147         insertIndex--;
6148     }
6149
6150     id object = [[array objectAtIndex:removeIndex] retain];
6151     [array removeObjectAtIndex:removeIndex];
6152     [array insertObject:object atIndex:insertIndex];
6153     [object release];
6154
6155     index = [indexSet indexLessThanIndex:index];
6156 }
6157
6158
6159
6160 #pragma mark - Functional Preset NSOutlineView Methods
6161
6162 - (IBAction)selectPreset:(id)sender
6163 {
6164     
6165     if ([fPresetsOutlineView selectedRow] >= 0 && [[[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]] objectForKey:@"Folder"] intValue] != 1)
6166     {
6167         chosenPreset = [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]];
6168         [fPresetSelectedDisplay setStringValue:[chosenPreset objectForKey:@"PresetName"]];
6169         
6170         if ([[chosenPreset objectForKey:@"Default"] intValue] == 1)
6171         {
6172             [fPresetSelectedDisplay setStringValue:[NSString stringWithFormat:@"%@ (Default)", [chosenPreset objectForKey:@"PresetName"]]];
6173         }
6174         else
6175         {
6176             [fPresetSelectedDisplay setStringValue:[chosenPreset objectForKey:@"PresetName"]];
6177         }
6178         
6179         /* File Format */
6180         [fDstFormatPopUp selectItemWithTitle:[chosenPreset objectForKey:@"FileFormat"]];
6181         [self formatPopUpChanged:nil];
6182         
6183         /* Chapter Markers*/
6184         [fCreateChapterMarkers setState:[[chosenPreset objectForKey:@"ChapterMarkers"] intValue]];
6185         /* check to see if we have only one chapter */
6186         [self chapterPopUpChanged:nil];
6187         
6188         /* Allow Mpeg4 64 bit formatting +4GB file sizes */
6189         [fDstMp4LargeFileCheck setState:[[chosenPreset objectForKey:@"Mp4LargeFile"] intValue]];
6190         /* Mux mp4 with http optimization */
6191         [fDstMp4HttpOptFileCheck setState:[[chosenPreset objectForKey:@"Mp4HttpOptimize"] intValue]];
6192         
6193         /* Video encoder */
6194         [fVidEncoderPopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoEncoder"]];
6195         /* We set the advanced opt string here if applicable*/
6196         [fAdvancedOptions setOptions:[chosenPreset objectForKey:@"x264Option"]];
6197         
6198         /* Lets run through the following functions to get variables set there */
6199         [self videoEncoderPopUpChanged:nil];
6200         /* Set the state of ipod compatible with Mp4iPodCompatible. Only for x264*/
6201         [fDstMp4iPodFileCheck setState:[[chosenPreset objectForKey:@"Mp4iPodCompatible"] intValue]];
6202         [self calculateBitrate:nil];
6203         
6204         /* Video quality */
6205         [fVidQualityMatrix selectCellAtRow:[[chosenPreset objectForKey:@"VideoQualityType"] intValue] column:0];
6206         
6207         [fVidTargetSizeField setStringValue:[chosenPreset objectForKey:@"VideoTargetSize"]];
6208         [fVidBitrateField setStringValue:[chosenPreset objectForKey:@"VideoAvgBitrate"]];
6209         
6210         /* Since we are now using RF Values for the slider, we detect if the preset uses an old quality float.
6211          * So, check to see if the quality value is less than 1.0 which should indicate the old ".062" type
6212          * quality preset. Caveat: in the case of x264, where the RF scale starts at 0, it would misinterpret
6213          * a preset that uses 0.0 - 0.99 for RF as an old style preset. Not sure how to get around that one yet,
6214          * though it should be a corner case since it would pretty much be a preset for lossless encoding. */
6215         if ([[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue] < 1.0)
6216         {
6217             /* For the quality slider we need to convert the old percent's to the new rf scales */
6218             float rf =  (([fVidQualitySlider maxValue] - [fVidQualitySlider minValue]) * [[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue]);
6219             [fVidQualitySlider setFloatValue:rf];
6220             
6221         }
6222         else
6223         {
6224             /* Since theora's qp value goes up from left to right, we can just set the slider float value */
6225             if ([[fVidEncoderPopUp selectedItem] tag] == HB_VCODEC_THEORA)
6226             {
6227                 [fVidQualitySlider setFloatValue:[[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue]];
6228             }
6229             else
6230             {
6231                 /* since ffmpeg and x264 use an "inverted" slider (lower qp/rf values indicate a higher quality) we invert the value on the slider */
6232                 [fVidQualitySlider setFloatValue:([fVidQualitySlider maxValue] + [fVidQualitySlider minValue]) - [[chosenPreset objectForKey:@"VideoQualitySlider"] floatValue]];
6233             }
6234         }
6235         
6236         [self videoMatrixChanged:nil];
6237         
6238         /* Video framerate */
6239         /* For video preset video framerate, we want to make sure that Same as source does not conflict with the
6240          detected framerate in the fVidRatePopUp so we use index 0*/
6241         if ([[chosenPreset objectForKey:@"VideoFramerate"] isEqualToString:@"Same as source"])
6242         {
6243             [fVidRatePopUp selectItemAtIndex: 0];
6244         }
6245         else
6246         {
6247             [fVidRatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"VideoFramerate"]];
6248         }
6249         
6250         
6251         /* 2 Pass Encoding */
6252         [fVidTwoPassCheck setState:[[chosenPreset objectForKey:@"VideoTwoPass"] intValue]];
6253         [self twoPassCheckboxChanged:nil];
6254         
6255         /* Turbo 1st pass for 2 Pass Encoding */
6256         [fVidTurboPassCheck setState:[[chosenPreset objectForKey:@"VideoTurboTwoPass"] intValue]];
6257         
6258         /*Audio*/
6259         /* First we check to see if we are using the current audio track layout based on AudioList array */
6260         if ([chosenPreset objectForKey:@"AudioList"])
6261         {
6262             /* Populate the audio widgets based on the contents of the AudioList array */
6263             int i = 0;
6264             NSEnumerator *enumerator = [[chosenPreset objectForKey:@"AudioList"] objectEnumerator];
6265             id tempObject;
6266             while (tempObject = [enumerator nextObject])
6267             {
6268                 i++;
6269                 if( i == 1 )
6270                 {
6271                     if ([fAudLang1PopUp indexOfSelectedItem] == 0)
6272                     {
6273                         [fAudLang1PopUp selectItemAtIndex: 1];
6274                     }
6275                     [self audioTrackPopUpChanged: fAudLang1PopUp];
6276                     [fAudTrack1CodecPopUp selectItemWithTitle:[tempObject objectForKey:@"AudioEncoder"]];
6277                     /* check our pref for core audio and use it in place of faac if applicable */
6278                     if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && 
6279                         [[tempObject objectForKey:@"AudioEncoder"] isEqualToString: @"AAC (faac)"])
6280                     {
6281                         [fAudTrack1CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"];
6282                     }                    
6283                     
6284                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
6285                     [fAudTrack1MixPopUp selectItemWithTitle:[tempObject objectForKey:@"AudioMixdown"]];
6286                     /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
6287                      * mixdown*/
6288                     if  ([fAudTrack1MixPopUp selectedItem] == nil)
6289                     {
6290                         [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
6291                     }
6292                     [fAudTrack1RatePopUp selectItemWithTitle:[tempObject objectForKey:@"AudioSamplerate"]];
6293                     /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
6294                     if (![[tempObject objectForKey:@"AudioEncoder"] isEqualToString:@"AC3 Passthru"])
6295                     {
6296                         [fAudTrack1BitratePopUp selectItemWithTitle:[tempObject objectForKey:@"AudioBitrate"]];
6297                     }
6298                     [fAudTrack1DrcSlider setFloatValue:[[tempObject objectForKey:@"AudioTrackDRCSlider"] floatValue]];
6299                     [self audioDRCSliderChanged: fAudTrack1DrcSlider];
6300                 }
6301                 
6302                 if( i == 2 )
6303                 {
6304                     
6305                     if ([fAudLang2PopUp indexOfSelectedItem] == 0)
6306                     {
6307                         [fAudLang2PopUp selectItemAtIndex: 1];
6308                     }
6309                     [self audioTrackPopUpChanged: fAudLang2PopUp];
6310                     [fAudTrack2CodecPopUp selectItemWithTitle:[tempObject objectForKey:@"AudioEncoder"]];
6311                     /* check our pref for core audio and use it in place of faac if applicable */
6312                     if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && 
6313                         [[tempObject objectForKey:@"AudioEncoder"] isEqualToString: @"AAC (faac)"])
6314                     {
6315                         [fAudTrack2CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"];
6316                     }
6317                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
6318                     [fAudTrack2MixPopUp selectItemWithTitle:[tempObject objectForKey:@"AudioMixdown"]];
6319                     /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
6320                      * mixdown*/
6321                     if  ([fAudTrack2MixPopUp selectedItem] == nil)
6322                     {
6323                         [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
6324                     }
6325                     [fAudTrack2RatePopUp selectItemWithTitle:[tempObject objectForKey:@"AudioSamplerate"]];
6326                     /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
6327                     if (![[tempObject objectForKey:@"AudioEncoder"] isEqualToString:@"AC3 Passthru"])
6328                     {
6329                         [fAudTrack2BitratePopUp selectItemWithTitle:[tempObject objectForKey:@"AudioBitrate"]];
6330                     }
6331                     [fAudTrack2DrcSlider setFloatValue:[[tempObject objectForKey:@"AudioTrackDRCSlider"] floatValue]];
6332                     [self audioDRCSliderChanged: fAudTrack2DrcSlider];
6333                     
6334                 }
6335                 
6336             }
6337             
6338              /* We now cleanup any extra audio tracks that may have been previously set if we need to */
6339             
6340             if (i < 4)
6341             {
6342                 [fAudLang4PopUp selectItemAtIndex: 0];
6343                 [self audioTrackPopUpChanged: fAudLang4PopUp];
6344                 
6345                 if (i < 3)
6346                 {
6347                     [fAudLang3PopUp selectItemAtIndex: 0];
6348                     [self audioTrackPopUpChanged: fAudLang3PopUp];
6349                     
6350                     if (i < 2)
6351                     {
6352                         [fAudLang2PopUp selectItemAtIndex: 0];
6353                         [self audioTrackPopUpChanged: fAudLang2PopUp];
6354                     }
6355                 }
6356             }
6357             
6358         }
6359         else
6360         {
6361             if ([chosenPreset objectForKey:@"Audio1Track"] > 0)
6362             {
6363                 if ([fAudLang1PopUp indexOfSelectedItem] == 0)
6364                 {
6365                     [fAudLang1PopUp selectItemAtIndex: 1];
6366                 }
6367                 [self audioTrackPopUpChanged: fAudLang1PopUp];
6368                 [fAudTrack1CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Encoder"]];
6369                 /* check our pref for core audio and use it in place of faac if applicable */
6370                 if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && 
6371                     [[chosenPreset objectForKey:@"Audio1Encoder"] isEqualToString: @"AAC (faac)"])
6372                 {
6373                     [fAudTrack1CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"];
6374                 }
6375                 [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
6376                 [fAudTrack1MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Mixdown"]];
6377                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
6378                  * mixdown*/
6379                 if  ([fAudTrack1MixPopUp selectedItem] == nil)
6380                 {
6381                     [self audioTrackPopUpChanged: fAudTrack1CodecPopUp];
6382                 }
6383                 [fAudTrack1RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Samplerate"]];
6384                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
6385                 if (![[chosenPreset objectForKey:@"Audio1Encoder"] isEqualToString:@"AC3 Passthru"])
6386                 {
6387                     [fAudTrack1BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Bitrate"]];
6388                 }
6389                 [fAudTrack1DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio1TrackDRCSlider"] floatValue]];
6390                 [self audioDRCSliderChanged: fAudTrack1DrcSlider];
6391             }
6392             if ([chosenPreset objectForKey:@"Audio2Track"] > 0)
6393             {
6394                 if ([fAudLang2PopUp indexOfSelectedItem] == 0)
6395                 {
6396                     [fAudLang2PopUp selectItemAtIndex: 1];
6397                 }
6398                 [self audioTrackPopUpChanged: fAudLang2PopUp];
6399                 [fAudTrack2CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Encoder"]];
6400                 /* check our pref for core audio and use it in place of faac if applicable */
6401                 if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && 
6402                     [[chosenPreset objectForKey:@"Audio2Encoder"] isEqualToString: @"AAC (faac)"])
6403                 {
6404                     [fAudTrack2CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"];
6405                 }
6406                 [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
6407                 [fAudTrack2MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Mixdown"]];
6408                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
6409                  * mixdown*/
6410                 if  ([fAudTrack2MixPopUp selectedItem] == nil)
6411                 {
6412                     [self audioTrackPopUpChanged: fAudTrack2CodecPopUp];
6413                 }
6414                 [fAudTrack2RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Samplerate"]];
6415                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
6416                 if (![[chosenPreset objectForKey:@"Audio2Encoder"] isEqualToString:@"AC3 Passthru"])
6417                 {
6418                     [fAudTrack2BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Bitrate"]];
6419                 }
6420                 [fAudTrack2DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio2TrackDRCSlider"] floatValue]];
6421                 [self audioDRCSliderChanged: fAudTrack2DrcSlider];
6422             }
6423             if ([chosenPreset objectForKey:@"Audio3Track"] > 0)
6424             {
6425                 if ([fAudLang3PopUp indexOfSelectedItem] == 0)
6426                 {
6427                     [fAudLang3PopUp selectItemAtIndex: 1];
6428                 }
6429                 [self audioTrackPopUpChanged: fAudLang3PopUp];
6430                 [fAudTrack3CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Encoder"]];
6431                 /* check our pref for core audio and use it in place of faac if applicable */
6432                 if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && 
6433                     [[chosenPreset objectForKey:@"Audio3Encoder"] isEqualToString: @"AAC (faac)"])
6434                 {
6435                     [fAudTrack3CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"];
6436                 }
6437                 [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
6438                 [fAudTrack3MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Mixdown"]];
6439                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
6440                  * mixdown*/
6441                 if  ([fAudTrack3MixPopUp selectedItem] == nil)
6442                 {
6443                     [self audioTrackPopUpChanged: fAudTrack3CodecPopUp];
6444                 }
6445                 [fAudTrack3RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Samplerate"]];
6446                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
6447                 if (![[chosenPreset objectForKey:@"Audio3Encoder"] isEqualToString: @"AC3 Passthru"])
6448                 {
6449                     [fAudTrack3BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Bitrate"]];
6450                 }
6451                 [fAudTrack3DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio3TrackDRCSlider"] floatValue]];
6452                 [self audioDRCSliderChanged: fAudTrack3DrcSlider];
6453             }
6454             if ([chosenPreset objectForKey:@"Audio4Track"] > 0)
6455             {
6456                 if ([fAudLang4PopUp indexOfSelectedItem] == 0)
6457                 {
6458                     [fAudLang4PopUp selectItemAtIndex: 1];
6459                 }
6460                 [self audioTrackPopUpChanged: fAudLang4PopUp];
6461                 [fAudTrack4CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Encoder"]];
6462                 /* check our pref for core audio and use it in place of faac if applicable */
6463                 if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && 
6464                     [[chosenPreset objectForKey:@"Audio4Encoder"] isEqualToString: @"AAC (faac)"])
6465                 {
6466                     [fAudTrack4CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"];
6467                 }
6468                 [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
6469                 [fAudTrack4MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Mixdown"]];
6470                 /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default
6471                  * mixdown*/
6472                 if  ([fAudTrack4MixPopUp selectedItem] == nil)
6473                 {
6474                     [self audioTrackPopUpChanged: fAudTrack4CodecPopUp];
6475                 }
6476                 [fAudTrack4RatePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Samplerate"]];
6477                 /* We set the presets bitrate if it is *not* an AC3 track since that uses the input bitrate */
6478                 if (![[chosenPreset objectForKey:@"Audio4Encoder"] isEqualToString:@"AC3 Passthru"])
6479                 {
6480                     [fAudTrack4BitratePopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Bitrate"]];
6481                 }
6482                 [fAudTrack4DrcSlider setFloatValue:[[chosenPreset objectForKey:@"Audio4TrackDRCSlider"] floatValue]];
6483                 [self audioDRCSliderChanged: fAudTrack4DrcSlider];
6484             }
6485             
6486             /* We now cleanup any extra audio tracks that may have been previously set if we need to */
6487             
6488             if (![chosenPreset objectForKey:@"Audio2Track"] || [chosenPreset objectForKey:@"Audio2Track"] == 0)
6489             {
6490                 [fAudLang2PopUp selectItemAtIndex: 0];
6491                 [self audioTrackPopUpChanged: fAudLang2PopUp];
6492             }
6493             if (![chosenPreset objectForKey:@"Audio3Track"] || [chosenPreset objectForKey:@"Audio3Track"] > 0)
6494             {
6495                 [fAudLang3PopUp selectItemAtIndex: 0];
6496                 [self audioTrackPopUpChanged: fAudLang3PopUp];
6497             }
6498             if (![chosenPreset objectForKey:@"Audio4Track"] || [chosenPreset objectForKey:@"Audio4Track"] > 0)
6499             {
6500                 [fAudLang4PopUp selectItemAtIndex: 0];
6501                 [self audioTrackPopUpChanged: fAudLang4PopUp];
6502             }
6503         }
6504         
6505         /*Subtitles*/
6506         [fSubPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Subtitles"]];
6507         /* Forced Subtitles */
6508         [fSubForcedCheck setState:[[chosenPreset objectForKey:@"SubtitlesForced"] intValue]];
6509         
6510         /* Picture Settings */
6511         /* Note: objectForKey:@"UsesPictureSettings" refers to picture size, which encompasses:
6512          * height, width, keep ar, anamorphic and crop settings.
6513          * picture filters are handled separately below.
6514          */
6515         /* Check to see if the objectForKey:@"UsesPictureSettings is greater than 0, as 0 means use picture sizing "None" 
6516          * ( 2 is use max for source and 1 is use exact size when the preset was created ) and the 
6517          * preset completely ignores any picture sizing values in the preset.
6518          */
6519         if ([[chosenPreset objectForKey:@"UsesPictureSettings"]  intValue] > 0)
6520         {
6521             hb_job_t * job = fTitle->job;
6522             
6523             /* If Cropping is set to custom, then recall all four crop values from
6524              when the preset was created and apply them */
6525             if ([[chosenPreset objectForKey:@"PictureAutoCrop"]  intValue] == 0)
6526             {
6527                 [fPictureController setAutoCrop:NO];
6528                 
6529                 /* Here we use the custom crop values saved at the time the preset was saved */
6530                 job->crop[0] = [[chosenPreset objectForKey:@"PictureTopCrop"]  intValue];
6531                 job->crop[1] = [[chosenPreset objectForKey:@"PictureBottomCrop"]  intValue];
6532                 job->crop[2] = [[chosenPreset objectForKey:@"PictureLeftCrop"]  intValue];
6533                 job->crop[3] = [[chosenPreset objectForKey:@"PictureRightCrop"]  intValue];
6534                 
6535             }
6536             else /* if auto crop has been saved in preset, set to auto and use post scan auto crop */
6537             {
6538                 [fPictureController setAutoCrop:YES];
6539                 /* Here we use the auto crop values determined right after scan */
6540                 job->crop[0] = AutoCropTop;
6541                 job->crop[1] = AutoCropBottom;
6542                 job->crop[2] = AutoCropLeft;
6543                 job->crop[3] = AutoCropRight;
6544                 
6545             }
6546             
6547             
6548             /* Check to see if the objectForKey:@"UsesPictureSettings is 2 which is "Use Max for the source */
6549             if ([[chosenPreset objectForKey:@"UsesPictureSettings"]  intValue] == 2 || [[chosenPreset objectForKey:@"UsesMaxPictureSettings"]  intValue] == 1)
6550             {
6551                 /* Use Max Picture settings for whatever the dvd is.*/
6552                 [self revertPictureSizeToMax:nil];
6553                 job->keep_ratio = [[chosenPreset objectForKey:@"PictureKeepRatio"]  intValue];
6554                 if (job->keep_ratio == 1)
6555                 {
6556                     hb_fix_aspect( job, HB_KEEP_WIDTH );
6557                     if( job->height > fTitle->height )
6558                     {
6559                         job->height = fTitle->height;
6560                         hb_fix_aspect( job, HB_KEEP_HEIGHT );
6561                     }
6562                 }
6563                 job->anamorphic.mode = [[chosenPreset objectForKey:@"PicturePAR"]  intValue];
6564             }
6565             else // /* If not 0 or 2 we assume objectForKey:@"UsesPictureSettings is 1 which is "Use picture sizing from when the preset was set" */
6566             {
6567                 /* we check to make sure the presets width/height does not exceed the sources width/height */
6568                 if (fTitle->width < [[chosenPreset objectForKey:@"PictureWidth"]  intValue] || fTitle->height < [[chosenPreset objectForKey:@"PictureHeight"]  intValue])
6569                 {
6570                     /* if so, then we use the sources height and width to avoid scaling up */
6571                     //job->width = fTitle->width;
6572                     //job->height = fTitle->height;
6573                     [self revertPictureSizeToMax:nil];
6574                 }
6575                 else // source width/height is >= the preset height/width
6576                 {
6577                     /* we can go ahead and use the presets values for height and width */
6578                     job->width = [[chosenPreset objectForKey:@"PictureWidth"]  intValue];
6579                     job->height = [[chosenPreset objectForKey:@"PictureHeight"]  intValue];
6580                 }
6581                 job->keep_ratio = [[chosenPreset objectForKey:@"PictureKeepRatio"]  intValue];
6582                 if (job->keep_ratio == 1)
6583                 {
6584                     hb_fix_aspect( job, HB_KEEP_WIDTH );
6585                     if( job->height > fTitle->height )
6586                     {
6587                         job->height = fTitle->height;
6588                         hb_fix_aspect( job, HB_KEEP_HEIGHT );
6589                     }
6590                 }
6591                 job->anamorphic.mode = [[chosenPreset objectForKey:@"PicturePAR"]  intValue];
6592                 
6593             }
6594             
6595             
6596         }
6597         /* If the preset has an objectForKey:@"UsesPictureFilters", and handle the filters here */
6598         if ([chosenPreset objectForKey:@"UsesPictureFilters"] && [[chosenPreset objectForKey:@"UsesPictureFilters"]  intValue] > 0)
6599         {
6600             /* Filters */
6601             
6602             /* We only allow *either* Decomb or Deinterlace. So check for the PictureDecombDeinterlace key.
6603              * also, older presets may not have this key, in which case we also check to see if that preset had  PictureDecomb
6604              * specified, in which case we use decomb and ignore any possible Deinterlace settings as using both was less than
6605              * sane.
6606              */
6607             [fPictureController setUseDecomb:1];
6608             [fPictureController setDecomb:0];
6609             [fPictureController setDeinterlace:0];
6610             if ([[chosenPreset objectForKey:@"PictureDecombDeinterlace"] intValue] == 1 || [[chosenPreset objectForKey:@"PictureDecomb"] intValue] > 0)
6611             {
6612                 /* we are using decomb */
6613                 /* Decomb */
6614                 if ([[chosenPreset objectForKey:@"PictureDecomb"] intValue] > 0)
6615                 {
6616                     [fPictureController setDecomb:[[chosenPreset objectForKey:@"PictureDecomb"] intValue]];
6617                     
6618                     /* if we are using "Custom" in the decomb setting, also set the custom string*/
6619                     if ([[chosenPreset objectForKey:@"PictureDecomb"] intValue] == 2)
6620                     {
6621                         [fPictureController setDecombCustomString:[chosenPreset objectForKey:@"PictureDecombCustom"]];    
6622                     }
6623                 }
6624              }
6625             else
6626             {
6627                 /* We are using Deinterlace */
6628                 /* Deinterlace */
6629                 if ([[chosenPreset objectForKey:@"PictureDeinterlace"] intValue] > 0)
6630                 {
6631                     [fPictureController setUseDecomb:0];
6632                     [fPictureController setDeinterlace:[[chosenPreset objectForKey:@"PictureDeinterlace"] intValue]];
6633                     /* if we are using "Custom" in the deinterlace setting, also set the custom string*/
6634                     if ([[chosenPreset objectForKey:@"PictureDeinterlace"] intValue] == 4)
6635                     {
6636                         [fPictureController setDeinterlaceCustomString:[chosenPreset objectForKey:@"PictureDeinterlaceCustom"]];    
6637                     }
6638                 }
6639             }
6640             
6641             
6642             /* Detelecine */
6643             if ([[chosenPreset objectForKey:@"PictureDetelecine"] intValue] > 0)
6644             {
6645                 [fPictureController setDetelecine:[[chosenPreset objectForKey:@"PictureDetelecine"] intValue]];
6646                 /* if we are using "Custom" in the detelecine setting, also set the custom string*/
6647                 if ([[chosenPreset objectForKey:@"PictureDetelecine"] intValue] == 2)
6648                 {
6649                     [fPictureController setDetelecineCustomString:[chosenPreset objectForKey:@"PictureDetelecineCustom"]];    
6650                 }
6651             }
6652             else
6653             {
6654                 [fPictureController setDetelecine:0];
6655             }
6656             
6657             /* Denoise */
6658             if ([[chosenPreset objectForKey:@"PictureDenoise"] intValue] > 0)
6659             {
6660                 [fPictureController setDenoise:[[chosenPreset objectForKey:@"PictureDenoise"] intValue]];
6661                 /* if we are using "Custom" in the denoise setting, also set the custom string*/
6662                 if ([[chosenPreset objectForKey:@"PictureDenoise"] intValue] == 4)
6663                 {
6664                     [fPictureController setDenoiseCustomString:[chosenPreset objectForKey:@"PictureDenoiseCustom"]];    
6665                 }
6666             }
6667             else
6668             {
6669                 [fPictureController setDenoise:0];
6670             }   
6671             
6672             /* Deblock */
6673             if ([[chosenPreset objectForKey:@"PictureDeblock"] intValue] == 1)
6674             {
6675                 /* if its a one, then its the old on/off deblock, set on to 5*/
6676                 [fPictureController setDeblock:5];
6677             }
6678             else
6679             {
6680                 /* use the settings intValue */
6681                 [fPictureController setDeblock:[[chosenPreset objectForKey:@"PictureDeblock"] intValue]];
6682             }
6683             
6684             if ([[chosenPreset objectForKey:@"VideoGrayScale"] intValue] == 1)
6685             {
6686                 [fPictureController setGrayscale:1];
6687             }
6688             else
6689             {
6690                 [fPictureController setGrayscale:0];
6691             }
6692         }
6693         /* we call SetTitle: in fPictureController so we get an instant update in the Picture Settings window */
6694         [fPictureController SetTitle:fTitle];
6695         [fPictureController SetTitle:fTitle];
6696         [self calculatePictureSizing:nil];
6697     }
6698 }
6699
6700
6701 #pragma mark -
6702 #pragma mark Manage Presets
6703
6704 - (void) loadPresets {
6705         /* We declare the default NSFileManager into fileManager */
6706         NSFileManager * fileManager = [NSFileManager defaultManager];
6707         /*We define the location of the user presets file */
6708     UserPresetsFile = @"~/Library/Application Support/HandBrake/UserPresets.plist";
6709         UserPresetsFile = [[UserPresetsFile stringByExpandingTildeInPath]retain];
6710     /* We check for the presets.plist */
6711         if ([fileManager fileExistsAtPath:UserPresetsFile] == 0)
6712         {
6713                 [fileManager createFileAtPath:UserPresetsFile contents:nil attributes:nil];
6714         }
6715
6716         UserPresets = [[NSMutableArray alloc] initWithContentsOfFile:UserPresetsFile];
6717         if (nil == UserPresets)
6718         {
6719                 UserPresets = [[NSMutableArray alloc] init];
6720                 [self addFactoryPresets:nil];
6721         }
6722         [fPresetsOutlineView reloadData];
6723     
6724     [self checkBuiltInsForUpdates];
6725 }
6726
6727 - (void) checkBuiltInsForUpdates {
6728     
6729         BOOL updateBuiltInPresets = NO;
6730     int i = 0;
6731     NSEnumerator *enumerator = [UserPresets objectEnumerator];
6732     id tempObject;
6733     while (tempObject = [enumerator nextObject])
6734     {
6735         /* iterate through the built in presets to see if any have an old build number */
6736         NSMutableDictionary *thisPresetDict = tempObject;
6737         /*Key Type == 0 is built in, and key PresetBuildNumber is the build number it was created with */
6738         if ([[thisPresetDict objectForKey:@"Type"] intValue] == 0)              
6739         {
6740                         if (![thisPresetDict objectForKey:@"PresetBuildNumber"] || [[thisPresetDict objectForKey:@"PresetBuildNumber"] intValue] < [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] intValue])
6741             {
6742                 updateBuiltInPresets = YES;
6743             }   
6744                 }
6745         i++;
6746     }
6747     /* if we have built in presets to update, then do so AlertBuiltInPresetUpdate*/
6748     if ( updateBuiltInPresets == YES)
6749     {
6750         if( [[NSUserDefaults standardUserDefaults] boolForKey:@"AlertBuiltInPresetUpdate"] == YES)
6751         {
6752             /* Show an alert window that built in presets will be updated */
6753             /*On Screen Notification*/
6754             int status;
6755             NSBeep();
6756             status = NSRunAlertPanel(@"HandBrake has determined your built in presets are out of date...",@"HandBrake will now update your built-in presets.", @"OK", nil, nil);
6757             [NSApp requestUserAttention:NSCriticalRequest];
6758         }
6759         /* when alert is dismissed, go ahead and update the built in presets */
6760         [self addFactoryPresets:nil];
6761     }
6762     
6763 }
6764
6765
6766 - (IBAction) showAddPresetPanel: (id) sender
6767 {
6768     /* Deselect the currently selected Preset if there is one*/
6769     [fPresetsOutlineView deselectRow:[fPresetsOutlineView selectedRow]];
6770
6771     /* Populate the preset picture settings popup here */
6772     [fPresetNewPicSettingsPopUp removeAllItems];
6773     [fPresetNewPicSettingsPopUp addItemWithTitle:@"None"];
6774     [fPresetNewPicSettingsPopUp addItemWithTitle:@"Current"];
6775     [fPresetNewPicSettingsPopUp addItemWithTitle:@"Source Maximum (post source scan)"];
6776     [fPresetNewPicSettingsPopUp selectItemAtIndex: 0];  
6777     /* Uncheck the preset use filters checkbox */
6778     [fPresetNewPicFiltersCheck setState:NSOffState];
6779     // fPresetNewFolderCheck
6780     [fPresetNewFolderCheck setState:NSOffState];
6781     /* Erase info from the input fields*/
6782         [fPresetNewName setStringValue: @""];
6783         [fPresetNewDesc setStringValue: @""];
6784         /* Show the panel */
6785         [NSApp beginSheet:fAddPresetPanel modalForWindow:fWindow modalDelegate:nil didEndSelector:NULL contextInfo:NULL];
6786 }
6787
6788 - (IBAction) closeAddPresetPanel: (id) sender
6789 {
6790     [NSApp endSheet: fAddPresetPanel];
6791     [fAddPresetPanel orderOut: self];
6792 }
6793
6794 - (IBAction)addUserPreset:(id)sender
6795 {
6796     if (![[fPresetNewName stringValue] length])
6797             NSRunAlertPanel(@"Warning!", @"You need to insert a name for the preset.", @"OK", nil , nil);
6798     else
6799     {
6800         /* Here we create a custom user preset */
6801         [UserPresets addObject:[self createPreset]];
6802         [self addPreset];
6803
6804         [self closeAddPresetPanel:nil];
6805     }
6806 }
6807 - (void)addPreset
6808 {
6809
6810         
6811         /* We Reload the New Table data for presets */
6812     [fPresetsOutlineView reloadData];
6813    /* We save all of the preset data here */
6814     [self savePreset];
6815 }
6816
6817 - (void)sortPresets
6818 {
6819
6820         
6821         /* We Sort the Presets By Factory or Custom */
6822         NSSortDescriptor * presetTypeDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"Type" 
6823                                                     ascending:YES] autorelease];
6824         /* We Sort the Presets Alphabetically by name  We do not use this now as we have drag and drop*/
6825         /*
6826     NSSortDescriptor * presetNameDescriptor=[[[NSSortDescriptor alloc] initWithKey:@"PresetName" 
6827                                                     ascending:YES selector:@selector(caseInsensitiveCompare:)] autorelease];
6828         //NSArray *sortDescriptors=[NSArray arrayWithObjects:presetTypeDescriptor,presetNameDescriptor,nil];
6829     
6830     */
6831     /* Since we can drag and drop our custom presets, lets just sort by type and not name */
6832     NSArray *sortDescriptors=[NSArray arrayWithObjects:presetTypeDescriptor,nil];
6833         NSArray *sortedArray=[UserPresets sortedArrayUsingDescriptors:sortDescriptors];
6834         [UserPresets setArray:sortedArray];
6835         
6836
6837 }
6838
6839 - (IBAction)insertPreset:(id)sender
6840 {
6841     int index = [fPresetsOutlineView selectedRow];
6842     [UserPresets insertObject:[self createPreset] atIndex:index];
6843     [fPresetsOutlineView reloadData];
6844     [self savePreset];
6845 }
6846
6847 - (NSDictionary *)createPreset
6848 {
6849     NSMutableDictionary *preset = [[NSMutableDictionary alloc] init];
6850     /* Preset build number */
6851     [preset setObject:[NSString stringWithFormat: @"%d", [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] intValue]] forKey:@"PresetBuildNumber"];
6852     [preset setObject:[fPresetNewName stringValue] forKey:@"PresetName"];
6853         /* Get the New Preset Name from the field in the AddPresetPanel */
6854     [preset setObject:[fPresetNewName stringValue] forKey:@"PresetName"];
6855     /* Set whether or not this is to be a folder fPresetNewFolderCheck*/
6856     [preset setObject:[NSNumber numberWithBool:[fPresetNewFolderCheck state]] forKey:@"Folder"];
6857         /*Set whether or not this is a user preset or factory 0 is factory, 1 is user*/
6858         [preset setObject:[NSNumber numberWithInt:1] forKey:@"Type"];
6859         /*Set whether or not this is default, at creation set to 0*/
6860         [preset setObject:[NSNumber numberWithInt:0] forKey:@"Default"];
6861     if ([fPresetNewFolderCheck state] == YES)
6862     {
6863         /* initialize and set an empty array for children here since we are a new folder */
6864         NSMutableArray *childrenArray = [[NSMutableArray alloc] init];
6865         [preset setObject:[NSMutableArray arrayWithArray: childrenArray] forKey:@"ChildrenArray"];
6866         [childrenArray autorelease];
6867     }
6868     else // we are not creating a preset folder, so we go ahead with the rest of the preset info
6869     {
6870         /*Get the whether or not to apply pic Size and Cropping (includes Anamorphic)*/
6871         [preset setObject:[NSNumber numberWithInt:[fPresetNewPicSettingsPopUp indexOfSelectedItem]] forKey:@"UsesPictureSettings"];
6872         /* Get whether or not to use the current Picture Filter settings for the preset */
6873         [preset setObject:[NSNumber numberWithInt:[fPresetNewPicFiltersCheck state]] forKey:@"UsesPictureFilters"];
6874         
6875         /* Get New Preset Description from the field in the AddPresetPanel*/
6876         [preset setObject:[fPresetNewDesc stringValue] forKey:@"PresetDescription"];
6877         /* File Format */
6878         [preset setObject:[fDstFormatPopUp titleOfSelectedItem] forKey:@"FileFormat"];
6879         /* Chapter Markers fCreateChapterMarkers*/
6880         [preset setObject:[NSNumber numberWithInt:[fCreateChapterMarkers state]] forKey:@"ChapterMarkers"];
6881         /* Allow Mpeg4 64 bit formatting +4GB file sizes */
6882         [preset setObject:[NSNumber numberWithInt:[fDstMp4LargeFileCheck state]] forKey:@"Mp4LargeFile"];
6883         /* Mux mp4 with http optimization */
6884         [preset setObject:[NSNumber numberWithInt:[fDstMp4HttpOptFileCheck state]] forKey:@"Mp4HttpOptimize"];
6885         /* Add iPod uuid atom */
6886         [preset setObject:[NSNumber numberWithInt:[fDstMp4iPodFileCheck state]] forKey:@"Mp4iPodCompatible"];
6887         
6888         /* Codecs */
6889         /* Video encoder */
6890         [preset setObject:[fVidEncoderPopUp titleOfSelectedItem] forKey:@"VideoEncoder"];
6891         /* x264 Option String */
6892         [preset setObject:[fAdvancedOptions optionsString] forKey:@"x264Option"];
6893         
6894         [preset setObject:[NSNumber numberWithInt:[fVidQualityMatrix selectedRow]] forKey:@"VideoQualityType"];
6895         [preset setObject:[fVidTargetSizeField stringValue] forKey:@"VideoTargetSize"];
6896         [preset setObject:[fVidBitrateField stringValue] forKey:@"VideoAvgBitrate"];
6897         [preset setObject:[NSNumber numberWithFloat:[fVidQualityRFField floatValue]] forKey:@"VideoQualitySlider"];
6898         
6899         /* Video framerate */
6900         if ([fVidRatePopUp indexOfSelectedItem] == 0) // Same as source is selected
6901         {
6902             [preset setObject:@"Same as source" forKey:@"VideoFramerate"];
6903         }
6904         else // we can record the actual titleOfSelectedItem
6905         {
6906             [preset setObject:[fVidRatePopUp titleOfSelectedItem] forKey:@"VideoFramerate"];
6907         }
6908         
6909         /* 2 Pass Encoding */
6910         [preset setObject:[NSNumber numberWithInt:[fVidTwoPassCheck state]] forKey:@"VideoTwoPass"];
6911         /* Turbo 2 pass Encoding fVidTurboPassCheck*/
6912         [preset setObject:[NSNumber numberWithInt:[fVidTurboPassCheck state]] forKey:@"VideoTurboTwoPass"];
6913         /*Picture Settings*/
6914         hb_job_t * job = fTitle->job;
6915         /* Picture Sizing */
6916         /* Use Max Picture settings for whatever the dvd is.*/
6917         [preset setObject:[NSNumber numberWithInt:0] forKey:@"UsesMaxPictureSettings"];
6918         [preset setObject:[NSNumber numberWithInt:fTitle->job->width] forKey:@"PictureWidth"];
6919         [preset setObject:[NSNumber numberWithInt:fTitle->job->height] forKey:@"PictureHeight"];
6920         [preset setObject:[NSNumber numberWithInt:fTitle->job->keep_ratio] forKey:@"PictureKeepRatio"];
6921         [preset setObject:[NSNumber numberWithInt:fTitle->job->anamorphic.mode] forKey:@"PicturePAR"];
6922         
6923         /* Set crop settings here */
6924         [preset setObject:[NSNumber numberWithInt:[fPictureController autoCrop]] forKey:@"PictureAutoCrop"];
6925         [preset setObject:[NSNumber numberWithInt:job->crop[0]] forKey:@"PictureTopCrop"];
6926         [preset setObject:[NSNumber numberWithInt:job->crop[1]] forKey:@"PictureBottomCrop"];
6927         [preset setObject:[NSNumber numberWithInt:job->crop[2]] forKey:@"PictureLeftCrop"];
6928         [preset setObject:[NSNumber numberWithInt:job->crop[3]] forKey:@"PictureRightCrop"];
6929         
6930         /* Picture Filters */
6931         [preset setObject:[NSNumber numberWithInt:[fPictureController useDecomb]] forKey:@"PictureDecombDeinterlace"];
6932         [preset setObject:[NSNumber numberWithInt:[fPictureController deinterlace]] forKey:@"PictureDeinterlace"];
6933         [preset setObject:[fPictureController deinterlaceCustomString] forKey:@"PictureDeinterlaceCustom"];
6934         [preset setObject:[NSNumber numberWithInt:[fPictureController detelecine]] forKey:@"PictureDetelecine"];
6935         [preset setObject:[fPictureController detelecineCustomString] forKey:@"PictureDetelecineCustom"];
6936         [preset setObject:[NSNumber numberWithInt:[fPictureController denoise]] forKey:@"PictureDenoise"];
6937         [preset setObject:[fPictureController denoiseCustomString] forKey:@"PictureDenoiseCustom"];
6938         [preset setObject:[NSNumber numberWithInt:[fPictureController deblock]] forKey:@"PictureDeblock"]; 
6939         [preset setObject:[NSNumber numberWithInt:[fPictureController decomb]] forKey:@"PictureDecomb"];
6940         [preset setObject:[fPictureController decombCustomString] forKey:@"PictureDecombCustom"];
6941         [preset setObject:[NSNumber numberWithInt:[fPictureController grayscale]] forKey:@"VideoGrayScale"];
6942         
6943         /*Audio*/
6944         NSMutableArray *audioListArray = [[NSMutableArray alloc] init];
6945         /* we actually call the methods for the nests here */
6946         if ([fAudLang1PopUp indexOfSelectedItem] > 0)
6947         {
6948             NSMutableDictionary *audioTrack1Array = [[NSMutableDictionary alloc] init];
6949             [audioTrack1Array setObject:[NSNumber numberWithInt:[fAudLang1PopUp indexOfSelectedItem]] forKey:@"AudioTrack"];
6950             [audioTrack1Array setObject:[fAudLang1PopUp titleOfSelectedItem] forKey:@"AudioTrackDescription"];
6951             [audioTrack1Array setObject:[fAudTrack1CodecPopUp titleOfSelectedItem] forKey:@"AudioEncoder"];
6952             [audioTrack1Array setObject:[fAudTrack1MixPopUp titleOfSelectedItem] forKey:@"AudioMixdown"];
6953             [audioTrack1Array setObject:[fAudTrack1RatePopUp titleOfSelectedItem] forKey:@"AudioSamplerate"];
6954             [audioTrack1Array setObject:[fAudTrack1BitratePopUp titleOfSelectedItem] forKey:@"AudioBitrate"];
6955             [audioTrack1Array setObject:[NSNumber numberWithFloat:[fAudTrack1DrcSlider floatValue]] forKey:@"AudioTrackDRCSlider"];
6956             [audioTrack1Array autorelease];
6957             [audioListArray addObject:audioTrack1Array];
6958         }
6959         
6960         if ([fAudLang2PopUp indexOfSelectedItem] > 0)
6961         {
6962             NSMutableDictionary *audioTrack2Array = [[NSMutableDictionary alloc] init];
6963             [audioTrack2Array setObject:[NSNumber numberWithInt:[fAudLang2PopUp indexOfSelectedItem]] forKey:@"AudioTrack"];
6964             [audioTrack2Array setObject:[fAudLang2PopUp titleOfSelectedItem] forKey:@"AudioTrackDescription"];
6965             [audioTrack2Array setObject:[fAudTrack2CodecPopUp titleOfSelectedItem] forKey:@"AudioEncoder"];
6966             [audioTrack2Array setObject:[fAudTrack2MixPopUp titleOfSelectedItem] forKey:@"AudioMixdown"];
6967             [audioTrack2Array setObject:[fAudTrack2RatePopUp titleOfSelectedItem] forKey:@"AudioSamplerate"];
6968             [audioTrack2Array setObject:[fAudTrack2BitratePopUp titleOfSelectedItem] forKey:@"AudioBitrate"];
6969             [audioTrack2Array setObject:[NSNumber numberWithFloat:[fAudTrack2DrcSlider floatValue]] forKey:@"AudioTrackDRCSlider"];
6970             [audioTrack2Array autorelease];
6971             [audioListArray addObject:audioTrack2Array];
6972         }
6973         
6974         if ([fAudLang3PopUp indexOfSelectedItem] > 0)
6975         {
6976             NSMutableDictionary *audioTrack3Array = [[NSMutableDictionary alloc] init];
6977             [audioTrack3Array setObject:[NSNumber numberWithInt:[fAudLang3PopUp indexOfSelectedItem]] forKey:@"AudioTrack"];
6978             [audioTrack3Array setObject:[fAudLang3PopUp titleOfSelectedItem] forKey:@"AudioTrackDescription"];
6979             [audioTrack3Array setObject:[fAudTrack3CodecPopUp titleOfSelectedItem] forKey:@"AudioEncoder"];
6980             [audioTrack3Array setObject:[fAudTrack3MixPopUp titleOfSelectedItem] forKey:@"AudioMixdown"];
6981             [audioTrack3Array setObject:[fAudTrack3RatePopUp titleOfSelectedItem] forKey:@"AudioSamplerate"];
6982             [audioTrack3Array setObject:[fAudTrack3BitratePopUp titleOfSelectedItem] forKey:@"AudioBitrate"];
6983             [audioTrack3Array setObject:[NSNumber numberWithFloat:[fAudTrack3DrcSlider floatValue]] forKey:@"AudioTrackDRCSlider"];
6984             [audioTrack3Array autorelease];
6985             [audioListArray addObject:audioTrack3Array];
6986         }
6987         
6988         if ([fAudLang4PopUp indexOfSelectedItem] > 0)
6989         {
6990             NSMutableDictionary *audioTrack4Array = [[NSMutableDictionary alloc] init];
6991             [audioTrack4Array setObject:[NSNumber numberWithInt:[fAudLang4PopUp indexOfSelectedItem]] forKey:@"AudioTrack"];
6992             [audioTrack4Array setObject:[fAudLang4PopUp titleOfSelectedItem] forKey:@"AudioTrackDescription"];
6993             [audioTrack4Array setObject:[fAudTrack4CodecPopUp titleOfSelectedItem] forKey:@"AudioEncoder"];
6994             [audioTrack4Array setObject:[fAudTrack4MixPopUp titleOfSelectedItem] forKey:@"AudioMixdown"];
6995             [audioTrack4Array setObject:[fAudTrack4RatePopUp titleOfSelectedItem] forKey:@"AudioSamplerate"];
6996             [audioTrack4Array setObject:[fAudTrack4BitratePopUp titleOfSelectedItem] forKey:@"AudioBitrate"];
6997             [audioTrack4Array setObject:[NSNumber numberWithFloat:[fAudTrack4DrcSlider floatValue]] forKey:@"AudioTrackDRCSlider"];
6998             [audioTrack4Array autorelease];
6999             [audioListArray addObject:audioTrack4Array];
7000         }
7001         
7002         
7003         [preset setObject:[NSMutableArray arrayWithArray: audioListArray] forKey:@"AudioList"];
7004
7005         
7006         /* Temporarily remove subtitles from creating a new preset as it has to be converted over to use the new
7007          * subititle array code. */
7008         /* Subtitles*/
7009         //[preset setObject:[fSubPopUp titleOfSelectedItem] forKey:@"Subtitles"];
7010         /* Forced Subtitles */
7011         //[preset setObject:[NSNumber numberWithInt:[fSubForcedCheck state]] forKey:@"SubtitlesForced"];
7012     }
7013     [preset autorelease];
7014     return preset;
7015     
7016 }
7017
7018 - (void)savePreset
7019 {
7020     [UserPresets writeToFile:UserPresetsFile atomically:YES];
7021         /* We get the default preset in case it changed */
7022         [self getDefaultPresets:nil];
7023
7024 }
7025
7026 - (IBAction)deletePreset:(id)sender
7027 {
7028     
7029     
7030     if ( [fPresetsOutlineView numberOfSelectedRows] == 0 )
7031     {
7032         return;
7033     }
7034     /* Alert user before deleting preset */
7035         int status;
7036     status = NSRunAlertPanel(@"Warning!", @"Are you sure that you want to delete the selected preset?", @"OK", @"Cancel", nil);
7037     
7038     if ( status == NSAlertDefaultReturn ) 
7039     {
7040         int presetToModLevel = [fPresetsOutlineView levelForItem: [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]]];
7041         NSDictionary *presetToMod = [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]];
7042         NSDictionary *presetToModParent = [fPresetsOutlineView parentForItem: presetToMod];
7043         
7044         NSEnumerator *enumerator;
7045         NSMutableArray *presetsArrayToMod;
7046         NSMutableArray *tempArray;
7047         id tempObject;
7048         /* If we are a root level preset, we are modding the UserPresets array */
7049         if (presetToModLevel == 0)
7050         {
7051             presetsArrayToMod = UserPresets;
7052         }
7053         else // We have a parent preset, so we modify the chidren array object for key
7054         {
7055             presetsArrayToMod = [presetToModParent objectForKey:@"ChildrenArray"]; 
7056         }
7057         
7058         enumerator = [presetsArrayToMod objectEnumerator];
7059         tempArray = [NSMutableArray array];
7060         
7061         while (tempObject = [enumerator nextObject]) 
7062         {
7063             NSDictionary *thisPresetDict = tempObject;
7064             if (thisPresetDict == presetToMod)
7065             {
7066                 [tempArray addObject:tempObject];
7067             }
7068         }
7069         
7070         [presetsArrayToMod removeObjectsInArray:tempArray];
7071         [fPresetsOutlineView reloadData];
7072         [self savePreset];   
7073     }
7074 }
7075
7076
7077 #pragma mark -
7078 #pragma mark Import Export Preset(s)
7079
7080 - (IBAction) browseExportPresetFile: (id) sender
7081 {
7082     /* Open a panel to let the user choose where and how to save the export file */
7083     NSSavePanel * panel = [NSSavePanel savePanel];
7084         /* We get the current file name and path from the destination field here */
7085     NSString *defaultExportDirectory = [NSString stringWithFormat: @"%@/Desktop/", NSHomeDirectory()];
7086
7087         [panel beginSheetForDirectory: defaultExportDirectory file: @"HB_Export.plist"
7088                                    modalForWindow: fWindow modalDelegate: self
7089                                    didEndSelector: @selector( browseExportPresetFileDone:returnCode:contextInfo: )
7090                                           contextInfo: NULL];
7091 }
7092
7093 - (void) browseExportPresetFileDone: (NSSavePanel *) sheet
7094                    returnCode: (int) returnCode contextInfo: (void *) contextInfo
7095 {
7096     if( returnCode == NSOKButton )
7097     {
7098         NSString *presetExportDirectory = [[sheet filename] stringByDeletingLastPathComponent];
7099         NSString *exportPresetsFile = [sheet filename];
7100         [[NSUserDefaults standardUserDefaults] setObject:presetExportDirectory forKey:@"LastPresetExportDirectory"];
7101         /* We check for the presets.plist */
7102         if ([[NSFileManager defaultManager] fileExistsAtPath:exportPresetsFile] == 0)
7103         {
7104             [[NSFileManager defaultManager] createFileAtPath:exportPresetsFile contents:nil attributes:nil];
7105         }
7106         NSMutableArray * presetsToExport = [[NSMutableArray alloc] initWithContentsOfFile:exportPresetsFile];
7107         if (nil == presetsToExport)
7108         {
7109             presetsToExport = [[NSMutableArray alloc] init];
7110             
7111             /* now get and add selected presets to export */
7112             
7113         }
7114         if ([fPresetsOutlineView selectedRow] >= 0 && [[[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]] objectForKey:@"Folder"] intValue] != 1)
7115         {
7116             [presetsToExport addObject:[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]]];
7117             [presetsToExport writeToFile:exportPresetsFile atomically:YES];
7118             
7119         }
7120         
7121     }
7122 }
7123
7124
7125 - (IBAction) browseImportPresetFile: (id) sender
7126 {
7127
7128     NSOpenPanel * panel;
7129         
7130     panel = [NSOpenPanel openPanel];
7131     [panel setAllowsMultipleSelection: NO];
7132     [panel setCanChooseFiles: YES];
7133     [panel setCanChooseDirectories: NO ];
7134     NSString * sourceDirectory;
7135         if ([[NSUserDefaults standardUserDefaults] stringForKey:@"LastPresetImportDirectory"])
7136         {
7137                 sourceDirectory = [[NSUserDefaults standardUserDefaults] stringForKey:@"LastPresetImportDirectory"];
7138         }
7139         else
7140         {
7141                 sourceDirectory = @"~/Desktop";
7142                 sourceDirectory = [sourceDirectory stringByExpandingTildeInPath];
7143         }
7144     /* we open up the browse sources sheet here and call for browseSourcesDone after the sheet is closed
7145         * to evaluate whether we want to specify a title, we pass the sender in the contextInfo variable
7146         */
7147     /* set this for allowed file types, not sure if we should allow xml or not */
7148     NSArray *fileTypes = [NSArray arrayWithObjects:@"plist", @"xml", nil];
7149     [panel beginSheetForDirectory: sourceDirectory file: nil types: fileTypes
7150                    modalForWindow: fWindow modalDelegate: self
7151                    didEndSelector: @selector( browseImportPresetDone:returnCode:contextInfo: )
7152                       contextInfo: sender];
7153 }
7154
7155 - (void) browseImportPresetDone: (NSSavePanel *) sheet
7156                      returnCode: (int) returnCode contextInfo: (void *) contextInfo
7157 {
7158     if( returnCode == NSOKButton )
7159     {
7160         NSString *importPresetsDirectory = [[sheet filename] stringByDeletingLastPathComponent];
7161         NSString *importPresetsFile = [sheet filename];
7162         [[NSUserDefaults standardUserDefaults] setObject:importPresetsDirectory forKey:@"LastPresetImportDirectory"];
7163         /* NOTE: here we need to do some sanity checking to verify we do not hose up our presets file   */
7164         NSMutableArray * presetsToImport = [[NSMutableArray alloc] initWithContentsOfFile:importPresetsFile];
7165         /* iterate though the new array of presets to import and add them to our presets array */
7166         int i = 0;
7167         NSEnumerator *enumerator = [presetsToImport objectEnumerator];
7168         id tempObject;
7169         while (tempObject = [enumerator nextObject])
7170         {
7171             /* make any changes to the incoming preset we see fit */
7172             /* make sure the incoming preset is not tagged as default */
7173             [tempObject setObject:[NSNumber numberWithInt:0] forKey:@"Default"];
7174             /* prepend "(imported) to the name of the incoming preset for clarification since it can be changed */
7175             NSString * prependedName = [@"(import) " stringByAppendingString:[tempObject objectForKey:@"PresetName"]] ;
7176             [tempObject setObject:prependedName forKey:@"PresetName"];
7177             
7178             /* actually add the new preset to our presets array */
7179             [UserPresets addObject:tempObject];
7180             i++;
7181         }
7182         [presetsToImport autorelease];
7183         [self sortPresets];
7184         [self addPreset];
7185         
7186     }
7187 }
7188
7189 #pragma mark -
7190 #pragma mark Manage Default Preset
7191
7192 - (IBAction)getDefaultPresets:(id)sender
7193 {
7194         presetHbDefault = nil;
7195     presetUserDefault = nil;
7196     presetUserDefaultParent = nil;
7197     presetUserDefaultParentParent = nil;
7198     NSMutableDictionary *presetHbDefaultParent = nil;
7199     NSMutableDictionary *presetHbDefaultParentParent = nil;
7200     
7201     int i = 0;
7202     BOOL userDefaultFound = NO;
7203     presetCurrentBuiltInCount = 0;
7204     /* First we iterate through the root UserPresets array to check for defaults */
7205     NSEnumerator *enumerator = [UserPresets objectEnumerator];
7206         id tempObject;
7207         while (tempObject = [enumerator nextObject])
7208         {
7209                 NSMutableDictionary *thisPresetDict = tempObject;
7210                 if ([[thisPresetDict objectForKey:@"Default"] intValue] == 1) // 1 is HB default
7211                 {
7212                         presetHbDefault = thisPresetDict;       
7213                 }
7214                 if ([[thisPresetDict objectForKey:@"Default"] intValue] == 2) // 2 is User specified default
7215                 {
7216                         presetUserDefault = thisPresetDict;
7217             userDefaultFound = YES;
7218         }
7219         if ([[thisPresetDict objectForKey:@"Type"] intValue] == 0) // Type 0 is a built in preset               
7220         {
7221                         presetCurrentBuiltInCount++; // <--increment the current number of built in presets     
7222                 }
7223                 i++;
7224         
7225         /* if we run into a folder, go to level 1 and iterate through the children arrays for the default */
7226         if ([thisPresetDict objectForKey:@"ChildrenArray"])
7227         {
7228             NSMutableDictionary *thisPresetDictParent = thisPresetDict;
7229             NSEnumerator *enumerator = [[thisPresetDict objectForKey:@"ChildrenArray"] objectEnumerator];
7230             id tempObject;
7231             while (tempObject = [enumerator nextObject])
7232             {
7233                 NSMutableDictionary *thisPresetDict = tempObject;
7234                 if ([[thisPresetDict objectForKey:@"Default"] intValue] == 1) // 1 is HB default
7235                 {
7236                     presetHbDefault = thisPresetDict;
7237                     presetHbDefaultParent = thisPresetDictParent;
7238                 }
7239                 if ([[thisPresetDict objectForKey:@"Default"] intValue] == 2) // 2 is User specified default
7240                 {
7241                     presetUserDefault = thisPresetDict;
7242                     presetUserDefaultParent = thisPresetDictParent;
7243                     userDefaultFound = YES;
7244                 }
7245                 
7246                 /* if we run into a folder, go to level 2 and iterate through the children arrays for the default */
7247                 if ([thisPresetDict objectForKey:@"ChildrenArray"])
7248                 {
7249                     NSMutableDictionary *thisPresetDictParentParent = thisPresetDict;
7250                     NSEnumerator *enumerator = [[thisPresetDict objectForKey:@"ChildrenArray"] objectEnumerator];
7251                     id tempObject;
7252                     while (tempObject = [enumerator nextObject])
7253                     {
7254                         NSMutableDictionary *thisPresetDict = tempObject;
7255                         if ([[thisPresetDict objectForKey:@"Default"] intValue] == 1) // 1 is HB default
7256                         {
7257                             presetHbDefault = thisPresetDict;
7258                             presetHbDefaultParent = thisPresetDictParent;
7259                             presetHbDefaultParentParent = thisPresetDictParentParent;   
7260                         }
7261                         if ([[thisPresetDict objectForKey:@"Default"] intValue] == 2) // 2 is User specified default
7262                         {
7263                             presetUserDefault = thisPresetDict;
7264                             presetUserDefaultParent = thisPresetDictParent;
7265                             presetUserDefaultParentParent = thisPresetDictParentParent;
7266                             userDefaultFound = YES;     
7267                         }
7268                         
7269                     }
7270                 }
7271             }
7272         }
7273         
7274         }
7275     /* check to see if a user specified preset was found, if not then assign the parents for
7276      * the presetHbDefault so that we can open the parents for the nested presets
7277      */
7278     if (userDefaultFound == NO)
7279     {
7280         presetUserDefaultParent = presetHbDefaultParent;
7281         presetUserDefaultParentParent = presetHbDefaultParentParent;
7282     }
7283 }
7284
7285 - (IBAction)setDefaultPreset:(id)sender
7286 {
7287 /* We need to determine if the item is a folder */
7288    if ([[[fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]] objectForKey:@"Folder"] intValue] == 1)
7289    {
7290    return;
7291    }
7292
7293     int i = 0;
7294     NSEnumerator *enumerator = [UserPresets objectEnumerator];
7295         id tempObject;
7296         /* First make sure the old user specified default preset is removed */
7297     while (tempObject = [enumerator nextObject])
7298         {
7299                 NSMutableDictionary *thisPresetDict = tempObject;
7300                 if ([[tempObject objectForKey:@"Default"] intValue] != 1) // if not the default HB Preset, set to 0
7301                 {
7302                         [[UserPresets objectAtIndex:i] setObject:[NSNumber numberWithInt:0] forKey:@"Default"]; 
7303                 }
7304                 
7305                 /* if we run into a folder, go to level 1 and iterate through the children arrays for the default */
7306         if ([thisPresetDict objectForKey:@"ChildrenArray"])
7307         {
7308             NSEnumerator *enumerator = [[thisPresetDict objectForKey:@"ChildrenArray"] objectEnumerator];
7309             id tempObject;
7310             int ii = 0;
7311             while (tempObject = [enumerator nextObject])
7312             {
7313                 NSMutableDictionary *thisPresetDict1 = tempObject;
7314                 if ([[tempObject objectForKey:@"Default"] intValue] != 1) // if not the default HB Preset, set to 0
7315                 {
7316                     [[[thisPresetDict objectForKey:@"ChildrenArray"] objectAtIndex:ii] setObject:[NSNumber numberWithInt:0] forKey:@"Default"]; 
7317                 }
7318                 /* if we run into a folder, go to level 2 and iterate through the children arrays for the default */
7319                 if ([thisPresetDict1 objectForKey:@"ChildrenArray"])
7320                 {
7321                     NSEnumerator *enumerator = [[thisPresetDict1 objectForKey:@"ChildrenArray"] objectEnumerator];
7322                     id tempObject;
7323                     int iii = 0;
7324                     while (tempObject = [enumerator nextObject])
7325                     {
7326                         if ([[tempObject objectForKey:@"Default"] intValue] != 1) // if not the default HB Preset, set to 0
7327                         {
7328                             [[[thisPresetDict1 objectForKey:@"ChildrenArray"] objectAtIndex:iii] setObject:[NSNumber numberWithInt:0] forKey:@"Default"];       
7329                         }
7330                         iii++;
7331                     }
7332                 }
7333                 ii++;
7334             }
7335             
7336         }
7337         i++; 
7338         }
7339     
7340     
7341     int presetToModLevel = [fPresetsOutlineView levelForItem: [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]]];
7342     NSDictionary *presetToMod = [fPresetsOutlineView itemAtRow:[fPresetsOutlineView selectedRow]];
7343     NSDictionary *presetToModParent = [fPresetsOutlineView parentForItem: presetToMod];
7344     
7345     
7346     NSMutableArray *presetsArrayToMod;
7347     NSMutableArray *tempArray;
7348     
7349     /* If we are a root level preset, we are modding the UserPresets array */
7350     if (presetToModLevel == 0)
7351     {
7352         presetsArrayToMod = UserPresets;
7353     }
7354     else // We have a parent preset, so we modify the chidren array object for key
7355     {
7356         presetsArrayToMod = [presetToModParent objectForKey:@"ChildrenArray"]; 
7357     }
7358     
7359     enumerator = [presetsArrayToMod objectEnumerator];
7360     tempArray = [NSMutableArray array];
7361     int iiii = 0;
7362     while (tempObject = [enumerator nextObject]) 
7363     {
7364         NSDictionary *thisPresetDict = tempObject;
7365         if (thisPresetDict == presetToMod)
7366         {
7367             if ([[tempObject objectForKey:@"Default"] intValue] != 1) // if not the default HB Preset, set to 2
7368             {
7369                 [[presetsArrayToMod objectAtIndex:iiii] setObject:[NSNumber numberWithInt:2] forKey:@"Default"];        
7370             }
7371         }
7372      iiii++;
7373      }
7374     
7375     
7376     /* We save all of the preset data here */
7377     [self savePreset];
7378     /* We Reload the New Table data for presets */
7379     [fPresetsOutlineView reloadData];
7380 }
7381
7382 - (IBAction)selectDefaultPreset:(id)sender
7383 {
7384         NSMutableDictionary *presetToMod;
7385     /* if there is a user specified default, we use it */
7386         if (presetUserDefault)
7387         {
7388         presetToMod = presetUserDefault;
7389     }
7390         else if (presetHbDefault) //else we use the built in default presetHbDefault
7391         {
7392         presetToMod = presetHbDefault;
7393         }
7394     else
7395     {
7396     return;
7397     }
7398     
7399     if (presetUserDefaultParent != nil)
7400     {
7401         [fPresetsOutlineView expandItem:presetUserDefaultParent];
7402         
7403     }
7404     if (presetUserDefaultParentParent != nil)
7405     {
7406         [fPresetsOutlineView expandItem:presetUserDefaultParentParent];
7407         
7408     }
7409     
7410     [fPresetsOutlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:[fPresetsOutlineView rowForItem: presetToMod]] byExtendingSelection:NO];
7411         [self selectPreset:nil];
7412 }
7413
7414
7415 #pragma mark -
7416 #pragma mark Manage Built In Presets
7417
7418
7419 - (IBAction)deleteFactoryPresets:(id)sender
7420 {
7421     //int status;
7422     NSEnumerator *enumerator = [UserPresets objectEnumerator];
7423         id tempObject;
7424     
7425         //NSNumber *index;
7426     NSMutableArray *tempArray;
7427
7428
7429         tempArray = [NSMutableArray array];
7430         /* we look here to see if the preset is we move on to the next one */
7431         while ( tempObject = [enumerator nextObject] )  
7432                 {
7433                         /* if the preset is "Factory" then we put it in the array of
7434                         presets to delete */
7435                         if ([[tempObject objectForKey:@"Type"] intValue] == 0)
7436                         {
7437                                 [tempArray addObject:tempObject];
7438                         }
7439         }
7440         
7441         [UserPresets removeObjectsInArray:tempArray];
7442         [fPresetsOutlineView reloadData];
7443         [self savePreset];   
7444
7445 }
7446
7447    /* We use this method to recreate new, updated factory presets */
7448 - (IBAction)addFactoryPresets:(id)sender
7449 {
7450     
7451     /* First, we delete any existing built in presets */
7452     [self deleteFactoryPresets: sender];
7453     /* Then we generate new built in presets programmatically with fPresetsBuiltin
7454      * which is all setup in HBPresets.h and  HBPresets.m*/
7455     [fPresetsBuiltin generateBuiltinPresets:UserPresets];
7456     /* update build number for built in presets */
7457     /* iterate though the new array of presets to import and add them to our presets array */
7458     int i = 0;
7459     NSEnumerator *enumerator = [UserPresets objectEnumerator];
7460     id tempObject;
7461     while (tempObject = [enumerator nextObject])
7462     {
7463         /* Record the apps current build number in the PresetBuildNumber key */
7464         if ([[tempObject objectForKey:@"Type"] intValue] == 0) // Type 0 is a built in preset           
7465         {
7466             /* Preset build number */
7467             [[UserPresets objectAtIndex:i] setObject:[NSNumber numberWithInt:[[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] intValue]] forKey:@"PresetBuildNumber"];
7468         }
7469         i++;
7470     }
7471     /* report the built in preset updating to the activity log */
7472     [self writeToActivityLog: "built in presets updated to build number: %d", [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] intValue]];
7473     
7474     [self sortPresets];
7475     [self addPreset];
7476     
7477 }
7478
7479
7480 @end
7481
7482 /*******************************
7483  * Subclass of the HBPresetsOutlineView *
7484  *******************************/
7485
7486 @implementation HBPresetsOutlineView
7487 - (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray *)tableColumns event:(NSEvent*)dragEvent offset:(NSPointPointer)dragImageOffset
7488 {
7489     fIsDragging = YES;
7490
7491     // By default, NSTableView only drags an image of the first column. Change this to
7492     // drag an image of the queue's icon and PresetName columns.
7493     NSArray * cols = [NSArray arrayWithObjects: [self tableColumnWithIdentifier:@"PresetName"], nil];
7494     return [super dragImageForRowsWithIndexes:dragRows tableColumns:cols event:dragEvent offset:dragImageOffset];
7495 }
7496
7497
7498
7499 - (void) mouseDown:(NSEvent *)theEvent
7500 {
7501     [super mouseDown:theEvent];
7502         fIsDragging = NO;
7503 }
7504
7505
7506
7507 - (BOOL) isDragging;
7508 {
7509     return fIsDragging;
7510 }
7511 @end
7512
7513
7514