summaryrefslogtreecommitdiffstats
path: root/macosx/HBQueueController.mm
diff options
context:
space:
mode:
authordynaflash <[email protected]>2007-12-17 16:25:38 +0000
committerdynaflash <[email protected]>2007-12-17 16:25:38 +0000
commit4a53d572a85a263e54bcc32c2c945c93f4c77a68 (patch)
treec20b44126a537723b12e3fcfe34edb5e79beda69 /macosx/HBQueueController.mm
parent1ca7105bb474fee3829eaf98c75177e21bf54744 (diff)
MacGui: Queue Update - thanks travistex
- The primary change is that HBJob now copies the relevant fields out of hb_job_s that it needs. It no longer keeps a pointer reference to libhb's job. - The only time the queue looks at libhb's jobs is when scanning the job list in order to build of the GUI queue display. - Removed all uses of hb_current_job(). - Canceled jobs now stay listed in the queue, with a canceled icon. git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@1130 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'macosx/HBQueueController.mm')
-rw-r--r--macosx/HBQueueController.mm572
1 files changed, 328 insertions, 244 deletions
diff --git a/macosx/HBQueueController.mm b/macosx/HBQueueController.mm
index fa307e837..428956d60 100644
--- a/macosx/HBQueueController.mm
+++ b/macosx/HBQueueController.mm
@@ -13,6 +13,19 @@
// Pasteboard type for or drag operations
#define HBQueuePboardType @"HBQueuePboardType"
+//------------------------------------------------------------------------------------
+// Job ID Utilities
+//------------------------------------------------------------------------------------
+
+int MakeJobID(int jobGroupID, int sequenceNum)
+{
+ return jobGroupID<<16 | sequenceNum;
+}
+
+bool IsFirstPass(int jobID)
+{
+ return LoWord(jobID) == 0;
+}
//------------------------------------------------------------------------------------
// NSMutableAttributedString (HBAdditions)
@@ -100,7 +113,7 @@ static int hb_group_count(hb_handle_t * h)
int index = 0;
while( ( job = hb_job( h, index++ ) ) )
{
- if (job->sequence_id == 0)
+ if (IsFirstPass(job->sequence_id))
count++;
}
return count;
@@ -119,7 +132,7 @@ static hb_job_t * hb_group(hb_handle_t * h, int i)
int index = 0;
while( ( job = hb_job( h, index++ ) ) )
{
- if (job->sequence_id == 0)
+ if (IsFirstPass(job->sequence_id))
{
if (count == i)
return job;
@@ -145,7 +158,7 @@ static void hb_rem_group( hb_handle_t * h, hb_job_t * 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) )
+ while( ( j = hb_job( h, index ) ) && ( !IsFirstPass(j->sequence_id ) ) )
hb_rem( h, j );
return;
}
@@ -189,23 +202,80 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
{
if (self = [super init])
{
- // job is not owned by HBJob. It does not get dealloacted when HBJob is released.
- hbJob = job;
+ sequence_id = job->sequence_id;
+
+ chapter_start = job->chapter_start;
+ chapter_end = job->chapter_end;
+ chapter_markers = job->chapter_markers;
+ memcpy(crop, job->crop, sizeof(crop));
+ deinterlace = job->deinterlace;
+ width = job->width;
+ height = job->height;
+ keep_ratio = job->keep_ratio;
+ grayscale = job->grayscale;
+ pixel_ratio = job->pixel_ratio;
+ pixel_aspect_width = job->pixel_aspect_width;
+ pixel_aspect_height = job->pixel_aspect_height;
+ vcodec = job->vcodec;
+ vquality = job->vquality;
+ vbitrate = job->vbitrate;
+ vrate = job->vrate;
+ vrate_base = job->vrate_base;
+ pass = job->pass;
+ h264_level = job->h264_level;
+ crf = job->crf;
+ if (job->x264opts)
+ x264opts = [[NSString stringWithUTF8String:job->x264opts] retain];
+ memcpy(audio_mixdowns, job->audio_mixdowns, sizeof(audio_mixdowns));
+ acodec = job->acodec;
+ abitrate = job->abitrate;
+ arate = job->arate;
+ subtitle = job->subtitle;
+ mux = job->mux;
+ if (job->file)
+ file = [[NSString stringWithUTF8String:job->file] retain];
+ if (job->title->name)
+ titleName = [[NSString stringWithUTF8String:job->title->name] retain];
+ titleIndex = job->title->index;
+ titleWidth = job->title->width;
+ titleHeight = job->title->height;
+ if (job->subtitle >= 0)
+ {
+ hb_subtitle_t * aSubtitle = (hb_subtitle_t *) hb_list_item(job->title->list_subtitle, 0);
+ if (aSubtitle)
+ subtitleLang = [[NSString stringWithUTF8String:aSubtitle->lang] retain];
+ }
+
}
- return self;
+ return self;
+}
+
+- (void) dealloc
+{
+ // jobGroup is a weak reference and does not need to be deleted
+ [x264opts release];
+ [file release];
+ [titleName release];
+ [subtitleLang release];
+ [super dealloc];
}
-- (hb_job_t*) job
+- (HBJobGroup *) jobGroup
{
- return hbJob;
+ return jobGroup;
+}
+
+- (void) setJobGroup: (HBJobGroup *)aJobGroup
+{
+ // This is a weak reference. We don't retain or release it.
+ jobGroup = aJobGroup;
}
//------------------------------------------------------------------------------------
// Generate string to display in UI.
//------------------------------------------------------------------------------------
-- (NSMutableAttributedString *) attributedDescriptionWithHBHandle: (hb_handle_t *)handle
- withIcon: (BOOL)withIcon
+- (NSMutableAttributedString *) attributedDescriptionWithIcon: (BOOL)withIcon
withTitle: (BOOL)withTitle
withPassName: (BOOL)withPassName
withFormatInfo: (BOOL)withFormatInfo
@@ -219,8 +289,6 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
{
NSMutableAttributedString * finalString = [[[NSMutableAttributedString alloc] initWithString: @""] autorelease];
- hb_title_t * title = hbJob->title;
-
// Attributes
static NSMutableParagraphStyle * ps = NULL;
if (!ps)
@@ -271,15 +339,15 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
// Note: use title->name instead of title->dvd since name is just the chosen
// folder, instead of dvd which is the full path
- [finalString appendString:[NSString stringWithUTF8String:title->name] withAttributes:titleAttribute];
+ [finalString appendString:titleName withAttributes:titleAttribute];
NSString * summaryInfo;
- NSString * chapterString = (hbJob->chapter_start == hbJob->chapter_end) ?
- [NSString stringWithFormat:@"Chapter %d", hbJob->chapter_start] :
- [NSString stringWithFormat:@"Chapters %d through %d", hbJob->chapter_start, hbJob->chapter_end];
+ NSString * chapterString = (chapter_start == chapter_end) ?
+ [NSString stringWithFormat:@"Chapter %d", chapter_start] :
+ [NSString stringWithFormat:@"Chapters %d through %d", chapter_start, chapter_end];
- BOOL hasIndepthScan = (hbJob->pass == -1);
+ BOOL hasIndepthScan = (pass == -1);
int numVideoPasses = 0;
// To determine number of video passes, we need to skip past the subtitle scan.
@@ -287,25 +355,24 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
{
// 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 (hbJob == hb_current_job(handle))
- nextjob = hb_job(handle, 0);
- else
- nextjob = hb_next_job(handle, hbJob);
+ HBJob * nextjob = nil;
+ unsigned int index = [jobGroup indexOfJob:self];
+ if (index != NSNotFound)
+ nextjob = [jobGroup jobAtIndex:index+1];
if (nextjob) // Overly cautious in case there is no next job!
numVideoPasses = MIN( 2, nextjob->pass + 1 );
}
else
- numVideoPasses = MIN( 2, hbJob->pass + 1 );
+ numVideoPasses = MIN( 2, pass + 1 );
if (hasIndepthScan && numVideoPasses == 1)
- summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Deep Scan, Single Video Pass)", title->index, chapterString];
+ summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Deep Scan, Single Video Pass)", titleIndex, chapterString];
else if (hasIndepthScan && numVideoPasses > 1)
- summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Deep Scan, %d Video Passes)", title->index, chapterString, numVideoPasses];
+ summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Deep Scan, %d Video Passes)", titleIndex, chapterString, numVideoPasses];
else if (numVideoPasses == 1)
- summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Single Video Pass)", title->index, chapterString];
+ summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Single Video Pass)", titleIndex, chapterString];
else
- summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, %d Video Passes)", title->index, chapterString, numVideoPasses];
+ summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, %d Video Passes)", titleIndex, chapterString, numVideoPasses];
[finalString appendString:[NSString stringWithFormat:@"%@\n", summaryInfo] withAttributes:detailAttribute];
@@ -322,7 +389,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
if (withIcon)
{
NSString * imageName;
- switch (hbJob->pass)
+ switch (pass)
{
case -1: imageName = @"JobPassSubtitleSmall"; break;
case 0: imageName = @"JobPassFirstSmall"; break;
@@ -348,11 +415,11 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
}
NSString * jobPassName;
- if (hbJob->pass == -1)
+ if (pass == -1)
jobPassName = NSLocalizedString (@"Deep Scan", nil);
else
{
- int passNum = MAX( 1, hbJob->pass );
+ int passNum = MAX( 1, pass );
if (passNum == 0)
jobPassName = NSLocalizedString (@"1st Pass", nil);
else if (passNum == 1)
@@ -371,14 +438,14 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
{
// 2097152
// Video Codec settings (Encoder in the gui)
- if (hbJob->vcodec == HB_VCODEC_FFMPEG)
+ if (vcodec == HB_VCODEC_FFMPEG)
jobVideoCodec = @"FFmpeg"; // HB_VCODEC_FFMPEG
- else if (hbJob->vcodec == HB_VCODEC_XVID)
+ else if (vcodec == HB_VCODEC_XVID)
jobVideoCodec = @"XviD"; // HB_VCODEC_XVID
- else if (hbJob->vcodec == HB_VCODEC_X264)
+ else if (vcodec == HB_VCODEC_X264)
{
// Deterimine for sure how we are now setting iPod uuid atom
- if (hbJob->h264_level) // We are encoding for iPod
+ if (h264_level) // We are encoding for iPod
jobVideoCodec = @"x264 (H.264 iPod)"; // HB_VCODEC_X264
else
jobVideoCodec = @"x264 (H.264 Main)"; // HB_VCODEC_X264
@@ -391,13 +458,13 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
NSString * jobAudioCodec = nil;
if (withFormatInfo || withAudioInfo)
{
- if (hbJob->acodec == 256)
+ if (acodec == 256)
jobAudioCodec = @"AAC"; // HB_ACODEC_FAAC
- else if (hbJob->acodec == 512)
+ else if (acodec == 512)
jobAudioCodec = @"MP3"; // HB_ACODEC_LAME
- else if (hbJob->acodec == 1024)
+ else if (acodec == 1024)
jobAudioCodec = @"Vorbis"; // HB_ACODEC_VORBIS
- else if (hbJob->acodec == 2048)
+ else if (acodec == 2048)
jobAudioCodec = @"AC3"; // HB_ACODEC_AC3
}
if (jobAudioCodec == nil)
@@ -408,18 +475,18 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
{
NSString * jobFormatInfo;
// Muxer settings (File Format in the gui)
- if (hbJob->mux == 65536 || hbJob->mux == 131072 || hbJob->mux == 1048576)
+ if (mux == 65536 || mux == 131072 || mux == 1048576)
jobFormatInfo = @"MP4"; // HB_MUX_MP4,HB_MUX_PSP,HB_MUX_IPOD
- else if (hbJob->mux == 262144)
+ else if (mux == 262144)
jobFormatInfo = @"AVI"; // HB_MUX_AVI
- else if (hbJob->mux == 524288)
+ else if (mux == 524288)
jobFormatInfo = @"OGM"; // HB_MUX_OGM
- else if (hbJob->mux == 2097152)
+ else if (mux == 2097152)
jobFormatInfo = @"MKV"; // HB_MUX_MKV
else
jobFormatInfo = @"unknown";
- if (hbJob->chapter_markers == 1)
+ if (chapter_markers == 1)
jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video + %@ Audio, Chapter Markers\n", jobFormatInfo, jobVideoCodec, jobAudioCodec];
else
jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video + %@ Audio\n", jobFormatInfo, jobVideoCodec, jobAudioCodec];
@@ -431,7 +498,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
if (withDestination)
{
[finalString appendString: @"Destination: " withAttributes:detailBoldAttribute];
- [finalString appendString:[NSString stringWithFormat:@"%@\n", [NSString stringWithUTF8String:hbJob->file]] withAttributes:detailAttribute];
+ [finalString appendString:[NSString stringWithFormat:@"%@\n", file] withAttributes:detailAttribute];
}
@@ -440,22 +507,22 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
NSString * jobPictureInfo;
// integers for picture values deinterlace, crop[4], keep_ratio, grayscale, pixel_ratio, pixel_aspect_width, pixel_aspect_height,
// maxWidth, maxHeight
- if (hbJob->pixel_ratio == 1)
+ if (pixel_ratio == 1)
{
- int titlewidth = title->width - hbJob->crop[2] - hbJob->crop[3];
- int displayparwidth = titlewidth * hbJob->pixel_aspect_width / hbJob->pixel_aspect_height;
- int displayparheight = title->height - hbJob->crop[0] - hbJob->crop[1];
- jobPictureInfo = [NSString stringWithFormat:@"%dx%d (%dx%d Anamorphic)", displayparwidth, displayparheight, hbJob->width, displayparheight];
+ int croppedWidth = titleWidth - crop[2] - crop[3];
+ int displayparwidth = croppedWidth * pixel_aspect_width / pixel_aspect_height;
+ int displayparheight = titleHeight - crop[0] - crop[1];
+ jobPictureInfo = [NSString stringWithFormat:@"%dx%d (%dx%d Anamorphic)", displayparwidth, displayparheight, width, displayparheight];
}
else
- jobPictureInfo = [NSString stringWithFormat:@"%dx%d", hbJob->width, hbJob->height];
- if (hbJob->keep_ratio == 1)
+ jobPictureInfo = [NSString stringWithFormat:@"%dx%d", width, height];
+ if (keep_ratio == 1)
jobPictureInfo = [jobPictureInfo stringByAppendingString:@" Keep Aspect Ratio"];
- if (hbJob->grayscale == 1)
+ if (grayscale == 1)
jobPictureInfo = [jobPictureInfo stringByAppendingString:@", Grayscale"];
- if (hbJob->deinterlace == 1)
+ if (deinterlace == 1)
jobPictureInfo = [jobPictureInfo stringByAppendingString:@", Deinterlace"];
if (withIcon) // implies indent the info
[finalString appendString: @"\t" withAttributes:detailBoldAttribute];
@@ -468,25 +535,25 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
NSString * jobVideoQuality;
NSString * jobVideoDetail;
- if (hbJob->vquality <= 0 || hbJob->vquality >= 1)
- jobVideoQuality = [NSString stringWithFormat:@"%d kbps", hbJob->vbitrate];
+ if (vquality <= 0 || vquality >= 1)
+ jobVideoQuality = [NSString stringWithFormat:@"%d kbps", vbitrate];
else
{
NSNumber * vidQuality;
- vidQuality = [NSNumber numberWithInt:hbJob->vquality * 100];
+ vidQuality = [NSNumber numberWithInt:vquality * 100];
// this is screwed up kind of. Needs to be formatted properly.
- if (hbJob->crf == 1)
+ if (crf == 1)
jobVideoQuality = [NSString stringWithFormat:@"%@%% CRF", vidQuality];
else
jobVideoQuality = [NSString stringWithFormat:@"%@%% CQP", vidQuality];
}
- if (hbJob->vrate_base == 1126125)
+ if (vrate_base == 1126125)
{
// NTSC FILM 23.976
jobVideoDetail = [NSString stringWithFormat:@"%@, %@, 23.976 fps", jobVideoCodec, jobVideoQuality];
}
- else if (hbJob->vrate_base == 900900)
+ else if (vrate_base == 900900)
{
// NTSC 29.97
jobVideoDetail = [NSString stringWithFormat:@"%@, %@, 29.97 fps", jobVideoCodec, jobVideoQuality];
@@ -494,7 +561,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
else
{
// Everything else
- jobVideoDetail = [NSString stringWithFormat:@"%@, %@, %d fps", jobVideoCodec, jobVideoQuality, hbJob->vrate / hbJob->vrate_base];
+ jobVideoDetail = [NSString stringWithFormat:@"%@, %@, %d fps", jobVideoCodec, jobVideoQuality, vrate / vrate_base];
}
if (withIcon) // implies indent the info
[finalString appendString: @"\t" withAttributes:detailBoldAttribute];
@@ -504,12 +571,12 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
if (withx264Info)
{
- if (hbJob->vcodec == HB_VCODEC_X264 && hbJob->x264opts)
+ if (vcodec == HB_VCODEC_X264 && x264opts)
{
if (withIcon) // implies indent the info
[finalString appendString: @"\t" withAttributes:detailBoldAttribute];
[finalString appendString: @"x264 Options: " withAttributes:detailBoldAttribute];
- [finalString appendString:[NSString stringWithFormat:@"%@\n", [NSString stringWithUTF8String:hbJob->x264opts]] withAttributes:detailAttribute];
+ [finalString appendString:[NSString stringWithFormat:@"%@\n", x264opts] withAttributes:detailAttribute];
}
}
@@ -519,7 +586,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
if ([jobAudioCodec isEqualToString: @"AC3"])
jobAudioInfo = [NSString stringWithFormat:@"%@, Pass-Through", jobAudioCodec];
else
- jobAudioInfo = [NSString stringWithFormat:@"%@, %d kbps, %d Hz", jobAudioCodec, hbJob->abitrate, hbJob->arate];
+ jobAudioInfo = [NSString stringWithFormat:@"%@, %d kbps, %d Hz", jobAudioCodec, abitrate, 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.
@@ -527,15 +594,15 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
int ai; // counter for each audios [] , macgui only allows for two audio tracks currently
for( ai = 0; ai < 2; ai++ )
{
- if (hbJob->audio_mixdowns[ai] == HB_AMIXDOWN_MONO)
+ if (audio_mixdowns[ai] == HB_AMIXDOWN_MONO)
jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Mono", ai + 1]];
- if (hbJob->audio_mixdowns[ai] == HB_AMIXDOWN_STEREO)
+ if (audio_mixdowns[ai] == HB_AMIXDOWN_STEREO)
jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Stereo", ai + 1]];
- if (hbJob->audio_mixdowns[ai] == HB_AMIXDOWN_DOLBY)
+ if (audio_mixdowns[ai] == HB_AMIXDOWN_DOLBY)
jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Dolby Surround", ai + 1]];
- if (hbJob->audio_mixdowns[ai] == HB_AMIXDOWN_DOLBYPLII)
+ if (audio_mixdowns[ai] == HB_AMIXDOWN_DOLBYPLII)
jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Dolby Pro Logic II", ai + 1]];
- if (hbJob->audio_mixdowns[ai] == HB_AMIXDOWN_6CH)
+ if (audio_mixdowns[ai] == HB_AMIXDOWN_6CH)
jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: 6-channel discreet", ai + 1]];
}
if (withIcon) // implies indent the info
@@ -546,25 +613,24 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
if (withSubtitleInfo)
{
- // hbJob->subtitle can == -1 in two cases:
+ // subtitle can == -1 in two cases:
// autoselect: when pass == -1
// none: when pass != -1
- if ((hbJob->subtitle == -1) && (hbJob->pass == -1))
+ if ((subtitle == -1) && (pass == -1))
{
if (withIcon) // implies indent the info
[finalString appendString: @"\t" withAttributes:detailBoldAttribute];
[finalString appendString: @"Subtitles: " withAttributes:detailBoldAttribute];
[finalString appendString: @"Autoselect " withAttributes:detailAttribute];
}
- else if (hbJob->subtitle >= 0)
+ else if (subtitle >= 0)
{
- hb_subtitle_t * subtitle = (hb_subtitle_t *) hb_list_item( title->list_subtitle, 0 );
- if (subtitle)
+ if (subtitleLang)
{
if (withIcon) // implies indent the info
[finalString appendString: @"\t" withAttributes:detailBoldAttribute];
[finalString appendString: @"Subtitles: " withAttributes:detailBoldAttribute];
- [finalString appendString: [NSString stringWithCString: subtitle->lang] withAttributes:detailAttribute];
+ [finalString appendString: subtitleLang withAttributes:detailAttribute];
}
}
}
@@ -606,7 +672,6 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
- (void) dealloc
{
[fJobs release];
- [fPath release];
[super dealloc];
}
@@ -617,17 +682,13 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
- (void) addJob: (HBJob *)aJob
{
+ [aJob setJobGroup:self];
[fJobs addObject: aJob];
[self setNeedsDescription: YES];
fLastDescriptionHeight = 0;
fLastDescriptionWidth = 0;
}
-- (void) removeAllJobs
-{
- [fJobs removeAllObjects];
-}
-
- (HBJob *) jobAtIndex: (unsigned)index
{
return [fJobs objectAtIndex: index];
@@ -648,7 +709,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
fNeedsDescription = flag;
}
-- (void) updateDescriptionWithHBHandle: (hb_handle_t *)handle
+- (void) updateDescription
{
fNeedsDescription = NO;
@@ -662,8 +723,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
HBJob * job = [self jobAtIndex:0];
- [fDescription appendAttributedString: [job attributedDescriptionWithHBHandle: handle
- withIcon: NO
+ [fDescription appendAttributedString: [job attributedDescriptionWithIcon: NO
withTitle: YES
withPassName: NO
withFormatInfo: YES
@@ -679,11 +739,10 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
NSEnumerator * e = [self jobEnumerator];
while ( (job = [e nextObject]) )
{
- int pass = [job job]->pass;
+ int pass = job->pass;
[fDescription appendAttributedString:carriageReturn];
[fDescription appendAttributedString:
- [job attributedDescriptionWithHBHandle: handle
- withIcon: YES
+ [job attributedDescriptionWithIcon: YES
withTitle: NO
withPassName: YES
withFormatInfo: NO
@@ -697,21 +756,21 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
}
-- (NSMutableAttributedString *) attributedDescriptionWithHBHandle: (hb_handle_t *)handle
+- (NSMutableAttributedString *) attributedDescription
{
if (fNeedsDescription)
- [self updateDescriptionWithHBHandle: handle];
+ [self updateDescription];
return fDescription;
}
-- (float) heightOfDescriptionForWidth:(float)width withHBHandle: (hb_handle_t *)handle
+- (float) heightOfDescriptionForWidth:(float)width
{
// 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 updateDescriptionWithHBHandle: handle];
+ [self updateDescription];
// Calculate the height
NSRect bounds = [fDescription boundingRectWithSize:NSMakeSize(width, 10000) options:NSStringDrawingUsesLineFragmentOrigin];
@@ -748,16 +807,16 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job )
return self->fStatus;
}
-- (void) setPath: (NSString *)path
+- (NSString *) name
{
- [path retain];
- [fPath release];
- fPath = path;
+ HBJob * firstJob = [self jobAtIndex:0];
+ return firstJob ? firstJob->titleName : nil;
}
- (NSString *) path
{
- return fPath;
+ HBJob * firstJob = [self jobAtIndex:0];
+ return firstJob ? firstJob->file : nil;
}
@end
@@ -837,6 +896,24 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
}
//------------------------------------------------------------------------------------
+// Returns the HBJobGroup that is currently being encoded; nil if no encoding is
+// occurring.
+//------------------------------------------------------------------------------------
+- (HBJobGroup *) currentJobGroup;
+{
+ return fCurrentJobGroup;
+}
+
+//------------------------------------------------------------------------------------
+// Returns the HBJob (pass) that is currently being encoded; nil if no encoding is
+// occurring.
+//------------------------------------------------------------------------------------
+- (HBJob *) currentJob
+{
+ return fCurrentJob;
+}
+
+//------------------------------------------------------------------------------------
// Displays and brings the queue window to the front
//------------------------------------------------------------------------------------
- (IBAction) showQueueWindow: (id)sender
@@ -845,6 +922,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
[fQueueWindow makeKeyAndOrderFront: self];
[[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"QueueWindowIsOpen"];
}
+
//------------------------------------------------------------------------------------
// Show or hide the current job pane (fCurrentJobPane).
//------------------------------------------------------------------------------------
@@ -897,7 +975,14 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
- (void)rebuildJobGroups
{
- // Currently, job groups are rdered like this:
+ // This method is called every time we detect that hblib has changed its job list.
+ // It releases the previous job group list and rebuilds it by reading the current
+ // list of jobs from libhb. libhb does not implement job groups/encodes itself. It
+ // just maintains a simply list of jobs. The queue controller however, presents
+ // these jobs to the user organized into encodes where all jobs associated with
+ // the same encode are grouped into a logical job group/encode.
+
+ // Currently, job groups are ordered like this:
// Completed job groups
// Current job group
// Pending job groups
@@ -908,7 +993,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
// Add all the completed job groups
[fJobGroups addObjectsFromArray: fCompleted];
- // Add all the completed job groups
+ // Add the current job group
if (fCurrentJobGroup)
[fJobGroups addObject: fCurrentJobGroup];
@@ -921,7 +1006,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
hb_job_t * nextJob = hb_group( fHandle, 0 );
while( nextJob )
{
- if (nextJob->sequence_id == 0)
+ if (IsFirstPass(nextJob->sequence_id))
{
// Encountered a new group. Add the current one to fJobGroups and then start a new one.
if ([aJobGroup count] > 0)
@@ -932,7 +1017,6 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
}
}
[aJobGroup addJob: [HBJob jobWithJob:nextJob]];
- [aJobGroup setPath: [NSString stringWithUTF8String:nextJob->file]];
nextJob = hb_next_job (fHandle, nextJob);
}
if ([aJobGroup count] > 0)
@@ -943,68 +1027,70 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
}
//------------------------------------------------------------------------------------
-// Adds aJobGroup to the list of completed job groups, marking its status as
-// HBStatusComplete.
+// Adds aJobGroup to the list of completed job groups. The completed list is
+// maintained by the queue, since libhb deletes all its jobs after they are complete.
//------------------------------------------------------------------------------------
- (void) addCompletedJobGroup: (HBJobGroup *)aJobGroup
{
- // Once hblib has completed its work, the hb_job_t objects will be freed, so we
- // can't keep a reference to them.
- [aJobGroup removeAllJobs];
-
- [aJobGroup setStatus: HBStatusComplete];
-
- // Put the group in the completed list for permanent storage, and also rebuild
- // the master job group list which contains completed and pending groups.
+ // Put the group in the completed list for permanent storage.
[fCompleted addObject: aJobGroup];
}
-- (void) setCurrentJobGroupFromJob: (hb_job_t *)aJob
+//------------------------------------------------------------------------------------
+// Sets fCurrentJobGroup to a new job group.
+//------------------------------------------------------------------------------------
+- (void) setCurrentJobGroup: (HBJobGroup *)aJobGroup
{
- HBJobGroup * aJobGroup = nil;
-
- // Try to find this new group in our existing job groups.
- if (aJob)
+ if (aJobGroup)
+ [aJobGroup setStatus: HBStatusWorking];
+
+ [aJobGroup retain];
+ [fCurrentJobGroup release];
+ fCurrentJobGroup = aJobGroup;
+}
+
+//------------------------------------------------------------------------------------
+// Locates and returns a HBJob whose sequence_id matches a specified value.
+//------------------------------------------------------------------------------------
+- (HBJob *) findJobWithID: (int)aJobID
+{
+ HBJobGroup * aJobGroup;
+ NSEnumerator * groupEnum = [fJobGroups objectEnumerator];
+ while ( (aJobGroup = [groupEnum nextObject]) )
{
- BOOL found = NO;
- NSEnumerator * groupEnum = [fJobGroups objectEnumerator];
- while ( !found && (aJobGroup = [groupEnum nextObject]) )
+ HBJob * job;
+ NSEnumerator * jobEnum = [aJobGroup jobEnumerator];
+ while ( (job = [jobEnum nextObject]) )
{
- HBJob * j;
- NSEnumerator * jobEnum = [aJobGroup jobEnumerator];
- while ( !found && (j = [jobEnum nextObject]) )
- {
- if ([j job] == aJob)
- found = YES;
- }
+ if (job->sequence_id == aJobID)
+ return job;
}
-
- // Or create the job group.
- if (!aJobGroup)
- {
- aJobGroup = [HBJobGroup jobGroup];
- [aJobGroup addJob: [HBJob jobWithJob: aJob]];
- [aJobGroup setPath: [NSString stringWithUTF8String:aJob->file]];
- while ( (aJob = hb_next_job(fHandle, aJob)) && (aJob->sequence_id != 0) )
- [aJobGroup addJob: [HBJob jobWithJob: aJob]];
+ }
+ return nil;
+}
- [aJobGroup updateDescriptionWithHBHandle: fHandle];
- }
-
- [aJobGroup setStatus: HBStatusWorking];
+//------------------------------------------------------------------------------------
+// Locates and returns a libhb job whose sequence_id matches a specified value.
+//------------------------------------------------------------------------------------
+- (hb_job_t *) findLibhbJobWithID: (int)aJobID
+{
+ hb_job_t * job;
+ int index = 0;
+ while( ( job = hb_job( fHandle, index++ ) ) )
+ {
+ if (job->sequence_id == aJobID)
+ return job;
}
-
- [aJobGroup retain];
- [fCurrentJobGroup release];
- fCurrentJobGroup = aJobGroup;
+ return nil;
}
#pragma mark -
#pragma mark UI Updating
//------------------------------------------------------------------------------------
-// Saves the state of the items that are currently expanded. Calling restoreOutlineViewState
-// will restore the state of all items to match what was saved by saveOutlineViewState.
+// Saves the state of the items that are currently expanded and selected. Calling
+// restoreOutlineViewState will restore the state of all items to match what was saved
+// by saveOutlineViewState. Nested calls to saveOutlineViewState are not supported.
//------------------------------------------------------------------------------------
- (void) saveOutlineViewState
{
@@ -1013,29 +1099,18 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
else
[fSavedExpandedItems removeAllIndexes];
- // NB: This code is stuffing the address of each job into an index set. While it
- // works 99.9% of the time, it's not the ideal solution. We need unique ids in
- // each job, possibly using the existing sequence_id field. Could use the high
- // word as a unique encode id and the low word the sequence number.
+ // This code stores the sequence_id of the first job of each job group into an
+ // index set. This is sufficient to identify each group uniquely.
HBJobGroup * aJobGroup;
NSEnumerator * e = [fJobGroups objectEnumerator];
while ( (aJobGroup = [e nextObject]) )
{
if ([fOutlineView isItemExpanded: aJobGroup])
- {
- if ([aJobGroup status] == HBStatusComplete)
- [fSavedExpandedItems addIndex: (unsigned int)aJobGroup];
- else
- [fSavedExpandedItems addIndex: (unsigned int)[[aJobGroup jobAtIndex:0] job]];
- }
+ [fSavedExpandedItems addIndex: [aJobGroup jobAtIndex:0]->sequence_id];
}
- // Save the selection also. This is really UGLY code. Since I have to rebuild the
- // entire outline hierachy every time hblib changes its job list, there's no easy
- // way for me to remember the selection state other than saving off the first
- // hb_job_t item in each selected group. This is done by saving the object's
- // address. This could go away if I'd save a unique id in each job object.
+ // Save the selection also.
if (!fSavedSelectedItems)
fSavedSelectedItems = [[NSMutableIndexSet alloc] init];
@@ -1047,10 +1122,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
while (row != NSNotFound)
{
aJobGroup = [fOutlineView itemAtRow: row];
- if ([aJobGroup status] == HBStatusComplete)
- [fSavedSelectedItems addIndex: (unsigned int)aJobGroup];
- else
- [fSavedSelectedItems addIndex: (unsigned int)[[aJobGroup jobAtIndex:0] job]];
+ [fSavedSelectedItems addIndex: [aJobGroup jobAtIndex:0]->sequence_id];
row = [selectedRows indexGreaterThanIndex: row];
}
@@ -1068,40 +1140,24 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
NSEnumerator * e = [fJobGroups objectEnumerator];
while ( (aJobGroup = [e nextObject]) )
{
- if ([aJobGroup status] == HBStatusComplete)
- {
- if ([fSavedExpandedItems containsIndex: (unsigned int)aJobGroup])
- [fOutlineView expandItem: aJobGroup];
- }
- else
- {
- hb_job_t * j = [[aJobGroup jobAtIndex:0] job];
- if ([fSavedExpandedItems containsIndex: (unsigned int)j])
- [fOutlineView expandItem: aJobGroup];
- }
+ HBJob * job = [aJobGroup jobAtIndex:0];
+ if (job && [fSavedExpandedItems containsIndex: job->sequence_id])
+ [fOutlineView expandItem: aJobGroup];
}
}
if (fSavedSelectedItems)
{
- // Ugh. Have to cycle through each row looking for the previously selected job.
- // See the explanation in saveOutlineViewState about the logic here.
-
NSMutableIndexSet * rowsToSelect = [[[NSMutableIndexSet alloc] init] autorelease];
- for (int i = 0; i < [fOutlineView numberOfRows]; i++)
+ HBJobGroup * aJobGroup;
+ NSEnumerator * e = [fJobGroups objectEnumerator];
+ int i = 0;
+ while ( (aJobGroup = [e nextObject]) )
{
- HBJobGroup * aJobGroup = [fOutlineView itemAtRow: i];
- // Test to see if the group or the group's first job is a match
- if ([aJobGroup status] == HBStatusComplete)
- {
- if ([fSavedSelectedItems containsIndex: (unsigned int)aJobGroup])
- [rowsToSelect addIndex: i];
- }
- else
- {
- if ([fSavedSelectedItems containsIndex: (unsigned int)[[aJobGroup jobAtIndex:0] job]])
- [rowsToSelect addIndex: i];
- }
+ HBJob * job = [aJobGroup jobAtIndex:0];
+ if (job && [fSavedSelectedItems containsIndex: job->sequence_id])
+ [rowsToSelect addIndex: i];
+ i++;
}
if ([rowsToSelect count] == 0)
[fOutlineView deselectAll: nil];
@@ -1158,7 +1214,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
// Generate string to display in UI.
//------------------------------------------------------------------------------------
-- (NSString *) progressStatusStringForJob: (hb_job_t *)job state: (hb_state_t *)s
+- (NSString *) progressStatusStringForJob: (HBJob *)job state: (hb_state_t *)s
{
if (s->state == HB_STATE_WORKING)
{
@@ -1198,7 +1254,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
// Generate string to display in UI.
//------------------------------------------------------------------------------------
-- (NSString *) progressTimeRemainingStringForJob: (hb_job_t *)job state: (hb_state_t *)s
+- (NSString *) progressTimeRemainingStringForJob: (HBJob *)job state: (hb_state_t *)s
{
if (s->state == HB_STATE_WORKING)
{
@@ -1270,7 +1326,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
// Refresh progress bar (fProgressTextField) from current state.
//------------------------------------------------------------------------------------
-- (void) updateProgressTextForJob: (hb_job_t *)job state: (hb_state_t *)s
+- (void) updateProgressTextForJob: (HBJob *)job state: (hb_state_t *)s
{
NSString * statusMsg = [self progressStatusStringForJob:job state:s];
NSString * timeMsg = [self progressTimeRemainingStringForJob:job state:s];
@@ -1335,17 +1391,13 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
- (void)updateCurrentJobDescription
{
- hb_job_t * job = fHandle ? hb_current_job(fHandle) : nil;
-
- if (job)
+ if (fCurrentJob)
{
- HBJob * currentJob = [HBJob jobWithJob: job];
- switch (job->pass)
+ switch (fCurrentJob->pass)
{
case -1: // Subtitle scan
[fJobDescTextField setAttributedStringValue:
- [currentJob attributedDescriptionWithHBHandle:fHandle
- withIcon: NO
+ [fCurrentJob attributedDescriptionWithIcon: NO
withTitle: YES
withPassName: YES
withFormatInfo: NO
@@ -1359,8 +1411,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
case 1: // video 1st pass
[fJobDescTextField setAttributedStringValue:
- [currentJob attributedDescriptionWithHBHandle:fHandle
- withIcon: NO
+ [fCurrentJob attributedDescriptionWithIcon: NO
withTitle: YES
withPassName: YES
withFormatInfo: NO
@@ -1375,8 +1426,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
case 0: // single pass
case 2: // video 2nd pass + audio
[fJobDescTextField setAttributedStringValue:
- [currentJob attributedDescriptionWithHBHandle:fHandle
- withIcon: NO
+ [fCurrentJob attributedDescriptionWithIcon: NO
withTitle: YES
withPassName: YES
withFormatInfo: NO
@@ -1390,8 +1440,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
default: // unknown
[fJobDescTextField setAttributedStringValue:
- [currentJob attributedDescriptionWithHBHandle:fHandle
- withIcon: NO
+ [fCurrentJob attributedDescriptionWithIcon: NO
withTitle: YES
withPassName: YES
withFormatInfo: NO
@@ -1414,10 +1463,9 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
- (void)updateCurrentJobProgress
{
- hb_job_t * job = fHandle ? hb_current_job(fHandle) : nil;
hb_state_t s;
hb_get_state2( fHandle, &s );
- [self updateProgressTextForJob: job state: &s];
+ [self updateProgressTextForJob: fCurrentJob state: &s];
[self updateProgressBarWithState:&s];
}
@@ -1462,8 +1510,10 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
[self cancelCurrentJob: sender];
break;
case HBStatusPending:
- hb_job_t * job = [[jobGroup jobAtIndex: 0] job];
- hb_rem_group( fHandle, job );
+ HBJob * job = [jobGroup jobAtIndex: 0];
+ hb_job_t * libhbJob = [self findLibhbJobWithID:job->sequence_id];
+ if (libhbJob)
+ hb_rem_group( fHandle, libhbJob );
break;
case HBStatusNone:
break;
@@ -1548,18 +1598,52 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
// Notifies HBQueueController that hblib's current job has changed
//------------------------------------------------------------------------------------
-- (void)currentJobGroupChanged: (hb_job_t *) currentJob
+- (void)currentJobChanged: (HBJob *) currentJob
{
- if (fCurrentJobGroup && [fCurrentJobGroup status] != HBStatusCanceled)
- [self addCompletedJobGroup: fCurrentJobGroup];
- [self setCurrentJobGroupFromJob: currentJob];
- [self updateCurrentJobDescription];
- [self updateCurrentJobProgress];
- [self showCurrentJobPane: fCurrentJobGroup != nil];
- if (fCurrentJobGroup)
- [self startAnimatingCurrentJobGroupInQueue];
- else
- [self stopAnimatingCurrentJobGroupInQueue];
+ [currentJob retain];
+ [fCurrentJob release];
+ fCurrentJob = currentJob;
+
+ // Check to see if this is also a change in Job Group
+
+ HBJobGroup * theJobGroup = [currentJob jobGroup];
+ if ((theJobGroup == nil) || (theJobGroup != fCurrentJobGroup)) // no more job groups or start of a new group
+ {
+ // Previous job has completed
+ if (fCurrentJobGroup)
+ {
+ // Update the status of the job that just finished. If the user canceled,
+ // the status will have already been set to canceled by hblibWillStop. So
+ // all other cases are assumed to be a successful encode. BTW, libhb
+ // doesn't currently report errors back to the GUI.
+ if ([fCurrentJobGroup status] != HBStatusCanceled)
+ [fCurrentJobGroup setStatus:HBStatusComplete];
+
+ [self addCompletedJobGroup: fCurrentJobGroup];
+ }
+
+ // Set the new group
+ [self setCurrentJobGroup: theJobGroup];
+
+ // Update the UI
+ [self updateCurrentJobDescription];
+ [self updateCurrentJobProgress];
+ [self showCurrentJobPane: fCurrentJobGroup != nil];
+ if (fCurrentJobGroup)
+ [self startAnimatingCurrentJobGroupInQueue];
+ else
+ [self stopAnimatingCurrentJobGroupInQueue];
+
+ [self hblibJobListChanged];
+ }
+
+ else // start a new job/pass in the same group
+ {
+ // Update the UI
+ [self updateCurrentJobDescription];
+ [self updateCurrentJobProgress];
+ }
+
}
//------------------------------------------------------------------------------------
@@ -1590,32 +1674,26 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
//------------------------------------------------------------------------------------
- (void)hblibStateChanged: (hb_state_t &)state
{
- // First check to see if hblib has moved on to another job. We get no direct
- // message when this happens, so we have to detect it ourself. The new job could
- // be either just the next job in the current group, or the start of a new group.
- if (fLastKnownCurrentJob != hb_current_job(fHandle))
- {
- hb_job_t * currentJob = hb_current_job(fHandle);
- if (!currentJob || currentJob->sequence_id == 0) // start of a new group
- {
- [self currentJobGroupChanged: currentJob];
- [self hblibJobListChanged];
- }
- else
- {
- [self updateCurrentJobDescription];
- [self updateCurrentJobProgress];
- }
-
- fLastKnownCurrentJob = currentJob;
- }
-
switch( state.state )
{
case HB_STATE_WORKING:
{
- [self updateCurrentJobProgress];
- [self startAnimatingCurrentJobGroupInQueue];
+ //NSLog(@"job = %x; job_cur = %d; job_count = %d", state.param.working.sequence_id, state.param.working.job_cur, state.param.working.job_count);
+ // First check to see if hblib has moved on to another job. We get no direct
+ // message when this happens, so we have to detect it ourself. The new job could
+ // be either just the next job in the current group, or the start of a new group.
+ if (fCurrentJobID != state.param.working.sequence_id)
+ {
+ fCurrentJobID = state.param.working.sequence_id;
+ HBJob * currentJob = [self findJobWithID:fCurrentJobID];
+ [self currentJobChanged: currentJob];
+ }
+
+ if (fCurrentJob)
+ {
+ [self updateCurrentJobProgress];
+ [self startAnimatingCurrentJobGroupInQueue];
+ }
break;
}
@@ -1637,6 +1715,9 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe
// HB_STATE_WORKDONE means that hblib has finished processing all the jobs
// in *its* queue. This message is NOT sent as each individual job is
// completed.
+
+ [self currentJobChanged: nil];
+ fCurrentJobID = 0;
}
}
@@ -1984,7 +2065,7 @@ static float spacingWidth = 3.0;
// Column width is NOT what is ultimately used
width -= 47; // 26 pixels for disclosure triangle, 20 for icon, 1 for intercell spacing
- float height = [item heightOfDescriptionForWidth: width withHBHandle: fHandle];
+ float height = [item heightOfDescriptionForWidth: width];
return height;
}
else
@@ -1997,11 +2078,14 @@ static float spacingWidth = 3.0;
// using the image portion of the cell so we could switch back to a regular NSTextFieldCell.
if ([[tableColumn identifier] isEqualToString:@"desc"])
- return [item attributedDescriptionWithHBHandle: fHandle];
+ return [item attributedDescription];
else if ([[tableColumn identifier] isEqualToString:@"icon"])
{
switch ([(HBJobGroup*)item status])
{
+ case HBStatusCanceled:
+ return [NSImage imageNamed:@"EncodeCanceled"];
+ break;
case HBStatusComplete:
return [NSImage imageNamed:@"EncodeComplete"];
break;