OSDN Git Service

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