X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=macosx%2FController.m;h=5a85cd2c0faefa219c99c01ed7aa5d9a477fda88;hb=55b0015a8c50106e553bc2f48336cc2a1c495459;hp=0715bff0eb22531c2c79a005ba8696fe030b3978;hpb=7e083011cd7ddde540f88d725efbc951c822fb9b;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/macosx/Controller.m b/macosx/Controller.m index 0715bff0..5a85cd2c 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -4,6 +4,7 @@ Homepage: . It may be used under the terms of the GNU General Public License. */ +#include #import "Controller.h" #import "HBOutputPanelController.h" #import "HBPreferencesController.h" @@ -262,15 +263,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *) app { - /* if we are in preview full screen mode, we need to go to - * windowed mode and release the display before we terminate. - * We do it here (instead of applicationWillTerminate) so we - * release the displays and can then see the alerts below. - */ - if ([fPictureController previewFullScreenMode] == YES) - { - [fPictureController previewGoWindowed:nil]; - } + hb_state_t s; hb_get_state( fQueueEncodeLibhb, &s ); @@ -317,15 +310,18 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [fPictureController release]; [fApplicationIcon release]; - hb_close(&fHandle); + hb_close(&fHandle); hb_close(&fQueueEncodeLibhb); + hb_global_close(); + } - (void) awakeFromNib { [fWindow center]; - [fWindow setExcludedFromWindowsMenu:YES]; + [fWindow setExcludedFromWindowsMenu:NO]; + [fAdvancedOptions setView:fAdvancedView]; /* lets setup our presets drawer for drag and drop here */ @@ -519,7 +515,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It fQueueStatus,fPresetsAdd,fPresetsDelete,fSrcAngleLabel,fSrcAnglePopUp, fCreateChapterMarkers,fVidTurboPassCheck,fDstMp4LargeFileCheck,fSubForcedCheck,fPresetsOutlineView, fAudDrcLabel,fDstMp4HttpOptFileCheck,fDstMp4iPodFileCheck,fVidQualityRFField,fVidQualityRFLabel, - fEncodeStartStopPopUp,fSrcTimeStartEncodingField,fSrcTimeEndEncodingField,fSrcFrameStartEncodingField,fSrcFrameEndEncodingField}; + fEncodeStartStopPopUp,fSrcTimeStartEncodingField,fSrcTimeEndEncodingField,fSrcFrameStartEncodingField,fSrcFrameEndEncodingField, fLoadChaptersButton, fSaveChaptersButton}; for( unsigned i = 0; i < sizeof( controls ) / sizeof( NSControl * ); i++ ) @@ -1619,31 +1615,20 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It if( [detector isVideoDVD] ) { - int hb_arch; -#if defined( __LP64__ ) - /* we are 64 bit */ - hb_arch = 64; -#else - /* we are 32 bit */ - hb_arch = 32; -#endif - - // The chosen path was actually on a DVD, so use the raw block // device path instead. path = [detector devicePath]; [self writeToActivityLog: "trying to open a physical dvd at: %s", [scanPath UTF8String]]; /* lets check for vlc here to make sure we have a dylib available to use for decrypting */ - NSString *vlcPath = @"/Applications/VLC.app/Contents/MacOS/lib/libdvdcss.2.dylib"; - NSFileManager * fileManager = [NSFileManager defaultManager]; - if ([fileManager fileExistsAtPath:vlcPath] == 0) - { - /*vlc not found in /Applications so we set the bool to cancel scanning to 1 */ + void *dvdcss = dlopen("libdvdcss.2.dylib", RTLD_LAZY); + if (dvdcss == NULL) + { + /*compatible vlc not found, so we set the bool to cancel scanning to 1 */ cancelScanDecrypt = 1; [self writeToActivityLog: "VLC app not found for decrypting physical dvd"]; int status; - 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"); + status = NSRunAlertPanel(@"HandBrake could not find VLC or your VLC is incompatible (Note: 32 bit vlc is not compatible with 64 bit HandBrake and vice-versa).",@"Please download and install VLC media player if you wish to read encrypted DVDs.", @"Get VLC", @"Cancel Scan", @"Attempt Scan Anyway"); [NSApp requestUserAttention:NSCriticalRequest]; if (status == NSAlertDefaultReturn) @@ -1669,111 +1654,8 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It /* VLC was found in /Applications so all is well, we can carry on using vlc's libdvdcss.dylib for decrypting if needed */ [self writeToActivityLog: "VLC app found for decrypting physical dvd"]; vlcFound = 1; + dlclose(dvdcss); } - /* test for architecture of the vlc app */ - NSArray *vlc_architecturesArray = [[NSBundle bundleWithPath:@"/Applications/VLC.app"] executableArchitectures]; - BOOL vlcIntel32bit = NO; - BOOL vlcIntel64bit = NO; - BOOL vlcPPC32bit = NO; - BOOL vlcPPC64bit = NO; - /* check the available architectures for vlc and note accordingly */ - NSEnumerator *enumerator = [vlc_architecturesArray objectEnumerator]; - id tempObject; - while (tempObject = [enumerator nextObject]) - { - - if ([tempObject intValue] == NSBundleExecutableArchitectureI386) - { - vlcIntel32bit = YES; - } - if ([tempObject intValue] == NSBundleExecutableArchitectureX86_64) - { - vlcIntel64bit = YES; - } - if ([tempObject intValue] == NSBundleExecutableArchitecturePPC) - { - vlcPPC32bit = YES; - } - if ([tempObject intValue] == NSBundleExecutableArchitecturePPC64) - { - vlcPPC64bit = YES; - } - - } - /* Write vlc architecture findings to activity window */ - if (vlcIntel32bit) - { - [self writeToActivityLog: " 32-Bit VLC app found for decrypting physical dvd"]; - } - if (vlcIntel64bit) - { - [self writeToActivityLog: " 64-Bit VLC app found for decrypting physical dvd"]; - } - - - - if (vlcFound && hb_arch == 64 && !vlcIntel64bit && cancelScanDecrypt != 1) - { - - /* we are 64 bit */ - - /* Appropriate VLC not found, so cancel */ - cancelScanDecrypt = 1; - [self writeToActivityLog: "This version of HandBrake is 64 bit, 64 bit version of vlc not found, scan cancelled"]; - /*On Screen Notification*/ - int status; - NSBeep(); - status = NSRunAlertPanel(@"This version of HandBrake is 64 bit, VLC found but not 64 bit!",@"", @"Cancel Scan", @"Attempt Scan Anyway", @"Get 64 bit VLC", nil); - [NSApp requestUserAttention:NSCriticalRequest]; - - if (status == NSAlertDefaultReturn) - { - /* User chose to cancel the scan */ - [self writeToActivityLog: "cannot open physical dvd VLC found but not 64 bit, scan cancelled"]; - cancelScanDecrypt = 1; - } - else if (status == NSAlertAlternateReturn) - { - [self writeToActivityLog: "user overrode 64-bit warning trying to open physical dvd without proper decryption"]; - cancelScanDecrypt = 0; - } - else - { - /* User chose to go download vlc (as they rightfully should) so we send them to the vlc site */ - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.videolan.org/vlc/download-macosx.html"]]; - } - - } - else if (vlcFound && hb_arch == 32 && !vlcIntel32bit && cancelScanDecrypt != 1) - { - /* we are 32 bit */ - /* Appropriate VLC not found, so cancel */ - cancelScanDecrypt = 1; - [self writeToActivityLog: "This version of HandBrake is 32 bit, 32 bit version of vlc not found, scan cancelled"]; - /*On Screen Notification*/ - int status; - NSBeep(); - status = NSRunAlertPanel(@"This version of HandBrake is 32 bit, VLC found but not 32 bit!",@"", @"Cancel Scan", @"Attempt Scan Anyway", @"Get 32 bit VLC", nil); - [NSApp requestUserAttention:NSCriticalRequest]; - - if (status == NSAlertDefaultReturn) - { - /* User chose to cancel the scan */ - [self writeToActivityLog: "cannot open physical dvd VLC found but not 32 bit, scan cancelled"]; - cancelScanDecrypt = 1; - } - else if (status == NSAlertAlternateReturn) - { - [self writeToActivityLog: "user overrode 32-bit warning trying to open physical dvd without proper decryption"]; - cancelScanDecrypt = 0; - } - else - { - /* User chose to go download vlc (as they rightfully should) so we send them to the vlc site */ - [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.videolan.org/vlc/download-macosx.html"]]; - } - - } } if (cancelScanDecrypt == 0) @@ -1808,9 +1690,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It { hb_list_t * list; hb_title_t * title; - int indxpri=0; // Used to search the longuest title (default in combobox) - int longuestpri=0; // Used to search the longuest title (default in combobox) - + int feature_title=0; // Used to store the main feature title list = hb_get_titles( fHandle ); @@ -1884,11 +1764,10 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It @"%@/Desktop/%@.mp4", NSHomeDirectory(),[browsedSourceDisplayName stringByDeletingPathExtension]]]; } - - if (longuestpri < title->hours*60*60 + title->minutes *60 + title->seconds) + /* See if this is the main feature according to libhb */ + if (title->index == title->job->feature) { - longuestpri=title->hours*60*60 + title->minutes *60 + title->seconds; - indxpri=i; + feature_title = i; } [fSrcTitlePopUp addItemWithTitle: [NSString @@ -1904,8 +1783,8 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } else { - /* if not then select the longest title (dvd) */ - [fSrcTitlePopUp selectItemAtIndex: indxpri]; + /* if not then select the main feature title */ + [fSrcTitlePopUp selectItemAtIndex: feature_title]; } [self titlePopUpChanged:nil]; @@ -2052,7 +1931,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It * by one to keep in sync with the queue array */ currentQueueEncodeIndex--; - [self writeToActivityLog: "removeQueueFileItem: Removing a cancelled/finished encode, decrement currentQueueEncodeIndex to %d", currentQueueEncodeIndex]; + } [QueueFileArray removeObjectAtIndex:queueItemToRemove]; [self saveQueueFileItem]; @@ -2249,7 +2128,7 @@ fWorkingCount = 0; /* The number of seek points equals the number of seconds announced in the title as that is our current granularity */ - int title_duration_seconds = (title->hours * 3600) + (title->minutes * 60) + (title->seconds); + int title_duration_seconds = (title->hours * 3600) + (title->minutes * 60) + (title->seconds); [queueFileJob setObject:[NSNumber numberWithInt:title_duration_seconds] forKey:@"SourceTotalSeconds"]; [queueFileJob setObject:[fDstFile2Field stringValue] forKey:@"DestinationPath"]; @@ -2448,7 +2327,6 @@ fWorkingCount = 0; /*Audio*/ if ([fAudLang1PopUp indexOfSelectedItem] > 0) { - //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio1Encoder"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1CodecPopUp selectedItem] tag]] forKey:@"JobAudio1Encoder"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1MixPopUp selectedItem] tag]] forKey:@"JobAudio1Mixdown"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack1RatePopUp selectedItem] tag]] forKey:@"JobAudio1Samplerate"]; @@ -2456,7 +2334,6 @@ fWorkingCount = 0; } if ([fAudLang2PopUp indexOfSelectedItem] > 0) { - //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio2Encoder"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2CodecPopUp selectedItem] tag]] forKey:@"JobAudio2Encoder"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2MixPopUp selectedItem] tag]] forKey:@"JobAudio2Mixdown"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack2RatePopUp selectedItem] tag]] forKey:@"JobAudio2Samplerate"]; @@ -2464,7 +2341,6 @@ fWorkingCount = 0; } if ([fAudLang3PopUp indexOfSelectedItem] > 0) { - //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio3Encoder"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3CodecPopUp selectedItem] tag]] forKey:@"JobAudio3Encoder"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3MixPopUp selectedItem] tag]] forKey:@"JobAudio3Mixdown"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack3RatePopUp selectedItem] tag]] forKey:@"JobAudio3Samplerate"]; @@ -2472,14 +2348,12 @@ fWorkingCount = 0; } if ([fAudLang4PopUp indexOfSelectedItem] > 0) { - //[queueFileJob setObject:[fAudTrack1CodecPopUp indexOfSelectedItem] forKey:@"JobAudio4Encoder"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4CodecPopUp selectedItem] tag]] forKey:@"JobAudio4Encoder"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4MixPopUp selectedItem] tag]] forKey:@"JobAudio4Mixdown"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4RatePopUp selectedItem] tag]] forKey:@"JobAudio4Samplerate"]; [queueFileJob setObject:[NSNumber numberWithInt:[[fAudTrack4BitratePopUp selectedItem] tag]] forKey:@"JobAudio4Bitrate"]; } - /* we need to auto relase the queueFileJob and return it */ [queueFileJob autorelease]; return queueFileJob; @@ -2530,21 +2404,17 @@ fWorkingCount = 0; /* We save all of the Queue data here */ [self saveQueueFileItem]; - /* We Reload the New Table data for presets */ - //[fPresetsOutlineView reloadData]; /* Since we have now marked a queue item as done * we can go ahead and increment currentQueueEncodeIndex * so that if there is anything left in the queue we can * go ahead and move to the next item if we want to */ currentQueueEncodeIndex++ ; - [self writeToActivityLog: "incrementQueueItemDone currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex]; int queueItems = [QueueFileArray count]; /* If we still have more items in our queue, lets go to the next one */ if (currentQueueEncodeIndex < queueItems) { - [self writeToActivityLog: "incrementQueueItemDone currentQueueEncodeIndex is incremented to: %d", currentQueueEncodeIndex]; - [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; + [self performNewQueueScan:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"SourcePath"] scanTitleNum:[[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"TitleNumber"]intValue]]; } else { @@ -2558,13 +2428,11 @@ fWorkingCount = 0; /* Tell HB to output a new activity log file for this encode */ [outputPanel startEncodeLog:[[QueueFileArray objectAtIndex:currentQueueEncodeIndex] objectForKey:@"DestinationPath"]]; - - /* use a bool to determine whether or not we can decrypt using vlc */ + /* use a bool to determine whether or not we can decrypt using vlc */ BOOL cancelScanDecrypt = 0; /* set the bool so that showNewScan knows to apply the appropriate queue - * settings as this is a queue rescan - */ - //applyQueueToScan = YES; + * settings as this is a queue rescan + */ NSString *path = scanPath; HBDVDDetector *detector = [HBDVDDetector detectorForPath:path]; @@ -2576,10 +2444,9 @@ fWorkingCount = 0; [self writeToActivityLog: "trying to open a physical dvd at: %s", [scanPath UTF8String]]; /* lets check for vlc here to make sure we have a dylib available to use for decrypting */ - NSString *vlcPath = @"/Applications/VLC.app"; - NSFileManager * fileManager = [NSFileManager defaultManager]; - if ([fileManager fileExistsAtPath:vlcPath] == 0) - { + void *dvdcss = dlopen("libdvdcss.2.dylib", RTLD_LAZY); + if (dvdcss == NULL) + { /*vlc not found in /Applications so we set the bool to cancel scanning to 1 */ cancelScanDecrypt = 1; [self writeToActivityLog: "VLC app not found for decrypting physical dvd"]; @@ -2608,6 +2475,7 @@ fWorkingCount = 0; else { /* VLC was found in /Applications so all is well, we can carry on using vlc's libdvdcss.dylib for decrypting if needed */ + dlclose(dvdcss); [self writeToActivityLog: "VLC app found for decrypting physical dvd"]; } } @@ -2627,8 +2495,7 @@ fWorkingCount = 0; [self writeToActivityLog: "scanning specifically for title: %d", scanTitleNum]; } - [self writeToActivityLog: "performNewQueueScan currentQueueEncodeIndex is: %d", currentQueueEncodeIndex]; - /* We use our advance pref to determine how many previews to scan */ + /* We use our advance pref to determine how many previews to scan */ int hb_num_previews = [[[NSUserDefaults standardUserDefaults] objectForKey:@"PreviewsNumber"] intValue]; hb_scan( fQueueEncodeLibhb, [path UTF8String], scanTitleNum, hb_num_previews, 0 ); } @@ -2650,7 +2517,6 @@ fWorkingCount = 0; [self writeToActivityLog: "Preset: %s", [[queueToApply objectForKey:@"PresetName"] UTF8String]]; [self writeToActivityLog: "processNewQueueEncode number of passes expected is: %d", ([[queueToApply objectForKey:@"VideoTwoPass"] intValue] + 1)]; job->file = [[queueToApply objectForKey:@"DestinationPath"] UTF8String]; - //[self writeToActivityLog: "processNewQueueEncode sending to prepareJob"]; [self prepareJob]; /* @@ -2725,7 +2591,6 @@ fWorkingCount = 0; free(subtitle); } - /* We should be all setup so let 'er rip */ [self doRip]; } @@ -2760,8 +2625,10 @@ fWorkingCount = 0; [self writeToActivityLog: "applyQueueSettingsToMainWindow: queue item found"]; } /* Set title number and chapters */ - /* since the queue only scans a single title, we really don't need to pick a title */ - [fSrcTitlePopUp selectItemAtIndex: [[queueToApply objectForKey:@"TitleNumber"] intValue] - 1]; + /* since the queue only scans a single title, its already been selected in showNewScan + so do not try to reset it here. However if we do decide to do full source scans on + a queue edit rescan, we would need it. So leaving in for now but commenting out. */ + //[fSrcTitlePopUp selectItemAtIndex: [[queueToApply objectForKey:@"TitleNumber"] intValue] - 1]; [fSrcChapterStartPopUp selectItemAtIndex: [[queueToApply objectForKey:@"ChapterStart"] intValue] - 1]; [fSrcChapterEndPopUp selectItemAtIndex: [[queueToApply objectForKey:@"ChapterEnd"] intValue] - 1]; @@ -2820,7 +2687,7 @@ fWorkingCount = 0; } [self videoMatrixChanged:nil]; - [self writeToActivityLog: "applyQueueSettingsToMainWindow: video matrix changed"]; + /* Video framerate */ /* For video preset video framerate, we want to make sure that Same as source does not conflict with the detected framerate in the fVidRatePopUp so we use index 0*/ @@ -2924,7 +2791,6 @@ fWorkingCount = 0; [self audioTrackPopUpChanged: fAudLang4PopUp]; } - [self writeToActivityLog: "applyQueueSettingsToMainWindow: audio set up"]; /*Subtitles*/ /* Crashy crashy right now, working on it */ [fSubtitlesDelegate setNewSubtitles:[queueToApply objectForKey:@"SubtitleList"]]; @@ -2955,7 +2821,7 @@ fWorkingCount = 0; } - //job->modulus = [[queueToApply objectForKey:@"PictureModulus"] intValue]; + job->modulus = [[queueToApply objectForKey:@"PictureModulus"] intValue]; /* we check to make sure the presets width/height does not exceed the sources width/height */ if (fTitle->width < [[queueToApply objectForKey:@"PictureWidth"] intValue] || fTitle->height < [[queueToApply objectForKey:@"PictureHeight"] intValue]) @@ -2984,9 +2850,6 @@ fWorkingCount = 0; job->anamorphic.mode = [[queueToApply objectForKey:@"PicturePAR"] intValue]; job->modulus = [[queueToApply objectForKey:@"PictureModulus"] intValue]; - [self writeToActivityLog: "applyQueueSettingsToMainWindow: picture sizing set up"]; - - /* Filters */ /* We only allow *either* Decomb or Deinterlace. So check for the PictureDecombDeinterlace key. @@ -3084,10 +2947,9 @@ fWorkingCount = 0; [fPictureController SetTitle:fTitle]; [self calculatePictureSizing:nil]; - [self writeToActivityLog: "applyQueueSettingsToMainWindow: picture filters set up"]; /* somehow we need to figure out a way to tie the queue item to a preset if it used one */ //[queueFileJob setObject:[fPresetSelectedDisplay stringValue] forKey:@"PresetName"]; - // [queueFileJob setObject:[NSNumber numberWithInt:[fPresetsOutlineView selectedRow]] forKey:@"PresetIndexNum"]; + //[queueFileJob setObject:[NSNumber numberWithInt:[fPresetsOutlineView selectedRow]] forKey:@"PresetIndexNum"]; if ([queueToApply objectForKey:@"PresetIndexNum"]) // This item used a preset so insert that info { /* Deselect the currently selected Preset if there is one*/ @@ -3246,23 +3108,18 @@ bool one_burned = FALSE; [self writeToActivityLog: "Foreign Language Search: %d", 1]; job->indepth_scan = 1; - if (burned == 1 || job->mux != HB_MUX_MP4) + + if (burned != 1) { - if (burned != 1 && job->mux == HB_MUX_MKV) - { - job->select_subtitle_config.dest = PASSTHRUSUB; - } - else - { - job->select_subtitle_config.dest = RENDERSUB; - } - - job->select_subtitle_config.force = force; - job->select_subtitle_config.default_track = def; - + job->select_subtitle_config.dest = PASSTHRUSUB; + } + else + { + job->select_subtitle_config.dest = RENDERSUB; } - + job->select_subtitle_config.force = force; + job->select_subtitle_config.default_track = def; } else { @@ -3310,17 +3167,10 @@ bool one_burned = FALSE; { hb_subtitle_config_t sub_config = subt->config; - if (!burned && job->mux == HB_MUX_MKV && - subt->format == PICTURESUB) + if ( !burned && subt->format == PICTURESUB ) { sub_config.dest = PASSTHRUSUB; } - else if (!burned && job->mux == HB_MUX_MP4 && - subt->format == PICTURESUB) - { - // Skip any non-burned vobsubs when output is mp4 - continue; - } else if ( burned && subt->format == PICTURESUB ) { // Only allow one subtitle to be burned into the video @@ -3447,6 +3297,7 @@ bool one_burned = FALSE; */ /* Detelecine */ + hb_filter_detelecine.settings = NULL; if ([fPictureController detelecine] == 1) { /* use a custom detelecine string */ @@ -3465,6 +3316,7 @@ bool one_burned = FALSE; { /* Decomb */ /* we add the custom string if present */ + hb_filter_decomb.settings = NULL; if ([fPictureController decomb] == 1) { /* use a custom decomb string */ @@ -3575,51 +3427,28 @@ bool one_burned = FALSE; /* we are pts based start / stop */ [self writeToActivityLog: "Start / Stop set to seconds ..."]; - /* Point A to Point B. Since we cannot get frame accurate start times, attempt to glean a semi-accurate start time based on a percentage of the - * scanned title time as per live preview, while in some cases inaccurate its the best I can do with what I have barring a pre-scan index afaik. - */ - /* Attempt to bastardize the live preview code to get a roughly 1 second accurate point a to point b encode ... */ + /* Point A to Point B. Time to time in seconds.*/ /* get the start seconds from the start seconds field */ int start_seconds = [[queueToApply objectForKey:@"StartSeconds"] intValue]; - //job->start_at_preview = start_seconds; - /* The number of seek points equals the number of seconds announced in the title as that is our current granularity */ - //job->seek_points = [[queueToApply objectForKey:@"SourceTotalSeconds"] intValue]; job->pts_to_start = start_seconds * 90000LL; /* Stop seconds is actually the duration of encode, so subtract the end seconds from the start seconds */ int stop_seconds = [[queueToApply objectForKey:@"StopSeconds"] intValue]; job->pts_to_stop = stop_seconds * 90000LL; - - /* A bunch of verbose activity log messages to check on what should be expected */ - [self writeToActivityLog: "point a to b should start at: %d seconds", start_seconds]; - [self writeToActivityLog: "point a to b should start at (hh:mm:ss): %d:%d:%d", start_seconds / 3600, ( start_seconds / 60 ) % 60,start_seconds % 60]; - [self writeToActivityLog: "point a to b duration: %d seconds", stop_seconds]; - [self writeToActivityLog: "point a to b duration (hh:mm:ss): %d:%d:%d", stop_seconds / 3600, ( stop_seconds / 60 ) % 60,stop_seconds % 60]; - [self writeToActivityLog: "point a to b should end at: %d seconds", start_seconds + stop_seconds]; - [self writeToActivityLog: "point a to b should end at (hh:mm:ss): %d:%d:%d", (start_seconds + stop_seconds) / 3600, ( (start_seconds + stop_seconds) / 60 ) % 60,(start_seconds + stop_seconds) % 60]; + } else if ([[queueToApply objectForKey:@"fEncodeStartStop"] intValue] == 2) { /* we are frame based start / stop */ [self writeToActivityLog: "Start / Stop set to frames ..."]; - /* Point A to Point B. Since we cannot get frame accurate start times, attempt to glean a semi-accurate start time based on a percentage of the - * scanned title time as per live preview, while in some cases inaccurate its the best I can do with what I have barring a pre-scan index afaik. - */ - /* Attempt to bastardize the live preview code to get a roughly 1 second accurate point a to point b encode ... */ - /* get the start seconds from the start seconds field */ + /* Point A to Point B. Frame to frame */ + /* get the start frame from the start frame field */ int start_frame = [[queueToApply objectForKey:@"StartFrame"] intValue]; - //job->start_at_preview = start_seconds; - /* The number of seek points equals the number of seconds announced in the title as that is our current granularity */ - //job->seek_points = [[queueToApply objectForKey:@"SourceTotalSeconds"] intValue]; job->frame_to_start = start_frame; - /* Stop seconds is actually the duration of encode, so subtract the end seconds from the start seconds */ + /* get the frame to stop on from the end frame field */ int stop_frame = [[queueToApply objectForKey:@"StopFrame"] intValue]; job->frame_to_stop = stop_frame; - - /* A bunch of verbose activity log messages to check on what should be expected */ - [self writeToActivityLog: "point a to b should start at frame %d", start_frame]; - [self writeToActivityLog: "point a to b duration: %d frames", stop_frame]; - [self writeToActivityLog: "point a to b should end at frame %d", start_frame + stop_frame]; + } @@ -3842,22 +3671,18 @@ bool one_burned = FALSE; [self writeToActivityLog: "Foreign Language Search: %d", 1]; job->indepth_scan = 1; - if (burned == 1 || job->mux != HB_MUX_MP4) + + if (burned != 1) { - if (burned != 1 && job->mux == HB_MUX_MKV) - { - job->select_subtitle_config.dest = PASSTHRUSUB; - } - else - { - job->select_subtitle_config.dest = RENDERSUB; - } - - job->select_subtitle_config.force = force; - job->select_subtitle_config.default_track = def; + job->select_subtitle_config.dest = PASSTHRUSUB; + } + else + { + job->select_subtitle_config.dest = RENDERSUB; } - + job->select_subtitle_config.force = force; + job->select_subtitle_config.default_track = def; } else { @@ -3906,17 +3731,10 @@ bool one_burned = FALSE; { hb_subtitle_config_t sub_config = subt->config; - if (!burned && job->mux == HB_MUX_MKV && - subt->format == PICTURESUB) + if ( !burned && subt->format == PICTURESUB ) { sub_config.dest = PASSTHRUSUB; } - else if (!burned && job->mux == HB_MUX_MP4 && - subt->format == PICTURESUB) - { - // Skip any non-burned vobsubs when output is mp4 - continue; - } else if ( burned && subt->format == PICTURESUB ) { // Only allow one subtitle to be burned into the video @@ -4023,6 +3841,7 @@ bool one_burned = FALSE; * The order of the filters is critical */ /* Detelecine */ + hb_filter_detelecine.settings = NULL; if ([[queueToApply objectForKey:@"PictureDetelecine"] intValue] == 1) { /* use a custom detelecine string */ @@ -4039,6 +3858,7 @@ bool one_burned = FALSE; { /* Decomb */ /* we add the custom string if present */ + hb_filter_decomb.settings = NULL; if ([[queueToApply objectForKey:@"PictureDecomb"] intValue] == 1) { /* use a custom decomb string */ @@ -4463,19 +4283,17 @@ bool one_burned = FALSE; hb_title_t * title = (hb_title_t*) hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] ); - /* If we are a stream type, grok the output file name from title->name upon title change */ - if (title->type == HB_STREAM_TYPE) + /* If we are a stream type and a batch scan, grok the output file name from title->name upon title change */ + if (title->type == HB_STREAM_TYPE && hb_list_count( list ) > 1 ) { /* we set the default name according to the new title->name */ [fDstFile2Field setStringValue: [NSString stringWithFormat: @"%@/%@.%@", [[fDstFile2Field stringValue] stringByDeletingLastPathComponent], [NSString stringWithUTF8String: title->name], [[fDstFile2Field stringValue] pathExtension]]]; - /* If we have more than one title and are stream then we have a batch, change the source to read out the parent folder also */ - if ( hb_list_count( list ) > 1 ) - { - [fSrcDVD2Field setStringValue:[NSString stringWithFormat:@"%@/%@", browsedSourceDisplayName,[NSString stringWithUTF8String: title->name]]]; - } + + /* Change the source to read out the parent folder also */ + [fSrcDVD2Field setStringValue:[NSString stringWithFormat:@"%@/%@", browsedSourceDisplayName,[NSString stringWithUTF8String: title->name]]]; } /* For point a to point b pts encoding, set the start and end fields to 0 and the title duration in seconds respectively */ @@ -5367,6 +5185,13 @@ the user is using "Custom" settings by determining the sender*/ /* We will first verify that a lower track number has been selected before enabling each track * for example, make sure a track is selected for track 1 before enabling track 2, etc. */ + + /* If the source has no audio then disable audio track 1 */ + if (hb_list_count( fTitle->list_audio ) == 0) + { + [fAudLang1PopUp selectItemAtIndex:0]; + } + if ([fAudLang1PopUp indexOfSelectedItem] == 0) { [fAudLang2PopUp setEnabled: NO]; @@ -5522,28 +5347,34 @@ the user is using "Custom" settings by determining the sender*/ /* e.g. to find the first French track, pass in an NSString * of "Francais" */ /* e.g. to find the first English 5.1 AC3 track, pass in an NSString * of "English (AC3) (5.1 ch)" */ /* if no matching track is found, then selectIndexIfNotFound is used to choose which track to select instead */ - - if (searchPrefixString) - { - - for( int i = 0; i < [sender numberOfItems]; i++ ) + if (hb_list_count( fTitle->list_audio ) != 0) + { + if (searchPrefixString) { - /* Try to find the desired search string */ - if ([[[sender itemAtIndex: i] title] hasPrefix:searchPrefixString]) + + for( int i = 0; i < [sender numberOfItems]; i++ ) { - [sender selectItemAtIndex: i]; - return; + /* Try to find the desired search string */ + if ([[[sender itemAtIndex: i] title] hasPrefix:searchPrefixString]) + { + [sender selectItemAtIndex: i]; + return; + } } + /* couldn't find the string, so select the requested "search string not found" item */ + /* index of 0 means select the "none" item */ + /* index of 1 means select the first audio track */ + [sender selectItemAtIndex: selectIndexIfNotFound]; } - /* couldn't find the string, so select the requested "search string not found" item */ - /* index of 0 means select the "none" item */ - /* index of 1 means select the first audio track */ - [sender selectItemAtIndex: selectIndexIfNotFound]; - } + else + { + /* if no search string is provided, then select the selectIndexIfNotFound item */ + [sender selectItemAtIndex: selectIndexIfNotFound]; + } + } else { - /* if no search string is provided, then select the selectIndexIfNotFound item */ - [sender selectItemAtIndex: selectIndexIfNotFound]; + [sender selectItemAtIndex: 0]; } } @@ -5586,14 +5417,15 @@ the user is using "Custom" settings by determining the sender*/ { case 0: /* MP4 */ - // FAAC - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_FAAC]; - // CA_AAC menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (CoreAudio)" action: NULL keyEquivalent: @""]; [menuItem setTag: HB_ACODEC_CA_AAC]; - + // FAAC + menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""]; + [menuItem setTag: HB_ACODEC_FAAC]; + // MP3 + menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""]; + [menuItem setTag: HB_ACODEC_LAME]; // AC3 Passthru menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""]; [menuItem setTag: HB_ACODEC_AC3]; @@ -5601,12 +5433,12 @@ the user is using "Custom" settings by determining the sender*/ case 1: /* MKV */ - // FAAC - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_FAAC]; // CA_AAC menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (CoreAudio)" action: NULL keyEquivalent: @""]; [menuItem setTag: HB_ACODEC_CA_AAC]; + // FAAC + menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AAC (faac)" action: NULL keyEquivalent: @""]; + [menuItem setTag: HB_ACODEC_FAAC]; // AC3 Passthru menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""]; [menuItem setTag: HB_ACODEC_AC3]; @@ -5620,26 +5452,6 @@ the user is using "Custom" settings by determining the sender*/ menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"Vorbis (vorbis)" action: NULL keyEquivalent: @""]; [menuItem setTag: HB_ACODEC_VORBIS]; break; - - case 2: - /* AVI */ - // MP3 - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_LAME]; - // AC3 Passthru - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"AC3 Passthru" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_AC3]; - break; - - case 3: - /* OGM */ - // Vorbis - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"Vorbis (vorbis)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_VORBIS]; - // MP3 - menuItem = [[audiocodecPopUp menu] addItemWithTitle:@"MP3 (lame)" action: NULL keyEquivalent: @""]; - [menuItem setTag: HB_ACODEC_LAME]; - break; } [audiocodecPopUp selectItemAtIndex:0]; } @@ -5660,6 +5472,12 @@ the user is using "Custom" settings by determining the sender*/ /* make sure we have a selected title before continuing */ if (fTitle == NULL) return; + /* make sure we have a source audio track before continuing */ + if (hb_list_count( fTitle->list_audio ) == 0) + { + [sender selectItemAtIndex:0]; + return; + } /* if the sender is the lanaguage popup and there is nothing in the codec popup, lets call * audioAddAudioTrackCodecs on the codec popup to populate it properly before moving on */ @@ -5758,16 +5576,10 @@ the user is using "Custom" settings by determining the sender*/ { /* find out if our selected output audio codec supports mono and / or 6ch */ - /* we also check for an input codec of AC3 or DCA, - as they are the only libraries able to do the mixdown to mono / conversion to 6-ch */ /* audioCodecsSupportMono and audioCodecsSupport6Ch are the same for now, but this may change in the future, so they are separated for flexibility */ - int audioCodecsSupportMono = - (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) && - (acodec != HB_ACODEC_LAME); - int audioCodecsSupport6Ch = - (audio->in.codec & (HB_ACODEC_AC3|HB_ACODEC_DCA)) && - (acodec != HB_ACODEC_LAME); + int audioCodecsSupportMono = (audio->in.codec && acodec != HB_ACODEC_LAME); + int audioCodecsSupport6Ch = (audio->in.codec && acodec != HB_ACODEC_LAME); /* check for AC-3 passthru */ if (audio->in.codec == HB_ACODEC_AC3 && acodec == HB_ACODEC_AC3) @@ -5911,37 +5723,19 @@ the user is using "Custom" settings by determining the sender*/ } /* In the case of a source track that is not AC3 and the user tries to use AC3 Passthru (which does not work) - * we force the Audio Codec choice back to a workable codec. We use MP3 for avi and aac for all - * other containers. + * we force the Audio Codec choice back to a workable codec. We use CoreAudio aac for all containers. */ if (audio->in.codec != HB_ACODEC_AC3 && [[audiocodecPopUp selectedItem] tag] == HB_ACODEC_AC3) { - /* If we are using the avi container, we select MP3 as there is no aac available*/ - if ([[fDstFormatPopUp selectedItem] tag] == HB_MUX_AVI) - { - [audiocodecPopUp selectItemWithTag: HB_ACODEC_LAME]; - } - else - { - [audiocodecPopUp selectItemWithTag: HB_ACODEC_FAAC]; - } + [audiocodecPopUp selectItemWithTag: HB_ACODEC_CA_AAC]; } /* In the case of a source track that is not DTS and the user tries to use DTS Passthru (which does not work) - * we force the Audio Codec choice back to a workable codec. We use MP3 for avi and aac for all - * other containers. + * we force the Audio Codec choice back to a workable codec. We use CoreAudio aac for all containers. */ if (audio->in.codec != HB_ACODEC_DCA && [[audiocodecPopUp selectedItem] tag] == HB_ACODEC_DCA) { - /* If we are using the avi container, we select MP3 as there is no aac available*/ - if ([[fDstFormatPopUp selectedItem] tag] == HB_MUX_AVI) - { - [audiocodecPopUp selectItemWithTag: HB_ACODEC_LAME]; - } - else - { - [audiocodecPopUp selectItemWithTag: HB_ACODEC_FAAC]; - } + [audiocodecPopUp selectItemWithTag: HB_ACODEC_CA_AAC]; } /* Setup our samplerate and bitrate popups we will need based on mixdown */ @@ -6022,17 +5816,16 @@ the user is using "Custom" settings by determining the sender*/ { /* FAAC has a minimum of 192 kbps for 6-channel discrete */ minbitrate = 192; - /* If either mixdown popup includes 6-channel discrete, then allow up to 448 kbps */ - maxbitrate = 448; + /* If either mixdown popup includes 6-channel discrete, then allow up to 768 kbps */ + maxbitrate = 768; break; } else { /* FAAC is happy using our min bitrate of 32 kbps for stereo or mono */ minbitrate = 32; - /* FAAC won't honour anything more than 160 for stereo, so let's not offer it */ /* note: haven't dealt with mono separately here, FAAC will just use the max it can */ - maxbitrate = 160; + maxbitrate = 320; break; } @@ -6084,7 +5877,7 @@ the user is using "Custom" settings by determining the sender*/ } /* make sure we have a selected title before continuing */ - if (fTitle == NULL) return; + if (fTitle == NULL || hb_list_count( fTitle->list_audio ) == 0) return; /* get the audio so we can find out what input rates are*/ hb_audio_config_t * audio; audio = (hb_audio_config_t *) hb_list_audio_config_item( fTitle->list_audio, [audiotrackPopUp indexOfSelectedItem] - 1 ); @@ -6772,6 +6565,7 @@ return YES; { /* pointer to this track's mixdown, codec, sample rate and bitrate NSPopUpButton's */ + NSPopUpButton * trackLangPreviousPopUp = nil; NSPopUpButton * trackLangPopUp = nil; NSPopUpButton * mixdownPopUp = nil; NSPopUpButton * audiocodecPopUp = nil; @@ -6798,6 +6592,7 @@ return YES; } if( i == 2 ) { + trackLangPreviousPopUp = fAudLang1PopUp; trackLangPopUp = fAudLang2PopUp; mixdownPopUp = fAudTrack2MixPopUp; audiocodecPopUp = fAudTrack2CodecPopUp; @@ -6807,6 +6602,7 @@ return YES; } if( i == 3 ) { + trackLangPreviousPopUp = fAudLang2PopUp; trackLangPopUp = fAudLang3PopUp; mixdownPopUp = fAudTrack3MixPopUp; audiocodecPopUp = fAudTrack3CodecPopUp; @@ -6816,6 +6612,7 @@ return YES; } if( i == 4 ) { + trackLangPreviousPopUp = fAudLang3PopUp; trackLangPopUp = fAudLang4PopUp; mixdownPopUp = fAudTrack4MixPopUp; audiocodecPopUp = fAudTrack4CodecPopUp; @@ -6827,12 +6624,22 @@ return YES; if ([trackLangPopUp indexOfSelectedItem] == 0) { - [trackLangPopUp selectItemAtIndex: 1]; + if (i ==1) + { + [trackLangPopUp selectItemAtIndex: 1]; + } + else + { + /* if we are greater than track 1, select + * the same track as the previous track */ + [trackLangPopUp selectItemAtIndex: [trackLangPreviousPopUp indexOfSelectedItem]]; + } } [self audioTrackPopUpChanged: trackLangPopUp]; [audiocodecPopUp selectItemWithTitle:[tempObject objectForKey:@"AudioEncoder"]]; - /* check our pref for core audio and use it in place of faac if applicable */ - if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && + /* check our pref for core audio and use it in place of faac if preset is a built in */ + if ([[chosenPreset objectForKey:@"Type"] intValue] == 0 && + [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && [[tempObject objectForKey:@"AudioEncoder"] isEqualToString: @"AAC (faac)"]) { [audiocodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; @@ -6926,12 +6733,14 @@ return YES; } [self audioTrackPopUpChanged: fAudLang1PopUp]; [fAudTrack1CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Encoder"]]; - /* check our pref for core audio and use it in place of faac if applicable */ - if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && + /* check our pref for core audio and use it in place of faac if preset is built in */ + if ([[chosenPreset objectForKey:@"Type"] intValue] == 0 && + [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && [[chosenPreset objectForKey:@"Audio1Encoder"] isEqualToString: @"AAC (faac)"]) { [fAudTrack1CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; } + [self audioTrackPopUpChanged: fAudTrack1CodecPopUp]; [fAudTrack1MixPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio1Mixdown"]]; /* check to see if the selections was available, if not, rerun audioTrackPopUpChanged using the codec to just set the default @@ -6958,8 +6767,9 @@ return YES; } [self audioTrackPopUpChanged: fAudLang2PopUp]; [fAudTrack2CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio2Encoder"]]; - /* check our pref for core audio and use it in place of faac if applicable */ - if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && + /* check our pref for core audio and use it in place of faac if preset is built in */ + if ([[chosenPreset objectForKey:@"Type"] intValue] == 0 && + [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && [[chosenPreset objectForKey:@"Audio2Encoder"] isEqualToString: @"AAC (faac)"]) { [fAudTrack2CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; @@ -6989,8 +6799,9 @@ return YES; } [self audioTrackPopUpChanged: fAudLang3PopUp]; [fAudTrack3CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio3Encoder"]]; - /* check our pref for core audio and use it in place of faac if applicable */ - if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && + /* check our pref for core audio and use it in place of faac if preset is built in */ + if ([[chosenPreset objectForKey:@"Type"] intValue] == 0 && + [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && [[chosenPreset objectForKey:@"Audio3Encoder"] isEqualToString: @"AAC (faac)"]) { [fAudTrack3CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; @@ -7020,8 +6831,9 @@ return YES; } [self audioTrackPopUpChanged: fAudLang4PopUp]; [fAudTrack4CodecPopUp selectItemWithTitle:[chosenPreset objectForKey:@"Audio4Encoder"]]; - /* check our pref for core audio and use it in place of faac if applicable */ - if ([[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && + /* check our pref for core audio and use it in place of faac if preset is built in */ + if ([[chosenPreset objectForKey:@"Type"] intValue] == 0 && + [[NSUserDefaults standardUserDefaults] boolForKey: @"UseCoreAudio"] == YES && [[chosenPreset objectForKey:@"Audio4Encoder"] isEqualToString: @"AAC (faac)"]) { [fAudTrack4CodecPopUp selectItemWithTitle:@"AAC (CoreAudio)"]; @@ -8047,6 +7859,154 @@ return YES; } +#pragma mark - +#pragma mark Chapter Files Import / Export + +- (IBAction) browseForChapterFile: (id) sender +{ + /* Open a panel to let the user choose the file */ + NSOpenPanel * panel = [NSOpenPanel openPanel]; + /* We get the current file name and path from the destination field here */ + [panel beginSheetForDirectory: [NSString stringWithFormat:@"%@/", + [[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"]] + file: NULL + types: [NSArray arrayWithObjects:@"csv",nil] + modalForWindow: fWindow modalDelegate: self + didEndSelector: @selector( browseForChapterFileDone:returnCode:contextInfo: ) + contextInfo: NULL]; +} + +- (void) browseForChapterFileDone: (NSOpenPanel *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo +{ + NSArray *chaptersArray; /* temp array for chapters */ + NSMutableArray *chaptersMutableArray; /* temp array for chapters */ + NSString *chapterName; /* temp string from file */ + int chapters, i; + + if( returnCode == NSOKButton ) /* if they click OK */ + { + chapterName = [[NSString alloc] initWithContentsOfFile:[sheet filename] encoding:NSUTF8StringEncoding error:NULL]; + chaptersArray = [chapterName componentsSeparatedByString:@"\n"]; + chaptersMutableArray= [chaptersArray mutableCopy]; + chapters = [fChapterTitlesDelegate numberOfRowsInTableView:fChapterTable]; + if ([chaptersMutableArray count] > 0) + { + /* if last item is empty remove it */ + if ([[chaptersMutableArray objectAtIndex:[chaptersArray count]-1] length] == 0) + { + [chaptersMutableArray removeLastObject]; + } + } + /* if chapters in table is not equal to array count */ + if ((unsigned int) chapters != [chaptersMutableArray count]) + { + [sheet close]; + [[NSAlert alertWithMessageText:NSLocalizedString(@"Unable to load chapter file", @"Unable to load chapter file") + defaultButton:NSLocalizedString(@"OK", @"OK") + alternateButton:NULL + otherButton:NULL + informativeTextWithFormat:NSLocalizedString(@"%d chapters expected, %d chapters found in %@", @"%d chapters expected, %d chapters found in %@"), + chapters, [chaptersMutableArray count], [[sheet filename] lastPathComponent]] runModal]; + return; + } + /* otherwise, go ahead and populate table with array */ + for (i=0; i 5) + { + /* avoid a segfault */ + /* Get the Range.location of the first comma in the line and then put everything after that into chapterTitle */ + NSRange firstCommaRange = [[chaptersMutableArray objectAtIndex:i] rangeOfString:@","]; + NSString *chapterTitle = [[chaptersMutableArray objectAtIndex:i] substringFromIndex:firstCommaRange.location + 1]; + /* Since we store our chapterTitle commas as "\," for the cli, we now need to remove the escaping "\" from the title */ + chapterTitle = [chapterTitle stringByReplacingOccurrencesOfString:@"\\," withString:@","]; + [fChapterTitlesDelegate tableView:fChapterTable + setObjectValue:chapterTitle + forTableColumn:fChapterTableNameColumn + row:i]; + } + else + { + [sheet close]; + [[NSAlert alertWithMessageText:NSLocalizedString(@"Unable to load chapter file", @"Unable to load chapter file") + defaultButton:NSLocalizedString(@"OK", @"OK") + alternateButton:NULL + otherButton:NULL + informativeTextWithFormat:NSLocalizedString(@"%@ was not formatted as expected.", @"%@ was not formatted as expected."), [[sheet filename] lastPathComponent]] runModal]; + [fChapterTable reloadData]; + return; + } + } + [fChapterTable reloadData]; + } +} + +- (IBAction) browseForChapterFileSave: (id) sender +{ + NSSavePanel *panel = [NSSavePanel savePanel]; + /* Open a panel to let the user save to a file */ + [panel setAllowedFileTypes:[NSArray arrayWithObjects:@"csv",nil]]; + [panel beginSheetForDirectory: [[fDstFile2Field stringValue] stringByDeletingLastPathComponent] + file: [[[[fDstFile2Field stringValue] lastPathComponent] stringByDeletingPathExtension] + stringByAppendingString:@"-chapters.csv"] + modalForWindow: fWindow + modalDelegate: self + didEndSelector: @selector( browseForChapterFileSaveDone:returnCode:contextInfo: ) + contextInfo: NULL]; +} + +- (void) browseForChapterFileSaveDone: (NSSavePanel *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo +{ + NSString *chapterName; /* pointer for string for later file-writing */ + NSString *chapterTitle; + NSError *saveError = [[NSError alloc] init]; + int chapters, i; /* ints for the number of chapters in the table and the loop */ + + if( returnCode == NSOKButton ) /* if they clicked OK */ + { + chapters = [fChapterTitlesDelegate numberOfRowsInTableView:fChapterTable]; + chapterName = [NSString string]; + for (i=0; i