OSDN Git Service

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