summaryrefslogtreecommitdiffstats
path: root/macosx/HBQueueController.mm
diff options
context:
space:
mode:
Diffstat (limited to 'macosx/HBQueueController.mm')
-rw-r--r--macosx/HBQueueController.mm1716
1 files changed, 903 insertions, 813 deletions
diff --git a/macosx/HBQueueController.mm b/macosx/HBQueueController.mm
index 542b2ba33..9ca4137bf 100644
--- a/macosx/HBQueueController.mm
+++ b/macosx/HBQueueController.mm
@@ -1,3 +1,4 @@
+
/* HBQueueController
This file is part of the HandBrake source code.
@@ -5,92 +6,53 @@
It may be used under the terms of the GNU General Public License. */
#import "HBQueueController.h"
+
#import "HBCore.h"
#import "Controller.h"
+#import "HBOutputPanelController.h"
#import "HBQueueOutlineView.h"
-#import "HBImageAndTextCell.h"
#import "HBUtilities.h"
#import "HBJob.h"
-#import "HBAudioDefaults.h"
-#import "HBAudioTrack.h"
+#import "HBJob+UIAdditions.h"
-#import "HBPicture+UIAdditions.h"
-#import "HBFilters+UIAdditions.h"
+#import "HBDistributedArray.h"
-#define HB_ROW_HEIGHT_TITLE_ONLY 17.0
+#import "HBDockTile.h"
// Pasteboard type for or drag operations
-#define DragDropSimplePboardType @"HBQueueCustomOutlineViewPboardType"
+#define DragDropSimplePboardType @"HBQueueCustomOutlineViewPboardType"
-#pragma mark -
+// DockTile update freqency in total percent increment
+#define dockTileUpdateFrequency 0.1f
-//------------------------------------------------------------------------------------
-// NSMutableAttributedString (HBAdditions)
-//------------------------------------------------------------------------------------
-
-@interface NSMutableAttributedString (HBAdditions)
-- (void) appendString: (NSString*)aString withAttributes: (NSDictionary *)aDictionary;
-@end
-
-@implementation NSMutableAttributedString (HBAdditions)
-- (void) appendString: (NSString*)aString withAttributes: (NSDictionary *)aDictionary
-{
- NSAttributedString *s = [[[NSAttributedString alloc] initWithString:aString
- attributes:aDictionary] autorelease];
- [self appendAttributedString:s];
-}
-@end
-
-#pragma mark -
+#define HB_ROW_HEIGHT_TITLE_ONLY 17.0
@interface HBQueueController () <HBQueueOutlineViewDelegate>
-{
- HBController *fHBController; // reference to HBController
- NSMutableArray *fJobGroups; // mirror image of the queue array from controller.mm
-
- int pidNum; // Records the PID number from HBController for this instance
- int fEncodingQueueItem; // corresponds to the index of fJobGroups encoding item
- int fPendingCount; // Number of various kinds of job groups in fJobGroups.
- int fWorkingCount;
- NSMutableIndexSet *fSavedExpandedItems; // used by save/restoreOutlineViewState to preserve which items are expanded
- NSMutableIndexSet *fSavedSelectedItems; // used by save/restoreOutlineViewState to preserve which items are selected
- NSMutableDictionary *descriptions;
+@property (nonatomic, readonly) HBDockTile *dockTile;
+@property (nonatomic, readwrite) double dockIconProgress;
- NSTimer *fAnimationTimer; // animates the icon of the current job in the queue outline view
- int fAnimationIndex; // used to generate name of image used to animate the current job in the queue outline view
+@property (assign) IBOutlet NSTextField *progressTextField;
+@property (assign) IBOutlet NSTextField *countTextField;
+@property (assign) IBOutlet HBQueueOutlineView *outlineView;
- IBOutlet NSTextField *fProgressTextField;
+@property (nonatomic, readonly) NSMutableDictionary *descriptions;
- IBOutlet HBQueueOutlineView *fOutlineView;
- IBOutlet NSTextField *fQueueCountField;
- NSArray *fDraggedNodes;
+@property (nonatomic, readonly) HBDistributedArray *jobs;
+@property (nonatomic, retain) HBJob *currentJob;
- // Text Styles
- NSMutableParagraphStyle *ps;
- NSDictionary *detailAttr;
- NSDictionary *detailBoldAttr;
- NSDictionary *titleAttr;
- NSDictionary *shortHeightAttr;
-}
-
-@property (nonatomic, readonly) HBCore *queueCore;
+@property (nonatomic, readwrite) NSUInteger pendingItemsCount;
+@property (nonatomic, readwrite) NSUInteger workingItemsCount;
-/* control encodes in the window */
-- (IBAction)removeSelectedQueueItem: (id)sender;
-- (IBAction)revealSelectedQueueItem: (id)sender;
-- (IBAction)editSelectedQueueItem: (id)sender;
+@property (nonatomic, retain) NSArray *dragNodesArray;
@end
@implementation HBQueueController
-//------------------------------------------------------------------------------------
-// init
-//------------------------------------------------------------------------------------
-- (id)init
+- (instancetype)init
{
if (self = [super initWithWindowNibName:@"Queue"])
{
@@ -101,267 +63,743 @@
// If/when we switch to using bindings, this can probably go away.
[self window];
- // Our defaults
- [[NSUserDefaults standardUserDefaults] registerDefaults:@{@"QueueWindowIsOpen": @"NO"}];
+ _descriptions = [[NSMutableDictionary alloc] init];
+
+ // Workaround to avoid a bug in Snow Leopard
+ // we can switch back to [[NSApplication sharedApplication] applicationIconImage]
+ // when we won't support it anymore.
+ NSImage *appIcon = [NSImage imageNamed:@"HandBrake"];
+ [appIcon setSize:NSMakeSize(1024, 1024)];
+
+ // Load the dockTile and instiante initial text fields
+ _dockTile = [[HBDockTile alloc] initWithDockTile:[[NSApplication sharedApplication] dockTile]
+ image:appIcon];
- fJobGroups = [[NSMutableArray arrayWithCapacity:0] retain];
- descriptions = [[NSMutableDictionary alloc] init];
+ int loggingLevel = [[[NSUserDefaults standardUserDefaults] objectForKey:@"LoggingLevel"] intValue];
- [self initStyles];
+ // Init a separate instance of libhb for the queue
+ _core = [[HBCore alloc] initWithLoggingLevel:loggingLevel];
+ _core.name = @"QueueCore";
+
+ [self loadQueueFile];
}
return self;
}
-- (void)setQueueArray:(NSMutableArray *)QueueFileArray
+- (void)dealloc
+{
+ // clear the delegate so that windowWillClose is not attempted
+ if ([[self window] delegate] == self)
+ [[self window] setDelegate:nil];
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
+ [_core release];
+ [_jobs release];
+ [_currentJob release];
+
+ [_dockTile release];
+ [_descriptions release];
+ [_dragNodesArray release];
+
+ [super dealloc];
+}
+
+- (void)windowDidLoad
+{
+ // lets setup our queue list outline view for drag and drop here
+ [self.outlineView registerForDraggedTypes:@[DragDropSimplePboardType]];
+ [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];
+}
+
+- (void)windowWillClose:(NSNotification *)aNotification
+{
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"QueueWindowIsOpen"];
+}
+
+/**
+ * Displays and brings the queue window to the front
+ */
+- (IBAction)showWindow:(id)sender
+{
+ [super showWindow:sender];
+ [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"QueueWindowIsOpen"];
+}
+
+#pragma mark Toolbar
+
+- (BOOL)validateToolbarItem:(NSToolbarItem *)theItem
+{
+ SEL action = theItem.action;
+ HBState s = self.core.state;
+
+ if (action == @selector(toggleStartCancel:))
+ {
+ if ((s == HBStatePaused) || (s == HBStateWorking) || (s == HBStateMuxing))
+ {
+ theItem.image = [NSImage imageNamed:@"stopencode"];
+ theItem.label = NSLocalizedString(@"Stop", @"");
+ theItem.toolTip = NSLocalizedString(@"Stop Encoding", @"");
+ return YES;
+ }
+ else
+ {
+ theItem.image = [NSImage imageNamed:@"encode"];
+ theItem.label = NSLocalizedString(@"Start", @"");
+ theItem.toolTip = NSLocalizedString(@"Start Encoding", @"");
+ return (self.pendingItemsCount > 0);
+ }
+ }
+
+ if (action == @selector(togglePauseResume:))
+ {
+ if (s == HBStatePaused)
+ {
+ theItem.image = [NSImage imageNamed:@"encode"];
+ theItem.label = NSLocalizedString(@"Resume", @"");
+ theItem.toolTip = NSLocalizedString(@"Resume Encoding", @"");
+ return YES;
+ }
+ else
+ {
+ theItem.image = [NSImage imageNamed:@"pauseencode"];
+ theItem.label = NSLocalizedString(@"Pause", @"");
+ theItem.toolTip = NSLocalizedString(@"Pause Encoding", @"");
+ return (s == HBStateWorking || s == HBStateMuxing);
+ }
+ }
+
+ return NO;
+}
+
+#pragma mark -
+#pragma mark Queue File
+
+- (void)reloadQueue
{
- [fJobGroups setArray:QueueFileArray];
- [descriptions removeAllObjects];
+ [self getQueueStats];
+ [self.outlineView reloadData];
+}
- [fOutlineView reloadData];
+- (void)loadQueueFile
+{
+ NSURL *queueURL = [NSURL fileURLWithPath:[[HBUtilities appSupportPath] stringByAppendingPathComponent:@"Queue/Queue.hbqueue"]];
+ _jobs = [[HBDistributedArray alloc] initWithURL:queueURL];
+
+ [self reloadQueue];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reloadQueue) name:HBDistributedArrayChanged object:_jobs];
+}
+
+- (void)addJob:(HBJob *)item
+{
+ [self.jobs beginTransaction];
+ [self.jobs addObject:item];
+ [self.jobs commit];
+
+ [self reloadQueue];
+}
+- (void)addJobsFromArray:(NSArray *)items;
+{
+ [self.jobs beginTransaction];
+ [self.jobs addObjectsFromArray:items];
+ [self.jobs commit];
+
+ [self reloadQueue];
+}
+
+- (BOOL)jobExistAtURL:(NSURL *)url
+{
+ for (HBJob *item in self.jobs)
+ {
+ if ([item.destURL isEqualTo:url])
+ {
+ return YES;
+ }
+ }
+ return NO;
+}
+
+- (void)removeQueueItemAtIndex:(NSUInteger)index
+{
+ [self.jobs beginTransaction];
+ if (self.jobs.count > index)
+ {
+ [self.jobs removeObjectAtIndex:index];
+ }
+ [self.jobs commit];
+
+ [self reloadQueue];
+}
+
+/**
+ * Updates the queue status label.
+ */
+- (void)getQueueStats
+{
// lets get the stats on the status of the queue array
-
- fPendingCount = 0;
- fWorkingCount = 0;
-
- int i = 0;
- for (HBJob *job in fJobGroups)
- {
- if (job.state == HBJobStateWorking) // being encoded
- {
- fWorkingCount++;
- // we have an encoding job so, lets start the animation timer
- if (job.pidId == pidNum)
- {
- fEncodingQueueItem = i;
- }
- }
+ NSUInteger pendingCount = 0;
+ NSUInteger workingCount = 0;
+
+ for (HBJob *job in self.jobs)
+ {
+ if (job.state == HBJobStateWorking) // being encoded
+ {
+ workingCount++;
+ }
if (job.state == HBJobStateReady) // pending
{
- fPendingCount++;
- }
- i++;
- }
+ pendingCount++;
+ }
+ }
- // Set the queue status field in the queue window
- NSMutableString *string;
- if (fPendingCount == 0)
+ NSString *string;
+ if (pendingCount == 0)
{
- string = [NSMutableString stringWithFormat: NSLocalizedString( @"No encode pending", @"" )];
+ string = NSLocalizedString(@"No encode pending", @"");
}
- else if (fPendingCount == 1)
+ else if (pendingCount == 1)
{
- string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encode pending", @"" ), fPendingCount];
+ string = [NSString stringWithFormat: NSLocalizedString(@"%d encode pending", @""), pendingCount];
}
else
{
- string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encodes pending", @"" ), fPendingCount];
+ string = [NSString stringWithFormat: NSLocalizedString(@"%d encodes pending", @""), pendingCount];
}
- [fQueueCountField setStringValue:string];
-
+
+ self.countTextField.stringValue = string;
+ [self.controller setQueueState:string];
+
+ self.pendingItemsCount = pendingCount;
+ self.workingItemsCount = workingCount;
}
-/* This method sets the status string in the queue window
- * and is called from Controller.mm (fHBController)
- * instead of running another timer here polling libhb
- * for encoding status
- */
-- (void)setQueueStatusString:(NSString *)statusString
+- (NSUInteger)count
{
- [fProgressTextField setStringValue:statusString];
+ return self.jobs.count;
}
-//------------------------------------------------------------------------------------
-// dealloc
-//------------------------------------------------------------------------------------
-- (void)dealloc
+/**
+ * Used to get the next pending queue item and return it if found
+ */
+- (HBJob *)getNextPendingQueueItem
{
- // clear the delegate so that windowWillClose is not attempted
- if( [[self window] delegate] == self )
- [[self window] setDelegate:nil];
+ for (HBJob *job in self.jobs)
+ {
+ if (job.state == HBJobStateReady)
+ {
+ return job;
+ }
+ }
+ return nil;
+}
- [fJobGroups release];
+/**
+ * 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];
- [fSavedExpandedItems release];
- [fSavedSelectedItems release];
+ [self reloadQueue];
+}
- [ps release];
- [detailAttr release];
- [detailBoldAttr release];
- [titleAttr release];
- [shortHeightAttr release];
+/**
+ * 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)clearEncodedJobs
+{
+ [self.jobs beginTransaction];
+ NSMutableArray *encodedJobs = [NSMutableArray array];
+ for (HBJob *job in self.jobs)
+ {
+ if (job.state == HBJobStateCompleted || job.state == HBJobStateCanceled)
+ {
+ [encodedJobs addObject:job];
+ }
+ }
- [[NSNotificationCenter defaultCenter] removeObserver:self];
+ [self.jobs removeObjectsInArray:encodedJobs];
+ [self.jobs commit];
- [super dealloc];
+ [self reloadQueue];
}
-//------------------------------------------------------------------------------------
-// Receive HB handle
-//------------------------------------------------------------------------------------
-- (void)setCore: (HBCore *)core
+/**
+ * This method will clear the queue of all encodes. effectively creating an empty queue
+ */
+- (void)removeAllJobs
{
- _queueCore = core;
-}
+ [self.jobs beginTransaction];
+ [self.jobs removeAllObjects];
+ [self.jobs commit];
-//------------------------------------------------------------------------------------
-// Receive HBController
-//------------------------------------------------------------------------------------
-- (void)setHBController: (HBController *)controller
-{
- fHBController = controller;
+ [self reloadQueue];
}
-- (void)setPidNum: (int)myPidnum
+/**
+ * this is actually called from the queue controller to modify the queue array and return it back to the queue controller
+ */
+- (void)moveObjectsInQueueArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex
{
- pidNum = myPidnum;
- [HBUtilities writeToActivityLog: "HBQueueController : My Pidnum is %d", pidNum];
+ [self.jobs beginTransaction];
+
+ NSUInteger index = [indexSet lastIndex];
+ NSUInteger aboveInsertIndexCount = 0;
+
+ NSUInteger removeIndex;
+
+ if (index >= insertIndex)
+ {
+ removeIndex = index + aboveInsertIndexCount;
+ aboveInsertIndexCount++;
+ }
+ else
+ {
+ removeIndex = index;
+ insertIndex--;
+ }
+
+ id object = [self.jobs[removeIndex] retain];
+ [self.jobs removeObjectAtIndex:removeIndex];
+ [self.jobs insertObject:object atIndex:insertIndex];
+ [object release];
+
+ // We save all of the Queue data here
+ // and it also gets sent back to the queue controller
+ [self.jobs commit];
+ [self reloadQueue];
}
#pragma mark -
+#pragma mark Queue Job Processing
-//------------------------------------------------------------------------------------
-// Displays and brings the queue window to the front
-//------------------------------------------------------------------------------------
-- (IBAction) showQueueWindow: (id)sender
+/**
+ * Starts the queue
+ */
+- (void)encodeNextQueueItem
{
- [self showWindow:sender];
- [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"QueueWindowIsOpen"];
- [self startAnimatingCurrentWorkingEncodeInQueue];
+ // 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)
+ {
+ 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;
+
+ // now we can go ahead and scan the new pending queue item
+ [self performScan:self.currentJob.fileURL titleIdx:self.currentJob.titleIdx];
+ }
+ else
+ {
+ self.currentJob = nil;
+
+ [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];
+ }
}
-//------------------------------------------------------------------------------------
-// windowDidLoad
-//------------------------------------------------------------------------------------
-- (void)windowDidLoad
+- (void)encodeCompleted
{
- /* lets setup our queue list outline view for drag and drop here */
- [fOutlineView registerForDraggedTypes: @[DragDropSimplePboardType] ];
- [fOutlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
- [fOutlineView setVerticalMotionCanBeginDrag: YES];
+ // Since we are done with this encode, tell output to stop writing to the
+ // individual encode log.
+ [self.outputPanel endEncodeLog];
- // Don't allow autoresizing of main column, else the "delete" column will get
- // pushed out of view.
- [fOutlineView setAutoresizesOutlineColumn: NO];
+ // 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)
+ {
+ // Both the Growl Alert and Sending to tagger can be done as encodes roll off the queue
+ if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Growl Notification"] ||
+ [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"])
+ {
+ // If Play System Alert has been selected in Preferences
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"AlertWhenDoneSound"] == YES)
+ {
+ NSBeep();
+ }
+ [self showGrowlDoneNotification:self.currentJob.destURL];
+ }
+
+ // Mark the encode just finished as done
+ self.currentJob.state = HBJobStateCompleted;
+
+ // Send to tagger
+ [self sendToExternalApp:self.currentJob.destURL];
+ }
+
+ self.currentJob = nil;
+
+ // since we have successfully completed an encode, we go to the next
+ [self encodeNextQueueItem];
+
+ [self.window.toolbar validateVisibleItems];
+ [self reloadQueue];
}
-//------------------------------------------------------------------------------------
-// windowWillClose
-//------------------------------------------------------------------------------------
-- (void)windowWillClose:(NSNotification *)aNotification
+/**
+ * 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
{
- [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"QueueWindowIsOpen"];
- [self stopAnimatingCurrentJobGroupInQueue];
+ // Tell HB to output a new activity log file for this encode
+ [self.outputPanel startEncodeLog:self.currentJob.destURL];
+
+ // 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
+ previews:10
+ minDuration:0
+ progressHandler:^(HBState state, hb_state_t hb_state) {
+ NSMutableString *status = [NSMutableString stringWithFormat:
+ NSLocalizedString( @"Queue Scanning title %d of %d…", @"" ),
+ hb_state.param.scanning.title_cur, hb_state.param.scanning.title_count];
+ if (hb_state.param.scanning.preview_cur)
+ {
+ [status appendFormat:@", preview %d…", hb_state.param.scanning.preview_cur];
+ }
+
+ self.progressTextField.stringValue = status;
+ [self.controller setQueueInfo:status progress:0 hidden:NO];
+ }
+ completationHandler:^(BOOL success) {
+ if (success)
+ {
+ [self doEncodeQueueItem];
+ }
+ else
+ {
+ [self.jobs beginTransaction];
+
+ self.currentJob.state = HBJobStateCanceled;
+ [self encodeCompleted];
+
+ [self.jobs commit];
+ [self reloadQueue];
+ }
+
+ [self.window.toolbar validateVisibleItems];
+ }];
}
-#pragma mark Toolbar
+/**
+ * This assumes that we have re-scanned and loaded up a new queue item to send to libhb
+ */
+- (void)doEncodeQueueItem
+{
+ // Reset the title in the job.
+ self.currentJob.title = self.core.titles[0];
+
+ // We should be all setup so let 'er rip
+ [self.core encodeJob:self.currentJob
+ progressHandler:^(HBState state, hb_state_t hb_state) {
+ NSMutableString *string = nil;
+ CGFloat progress = 0;
+ switch (state)
+ {
+ case HBStateSearching:
+ {
+ #define p hb_state.param.working
+ string = [NSMutableString stringWithFormat:
+ NSLocalizedString(@"Searching for start point… : %.2f %%", @""),
+ 100.0 * p.progress];
+
+ if (p.seconds > -1)
+ {
+ [string appendFormat:NSLocalizedString(@" (ETA %02dh%02dm%02ds)", @"" ), p.hours, p.minutes, p.seconds];
+ }
+ #undef p
+
+ break;
+ }
+ case HBStateWorking:
+ {
+ #define p hb_state.param.working
+ NSString *pass_desc = @"";
+ if (p.job_cur == 1 && p.job_count > 1)
+ {
+ if ([self.currentJob.subtitles.tracks.firstObject[keySubTrackIndex] intValue] == -1)
+ {
+ pass_desc = NSLocalizedString(@"(subtitle scan)", @"");
+ }
+ }
+
+ if (pass_desc.length)
+ {
+ string = [NSMutableString stringWithFormat:
+ NSLocalizedString(@"Encoding: %@ \nPass %d %@ of %d, %.2f %%", @""),
+ self.currentJob.destURL.lastPathComponent,
+ p.job_cur, pass_desc, p.job_count, 100.0 * p.progress];
+ }
+ else
+ {
+ string = [NSMutableString stringWithFormat:
+ NSLocalizedString(@"Encoding: %@ \nPass %d of %d, %.2f %%", @""),
+ self.currentJob.destURL.lastPathComponent,
+ p.job_cur, p.job_count, 100.0 * p.progress];
+ }
+
+ if (p.seconds > -1)
+ {
+ if (p.rate_cur > 0.0)
+ {
+ [string appendFormat:
+ NSLocalizedString(@" (%.2f fps, avg %.2f fps, ETA %02dh%02dm%02ds)", @""),
+ p.rate_cur, p.rate_avg, p.hours, p.minutes, p.seconds];
+ }
+ else
+ {
+ [string appendFormat:
+ NSLocalizedString(@" (ETA %02dh%02dm%02ds)", @""),
+ p.hours, p.minutes, p.seconds];
+ }
+ }
+
+ progress = (p.progress + p.job_cur - 1) / p.job_count;
+
+ // 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 (~)
+
+ 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 = @"~";
+
+ [self.dockTile updateDockIcon:progress withETA:etaStr];
+
+ self.dockIconProgress += dockTileUpdateFrequency;
+ }
+ #undef p
+
+ break;
+ }
+ case HBStateMuxing:
+ {
+ string = [NSMutableString stringWithString:NSLocalizedString(@"Muxing…", @"")];
+
+ // Update dock icon
+ [self.dockTile updateDockIcon:1.0 withETA:@""];
+
+ break;
+ }
+ case HBStatePaused:
+ {
+ string = [NSMutableString stringWithString:NSLocalizedString(@"Paused", @"")];
+ break;
+ }
+ default:
+ break;
+ }
+
+ // Update text field
+ self.progressTextField.stringValue = string;
+ [self.controller setQueueInfo:string progress:progress * 100.0 hidden:NO];
+ }
+ completationHandler:^(BOOL success) {
+ NSString *info = NSLocalizedString(@"Encode Finished.", @"");
+
+ self.progressTextField.stringValue = info;
+ [self.controller setQueueInfo:info progress:100.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];
+ }];
+
+ // We are done using the title, remove it from the job
+ self.currentJob.title = nil;
+}
+
+/**
+ * Cancels and deletes the current job and starts processing the next in queue.
+ */
+- (void)doCancelCurrentJob
+{
+ [self.jobs beginTransaction];
+
+ self.currentJob.state = HBJobStateCanceled;
+ [self.core cancelEncode];
+
+ [self.jobs commit];
+ [self reloadQueue];
+}
-//------------------------------------------------------------------------------------
-// validateToolbarItem:
-//------------------------------------------------------------------------------------
-- (BOOL) validateToolbarItem: (NSToolbarItem *) toolbarItem
+/**
+ * Cancels and deletes the current job and stops libhb from processing the remaining encodes.
+ */
+- (void)doCancelCurrentJobAndStop
{
- // Optional method: This message is sent to us since we are the target of some
- // toolbar item actions.
+ [self.jobs beginTransaction];
- if (!self.queueCore) return NO;
+ self.currentJob.state = HBJobStateCanceled;
- BOOL enable = NO;
- HBState s = self.queueCore.state;
+ [self.core cancelEncode];
- if ([[toolbarItem itemIdentifier] isEqualToString:@"HBQueueStartCancelToolbarIdentifier"])
- {
- if ((s == HBStatePaused) || (s == HBStateWorking) || (s == HBStateMuxing))
- {
- enable = YES;
- [toolbarItem setImage:[NSImage imageNamed: @"stopencode"]];
- [toolbarItem setLabel: @"Stop"];
- [toolbarItem setToolTip: @"Stop Encoding"];
- }
+ [self.jobs commit];
+ [self reloadQueue];
+}
- else if (fPendingCount > 0)
- {
- enable = YES;
- [toolbarItem setImage:[NSImage imageNamed: @"encode"]];
- [toolbarItem setLabel: @"Start"];
- [toolbarItem setToolTip: @"Start Encoding"];
- }
+#pragma mark - Encode Done Actions
- else
+#define SERVICE_NAME @"Encode Done"
+
+/**
+ * Register a test notification and make
+ * it enabled by default
+ */
+- (NSDictionary *)registrationDictionaryForGrowl
+{
+ return @{GROWL_NOTIFICATIONS_ALL: @[SERVICE_NAME],
+ GROWL_NOTIFICATIONS_DEFAULT: @[SERVICE_NAME]};
+}
+
+- (void)showGrowlDoneNotification:(NSURL *)fileURL
+{
+ // This end of encode action is called as each encode rolls off of the queue
+ // Setup the Growl stuff
+ NSString *growlMssg = [NSString stringWithFormat:@"your HandBrake encode %@ is done!", fileURL.lastPathComponent];
+ [GrowlApplicationBridge notifyWithTitle:@"Put down that cocktail…"
+ description:growlMssg
+ notificationName:SERVICE_NAME
+ iconData:nil
+ priority:0
+ isSticky:1
+ clickContext:nil];
+}
+
+- (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)
+ {
+ NSString *sendToApp = [[NSUserDefaults standardUserDefaults] objectForKey:@"SendCompletedEncodeToApp"];
+ if (![sendToApp isEqualToString:@"None"])
{
- enable = NO;
- [toolbarItem setImage:[NSImage imageNamed: @"encode"]];
- [toolbarItem setLabel: @"Start"];
- [toolbarItem setToolTip: @"Start Encoding"];
+ [HBUtilities writeToActivityLog: "trying to send encode to: %s", [sendToApp UTF8String]];
+ NSAppleScript *myScript = [[NSAppleScript alloc] initWithSource: [NSString stringWithFormat: @"%@%@%@%@%@", @"tell application \"",sendToApp,@"\" to open (POSIX file \"", fileURL.path, @"\")"]];
+ [myScript executeAndReturnError: nil];
+ [myScript release];
}
}
+}
- if ([[toolbarItem itemIdentifier] isEqualToString:@"HBQueuePauseResumeToolbarIdentifier"])
+- (void)queueCompletedAlerts
+{
+ // If Play System Alert has been selected in Preferences
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:@"AlertWhenDoneSound"] == YES)
{
- if (s == HBStatePaused)
- {
- enable = YES;
- [toolbarItem setImage:[NSImage imageNamed: @"encode"]];
- [toolbarItem setLabel: @"Resume"];
- [toolbarItem setToolTip: @"Resume Encoding"];
- }
+ NSBeep();
+ }
- else if ((s == HBStateWorking) || (s == HBStateMuxing))
- {
- enable = YES;
- [toolbarItem setImage:[NSImage imageNamed: @"pauseencode"]];
- [toolbarItem setLabel: @"Pause"];
- [toolbarItem setToolTip: @"Pause Encoding"];
- }
- else
- {
- enable = NO;
- [toolbarItem setImage:[NSImage imageNamed: @"pauseencode"]];
- [toolbarItem setLabel: @"Pause"];
- [toolbarItem setToolTip: @"Pause Encoding"];
- }
+ // If Alert Window or Window and Growl has been selected
+ if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window"] ||
+ [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Alert Window And Growl"])
+ {
+ // On Screen Notification
+ NSAlert *alert = [[NSAlert alloc] init];
+ [alert setMessageText:NSLocalizedString(@"Put down that cocktail…", @"")];
+ [alert setInformativeText:NSLocalizedString(@"Your HandBrake queue is done!", @"")];
+ [NSApp requestUserAttention:NSCriticalRequest];
+ [alert runModal];
+ [alert release];
}
- return enable;
+ // If sleep has been selected
+ if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Put Computer To Sleep"])
+ {
+ // Sleep
+ NSDictionary *errorDict;
+ NSAppleScript *scriptObject = [[NSAppleScript alloc] initWithSource:
+ @"tell application \"Finder\" to sleep"];
+ [scriptObject executeAndReturnError: &errorDict];
+ [scriptObject release];
+ }
+ // If Shutdown has been selected
+ if( [[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString: @"Shut Down Computer"] )
+ {
+ // Shut Down
+ NSDictionary *errorDict;
+ NSAppleScript *scriptObject = [[NSAppleScript alloc] initWithSource:@"tell application \"Finder\" to shut down"];
+ [scriptObject executeAndReturnError: &errorDict];
+ [scriptObject release];
+ }
}
-#pragma mark -
-
-
-#pragma mark Queue Item Controls
+#pragma mark - Queue Item Controls
- (void)HB_deleteSelectionFromTableView:(NSTableView *)tableView
{
[self removeSelectedQueueItem:tableView];
}
-//------------------------------------------------------------------------------------
-// Delete encodes from the queue window and accompanying array
-// Also handling first cancelling the encode if in fact its currently encoding.
-//------------------------------------------------------------------------------------
-- (IBAction)removeSelectedQueueItem: (id)sender
+/**
+ * Delete encodes from the queue window and accompanying array
+ * Also handling first cancelling the encode if in fact its currently encoding.
+ */
+- (IBAction)removeSelectedQueueItem:(id)sender
{
- NSIndexSet *targetedRow = [fOutlineView targetedRowIndexes];
+ NSIndexSet *targetedRow = [self.outlineView targetedRowIndexes];
NSUInteger row = [targetedRow firstIndex];
if (row == NSNotFound)
+ {
return;
- /* 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 */
-
- if ([fJobGroups[row] state] == HBJobStateWorking)
+ }
+
+ // 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
+ if (self.jobs[row] == self.currentJob)
{
- /* We pause the encode here so that it doesn't finish right after and then
- * screw up the sync while the window is open
- */
- [fHBController Pause:NULL];
- NSString *alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Stop This Encode and Remove It ?", nil)];
+ // We pause the encode here so that it doesn't finish right after and then
+ // screw up the sync while the window is open
+ [self togglePauseResume:nil];
+
+ NSString *alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Stop This Encode and Remove It?", nil)];
+
// Which window to attach the sheet to?
- NSWindow *docWindow = nil;
+ NSWindow *targetWindow = nil;
if ([sender respondsToSelector: @selector(window)])
{
- docWindow = [sender window];
+ targetWindow = [sender window];
}
NSAlert *alert = [[NSAlert alloc] init];
@@ -371,56 +809,55 @@
[alert addButtonWithTitle:NSLocalizedString(@"Stop Encoding and Delete", nil)];
[alert setAlertStyle:NSCriticalAlertStyle];
- [alert beginSheetModalForWindow:docWindow
+ [alert beginSheetModalForWindow:targetWindow
modalDelegate:self
didEndSelector:@selector(didDimissCancelCurrentJob:returnCode:contextInfo:)
- contextInfo:nil];
+ contextInfo:self.jobs[row]];
[alert release];
}
- else
- {
+ else if ([self.jobs[row] state] != HBJobStateWorking)
+ {
// since we are not a currently encoding item, we can just be removed
- [fHBController removeQueueFileItem:row];
+ [self removeQueueItemAtIndex:row];
}
}
-- (void) didDimissCancelCurrentJob: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
+- (void)didDimissCancelCurrentJob:(NSAlert *)alert
+ returnCode:(NSInteger)returnCode
+ contextInfo:(void *)contextInfo
{
- /* We resume encoding and perform the appropriate actions
- * Note: Pause: is a toggle type method based on hb's current
- * state, if it paused, it will resume encoding and vice versa.
- * In this case, we are paused from the calling window, so calling
- * [fHBController Pause:NULL]; Again will resume encoding
- */
- [fHBController Pause:NULL];
+ // We resume encoding and perform the appropriate actions
+ // Note: Pause: is a toggle type method based on hb's current
+ // state, if it paused, it will resume encoding and vice versa.
+ // In this case, we are paused from the calling window, so calling
+ // [self togglePauseResume:nil]; Again will resume encoding
+ [self togglePauseResume:nil];
+
if (returnCode == NSAlertSecondButtonReturn)
{
- /* We need to save the currently encoding item number first */
- int encodingItemToRemove = fEncodingQueueItem;
- /* Since we are encoding, we need to let fHBController Cancel this job
- * upon which it will move to the next one if there is one
- */
- [fHBController doCancelCurrentJob];
- /* Now, we can go ahead and remove the job we just cancelled since
- * we have its item number from above
- */
- [fHBController removeQueueFileItem:encodingItemToRemove];
+ // We need to save the currently encoding item number first
+ NSInteger index = [self.jobs indexOfObject:self.currentJob];
+ // Since we are encoding, we need to let fHBController Cancel this job
+ // upon which it will move to the next one if there is one
+ [self doCancelCurrentJob];
+ // Now, we can go ahead and remove the job we just cancelled since
+ // we have its item number from above
+ [self removeQueueItemAtIndex:index];
}
-
}
-//------------------------------------------------------------------------------------
-// Show the finished encode in the finder
-//------------------------------------------------------------------------------------
+/**
+ * Show the finished encode in the finder
+ */
- (IBAction)revealSelectedQueueItem: (id)sender
{
- NSIndexSet *targetedRow = [fOutlineView targetedRowIndexes];
+ NSIndexSet *targetedRow = [self.outlineView targetedRowIndexes];
NSInteger row = [targetedRow firstIndex];
if (row != NSNotFound)
{
while (row != NSNotFound)
{
- HBJob *queueItemToOpen = [fOutlineView itemAtRow:row];
+ HBJob *queueItemToOpen = [self.outlineView itemAtRow:row];
[[NSWorkspace sharedWorkspace] selectFile:queueItemToOpen.destURL.path inFileViewerRootedAtPath:nil];
row = [targetedRow indexGreaterThanIndex: row];
@@ -428,65 +865,177 @@
}
}
-//------------------------------------------------------------------------------------
-// Starts or cancels the processing of jobs depending on the current state
-//------------------------------------------------------------------------------------
-- (IBAction)toggleStartCancel: (id)sender
+- (void)remindUserOfSleepOrShutdown
{
- if (!self.queueCore) return;
+ if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString:@"Put Computer To Sleep"])
+ {
+ // Warn that computer will sleep after encoding
+ NSBeep();
+ [NSApp requestUserAttention:NSCriticalRequest];
- HBState s = self.queueCore.state;
- if ((s == HBStatePaused) || (s == HBStateWorking) || (s == HBStateMuxing))
+ NSAlert *alert = [[NSAlert alloc] init];
+ [alert setMessageText:NSLocalizedString(@"The computer will sleep after encoding is done.", @"")];
+ [alert setInformativeText:NSLocalizedString(@"You have selected to sleep the computer after encoding. To turn off sleeping, go to the HandBrake preferences.", @"")];
+ [alert addButtonWithTitle:NSLocalizedString(@"OK", @"")];
+ [alert addButtonWithTitle:NSLocalizedString(@"Preferences…",@"")];
+
+ NSInteger response = [alert runModal];
+ if (response == NSAlertSecondButtonReturn)
+ {
+ [self.controller showPreferencesWindow:nil];
+ }
+ [alert release];
+ }
+ else if ([[[NSUserDefaults standardUserDefaults] stringForKey:@"AlertWhenDone"] isEqualToString:@"Shut Down Computer"])
{
- [fHBController Cancel: self];
+ // Warn that computer will shut down after encoding
+ NSBeep();
+ [NSApp requestUserAttention:NSCriticalRequest];
+
+ NSAlert *alert = [[NSAlert alloc] init];
+ [alert setMessageText:NSLocalizedString(@"The computer will shut down after encoding is done.", @"")];
+ [alert setInformativeText:NSLocalizedString(@"You have selected to shut down the computer after encoding. To turn off shut down, go to the HandBrake preferences.", @"")];
+ [alert addButtonWithTitle:NSLocalizedString(@"OK", @"")];
+ [alert addButtonWithTitle:NSLocalizedString(@"Preferences…", @"")];
+
+ NSInteger response = [alert runModal];
+ if (response == NSAlertSecondButtonReturn)
+ {
+ [self.controller showPreferencesWindow:nil];
+ }
+ [alert release];
}
- else if (fPendingCount > 0)
+}
+
+/**
+ * Rip: puts up an alert before ultimately calling doRip
+ */
+- (IBAction)rip:(id)sender
+{
+ // Rip or Cancel ?
+ if (self.core.state == HBStateWorking || self.core.state == HBStatePaused)
{
- [fHBController Rip: NULL];
+ [self cancel:sender];
}
+ // If there are pending jobs in the queue, then this is a rip the queue
+ else if (self.pendingItemsCount > 0)
+ {
+ // We check to see if we need to warn the user that the computer will go to sleep
+ // or shut down when encoding is finished
+ [self remindUserOfSleepOrShutdown];
+
+ [self.jobs beginTransaction];
+
+ [self encodeNextQueueItem];
+
+ [self.jobs commit];
+ [self reloadQueue];
+ }
+}
+
+/**
+ * Displays an alert asking user if the want to cancel encoding of current job.
+ * Cancel: returns immediately after posting the alert. Later, when the user
+ * acknowledges the alert, doCancelCurrentJob is called.
+ */
+- (IBAction)cancel:(id)sender
+{
+ [self.core pause];
+
+ // Which window to attach the sheet to?
+ NSWindow *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)];
+ [alert setInformativeText:NSLocalizedString(@"Your encode will be cancelled if you don't continue encoding.", nil)];
+ [alert addButtonWithTitle:NSLocalizedString(@"Continue Encoding", nil)];
+ [alert addButtonWithTitle:NSLocalizedString(@"Cancel Current and Stop", nil)];
+ [alert addButtonWithTitle:NSLocalizedString(@"Cancel Current and Continue", nil)];
+ [alert setAlertStyle:NSCriticalAlertStyle];
+
+ [alert beginSheetModalForWindow:window
+ modalDelegate:self
+ didEndSelector:@selector(didDimissCancel:returnCode:contextInfo:)
+ contextInfo:nil];
+ [alert release];
}
-//------------------------------------------------------------------------------------
-// Toggles the pause/resume state of libhb
-//------------------------------------------------------------------------------------
-- (IBAction)togglePauseResume: (id)sender
+- (void)didDimissCancel:(NSAlert *)alert
+ returnCode:(NSInteger)returnCode
+ contextInfo:(void *)contextInfo
{
- if (!self.queueCore) return;
+ [self.core resume];
- HBState s = self.queueCore.state;
+ if (returnCode == NSAlertSecondButtonReturn)
+ {
+ [self doCancelCurrentJobAndStop]; // <- this also stops libhb
+ }
+ else if (returnCode == NSAlertThirdButtonReturn)
+ {
+ [self doCancelCurrentJob];
+ }
+}
+
+/**
+ * Starts or cancels the processing of jobs depending on the current state
+ */
+- (IBAction)toggleStartCancel:(id)sender
+{
+ HBState s = self.core.state;
+ if ((s == HBStatePaused) || (s == HBStateWorking) || (s == HBStateMuxing))
+ {
+ [self cancel:self];
+ }
+ else if (self.pendingItemsCount > 0)
+ {
+ [self rip:self];
+ }
+}
+
+/**
+ * Toggles the pause/resume state of libhb
+ */
+- (IBAction)togglePauseResume:(id)sender
+{
+ HBState s = self.core.state;
if (s == HBStatePaused)
{
- [self.queueCore resume];
- [self startAnimatingCurrentWorkingEncodeInQueue];
+ [self.core resume];
}
- else if ((s == HBStateWorking) || (s == HBStateMuxing))
+ else if (s == HBStateWorking || s == HBStateMuxing)
{
- [self.queueCore pause];
- [self stopAnimatingCurrentJobGroupInQueue];
+ [self.core pause];
}
}
-//------------------------------------------------------------------------------------
-// Send the selected queue item back to the main window for rescan and possible edit.
-//------------------------------------------------------------------------------------
-- (IBAction)editSelectedQueueItem: (id)sender
+/**
+ * Send the selected queue item back to the main window for rescan and possible edit.
+ */
+- (IBAction)editSelectedQueueItem:(id)sender
{
- NSInteger row = [fOutlineView clickedRow];
+ NSInteger row = [self.outlineView clickedRow];
if (row == NSNotFound)
{
return;
}
- /* 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 */
-
- HBJob *job = fJobGroups[row];
+ // 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
+ HBJob *job = self.jobs[row];
if (job.state == HBJobStateWorking)
{
// We pause the encode here so that it doesn't finish right after and then
// screw up the sync while the window is open
- [fHBController Pause:NULL];
+ [self togglePauseResume:nil];
NSString *alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Stop This Encode and Remove It ?", nil)];
// Which window to attach the sheet to?
NSWindow *docWindow = nil;
@@ -505,115 +1054,29 @@
[alert beginSheetModalForWindow:docWindow
modalDelegate:self
didEndSelector:@selector(didDimissCancelCurrentJob:returnCode:contextInfo:)
- contextInfo:nil];
+ contextInfo:job];
[alert release];
}
else
{
- /* since we are not a currently encoding item, we can just be cancelled */
- [fHBController rescanQueueItemToMainWindow:row];
- }
-}
-
-
-#pragma mark -
-#pragma mark Animate Encoding Item
-
-//------------------------------------------------------------------------------------
-// Starts animating the job icon of the currently processing job in the queue outline
-// view.
-//------------------------------------------------------------------------------------
-- (void) startAnimatingCurrentWorkingEncodeInQueue
-{
- if (!fAnimationTimer)
- fAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0/12.0 // 1/12 because there are 6 images in the animation cycle
- target:self
- selector:@selector(animateWorkingEncodeInQueue:)
- userInfo:nil
- repeats:YES] retain];
-}
-
-//------------------------------------------------------------------------------------
-// If a job is currently processing, its job icon in the queue outline view is
-// animated to its next state.
-//------------------------------------------------------------------------------------
-- (void) animateWorkingEncodeInQueue:(NSTimer*)theTimer
-{
- if (fWorkingCount > 0)
- {
- fAnimationIndex++;
- fAnimationIndex %= 6; // there are 6 animation images; see outlineView:objectValueForTableColumn:byItem: below.
- [self animateWorkingEncodeIconInQueue];
- }
-}
+ // since we are not a currently encoding item, we can just be cancelled
+ HBJob *item = [[[self.jobs[row] representedObject] copy] autorelease];
+ [self.controller rescanJobToMainWindow:item];
-/* We need to make sure we denote only working encodes even for multiple instances */
-- (void) animateWorkingEncodeIconInQueue
-{
- NSInteger row = fEncodingQueueItem; /// need to set to fEncodingQueueItem
- NSInteger col = [fOutlineView columnWithIdentifier: @"icon"];
- if (row != -1 && col != -1)
- {
- NSRect frame = [fOutlineView frameOfCellAtColumn:col row:row];
- [fOutlineView setNeedsDisplayInRect: frame];
+ // Now that source is loaded and settings applied, delete the queue item from the queue
+ [self removeQueueItemAtIndex:row];
}
}
-//------------------------------------------------------------------------------------
-// Stops animating the job icon of the currently processing job in the queue outline
-// view.
-//------------------------------------------------------------------------------------
-- (void) stopAnimatingCurrentJobGroupInQueue
-{
- if (fAnimationTimer && [fAnimationTimer isValid])
- {
- [fAnimationTimer invalidate];
- [fAnimationTimer release];
- fAnimationTimer = nil;
- }
-}
-
-
-#pragma mark -
-
-- (void)moveObjectsInArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex
-{
- NSUInteger index = [indexSet lastIndex];
- NSUInteger aboveInsertIndexCount = 0;
-
- while (index != NSNotFound)
- {
- NSUInteger removeIndex;
-
- if (index >= insertIndex)
- {
- removeIndex = index + aboveInsertIndexCount;
- aboveInsertIndexCount++;
- }
- else
- {
- removeIndex = index;
- insertIndex--;
- }
-
- id object = [array[removeIndex] retain];
- [array removeObjectAtIndex:removeIndex];
- [array insertObject:object atIndex:insertIndex];
- [object release];
-
- index = [indexSet indexLessThanIndex:index];
- }
-}
-
-
#pragma mark -
#pragma mark NSOutlineView delegate
-
- (id)outlineView:(NSOutlineView *)fOutlineView child:(NSInteger)index ofItem:(id)item
{
if (item == nil)
- return fJobGroups[index];
+ {
+ return self.jobs[index];
+ }
// We are only one level deep, so we can't be asked about children
NSAssert (NO, @"HBQueueController outlineView:child:ofItem: can't handle nested items.");
@@ -639,23 +1102,27 @@
// Our outline view has no levels, so number of children will be zero for all
// top-level items.
if (item == nil)
- return [fJobGroups count];
+ {
+ return [self.jobs count];
+ }
else
+ {
return 0;
+ }
}
- (void)outlineViewItemDidCollapse:(NSNotification *)notification
{
id item = [notification userInfo][@"NSObject"];
- NSInteger row = [fOutlineView rowForItem:item];
- [fOutlineView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row,1)]];
+ NSInteger row = [self.outlineView rowForItem:item];
+ [self.outlineView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row,1)]];
}
- (void)outlineViewItemDidExpand:(NSNotification *)notification
{
id item = [notification userInfo][@"NSObject"];
- NSInteger row = [fOutlineView rowForItem:item];
- [fOutlineView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row,1)]];
+ NSInteger row = [self.outlineView rowForItem:item];
+ [self.outlineView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row,1)]];
}
- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
@@ -685,403 +1152,24 @@
}
}
-- (void)initStyles
-{
- // Attributes
- ps = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
- [ps setHeadIndent: 40.0];
- [ps setParagraphSpacing: 1.0];
- [ps setTabStops:@[]]; // clear all tabs
- [ps addTabStop: [[[NSTextTab alloc] initWithType: NSLeftTabStopType location: 20.0] autorelease]];
-
- detailAttr = [@{NSFontAttributeName: [NSFont systemFontOfSize:10.0],
- NSParagraphStyleAttributeName: ps} retain];
-
- detailBoldAttr = [@{NSFontAttributeName: [NSFont boldSystemFontOfSize:10.0],
- NSParagraphStyleAttributeName: ps} retain];
-
- titleAttr = [@{NSFontAttributeName: [NSFont systemFontOfSize:[NSFont systemFontSize]],
- NSParagraphStyleAttributeName: ps} retain];
-
- shortHeightAttr = [@{NSFontAttributeName: [NSFont systemFontOfSize:2.0]} retain];
-}
-
- (id)outlineView:(NSOutlineView *)fOutlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
- if ([[tableColumn identifier] isEqualToString:@"desc"])
+ if ([tableColumn.identifier isEqualToString:@"desc"])
{
HBJob *job = item;
- if ([descriptions objectForKey:@(job.hash)])
- {
- return [descriptions objectForKey:@(job.hash)];
- }
-
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
- /* Below should be put into a separate method but I am way too f'ing lazy right now */
- NSMutableAttributedString *finalString = [[NSMutableAttributedString alloc] initWithString: @""];
-
- /* First line, we should strip the destination path and just show the file name and add the title num and chapters (if any) */
- NSString *summaryInfo;
-
- NSString *titleString = [NSString stringWithFormat:@"Title %d", job.titleIdx];
-
- NSString *startStopString = @"";
- if (job.range.type == HBRangeTypeChapters)
- {
- // Start Stop is chapters
- startStopString = (job.range.chapterStart == job.range.chapterStop) ?
- [NSString stringWithFormat:@"Chapter %d", job.range.chapterStart] :
- [NSString stringWithFormat:@"Chapters %d through %d", job.range.chapterStart, job.range.chapterStop];
- }
- else if (job.range.type == HBRangeTypeSeconds)
+ if (self.descriptions[@(job.hash)])
{
- // Start Stop is seconds
- startStopString = [NSString stringWithFormat:@"Seconds %d through %d", job.range.secondsStart, job.range.secondsStop];
- }
- else if (job.range.type == HBRangeTypeFrames)
- {
- // Start Stop is Frames
- startStopString = [NSString stringWithFormat:@"Frames %d through %d", job.range.frameStart, job.range.frameStop];
- }
- NSString *passesString = @"";
- // check to see if our first subtitle track is Foreign Language Search, in which case there is an in depth scan
- if (job.subtitles.tracks.count && [job.subtitles.tracks[0][@"keySubTrackIndex"] intValue] == -1)
- {
- passesString = [passesString stringByAppendingString:@"1 Foreign Language Search Pass - "];
- }
- if (job.video.qualityType == 1 || job.video.twoPass == NO)
- {
- passesString = [passesString stringByAppendingString:@"1 Video Pass"];
- }
- else
- {
- if (job.video.turboTwoPass == YES)
- {
- passesString = [passesString stringByAppendingString:@"2 Video Passes First Turbo"];
- }
- else
- {
- passesString = [passesString stringByAppendingString:@"2 Video Passes"];
- }
+ return self.descriptions[@(job.hash)];
}
- [finalString appendString:[NSString stringWithFormat:@"%@", job.fileURL.path.lastPathComponent] withAttributes:titleAttr];
+ NSAttributedString *finalString = job.attributedDescription;
+ self.descriptions[@(job.hash)] = finalString;;
- /* lets add the output file name to the title string here */
- NSString *outputFilenameString = job.destURL.lastPathComponent;
-
- summaryInfo = [NSString stringWithFormat: @" (%@, %@, %@) -> %@", titleString, startStopString, passesString, outputFilenameString];
-
- [finalString appendString:[NSString stringWithFormat:@"%@\n", summaryInfo] withAttributes:detailAttr];
-
- // Insert a short-in-height line to put some white space after the title
- [finalString appendString:@"\n" withAttributes:shortHeightAttr];
- // End of Title Stuff
-
- // Second Line (Preset Name)
- [finalString appendString: @"Preset: " withAttributes:detailBoldAttr];
- [finalString appendString:[NSString stringWithFormat:@"%@\n", job.presetName] withAttributes:detailAttr];
-
- // Third Line (Format Summary)
- NSString *audioCodecSummary = @""; // This seems to be set by the last track we have available...
- // Lets also get our audio track detail since we are going through the logic for use later
-
- NSMutableArray *audioDetails = [NSMutableArray array];
- BOOL autoPassthruPresent = NO;
-
- for (HBAudioTrack *audioTrack in job.audio.tracks)
- {
- if (audioTrack.enabled)
- {
- audioCodecSummary = [NSString stringWithFormat: @"%@", audioTrack.codec[keyAudioCodecName]];
- NSNumber *drc = audioTrack.drc;
- NSNumber *gain = audioTrack.gain;
- NSString *detailString = [NSString stringWithFormat: @"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps), DRC: %@, Gain: %@",
- audioTrack.track[keyAudioTrackName],
- audioTrack.codec[keyAudioCodecName],
- audioTrack.mixdown[keyAudioMixdownName],
- audioTrack.sampleRate[keyAudioSampleRateName],
- audioTrack.bitRate[keyAudioBitrateName],
- (0.0 < [drc floatValue]) ? (NSObject *)drc : (NSObject *)@"Off",
- (0.0 != [gain floatValue]) ? (NSObject *)gain : (NSObject *)@"Off"
- ];
- [audioDetails addObject: detailString];
- // check if we have an Auto Passthru output track
- if ([audioTrack.codec[keyAudioCodecName] isEqualToString: @"Auto Passthru"])
- {
- autoPassthruPresent = YES;
- }
- }
- }
-
- NSString *jobFormatInfo;
- if (job.chaptersEnabled)
- jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video %@ Audio, Chapter Markers\n",
- @(hb_container_get_name(job.container)), @(hb_video_encoder_get_name(job.video.encoder)), audioCodecSummary];
- else
- jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video %@ Audio\n",
- @(hb_container_get_name(job.container)), @(hb_video_encoder_get_name(job.video.encoder)), audioCodecSummary];
-
- [finalString appendString: @"Format: " withAttributes:detailBoldAttr];
- [finalString appendString: jobFormatInfo withAttributes:detailAttr];
-
- // Optional String for muxer options
- NSMutableString *containerOptions = [NSMutableString stringWithString:@""];
- if ((job.container & HB_MUX_MASK_MP4) && job.mp4HttpOptimize)
- {
- [containerOptions appendString:@" - Web optimized"];
- }
- if ((job.container & HB_MUX_MASK_MP4) && job.mp4iPodCompatible)
- {
- [containerOptions appendString:@" - iPod 5G support"];
- }
- if ([containerOptions hasPrefix:@" - "])
- {
- [containerOptions deleteCharactersInRange:NSMakeRange(0, 3)];
- }
- if (containerOptions.length)
- {
- [finalString appendString:@"Container Options: " withAttributes:detailBoldAttr];
- [finalString appendString:containerOptions withAttributes:detailAttr];
- [finalString appendString:@"\n" withAttributes:detailAttr];
- }
-
- // Fourth Line (Destination Path)
- [finalString appendString: @"Destination: " withAttributes:detailBoldAttr];
- [finalString appendString: job.destURL.path withAttributes:detailAttr];
- [finalString appendString:@"\n" withAttributes:detailAttr];
-
-
- // Fifth Line Picture Details
- NSString *pictureInfo = [NSString stringWithFormat:@"%@", job.picture.summary];
- if (job.picture.keepDisplayAspect)
- {
- pictureInfo = [pictureInfo stringByAppendingString:@" Keep Aspect Ratio"];
- }
- [finalString appendString:@"Picture: " withAttributes:detailBoldAttr];
- [finalString appendString:pictureInfo withAttributes:detailAttr];
- [finalString appendString:@"\n" withAttributes:detailAttr];
-
- /* Optional String for Picture Filters */
- if (job.filters.summary.length)
- {
- NSString *pictureFilters = [NSString stringWithFormat:@"%@", job.filters.summary];
- [finalString appendString:@"Filters: " withAttributes:detailBoldAttr];
- [finalString appendString:pictureFilters withAttributes:detailAttr];
- [finalString appendString:@"\n" withAttributes:detailAttr];
- }
-
- // Sixth Line Video Details
- NSString * videoInfo = [NSString stringWithFormat:@"Encoder: %@", @(hb_video_encoder_get_name(job.video.encoder))];
-
- // for framerate look to see if we are using vfr detelecine
- if (job.video.frameRate == 0)
- {
- if (job.video.frameRateMode == 0)
- {
- // we are using same as source with vfr detelecine
- videoInfo = [NSString stringWithFormat:@"%@ Framerate: Same as source (Variable Frame Rate)", videoInfo];
- }
- else
- {
- // we are using a variable framerate without dropping frames
- videoInfo = [NSString stringWithFormat:@"%@ Framerate: Same as source (Constant Frame Rate)", videoInfo];
- }
- }
- else
- {
- // we have a specified, constant framerate
- if (job.video.frameRateMode == 0)
- {
- videoInfo = [NSString stringWithFormat:@"%@ Framerate: %@ (Peak Frame Rate)", videoInfo, @(hb_video_framerate_get_name(job.video.frameRate))];
- }
- else
- {
- videoInfo = [NSString stringWithFormat:@"%@ Framerate: %@ (Constant Frame Rate)", videoInfo, @(hb_video_framerate_get_name(job.video.frameRate))];
- }
- }
-
-
- if (job.video.qualityType == 0) // ABR
- {
- videoInfo = [NSString stringWithFormat:@"%@ Bitrate: %d(kbps)", videoInfo, job.video.avgBitrate];
- }
- else // CRF
- {
- videoInfo = [NSString stringWithFormat:@"%@ Constant Quality: %.2f", videoInfo ,job.video.quality];
- }
-
- [finalString appendString: @"Video: " withAttributes:detailBoldAttr];
- [finalString appendString: videoInfo withAttributes:detailAttr];
- [finalString appendString:@"\n" withAttributes:detailAttr];
-
-
- if (job.video.encoder == HB_VCODEC_X264 || job.video.encoder == HB_VCODEC_X265)
- {
- // we are using x264/x265
- NSString *encoderPresetInfo = @"";
- if (job.video.advancedOptions)
- {
- // we are using the old advanced panel
- if (job.video.videoOptionExtra.length)
- {
- encoderPresetInfo = [encoderPresetInfo stringByAppendingString:job.video.videoOptionExtra];
- }
- else
- {
- encoderPresetInfo = [encoderPresetInfo stringByAppendingString:@"default settings"];
- }
- }
- else
- {
- // we are using the x264 system
- encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@"Preset: %@", job.video.preset]];
- if (job.video.tune.length)
- {
- encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Tune: %@", job.video.tune]];
- }
- if (job.video.videoOptionExtra.length)
- {
- encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Options: %@", job.video.videoOptionExtra]];
- }
- if (job.video.profile.length)
- {
- encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Profile: %@", job.video.profile]];
- }
- if (job.video.level.length)
- {
- encoderPresetInfo = [encoderPresetInfo stringByAppendingString: [NSString stringWithFormat:@" - Level: %@", job.video.level]];
- }
- }
- [finalString appendString: @"Encoder Options: " withAttributes:detailBoldAttr];
- [finalString appendString: encoderPresetInfo withAttributes:detailAttr];
- [finalString appendString:@"\n" withAttributes:detailAttr];
- }
- else
- {
- // we are using libavcodec
- NSString *lavcInfo = @"";
- if (job.video.videoOptionExtra.length)
- {
- lavcInfo = [lavcInfo stringByAppendingString:job.video.videoOptionExtra];
- }
- else
- {
- lavcInfo = [lavcInfo stringByAppendingString: @"default settings"];
- }
- [finalString appendString: @"Encoder Options: " withAttributes:detailBoldAttr];
- [finalString appendString: lavcInfo withAttributes:detailAttr];
- [finalString appendString:@"\n" withAttributes:detailAttr];
- }
-
-
- // Seventh Line Audio Details
- int audioDetailCount = 0;
- for (NSString *anAudioDetail in audioDetails) {
- audioDetailCount++;
- if (anAudioDetail.length) {
- [finalString appendString: [NSString stringWithFormat: @"Audio Track %d ", audioDetailCount] withAttributes: detailBoldAttr];
- [finalString appendString: anAudioDetail withAttributes: detailAttr];
- [finalString appendString: @"\n" withAttributes: detailAttr];
- }
- }
-
- // Eigth Line Auto Passthru Details
- // only print Auto Passthru settings if we have an Auro Passthru output track
- if (autoPassthruPresent == YES)
- {
- NSString *autoPassthruFallback = @"", *autoPassthruCodecs = @"";
- HBAudioDefaults *audioDefaults = job.audio.defaults;
- autoPassthruFallback = [autoPassthruFallback stringByAppendingString:@(hb_audio_encoder_get_name(audioDefaults.encoderFallback))];
- if (audioDefaults.allowAACPassthru)
- {
- autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@"AAC"];
- }
- if (audioDefaults.allowAC3Passthru)
- {
- if (autoPassthruCodecs.length)
- {
- autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@", "];
- }
- autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@"AC3"];
- }
- if (audioDefaults.allowDTSHDPassthru)
- {
- if (autoPassthruCodecs.length)
- {
- autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@", "];
- }
- autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@"DTS-HD"];
- }
- if (audioDefaults.allowDTSPassthru)
- {
- if (autoPassthruCodecs.length)
- {
- autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@", "];
- }
- autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@"DTS"];
- }
- if (audioDefaults.allowMP3Passthru)
- {
- if (autoPassthruCodecs.length)
- {
- autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@", "];
- }
- autoPassthruCodecs = [autoPassthruCodecs stringByAppendingString:@"MP3"];
- }
- [finalString appendString: @"Auto Passthru Codecs: " withAttributes: detailBoldAttr];
- if (autoPassthruCodecs.length)
- {
- [finalString appendString: autoPassthruCodecs withAttributes: detailAttr];
- }
- else
- {
- [finalString appendString: @"None" withAttributes: detailAttr];
- }
- [finalString appendString: @"\n" withAttributes: detailAttr];
- [finalString appendString: @"Auto Passthru Fallback: " withAttributes: detailBoldAttr];
- [finalString appendString: autoPassthruFallback withAttributes: detailAttr];
- [finalString appendString: @"\n" withAttributes: detailAttr];
- }
-
- // Ninth Line Subtitle Details
- int i = 0;
- for (NSDictionary *track in job.subtitles.tracks)
- {
- // Ignore the none track.
- if (i == job.subtitles.tracks.count - 1)
- {
- continue;
- }
-
- /* remember that index 0 of Subtitles can contain "Foreign Audio Search*/
- [finalString appendString: @"Subtitle: " withAttributes:detailBoldAttr];
- [finalString appendString: track[@"keySubTrackName"] withAttributes:detailAttr];
- if ([track[@"keySubTrackForced"] intValue] == 1)
- {
- [finalString appendString: @" - Forced Only" withAttributes:detailAttr];
- }
- if ([track[@"keySubTrackBurned"] intValue] == 1)
- {
- [finalString appendString: @" - Burned In" withAttributes:detailAttr];
- }
- if ([track[@"keySubTrackDefault"] intValue] == 1)
- {
- [finalString appendString: @" - Default" withAttributes:detailAttr];
- }
- [finalString appendString:@"\n" withAttributes:detailAttr];
- i++;
- }
-
- [pool release];
-
- [descriptions setObject:finalString forKey:@(job.hash)];
-
- return [finalString autorelease];
+ return finalString;
}
- else if ([[tableColumn identifier] isEqualToString:@"icon"])
+ else if ([tableColumn.identifier isEqualToString:@"icon"])
{
HBJob *job = item;
if (job.state == HBJobStateCompleted)
@@ -1090,7 +1178,7 @@
}
else if (job.state == HBJobStateWorking)
{
- return [NSImage imageNamed: [NSString stringWithFormat: @"EncodeWorking%d", fAnimationIndex]];
+ return [NSImage imageNamed:@"EncodeWorking0"];
}
else if (job.state == HBJobStateCanceled)
{
@@ -1106,10 +1194,13 @@
return @"";
}
}
-/* This method inserts the proper action icons into the far right of the queue window */
+
+/**
+ * This method inserts the proper action icons into the far right of the queue window
+ */
- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
- if ([[tableColumn identifier] isEqualToString:@"desc"])
+ if ([tableColumn.identifier isEqualToString:@"desc"])
{
// nb: The "desc" column is currently an HBImageAndTextCell. However, we are longer
// using the image portion of the cell so we could switch back to a regular NSTextFieldCell.
@@ -1117,7 +1208,7 @@
// Set the image here since the value returned from outlineView:objectValueForTableColumn: didn't specify the image part
[cell setImage:nil];
}
- else if ([[tableColumn identifier] isEqualToString:@"action"])
+ else if ([tableColumn.identifier isEqualToString:@"action"])
{
[cell setEnabled: YES];
BOOL highlighted = [outlineView isRowSelected:[outlineView rowForItem: item]] && [[outlineView window] isKeyWindow] && ([[outlineView window] firstResponder] == outlineView);
@@ -1152,43 +1243,40 @@
{
// By default, the disclosure image gets centered vertically in the cell. We want
// always at the top.
- if ([outlineView isItemExpanded: item])
+ if ([outlineView isItemExpanded:item])
+ {
[cell setImagePosition: NSImageAbove];
+ }
else
+ {
[cell setImagePosition: NSImageOnly];
+ }
}
#pragma mark -
#pragma mark NSOutlineView delegate (dragging related)
-//------------------------------------------------------------------------------------
-// NSTableView delegate
-//------------------------------------------------------------------------------------
-
-
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard
{
// Dragging is only allowed of the pending items.
- if ([items[0] state] != HBJobStateReady) // 2 is pending
+ if ([items[0] state] != HBJobStateReady)
{
return NO;
}
-
+
// Don't retain since this is just holding temporaral drag information, and it is
//only used during a drag! We could put this in the pboard actually.
- fDraggedNodes = items;
-
+ self.dragNodesArray = items;
+
// Provide data for our custom type, and simple NSStrings.
[pboard declareTypes:@[DragDropSimplePboardType] owner:self];
-
+
// the actual data doesn't matter since DragDropSimplePboardType drags aren't recognized by anyone but us!.
[pboard setData:[NSData data] forType:DragDropSimplePboardType];
-
+
return YES;
}
-
-/* This method is used to validate the drops. */
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
{
// Don't allow dropping ONTO an item since they can't really contain any children.
@@ -1201,20 +1289,19 @@
// Don't allow dropping INTO an item since they can't really contain any children.
if (item != nil)
{
- index = [fOutlineView rowForItem: item] + 1;
+ index = [self.outlineView rowForItem: item] + 1;
item = nil;
}
-
- // NOTE: Should we allow dropping a pending job *above* the
- // finished or already encoded jobs ?
+
// We do not let the user drop a pending job before or *above*
// already finished or currently encoding jobs.
- if (index <= fEncodingQueueItem)
+ NSInteger encodingIndex = [self.jobs indexOfObject:self.currentJob];
+ if (index <= encodingIndex)
{
return NSDragOperationNone;
- index = MAX (index, fEncodingQueueItem);
+ index = MAX (index, encodingIndex);
}
-
+
[outlineView setDropItem:item dropChildIndex:index];
return NSDragOperationGeneric;
}
@@ -1223,14 +1310,17 @@
{
NSMutableIndexSet *moveItems = [NSMutableIndexSet indexSet];
- for (id obj in fDraggedNodes)
- [moveItems addIndex:[fJobGroups indexOfObject:obj]];
+ for (id obj in self.dragNodesArray)
+ {
+ [moveItems addIndex:[self.jobs indexOfObject:obj]];
+ }
// Successful drop, we use moveObjectsInQueueArray:... in fHBController
// to properly rearrange the queue array, save it to plist and then send it back here.
// since Controller.mm is handling all queue array manipulation.
- // We *could do this here, but I think we are better served keeping that code together.
- [fHBController moveObjectsInQueueArray:fJobGroups fromIndexes:moveItems toIndex: index];
+ // We could do this here, but I think we are better served keeping that code together.
+ [self moveObjectsInQueueArray:self.jobs fromIndexes:moveItems toIndex: index];
+
return YES;
}