X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=macosx%2FController.m;h=6526d15985f4c24b614efee763a79c0d1bd5fca9;hb=4f0019f03c2e85e8634150ff0c9a31bee6d35ce5;hp=a25b273a9b533eafc7147c531b3aa8a2c5084ba8;hpb=747f309a44bee16c176837f3d24514cfbcc085d3;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/macosx/Controller.m b/macosx/Controller.m index a25b273a..6526d159 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -514,7 +514,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++ ) @@ -1803,9 +1803,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 ); @@ -1879,11 +1877,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 @@ -1899,8 +1896,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]; @@ -2047,7 +2044,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]; @@ -2244,7 +2241,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"]; @@ -2443,7 +2440,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"]; @@ -2451,7 +2447,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"]; @@ -2459,7 +2454,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"]; @@ -2467,14 +2461,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; @@ -2525,21 +2517,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 { @@ -2553,13 +2541,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]; @@ -2622,8 +2608,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 ); } @@ -2645,7 +2630,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]; /* @@ -2720,7 +2704,6 @@ fWorkingCount = 0; free(subtitle); } - /* We should be all setup so let 'er rip */ [self doRip]; } @@ -2817,7 +2800,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*/ @@ -2921,7 +2904,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"]]; @@ -2981,9 +2963,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. @@ -3081,10 +3060,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*/ @@ -3243,23 +3221,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 { @@ -3307,17 +3280,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 @@ -3444,6 +3410,7 @@ bool one_burned = FALSE; */ /* Detelecine */ + hb_filter_detelecine.settings = NULL; if ([fPictureController detelecine] == 1) { /* use a custom detelecine string */ @@ -3462,6 +3429,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 */ @@ -3573,20 +3541,13 @@ bool one_burned = FALSE; [self writeToActivityLog: "Start / Stop set to seconds ..."]; /* Point A to Point B. Time to time in seconds.*/ - /* get the start seconds from the start seconds field */ + /* get the start seconds from the start seconds field */ int start_seconds = [[queueToApply objectForKey:@"StartSeconds"] 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) { @@ -3594,17 +3555,13 @@ bool one_burned = FALSE; [self writeToActivityLog: "Start / Stop set to frames ..."]; /* Point A to Point B. Frame to frame */ - /* get the start frame from the start frame field */ + /* get the start frame from the start frame field */ int start_frame = [[queueToApply objectForKey:@"StartFrame"] intValue]; job->frame_to_start = start_frame; /* 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]; + } @@ -3827,22 +3784,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 { @@ -3891,17 +3844,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 @@ -4008,6 +3954,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 */ @@ -4024,6 +3971,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 */ @@ -5588,6 +5536,9 @@ the user is using "Custom" settings by determining the sender*/ // 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]; @@ -5978,17 +5929,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; } @@ -8022,6 +7972,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