OSDN Git Service

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