OSDN Git Service

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