diff options
author | Damiano Galassi <[email protected]> | 2015-10-19 17:57:49 +0200 |
---|---|---|
committer | Damiano Galassi <[email protected]> | 2015-10-19 17:57:49 +0200 |
commit | 333a81d49982c504bbc3ba7bcb88787442a3a8c4 (patch) | |
tree | 2136c41bfb66fd26578b5305f39ec9a6637e9282 /macosx | |
parent | e5b59be057da16e782d970e41299d78beef9e878 (diff) |
MacGui: improved queue with undo/redo support for adding/removing jobs, and added a icon for failed encode.
Diffstat (limited to 'macosx')
-rw-r--r-- | macosx/English.lproj/Queue.xib | 10 | ||||
-rw-r--r-- | macosx/HBAppDelegate.m | 8 | ||||
-rw-r--r-- | macosx/HBDockTile.h | 12 | ||||
-rw-r--r-- | macosx/HBDockTile.m | 26 | ||||
-rw-r--r-- | macosx/HBJob+UIAdditions.m | 8 | ||||
-rw-r--r-- | macosx/HBQueueController.h | 2 | ||||
-rw-r--r-- | macosx/HBQueueController.m | 834 | ||||
-rw-r--r-- | macosx/HandBrake.xcodeproj/project.pbxproj | 8 | ||||
-rw-r--r-- | macosx/NSArray+HBAdditions.h | 7 | ||||
-rw-r--r-- | macosx/NSArray+HBAdditions.m | 17 | ||||
-rw-r--r-- | macosx/icons/EncodeCanceled.png | bin | 558 -> 1392 bytes | |||
-rw-r--r-- | macosx/icons/[email protected] | bin | 1074 -> 1592 bytes | |||
-rw-r--r-- | macosx/icons/EncodeFailed.png | bin | 0 -> 377 bytes | |||
-rw-r--r-- | macosx/icons/[email protected] | bin | 0 -> 656 bytes |
14 files changed, 575 insertions, 357 deletions
diff --git a/macosx/English.lproj/Queue.xib b/macosx/English.lproj/Queue.xib index f33d67013..9220cc0cb 100644 --- a/macosx/English.lproj/Queue.xib +++ b/macosx/English.lproj/Queue.xib @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="8164.2" systemVersion="15A225f" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9058" systemVersion="15B38b" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> <dependencies> <deployment identifier="macosx"/> <development version="6300" identifier="xcode"/> - <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="8164.2"/> + <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9058"/> </dependencies> <objects> <customObject id="-2" userLabel="File's Owner" customClass="HBQueueController"> @@ -34,7 +34,7 @@ <rect key="frame" x="1" y="1" width="532" height="336"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <outlineView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" indentationPerLevel="16" autoresizesOutlineColumn="YES" outlineTableColumn="2624" id="2597" customClass="HBQueueOutlineView"> + <outlineView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" indentationPerLevel="16" outlineTableColumn="2624" id="2597" customClass="HBQueueOutlineView"> <rect key="frame" x="0.0" y="0.0" width="532" height="336"/> <autoresizingMask key="autoresizingMask"/> <animations/> @@ -87,12 +87,12 @@ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> </clipView> <animations/> - <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="2644"> + <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="2644"> <rect key="frame" x="-100" y="-100" width="282" height="15"/> <autoresizingMask key="autoresizingMask"/> <animations/> </scroller> - <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="2643"> + <scroller key="verticalScroller" verticalHuggingPriority="750" horizontal="NO" id="2643"> <rect key="frame" x="517" y="1" width="16" height="336"/> <autoresizingMask key="autoresizingMask"/> <animations/> diff --git a/macosx/HBAppDelegate.m b/macosx/HBAppDelegate.m index 32251f96f..6c21b1937 100644 --- a/macosx/HBAppDelegate.m +++ b/macosx/HBAppDelegate.m @@ -17,6 +17,7 @@ #import "HBController.h" #define PRESET_FILE @"UserPresets.json" +#define QUEUE_FILE @"Queue.hbqueue" @interface HBAppDelegate () @@ -51,10 +52,11 @@ _outputPanel = [[HBOutputPanelController alloc] init]; // we init the HBPresetsManager - NSURL *presetsURL = [[HBUtilities appSupportURL] URLByAppendingPathComponent:PRESET_FILE]; - _presetsManager = [[HBPresetsManager alloc] initWithURL:presetsURL]; + NSURL *appSupportURL = [HBUtilities appSupportURL]; + _presetsManager = [[HBPresetsManager alloc] initWithURL:[appSupportURL URLByAppendingPathComponent:PRESET_FILE]]; - _queueController = [[HBQueueController alloc] init]; + // Queue + _queueController = [[HBQueueController alloc] initWithURL:[appSupportURL URLByAppendingPathComponent:QUEUE_FILE]]; _queueController.delegate = self; _mainController = [[HBController alloc] initWithQueue:_queueController presetsManager:_presetsManager]; diff --git a/macosx/HBDockTile.h b/macosx/HBDockTile.h index 15117ab21..caac2844e 100644 --- a/macosx/HBDockTile.h +++ b/macosx/HBDockTile.h @@ -20,4 +20,16 @@ */ - (void)updateDockIcon:(double)progress withETA:(NSString *)etaStr; + +/** + * Updates two DockTextFields on the dockTile, + * one with total percentage, the other one with the ETA. + * + * ETA format is [XX]X:XX:XX when ETA is greater than one hour + * [X]X:XX when ETA is greater than 0 (minutes or seconds) + * When these conditions doesn't applied (eg. when ETA is undefined) + * we show just a tilde (~) + */ +- (void)updateDockIcon:(double)progress hours:(NSInteger)hours minutes:(NSInteger)minutes seconds:(NSInteger)seconds; + @end diff --git a/macosx/HBDockTile.m b/macosx/HBDockTile.m index 1b61d71c5..dfad7d5ec 100644 --- a/macosx/HBDockTile.m +++ b/macosx/HBDockTile.m @@ -68,4 +68,30 @@ NSString *dockTilePercentFormat = @"%2.1f%%"; [_dockTile display]; } +- (void)updateDockIcon:(double)progress hours:(NSInteger)hours minutes:(NSInteger)minutes seconds:(NSInteger)seconds +{ + // ETA format is [XX]X:XX:XX when ETA is greater than one hour + // [X]X:XX when ETA is greater than 0 (minutes or seconds) + // When these conditions doesn't applied (eg. when ETA is undefined) + // we show just a tilde (~) + + NSString *etaStr; + if (hours > 0) + { + etaStr = [NSString stringWithFormat:@"%ld:%02ld:%02ld", (long)hours, (long)minutes, (long)seconds]; + } + else if (minutes > 0 || seconds > 0) + { + etaStr = [NSString stringWithFormat:@"%ld:%02ld", (long)minutes, (long)seconds]; + } + else + { + etaStr = @"~"; + } + + [self updateDockIcon:progress withETA:etaStr]; + +} + + @end diff --git a/macosx/HBJob+UIAdditions.m b/macosx/HBJob+UIAdditions.m index 7eae8a773..c7a7fec1f 100644 --- a/macosx/HBJob+UIAdditions.m +++ b/macosx/HBJob+UIAdditions.m @@ -84,10 +84,10 @@ static NSDictionary *shortHeightAttr; [ps setTabStops:@[]]; // clear all tabs [ps addTabStop: [[NSTextTab alloc] initWithType: NSLeftTabStopType location: 20.0]]; - detailAttr = @{NSFontAttributeName: [NSFont systemFontOfSize:10.0], + detailAttr = @{NSFontAttributeName: [NSFont systemFontOfSize:[NSFont smallSystemFontSize]], NSParagraphStyleAttributeName: ps}; - detailBoldAttr = @{NSFontAttributeName: [NSFont boldSystemFontOfSize:10.0], + detailBoldAttr = @{NSFontAttributeName: [NSFont boldSystemFontOfSize:[NSFont smallSystemFontSize]], NSParagraphStyleAttributeName: ps}; titleAttr = @{NSFontAttributeName: [NSFont systemFontOfSize:[NSFont systemFontSize]], @@ -474,7 +474,9 @@ static NSDictionary *shortHeightAttr; i++; } } - + + [finalString deleteCharactersInRange:NSMakeRange(finalString.length - 1, 1)]; + return finalString; } diff --git a/macosx/HBQueueController.h b/macosx/HBQueueController.h index ca14104ba..ff8ca5aaf 100644 --- a/macosx/HBQueueController.h +++ b/macosx/HBQueueController.h @@ -17,6 +17,8 @@ NS_ASSUME_NONNULL_BEGIN @interface HBQueueController : NSWindowController <NSToolbarDelegate, NSWindowDelegate, GrowlApplicationBridgeDelegate> +- (instancetype)initWithURL:(NSURL *)queueURL; + /// The HBCore used for encoding. @property (nonatomic, readonly) HBCore *core; diff --git a/macosx/HBQueueController.m b/macosx/HBQueueController.m index 7ae19da3e..5c99507b0 100644 --- a/macosx/HBQueueController.m +++ b/macosx/HBQueueController.m @@ -1,4 +1,3 @@ - /* HBQueueController This file is part of the HandBrake source code. @@ -34,8 +33,6 @@ // DockTile update freqency in total percent increment #define dockTileUpdateFrequency 0.1f -#define HB_ROW_HEIGHT_TITLE_ONLY 17.0 - @interface HBQueueController () <NSOutlineViewDataSource, HBQueueOutlineViewDelegate> @property (nonatomic, readonly) HBDockTile *dockTile; @@ -48,24 +45,27 @@ @property (nonatomic, readonly) NSMutableDictionary *descriptions; @property (nonatomic, readonly) HBDistributedArray *jobs; -@property (nonatomic, strong) HBJob *currentJob; -@property (nonatomic, strong) HBJobOutputFileWriter *currentLog; +@property (nonatomic) HBJob *currentJob; +@property (nonatomic) HBJobOutputFileWriter *currentLog; @property (nonatomic, readwrite) BOOL stop; @property (nonatomic, readwrite) NSUInteger pendingItemsCount; @property (nonatomic, readwrite) NSUInteger completedItemsCount; -@property (nonatomic, strong) NSArray *dragNodesArray; +@property (nonatomic) NSArray *dragNodesArray; @end @implementation HBQueueController -- (instancetype)init +- (instancetype)initWithURL:(NSURL *)queueURL; { + NSParameterAssert(queueURL); + if (self = [super initWithWindowNibName:@"Queue"]) { + // Cached queue items descriptions _descriptions = [[NSMutableDictionary alloc] init]; // Load the dockTile and instiante initial text fields @@ -77,7 +77,9 @@ // Init a separate instance of libhb for the queue _core = [[HBCore alloc] initWithLogLevel:loggingLevel name:@"QueueCore"]; - [self loadQueueFile]; + // Load the queue from disk. + _jobs = [[HBDistributedArray alloc] initWithURL:queueURL]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadQueue) name:HBDistributedArrayChanged object:_jobs]; } return self; @@ -95,11 +97,7 @@ [self.outlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES]; [self.outlineView setVerticalMotionCanBeginDrag:YES]; - // Don't allow autoresizing of main column, else the "delete" column will get - // pushed out of view. - [self.outlineView setAutoresizesOutlineColumn: NO]; - - [self getQueueStats]; + [self updateQueueStats]; } #pragma mark Toolbar @@ -207,53 +205,157 @@ return NO; } -#pragma mark - -#pragma mark Queue File +#pragma mark - Public methods -- (void)reloadQueue +- (void)addJob:(HBJob *)item { - [self getQueueStats]; - [self.outlineView reloadData]; + NSParameterAssert(item); + [self addJobsFromArray:@[item]]; } -- (void)loadQueueFile +- (void)addJobsFromArray:(NSArray *)items; { - NSURL *queueURL = [[HBUtilities appSupportURL] URLByAppendingPathComponent:@"Queue.hbqueue"]; - _jobs = [[HBDistributedArray alloc] initWithURL:queueURL]; + NSParameterAssert(items); + [self addQueueItems:items]; +} - [self reloadQueue]; +- (BOOL)jobExistAtURL:(NSURL *)url +{ + NSParameterAssert(url); - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadQueue) name:HBDistributedArrayChanged object:_jobs]; + for (HBJob *item in self.jobs) + { + if ([item.destURL isEqualTo:url]) + { + return YES; + } + } + return NO; } -- (void)addJob:(HBJob *)item +- (NSUInteger)count +{ + return self.jobs.count; +} + +/** + * This method will clear the queue of any encodes that are not still pending + * this includes both successfully completed encodes as well as cancelled encodes + */ +- (void)removeCompletedJobs { [self.jobs beginTransaction]; - [self.jobs addObject:item]; + NSIndexSet *indexes = [self.jobs indexesOfObjectsUsingBlock:^BOOL(HBJob *item) { + return (item.state == HBJobStateCompleted || item.state == HBJobStateCanceled); + }]; + [self removeQueueItemsAtIndexes:indexes]; [self.jobs commit]; +} - [self reloadQueue]; +/** + * This method will clear the queue of all encodes. effectively creating an empty queue + */ +- (void)removeAllJobs +{ + [self.jobs beginTransaction]; + [self removeQueueItemsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.jobs.count)]]; + [self.jobs commit]; } -- (void)addJobsFromArray:(NSArray *)items; +/** + * This method will set any item marked as encoding back to pending + * currently used right after a queue reload + */ +- (void)setEncodingJobsAsPending { [self.jobs beginTransaction]; - [self.jobs addObjectsFromArray:items]; + + NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet]; + NSUInteger idx = 0; + for (HBJob *job in self.jobs) + { + // We want to keep any queue item that is pending or was previously being encoded + if (job.state == HBJobStateWorking) + { + job.state = HBJobStateReady; + [indexes addIndex:idx]; + } + idx++; + } + [self reloadQueueItemsAtIndexes:indexes]; [self.jobs commit]; +} + +#pragma mark - Private queue editing methods + +/** + * Reloads the queue, this is called + * when another HandBrake instances modifies the queue + */ +- (void)reloadQueue +{ + [self updateQueueStats]; + [self.outlineView reloadData]; + [self.window.undoManager removeAllActions]; +} + +- (void)reloadQueueItemAtIndex:(NSUInteger)idx +{ + [self reloadQueueItemsAtIndexes:[NSIndexSet indexSetWithIndex:idx]]; +} - [self reloadQueue]; +- (void)reloadQueueItemsAtIndexes:(NSIndexSet *)indexes +{ + [self.outlineView reloadDataForRowIndexes:indexes columnIndexes:[NSIndexSet indexSetWithIndex:0]]; + [self updateQueueStats]; } -- (BOOL)jobExistAtURL:(NSURL *)url +- (void)addQueueItems:(NSArray *)items { - for (HBJob *item in self.jobs) + NSParameterAssert(items); + NSIndexSet *indexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(self.jobs.count, items.count)]; + [self addQueueItems:items atIndexes:indexes]; +} + +- (void)addQueueItems:(NSArray *)items atIndexes:(NSIndexSet *)indexes +{ + NSParameterAssert(items); + NSParameterAssert(indexes); + [self.jobs beginTransaction]; + [self.outlineView beginUpdates]; + + // Forward + NSUInteger currentIndex = indexes.firstIndex; + NSUInteger currentObjectIndex = 0; + while (currentIndex != NSNotFound) { - if ([item.destURL isEqualTo:url]) + [self.jobs insertObject:items[currentObjectIndex] atIndex:currentIndex]; + currentIndex = [indexes indexGreaterThanIndex:currentIndex]; + currentObjectIndex++; + } + + [self.outlineView insertItemsAtIndexes:indexes + inParent:nil + withAnimation:NSTableViewAnimationSlideDown]; + + NSUndoManager *undo = self.window.undoManager; + [[undo prepareWithInvocationTarget:self] removeQueueItemsAtIndexes:indexes]; + + if (!undo.isUndoing) + { + if (items.count == 1) { - return YES; + [undo setActionName:NSLocalizedString(@"Add Job To Queue", nil)]; + } + else + { + [undo setActionName:NSLocalizedString(@"Add Jobs To Queue", nil)]; } } - return NO; + + [self.outlineView endUpdates]; + [self updateQueueStats]; + [self.jobs commit]; } - (void)removeQueueItemAtIndex:(NSUInteger)index @@ -263,16 +365,138 @@ - (void)removeQueueItemsAtIndexes:(NSIndexSet *)indexes { - if (self.jobs.count > [indexes lastIndex]) + NSParameterAssert(indexes); + + if (indexes.count == 0) + { + return; + } + + [self.jobs beginTransaction]; + [self.outlineView beginUpdates]; + + NSArray *removeJobs = [self.jobs objectsAtIndexes:indexes]; + + if (self.jobs.count > indexes.lastIndex) { [self.jobs removeObjectsAtIndexes:indexes]; } + + [self.outlineView removeItemsAtIndexes:indexes inParent:nil withAnimation:NSTableViewAnimationSlideUp]; + [self.outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:indexes.firstIndex] byExtendingSelection:NO]; + + NSUndoManager *undo = self.window.undoManager; + [[undo prepareWithInvocationTarget:self] addQueueItems:removeJobs atIndexes:indexes]; + + if (!undo.isUndoing) + { + if (indexes.count == 1) + { + [undo setActionName:NSLocalizedString(@"Remove Job From Queue", nil)]; + } + else + { + [undo setActionName:NSLocalizedString(@"Remove Jobs From Queue", nil)]; + } + } + + [self.outlineView endUpdates]; + [self updateQueueStats]; + [self.jobs commit]; +} + +- (void)moveQueueItems:(NSArray *)items toIndex:(NSUInteger)index +{ + [self.jobs beginTransaction]; + [self.outlineView beginUpdates]; + + NSMutableArray *source = [NSMutableArray array]; + NSMutableArray *dest = [NSMutableArray array]; + + for (id object in items.reverseObjectEnumerator) + { + NSUInteger sourceIndex = [self.jobs indexOfObject:object]; + [self.jobs removeObjectAtIndex:sourceIndex]; + + + if (sourceIndex < index) + { + index--; + } + + [self.jobs insertObject:object atIndex:index]; + + [source addObject:@(index)]; + [dest addObject:@(sourceIndex)]; + + [self.outlineView moveItemAtIndex:sourceIndex inParent:nil toIndex:index inParent:nil]; + } + + NSUndoManager *undo = self.window.undoManager; + [[undo prepareWithInvocationTarget:self] moveQueueItemsAtIndexes:source toIndexes:dest]; + + if (!undo.isUndoing) + { + if (items.count == 1) + { + [undo setActionName:NSLocalizedString(@"Move Job in Queue", nil)]; + } + else + { + [undo setActionName:NSLocalizedString(@"Move Jobs in Queue", nil)]; + } + } + + [self.outlineView endUpdates]; + [self.jobs commit]; +} + +- (void)moveQueueItemsAtIndexes:(NSArray *)source toIndexes:(NSArray *)dest +{ + [self.jobs beginTransaction]; + [self.outlineView beginUpdates]; + + NSMutableArray *newSource = [NSMutableArray array]; + NSMutableArray *newDest = [NSMutableArray array]; + + for (NSInteger idx = source.count - 1; idx >= 0; idx--) + { + NSUInteger sourceIndex = [source[idx] integerValue]; + NSUInteger destIndex = [dest[idx] integerValue]; + + [newSource addObject:@(destIndex)]; + [newDest addObject:@(sourceIndex)]; + + id obj = [self.jobs objectAtIndex:sourceIndex]; + [self.jobs removeObjectAtIndex:sourceIndex]; + [self.jobs insertObject:obj atIndex:destIndex]; + + [self.outlineView moveItemAtIndex:sourceIndex inParent:nil toIndex:destIndex inParent:nil]; + } + + NSUndoManager *undo = self.window.undoManager; + [[undo prepareWithInvocationTarget:self] moveQueueItemsAtIndexes:newSource toIndexes:newDest]; + + if (!undo.isUndoing) + { + if (source.count == 1) + { + [undo setActionName:NSLocalizedString(@"Move Job in Queue", nil)]; + } + else + { + [undo setActionName:NSLocalizedString(@"Move Jobs in Queue", nil)]; + } + } + + [self.outlineView endUpdates]; + [self.jobs commit]; } /** * Updates the queue status label. */ -- (void)getQueueStats +- (void)updateQueueStats { // lets get the stats on the status of the queue array NSUInteger pendingCount = 0; @@ -311,10 +535,8 @@ self.completedItemsCount = completedCount; } -- (NSUInteger)count -{ - return self.jobs.count; -} +#pragma mark - +#pragma mark Queue Job Processing /** * Used to get the next pending queue item and return it if found @@ -332,232 +554,197 @@ } /** - * This method will set any item marked as encoding back to pending - * currently used right after a queue reload - */ -- (void)setEncodingJobsAsPending -{ - [self.jobs beginTransaction]; - for (HBJob *job in self.jobs) - { - // We want to keep any queue item that is pending or was previously being encoded - if (job.state == HBJobStateWorking) - { - job.state = HBJobStateReady; - } - } - [self.jobs commit]; - - [self reloadQueue]; -} - -/** - * This method will clear the queue of any encodes that are not still pending - * this includes both successfully completed encodes as well as cancelled encodes - */ -- (void)removeCompletedJobs -{ - [self.jobs beginTransaction]; - [self.jobs removeObjectsUsingBlock:^BOOL(HBJob *item) { - return (item.state == HBJobStateCompleted || item.state == HBJobStateCanceled); - }]; - [self.jobs commit]; - [self reloadQueue]; -} - -/** - * This method will clear the queue of all encodes. effectively creating an empty queue - */ -- (void)removeAllJobs -{ - [self.jobs beginTransaction]; - [self.jobs removeAllObjects]; - [self.jobs commit]; - - [self reloadQueue]; -} - -#pragma mark - -#pragma mark Queue Job Processing - -/** * Starts the queue */ - (void)encodeNextQueueItem { - // Check to see if there are any more pending items in the queue - HBJob *nextJob = [self getNextPendingQueueItem]; + [self.jobs beginTransaction]; + self.currentJob = nil; - // If we still have more pending items in our queue, lets go to the next one - if (nextJob) + // since we have completed an encode, we go to the next + if (self.stop) { - self.currentJob = nextJob; - // now we mark the queue item as working so another instance can not come along and try to scan it while we are scanning - self.currentJob.state = HBJobStateWorking; - - // Tell HB to output a new activity log file for this encode - self.currentLog = [[HBJobOutputFileWriter alloc] initWithJob:self.currentJob]; - [[HBOutputRedirect stderrRedirect] addListener:self.currentLog]; - [[HBOutputRedirect stdoutRedirect] addListener:self.currentLog]; - - // now we can go ahead and scan the new pending queue item - [self performScan:self.currentJob.fileURL titleIdx:self.currentJob.titleIdx]; + self.stop = NO; } else { - self.currentJob = nil; + // Check to see if there are any more pending items in the queue + HBJob *nextJob = [self getNextPendingQueueItem]; + + // If we still have more pending items in our queue, lets go to the next one + if (nextJob) + { + // now we mark the queue item as working so another instance can not come along and try to scan it while we are scanning + nextJob.state = HBJobStateWorking; + + // Tell HB to output a new activity log file for this encode + self.currentLog = [[HBJobOutputFileWriter alloc] initWithJob:nextJob]; + [[HBOutputRedirect stderrRedirect] addListener:self.currentLog]; + [[HBOutputRedirect stdoutRedirect] addListener:self.currentLog]; - [HBUtilities writeToActivityLog:"Queue Done, there are no more pending encodes"]; + self.currentJob = nextJob; + [self reloadQueueItemAtIndex:[self.jobs indexOfObject:nextJob]]; - // Since there are no more items to encode, go to queueCompletedAlerts - // for user specified alerts after queue completed - [self queueCompletedAlerts]; + // now we can go ahead and scan the new pending queue item + [self encodeJob:nextJob]; + + // erase undo manager history + [self.window.undoManager removeAllActions]; + } + else + { + [HBUtilities writeToActivityLog:"Queue Done, there are no more pending encodes"]; + + // Since there are no more items to encode, go to queueCompletedAlerts + // for user specified alerts after queue completed + [self queueCompletedAlerts]; + } } + [self.jobs commit]; } -- (void)encodeCompleted +- (void)completedJob:(HBJob *)job result:(HBCoreResult)result; { + NSParameterAssert(job); + [self.jobs beginTransaction]; + // Since we are done with this encode, tell output to stop writing to the // individual encode log. [[HBOutputRedirect stderrRedirect] removeListener:self.currentLog]; [[HBOutputRedirect stdoutRedirect] removeListener:self.currentLog]; + self.currentLog = nil; // Check to see if the encode state has not been cancelled // to determine if we should check for encode done notifications. - if (self.currentJob.state != HBJobStateCanceled) + if (result != HBCoreResultCancelled) { - [self jobCompletedAlerts]; - - // Mark the encode just finished as done - self.currentJob.state = HBJobStateCompleted; - + [self jobCompletedAlerts:job]; // Send to tagger - [self sendToExternalApp:self.currentJob.destURL]; + [self sendToExternalApp:job.destURL]; } - self.currentJob = nil; + // Mark the encode just finished + switch (result) { + case HBCoreResultDone: + job.state = HBJobStateCompleted; + break; + case HBCoreResultCancelled: + job.state = HBJobStateCanceled; + break; + default: + job.state = HBJobStateFailed; + break; + } - // since we have successfully completed an encode, we go to the next - if (!self.stop) + if ([self.jobs containsObject:job]) { - [self encodeNextQueueItem]; + [self reloadQueueItemAtIndex:[self.jobs indexOfObject:job]]; } - self.stop = NO; - [self.window.toolbar validateVisibleItems]; - [self reloadQueue]; + [self.jobs commit]; } /** * Here we actually tell hb_scan to perform the source scan, using the path to source and title number */ -- (void)performScan:(NSURL *)scanURL titleIdx:(NSInteger)index +- (void)encodeJob:(HBJob *)job { + NSParameterAssert(job); HBStateFormatter *formatter = [[HBStateFormatter alloc] init]; + // Progress handler + void (^progressHandler)(HBState state, hb_state_t hb_state) = ^(HBState state, hb_state_t hb_state) + { + NSString *status = [formatter stateToString:hb_state title:nil]; + self.progressTextField.stringValue = status; + [self.controller setQueueInfo:status progress:0 hidden:NO]; + }; + + // Completion handler + void (^completionHandler)(HBCoreResult result) = ^(HBCoreResult result) + { + if (result == HBCoreResultDone) + { + [self realEncodeJob:job]; + } + else + { + [self completedJob:job result:result]; + [self encodeNextQueueItem]; + } + }; + // Only scan 10 previews before an encode - additional previews are // only useful for autocrop and static previews, which are already taken care of at this point - [self.core scanURL:scanURL - titleIndex:index + [self.core scanURL:job.fileURL + titleIndex:job.titleIdx previews:10 minDuration:0 - progressHandler:^(HBState state, hb_state_t hb_state) { - NSString *status = [formatter stateToString:hb_state title:nil]; - - self.progressTextField.stringValue = status; - [self.controller setQueueInfo:status progress:0 hidden:NO]; - } - completionHandler:^(HBCoreResult result) { - if (result == HBCoreResultDone) - { - [self doEncodeQueueItem]; - } - else - { - [self.jobs beginTransaction]; - - self.currentJob.state = HBJobStateCanceled; - [self encodeCompleted]; - - [self.jobs commit]; - [self reloadQueue]; - } - - [self.window.toolbar validateVisibleItems]; - }]; + progressHandler:progressHandler + completionHandler:completionHandler]; } /** * This assumes that we have re-scanned and loaded up a new queue item to send to libhb */ -- (void)doEncodeQueueItem +- (void)realEncodeJob:(HBJob *)job { + NSParameterAssert(job); + // Reset the title in the job. - self.currentJob.title = self.core.titles[0]; + job.title = self.core.titles[0]; HBStateFormatter *converter = [[HBStateFormatter alloc] init]; - NSString *destinationName = self.currentJob.destURL.lastPathComponent; + NSString *destinationName = job.destURL.lastPathComponent; + + // Progress handler + void (^progressHandler)(HBState state, hb_state_t hb_state) = ^(HBState state, hb_state_t hb_state) + { + NSString *string = [converter stateToString:hb_state title:destinationName]; + CGFloat progress = [converter stateToPercentComplete:hb_state]; + + if (state == HBStateWorking) + { + // Update dock icon + if (self.dockIconProgress < 100.0 * progress) + { + #define p hb_state.param.working + [self.dockTile updateDockIcon:progress hours:p.hours minutes:p.minutes seconds:p.seconds]; + #undef p + self.dockIconProgress += dockTileUpdateFrequency; + } + } + else if (state == HBStateMuxing) + { + [self.dockTile updateDockIcon:1.0 withETA:@""]; + } + + // Update text field + self.progressTextField.stringValue = string; + [self.controller setQueueInfo:string progress:progress hidden:NO]; + }; + + // Completion handler + void (^completionHandler)(HBCoreResult result) = ^(HBCoreResult result) + { + NSString *info = NSLocalizedString(@"Encode Finished.", @""); + self.progressTextField.stringValue = info; + [self.controller setQueueInfo:info progress:1.0 hidden:YES]; + + // Restore dock icon + [self.dockTile updateDockIcon:-1.0 withETA:@""]; + self.dockIconProgress = 0; + + [self completedJob:job result:result]; + [self encodeNextQueueItem]; + }; // We should be all setup so let 'er rip - [self.core encodeJob:self.currentJob - progressHandler:^(HBState state, hb_state_t hb_state) { - NSString *string = [converter stateToString:hb_state title:destinationName]; - CGFloat progress = [converter stateToPercentComplete:hb_state]; - - if (state == HBStateWorking) - { - // Update dock icon - if (self.dockIconProgress < 100.0 * progress) - { - // ETA format is [XX]X:XX:XX when ETA is greater than one hour - // [X]X:XX when ETA is greater than 0 (minutes or seconds) - // When these conditions doesn't applied (eg. when ETA is undefined) - // we show just a tilde (~) - - #define p hb_state.param.working - NSString *etaStr; - if (p.hours > 0) - etaStr = [NSString stringWithFormat:@"%d:%02d:%02d", p.hours, p.minutes, p.seconds]; - else if (p.minutes > 0 || p.seconds > 0) - etaStr = [NSString stringWithFormat:@"%d:%02d", p.minutes, p.seconds]; - else - etaStr = @"~"; - #undef p - - [self.dockTile updateDockIcon:progress withETA:etaStr]; - self.dockIconProgress += dockTileUpdateFrequency; - } - } - else if (state == HBStateMuxing) - { - [self.dockTile updateDockIcon:1.0 withETA:@""]; - } - - // Update text field - self.progressTextField.stringValue = string; - [self.controller setQueueInfo:string progress:progress hidden:NO]; - } - completionHandler:^(HBCoreResult result) { - NSString *info = NSLocalizedString(@"Encode Finished.", @""); - - self.progressTextField.stringValue = info; - [self.controller setQueueInfo:info progress:1.0 hidden:YES]; - - // Restore dock icon - [self.dockTile updateDockIcon:-1.0 withETA:@""]; - self.dockIconProgress = 0; - - [self.jobs beginTransaction]; - - [self encodeCompleted]; - - [self.jobs commit]; - [self reloadQueue]; - }]; + [self.core encodeJob:job progressHandler:progressHandler completionHandler:completionHandler]; // We are done using the title, remove it from the job - self.currentJob.title = nil; + job.title = nil; } /** @@ -565,8 +752,6 @@ */ - (void)doCancelCurrentJob { - self.currentJob.state = HBJobStateCanceled; - if (self.core.state == HBStateScanning) { [self.core cancelScan]; @@ -582,12 +767,7 @@ */ - (void)cancelCurrentJobAndContinue { - [self.jobs beginTransaction]; - [self doCancelCurrentJob]; - - [self.jobs commit]; - [self reloadQueue]; } /** @@ -595,13 +775,16 @@ */ - (void)cancelCurrentJobAndStop { - [self.jobs beginTransaction]; - self.stop = YES; [self doCancelCurrentJob]; +} - [self.jobs commit]; - [self reloadQueue]; +/** + * Finishes the current job and stops libhb from processing the remaining encodes. + */ +- (void)finishCurrentAndStop +{ + self.stop = YES; } #pragma mark - Encode Done Actions @@ -632,10 +815,16 @@ clickContext:nil]; } +/** + * Sends the URL to the external app + * selected in the preferences. + * + * @param fileURL the URL of the file to send + */ - (void)sendToExternalApp:(NSURL *)fileURL { // This end of encode action is called as each encode rolls off of the queue - if ([[NSUserDefaults standardUserDefaults] boolForKey:@"sendToMetaX"] == YES) + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"SendCompletedEncodeToApp"] == YES) { NSWorkspace *workspace = [NSWorkspace sharedWorkspace]; NSString *sendToApp = [workspace fullPathForApplication:[[NSUserDefaults standardUserDefaults] objectForKey:@"SendCompletedEncodeToApp"]]; @@ -654,7 +843,10 @@ } } -- (void)jobCompletedAlerts +/** + * Runs the alert for a single job + */ +- (void)jobCompletedAlerts:(HBJob *)job { // Both the Notification and Sending to tagger can be done as encodes roll off the queue if ([[NSUserDefaults standardUserDefaults] integerForKey:@"HBAlertWhenDone"] == HBDoneActionNotification || @@ -665,10 +857,13 @@ { NSBeep(); } - [self showDoneNotification:self.currentJob.destURL]; + [self showDoneNotification:job.destURL]; } } +/** + * Runs the global queue completed alerts + */ - (void)queueCompletedAlerts { // If Play System Alert has been selected in Preferences @@ -721,12 +916,17 @@ */ - (IBAction)removeSelectedQueueItem:(id)sender { + if ([self.jobs beginTransaction] == HBDistributedArrayContentReload) + { + // Do not execture the action if the array changed. + [self.jobs commit]; + return; + } + NSMutableIndexSet *targetedRows = [[self.outlineView targetedRowIndexes] mutableCopy]; if (targetedRows.count) { - [self.jobs beginTransaction]; - // if this is a currently encoding job, we need to be sure to alert the user, // to let them decide to cancel it first, then if they do, we can come back and // remove it @@ -746,7 +946,7 @@ NSString *alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Stop This Encode and Remove It?", nil)]; // Which window to attach the sheet to? - NSWindow *targetWindow = nil; + NSWindow *targetWindow = self.window; if ([sender respondsToSelector: @selector(window)]) { targetWindow = [sender window]; @@ -768,14 +968,8 @@ // remove the non working items immediately [self removeQueueItemsAtIndexes:targetedRows]; - [self getQueueStats]; - - [self.outlineView beginUpdates]; - [self.outlineView removeItemsAtIndexes:targetedRows inParent:nil withAnimation:NSTableViewAnimationEffectFade]; - [self.outlineView endUpdates]; - - [self.jobs commit]; } + [self.jobs commit]; } - (void)didDimissCancelCurrentJob:(NSAlert *)alert @@ -784,10 +978,11 @@ { if (returnCode == NSAlertSecondButtonReturn) { + [self.jobs beginTransaction]; + NSInteger index = [self.jobs indexOfObject:self.currentJob]; [self cancelCurrentJobAndContinue]; - [self.jobs beginTransaction]; [self removeQueueItemAtIndex:index]; [self.jobs commit]; } @@ -796,7 +991,7 @@ /** * Show the finished encode in the finder */ -- (IBAction)revealSelectedQueueItems: (id)sender +- (IBAction)revealSelectedQueueItems:(id)sender { NSIndexSet *targetedRows = [self.outlineView targetedRowIndexes]; NSMutableArray *urls = [[NSMutableArray alloc] init]; @@ -868,12 +1063,7 @@ // or shut down when encoding is finished [self remindUserOfSleepOrShutdown]; - [self.jobs beginTransaction]; - [self encodeNextQueueItem]; - - [self.jobs commit]; - [self reloadQueue]; } } @@ -885,15 +1075,11 @@ - (IBAction)cancelRip:(id)sender { // Which window to attach the sheet to? - NSWindow *window; + NSWindow *window = self.window; if ([sender respondsToSelector:@selector(window)]) { window = [sender window]; } - else - { - window = self.window; - } NSAlert *alert = [[NSAlert alloc] init]; [alert setMessageText:NSLocalizedString(@"You are currently encoding. What would you like to do?", nil)]; @@ -901,6 +1087,7 @@ [alert addButtonWithTitle:NSLocalizedString(@"Continue Encoding", nil)]; [alert addButtonWithTitle:NSLocalizedString(@"Cancel Current and Stop", nil)]; [alert addButtonWithTitle:NSLocalizedString(@"Cancel Current and Continue", nil)]; + [alert addButtonWithTitle:NSLocalizedString(@"Finish Current and Stop", nil)]; [alert setAlertStyle:NSCriticalAlertStyle]; [alert beginSheetModalForWindow:window @@ -921,6 +1108,10 @@ { [self cancelCurrentJobAndContinue]; } + else if (returnCode == NSAlertThirdButtonReturn + 1) + { + [self finishCurrentAndStop]; + } } /** @@ -955,9 +1146,17 @@ } } +/** + * Resets the job state to ready. + */ - (IBAction)resetJobState:(id)sender { - [self.jobs beginTransaction]; + if ([self.jobs beginTransaction] == HBDistributedArrayContentReload) + { + // Do not execture the action if the array changed. + [self.jobs commit]; + return; + } NSIndexSet *targetedRows = [self.outlineView targetedRowIndexes]; NSMutableIndexSet *updatedIndexes = [NSMutableIndexSet indexSet]; @@ -966,7 +1165,7 @@ while (currentIndex != NSNotFound) { HBJob *job = self.jobs[currentIndex]; - if (job.state == HBJobStateCanceled || job.state == HBJobStateCompleted) + if (job.state == HBJobStateCanceled || job.state == HBJobStateCompleted || job.state == HBJobStateFailed) { job.state = HBJobStateReady; [updatedIndexes addIndex:currentIndex]; @@ -974,8 +1173,32 @@ currentIndex = [targetedRows indexGreaterThanIndex:currentIndex]; } - [self.outlineView reloadDataForRowIndexes:updatedIndexes columnIndexes:[NSIndexSet indexSetWithIndex:0]]; - [self getQueueStats]; + [self reloadQueueItemsAtIndexes:updatedIndexes]; + [self.jobs commit]; +} + +- (void)editQueueItem:(HBJob *)job +{ + NSParameterAssert(job); + [self.jobs beginTransaction]; + + NSInteger index = [self.jobs indexOfObject:job]; + + // Cancel the encode if it's the current item + if (job == self.currentJob) + { + [self cancelCurrentJobAndContinue]; + } + + if ([self.controller openJob:job]) + { + // Now that source is loaded and settings applied, delete the queue item from the queue + [self removeQueueItemAtIndex:index]; + } + else + { + NSBeep(); + } [self.jobs commit]; } @@ -985,9 +1208,14 @@ */ - (IBAction)editSelectedQueueItem:(id)sender { - [self.jobs beginTransaction]; + if ([self.jobs beginTransaction] == HBDistributedArrayContentReload) + { + // Do not execture the action if the array changed. + [self.jobs commit]; + return; + } - NSInteger row = [self.outlineView clickedRow]; + NSInteger row = self.outlineView.clickedRow; if (row != NSNotFound) { // if this is a currently encoding job, we need to be sure to alert the user, @@ -999,7 +1227,7 @@ NSString *alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Stop This Encode and Edit It?", nil)]; // Which window to attach the sheet to? - NSWindow *docWindow = nil; + NSWindow *docWindow = self.window; if ([sender respondsToSelector: @selector(window)]) { docWindow = [sender window]; @@ -1019,18 +1247,7 @@ } else if (job.state != HBJobStateWorking) { - // since we are not a currently encoding item, we can just be edit it - HBJob *item = [[self.jobs[row] representedObject] copy]; - if ([self.controller openJob:item]) - { - // Now that source is loaded and settings applied, delete the queue item from the queue - [self.outlineView beginUpdates]; - [self removeQueueItemAtIndex:row]; - [self.outlineView removeItemsAtIndexes:[NSIndexSet indexSetWithIndex:row] inParent:nil withAnimation:NSTableViewAnimationEffectFade]; - [self.outlineView endUpdates]; - - [self getQueueStats]; - } + [self editQueueItem:job]; } } @@ -1044,42 +1261,28 @@ if (returnCode == NSAlertSecondButtonReturn) { HBJob *job = (__bridge HBJob *)contextInfo; - NSInteger index = [self.jobs indexOfObject:job]; - - if (job == self.currentJob) - { - [self cancelCurrentJobAndContinue]; - } - - if ([self.controller openJob:job]) - { - [self.jobs beginTransaction]; - [self.controller openJob:job]; - [self removeQueueItemAtIndex:index]; - [self.jobs commit]; - [self getQueueStats]; - } + [self editQueueItem:job]; } } - (IBAction)clearAll:(id)sender { [self.jobs beginTransaction]; - [self.jobs removeObjectsUsingBlock:^BOOL(HBJob *item) { + NSIndexSet *indexes = [self.jobs indexesOfObjectsUsingBlock:^BOOL(HBJob *item) { return (item.state != HBJobStateWorking); }]; + [self removeQueueItemsAtIndexes:indexes]; [self.jobs commit]; - [self reloadQueue]; } - (IBAction)clearCompleted:(id)sender { [self.jobs beginTransaction]; - [self.jobs removeObjectsUsingBlock:^BOOL(HBJob *item) { + NSIndexSet *indexes = [self.jobs indexesOfObjectsUsingBlock:^BOOL(HBJob *item) { return (item.state == HBJobStateCompleted); }]; + [self removeQueueItemsAtIndexes:indexes]; [self.jobs commit]; - [self reloadQueue]; } #pragma mark - @@ -1117,7 +1320,7 @@ // top-level items. if (item == nil) { - return [self.jobs count]; + return self.jobs.count; } else { @@ -1141,6 +1344,9 @@ [self.outlineView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row,1)]]; } +#define HB_ROW_HEIGHT_TITLE_ONLY 17.0 +#define HB_ROW_HEIGHT_PADDING 6.0 + - (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item { if ([outlineView isItemExpanded:item]) @@ -1153,14 +1359,14 @@ NSCell *cell = [outlineView preparedCellAtColumn:columnToWrap row:[outlineView rowForItem:item]]; // See how tall it naturally would want to be if given a restricted with, but unbound height - NSRect constrainedBounds = NSMakeRect(0, 0, [tableColumnToWrap width], CGFLOAT_MAX); + NSRect constrainedBounds = NSMakeRect(0, 0, tableColumnToWrap.width, CGFLOAT_MAX); NSSize naturalSize = [cell cellSizeForBounds:constrainedBounds]; // Make sure we have a minimum height -- use the table's set height as the minimum. - if (naturalSize.height > [outlineView rowHeight]) - return naturalSize.height; + if (naturalSize.height > outlineView.rowHeight) + return naturalSize.height + HB_ROW_HEIGHT_PADDING; else - return [outlineView rowHeight]; + return outlineView.rowHeight; } else { @@ -1173,17 +1379,15 @@ if ([tableColumn.identifier isEqualToString:@"desc"]) { HBJob *job = item; + NSAttributedString *description = self.descriptions[@(job.hash)]; - if (self.descriptions[@(job.hash)]) + if (description == nil) { - return self.descriptions[@(job.hash)]; + description = job.attributedDescription; + self.descriptions[@(job.hash)] = description; } - NSAttributedString *finalString = job.attributedDescription; - - self.descriptions[@(job.hash)] = finalString;; - - return finalString; + return description; } else if ([tableColumn.identifier isEqualToString:@"icon"]) { @@ -1200,6 +1404,10 @@ { return [NSImage imageNamed:@"EncodeCanceled"]; } + else if (job.state == HBJobStateFailed) + { + return [NSImage imageNamed:@"EncodeFailed"]; + } else { return [NSImage imageNamed:@"JobSmall"]; @@ -1231,7 +1439,9 @@ [cell setAlternateImage:[NSImage imageNamed:@"RevealHighlightPressed"]]; } else + { [cell setImage:[NSImage imageNamed:@"Reveal"]]; + } } else { @@ -1242,7 +1452,9 @@ [cell setAlternateImage:[NSImage imageNamed:@"DeleteHighlightPressed"]]; } else + { [cell setImage:[NSImage imageNamed:@"Delete"]]; + } } } } @@ -1261,7 +1473,7 @@ } } -#pragma mark NSOutlineView delegate (dragging related) +#pragma mark NSOutlineView drag & drop - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard { @@ -1294,7 +1506,7 @@ // Don't allow dropping INTO an item since they can't really contain any children. if (item != nil) { - index = [self.outlineView rowForItem: item] + 1; + index = [self.outlineView rowForItem:item] + 1; item = nil; } @@ -1304,7 +1516,7 @@ if (encodingIndex != NSNotFound && index <= encodingIndex) { return NSDragOperationNone; - index = MAX (index, encodingIndex); + index = MAX(index, encodingIndex); } [outlineView setDropItem:item dropChildIndex:index]; @@ -1313,29 +1525,7 @@ - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index { - [self.jobs beginTransaction]; - [self.outlineView beginUpdates]; - - for (id object in self.dragNodesArray.reverseObjectEnumerator) - { - NSUInteger sourceIndex = [self.jobs indexOfObject:object]; - [self.jobs removeObjectAtIndex:sourceIndex]; - - if (sourceIndex < index) - { - index--; - } - - [self.jobs insertObject:object atIndex:index]; - - NSUInteger destIndex = [self.jobs indexOfObject:object]; - - [self.outlineView moveItemAtIndex:sourceIndex inParent:nil toIndex:destIndex inParent:nil]; - } - - [self.outlineView endUpdates]; - [self.jobs commit]; - + [self moveQueueItems:self.dragNodesArray toIndex:index]; return YES; } diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index 53dbc1ebc..654be76b1 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -168,6 +168,8 @@ A990D9071A64562200139032 /* HBJob+HBJobConversion.m in Sources */ = {isa = PBXBuildFile; fileRef = A990D9061A64562200139032 /* HBJob+HBJobConversion.m */; }; A9935213196F38A70069C6B7 /* ChaptersTitles.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9935211196F38A70069C6B7 /* ChaptersTitles.xib */; }; A99422E01B1887B000DDB077 /* NSJSONSerialization+HBAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = A99422DF1B1887B000DDB077 /* NSJSONSerialization+HBAdditions.m */; }; + A996557D1BD2D32500BA50FA /* EncodeFailed.png in Resources */ = {isa = PBXBuildFile; fileRef = A996557B1BD2D32500BA50FA /* EncodeFailed.png */; }; + A996557E1BD2D32500BA50FA /* [email protected] in Resources */ = {isa = PBXBuildFile; fileRef = A996557C1BD2D32500BA50FA /* [email protected] */; }; A99F40CF1B624E7E00750170 /* HBPictureViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A99F40CD1B624E7E00750170 /* HBPictureViewController.m */; }; A99F40D31B624EA500750170 /* HBPictureViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A99F40D11B624EA500750170 /* HBPictureViewController.xib */; }; A9A24B2D1B09F6FD00AD1FAB /* HBPresetsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A9A24B2C1B09F6FD00AD1FAB /* HBPresetsTests.m */; }; @@ -474,6 +476,8 @@ A9935212196F38A70069C6B7 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = ChaptersTitles.xib; sourceTree = "<group>"; }; A99422DE1B1887B000DDB077 /* NSJSONSerialization+HBAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSJSONSerialization+HBAdditions.h"; sourceTree = "<group>"; }; A99422DF1B1887B000DDB077 /* NSJSONSerialization+HBAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSJSONSerialization+HBAdditions.m"; sourceTree = "<group>"; }; + A996557B1BD2D32500BA50FA /* EncodeFailed.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = EncodeFailed.png; sourceTree = "<group>"; }; + A996557C1BD2D32500BA50FA /* [email protected] */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "[email protected]"; sourceTree = "<group>"; }; A997D8EB1A4ABB0900E19B6F /* HBPresetCoding.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HBPresetCoding.h; sourceTree = "<group>"; }; A99F40CC1B624E7E00750170 /* HBPictureViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPictureViewController.h; sourceTree = "<group>"; }; A99F40CD1B624E7E00750170 /* HBPictureViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPictureViewController.m; sourceTree = "<group>"; }; @@ -831,6 +835,8 @@ 273F212814ADCBF70021BE6D /* DeletePressed.png */, 273F212A14ADCBF80021BE6D /* EncodeCanceled.png */, A967E4B91A16768200DF1DFC /* [email protected] */, + A996557B1BD2D32500BA50FA /* EncodeFailed.png */, + A996557C1BD2D32500BA50FA /* [email protected] */, A91C02501A165EA200DEA6F3 /* EncodeComplete.png */, A91C02511A165EA200DEA6F3 /* [email protected] */, 273F212C14ADCBF80021BE6D /* EncodeWorking0.png */, @@ -1362,6 +1368,7 @@ A922687B1A6E569B00A8D5C5 /* MainWindow.xib in Resources */, 273F219114ADDDA10021BE6D /* Queue.xib in Resources */, 3490BCB41614CF8D002A5AD7 /* HandBrake.icns in Resources */, + A996557D1BD2D32500BA50FA /* EncodeFailed.png in Resources */, A9E1468016BC2AD800C307BC /* next-p.pdf in Resources */, A9E1468116BC2AD800C307BC /* pause-p.pdf in Resources */, A9E1468216BC2AD800C307BC /* play-p.pdf in Resources */, @@ -1388,6 +1395,7 @@ A99F40D31B624EA500750170 /* HBPictureViewController.xib in Resources */, A9252C0A1A173D4800B8B7F8 /* [email protected] in Resources */, D2BCB11516F5152C0084604C /* picturesettings.png in Resources */, + A996557E1BD2D32500BA50FA /* [email protected] in Resources */, A93E0ED71972958C00FD67FB /* Video.xib in Resources */, A9252C0B1A173D4800B8B7F8 /* [email protected] in Resources */, D2BCB11616F5152C0084604C /* [email protected] in Resources */, diff --git a/macosx/NSArray+HBAdditions.h b/macosx/NSArray+HBAdditions.h index deb2796a4..b423e1e2b 100644 --- a/macosx/NSArray+HBAdditions.h +++ b/macosx/NSArray+HBAdditions.h @@ -8,13 +8,6 @@ #import <Foundation/Foundation.h> -@interface NSMutableArray (HBAdditions) - -- (void)removeObjectsUsingBlock:(BOOL (^)(id object))block; - -@end - - @interface NSArray (HBAdditions) - (NSArray *)filteredArrayUsingBlock:(BOOL (^)(id object))block; diff --git a/macosx/NSArray+HBAdditions.m b/macosx/NSArray+HBAdditions.m index babcc9f15..c54147098 100644 --- a/macosx/NSArray+HBAdditions.m +++ b/macosx/NSArray+HBAdditions.m @@ -8,23 +8,6 @@ #import "NSArray+HBAdditions.h" -@implementation NSMutableArray (HBAdditions) - -- (void)removeObjectsUsingBlock:(BOOL (^)(id object))block -{ - NSMutableArray *objectsToRemove = [NSMutableArray array]; - for (id object in self) - { - if (block(object)) - { - [objectsToRemove addObject:object]; - } - } - [self removeObjectsInArray:objectsToRemove]; -} - -@end - @implementation NSArray (HBAdditions) - (NSArray *)filteredArrayUsingBlock:(BOOL (^)(id object))block diff --git a/macosx/icons/EncodeCanceled.png b/macosx/icons/EncodeCanceled.png Binary files differindex 66c5bf7c9..6516035d5 100644 --- a/macosx/icons/EncodeCanceled.png +++ b/macosx/icons/EncodeCanceled.png diff --git a/macosx/icons/[email protected] b/macosx/icons/[email protected] Binary files differindex 915ec17e0..89e4fd397 100644 --- a/macosx/icons/[email protected] +++ b/macosx/icons/[email protected] diff --git a/macosx/icons/EncodeFailed.png b/macosx/icons/EncodeFailed.png Binary files differnew file mode 100644 index 000000000..2c7712f76 --- /dev/null +++ b/macosx/icons/EncodeFailed.png diff --git a/macosx/icons/[email protected] b/macosx/icons/[email protected] Binary files differnew file mode 100644 index 000000000..3740dfdb4 --- /dev/null +++ b/macosx/icons/[email protected] |