/* HBQueueController
This file is part of the HandBrake source code.
- Homepage: <http://handbrake.m0k.org/>.
+ Homepage: <http://handbrake.fr/>.
It may be used under the terms of the GNU General Public License. */
-#include "HBQueueController.h"
+#import "HBQueueController.h"
+#import "Controller.h"
+#import "HBImageAndTextCell.h"
-/**
- * Returns the number of jobs groups in the queue.
- * @param h Handle to hb_handle_t.
- * @return Number of job groups.
- */
-static int hb_group_count(hb_handle_t * h)
+#define HB_ROW_HEIGHT_TITLE_ONLY 17.0
+#define HB_ROW_HEIGHT_FULL_DESCRIPTION 200.0
+// Pasteboard type for or drag operations
+#define DragDropSimplePboardType @"MyCustomOutlineViewPboardType"
+
+//------------------------------------------------------------------------------------
+#pragma mark -
+//------------------------------------------------------------------------------------
+
+//------------------------------------------------------------------------------------
+// NSMutableAttributedString (HBAdditions)
+//------------------------------------------------------------------------------------
+
+@interface NSMutableAttributedString (HBAdditions)
+- (void) appendString: (NSString*)aString withAttributes: (NSDictionary *)aDictionary;
+@end
+
+@implementation NSMutableAttributedString (HBAdditions)
+- (void) appendString: (NSString*)aString withAttributes: (NSDictionary *)aDictionary
{
- hb_job_t * job;
- int count = 0;
- int index = 0;
- while( ( job = hb_job( h, index++ ) ) )
- {
- if (job->sequence_id == 0)
- count++;
- }
- return count;
+ NSAttributedString * s = [[[NSAttributedString alloc]
+ initWithString: aString
+ attributes: aDictionary] autorelease];
+ [self appendAttributedString: s];
}
+@end
-/**
- * Returns handle to the first job in the i-th group within the job list.
- * @param h Handle to hb_handle_t.
- * @param i Index of group.
- * @returns Handle to hb_job_t of desired job.
- */
-static hb_job_t * hb_group(hb_handle_t * h, int i)
+
+@implementation HBQueueOutlineView
+
+- (void)viewDidEndLiveResize
{
- hb_job_t * job;
- int count = 0;
- int index = 0;
- while( ( job = hb_job( h, index++ ) ) )
- {
- if (job->sequence_id == 0)
- {
- if (count == i)
- return job;
- count++;
- }
- }
- return NULL;
+ // Since we disabled calculating row heights during a live resize, force them to
+ // recalculate now.
+ [self noteHeightOfRowsWithIndexesChanged:
+ [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [self numberOfRows])]];
+ [super viewDidEndLiveResize];
}
-/**
- * Removes a groups of jobs from the job list.
- * @param h Handle to hb_handle_t.
- * @param job Handle to the first job in the group.
- */
-static void hb_rem_group( hb_handle_t * h, hb_job_t * job )
+
+
+/* This should be for dragging, we take this info from the presets right now */
+- (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray *)tableColumns event:(NSEvent*)dragEvent offset:(NSPointPointer)dragImageOffset
{
- // Find job in list
- hb_job_t * j;
- int index = 0;
- while( ( j = hb_job( h, index ) ) )
- {
- if (j == job)
- {
- // Delete this job plus the following ones in the sequence
- hb_rem( h, job );
- while( ( j = hb_job( h, index ) ) && (j->sequence_id != 0) )
- hb_rem( h, j );
- return;
- }
- else
- index++;
- }
+ fIsDragging = YES;
+
+ // By default, NSTableView only drags an image of the first column. Change this to
+ // drag an image of the queue's icon and desc and action columns.
+ NSArray * cols = [NSArray arrayWithObjects: [self tableColumnWithIdentifier:@"desc"], [self tableColumnWithIdentifier:@"icon"],[self tableColumnWithIdentifier:@"action"], nil];
+ return [super dragImageForRowsWithIndexes:dragRows tableColumns:cols event:dragEvent offset:dragImageOffset];
}
-/**
- * Returns handle to the next job after the given job.
- * @param h Handle to hb_handle_t.
- * @param job Handle to the a job in the group.
- * @returns Handle to hb_job_t of desired job or NULL if no such job.
- */
-static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
+
+
+- (void) mouseDown:(NSEvent *)theEvent
{
- hb_job_t * j = NULL;
- int index = 0;
- while( ( j = hb_job( h, index++ ) ) )
- {
- if (j == job)
- return hb_job( h, index+1 );
- }
- return NULL;
+ [super mouseDown:theEvent];
+ fIsDragging = NO;
}
-#pragma mark -
+
+- (BOOL) isDragging;
+{
+ return fIsDragging;
+}
+
+
+
+@end
+
+#pragma mark Toolbar Identifiers
// Toolbar identifiers
-static NSString* HBQueueToolbar = @"HBQueueToolbar";
-static NSString* HBStartPauseResumeToolbarIdentifier = @"HBStartPauseResumeToolbarIdentifier";
-static NSString* HBShowDetailToolbarIdentifier = @"HBShowDetailToolbarIdentifier";
-static NSString* HBShowGroupsToolbarIdentifier = @"HBShowGroupsToolbarIdentifier";
+static NSString* HBQueueToolbar = @"HBQueueToolbar1";
+static NSString* HBQueueStartCancelToolbarIdentifier = @"HBQueueStartCancelToolbarIdentifier";
+static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseResumeToolbarIdentifier";
+#pragma mark -
@implementation HBQueueController
//------------------------------------------------------------------------------------
- (id)init
{
- if (self = [super init])
+ if (self = [super initWithWindowNibName:@"Queue"])
{
+ // NSWindowController likes to lazily load its window nib. Since this
+ // controller tries to touch the outlets before accessing the window, we
+ // need to force it to load immadiately by invoking its accessor.
+ //
+ // If/when we switch to using bindings, this can probably go away.
+ [self window];
+
// Our defaults
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
@"NO", @"QueueWindowIsOpen",
@"YES", @"QueueShowsJobsAsGroups",
nil]];
- fShowsDetail = [[NSUserDefaults standardUserDefaults] boolForKey:@"QueueShowsDetail"];
- fShowsJobsAsGroups = [[NSUserDefaults standardUserDefaults] boolForKey:@"QueueShowsJobsAsGroups"];
+ fJobGroups = [[NSMutableArray arrayWithCapacity:0] retain];
+ }
+ return self;
+}
+- (void)setQueueArray: (NSMutableArray *)QueueFileArray
+{
+ [fJobGroups setArray:QueueFileArray];
+ fIsDragging = NO;
+ /* First stop any timer working now */
+ [self stopAnimatingCurrentJobGroupInQueue];
+ [fOutlineView reloadData];
+
+
+
+ /* lets get the stats on the status of the queue array */
+
+ fEncodingQueueItem = 0;
+ fPendingCount = 0;
+ fCompletedCount = 0;
+ fCanceledCount = 0;
+ fWorkingCount = 0;
+
+ /* We use a number system to set the encode status of the queue item
+ * in controller.mm
+ * 0 == already encoded
+ * 1 == is being encoded
+ * 2 == is yet to be encoded
+ * 3 == cancelled
+ */
+
+ int i = 0;
+ for(id tempObject in fJobGroups)
+ {
+ NSDictionary *thisQueueDict = tempObject;
+ if ([[thisQueueDict objectForKey:@"Status"] intValue] == 0) // Completed
+ {
+ fCompletedCount++;
+ }
+ if ([[thisQueueDict objectForKey:@"Status"] intValue] == 1) // being encoded
+ {
+ fWorkingCount++;
+ fEncodingQueueItem = i;
+ }
+ if ([[thisQueueDict objectForKey:@"Status"] intValue] == 2) // pending
+ {
+ fPendingCount++;
+ }
+ if ([[thisQueueDict objectForKey:@"Status"] intValue] == 3) // cancelled
+ {
+ fCanceledCount++;
+ }
+ i++;
+ }
+
+ /* We should fire up the encoding timer here based on fWorkingCount */
+
+ if (fWorkingCount > 0)
+ {
+ /* we have an encoding job so, lets start the animation timer */
+ [self startAnimatingCurrentWorkingEncodeInQueue];
+ }
+
+ /* Set the queue status field in the queue window */
+ NSMutableString * string;
+ if (fPendingCount == 1)
+ {
+ string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encode pending", @"" ), fPendingCount];
+ }
+ else
+ {
+ string = [NSMutableString stringWithFormat: NSLocalizedString( @"%d encode(s) pending", @"" ), fPendingCount];
}
- return self;
+ [fQueueCountField setStringValue:string];
+
+}
+/* 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
+{
+[fProgressTextField setStringValue:statusString];
}
//------------------------------------------------------------------------------------
//------------------------------------------------------------------------------------
- (void)dealloc
{
- [fAnimation release];
-
// clear the delegate so that windowWillClose is not attempted
- if ([fQueueWindow delegate] == self)
- [fQueueWindow setDelegate:nil];
-
+ if( [[self window] delegate] == self )
+ [[self window] setDelegate:nil];
+
+ [fJobGroups release];
+
+ [fSavedExpandedItems release];
+ [fSavedSelectedItems release];
+
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+
[super dealloc];
}
//------------------------------------------------------------------------------------
- (void)setHandle: (hb_handle_t *)handle
{
- fHandle = handle;
+ fQueueEncodeLibhb = handle;
+}
+
+//------------------------------------------------------------------------------------
+// Receive HBController
+//------------------------------------------------------------------------------------
+- (void)setHBController: (HBController *)controller
+{
+ fHBController = controller;
}
+#pragma mark -
+
//------------------------------------------------------------------------------------
// Displays and brings the queue window to the front
//------------------------------------------------------------------------------------
- (IBAction) showQueueWindow: (id)sender
{
- if (!fQueueWindow)
- {
- BOOL loadSucceeded = [NSBundle loadNibNamed:@"Queue" owner:self] && fQueueWindow;
- NSAssert(loadSucceeded, @"Could not open Queue nib file");
- }
+ [self showWindow:sender];
+ [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"QueueWindowIsOpen"];
+}
- [self updateQueueUI];
- [self updateCurrentJobUI];
- [fQueueWindow makeKeyAndOrderFront: self];
- [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"QueueWindowIsOpen"];
-}
//------------------------------------------------------------------------------------
-// Show or hide the current job pane (fCurrentJobPane).
+// awakeFromNib
//------------------------------------------------------------------------------------
-- (void) showCurrentJobPane: (BOOL)showPane
+- (void)awakeFromNib
{
- if (showPane != fCurrentJobHidden)
- return;
-
- // Things to keep in mind:
- // - When the current job pane is shown, it occupies the upper portion of the
- // window with the queue occupying the bottom portion of the window.
- // - When the current job pane is hidden, it slides up and out of view.
- // NSView setHidden is NOT used. The queue pane is resized to occupy the full
- // window.
-
- NSRect windowFrame = [[fCurrentJobPane superview] frame];
- NSRect queueFrame, jobFrame;
- if (showPane)
- NSDivideRect(windowFrame, &jobFrame, &queueFrame, NSHeight([fCurrentJobPane frame]), NSMaxYEdge);
- else
- {
- queueFrame = windowFrame;
- jobFrame = [fCurrentJobPane frame];
- jobFrame.origin.y = NSHeight(windowFrame);
- }
-
- // Move fCurrentJobPane
- NSDictionary * dict1 = [NSDictionary dictionaryWithObjectsAndKeys:
- fCurrentJobPane, NSViewAnimationTargetKey,
- [NSValue valueWithRect:jobFrame], NSViewAnimationEndFrameKey,
- nil];
+ [self setupToolbar];
- // Resize fQueuePane
- NSDictionary * dict2 = [NSDictionary dictionaryWithObjectsAndKeys:
- fQueuePane, NSViewAnimationTargetKey,
- [NSValue valueWithRect:queueFrame], NSViewAnimationEndFrameKey,
- nil];
+ if( ![[self window] setFrameUsingName:@"Queue"] )
+ [[self window] center];
+ [self setWindowFrameAutosaveName:@"Queue"];
+ [[self window] setExcludedFromWindowsMenu:YES];
+
+ /* lets setup our queue list outline view for drag and drop here */
+ [fOutlineView registerForDraggedTypes: [NSArray arrayWithObject:DragDropSimplePboardType] ];
+ [fOutlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
+ [fOutlineView setVerticalMotionCanBeginDrag: YES];
+
+
+ // Don't allow autoresizing of main column, else the "delete" column will get
+ // pushed out of view.
+ [fOutlineView setAutoresizesOutlineColumn: NO];
- if (!fAnimation)
- fAnimation = [[NSViewAnimation alloc] initWithViewAnimations:nil];
+#if HB_OUTLINE_METRIC_CONTROLS
+ [fIndentation setHidden: NO];
+ [fSpacing setHidden: NO];
+ [fIndentation setIntegerValue:[fOutlineView indentationPerLevel]]; // debug
+ [fSpacing setIntegerValue:3]; // debug
+#endif
- [fAnimation setViewAnimations:[NSArray arrayWithObjects:dict1, dict2, nil]];
- [fAnimation setDuration:0.25];
- [fAnimation setAnimationBlockingMode:NSAnimationBlocking]; // prevent user from resizing the window during an animation
- [fAnimation startAnimation];
- fCurrentJobHidden = !showPane;
+ // Show/hide UI elements
+ fCurrentJobPaneShown = NO; // it's shown in the nib
+ //[self showCurrentJobPane:NO];
+
+ //[self updateQueueCountField];
}
+
//------------------------------------------------------------------------------------
-// Enables or disables the display of detail information for each job.
+// windowWillClose
//------------------------------------------------------------------------------------
-- (void)setShowsDetail: (BOOL)showsDetail
+- (void)windowWillClose:(NSNotification *)aNotification
{
- fShowsDetail = showsDetail;
-
- [[NSUserDefaults standardUserDefaults] setBool:showsDetail forKey:@"QueueShowsDetail"];
- [[NSUserDefaults standardUserDefaults] synchronize];
-
- // clumsy - have to update UI
- [fDetailCheckbox setState:showsDetail ? NSOnState : NSOffState];
-
- [fTaskView setRowHeight:showsDetail ? 98.0 : 17.0];
- if ([fTaskView selectedRow] != -1)
- [fTaskView scrollRowToVisible:[fTaskView selectedRow]];
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"QueueWindowIsOpen"];
}
+#pragma mark Toolbar
+
//------------------------------------------------------------------------------------
-// Enables or disables the grouping of job passes into one item in the UI.
+// setupToolbar
//------------------------------------------------------------------------------------
-- (void)setShowsJobsAsGroups: (BOOL)showsGroups
+- (void)setupToolbar
{
- fShowsJobsAsGroups = showsGroups;
-
- [[NSUserDefaults standardUserDefaults] setBool:showsGroups forKey:@"QueueShowsJobsAsGroups"];
- [[NSUserDefaults standardUserDefaults] synchronize];
+ // Create a new toolbar instance, and attach it to our window
+ NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier: HBQueueToolbar] autorelease];
- // clumsy - have to update UI
- [fJobGroupsCheckbox setState:showsGroups ? NSOnState : NSOffState];
-
- [self updateQueueUI];
- if ([fTaskView selectedRow] != -1)
- [fTaskView scrollRowToVisible:[fTaskView selectedRow]];
+ // Set up toolbar properties: Allow customization, give a default display mode, and remember state in user defaults
+ [toolbar setAllowsUserCustomization: YES];
+ [toolbar setAutosavesConfiguration: YES];
+ [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
+
+ // We are the delegate
+ [toolbar setDelegate: self];
+
+ // Attach the toolbar to our window
+ [[self window] setToolbar:toolbar];
}
//------------------------------------------------------------------------------------
-// Generates a multi-line text string that includes the job name on the first line
-// followed by details of the job on subsequent lines. If the text is to be drawn as
-// part of a highlighted cell, set isHighlighted to true. The returned string may
-// contain multiple fonts and paragraph formating.
+// toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:
//------------------------------------------------------------------------------------
-- (NSAttributedString *)attributedDescriptionForJob: (hb_job_t *)job
- withDetail: (BOOL)detail
- withHighlighting: (BOOL)highlighted
+- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar
+ itemForItemIdentifier:(NSString *)itemIdentifier
+ willBeInsertedIntoToolbar:(BOOL)flag
{
- NSMutableAttributedString * finalString; // the return value
- NSAttributedString* anAttributedString; // a temp string for building up attributed substrings
- NSMutableString* aMutableString; // a temp string for non-attributed substrings
- hb_title_t * title = job->title;
-
- NSMutableParagraphStyle *ps = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
- [ps setLineBreakMode:NSLineBreakByClipping];
-
- static NSDictionary* detailAttribute = [[NSDictionary dictionaryWithObjectsAndKeys:
- [NSFont systemFontOfSize:10.0], NSFontAttributeName,
- [NSColor darkGrayColor], NSForegroundColorAttributeName,
- ps, NSParagraphStyleAttributeName,
- nil] retain];
- static NSDictionary* detailHighlightedAttribute = [[NSDictionary dictionaryWithObjectsAndKeys:
- [NSFont systemFontOfSize:10.0], NSFontAttributeName,
- [NSColor whiteColor], NSForegroundColorAttributeName,
- ps, NSParagraphStyleAttributeName,
- nil] retain];
- static NSDictionary* titleAttribute = [[NSDictionary dictionaryWithObjectsAndKeys:
- [NSFont systemFontOfSize:[NSFont systemFontSize]], NSFontAttributeName,
- ps, NSParagraphStyleAttributeName,
- nil] retain];
-
- finalString = [[[NSMutableAttributedString alloc] init] autorelease];
-
- // Title, in bold
- // Show the name of the source Note: use title->name instead of title->dvd since
- // name is just the chosen folder, instead of dvd which is the full path
- anAttributedString = [[[NSAttributedString alloc] initWithString:[NSString stringWithUTF8String:title->name] attributes:titleAttribute] autorelease];
- [finalString appendAttributedString:anAttributedString];
-
- // Other info in plain
- aMutableString = [NSMutableString stringWithCapacity:200];
-
- BOOL jobGroups = [[NSUserDefaults standardUserDefaults] boolForKey:@"QueueShowsJobsAsGroups"];
+ // Required delegate method: Given an item identifier, this method returns an item.
+ // The toolbar will use this method to obtain toolbar items that can be displayed
+ // in the customization sheet, or in the toolbar itself.
- // The subtitle scan doesn't contain all the stuff we need (like x264opts).
- // So grab the next job in the group for display purposes.
- if (jobGroups && job->pass == -1)
- {
- // When job is the one currently being processed, then the next in its group
- // is the the first job in the queue.
- hb_job_t * nextjob;
- if (job == hb_current_job(fHandle))
- nextjob = hb_job(fHandle, 0);
- else
- nextjob = hb_next_job(fHandle, job);
- if (nextjob) // Overly cautious in case there is no next job!
- job = nextjob;
- }
+ NSToolbarItem *toolbarItem = nil;
- NSString * chapterString = (job->chapter_start == job->chapter_end) ?
- [NSString stringWithFormat:@"Chapter %d", job->chapter_start] :
- [NSString stringWithFormat:@"Chapters %d through %d", job->chapter_start, job->chapter_end];
-
- // Scan pass
- if (job->pass == -1)
+ if ([itemIdentifier isEqual: HBQueueStartCancelToolbarIdentifier])
{
- [aMutableString appendString:[NSString stringWithFormat:
- @" (Title %d, %@, Subtitle Scan)", title->index, chapterString]];
- }
+ toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
- // Normal pass
- else
- {
- if (jobGroups)
- [aMutableString appendString:[NSString stringWithFormat:
- @" (Title %d, %@, %d-Pass)",
- title->index, chapterString, MIN( 2, job->pass + 1 )]];
- else
- [aMutableString appendString:[NSString stringWithFormat:
- @" (Title %d, %@, Pass %d of %d)",
- title->index, chapterString, MAX( 1, job->pass ), MIN( 2, job->pass + 1 )]];
-
- if (detail)
- {
- NSString * jobFormat;
- NSString * jobPictureDetail;
- NSString * jobVideoDetail;
- NSString * jobVideoCodec;
- NSString * jobVideoQuality;
- NSString * jobAudioDetail;
- NSString * jobAudioCodec;
-
- /* Muxer settings (File Format in the gui) */
- if (job->mux == 65536 || job->mux == 131072 || job->mux == 1048576)
- jobFormat = @"MP4"; // HB_MUX_MP4,HB_MUX_PSP,HB_MUX_IPOD
- else if (job->mux == 262144)
- jobFormat = @"AVI"; // HB_MUX_AVI
- else if (job->mux == 524288)
- jobFormat = @"OGM"; // HB_MUX_OGM
- else if (job->mux == 2097152)
- jobFormat = @"MKV"; // HB_MUX_MKV
- else
- jobFormat = @"unknown";
-
- // 2097152
- /* Video Codec settings (Encoder in the gui) */
- if (job->vcodec == 1)
- jobVideoCodec = @"FFmpeg"; // HB_VCODEC_FFMPEG
- else if (job->vcodec == 2)
- jobVideoCodec = @"XviD"; // HB_VCODEC_XVID
- else if (job->vcodec == 4)
- {
- /* Deterimine for sure how we are now setting iPod uuid atom */
- if (job->h264_level) // We are encoding for iPod
- jobVideoCodec = @"x264 (H.264 iPod)"; // HB_VCODEC_X264
- else
- jobVideoCodec = @"x264 (H.264 Main)"; // HB_VCODEC_X264
- }
- else
- jobVideoCodec = @"unknown";
-
- /* Audio Codecs (Second half of Codecs in the gui) */
- if (job->acodec == 256)
- jobAudioCodec = @"AAC"; // HB_ACODEC_FAAC
- else if (job->acodec == 512)
- jobAudioCodec = @"MP3"; // HB_ACODEC_LAME
- else if (job->acodec == 1024)
- jobAudioCodec = @"Vorbis"; // HB_ACODEC_VORBIS
- else if (job->acodec == 2048)
- jobAudioCodec = @"AC3"; // HB_ACODEC_AC3
- else
- jobAudioCodec = @"unknown";
- /* Show Basic File info */
- if (job->chapter_markers == 1)
- [aMutableString appendString:[NSString stringWithFormat:@"\nFormat: %@ Container, %@ Video + %@ Audio, Chapter Markers", jobFormat, jobVideoCodec, jobAudioCodec]];
- else
- [aMutableString appendString:[NSString stringWithFormat:@"\nFormat: %@ Container, %@ Video + %@ Audio", jobFormat, jobVideoCodec, jobAudioCodec]];
-
- /*Picture info*/
- /*integers for picture values deinterlace, crop[4], keep_ratio, grayscale, pixel_ratio, pixel_aspect_width, pixel_aspect_height,
- maxWidth, maxHeight */
- if (job->pixel_ratio == 1)
- {
- int titlewidth = title->width - job->crop[2] - job->crop[3];
- int displayparwidth = titlewidth * job->pixel_aspect_width / job->pixel_aspect_height;
- int displayparheight = title->height - job->crop[0] - job->crop[1];
- jobPictureDetail = [NSString stringWithFormat:@"Picture: %dx%d (%dx%d Anamorphic)", displayparwidth, displayparheight, job->width, displayparheight];
- }
- else
- jobPictureDetail = [NSString stringWithFormat:@"Picture: %dx%d", job->width, job->height];
- if (job->keep_ratio == 1)
- jobPictureDetail = [jobPictureDetail stringByAppendingString:@" Keep Aspect Ratio"];
-
- if (job->grayscale == 1)
- jobPictureDetail = [jobPictureDetail stringByAppendingString:@", Grayscale"];
-
- if (job->deinterlace == 1)
- jobPictureDetail = [jobPictureDetail stringByAppendingString:@", Deinterlace"];
- /* Show Picture info */
- [aMutableString appendString:[NSString stringWithFormat:@"\n%@", jobPictureDetail]];
-
- /* Detailed Video info */
- if (job->vquality <= 0 || job->vquality >= 1)
- jobVideoQuality =[NSString stringWithFormat:@"%d kbps", job->vbitrate];
- else
- {
- NSNumber * vidQuality;
- vidQuality = [NSNumber numberWithInt:job->vquality * 100];
- /* this is screwed up kind of. Needs to be formatted properly */
- if (job->crf == 1)
- jobVideoQuality =[NSString stringWithFormat:@"%@%% CRF", vidQuality];
- else
- jobVideoQuality =[NSString stringWithFormat:@"%@%% CQP", vidQuality];
- }
-
- if (job->vrate_base == 1126125)
- {
- /* NTSC FILM 23.976 */
- jobVideoDetail = [NSString stringWithFormat:@"Video: %@, %@, 23.976 fps", jobVideoCodec, jobVideoQuality];
- }
- else if (job->vrate_base == 900900)
- {
- /* NTSC 29.97 */
- jobVideoDetail = [NSString stringWithFormat:@"Video: %@, %@, 29.97 fps", jobVideoCodec, jobVideoQuality];
- }
- else
- {
- /* Everything else */
- jobVideoDetail = [NSString stringWithFormat:@"Video: %@, %@, %d fps", jobVideoCodec, jobVideoQuality, job->vrate / job->vrate_base];
- }
-
- /* Add the video detail string to the job filed in the window */
- [aMutableString appendString:[NSString stringWithFormat:@"\n%@", jobVideoDetail]];
-
- /* if there is an x264 option string, lets add it here*/
- /*NOTE: Due to size, lets get this in a tool tip*/
-
- if (job->x264opts)
- [aMutableString appendString:[NSString stringWithFormat:@"\nx264 Options: %@", [NSString stringWithUTF8String:job->x264opts]]];
-
- /* Audio Detail */
- if ([jobAudioCodec isEqualToString: @"AC3"])
- jobAudioDetail = [NSString stringWithFormat:@"Audio: %@, Pass-Through", jobAudioCodec];
- else
- jobAudioDetail = [NSString stringWithFormat:@"Audio: %@, %d kbps, %d Hz", jobAudioCodec, job->abitrate, job->arate];
-
- /* we now get the audio mixdown info for each of the two gui audio tracks */
- /* lets do it the long way here to get a handle on things.
- Hardcoded for two tracks for gui: audio_mixdowns[i] audio_mixdowns[i] */
- int ai; // counter for each audios [] , macgui only allows for two audio tracks currently
- for( ai = 0; ai < 2; ai++ )
- {
- if (job->audio_mixdowns[ai] == HB_AMIXDOWN_MONO)
- jobAudioDetail = [jobAudioDetail stringByAppendingString:[NSString stringWithFormat:@", Track %d: Mono",ai + 1]];
- if (job->audio_mixdowns[ai] == HB_AMIXDOWN_STEREO)
- jobAudioDetail = [jobAudioDetail stringByAppendingString:[NSString stringWithFormat:@", Track %d: Stereo",ai + 1]];
- if (job->audio_mixdowns[ai] == HB_AMIXDOWN_DOLBY)
- jobAudioDetail = [jobAudioDetail stringByAppendingString:[NSString stringWithFormat:@", Track %d: Dolby Surround",ai + 1]];
- if (job->audio_mixdowns[ai] == HB_AMIXDOWN_DOLBYPLII)
- jobAudioDetail = [jobAudioDetail stringByAppendingString:[NSString stringWithFormat:@", Track %d: Dolby Pro Logic II",ai + 1]];
- if (job->audio_mixdowns[ai] == HB_AMIXDOWN_6CH)
- jobAudioDetail = [jobAudioDetail stringByAppendingString:[NSString stringWithFormat:@", Track %d: 6-channel discreet",ai + 1]];
- }
-
- /* Add the Audio detail string to the job filed in the window */
- [aMutableString appendString:[NSString stringWithFormat: @"\n%@", jobAudioDetail]];
-
- /*Destination Field */
- [aMutableString appendString:[NSString stringWithFormat:@"\nDestination: %@", [NSString stringWithUTF8String:job->file]]];
- }
- }
-
- anAttributedString = [[[NSAttributedString alloc] initWithString:aMutableString attributes:highlighted ? detailHighlightedAttribute : detailAttribute] autorelease];
- [finalString appendAttributedString:anAttributedString];
+ // Set the text label to be displayed in the toolbar and customization palette
+ [toolbarItem setLabel: @"Start"];
+ [toolbarItem setPaletteLabel: @"Start/Cancel"];
-
- return finalString;
-}
+ // Set up a reasonable tooltip, and image
+ [toolbarItem setToolTip: @"Start Encoding"];
+ [toolbarItem setImage: [NSImage imageNamed: @"Play"]];
-//------------------------------------------------------------------------------------
-// Generate string to display in UI.
-//------------------------------------------------------------------------------------
-- (NSString *) progressStatusStringForJob: (hb_job_t *)job state: (hb_state_t *)s
-{
- if (s->state == HB_STATE_WORKING)
+ // Tell the item what message to send when it is clicked
+ [toolbarItem setTarget: self];
+ [toolbarItem setAction: @selector(toggleStartCancel:)];
+ }
+
+ if ([itemIdentifier isEqual: HBQueuePauseResumeToolbarIdentifier])
{
- NSString * msg;
- if (job->pass == -1)
- msg = NSLocalizedString( @"Analyzing subtitles", nil );
- else if (job->pass == 1)
- msg = NSLocalizedString( @"Analyzing video", nil );
- else if ((job->pass == 0) || (job->pass == 2))
- msg = NSLocalizedString( @"Encoding movie", nil );
- else
- return @""; // unknown condition!
-
- if( s->param.working.seconds > -1 )
- {
- return [NSString stringWithFormat:
- NSLocalizedString( @"%@ (%.2f fps, avg %.2f fps)", nil ),
- msg, s->param.working.rate_cur, s->param.working.rate_avg];
- }
- else
- return msg;
+ toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
- }
+ // Set the text label to be displayed in the toolbar and customization palette
+ [toolbarItem setLabel: @"Pause"];
+ [toolbarItem setPaletteLabel: @"Pause/Resume"];
- else if (s->state == HB_STATE_MUXING)
- return NSLocalizedString( @"Muxing", nil );
+ // Set up a reasonable tooltip, and image
+ [toolbarItem setToolTip: @"Pause Encoding"];
+ [toolbarItem setImage: [NSImage imageNamed: @"Pause"]];
- else if (s->state == HB_STATE_PAUSED)
- return NSLocalizedString( @"Paused", nil );
+ // Tell the item what message to send when it is clicked
+ [toolbarItem setTarget: self];
+ [toolbarItem setAction: @selector(togglePauseResume:)];
+ }
- else if (s->state == HB_STATE_WORKDONE)
- return NSLocalizedString( @"Done", nil );
-
- return @"";
+ return toolbarItem;
}
//------------------------------------------------------------------------------------
-// Generate string to display in UI.
+// toolbarDefaultItemIdentifiers:
//------------------------------------------------------------------------------------
-- (NSString *) progressTimeRemainingStringForJob: (hb_job_t *)job state: (hb_state_t *)s
+- (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
{
- if (s->state == HB_STATE_WORKING)
- {
- #define p s->param.working
- if (p.seconds < 0)
- return @"";
-
- // Minutes always needed
- NSString * minutes;
- if (p.minutes > 1)
- minutes = [NSString stringWithFormat:NSLocalizedString( @"%d minutes ", nil ), p.minutes];
- else if (p.minutes == 1)
- minutes = NSLocalizedString( @"1 minute ", nil );
- else
- minutes = @"";
-
- if (p.hours >= 1)
- {
- NSString * hours;
- if (p.hours > 1)
- hours = [NSString stringWithFormat:NSLocalizedString( @"%d hours ", nil ), p.hours];
- else
- hours = NSLocalizedString( @"1 hour ", nil );
-
- return [NSString stringWithFormat:NSLocalizedString( @"%@%@remaining", nil ), hours, minutes];
- }
-
- else
- {
- NSString * seconds;
- if (p.seconds > 1)
- seconds = [NSString stringWithFormat:NSLocalizedString( @"%d seconds ", nil ), p.seconds];
- else
- seconds = NSLocalizedString( @"1 second ", nil );
-
- return [NSString stringWithFormat:NSLocalizedString( @"%@%@remaining", nil ), minutes, seconds];
- }
+ // Required delegate method: Returns the ordered list of items to be shown in the
+ // toolbar by default.
-/* here is code that does it more like the Finder
- if( p.seconds > -1 )
- {
- float estHours = (p.hours + (p.minutes / 60.0));
- float estMinutes = (p.minutes + (p.seconds / 60.0));
-
- if (estHours > 1.5)
- return [NSString stringWithFormat:NSLocalizedString( @"Time remaining: About %d hours", nil ), lrintf(estHours)];
- else if (estHours > 0.983) // 59 minutes
- return NSLocalizedString( @"Time remaining: About 1 hour", nil );
- else if (estMinutes > 1.5)
- return [NSString stringWithFormat:NSLocalizedString( @"Time remaining: About %d minutes", nil ), lrintf(estMinutes)];
- else if (estMinutes > 0.983) // 59 seconds
- return NSLocalizedString( @"Time remaining: About 1 minute", nil );
- else if (p.seconds <= 5)
- return NSLocalizedString( @"Time remaining: Less than 5 seconds", nil );
- else if (p.seconds <= 10)
- return NSLocalizedString( @"Time remaining: Less than 10 seconds", nil );
- else
- return NSLocalizedString( @"Time remaining: Less than 1 minute", nil );
- }
- else
- return NSLocalizedString( @"Time remaining: Calculating...", nil );
-*/
- #undef p
- }
-
- return @"";
+ return [NSArray arrayWithObjects:
+ HBQueueStartCancelToolbarIdentifier,
+ HBQueuePauseResumeToolbarIdentifier,
+ nil];
}
//------------------------------------------------------------------------------------
-// Refresh progress bar (fProgressBar) from current state.
+// toolbarAllowedItemIdentifiers:
//------------------------------------------------------------------------------------
-- (void) updateProgressBarWithState: (hb_state_t *)s
+- (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
{
- if (s->state == HB_STATE_WORKING)
- {
- #define p s->param.working
- [fProgressBar setIndeterminate:NO];
-
- BOOL jobGroups = [[NSUserDefaults standardUserDefaults] boolForKey:@"QueueShowsJobsAsGroups"];
- float progress_total = jobGroups ?
- 100.0 * ( p.progress + p.job_cur - 1 ) / p.job_count :
- 100.0 * p.progress;
-
- [fProgressBar setDoubleValue:progress_total];
- #undef p
- }
-
- else if (s->state == HB_STATE_MUXING)
- {
- #define p s->param.muxing
- [fProgressBar setIndeterminate:YES];
- [fProgressBar startAnimation:nil];
- #undef p
- }
+ // Required delegate method: Returns the list of all allowed items by identifier.
+ // By default, the toolbar does not assume any items are allowed, even the
+ // separator. So, every allowed item must be explicitly listed.
- else if (s->state == HB_STATE_WORKDONE)
- {
- [fProgressBar setIndeterminate:NO];
- [fProgressBar setDoubleValue:0.0];
- }
+ return [NSArray arrayWithObjects:
+ HBQueueStartCancelToolbarIdentifier,
+ HBQueuePauseResumeToolbarIdentifier,
+ NSToolbarCustomizeToolbarItemIdentifier,
+ NSToolbarFlexibleSpaceItemIdentifier,
+ NSToolbarSpaceItemIdentifier,
+ NSToolbarSeparatorItemIdentifier,
+ nil];
}
//------------------------------------------------------------------------------------
-// Refresh start/pause button (fStartPauseButton) from current state.
+// validateToolbarItem:
//------------------------------------------------------------------------------------
-- (void) updateStartPauseButton
+- (BOOL) validateToolbarItem: (NSToolbarItem *) toolbarItem
{
+ // Optional method: This message is sent to us since we are the target of some
+ // toolbar item actions.
+
+ if (!fQueueEncodeLibhb) return NO;
-// ************* THIS METHOD CAN DISAPPEAR. THE BUTTON IS NOW HIDDEN AND CAN BE DELETED
- if (!fHandle) return;
+ BOOL enable = NO;
hb_state_t s;
- hb_get_state2 (fHandle, &s);
+ hb_get_state2 (fQueueEncodeLibhb, &s);
- if (s.state == HB_STATE_PAUSED)
+ if ([[toolbarItem itemIdentifier] isEqual: HBQueueStartCancelToolbarIdentifier])
{
- [fStartPauseButton setEnabled:YES];
-// [fStartPauseButton setTitle:NSLocalizedString(@"Resume", nil)];
- [fStartPauseButton setImage:[NSImage imageNamed: @"Play"]];
- }
-
- else if ((s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING))
- {
- [fStartPauseButton setEnabled:YES];
-// [fStartPauseButton setTitle:NSLocalizedString(@"Pause", nil)];
- [fStartPauseButton setImage:[NSImage imageNamed: @"Pause"]];
- }
+ if ((s.state == HB_STATE_PAUSED) || (s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING))
+ {
+ enable = YES;
+ [toolbarItem setImage:[NSImage imageNamed: @"Stop"]];
+ [toolbarItem setLabel: @"Stop"];
+ [toolbarItem setToolTip: @"Stop Encoding"];
+ }
- else if (hb_count(fHandle) > 0)
- {
- [fStartPauseButton setEnabled:YES];
-// [fStartPauseButton setTitle:NSLocalizedString(@"Start", nil)];
- [fStartPauseButton setImage:[NSImage imageNamed: @"Play"]];
+ else if (fPendingCount > 0)
+ {
+ enable = YES;
+ [toolbarItem setImage:[NSImage imageNamed: @"Play"]];
+ [toolbarItem setLabel: @"Start"];
+ [toolbarItem setToolTip: @"Start Encoding"];
+ }
+
+ else
+ {
+ enable = NO;
+ [toolbarItem setImage:[NSImage imageNamed: @"Play"]];
+ [toolbarItem setLabel: @"Start"];
+ [toolbarItem setToolTip: @"Start Encoding"];
+ }
}
- else
+ if ([[toolbarItem itemIdentifier] isEqual: HBQueuePauseResumeToolbarIdentifier])
{
- [fStartPauseButton setEnabled:NO];
-// [fStartPauseButton setTitle:NSLocalizedString(@"Start", nil)];
- [fStartPauseButton setImage:[NSImage imageNamed: @"Play"]];
+ if (s.state == HB_STATE_PAUSED)
+ {
+ enable = YES;
+ [toolbarItem setImage:[NSImage imageNamed: @"Play"]];
+ [toolbarItem setLabel: @"Resume"];
+ [toolbarItem setToolTip: @"Resume Encoding"];
+ }
+
+ else if ((s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING))
+ {
+ enable = YES;
+ [toolbarItem setImage:[NSImage imageNamed: @"Pause"]];
+ [toolbarItem setLabel: @"Pause"];
+ [toolbarItem setToolTip: @"Pause Encoding"];
+ }
+ else
+ {
+ enable = NO;
+ [toolbarItem setImage:[NSImage imageNamed: @"Pause"]];
+ [toolbarItem setLabel: @"Pause"];
+ [toolbarItem setToolTip: @"Pause Encoding"];
+ }
}
+
+ return enable;
}
+#pragma mark -
+
+
+#pragma mark Queue Item Controls
//------------------------------------------------------------------------------------
-// Refresh queue count text field (fQueueCountField).
+// Delete encodes from the queue window and accompanying array
+// Also handling first cancelling the encode if in fact its currently encoding.
//------------------------------------------------------------------------------------
-- (void)updateQueueCountField
+- (IBAction)removeSelectedQueueItem: (id)sender
{
- NSString * msg;
- int jobCount;
- BOOL jobGroups = [[NSUserDefaults standardUserDefaults] boolForKey:@"QueueShowsJobsAsGroups"];
+ NSIndexSet * selectedRows = [fOutlineView selectedRowIndexes];
+ NSUInteger row = [selectedRows 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 (jobGroups)
+ if ([[[fJobGroups objectAtIndex:row] objectForKey:@"Status"] integerValue] == 1)
{
- jobCount = fHandle ? hb_group_count(fHandle) : 0;
- if (jobCount == 1)
- msg = NSLocalizedString(@"1 pending encode", nil);
- else
- msg = [NSString stringWithFormat:NSLocalizedString(@"%d pending encodes", nil), jobCount];
+ /* 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)];
+ // Which window to attach the sheet to?
+ NSWindow * docWindow = nil;
+ if ([sender respondsToSelector: @selector(window)])
+ docWindow = [sender window];
+
+
+ NSBeginCriticalAlertSheet(
+ alertTitle,
+ NSLocalizedString(@"Keep Encoding", nil),
+ nil,
+ NSLocalizedString(@"Stop Encoding and Delete", nil),
+ docWindow, self,
+ nil, @selector(didDimissCancelCurrentJob:returnCode:contextInfo:), nil,
+ NSLocalizedString(@"Your movie will be lost if you don't continue encoding.", nil));
+
+ // didDimissCancelCurrentJob:returnCode:contextInfo: will be called when the dialog is dismissed
}
else
- {
- jobCount = fHandle ? hb_count(fHandle) : 0;
- if (jobCount == 1)
- msg = NSLocalizedString(@"1 pending pass", nil);
- else
- msg = [NSString stringWithFormat:NSLocalizedString(@"%d pending passes", nil), jobCount];
-
+ {
+ /* since we are not a currently encoding item, we can just be cancelled */
+ [fHBController removeQueueFileItem:row];
}
-
- [fQueueCountField setStringValue:msg];
}
-//------------------------------------------------------------------------------------
-// Refresh the UI in the current job pane. Should be called whenever the current job
-// being processed has changed or when progress has changed.
-//------------------------------------------------------------------------------------
-- (void)updateCurrentJobUI
+- (void) didDimissCancelCurrentJob: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
{
- hb_state_t s;
- hb_job_t * job = nil;
-
- if (fHandle)
+ /* 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];
+ if (returnCode == NSAlertOtherReturn)
{
- hb_get_state( fHandle, &s );
- job = hb_current_job(fHandle);
+ /* 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];
}
+
+}
- if (job)
- {
- [fJobDescTextField setAttributedStringValue:[self attributedDescriptionForJob:job withDetail:YES withHighlighting:NO]];
-
- [self showCurrentJobPane:YES];
- [fJobIconView setImage: fShowsJobsAsGroups ? [NSImage imageNamed:@"JobLarge"] : [NSImage imageNamed:@"JobPassLarge"] ];
-
- NSString * statusMsg = [self progressStatusStringForJob:job state:&s];
- NSString * timeMsg = [self progressTimeRemainingStringForJob:job state:&s];
- if ([timeMsg length] > 0)
- statusMsg = [NSString stringWithFormat:@"%@ - %@", statusMsg, timeMsg];
- [fProgressTextField setStringValue:statusMsg];
- [self updateProgressBarWithState:&s];
- }
- else
+//------------------------------------------------------------------------------------
+// Show the finished encode in the finder
+//------------------------------------------------------------------------------------
+- (IBAction)revealSelectedQueueItem: (id)sender
+{
+ NSIndexSet * selectedRows = [fOutlineView selectedRowIndexes];
+ NSInteger row = [selectedRows firstIndex];
+ if (row != NSNotFound)
{
- [fJobDescTextField setStringValue:NSLocalizedString(@"No job processing", nil)];
+ while (row != NSNotFound)
+ {
+ NSMutableDictionary *queueItemToOpen = [fOutlineView itemAtRow: row];
+ [[NSWorkspace sharedWorkspace] selectFile:[queueItemToOpen objectForKey:@"DestinationPath"] inFileViewerRootedAtPath:nil];
- [self showCurrentJobPane:NO];
- [fProgressBar stopAnimation:nil]; // just in case in was animating
+ row = [selectedRows indexGreaterThanIndex: row];
+ }
}
-
- // Gross hack. Also update start/pause button. Have to do it here since we don't
- // have any other periodic chance to update the button.
- [self updateStartPauseButton];
}
+
//------------------------------------------------------------------------------------
-// Refresh the UI in the queue pane. Should be called whenever the content of HB's job
-// list has changed so that HBQueueController can sync up.
+// Starts or cancels the processing of jobs depending on the current state
//------------------------------------------------------------------------------------
-- (void)updateQueueUI
+- (IBAction)toggleStartCancel: (id)sender
{
- [fTaskView noteNumberOfRowsChanged];
- [fTaskView reloadData];
-
- [self updateQueueCountField];
- [self updateStartPauseButton];
+ if (!fQueueEncodeLibhb) return;
+
+ hb_state_t s;
+ hb_get_state2 (fQueueEncodeLibhb, &s);
+
+ if ((s.state == HB_STATE_PAUSED) || (s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING))
+ [fHBController Cancel: fQueuePane]; // sender == fQueuePane so that warning alert shows up on queue window
+
+ else if (fPendingCount > 0)
+ [fHBController Rip: NULL];
}
//------------------------------------------------------------------------------------
-// Deletes the selected job from HB and the queue UI
+// Toggles the pause/resume state of libhb
//------------------------------------------------------------------------------------
-- (IBAction)removeSelectedJob: (id)sender
+- (IBAction)togglePauseResume: (id)sender
{
- if (!fHandle) return;
+ if (!fQueueEncodeLibhb) return;
+
+ hb_state_t s;
+ hb_get_state2 (fQueueEncodeLibhb, &s);
- int row = [sender selectedRow];
- if (row != -1)
+ if (s.state == HB_STATE_PAUSED)
{
- BOOL jobGroups = [[NSUserDefaults standardUserDefaults] boolForKey:@"QueueShowsJobsAsGroups"];
- if (jobGroups)
- hb_rem_group( fHandle, hb_group( fHandle, row ) );
- else
- hb_rem( fHandle, hb_job( fHandle, row ) );
- [self updateQueueUI];
+ hb_resume (fQueueEncodeLibhb);
+ [self startAnimatingCurrentWorkingEncodeInQueue];
+ }
+ else if ((s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING))
+ {
+ hb_pause (fQueueEncodeLibhb);
+ [self stopAnimatingCurrentJobGroupInQueue];
}
}
+#pragma mark -
+
+
+#pragma mark Animate Endcoding Item
+
+
+
+
//------------------------------------------------------------------------------------
-// Prompts user if the want to cancel encoding of current job. If so, hb_stop gets
-// called.
+// Starts animating the job icon of the currently processing job in the queue outline
+// view.
//------------------------------------------------------------------------------------
-- (IBAction)cancelCurrentJob: (id)sender
+- (void) startAnimatingCurrentWorkingEncodeInQueue
{
- if (!fHandle) return;
-
- hb_job_t * job = hb_current_job(fHandle);
- if (!job) return;
+ 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 command key is down, don't prompt
- BOOL hasCmdKeyMask = ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) != 0;
- if (hasCmdKeyMask)
- hb_stop(fHandle);
- else
+//------------------------------------------------------------------------------------
+// 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)
{
- NSString * alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Do you want to stop processing of %@?", nil),
- [NSString stringWithUTF8String:job->title->name]];
-
- NSBeginCriticalAlertSheet(
- alertTitle,
- NSLocalizedString(@"Stop Processing", nil), NSLocalizedString(@"Keep Processing", nil), nil, fQueueWindow, self,
- @selector(cancelCurrentJob:returnCode:contextInfo:), nil, nil,
- NSLocalizedString(@"Your movie will be lost if you don't continue processing.", nil),
- [NSString stringWithUTF8String:job->title->name]);
-
- // cancelCurrentJob:returnCode:contextInfo: will be called when the dialog is dismissed
+ fAnimationIndex++;
+ fAnimationIndex %= 6; // there are 6 animation images; see outlineView:objectValueForTableColumn:byItem: below.
+ [self animateWorkingEncodeIconInQueue];
}
}
-- (void) cancelCurrentJob: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
+
+- (void) animateWorkingEncodeIconInQueue
{
- if (returnCode == NSAlertDefaultReturn)
- hb_stop(fHandle);
+ 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];
+ }
}
//------------------------------------------------------------------------------------
-// Enables or disables the display of detail information for each job based on the
-// state of the sender.
+// Stops animating the job icon of the currently processing job in the queue outline
+// view.
//------------------------------------------------------------------------------------
-- (IBAction)detailChanged: (id)sender
+- (void) stopAnimatingCurrentJobGroupInQueue
{
- if ([sender isMemberOfClass:[NSButton class]])
+ if (fAnimationTimer && [fAnimationTimer isValid])
{
- BOOL detail = [sender state] == NSOnState;
- [[NSUserDefaults standardUserDefaults] setBool:detail forKey:@"QueueShowsDetail"];
-
- [self setShowsDetail:detail];
+ [fAnimationTimer invalidate];
+ [fAnimationTimer release];
+ fAnimationTimer = nil;
}
}
-//------------------------------------------------------------------------------------
-// Enables or disables the display of job groups based on the state of the sender.
-//------------------------------------------------------------------------------------
-- (IBAction)jobGroupsChanged: (id)sender
+
+#pragma mark -
+
+- (void)moveObjectsInArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex
{
- if ([sender isMemberOfClass:[NSButton class]])
- {
- BOOL groups = [sender state] == NSOnState;
- [[NSUserDefaults standardUserDefaults] setBool:groups forKey:@"QueueShowsJobsAsGroups"];
+ NSUInteger index = [indexSet lastIndex];
+ NSUInteger aboveInsertIndexCount = 0;
- [self setShowsJobsAsGroups:groups];
- }
- else if ([sender isMemberOfClass:[NSSegmentedControl class]])
+ while (index != NSNotFound)
{
- BOOL groups = [sender selectedSegment] == 0;
- [[NSUserDefaults standardUserDefaults] setBool:groups forKey:@"QueueShowsJobsAsGroups"];
+ NSUInteger removeIndex;
- [self setShowsJobsAsGroups:groups];
- }
- else if ([sender isMemberOfClass:[NSMatrix class]])
- {
- BOOL groups = [sender selectedColumn] == 0;
- [[NSUserDefaults standardUserDefaults] setBool:groups forKey:@"QueueShowsJobsAsGroups"];
+ if (index >= insertIndex)
+ {
+ removeIndex = index + aboveInsertIndexCount;
+ aboveInsertIndexCount++;
+ }
+ else
+ {
+ removeIndex = index;
+ insertIndex--;
+ }
+
+ id object = [[array objectAtIndex:removeIndex] retain];
+ [array removeObjectAtIndex:removeIndex];
+ [array insertObject:object atIndex:insertIndex];
+ [object release];
- [self setShowsJobsAsGroups:groups];
+ index = [indexSet indexLessThanIndex:index];
}
}
-//------------------------------------------------------------------------------------
-// Toggles the Shows Detail setting.
-//------------------------------------------------------------------------------------
-- (IBAction)toggleShowsDetail: (id)sender
+
+#pragma mark -
+#pragma mark NSOutlineView delegate
+
+
+- (id)outlineView:(NSOutlineView *)fOutlineView child:(NSInteger)index ofItem:(id)item
{
- [self setShowsDetail:!fShowsDetail];
+ if (item == nil)
+ return [fJobGroups objectAtIndex: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.");
+ return nil;
}
-//------------------------------------------------------------------------------------
-// Toggles the Shows Jobs As Groups setting.
-//------------------------------------------------------------------------------------
-- (IBAction)toggleShowsJobsAsGroups: (id)sender
+- (BOOL)outlineView:(NSOutlineView *)fOutlineView isItemExpandable:(id)item
{
- [self setShowsJobsAsGroups:!fShowsJobsAsGroups];
+ // Our outline view has no levels, but we can still expand every item. Doing so
+ // just makes the row taller. See heightOfRowByItem below.
+ return YES;
}
-//------------------------------------------------------------------------------------
-// Toggles the processing of jobs on or off depending on the current state
-//------------------------------------------------------------------------------------
-- (IBAction)toggleStartPause: (id)sender
+- (BOOL)outlineView:(NSOutlineView *)outlineView shouldExpandItem:(id)item
{
- if (!fHandle) return;
-
- hb_state_t s;
- hb_get_state2 (fHandle, &s);
+ // Our outline view has no levels, but we can still expand every item. Doing so
+ // just makes the row taller. See heightOfRowByItem below.
+return ![(HBQueueOutlineView*)outlineView isDragging];
+}
- if (s.state == HB_STATE_PAUSED)
- hb_resume (fHandle);
- else if ((s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING))
- hb_pause (fHandle);
+- (NSInteger)outlineView:(NSOutlineView *)fOutlineView numberOfChildrenOfItem:(id)item
+{
+ // Our outline view has no levels, so number of children will be zero for all
+ // top-level items.
+ if (item == nil)
+ return [fJobGroups count];
else
- {
- BOOL jobGroups = [[NSUserDefaults standardUserDefaults] boolForKey:@"QueueShowsJobsAsGroups"];
- if (jobGroups)
- {
- if (hb_group_count(fHandle) > 0)
- hb_start (fHandle);
- }
- else if (hb_count(fHandle) > 0)
- hb_start (fHandle);
- }
+ return 0;
}
-#pragma mark -
-#pragma mark Toolbar
+- (void)outlineViewItemDidCollapse:(NSNotification *)notification
+{
+ id item = [[notification userInfo] objectForKey:@"NSObject"];
+ NSInteger row = [fOutlineView rowForItem:item];
+ [fOutlineView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row,1)]];
+}
-//------------------------------------------------------------------------------------
-// setupToolbar
-//------------------------------------------------------------------------------------
-- (void)setupToolbar
+- (void)outlineViewItemDidExpand:(NSNotification *)notification
{
- // Create a new toolbar instance, and attach it to our window
- NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier: HBQueueToolbar] autorelease];
-
- // Set up toolbar properties: Allow customization, give a default display mode, and remember state in user defaults
- [toolbar setAllowsUserCustomization: YES];
- [toolbar setAutosavesConfiguration: YES];
- [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
-
- // We are the delegate
- [toolbar setDelegate: self];
-
- // Attach the toolbar to our window
- [fQueueWindow setToolbar: toolbar];
+ id item = [[notification userInfo] objectForKey:@"NSObject"];
+ NSInteger row = [fOutlineView rowForItem:item];
+ [fOutlineView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row,1)]];
}
-//------------------------------------------------------------------------------------
-// toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:
-//------------------------------------------------------------------------------------
-- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar
- itemForItemIdentifier:(NSString *)itemIdentifier
- willBeInsertedIntoToolbar:(BOOL)flag
+- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
{
- // Required delegate method: Given an item identifier, this method returns an item.
- // The toolbar will use this method to obtain toolbar items that can be displayed
- // in the customization sheet, or in the toolbar itself.
-
- NSToolbarItem *toolbarItem = nil;
-
- if ([itemIdentifier isEqual: HBStartPauseResumeToolbarIdentifier])
- {
- toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
-
- // Set the text label to be displayed in the toolbar and customization palette
- [toolbarItem setLabel: @"Start"];
- [toolbarItem setPaletteLabel: @"Start/Pause"];
-
- // Set up a reasonable tooltip, and image
- [toolbarItem setToolTip: @"Start Encoding"];
- [toolbarItem setImage: [NSImage imageNamed: @"Play"]];
-
- // Tell the item what message to send when it is clicked
- [toolbarItem setTarget: self];
- [toolbarItem setAction: @selector(toggleStartPause:)];
- }
-
- else if ([itemIdentifier isEqual: HBShowDetailToolbarIdentifier])
+ if ([outlineView isItemExpanded: item])
{
- toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
-
- // Set the text label to be displayed in the toolbar and customization palette
- [toolbarItem setLabel: @"Show Detail"];
- [toolbarItem setPaletteLabel: @"Show Detail"];
-
- // Set up a reasonable tooltip, and image
- [toolbarItem setToolTip: @"Show Detail"];
- [toolbarItem setImage: [NSImage imageNamed: @"Info"]];
-
- // Tell the item what message to send when it is clicked
- [toolbarItem setTarget: self];
- [toolbarItem setAction: @selector(toggleShowsDetail:)];
- }
-
- else if ([itemIdentifier isEqual: HBShowGroupsToolbarIdentifier])
+ /* Below is the original code to accommodate a live resize,
+ * however as stated in travistex's comments it's very buggy.
+ * For now I will leave it here ... commented out and use
+ * the code below to determine the row height based on each
+ * encodes optional parameters and how they are displayed. */
+
+ // Short-circuit here if in a live resize primarily to fix a bug but also to
+ // increase resposivness during a resize. There's a bug in NSTableView that
+ // causes row heights to get messed up if you try to change them during a live
+ // resize. So if in a live resize, simply return the previously calculated
+ // height. The row heights will get fixed up after the resize because we have
+ // implemented viewDidEndLiveResize to force all of them to be recalculated.
+ // if ([outlineView inLiveResize] && [item lastDescriptionHeight] > 0)
+ // return [item lastDescriptionHeight];
+
+ // CGFloat width = [[outlineView tableColumnWithIdentifier: @"desc"] width];
+ // Column width is NOT what is ultimately used. I can't quite figure out what
+ // width to use for calculating text metrics. No matter how I tweak this value,
+ // there are a few conditions in which the drawn text extends below the bounds
+ // of the row cell. In previous versions, which ran under Tiger, I was
+ // reducing width by 47 pixles.
+ // width -= 2; // (?) for intercell spacing
+
+ // CGFloat height = [item heightOfDescriptionForWidth: width];
+ // return height;
+
+ /* So, we know several rows of text that are in all queue items for display.
+ * These are the title line, Preset, Format, Destination, Picture, and Video Lines
+ */
+ CGFloat rowHeightNonTitle = 15.0;
+ /* Add the title line height, then the non title line height for Preset, Format, Destination
+ * Picture and Video
+ */
+ CGFloat itemHeightForDisplay = HB_ROW_HEIGHT_TITLE_ONLY + (rowHeightNonTitle * 5);
+
+ /* get our item row number so we an use it to calc how many lines we have to display based
+ * on MP4 Options, Filter Options, X264 Options, Audio Tracks and Subtitles from our queue array */
+ int itemRowNum = [outlineView rowForItem: item];
+ NSMutableDictionary *queueItemToCheck = [outlineView itemAtRow: itemRowNum];
+
+ /* Check to see if we need to allow for mp4 opts */
+ BOOL mp4OptsPresent = NO;
+ if ([[queueItemToCheck objectForKey:@"FileFormat"] isEqualToString: @"MP4 file"])
+ {
+
+ if( [[queueItemToCheck objectForKey:@"Mp4LargeFile"] intValue] == 1)
+ {
+ mp4OptsPresent = YES;
+ }
+ if( [[queueItemToCheck objectForKey:@"Mp4HttpOptimize"] intValue] == 1)
+ {
+ mp4OptsPresent = YES;
+ }
+ if( [[queueItemToCheck objectForKey:@"Mp4iPodCompatible"] intValue] == 1)
+ {
+ mp4OptsPresent = YES;
+ }
+ }
+
+ if (mp4OptsPresent == YES)
+ {
+ itemHeightForDisplay += rowHeightNonTitle;
+ }
+
+ /* check to see if we need to allow for the Picture Filters row */
+ BOOL pictureFiltersPresent = NO;
+ if( [[queueItemToCheck objectForKey:@"PictureDetelecine"] intValue] > 0)
+ {
+ pictureFiltersPresent = YES;
+ }
+ if( [[queueItemToCheck objectForKey:@"PictureDecomb"] intValue] > 0)
+ {
+ pictureFiltersPresent = YES;
+ }
+ if( [[queueItemToCheck objectForKey:@"PictureDeinterlace"] intValue] > 0)
+ {
+ pictureFiltersPresent = YES;
+ }
+ if( [[queueItemToCheck objectForKey:@"PictureDenoise"] intValue] > 0)
+ {
+ pictureFiltersPresent = YES;
+ }
+ if( [[queueItemToCheck objectForKey:@"PictureDeblock"] intValue] > 0)
+ {
+ pictureFiltersPresent = YES;
+ }
+ if( [[queueItemToCheck objectForKey:@"VideoGrayScale"] intValue] > 0)
+ {
+ pictureFiltersPresent = YES;
+ }
+
+ if (pictureFiltersPresent == YES)
+ {
+ itemHeightForDisplay += rowHeightNonTitle;
+ }
+
+ /* check to see if we need a line to display x264 options */
+ if ([[queueItemToCheck objectForKey:@"VideoEncoder"] isEqualToString: @"H.264 (x264)"])
+ {
+ itemHeightForDisplay += rowHeightNonTitle;
+ }
+
+ /* check to see how many audio track lines to allow for */
+ if ([[queueItemToCheck objectForKey:@"Audio1Track"] intValue] > 0)
+ {
+ itemHeightForDisplay += rowHeightNonTitle;
+ }
+ if ([[queueItemToCheck objectForKey:@"Audio2Track"] intValue] > 0)
+ {
+ itemHeightForDisplay += rowHeightNonTitle;
+ }
+ if ([[queueItemToCheck objectForKey:@"Audio3Track"] intValue] > 0)
+ {
+ itemHeightForDisplay += rowHeightNonTitle;
+ }
+ if ([[queueItemToCheck objectForKey:@"Audio4Track"] intValue] > 0)
+ {
+ itemHeightForDisplay += rowHeightNonTitle;
+ }
+
+ /* add in subtitle lines for each subtitle in the SubtitleList array */
+ itemHeightForDisplay += rowHeightNonTitle * [[queueItemToCheck objectForKey:@"SubtitleList"] count];
+
+ return itemHeightForDisplay;
+
+ }
+ else
{
- toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
-
- // Set the text label to be displayed in the toolbar and customization palette
- [toolbarItem setLabel: @"View"];
- [toolbarItem setPaletteLabel: @"View"];
-
- // Set up a reasonable tooltip, and image
- [toolbarItem setToolTip: @"View"];
-// [toolbarItem setImage: [NSImage imageNamed: @"Disc"]];
-
-
- NSButtonCell * buttonCell = [[[NSButtonCell alloc] initImageCell:nil] autorelease];
- [buttonCell setBezelStyle:NSShadowlessSquareBezelStyle];//NSShadowlessSquareBezelStyle
- [buttonCell setButtonType:NSToggleButton];
- [buttonCell setBordered:NO];
- [buttonCell setImagePosition:NSImageOnly];
-
- NSMatrix * matrix = [[[NSMatrix alloc] initWithFrame:NSMakeRect(0,0,54,25)
- mode:NSRadioModeMatrix
- prototype:buttonCell
- numberOfRows:1
- numberOfColumns:2] autorelease];
- [matrix setCellSize:NSMakeSize(27, 25)];
- [matrix setIntercellSpacing:NSMakeSize(0, 0)];
- [matrix selectCellAtRow:0 column:(fShowsJobsAsGroups ? 0 : 1)];
-
- buttonCell = [matrix cellAtRow:0 column:0];
- [buttonCell setTitle:@""];
- [buttonCell setImage:[NSImage imageNamed: @"Encodes"]];
- [buttonCell setAlternateImage:[NSImage imageNamed: @"EncodesPressed"]];
- buttonCell = [matrix cellAtRow:0 column:1];
- [buttonCell setTitle:@""];
- [buttonCell setImage:[NSImage imageNamed: @"Passes"]];
- [buttonCell setAlternateImage:[NSImage imageNamed: @"PassesPressed"]];
- [toolbarItem setMinSize: [matrix frame].size];
- [toolbarItem setMaxSize: [matrix frame].size];
- [toolbarItem setView: matrix];
-
-/*
- NSSegmentedControl * segControl = [[[NSSegmentedControl alloc] initWithFrame:NSMakeRect(0,0,20,20)] autorelease];
- [[segControl cell] setControlSize:NSSmallControlSize];
- [segControl setSegmentCount:2];
- [segControl setLabel:@"Encodes" forSegment:0];
- [segControl setLabel:@"Passes" forSegment:1];
- [segControl setImage:[NSImage imageNamed:@"Delete"] forSegment:0];
- [segControl setImage:[NSImage imageNamed:@"Delete"] forSegment:1];
- [segControl setSelectedSegment: (fShowsJobsAsGroups ? 0 : 1)];
- [segControl sizeToFit];
- [toolbarItem setMinSize: [segControl frame].size];
- [toolbarItem setMaxSize: [segControl frame].size];
- [toolbarItem setView: segControl];
-*/
-
-/*
- NSButton * button = [[[NSButton alloc] initWithFrame:NSMakeRect(0,0,20,20)] autorelease];
- [button setButtonType:NSSwitchButton];
- [button setTitle:@""];
- [button setState: fShowsJobsAsGroups ? NSOnState : NSOffState];
- [toolbarItem setMinSize: NSMakeSize(20,20)];
- [toolbarItem setMaxSize: NSMakeSize(20,20)];
- [toolbarItem setView: button];
-*/
-
- // Tell the item what message to send when it is clicked
- [toolbarItem setTarget: self];
- [toolbarItem setAction: @selector(jobGroupsChanged:)];
- }
-
- return toolbarItem;
+ return HB_ROW_HEIGHT_TITLE_ONLY;
+ }
}
-//------------------------------------------------------------------------------------
-// toolbarDefaultItemIdentifiers:
-//------------------------------------------------------------------------------------
-- (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
+- (CGFloat) heightOfDescriptionForWidth:(CGFloat)width
{
- // Required delegate method: Returns the ordered list of items to be shown in the
- // toolbar by default.
-
- return [NSArray arrayWithObjects:
- HBStartPauseResumeToolbarIdentifier,
- NSToolbarSeparatorItemIdentifier,
- HBShowGroupsToolbarIdentifier,
- HBShowDetailToolbarIdentifier,
- nil];
+ // Try to return the cached value if no changes have happened since the last time
+ //if ((width == fLastDescriptionWidth) && (fLastDescriptionHeight != 0) && !fNeedsDescription)
+ // return fLastDescriptionHeight;
+
+ //if (fNeedsDescription)
+ // [self updateDescription];
+
+ // Calculate the height
+ //NSRect bounds = [fDescription boundingRectWithSize:NSMakeSize(width, 10000) options:NSStringDrawingUsesLineFragmentOrigin];
+ //fLastDescriptionHeight = bounds.size.height + 6.0; // add some border to bottom
+ //fLastDescriptionWidth = width;
+ return HB_ROW_HEIGHT_FULL_DESCRIPTION;
+
+/* supposedly another way to do this, in case boundingRectWithSize isn't working
+ NSTextView* tmpView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, width, 1)];
+ [[tmpView textStorage] setAttributedString:aString];
+ [tmpView setHorizontallyResizable:NO];
+ [tmpView setVerticallyResizable:YES];
+// [[tmpView textContainer] setHeightTracksTextView: YES];
+// [[tmpView textContainer] setContainerSize: NSMakeSize(width, 10000)];
+ [tmpView sizeToFit];
+ float height = [tmpView frame].size.height;
+ [tmpView release];
+ return height;
+*/
}
-//------------------------------------------------------------------------------------
-// toolbarAllowedItemIdentifiers:
-//------------------------------------------------------------------------------------
-- (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
+- (CGFloat) lastDescriptionHeight
{
- // Required delegate method: Returns the list of all allowed items by identifier.
- // By default, the toolbar does not assume any items are allowed, even the
- // separator. So, every allowed item must be explicitly listed.
-
- return [NSArray arrayWithObjects:
- HBStartPauseResumeToolbarIdentifier,
- HBShowGroupsToolbarIdentifier,
- HBShowDetailToolbarIdentifier,
- NSToolbarCustomizeToolbarItemIdentifier,
- NSToolbarFlexibleSpaceItemIdentifier,
- NSToolbarSpaceItemIdentifier,
- NSToolbarSeparatorItemIdentifier,
- nil];
+ return HB_ROW_HEIGHT_FULL_DESCRIPTION;
}
-//------------------------------------------------------------------------------------
-// validateToolbarItem:
-//------------------------------------------------------------------------------------
-- (BOOL) validateToolbarItem: (NSToolbarItem *) toolbarItem
+- (id)outlineView:(NSOutlineView *)fOutlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
{
- // Optional method: This message is sent to us since we are the target of some
- // toolbar item actions.
-
- if (!fHandle) return NO;
-
- BOOL enable = NO;
-
- hb_state_t s;
- hb_get_state2 (fHandle, &s);
-
- if ([[toolbarItem itemIdentifier] isEqual: HBStartPauseResumeToolbarIdentifier])
+ // 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.
+
+ if ([[tableColumn identifier] isEqualToString:@"desc"])
{
- if (s.state == HB_STATE_PAUSED)
+ /* This should have caused the description we wanted to show*/
+ //return [item objectForKey:@"SourceName"];
+
+ /* code to build the description as per old queue */
+ //return [self formatEncodeItemDescription:item];
+
+ /* Below should be put into a separate method but I am way too f'ing lazy right now */
+ NSMutableAttributedString * finalString = [[[NSMutableAttributedString alloc] initWithString: @""] autorelease];
+ // Attributes
+ NSMutableParagraphStyle * ps = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
+ [ps setHeadIndent: 40.0];
+ [ps setParagraphSpacing: 1.0];
+ [ps setTabStops:[NSArray array]]; // clear all tabs
+ [ps addTabStop: [[[NSTextTab alloc] initWithType: NSLeftTabStopType location: 20.0] autorelease]];
+
+
+ NSDictionary* detailAttr = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSFont systemFontOfSize:10.0], NSFontAttributeName,
+ ps, NSParagraphStyleAttributeName,
+ nil];
+
+ NSDictionary* detailBoldAttr = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSFont boldSystemFontOfSize:10.0], NSFontAttributeName,
+ ps, NSParagraphStyleAttributeName,
+ nil];
+
+ NSDictionary* titleAttr = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSFont systemFontOfSize:[NSFont systemFontSize]], NSFontAttributeName,
+ ps, NSParagraphStyleAttributeName,
+ nil];
+
+ NSDictionary* shortHeightAttr = [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSFont systemFontOfSize:2.0], NSFontAttributeName,
+ nil];
+
+ /* First line, we should strip the destination path and just show the file name and add the title num and chapters (if any) */
+ //finalDescription = [finalDescription stringByAppendingString:[NSString stringWithFormat:@"Source: %@ Output: %@\n", [item objectForKey:@"SourceName"],[item objectForKey:@"DestinationPath"]]];
+ NSString * summaryInfo;
+
+ NSString * titleString = [NSString stringWithFormat:@"Title %d", [[item objectForKey:@"TitleNumber"] intValue]];
+
+ NSString * chapterString = ([[item objectForKey:@"ChapterStart"] intValue] == [[item objectForKey:@"ChapterEnd"] intValue]) ?
+ [NSString stringWithFormat:@"Chapter %d", [[item objectForKey:@"ChapterStart"] intValue]] :
+ [NSString stringWithFormat:@"Chapters %d through %d", [[item objectForKey:@"ChapterStart"] intValue], [[item objectForKey:@"ChapterEnd"] intValue]];
+
+ NSString * passesString;
+ if ([[item objectForKey:@"VideoTwoPass"] intValue] == 0)
{
- enable = YES;
- [toolbarItem setImage:[NSImage imageNamed: @"Play"]];
- [toolbarItem setLabel: @"Resume"];
- [toolbarItem setPaletteLabel: @"Resume"];
- [toolbarItem setToolTip: @"Resume Encoding"];
- }
+ passesString = [NSString stringWithFormat:@"1 Video Pass"];
+ }
+ else
+ {
+ if ([[item objectForKey:@"VideoTurboTwoPass"] intValue] == 1)
+ {
+ passesString = [NSString stringWithFormat:@"2 Video Passes Turbo"];
+ }
+ else
+ {
+ passesString = [NSString stringWithFormat:@"2 Video Passes"];
+ }
+ }
- else if ((s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING))
+ [finalString appendString:[NSString stringWithFormat:@"%@", [item objectForKey:@"SourceName"]] withAttributes:titleAttr];
+
+ /* lets add the output file name to the title string here */
+ NSString * outputFilenameString = [[item objectForKey:@"DestinationPath"] lastPathComponent];
+
+ summaryInfo = [NSString stringWithFormat: @" (%@, %@, %@) -> %@", titleString, chapterString, 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", [item objectForKey:@"PresetName"]] withAttributes:detailAttr];
+
+ /* Third Line (Format Summary) */
+ NSString * audioCodecSummary = @"";
+ /* Lets also get our audio track detail since we are going through the logic for use later */
+ NSString * audioDetail1 = @"";
+ NSString * audioDetail2 = @"";
+ NSString * audioDetail3 = @"";
+ NSString * audioDetail4 = @"";
+ if ([[item objectForKey:@"Audio1Track"] intValue] > 0)
{
- enable = YES;
- [toolbarItem setImage:[NSImage imageNamed: @"Pause"]];
- [toolbarItem setLabel: @"Pause"];
- [toolbarItem setPaletteLabel: @"Pause"];
- [toolbarItem setToolTip: @"Pause Encoding"];
+ audioCodecSummary = [NSString stringWithFormat:@"%@", [item objectForKey:@"Audio1Encoder"]];
+ audioDetail1 = [NSString stringWithFormat:@"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps)",
+ [item objectForKey:@"Audio1TrackDescription"] ,
+ [item objectForKey:@"Audio1Encoder"],
+ [item objectForKey:@"Audio1Mixdown"] ,
+ [item objectForKey:@"Audio1Samplerate"],
+ [item objectForKey:@"Audio1Bitrate"]];
+
+ if ([[item objectForKey:@"Audio1TrackDRCSlider"] floatValue] > 1.00)
+ {
+ audioDetail1 = [NSString stringWithFormat:@"%@, DRC: %@",audioDetail1,[item objectForKey:@"Audio1TrackDRCSlider"]];
+ }
+ else
+ {
+ audioDetail1 = [NSString stringWithFormat:@"%@, DRC: Off",audioDetail1];
+ }
}
-
- else if (hb_count(fHandle) > 0)
+
+ if ([[item objectForKey:@"Audio2Track"] intValue] > 0)
{
- enable = YES;
- [toolbarItem setImage:[NSImage imageNamed: @"Play"]];
- [toolbarItem setLabel: @"Start"];
- [toolbarItem setPaletteLabel: @"Start"];
- [toolbarItem setToolTip: @"Start Encoding"];
+ audioCodecSummary = [NSString stringWithFormat:@"%@, %@",audioCodecSummary ,[item objectForKey:@"Audio2Encoder"]];
+ audioDetail2 = [NSString stringWithFormat:@"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps)",
+ [item objectForKey:@"Audio2TrackDescription"] ,
+ [item objectForKey:@"Audio2Encoder"],
+ [item objectForKey:@"Audio2Mixdown"] ,
+ [item objectForKey:@"Audio2Samplerate"],
+ [item objectForKey:@"Audio2Bitrate"]];
+
+ if ([[item objectForKey:@"Audio2TrackDRCSlider"] floatValue] > 1.00)
+ {
+ audioDetail2 = [NSString stringWithFormat:@"%@, DRC: %@",audioDetail2,[item objectForKey:@"Audio2TrackDRCSlider"]];
+ }
+ else
+ {
+ audioDetail2 = [NSString stringWithFormat:@"%@, DRC: Off",audioDetail2];
+ }
}
-
+
+ if ([[item objectForKey:@"Audio3Track"] intValue] > 0)
+ {
+ audioCodecSummary = [NSString stringWithFormat:@"%@, %@",audioCodecSummary ,[item objectForKey:@"Audio3Encoder"]];
+ audioDetail3 = [NSString stringWithFormat:@"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps)",
+ [item objectForKey:@"Audio3TrackDescription"] ,
+ [item objectForKey:@"Audio3Encoder"],
+ [item objectForKey:@"Audio3Mixdown"] ,
+ [item objectForKey:@"Audio3Samplerate"],
+ [item objectForKey:@"Audio3Bitrate"]];
+
+ if ([[item objectForKey:@"Audio3TrackDRCSlider"] floatValue] > 1.00)
+ {
+ audioDetail3 = [NSString stringWithFormat:@"%@, DRC: %@",audioDetail3,[item objectForKey:@"Audio3TrackDRCSlider"]];
+ }
+ else
+ {
+ audioDetail3 = [NSString stringWithFormat:@"%@, DRC: Off",audioDetail3];
+ }
+ }
+
+ if ([[item objectForKey:@"Audio4Track"] intValue] > 0)
+ {
+ audioCodecSummary = [NSString stringWithFormat:@"%@, %@",audioCodecSummary ,[item objectForKey:@"Audio3Encoder"]];
+ audioDetail4 = [NSString stringWithFormat:@"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps)",
+ [item objectForKey:@"Audio4TrackDescription"] ,
+ [item objectForKey:@"Audio4Encoder"],
+ [item objectForKey:@"Audio4Mixdown"] ,
+ [item objectForKey:@"Audio4Samplerate"],
+ [item objectForKey:@"Audio4Bitrate"]];
+
+ if ([[item objectForKey:@"Audio4TrackDRCSlider"] floatValue] > 1.00)
+ {
+ audioDetail4 = [NSString stringWithFormat:@"%@, DRC: %@",audioDetail4,[item objectForKey:@"Audio4TrackDRCSlider"]];
+ }
+ else
+ {
+ audioDetail4 = [NSString stringWithFormat:@"%@, DRC: Off",audioDetail4];
+ }
+ }
+
+ NSString * jobFormatInfo;
+ if ([[item objectForKey:@"ChapterMarkers"] intValue] == 1)
+ jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video %@ Audio, Chapter Markers\n", [item objectForKey:@"FileFormat"], [item objectForKey:@"VideoEncoder"], audioCodecSummary];
else
+ jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video %@ Audio\n", [item objectForKey:@"FileFormat"], [item objectForKey:@"VideoEncoder"], audioCodecSummary];
+
+
+ [finalString appendString: @"Format: " withAttributes:detailBoldAttr];
+ [finalString appendString: jobFormatInfo withAttributes:detailAttr];
+
+ /* Optional String for mp4 options */
+ if ([[item objectForKey:@"FileFormat"] isEqualToString: @"MP4 file"])
{
- enable = NO;
- [toolbarItem setImage:[NSImage imageNamed: @"Play"]];
- [toolbarItem setLabel: @"Start"];
- [toolbarItem setPaletteLabel: @"Start"];
- [toolbarItem setToolTip: @"Start Encoding"];
+ NSString * MP4Opts = @"";
+ BOOL mp4OptsPresent = NO;
+ if( [[item objectForKey:@"Mp4LargeFile"] intValue] == 1)
+ {
+ mp4OptsPresent = YES;
+ MP4Opts = [MP4Opts stringByAppendingString:@" - Large file size"];
+ }
+ if( [[item objectForKey:@"Mp4HttpOptimize"] intValue] == 1)
+ {
+ mp4OptsPresent = YES;
+ MP4Opts = [MP4Opts stringByAppendingString:@" - Web optimized"];
+ }
+
+ if( [[item objectForKey:@"Mp4iPodCompatible"] intValue] == 1)
+ {
+ mp4OptsPresent = YES;
+ MP4Opts = [MP4Opts stringByAppendingString:@" - iPod 5G support "];
+ }
+ if (mp4OptsPresent == YES)
+ {
+ [finalString appendString: @"MP4 Options: " withAttributes:detailBoldAttr];
+ [finalString appendString: MP4Opts withAttributes:detailAttr];
+ [finalString appendString:@"\n" withAttributes:detailAttr];
+ }
}
- }
-
-/* not used because HBShowGroupsToolbarIdentifier is now a custom view
- else if ([[toolbarItem itemIdentifier] isEqual: HBShowGroupsToolbarIdentifier])
- {
- enable = hb_count(fHandle) > 0;
- if (fShowsJobsAsGroups)
+
+ /* Fourth Line (Destination Path)*/
+ [finalString appendString: @"Destination: " withAttributes:detailBoldAttr];
+ [finalString appendString: [item objectForKey:@"DestinationPath"] withAttributes:detailAttr];
+ [finalString appendString:@"\n" withAttributes:detailAttr];
+ /* Fifth Line Picture Details*/
+ NSString * pictureInfo;
+ pictureInfo = [NSString stringWithFormat:@"%@", [item objectForKey:@"PictureSizingSummary"]];
+ if ([[item objectForKey:@"PictureKeepRatio"] intValue] == 1)
+ {
+ pictureInfo = [pictureInfo stringByAppendingString:@" Keep Aspect Ratio"];
+ }
+ if ([[item objectForKey:@"VideoGrayScale"] intValue] == 1)
+ {
+ pictureInfo = [pictureInfo stringByAppendingString:@", Grayscale"];
+ }
+
+ [finalString appendString: @"Picture: " withAttributes:detailBoldAttr];
+ [finalString appendString: pictureInfo withAttributes:detailAttr];
+ [finalString appendString:@"\n" withAttributes:detailAttr];
+
+ /* Optional String for Picture Filters */
+
+ NSString * pictureFilters = @"";
+ BOOL pictureFiltersPresent = NO;
+
+ if( [[item objectForKey:@"PictureDetelecine"] intValue] == 1)
+ {
+ pictureFiltersPresent = YES;
+ pictureFilters = [pictureFilters stringByAppendingString:@" - Detelecine (Default)"];
+ }
+ else if( [[item objectForKey:@"PictureDetelecine"] intValue] == 2)
+ {
+ pictureFiltersPresent = YES;
+ pictureFilters = [pictureFilters stringByAppendingString:[NSString stringWithFormat:@" - Detelecine (%@)",[item objectForKey:@"PictureDetelecineCustom"]]];
+ }
+
+ if( [[item objectForKey:@"PictureDecombDeinterlace"] intValue] == 1)
{
- [toolbarItem setLabel: @"View Passes"];
- [toolbarItem setPaletteLabel: @"View Passes"];
- [toolbarItem setToolTip: @"Displays items in the queue as individual passes"];
+ if ([[item objectForKey:@"PictureDecomb"] intValue] != 0)
+ {
+ pictureFiltersPresent = YES;
+ if( [[item objectForKey:@"PictureDecomb"] intValue] == 1)
+ {
+ pictureFiltersPresent = YES;
+ pictureFilters = [pictureFilters stringByAppendingString:@" - Decomb (Default)"];
+ }
+ if( [[item objectForKey:@"PictureDecomb"] intValue] == 2)
+ {
+ pictureFiltersPresent = YES;
+ pictureFilters = [pictureFilters stringByAppendingString:[NSString stringWithFormat:@" - Decomb (%@)",[item objectForKey:@"PictureDecombCustom"]]];
+ }
+ }
}
else
{
- [toolbarItem setLabel: @"View Encodes"];
- [toolbarItem setPaletteLabel: @"View Encodes"];
- [toolbarItem setToolTip: @"Displays items in the queue as encodes"];
+ if ([[item objectForKey:@"PictureDeinterlace"] intValue] != 0)
+ {
+ pictureFiltersPresent = YES;
+ if ([[item objectForKey:@"PictureDeinterlace"] intValue] == 1)
+ {
+ pictureFilters = [pictureFilters stringByAppendingString:@" - Deinterlace (Fast)"];
+ }
+ else if ([[item objectForKey:@"PictureDeinterlace"] intValue] == 2)
+ {
+ pictureFilters = [pictureFilters stringByAppendingString:@" - Deinterlace (Slow)"];
+ }
+ else if ([[item objectForKey:@"PictureDeinterlace"] intValue] == 3)
+ {
+ pictureFilters = [pictureFilters stringByAppendingString:@" - Deinterlace (Slower)"];
+ }
+ else if ([[item objectForKey:@"PictureDeinterlace"] intValue] == 4)
+ {
+ pictureFilters = [pictureFilters stringByAppendingString:[NSString stringWithFormat:@" - Deinterlace (%@)",[item objectForKey:@"PictureDeinterlaceCustom"]]];
+ }
+
+ }
+ }
+ if ([[item objectForKey:@"PictureDenoise"] intValue] != 0)
+ {
+ pictureFiltersPresent = YES;
+ if ([[item objectForKey:@"PictureDenoise"] intValue] == 1)
+ {
+ pictureFilters = [pictureFilters stringByAppendingString:@" - Denoise (Weak)"];
+ }
+ else if ([[item objectForKey:@"PictureDenoise"] intValue] == 2)
+ {
+ pictureFilters = [pictureFilters stringByAppendingString:@" - Denoise (Medium)"];
+ }
+ else if ([[item objectForKey:@"PictureDenoise"] intValue] == 3)
+ {
+ pictureFilters = [pictureFilters stringByAppendingString:@" - Denoise (Strong)"];
+ }
+ else if ([[item objectForKey:@"PictureDenoise"] intValue] == 4)
+ {
+ pictureFilters = [pictureFilters stringByAppendingString:[NSString stringWithFormat:@" - Denoise (%@)",[item objectForKey:@"PictureDenoiseCustom"]]];
+ }
+
+ }
+ if ([[item objectForKey:@"PictureDeblock"] intValue] != 0)
+ {
+ pictureFiltersPresent = YES;
+ pictureFilters = [pictureFilters stringByAppendingString: [NSString stringWithFormat:@" - Deblock (pp7) (%d)",[[item objectForKey:@"PictureDeblock"] intValue]]];
+ }
+
+ if ([[item objectForKey:@"VideoGrayScale"] intValue] == 1)
+ {
+ pictureFiltersPresent = YES;
+ pictureFilters = [pictureFilters stringByAppendingString:@" - Grayscale"];
}
+
+ if (pictureFiltersPresent == YES)
+ {
+ [finalString appendString: @"Filters: " withAttributes:detailBoldAttr];
+ [finalString appendString: pictureFilters withAttributes:detailAttr];
+ [finalString appendString:@"\n" withAttributes:detailAttr];
+ }
+
+ /* Sixth Line Video Details*/
+ NSString * videoInfo;
+ videoInfo = [NSString stringWithFormat:@"Encoder: %@", [item objectForKey:@"VideoEncoder"]];
+
+ /* for framerate look to see if we are using vfr detelecine */
+ if ([[item objectForKey:@"JobIndexVideoFramerate"] intValue] == 0)
+ {
+ if ([[item objectForKey:@"PictureDetelecine"] intValue] == 1)
+ {
+ /* we are using same as source with vfr detelecine */
+ videoInfo = [NSString stringWithFormat:@"%@ Framerate: Same as source (vfr detelecine)", videoInfo];
+ }
+ else
+ {
+ /* we are using a variable framerate without dropping frames */
+ videoInfo = [NSString stringWithFormat:@"%@ Framerate: Same as source (variable)", videoInfo];
+ }
+ }
+ else
+ {
+ /* we have a specified, constant framerate */
+ videoInfo = [NSString stringWithFormat:@"%@ Framerate: %@ (constant framerate)", videoInfo ,[item objectForKey:@"VideoFramerate"]];
+ }
+
+ if ([[item objectForKey:@"VideoQualityType"] intValue] == 0)// Target Size MB
+ {
+ videoInfo = [NSString stringWithFormat:@"%@ Target Size: %@(MB) (%d(kbps) abr)", videoInfo ,[item objectForKey:@"VideoTargetSize"],[[item objectForKey:@"VideoAvgBitrate"] intValue]];
+ }
+ else if ([[item objectForKey:@"VideoQualityType"] intValue] == 1) // ABR
+ {
+ videoInfo = [NSString stringWithFormat:@"%@ Bitrate: %d(kbps)", videoInfo ,[[item objectForKey:@"VideoAvgBitrate"] intValue]];
+ }
+ else // CRF
+ {
+ videoInfo = [NSString stringWithFormat:@"%@ Constant Quality: %.2f", videoInfo ,[[item objectForKey:@"VideoQualitySlider"] floatValue]];
+ }
+
+ [finalString appendString: @"Video: " withAttributes:detailBoldAttr];
+ [finalString appendString: videoInfo withAttributes:detailAttr];
+ [finalString appendString:@"\n" withAttributes:detailAttr];
+
+ if ([[item objectForKey:@"VideoEncoder"] isEqualToString: @"H.264 (x264)"])
+ {
+ [finalString appendString: @"x264 Options: " withAttributes:detailBoldAttr];
+ [finalString appendString: [item objectForKey:@"x264Option"] withAttributes:detailAttr];
+ [finalString appendString:@"\n" withAttributes:detailAttr];
+ }
+
+
+
+ /* Seventh Line Audio Details*/
+ if ([audioDetail1 length] != 0)
+ {
+ [finalString appendString: @"Audio Track 1: " withAttributes:detailBoldAttr];
+ [finalString appendString: audioDetail1 withAttributes:detailAttr];
+ [finalString appendString:@"\n" withAttributes:detailAttr];
+ }
+
+ if ([audioDetail2 length] != 0)
+ {
+ [finalString appendString: @"Audio Track 2: " withAttributes:detailBoldAttr];
+ [finalString appendString: audioDetail2 withAttributes:detailAttr];
+ [finalString appendString:@"\n" withAttributes:detailAttr];
+ }
+
+ if ([audioDetail3 length] != 0)
+ {
+ [finalString appendString: @"Audio Track 3: " withAttributes:detailBoldAttr];
+ [finalString appendString: audioDetail3 withAttributes:detailAttr];
+ [finalString appendString:@"\n" withAttributes:detailAttr];
+ }
+
+ if ([audioDetail4 length] != 0)
+ {
+ [finalString appendString: @"Audio Track 4: " withAttributes:detailBoldAttr];
+ [finalString appendString: audioDetail4 withAttributes:detailAttr];
+ [finalString appendString:@"\n" withAttributes:detailAttr];
+ }
+ /* Eighth Line Subtitle Details */
+
+ int i = 0;
+ NSEnumerator *enumerator = [[item objectForKey:@"SubtitleList"] objectEnumerator];
+ id tempObject;
+ while (tempObject = [enumerator nextObject])
+ {
+ /* since the subtitleSourceTrackNum 0 is "None" in our array of the subtitle popups,
+ * we want to ignore it for display as well as encoding.
+ */
+ if ([[tempObject objectForKey:@"subtitleSourceTrackNum"] intValue] > 0)
+ {
+ /* remember that index 0 of Subtitles can contain "Foreign Audio Search*/
+ [finalString appendString: @"Subtitle: " withAttributes:detailBoldAttr];
+ [finalString appendString: [tempObject objectForKey:@"subtitleSourceTrackName"] withAttributes:detailAttr];
+ if ([[tempObject objectForKey:@"subtitleTrackForced"] intValue] == 1)
+ {
+ [finalString appendString: @" - Forced Only" withAttributes:detailAttr];
+ }
+ if ([[tempObject objectForKey:@"subtitleTrackBurned"] intValue] == 1)
+ {
+ [finalString appendString: @" - Burned In" withAttributes:detailAttr];
+ }
+ if ([[tempObject objectForKey:@"subtitleTrackDefault"] intValue] == 1)
+ {
+ [finalString appendString: @" - Default" withAttributes:detailAttr];
+ }
+ [finalString appendString:@"\n" withAttributes:detailAttr];
+ }
+ i++;
+ }
+
+ return finalString;
}
-*/
-
- else if ([[toolbarItem itemIdentifier] isEqual: HBShowDetailToolbarIdentifier])
+ else if ([[tableColumn identifier] isEqualToString:@"icon"])
{
- enable = hb_count(fHandle) > 0;
- if (fShowsDetail)
+ if ([[item objectForKey:@"Status"] intValue] == 0)
+ {
+ return [NSImage imageNamed:@"EncodeComplete"];
+ }
+ else if ([[item objectForKey:@"Status"] intValue] == 1)
+ {
+ return [NSImage imageNamed: [NSString stringWithFormat: @"EncodeWorking%d", fAnimationIndex]];
+ }
+ else if ([[item objectForKey:@"Status"] intValue] == 3)
{
- [toolbarItem setLabel: @"Hide Detail"];
- [toolbarItem setPaletteLabel: @"Hide Detail"];
- [toolbarItem setToolTip: @"Displays detailed information in the queue"];
+ return [NSImage imageNamed:@"EncodeCanceled"];
}
else
{
- [toolbarItem setLabel: @"Show Detail"];
- [toolbarItem setPaletteLabel: @"Show Detail"];
- [toolbarItem setToolTip: @"Displays detailed information in the queue"];
+ return [NSImage imageNamed:@"JobSmall"];
}
+
+ }
+ else
+ {
+ return @"";
}
-
- return enable;
}
-#pragma mark -
-
-//------------------------------------------------------------------------------------
-// awakeFromNib
-//------------------------------------------------------------------------------------
-- (void)awakeFromNib
+- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
- [self setupToolbar];
-
- if (![fQueueWindow setFrameUsingName:@"Queue"])
- [fQueueWindow center];
- [fQueueWindow setFrameAutosaveName: @"Queue"];
- [fQueueWindow setExcludedFromWindowsMenu:YES];
-
- // Show/hide UI elements
- [self setShowsDetail:fShowsDetail];
- [self setShowsJobsAsGroups:fShowsJobsAsGroups];
- [self showCurrentJobPane:NO];
-}
+ if ([[tableColumn identifier] isEqualToString:@"desc"])
+ {
-//------------------------------------------------------------------------------------
-// windowWillClose
-//------------------------------------------------------------------------------------
-- (void)windowWillClose:(NSNotification *)aNotification
-{
- [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"QueueWindowIsOpen"];
-}
+ // 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.
-#pragma mark -
-#pragma mark NSTableView delegate
+ // 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"])
+ {
+ [cell setEnabled: YES];
+ BOOL highlighted = [outlineView isRowSelected:[outlineView rowForItem: item]] && [[outlineView window] isKeyWindow] && ([[outlineView window] firstResponder] == outlineView);
+ if ([[item objectForKey:@"Status"] intValue] == 0)
+ {
+ [cell setAction: @selector(revealSelectedQueueItem:)];
+ if (highlighted)
+ {
+ [cell setImage:[NSImage imageNamed:@"RevealHighlight"]];
+ [cell setAlternateImage:[NSImage imageNamed:@"RevealHighlightPressed"]];
+ }
+ else
+ [cell setImage:[NSImage imageNamed:@"Reveal"]];
+ }
+ else
+ {
+ [cell setAction: @selector(removeSelectedQueueItem:)];
+ if (highlighted)
+ {
+ [cell setImage:[NSImage imageNamed:@"DeleteHighlight"]];
+ [cell setAlternateImage:[NSImage imageNamed:@"DeleteHighlightPressed"]];
+ }
+ else
+ [cell setImage:[NSImage imageNamed:@"Delete"]];
+ }
+ }
+}
-//------------------------------------------------------------------------------------
-// NSTableView delegate
-//------------------------------------------------------------------------------------
-- (int)numberOfRowsInTableView: (NSTableView *)aTableView
+- (void)outlineView:(NSOutlineView *)outlineView willDisplayOutlineCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
{
- BOOL jobGroups = [[NSUserDefaults standardUserDefaults] boolForKey:@"QueueShowsJobsAsGroups"];
- if (jobGroups)
- return hb_group_count(fHandle);
+ // By default, the discolsure image gets centered vertically in the cell. We want
+ // always at the top.
+ if ([outlineView isItemExpanded: item])
+ [cell setImagePosition: NSImageAbove];
else
- return hb_count(fHandle);
+ [cell setImagePosition: NSImageOnly];
}
+#pragma mark -
+#pragma mark NSOutlineView delegate (dragging related)
+
//------------------------------------------------------------------------------------
// NSTableView delegate
//------------------------------------------------------------------------------------
-- (id)tableView: (NSTableView *)aTableView
- objectValueForTableColumn: (NSTableColumn *)aTableColumn
- row: (int)rowIndex
-{
- if (!fHandle)
- return @""; // fatal error!
-
- hb_job_t * job;
- BOOL jobGroups = [[NSUserDefaults standardUserDefaults] boolForKey:@"QueueShowsJobsAsGroups"];
- if (jobGroups)
- job = hb_group(fHandle, rowIndex);
- else
- job = hb_job(fHandle, rowIndex);
-
- if (!job)
- return @""; // fatal error!
- if ([[aTableColumn identifier] isEqualToString:@"desc"])
+- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard
+{
+ // Dragging is only allowed of the pending items.
+ if ([[[items objectAtIndex:0] objectForKey:@"Status"] integerValue] != 2) // 2 is pending
{
- BOOL highlighted = [aTableView isRowSelected:rowIndex] && [[aTableView window] isKeyWindow] && ([[aTableView window] firstResponder] == aTableView);
- return [self attributedDescriptionForJob:job withDetail:fShowsDetail withHighlighting:highlighted];
+ return NO;
}
- else if ([[aTableColumn identifier] isEqualToString:@"delete"])
- return @"";
-
- else if ([[aTableColumn identifier] isEqualToString:@"icon"])
- return fShowsJobsAsGroups ? [NSImage imageNamed:@"JobSmall"] : [NSImage imageNamed:@"JobPassSmall"];
-
- return @"";
+ // 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;
+
+ // Provide data for our custom type, and simple NSStrings.
+ [pboard declareTypes:[NSArray arrayWithObjects: DragDropSimplePboardType, nil] 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;
}
-//------------------------------------------------------------------------------------
-// NSTableView delegate
-//------------------------------------------------------------------------------------
-- (void)tableView: (NSTableView *)aTableView
- willDisplayCell: (id)aCell
- forTableColumn: (NSTableColumn *)aTableColumn
- row: (int)rowIndex
+
+/* This method is used to validate the drops. */
+- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
{
- if ([[aTableColumn identifier] isEqualToString:@"delete"])
+ // Don't allow dropping ONTO an item since they can't really contain any children.
+ BOOL isOnDropTypeProposal = index == NSOutlineViewDropOnItemIndex;
+ if (isOnDropTypeProposal)
{
- BOOL highlighted = [aTableView isRowSelected:rowIndex] && [[aTableView window] isKeyWindow] && ([[aTableView window] firstResponder] == aTableView);
- if (highlighted)
- {
- [aCell setImage:[NSImage imageNamed:@"DeleteHighlight"]];
- [aCell setAlternateImage:[NSImage imageNamed:@"DeleteHighlightPressed"]];
- }
- else
- {
- [aCell setImage:[NSImage imageNamed:@"Delete"]];
- }
+ return NSDragOperationNone;
+ }
+
+ // Don't allow dropping INTO an item since they can't really contain any children.
+ if (item != nil)
+ {
+ index = [fOutlineView 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)
+ {
+ return NSDragOperationNone;
+ index = MAX (index, fEncodingQueueItem);
+ }
+
+ [outlineView setDropItem:item dropChildIndex:index];
+ return NSDragOperationGeneric;
}
+- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index
+{
+ NSMutableIndexSet *moveItems = [NSMutableIndexSet indexSet];
+
+ for( id obj in fDraggedNodes )
+ [moveItems addIndex:[fJobGroups 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];
+ return YES;
+}
+
+
@end