OSDN Git Service

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