/* ChapterTitles.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 "Controller.h" #import "HBJob.h" @interface HBChapterTitlesController () { NSMutableArray *fChapterTitlesArray; IBOutlet NSTableView * fChapterTable; IBOutlet NSButton * fLoadChaptersButton; IBOutlet NSButton * fSaveChaptersButton; IBOutlet NSButton * fCreateChaptersMarkers; IBOutlet NSTableColumn * fChapterTableNameColumn; } @end @implementation HBChapterTitlesController @synthesize enabled = _enabled; - (instancetype)init { self = [super initWithNibName:@"ChaptersTitles" bundle:nil]; if (self) { fChapterTitlesArray = [[[NSMutableArray alloc] init] retain]; } return self; } - (void)dealloc { [fChapterTitlesArray release]; [super dealloc]; } - (void)setJob:(HBJob *)job { [fChapterTitlesArray removeAllObjects]; [fChapterTitlesArray addObjectsFromArray:job.title.chapters]; [fChapterTable reloadData]; } - (void)addChaptersFromQueue:(NSMutableArray *)newChaptersArray { [fChapterTitlesArray removeAllObjects]; [fChapterTitlesArray addObjectsFromArray:newChaptersArray]; [fChapterTable reloadData]; } - (void)setEnabled:(BOOL)enabled { [fCreateChaptersMarkers setEnabled:enabled]; [fChapterTable setEnabled:enabled]; [fLoadChaptersButton setEnabled:enabled]; [fSaveChaptersButton setEnabled:enabled]; } - (NSArray *)chapterTitlesArray { return [NSArray arrayWithArray:fChapterTitlesArray]; } - (IBAction)createChapterMarkersChanged:(id)sender { [[NSNotificationCenter defaultCenter] postNotificationName:HBMixdownChangedNotification object:self]; } - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView { return [fChapterTitlesArray count]; } - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { if (aTableColumn != nil && [[aTableColumn identifier] intValue] == 2) { [fChapterTitlesArray replaceObjectAtIndex:rowIndex withObject:[NSString stringWithString:anObject]]; } } - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { if ([[aTableColumn identifier] intValue] == 1) { return [NSString stringWithFormat:@"%ld", rowIndex + 1]; } else { return [NSString stringWithString:[fChapterTitlesArray objectAtIndex:rowIndex]]; } return @"__DATA ERROR__"; } /* Method to edit the next chapter when the user presses Return. We have to use a timer to avoid interfering with the chain of events that handles the edit. */ - (void)controlTextDidEndEditing: (NSNotification *) notification { NSTableView *chapterTable = [notification object]; NSInteger column = [chapterTable editedColumn]; NSInteger row = [chapterTable editedRow]; NSInteger textMovement; // Edit the cell in the next row, same column row++; textMovement = [[[notification userInfo] objectForKey:@"NSTextMovement"] integerValue]; if( textMovement == NSReturnTextMovement && row < [chapterTable numberOfRows] ) { NSArray *info = [NSArray arrayWithObjects:chapterTable, [NSNumber numberWithInteger:column], [NSNumber numberWithInteger:row], nil]; /* 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 objectAtIndex:0]; NSInteger column = [[objects objectAtIndex:1] integerValue]; NSInteger row = [[objects objectAtIndex: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 - #pragma mark Chapter Files Import / Export - (IBAction) browseForChapterFile: (id) sender { /* We get the current file name and path from the destination field here */ NSString *sourceDirectory = [[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"]; /* Open a panel to let the user choose the file */ NSOpenPanel *panel = [NSOpenPanel openPanel]; [panel setDirectoryURL:[NSURL fileURLWithPath:sourceDirectory]]; [panel setAllowedFileTypes:@[@"csv"]]; [panel beginSheetModalForWindow:[[self view] window] completionHandler:^(NSInteger result) { NSArray *chaptersArray = nil; /* temp array for chapters */ NSMutableArray *chaptersMutableArray = nil; /* temp array for chapters */ NSString *chapterName = nil; /* temp string from file */ NSInteger chapters, i; if (result == NSOKButton) /* if they click OK */ { chapterName = [[NSString alloc] initWithContentsOfURL:[panel URL] encoding:NSUTF8StringEncoding error:NULL]; chaptersArray = [chapterName componentsSeparatedByString:@"\n"]; [chapterName release]; chaptersMutableArray = [[chaptersArray mutableCopy] autorelease]; chapters = [self 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]) { [panel 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], [[panel URL] 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:@","]; [self tableView:fChapterTable setObjectValue:chapterTitle forTableColumn:fChapterTableNameColumn row:i]; } else { [panel 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."), [[panel URL] lastPathComponent]] runModal]; [fChapterTable reloadData]; return; } } [fChapterTable reloadData]; } }]; } - (IBAction) browseForChapterFileSave: (id) sender { NSString *destinationDirectory = [[NSUserDefaults standardUserDefaults] stringForKey:@"LastDestinationDirectory"]; /* Open a panel to let the user save to a file */ NSSavePanel *panel = [NSSavePanel savePanel]; [panel setAllowedFileTypes:@[@"csv"]]; [panel setDirectoryURL:[NSURL fileURLWithPath:destinationDirectory]]; //[panel setNameFieldStringValue:[[[fDstFile2Field stringValue] lastPathComponent] stringByDeletingPathExtension]]; [panel beginSheetModalForWindow:[[self view] window] completionHandler:^(NSInteger result) { NSString *chapterName; /* pointer for string for later file-writing */ NSString *chapterTitle; NSError *saveError = nil; NSInteger chapters, i; /* ints for the number of chapters in the table and the loop */ if( result == NSOKButton ) /* if they clicked OK */ { chapters = [self numberOfRowsInTableView:fChapterTable]; chapterName = [NSString string]; for (i=0; i