/* HBChapterTitlesController.m $ This file is part of the HandBrake source code. Homepage: . It may be used under the terms of the GNU General Public License. */ #import "HBChapterTitlesController.h" @import HandBrakeKit.HBChapter; @import HandBrakeKit.HBJob; @interface HBChapterTitlesController () @property (weak) IBOutlet NSTableView *table; @property (nonatomic, readwrite, strong) NSArray *chapterTitles; @end @implementation HBChapterTitlesController - (instancetype)init { self = [super initWithNibName:@"ChaptersTitles" bundle:nil]; if (self) { _chapterTitles = [[NSMutableArray alloc] init]; } return self; } - (void)setJob:(HBJob *)job { _job = job; self.chapterTitles = job.chapterTitles; } /** * Method to edit the next chapter when the user presses Return. * We queue the action on the runloop to avoid interfering * with the chain of events that handles the edit. */ - (void)controlTextDidEndEditing:(NSNotification *)notification { NSTableView *chapterTable = self.table; NSInteger column = 2; NSInteger row = [self.table rowForView:[notification object]]; NSInteger textMovement; // Edit the cell in the next row, same column row++; textMovement = [[notification userInfo][@"NSTextMovement"] integerValue]; if (textMovement == NSReturnTextMovement && row < chapterTable.numberOfRows) { NSArray *info = @[chapterTable, @(column), @(row)]; // The delay is unimportant; editNextRow: won't be called until the responder // chain finishes because the event loop containing the timer is on this thread [self performSelector:@selector(editNextRow:) withObject:info afterDelay:0.0]; } } - (void)editNextRow:(id)objects { NSTableView *chapterTable = objects[0]; NSInteger column = [objects[1] integerValue]; NSInteger row = [objects[2] integerValue]; if (row >= 0 && row < chapterTable.numberOfRows) { [chapterTable selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO]; [chapterTable editColumn:column row:row withEvent:nil select:YES]; } } #pragma mark - Chapter Files Import / Export - (IBAction)browseForChapterFile:(id)sender { // We get the current file name and path from the destination field here NSURL *sourceDirectory = [[NSUserDefaults standardUserDefaults] URLForKey:@"HBLastDestinationDirectory"]; // Open a panel to let the user choose the file NSOpenPanel *panel = [NSOpenPanel openPanel]; panel.allowedFileTypes = @[@"csv"]; panel.directoryURL = sourceDirectory; [panel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result) { if (result == NSFileHandlingPanelOKButton) { NSString *csv = [[NSString alloc] initWithContentsOfURL:panel.URL encoding:NSUTF8StringEncoding error:NULL]; NSMutableArray *csvArray = [[csv componentsSeparatedByString:@"\n"] mutableCopy]; NSUInteger count = self.chapterTitles.count; if (csvArray.count > 0) { // if last item is empty remove it if ([csvArray.lastObject length] == 0) { [csvArray removeLastObject]; } } // if chapters in table is not equal to array count if (count != csvArray.count) { [panel close]; [[NSAlert alertWithMessageText:NSLocalizedString(@"Unable to load chapter file", nil) defaultButton:NSLocalizedString(@"OK", nil) alternateButton:NULL otherButton:NULL informativeTextWithFormat:NSLocalizedString(@"%d chapters expected, %d chapters found in %@", nil), count, csvArray.count, panel.URL.lastPathComponent] runModal]; } else { // otherwise, go ahead and populate table with array NSUInteger idx = 0; for (NSString *csvLine in csvArray) { if (csvLine.length > 4) { // Get the Range.location of the first comma in the line and then put everything after that into chapterTitle NSRange firstCommaRange = [csvLine rangeOfString:@","]; NSString *chapterTitle = [csvLine 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:@","]; [self.chapterTitles[idx] setTitle:chapterTitle]; idx++; } else { [panel close]; [[NSAlert alertWithMessageText:NSLocalizedString(@"Unable to load chapter file", nil) defaultButton:NSLocalizedString(@"OK", nil) alternateButton:NULL otherButton:NULL informativeTextWithFormat:NSLocalizedString(@"%@ was not formatted as expected.", nil), panel.URL.lastPathComponent] runModal]; break; } } } } }]; } - (IBAction)browseForChapterFileSave:(id)sender { NSURL *destinationDirectory = [[NSUserDefaults standardUserDefaults] URLForKey:@"HBLastDestinationDirectory"]; NSSavePanel *panel = [NSSavePanel savePanel]; panel.allowedFileTypes = @[@"csv"]; panel.directoryURL = destinationDirectory; panel.nameFieldStringValue = self.job.destURL.lastPathComponent.stringByDeletingPathExtension; [panel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result) { if (result == NSFileHandlingPanelOKButton) { NSError *saveError; NSMutableString *csv = [NSMutableString string]; NSInteger idx = 0; for (HBChapter *chapter in self.chapterTitles) { // put each chapter title from the table into the array [csv appendFormat:@"%03ld,",idx + 1]; idx++; // Escape any commas in the chapter name with "\," NSString *sanatizedTitle = [chapter.title stringByReplacingOccurrencesOfString:@"," withString:@"\\,"]; [csv appendString:sanatizedTitle]; [csv appendString:@"\n"]; } [csv deleteCharactersInRange:NSMakeRange(csv.length - 1, 1)]; // try to write it to where the user wanted if (![csv writeToURL:panel.URL atomically:YES encoding:NSUTF8StringEncoding error:&saveError]) { [panel close]; [[NSAlert alertWithError:saveError] runModal]; } } }]; } @end