OSDN Git Service

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