/* HBSummaryViewController.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 "HBSummaryViewController.h"
#import "HBPreviewView.h"
#import "HBPreviewGenerator.h"
@import HandBrakeKit;
static void *HBSummaryViewControllerContainerContext = &HBSummaryViewControllerContainerContext;
static void *HBSummaryViewControllerVideoContext = &HBSummaryViewControllerVideoContext;
static void *HBSummaryViewControllerPictureContext = &HBSummaryViewControllerPictureContext;
static void *HBSummaryViewControllerFiltersContext = &HBSummaryViewControllerFiltersContext;
static void *HBSummaryViewControllerAudioContext = &HBSummaryViewControllerAudioContext;
static void *HBSummaryViewControllerSubsContext = &HBSummaryViewControllerSubsContext;
@interface HBSummaryViewController ()
@property (nonatomic, strong) IBOutlet NSLayoutConstraint *bottomOptionsConstrain;
@property (nonatomic, strong) IBOutlet NSTextField *tracksLabel;
@property (nonatomic, strong) IBOutlet NSTextField *filtersLabel;
@property (nonatomic, strong) IBOutlet NSTextField *dimensionLabel;
@property (nonatomic, strong) IBOutlet HBPreviewView *previewView;
@property (nonatomic) BOOL tracksReloadInQueue;
@property (nonatomic) BOOL filtersReloadInQueue;
@property (nonatomic) BOOL pictureReloadInQueue;
@property (nonatomic) BOOL visible;
@end
@implementation HBSummaryViewController
- (instancetype)init
{
self = [super initWithNibName:@"HBSummaryViewController" bundle:nil];
return self;
}
- (void)loadView
{
[super loadView];
self.previewView.showShadow = NO;
self.visible = YES;
[self resetLabels];
}
- (void)viewWillAppear
{
self.visible = YES;
if (self.pictureReloadInQueue || self.previewView.image == NULL)
{
[self updatePicture];
}
}
- (void)viewDidDisappear
{
self.visible = NO;
}
- (void)setGenerator:(HBPreviewGenerator *)generator
{
_generator = generator;
if (generator)
{
[self updatePicture];
}
else
{
self.previewView.image = nil;
}
}
- (void)setJob:(HBJob *)job
{
if (job)
{
[self removeJobObservers];
_job = job;
[self addJobObservers];
[self updateTracksLabel];
[self updateFiltersLabel];
}
else
{
[self removeJobObservers];
[self resetLabels];
_job = job;
}
}
#pragma mark - KVO
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == HBSummaryViewControllerAudioContext)
{
if ([change[NSKeyValueChangeKindKey] integerValue] == NSKeyValueChangeInsertion)
{
[self addAudioTracksObservers:change[NSKeyValueChangeNewKey]];
}
else if ([change[NSKeyValueChangeKindKey] integerValue]== NSKeyValueChangeRemoval)
{
[self removeAudioTracksObservers:change[NSKeyValueChangeOldKey]];
}
[self updateTracks:nil];
}
else if (context == HBSummaryViewControllerSubsContext)
{
if ([change[NSKeyValueChangeKindKey] integerValue] == NSKeyValueChangeInsertion)
{
[self addSubtitlesTracksObservers:change[NSKeyValueChangeNewKey]];
}
else if ([change[NSKeyValueChangeKindKey] integerValue]== NSKeyValueChangeRemoval)
{
[self removeSubtitlesTracksObservers:change[NSKeyValueChangeOldKey]];
}
[self updateTracks:nil];
}
else if (context == HBSummaryViewControllerContainerContext)
{
if (NSAppKitVersionNumber >= NSAppKitVersionNumber10_10 && change[NSKeyValueChangeNewKey])
{
if ([change[NSKeyValueChangeNewKey] integerValue] & 0x030000)
{
self.bottomOptionsConstrain.active = YES;
}
else
{
self.bottomOptionsConstrain.active = NO;
}
}
[self updateTracks:nil];
}
else if (context == HBSummaryViewControllerVideoContext)
{
[self updateTracks:nil];
}
else if (context == HBSummaryViewControllerFiltersContext)
{
[self updatePicture:nil];
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)addAudioTracksObservers:(NSArray *)tracks
{
for (HBAudioTrack *track in tracks)
{
[track addObserver:self forKeyPath:@"encoder" options:0 context:HBSummaryViewControllerAudioContext];
[track addObserver:self forKeyPath:@"mixdown" options:0 context:HBSummaryViewControllerAudioContext];
}
}
- (void)removeAudioTracksObservers:(NSArray *)tracks
{
for (HBAudioTrack *track in tracks)
{
[track removeObserver:self forKeyPath:@"encoder"];
[track removeObserver:self forKeyPath:@"mixdown"];
}
}
- (void)addSubtitlesTracksObservers:(NSArray *)tracks
{
for (HBSubtitlesTrack *track in tracks)
{
[track addObserver:self forKeyPath:@"burnedIn" options:0 context:HBSummaryViewControllerSubsContext];
}
}
- (void)removeSubtitlesTracksObservers:(NSArray *)tracks
{
for (HBSubtitlesTrack *track in tracks)
{
[track removeObserver:self forKeyPath:@"burnedIn"];
}
}
- (void)addJobObservers
{
if (_job)
{
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updatePicture:) name:HBPictureChangedNotification object:_job.picture];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateFilters:) name:HBFiltersChangedNotification object:_job.filters];
[_job addObserver:self forKeyPath:@"container" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:HBSummaryViewControllerContainerContext];
[_job addObserver:self forKeyPath:@"chaptersEnabled" options:0 context:HBSummaryViewControllerVideoContext];
[_job addObserver:self forKeyPath:@"video.encoder" options:0 context:HBSummaryViewControllerVideoContext];
[_job addObserver:self forKeyPath:@"video.frameRate" options:0 context:HBSummaryViewControllerVideoContext];
[_job addObserver:self forKeyPath:@"video.frameRateMode" options:0 context:HBSummaryViewControllerVideoContext];
[_job addObserver:self forKeyPath:@"filters.deinterlace" options:0 context:HBSummaryViewControllerFiltersContext];
[_job addObserver:self forKeyPath:@"filters.rotate" options:0 context:HBSummaryViewControllerFiltersContext];
[_job addObserver:self forKeyPath:@"filters.flip" options:0 context:HBSummaryViewControllerFiltersContext];
[_job addObserver:self forKeyPath:@"audio.tracks" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:HBSummaryViewControllerAudioContext];
[_job addObserver:self forKeyPath:@"subtitles.tracks" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:HBSummaryViewControllerSubsContext];
[self addAudioTracksObservers:_job.audio.tracks];
[self addSubtitlesTracksObservers:_job.subtitles.tracks];
}
}
- (void)removeJobObservers
{
if (_job)
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:HBPictureChangedNotification object:_job.picture];
[[NSNotificationCenter defaultCenter] removeObserver:self name:HBFiltersChangedNotification object:_job.filters];
[_job removeObserver:self forKeyPath:@"container"];
[_job removeObserver:self forKeyPath:@"chaptersEnabled"];
[_job removeObserver:self forKeyPath:@"video.encoder"];
[_job removeObserver:self forKeyPath:@"video.frameRate"];
[_job removeObserver:self forKeyPath:@"video.frameRateMode"];
[_job removeObserver:self forKeyPath:@"filters.deinterlace"];
[_job removeObserver:self forKeyPath:@"filters.rotate"];
[_job removeObserver:self forKeyPath:@"filters.flip"];
[_job removeObserver:self forKeyPath:@"audio.tracks"];
[_job removeObserver:self forKeyPath:@"subtitles.tracks"];
[self removeAudioTracksObservers:_job.audio.tracks];
[self removeSubtitlesTracksObservers:_job.subtitles.tracks];
}
}
- (void)updateTracks:(NSNotification *)notification
{
if (self.tracksReloadInQueue == NO)
{
[[NSRunLoop mainRunLoop] performSelector:@selector(updateTracksLabel) target:self argument:nil order:0 modes:@[NSDefaultRunLoopMode]];
self.tracksReloadInQueue = YES;
}
}
- (void)updateFilters:(NSNotification *)notification
{
if (self.filtersReloadInQueue == NO)
{
[[NSRunLoop mainRunLoop] performSelector:@selector(updateFiltersLabel) target:self argument:nil order:0 modes:@[NSDefaultRunLoopMode]];
self.filtersReloadInQueue = YES;
}
}
- (void)updatePicture:(NSNotification *)notification
{
// Enquee the reload call on the main runloop
// to avoid reloading the same image multiple times.
if (self.pictureReloadInQueue == NO)
{
[[NSRunLoop mainRunLoop] performSelector:@selector(updatePicture) target:self argument:nil order:0 modes:@[NSDefaultRunLoopMode]];
self.pictureReloadInQueue = YES;
}
}
- (void)resetLabels
{
self.tracksLabel.stringValue = NSLocalizedString(@"None", nil);
self.filtersLabel.stringValue = NSLocalizedString(@"None", nil);
self.dimensionLabel.stringValue = NSLocalizedString(@"None", nil);
self.tracksReloadInQueue = NO;
self.filtersReloadInQueue = NO;
self.pictureReloadInQueue = NO;
}
- (void)updateTracksLabel
{
self.tracksLabel.stringValue = self.job.shortDescription;
self.tracksReloadInQueue = NO;
}
- (void)updateFiltersLabel
{
self.filtersLabel.stringValue = self.job.filtersShortDescription;
self.filtersReloadInQueue = NO;
}
- (void)updatePicture
{
if (self.visible && self.generator)
{
NSUInteger index = self.generator.imagesCount > 1 ? 1 : 0;
CGImageRef fPreviewImage = [self.generator copyImageAtIndex:index shouldCache:NO];
self.previewView.image = fPreviewImage;
CFRelease(fPreviewImage);
self.pictureReloadInQueue = NO;
self.dimensionLabel.stringValue = self.job.picture.shortInfo;
}
}
@end