diff options
Diffstat (limited to 'macosx/HBSubtitlesController.m')
-rw-r--r-- | macosx/HBSubtitlesController.m | 533 |
1 files changed, 24 insertions, 509 deletions
diff --git a/macosx/HBSubtitlesController.m b/macosx/HBSubtitlesController.m index 509ab0de5..3fb0b7f50 100644 --- a/macosx/HBSubtitlesController.m +++ b/macosx/HBSubtitlesController.m @@ -10,23 +10,11 @@ #import "HBSubtitles.h" #import "HBSubtitlesDefaults.h" -#include "hb.h" -#include "lang.h" - -static void *HBSubtitlesControllerContext = &HBSubtitlesControllerContext; - -@interface HBSubtitlesController () <NSTableViewDataSource, NSTableViewDelegate> - -// IBOutles -@property (unsafe_unretained) IBOutlet NSTableView *fTableView; +@interface HBSubtitlesController () // Defaults @property (nonatomic, readwrite, strong) HBSubtitlesDefaultsController *defaultsController; -// Cached table view's cells -@property (nonatomic, readonly) NSPopUpButtonCell *languagesCell; -@property (nonatomic, readonly) NSPopUpButtonCell *encodingsCell; - @end @implementation HBSubtitlesController @@ -34,41 +22,12 @@ static void *HBSubtitlesControllerContext = &HBSubtitlesControllerContext; - (instancetype)init { self = [super initWithNibName:@"Subtitles" bundle:nil]; - - [self addObserver:self forKeyPath:@"self.subtitles.tracks" options:NSKeyValueObservingOptionInitial context:HBSubtitlesControllerContext]; - return self; } -#pragma mark - KVO - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ - if (context == HBSubtitlesControllerContext) - { - // We use KVO to update the table manually - // because this table isn't using bindings - if ([keyPath isEqualToString:@"self.subtitles.tracks"]) - { - [self.fTableView reloadData]; - } - } - else - { - [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; - } -} - -- (void)setSubtitles:(HBSubtitles *)subtitles -{ - _subtitles = subtitles; - - [self.fTableView reloadData]; -} - #pragma mark - Actions -- (BOOL)validateUserInterfaceItem:(id < NSValidatedUserInterfaceItem >)anItem +- (BOOL)validateUserInterfaceItem:(id<NSValidatedUserInterfaceItem>)anItem { return (self.subtitles != nil); } @@ -79,7 +38,6 @@ static void *HBSubtitlesControllerContext = &HBSubtitlesControllerContext; - (IBAction)addAll:(id)sender { [self.subtitles addAllTracks]; - [self.fTableView reloadData]; } /** @@ -88,7 +46,6 @@ static void *HBSubtitlesControllerContext = &HBSubtitlesControllerContext; - (IBAction)removeAll:(id)sender { [self.subtitles removeAll]; - [self.fTableView reloadData]; } /** @@ -98,15 +55,14 @@ static void *HBSubtitlesControllerContext = &HBSubtitlesControllerContext; - (IBAction)addTracksFromDefaults:(id)sender { [self.subtitles reloadDefaults]; - [self.fTableView reloadData]; } - (IBAction)showSettingsSheet:(id)sender { self.defaultsController = [[HBSubtitlesDefaultsController alloc] initWithSettings:self.subtitles.defaults]; - [NSApp beginSheet:[self.defaultsController window] - modalForWindow:[[self view] window] + [NSApp beginSheet:self.defaultsController.window + modalForWindow:self.view.window modalDelegate:self didEndSelector:@selector(sheetDidEnd) contextInfo:NULL]; @@ -117,388 +73,6 @@ static void *HBSubtitlesControllerContext = &HBSubtitlesControllerContext; self.defaultsController = nil; } -#pragma mark - Subtitles tracks creation and validation - -/** - * Checks whether any subtitles in the list cannot be passed through. - * Set the first of any such subtitles to burned-in, remove the others. - */ -- (void)validatePassthru -{ - [self.subtitles validatePassthru]; - [self.fTableView reloadData]; -} - -- (void)validateBurned:(NSInteger)index -{ - [self.subtitles.tracks enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) - { - if (idx != index) - { - obj[keySubTrackBurned] = @0; - } - }]; - [self validatePassthru]; -} - -- (void)validateDefault:(NSInteger)index -{ - [self.subtitles.tracks enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) - { - if (idx != index) - { - obj[keySubTrackDefault] = @0; - } - }]; -} - -#pragma mark - -#pragma mark Subtitle Table Data Source Methods - -- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView -{ - return self.subtitles.tracks.count; -} - -- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex -{ - NSDictionary *track = self.subtitles.tracks[rowIndex]; - - if ([[aTableColumn identifier] isEqualToString:@"track"]) - { - NSNumber *index = track[keySubTrackSelectionIndex]; - if (index) - return index; - else - return @0; - } - else if ([[aTableColumn identifier] isEqualToString:@"forced"]) - { - return track[keySubTrackForced]; - } - else if ([[aTableColumn identifier] isEqualToString:@"burned"]) - { - return track[keySubTrackBurned]; - } - else if ([[aTableColumn identifier] isEqualToString:@"default"]) - { - return track[keySubTrackDefault]; - } - /* These next three columns only apply to srt's. they are disabled for source subs */ - else if ([[aTableColumn identifier] isEqualToString:@"srt_lang"]) - { - if ([track[keySubTrackType] intValue] == SRTSUB) - { - return track[keySubTrackLanguageIndex]; - } - else - { - return @0; - } - } - else if ([[aTableColumn identifier] isEqualToString:@"srt_charcode"]) - { - if ([track[keySubTrackType] intValue] == SRTSUB) - { - return track[keySubTrackSrtCharCodeIndex]; - } - else - { - return @0; - } - } - else if ([[aTableColumn identifier] isEqualToString:@"srt_offset"]) - { - if (track[keySubTrackSrtOffset]) - { - return [track[keySubTrackSrtOffset] stringValue]; - } - else - { - return @"0"; - } - } - - return nil; -} - -/** - * Called whenever a widget in the table is edited or changed, we use it to record the change in the controlling array - * including removing and adding new tracks via the "None" ("track" index of 0) - */ -- (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex -{ - if ([[aTableColumn identifier] isEqualToString:@"track"]) - { - /* Set the array to track if we are vobsub (picture sub) */ - if ([anObject intValue] > 0) - { - NSMutableDictionary *newTrack = [self.subtitles trackFromSourceTrackIndex:[anObject integerValue] - 1 - (rowIndex == 0)]; - // Selection index calculation - newTrack[keySubTrackSelectionIndex] = @([anObject integerValue]); - self.subtitles.tracks[rowIndex] = newTrack; - } - } - else if ([[aTableColumn identifier] isEqualToString:@"forced"]) - { - self.subtitles.tracks[rowIndex][keySubTrackForced] = @([anObject intValue]); - } - else if ([[aTableColumn identifier] isEqualToString:@"burned"]) - { - self.subtitles.tracks[rowIndex][keySubTrackBurned] = @([anObject intValue]); - if([anObject intValue] == 1) - { - /* Burned In and Default are mutually exclusive */ - self.subtitles.tracks[rowIndex][keySubTrackDefault] = @0; - } - /* now we need to make sure no other tracks are set to burned if we have set burned */ - if ([anObject intValue] == 1) - { - [self validateBurned:rowIndex]; - } - } - else if ([[aTableColumn identifier] isEqualToString:@"default"]) - { - self.subtitles.tracks[rowIndex][keySubTrackDefault] = @([anObject intValue]); - if([anObject intValue] == 1) - { - /* Burned In and Default are mutually exclusive */ - self.subtitles.tracks[rowIndex][keySubTrackBurned] = @0; - } - /* now we need to make sure no other tracks are set to default */ - if ([anObject intValue] == 1) - { - [self validateDefault:rowIndex]; - } - } - /* These next three columns only apply to srt's. they are disabled for source subs */ - else if ([[aTableColumn identifier] isEqualToString:@"srt_lang"]) - { - self.subtitles.tracks[rowIndex][keySubTrackLanguageIndex] = @([anObject intValue]); - self.subtitles.tracks[rowIndex][keySubTrackLanguageIsoCode] = self.subtitles.languagesArray[[anObject intValue]][1]; - } - else if ([[aTableColumn identifier] isEqualToString:@"srt_charcode"]) - { - /* charCodeArray */ - self.subtitles.tracks[rowIndex][keySubTrackSrtCharCodeIndex] = @([anObject intValue]); - self.subtitles.tracks[rowIndex][keySubTrackSrtCharCode] = self.subtitles.charCodeArray[[anObject intValue]]; - } - else if ([[aTableColumn identifier] isEqualToString:@"srt_offset"]) - { - self.subtitles.tracks[rowIndex][keySubTrackSrtOffset] = @([anObject integerValue]); - } - - /* now lets do a bit of logic to add / remove tracks as necessary via the "None" track (index 0) */ - if ([[aTableColumn identifier] isEqualToString:@"track"]) - { - /* Since currently no quicktime based playback devices support soft vobsubs in mp4, we make sure "burned in" is specified - * by default to avoid massive confusion and anarchy. However we also want to guard against multiple burned in subtitle tracks - * as libhb would ignore all but the first one anyway. Plus it would probably be stupid. - */ - if ((self.subtitles.container & HB_MUX_MASK_MP4) && ([anObject intValue] != 0)) - { - if ([self.subtitles.tracks[rowIndex][keySubTrackType] intValue] == VOBSUB) - { - /* lets see if there are currently any burned in subs specified */ - BOOL subtrackBurnedInFound = NO; - for (id tempObject in self.subtitles.tracks) - { - if ([tempObject[keySubTrackBurned] intValue] == 1) - { - subtrackBurnedInFound = YES; - } - } - /* if we have no current vobsub set to burn it in ... burn it in by default */ - if (!subtrackBurnedInFound) - { - self.subtitles.tracks[rowIndex][keySubTrackBurned] = @1; - /* Burned In and Default are mutually exclusive */ - self.subtitles.tracks[rowIndex][keySubTrackDefault] = @0; - } - } - } - - /* We use the track popup index number (presumes index 0 is "None" which is ignored and only used to remove tracks if need be) - * to determine whether to 1 modify an existing track, 2. add a new empty "None" track or 3. remove an existing track. - */ - - if ([anObject intValue] != 0 && rowIndex == [self.subtitles.tracks count] - 1) // if we have a last track which != "None" - { - /* add a new empty None track */ - [self.subtitles.tracks addObject:[self.subtitles createSubtitleTrack]]; - } - else if ([anObject intValue] == 0 && rowIndex != ([self.subtitles.tracks count] -1))// if this track is set to "None" and not the last track displayed - { - /* we know the user chose to remove this track by setting it to None, so remove it from the array */ - /* However,if this is the first track we have to reset the selected index of the next track by + 1, since it will now become - * the first track, which has to account for the extra "Foreign Language Search" index. */ - if (rowIndex == 0 && [self.subtitles.tracks[1][keySubTrackSelectionIndex] intValue] != 0) - { - /* get the index of the selection in row one (which is track two) */ - int trackOneSelectedIndex = [self.subtitles.tracks[1][keySubTrackSelectionIndex] intValue]; - /* increment the index of the subtitle menu item by one, to account for Foreign Language Search which is unique to the first track */ - self.subtitles.tracks[1][keySubTrackSelectionIndex] = @(trackOneSelectedIndex + 1); - } - /* now that we have made the adjustment for track one (index 0) go ahead and delete the track */ - [self.subtitles.tracks removeObjectAtIndex: rowIndex]; - } - - // Validate the current passthru tracks. - [self validatePassthru]; - } - - [aTableView reloadData]; -} - -#pragma mark - -#pragma mark Subtitle Table Delegate Methods - -- (NSCell *)tableView:(NSTableView *)tableView dataCellForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)rowIndex -{ - if ([[tableColumn identifier] isEqualToString:@"track"]) - { - // 'track' is a popup of all available source subtitle tracks for the given title - NSPopUpButtonCell *cellTrackPopup = [[NSPopUpButtonCell alloc] init]; - [cellTrackPopup setControlSize:NSSmallControlSize]; - [cellTrackPopup setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; - - // Add our initial "None" track which we use to add source tracks or remove tracks. - // "None" is always index 0. - [[cellTrackPopup menu] addItemWithTitle:@"None" action:NULL keyEquivalent:@""]; - - // Foreign Audio Search (index 1 in the popup) is only available for the first track - if (rowIndex == 0) - { - [[cellTrackPopup menu] addItemWithTitle:self.subtitles.foreignAudioSearchTrackName action:NULL keyEquivalent:@""]; - } - - for (NSDictionary *track in self.subtitles.masterTrackArray) - { - [[cellTrackPopup menu] addItemWithTitle:track[keySubTrackName] action:NULL keyEquivalent:@""]; - } - - return cellTrackPopup; - } - else if ([[tableColumn identifier] isEqualToString:@"srt_lang"]) - { - return self.languagesCell; - } - else if ([[tableColumn identifier] isEqualToString:@"srt_charcode"]) - { - return self.encodingsCell; - } - - return nil; -} - -/** - * Enables/Disables the table view cells. - */ -- (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex -{ - if ([[aTableColumn identifier] isEqualToString:@"track"]) - { - return; - } - - // If the Track is None, we disable the other cells as None is an empty track - if ([self.subtitles.tracks[rowIndex][keySubTrackSelectionIndex] intValue] == 0) - { - [aCell setEnabled:NO]; - } - else - { - // Since we have a valid track, we go ahead and enable the rest of the widgets and set them according to the controlling array */ - [aCell setEnabled:YES]; - } - - if ([[aTableColumn identifier] isEqualToString:@"forced"]) - { - // Disable the "Forced Only" checkbox if a) the track is "None" or b) the subtitle track doesn't support forced flags - if (![self.subtitles.tracks[rowIndex][keySubTrackSelectionIndex] intValue] || - !hb_subtitle_can_force([self.subtitles.tracks[rowIndex][keySubTrackType] intValue])) - { - [aCell setEnabled:NO]; - } - else - { - [aCell setEnabled:YES]; - } - } - else if ([[aTableColumn identifier] isEqualToString:@"burned"]) - { - /* - * Disable the "Burned In" checkbox if: - * a) the track is "None" OR - * b) the subtitle track can't be burned in OR - * c) the subtitle track can't be passed through (e.g. PGS w/MP4) - */ - int subtitleTrackType = [self.subtitles.tracks[rowIndex][keySubTrackType] intValue]; - if (![self.subtitles.tracks[rowIndex][keySubTrackSelectionIndex] intValue] || - !hb_subtitle_can_burn(subtitleTrackType) || !hb_subtitle_can_pass(subtitleTrackType, self.subtitles.container)) - { - [aCell setEnabled:NO]; - } - else - { - [aCell setEnabled:YES]; - } - } - else if ([[aTableColumn identifier] isEqualToString:@"default"]) - { - /* - * Disable the "Default" checkbox if: - * a) the track is "None" OR - * b) the subtitle track can't be passed through (e.g. PGS w/MP4) - */ - if (![self.subtitles.tracks[rowIndex][keySubTrackSelectionIndex] intValue] || - !hb_subtitle_can_pass([self.subtitles.tracks[rowIndex][keySubTrackType] intValue], self.subtitles.container)) - { - [aCell setEnabled:NO]; - } - else - { - [aCell setEnabled:YES]; - } - } - /* These next three columns only apply to srt's. they are disabled for source subs */ - else if ([[aTableColumn identifier] isEqualToString:@"srt_lang"]) - { - /* We have an srt file so set the track type (Source or SRT, and the srt file path ) kvp's*/ - if ([self.subtitles.tracks[rowIndex][keySubTrackType] intValue] == SRTSUB) - { - [aCell setEnabled:YES]; - } - else - { - [aCell setEnabled:NO]; - } - } - else if ([[aTableColumn identifier] isEqualToString:@"srt_charcode"]) - { - /* We have an srt file so set the track type (Source or SRT, and the srt file path ) kvp's*/ - if ([self.subtitles.tracks[rowIndex][keySubTrackType] intValue] == SRTSUB) - { - [aCell setEnabled:YES]; - } - else - { - [aCell setEnabled:NO]; - } - } - else if ([[aTableColumn identifier] isEqualToString:@"srt_offset"]) - { - if ([self.subtitles.tracks[rowIndex][keySubTrackType] intValue] == SRTSUB) - { - [aCell setEnabled:YES]; - } - else - { - [aCell setEnabled:NO]; - } - } -} - #pragma mark - Srt import /** @@ -509,92 +83,33 @@ static void *HBSubtitlesControllerContext = &HBSubtitlesControllerContext; - (IBAction)browseImportSrtFile:(id)sender { NSOpenPanel *panel = [NSOpenPanel openPanel]; - [panel setAllowsMultipleSelection:NO]; - [panel setCanChooseFiles:YES]; - [panel setCanChooseDirectories:NO]; + panel.allowsMultipleSelection = NO; + panel.canChooseFiles = YES; + panel.canChooseDirectories = NO; NSURL *sourceDirectory; - if ([[NSUserDefaults standardUserDefaults] URLForKey:@"LastSrtImportDirectoryURL"]) - { - sourceDirectory = [[NSUserDefaults standardUserDefaults] URLForKey:@"LastSrtImportDirectoryURL"]; - } - else - { - sourceDirectory = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"]; - } - - /* we open up the browse srt sheet here and call for browseImportSrtFileDone after the sheet is closed */ - NSArray *fileTypes = @[@"plist", @"srt"]; - [panel setDirectoryURL:sourceDirectory]; - [panel setAllowedFileTypes:fileTypes]; - [panel beginSheetModalForWindow:[[self view] window] completionHandler:^(NSInteger result) { - if (result == NSOKButton) - { - NSURL *importSrtFileURL = [panel URL]; - NSURL *importSrtDirectory = [importSrtFileURL URLByDeletingLastPathComponent]; - [[NSUserDefaults standardUserDefaults] setURL:importSrtDirectory forKey:@"LastSrtImportDirectoryURL"]; - - /* Create a new entry for the subtitle source array so it shows up in our subtitle source list */ - NSString *displayname = [importSrtFileURL lastPathComponent];// grok an appropriate display name from the srt subtitle */ - - /* create a dictionary of source subtitle information to store in our array */ - [self.subtitles.masterTrackArray addObject:@{keySubTrackIndex: @(self.subtitles.masterTrackArray.count), - keySubTrackName: displayname, - keySubTrackType: @(SRTSUB), - keySubTrackSrtFilePath: importSrtFileURL.path}]; - - // Now create a new srt subtitle dictionary assuming the user wants to add it to their list - NSMutableDictionary *newSubtitleSrtTrack = [self.subtitles trackFromSourceTrackIndex:self.subtitles.masterTrackArray.count - 1]; - // Calculate the pop up selection index - newSubtitleSrtTrack[keySubTrackSelectionIndex] = @(self.subtitles.masterTrackArray.count + (self.subtitles.tracks.count == 1)); - [self.subtitles.tracks insertObject:newSubtitleSrtTrack atIndex:self.subtitles.tracks.count - 1]; - - [self.fTableView reloadData]; - } - }]; -} - -#pragma mark - UI cells - -@synthesize languagesCell = _languagesCell; - -- (NSPopUpButtonCell *)languagesCell -{ - if (!_languagesCell) + if ([[NSUserDefaults standardUserDefaults] URLForKey:@"LastSrtImportDirectoryURL"]) { - // 'srt_lang' is a popup of commonly used languages to be matched to the source srt file - _languagesCell = [[NSPopUpButtonCell alloc] init]; - // Set the Popups properties - [_languagesCell setControlSize:NSSmallControlSize]; - [_languagesCell setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; - - // list our languages as per the languagesArray - for (NSArray *lang in self.subtitles.languagesArray) - { - [[_languagesCell menu] addItemWithTitle:lang[0] action:NULL keyEquivalent:@""]; - } + sourceDirectory = [[NSUserDefaults standardUserDefaults] URLForKey:@"LastSrtImportDirectoryURL"]; + } + else + { + sourceDirectory = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"]; } - return _languagesCell; -} - -@synthesize encodingsCell = _encodingsCell; -- (NSPopUpButtonCell *)encodingsCell -{ - if (!_encodingsCell) { - // 'srt_charcode' is a popup of commonly used character codes to be matched to the source srt file - _encodingsCell = [[NSPopUpButtonCell alloc] init]; - // Set the Popups properties - [_encodingsCell setControlSize:NSSmallControlSize]; - [_encodingsCell setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]]; + panel.directoryURL = sourceDirectory; + panel.allowedFileTypes = @[@"srt"]; - // list our character codes, as per charCodeArray - for (NSString *charCode in self.subtitles.charCodeArray) + [panel beginSheetModalForWindow:self.view.window completionHandler:^(NSInteger result) + { + if (result == NSFileHandlingPanelOKButton) { - [[_encodingsCell menu] addItemWithTitle:charCode action: NULL keyEquivalent: @""]; + NSURL *importSrtFileURL = panel.URL; + NSURL *importSrtDirectory = importSrtFileURL.URLByDeletingLastPathComponent; + [[NSUserDefaults standardUserDefaults] setURL:importSrtDirectory forKey:@"LastSrtImportDirectoryURL"]; + + [self.subtitles addSrtTrackFromURL:importSrtFileURL]; } - } - return _encodingsCell; + }]; } - @end |