diff options
-rw-r--r-- | macosx/Controller.mm | 50 | ||||
-rw-r--r-- | macosx/HBQueueController.h | 56 | ||||
-rw-r--r-- | macosx/HBQueueController.mm | 639 |
3 files changed, 436 insertions, 309 deletions
diff --git a/macosx/Controller.mm b/macosx/Controller.mm index 00311010e..27b6abddb 100644 --- a/macosx/Controller.mm +++ b/macosx/Controller.mm @@ -611,7 +611,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It // Has current job changed? That means the queue has probably changed as // well so update it - [fQueueController hblibStateChanged: s]; + [fQueueController libhbStateChanged: s]; break; } @@ -635,7 +635,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [self UpdateDockIcon: 1.0]; // Pass along the info to HBQueueController - [fQueueController hblibStateChanged: s]; + [fQueueController libhbStateChanged: s]; break; } @@ -645,13 +645,13 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [fStatusField setStringValue: _( @"Paused" )]; // Pass along the info to HBQueueController - [fQueueController hblibStateChanged: s]; + [fQueueController libhbStateChanged: s]; break; case HB_STATE_WORKDONE: { - // HB_STATE_WORKDONE happpens as a result of hblib finishing all its jobs + // HB_STATE_WORKDONE happpens as a result of libhb finishing all its jobs // or someone calling hb_stop. In the latter case, hb_stop does not clear // out the remaining passes/jobs in the queue. We'll do that here. @@ -680,7 +680,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } // Pass along the info to HBQueueController - [fQueueController hblibStateChanged: s]; + [fQueueController libhbStateChanged: s]; /* Check to see if the encode state has not been cancelled to determine if we should check for encode done notifications */ @@ -754,17 +754,13 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It } /* Lets show the queue status here in the main window */ - int queue_count = hb_count( fHandle ); - if( queue_count ) - { - [fQueueStatus setStringValue: [NSString stringWithFormat: - @"%d pass%s in the queue", - queue_count, ( queue_count > 1 ) ? "es" : ""]]; - } + int queue_count = [fQueueController pendingCount]; + if( queue_count == 1) + [fQueueStatus setStringValue: _( @"1 encode queued") ]; + else if (queue_count > 1) + [fQueueStatus setStringValue: [NSString stringWithFormat: _( @"%d encodes queued" ), queue_count]]; else - { [fQueueStatus setStringValue: @""]; - } } /* We use this to write messages to stderr from the macgui which show up in the activity window and log*/ @@ -1722,13 +1718,21 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It hb_title_t * title = (hb_title_t *) hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] ); hb_job_t * job = title->job; - // Assign a unique job group ID for all passes of the same encode. This is how the - // UI lumps together jobs to form encodes. libhb does not use this id. + // Create a Queue Controller job group. Each job that we submit to libhb will also + // get added to the job group so that the queue can track the jobs. + HBJobGroup * jobGroup = [HBJobGroup jobGroup]; + // The job group can maintain meta data that libhb can not... + [jobGroup setPresetName: [fPresetSelectedDisplay stringValue]]; + + // Job groups require that each job within the group be assigned a unique id so + // that the queue can xref between itself and the private jobs that libhb + // maintains. The ID is composed a group id number and a "sequence" number. libhb + // does not use this id. static int jobGroupID = 0; jobGroupID++; - // A sequence number, starting at zero, is also used to identifiy to each pass. - // This is used by the UI to determine if a pass if the first pass of an encode. + // A sequence number, starting at zero, is used to identifiy to each pass. This is + // used by the queue UI to determine if a pass if the first pass of an encode. int sequenceNum = -1; [self prepareJob]; @@ -1768,6 +1772,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It */ job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum); hb_add( fHandle, job ); + [jobGroup addJob:[HBJob jobWithLibhbJob:job]]; // add this pass to the job group job->x264opts = x264opts_tmp; } @@ -1793,6 +1798,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It job->pass = 1; job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum); hb_add( fHandle, job ); + [jobGroup addJob:[HBJob jobWithLibhbJob:job]]; // add this pass to the job group job->pass = 2; job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum); @@ -1803,6 +1809,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It job->select_subtitle = subtitle_tmp; hb_add( fHandle, job ); + [jobGroup addJob:[HBJob jobWithLibhbJob:job]]; // add this pass to the job group } else { @@ -1810,13 +1817,14 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It job->pass = 0; job->sequence_id = MakeJobID(jobGroupID, ++sequenceNum); hb_add( fHandle, job ); + [jobGroup addJob:[HBJob jobWithLibhbJob:job]]; // add this pass to the job group } NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"]; - // Notify the queue - [fQueueController hblibJobListChanged]; + // Let the queue controller know about the job group + [fQueueController addJobGroup:jobGroup]; } /* Rip: puts up an alert before ultimately calling doRip @@ -1961,7 +1969,7 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It // remaining passes of the job and then start the queue back up if there are any // remaining jobs. - [fQueueController hblibWillStop]; + [fQueueController libhbWillStop]; hb_stop( fHandle ); fEncodeState = 2; // don't alert at end of processing since this was a cancel diff --git a/macosx/HBQueueController.h b/macosx/HBQueueController.h index ae90acc65..d1bb0c782 100644 --- a/macosx/HBQueueController.h +++ b/macosx/HBQueueController.h @@ -13,7 +13,7 @@ @class HBJobGroup; #define HB_QUEUE_DRAGGING 0 // <--- NOT COMPLETELY FUNCTIONAL YET -#define HB_OUTLINE_METRIC_CONTROLS 1 // for tweaking the outline cell spacings +#define HB_OUTLINE_METRIC_CONTROLS 0 // for tweaking the outline cell spacings // hb_job_t contains a sequence_id field. The high word is a unique job group id. // The low word contains the "sequence id" which is a value starting at 0 and @@ -27,10 +27,15 @@ typedef enum _HBQueueJobGroupStatus HBStatusNone = 0, HBStatusPending = 1, HBStatusWorking = 2, - HBStatusComplete = 3, + HBStatusCompleted = 3, HBStatusCanceled = 4 } HBQueueJobGroupStatus; +// Notification sent whenever the status of a HBJobGroup changes (via setStatus). The +// user info contains one object, @"HBOldJobGroupStatus", which is an NSNumber +// containing the previous status of the job group. +extern NSString * HBJobGroupStatusNotification; + //------------------------------------------------------------------------------------ // As usual, we need to subclass NSOutlineView to handle a few special cases: // @@ -67,7 +72,7 @@ BOOL fIsDragging; @interface HBJob : NSObject { - HBJobGroup *jobGroup; + HBJobGroup *jobGroup; // The group this job belongs to // The following fields match up with similar fields found in hb_job_t and it's // various substructures. @@ -116,8 +121,8 @@ BOOL fIsDragging; NSString *subtitleLang; } -+ (HBJob*) jobWithJob: (hb_job_t *) job; -- (id) initWithJob: (hb_job_t *) job; ++ (HBJob*) jobWithLibhbJob: (hb_job_t *) job; +- (id) initWithLibhbJob: (hb_job_t *) job; - (HBJobGroup *) jobGroup; - (void) setJobGroup: (HBJobGroup *)aJobGroup; - (NSMutableAttributedString *) attributedDescriptionWithIcon: (BOOL)withIcon @@ -131,6 +136,13 @@ BOOL fIsDragging; withAudioInfo: (BOOL)withAudioInfo withSubtitleInfo: (BOOL)withSubtitleInfo; +// Attributes used by attributedDescriptionWithIcon::::::::: ++ (NSMutableParagraphStyle *) descriptionParagraphStyle; ++ (NSDictionary *) descriptionDetailAttribute; ++ (NSDictionary *) descriptionDetailBoldAttribute; ++ (NSDictionary *) descriptionTitleAttribute; ++ (NSDictionary *) descriptionShortHeightAttribute; + @end //------------------------------------------------------------------------------------ @@ -148,6 +160,7 @@ BOOL fIsDragging; float fLastDescriptionHeight; float fLastDescriptionWidth; HBQueueJobGroupStatus fStatus; + NSString *fPresetName; } // Creating a job group @@ -163,6 +176,8 @@ BOOL fIsDragging; - (NSEnumerator *) jobEnumerator; - (void) setStatus: (HBQueueJobGroupStatus)status; - (HBQueueJobGroupStatus) status; +- (void) setPresetName: (NSString *)name; +- (NSString *) presetName; - (NSString *) path; - (NSString *) name; @@ -178,19 +193,25 @@ BOOL fIsDragging; @interface HBQueueController : NSObject { - hb_handle_t *fHandle; // reference to hblib + hb_handle_t *fHandle; // reference to libhb HBController *fHBController; // reference to HBController - NSMutableArray *fJobGroups; // hblib's job list organized in a hierarchy of HBJobGroup and HBJob - HBJobGroup *fCurrentJobGroup; // the HJobGroup currently being processed by hblib - HBJob *fCurrentJob; // the HJob (pass) currently being processed by hblib + NSMutableArray *fJobGroups; // libhb's job list organized in a hierarchy of HBJobGroup and HBJob + HBJobGroup *fCurrentJobGroup; // the HJobGroup currently being processed by libhb + HBJob *fCurrentJob; // the HJob (pass) currently being processed by libhb int fCurrentJobID; // this is how we track when hbib has started processing a different job. This is the job's sequence_id. + + unsigned int fPendingCount; // Number of various kinds of job groups in fJobGroups. + unsigned int fCompletedCount; // Don't access these directly as they may not always be up-to-date. + unsigned int fCanceledCount; // Use the accessor functions instead. + unsigned int fWorkingCount; + BOOL fJobGroupCountsNeedUpdating; + BOOL fCurrentJobPaneShown; // NO when fCurrentJobPane has been shifted out of view (see showCurrentJobPane) NSMutableIndexSet *fSavedExpandedItems; // used by save/restoreOutlineViewState to preserve which items are expanded NSMutableIndexSet *fSavedSelectedItems; // used by save/restoreOutlineViewState to preserve which items are selected #if HB_QUEUE_DRAGGING NSArray *fDraggedNodes; #endif - NSMutableArray *fCompleted; // HBJobGroups that libhb has finihsed with, whether successfully encoded or canceled by the user. These also appear in fJobGroups. NSTimer *fAnimationTimer; // animates the icon of the current job in the queue outline view int fAnimationIndex; // used to generate name of image used to animate the current job in the queue outline view @@ -233,13 +254,22 @@ BOOL fIsDragging; - (void)setHandle: (hb_handle_t *)handle; - (void)setHBController: (HBController *)controller; -- (void)hblibJobListChanged; -- (void)hblibStateChanged: (hb_state_t &)state; -- (void)hblibWillStop; +- (void)libhbStateChanged: (hb_state_t &)state; +- (void)libhbWillStop; + +// Adding items to the queue +- (void) addJobGroup: (HBJobGroup *) aJobGroup; +// Getting the currently processing job group - (HBJobGroup *) currentJobGroup; - (HBJob *) currentJob; +// Getting queue statistics +- (unsigned int) pendingCount; +- (unsigned int) completedCount; +- (unsigned int) canceledCount; +- (unsigned int) workingCount; + - (IBAction)showQueueWindow: (id)sender; - (IBAction)removeSelectedJobGroups: (id)sender; - (IBAction)revealSelectedJobGroups: (id)sender; diff --git a/macosx/HBQueueController.mm b/macosx/HBQueueController.mm index 428956d60..6743b378c 100644 --- a/macosx/HBQueueController.mm +++ b/macosx/HBQueueController.mm @@ -94,111 +94,26 @@ bool IsFirstPass(int jobID) @end -//------------------------------------------------------------------------------------ -#pragma mark - -#pragma mark Job group functions -//------------------------------------------------------------------------------------ -// These could be part of hblib if we think hblib should have knowledge of groups. -// For now, I see groups as a metaphor that HBQueueController provides. - -/** - * 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) -{ - hb_job_t * job; - int count = 0; - int index = 0; - while( ( job = hb_job( h, index++ ) ) ) - { - if (IsFirstPass(job->sequence_id)) - count++; - } - return count; -} - -/** - * 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) -{ - hb_job_t * job; - int count = 0; - int index = 0; - while( ( job = hb_job( h, index++ ) ) ) - { - if (IsFirstPass(job->sequence_id)) - { - if (count == i) - return job; - count++; - } - } - return NULL; -} - -/** - * 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 ) -{ - // 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 ) ) && ( !IsFirstPass(j->sequence_id ) ) ) - hb_rem( h, j ); - return; - } - else - index++; - } -} - -/** - * 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 ) -{ - hb_job_t * j = NULL; - int index = 0; - while( ( j = hb_job( h, index++ ) ) ) - { - if (j == job) - return hb_job( h, index ); - } - return NULL; -} - #pragma mark - //------------------------------------------------------------------------------------ // HBJob //------------------------------------------------------------------------------------ +static NSMutableParagraphStyle * _descriptionParagraphStyle = NULL; +static NSDictionary* _detailAttribute = NULL; +static NSDictionary* _detailBoldAttribute = NULL; +static NSDictionary* _titleAttribute = NULL; +static NSDictionary* _shortHeightAttribute = NULL; + @implementation HBJob -+ (HBJob*) jobWithJob: (hb_job_t *) job ++ (HBJob*) jobWithLibhbJob: (hb_job_t *) job { - return [[[HBJob alloc] initWithJob:job] autorelease]; + return [[[HBJob alloc] initWithLibhbJob:job] autorelease]; } -- (id) initWithJob: (hb_job_t *) job +- (id) initWithLibhbJob: (hb_job_t *) job { if (self = [super init]) { @@ -290,31 +205,11 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) NSMutableAttributedString * finalString = [[[NSMutableAttributedString alloc] initWithString: @""] autorelease]; // Attributes - static NSMutableParagraphStyle * ps = NULL; - if (!ps) - { - 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]]; - } - - static NSDictionary* detailAttribute = [[NSDictionary dictionaryWithObjectsAndKeys: - [NSFont systemFontOfSize:10.0], NSFontAttributeName, - ps, NSParagraphStyleAttributeName, - nil] retain]; - static NSDictionary* detailBoldAttribute = [[NSDictionary dictionaryWithObjectsAndKeys: - [NSFont boldSystemFontOfSize:10.0], NSFontAttributeName, - ps, NSParagraphStyleAttributeName, - nil] retain]; - static NSDictionary* titleAttribute = [[NSDictionary dictionaryWithObjectsAndKeys: - [NSFont systemFontOfSize:[NSFont systemFontSize]], NSFontAttributeName, - ps, NSParagraphStyleAttributeName, - nil] retain]; - static NSDictionary* shortHeightAttribute = [[NSDictionary dictionaryWithObjectsAndKeys: - [NSFont systemFontOfSize:2.0], NSFontAttributeName, - nil] retain]; + NSMutableParagraphStyle * ps = [HBJob descriptionParagraphStyle]; + NSDictionary* detailAttr = [HBJob descriptionDetailAttribute]; + NSDictionary* detailBoldAttr = [HBJob descriptionDetailBoldAttribute]; + NSDictionary* titleAttr = [HBJob descriptionTitleAttribute]; + NSDictionary* shortHeightAttr = [HBJob descriptionShortHeightAttribute]; // Title with summary if (withTitle) @@ -339,7 +234,7 @@ 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:titleName withAttributes:titleAttribute]; + [finalString appendString:titleName withAttributes:titleAttr]; NSString * summaryInfo; @@ -374,10 +269,10 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) else summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, %d Video Passes)", titleIndex, chapterString, numVideoPasses]; - [finalString appendString:[NSString stringWithFormat:@"%@\n", summaryInfo] withAttributes:detailAttribute]; + [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:shortHeightAttribute]; + [finalString appendString:@"\n" withAttributes:shortHeightAttr]; } // End of title stuff @@ -429,7 +324,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) else jobPassName = [NSString stringWithFormat: NSLocalizedString(@"Pass %d", nil), passNum]; } - [finalString appendString:[NSString stringWithFormat:@"%@\n", jobPassName] withAttributes:detailBoldAttribute]; + [finalString appendString:[NSString stringWithFormat:@"%@\n", jobPassName] withAttributes:detailBoldAttr]; } // Video Codec needed by FormatInfo and withVideoInfo @@ -491,14 +386,14 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) else jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video + %@ Audio\n", jobFormatInfo, jobVideoCodec, jobAudioCodec]; - [finalString appendString: @"Format: " withAttributes:detailBoldAttribute]; - [finalString appendString: jobFormatInfo withAttributes:detailAttribute]; + [finalString appendString: @"Format: " withAttributes:detailBoldAttr]; + [finalString appendString: jobFormatInfo withAttributes:detailAttr]; } if (withDestination) { - [finalString appendString: @"Destination: " withAttributes:detailBoldAttribute]; - [finalString appendString:[NSString stringWithFormat:@"%@\n", file] withAttributes:detailAttribute]; + [finalString appendString: @"Destination: " withAttributes:detailBoldAttr]; + [finalString appendString:[NSString stringWithFormat:@"%@\n", file] withAttributes:detailAttr]; } @@ -525,9 +420,9 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) if (deinterlace == 1) jobPictureInfo = [jobPictureInfo stringByAppendingString:@", Deinterlace"]; if (withIcon) // implies indent the info - [finalString appendString: @"\t" withAttributes:detailBoldAttribute]; - [finalString appendString: @"Picture: " withAttributes:detailBoldAttribute]; - [finalString appendString:[NSString stringWithFormat:@"%@\n", jobPictureInfo] withAttributes:detailAttribute]; + [finalString appendString: @"\t" withAttributes:detailBoldAttr]; + [finalString appendString: @"Picture: " withAttributes:detailBoldAttr]; + [finalString appendString:[NSString stringWithFormat:@"%@\n", jobPictureInfo] withAttributes:detailAttr]; } if (withVideoInfo) @@ -564,9 +459,9 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) jobVideoDetail = [NSString stringWithFormat:@"%@, %@, %d fps", jobVideoCodec, jobVideoQuality, vrate / vrate_base]; } if (withIcon) // implies indent the info - [finalString appendString: @"\t" withAttributes:detailBoldAttribute]; - [finalString appendString: @"Video: " withAttributes:detailBoldAttribute]; - [finalString appendString:[NSString stringWithFormat:@"%@\n", jobVideoDetail] withAttributes:detailAttribute]; + [finalString appendString: @"\t" withAttributes:detailBoldAttr]; + [finalString appendString: @"Video: " withAttributes:detailBoldAttr]; + [finalString appendString:[NSString stringWithFormat:@"%@\n", jobVideoDetail] withAttributes:detailAttr]; } if (withx264Info) @@ -574,9 +469,9 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) 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", x264opts] withAttributes:detailAttribute]; + [finalString appendString: @"\t" withAttributes:detailBoldAttr]; + [finalString appendString: @"x264 Options: " withAttributes:detailBoldAttr]; + [finalString appendString:[NSString stringWithFormat:@"%@\n", x264opts] withAttributes:detailAttr]; } } @@ -606,9 +501,9 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: 6-channel discreet", ai + 1]]; } if (withIcon) // implies indent the info - [finalString appendString: @"\t" withAttributes:detailBoldAttribute]; - [finalString appendString: @"Audio: " withAttributes:detailBoldAttribute]; - [finalString appendString:[NSString stringWithFormat:@"%@\n", jobAudioInfo] withAttributes:detailAttribute]; + [finalString appendString: @"\t" withAttributes:detailBoldAttr]; + [finalString appendString: @"Audio: " withAttributes:detailBoldAttr]; + [finalString appendString:[NSString stringWithFormat:@"%@\n", jobAudioInfo] withAttributes:detailAttr]; } if (withSubtitleInfo) @@ -619,18 +514,18 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) 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]; + [finalString appendString: @"\t" withAttributes:detailBoldAttr]; + [finalString appendString: @"Subtitles: " withAttributes:detailBoldAttr]; + [finalString appendString: @"Autoselect " withAttributes:detailAttr]; } else if (subtitle >= 0) { if (subtitleLang) { if (withIcon) // implies indent the info - [finalString appendString: @"\t" withAttributes:detailBoldAttribute]; - [finalString appendString: @"Subtitles: " withAttributes:detailBoldAttribute]; - [finalString appendString: subtitleLang withAttributes:detailAttribute]; + [finalString appendString: @"\t" withAttributes:detailBoldAttr]; + [finalString appendString: @"Subtitles: " withAttributes:detailBoldAttr]; + [finalString appendString: subtitleLang withAttributes:detailAttr]; } } } @@ -642,6 +537,59 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) return finalString; } ++ (NSMutableParagraphStyle *) descriptionParagraphStyle +{ + if (!_descriptionParagraphStyle) + { + _descriptionParagraphStyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain]; + [_descriptionParagraphStyle setHeadIndent: 40.0]; + [_descriptionParagraphStyle setParagraphSpacing: 1.0]; + [_descriptionParagraphStyle setTabStops:[NSArray array]]; // clear all tabs + [_descriptionParagraphStyle addTabStop: [[[NSTextTab alloc] initWithType: NSLeftTabStopType location: 20.0] autorelease]]; + } + return _descriptionParagraphStyle; +} + ++ (NSDictionary *) descriptionDetailAttribute +{ + if (!_detailAttribute) + _detailAttribute = [[NSDictionary dictionaryWithObjectsAndKeys: + [NSFont systemFontOfSize:10.0], NSFontAttributeName, + _descriptionParagraphStyle, NSParagraphStyleAttributeName, + nil] retain]; + return _detailAttribute; +} + ++ (NSDictionary *) descriptionDetailBoldAttribute +{ + if (!_detailBoldAttribute) + _detailBoldAttribute = [[NSDictionary dictionaryWithObjectsAndKeys: + [NSFont boldSystemFontOfSize:10.0], NSFontAttributeName, + _descriptionParagraphStyle, NSParagraphStyleAttributeName, + nil] retain]; + return _detailBoldAttribute; +} + ++ (NSDictionary *) descriptionTitleAttribute +{ + if (!_titleAttribute) + _titleAttribute = [[NSDictionary dictionaryWithObjectsAndKeys: + [NSFont systemFontOfSize:[NSFont systemFontSize]], NSFontAttributeName, + _descriptionParagraphStyle, NSParagraphStyleAttributeName, + nil] retain]; + return _titleAttribute; +} + ++ (NSDictionary *) descriptionShortHeightAttribute +{ + if (!_shortHeightAttribute) + _shortHeightAttribute = [[NSDictionary dictionaryWithObjectsAndKeys: + [NSFont systemFontOfSize:2.0], NSFontAttributeName, + nil] retain]; + return _shortHeightAttribute; +} + + @end #pragma mark - @@ -650,6 +598,9 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) // HBJobGroup //------------------------------------------------------------------------------------ +// Notification sent from HBJobGroup setStatus whenever the status changes. +NSString *HBJobGroupStatusNotification = @"HBJobGroupStatusNotification"; + @implementation HBJobGroup + (HBJobGroup *) jobGroup; @@ -671,6 +622,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) - (void) dealloc { + [fPresetName release]; [fJobs release]; [super dealloc]; } @@ -723,9 +675,30 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) HBJob * job = [self jobAtIndex:0]; + // append the title [fDescription appendAttributedString: [job attributedDescriptionWithIcon: NO withTitle: YES withPassName: NO + withFormatInfo: NO + withDestination: NO + withPictureInfo: NO + withVideoInfo: NO + withx264Info: NO + withAudioInfo: NO + withSubtitleInfo: NO]]; + + // append the preset name + if ([fPresetName length]) + { + [fDescription appendString:@"Preset: " withAttributes:[HBJob descriptionDetailBoldAttribute]]; + [fDescription appendString:fPresetName withAttributes:[HBJob descriptionDetailAttribute]]; + [fDescription appendString:@"\n" withAttributes:[HBJob descriptionDetailAttribute]]; + } + + // append the format and destinaton + [fDescription appendAttributedString: [job attributedDescriptionWithIcon: NO + withTitle: NO + withPassName: NO withFormatInfo: YES withDestination: YES withPictureInfo: NO @@ -734,6 +707,7 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) withAudioInfo: NO withSubtitleInfo: NO]]; + static NSAttributedString * carriageReturn = [[NSAttributedString alloc] initWithString:@"\n"]; NSEnumerator * e = [self jobEnumerator]; @@ -799,7 +773,13 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) - (void) setStatus: (HBQueueJobGroupStatus)status { + // Create a dictionary with the old status + NSDictionary * userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:self->fStatus] forKey:@"HBOldJobGroupStatus"]; + self->fStatus = status; + + // Send notification with old status + [[NSNotificationCenter defaultCenter] postNotificationName:HBJobGroupStatusNotification object:self userInfo:userInfo]; } - (HBQueueJobGroupStatus) status @@ -807,6 +787,18 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) return self->fStatus; } +- (void) setPresetName: (NSString *)name +{ + [name retain]; + [fPresetName release]; + fPresetName = name; +} + +- (NSString *) presetName +{ + return fPresetName; +} + - (NSString *) name { HBJob * firstJob = [self jobAtIndex:0]; @@ -824,10 +816,6 @@ static hb_job_t * hb_next_job( hb_handle_t * h, hb_job_t * job ) #pragma mark - -@interface HBQueueController (Private) -- (void)updateQueueUI; -@end - // Toolbar identifiers static NSString* HBQueueToolbar = @"HBQueueToolbar1"; static NSString* HBQueueStartCancelToolbarIdentifier = @"HBQueueStartCancelToolbarIdentifier"; @@ -852,11 +840,13 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe nil]]; fJobGroups = [[NSMutableArray arrayWithCapacity:0] retain]; - fCompleted = [[NSMutableArray arrayWithCapacity:0] retain]; BOOL loadSucceeded = [NSBundle loadNibNamed:@"Queue" owner:self] && fQueueWindow; NSAssert(loadSucceeded, @"Could not open Queue nib"); NSAssert(fQueueWindow, @"fQueueWindow not found in Queue nib"); + + // Register for HBJobGroup status changes + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobGroupStatusNotification:) name:HBJobGroupStatusNotification object:nil]; } return self; } @@ -871,11 +861,12 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe [fQueueWindow setDelegate:nil]; [fJobGroups release]; - [fCompleted release]; [fCurrentJobGroup release]; [fSavedExpandedItems release]; [fSavedSelectedItems release]; + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; } @@ -895,6 +886,9 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe fHBController = controller; } +#pragma mark - +#pragma mark - Getting the currently processing job group + //------------------------------------------------------------------------------------ // Returns the HBJobGroup that is currently being encoded; nil if no encoding is // occurring. @@ -918,7 +912,6 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe //------------------------------------------------------------------------------------ - (IBAction) showQueueWindow: (id)sender { - [self updateQueueUI]; [fQueueWindow makeKeyAndOrderFront: self]; [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"QueueWindowIsOpen"]; } @@ -971,72 +964,6 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe } //------------------------------------------------------------------------------------ -// Rebuilds the contents of fJobGroups which is a hierarchy of HBJobGroup and HBJobs. -//------------------------------------------------------------------------------------ -- (void)rebuildJobGroups -{ - // 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 - - [fJobGroups autorelease]; - fJobGroups = [[NSMutableArray arrayWithCapacity:0] retain]; - - // Add all the completed job groups - [fJobGroups addObjectsFromArray: fCompleted]; - - // Add the current job group - if (fCurrentJobGroup) - [fJobGroups addObject: fCurrentJobGroup]; - - // Add all the pending job groups. These come from hblib - HBJobGroup * aJobGroup = [HBJobGroup jobGroup]; - - // If hblib is currently processing something, hb_group will skip over that group. - // And that's exactly what we want -- fJobGroups contains only pending job groups. - - hb_job_t * nextJob = hb_group( fHandle, 0 ); - while( nextJob ) - { - 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) - { - [aJobGroup setStatus: HBStatusPending]; - [fJobGroups addObject: aJobGroup]; - aJobGroup = [HBJobGroup jobGroup]; - } - } - [aJobGroup addJob: [HBJob jobWithJob:nextJob]]; - nextJob = hb_next_job (fHandle, nextJob); - } - if ([aJobGroup count] > 0) - { - [aJobGroup setStatus: HBStatusPending]; - [fJobGroups addObject:aJobGroup]; - } -} - -//------------------------------------------------------------------------------------ -// 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 -{ - // Put the group in the completed list for permanent storage. - [fCompleted addObject: aJobGroup]; -} - -//------------------------------------------------------------------------------------ // Sets fCurrentJobGroup to a new job group. //------------------------------------------------------------------------------------ - (void) setCurrentJobGroup: (HBJobGroup *)aJobGroup @@ -1085,6 +1012,95 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe } #pragma mark - +#pragma mark Queue Counts + +//------------------------------------------------------------------------------------ +// Sets a flag indicating that the values for fPendingCount, fCompletedCount, +// fCanceledCount, and fWorkingCount need to be recalculated. +//------------------------------------------------------------------------------------ +- (void) setJobGroupCountsNeedUpdating: (BOOL)flag +{ + fJobGroupCountsNeedUpdating = flag; +} + +//------------------------------------------------------------------------------------ +// Recalculates and stores new values in fPendingCount, fCompletedCount, +// fCanceledCount, and fWorkingCount. +//------------------------------------------------------------------------------------ +- (void) recalculateJobGroupCounts +{ + fPendingCount = 0; + fCompletedCount = 0; + fCanceledCount = 0; + fWorkingCount = 0; + + NSEnumerator * groupEnum = [fJobGroups objectEnumerator]; + HBJobGroup * aJobGroup; + while ( (aJobGroup = [groupEnum nextObject]) ) + { + switch ([aJobGroup status]) + { + case HBStatusNone: + // We don't track these. + break; + case HBStatusPending: + fPendingCount++; + break; + case HBStatusCompleted: + fCompletedCount++; + break; + case HBStatusCanceled: + fCanceledCount++; + break; + case HBStatusWorking: + fWorkingCount++; + break; + } + } + fJobGroupCountsNeedUpdating = NO; +} + +//------------------------------------------------------------------------------------ +// Returns the number of job groups whose status is HBStatusPending. +//------------------------------------------------------------------------------------ +- (unsigned int) pendingCount +{ + if (fJobGroupCountsNeedUpdating) + [self recalculateJobGroupCounts]; + return fPendingCount; +} + +//------------------------------------------------------------------------------------ +// Returns the number of job groups whose status is HBStatusCompleted. +//------------------------------------------------------------------------------------ +- (unsigned int) completedCount +{ + if (fJobGroupCountsNeedUpdating) + [self recalculateJobGroupCounts]; + return fCompletedCount; +} + +//------------------------------------------------------------------------------------ +// Returns the number of job groups whose status is HBStatusCanceled. +//------------------------------------------------------------------------------------ +- (unsigned int) canceledCount +{ + if (fJobGroupCountsNeedUpdating) + [self recalculateJobGroupCounts]; + return fCanceledCount; +} + +//------------------------------------------------------------------------------------ +// Returns the number of job groups whose status is HBStatusWorking. +//------------------------------------------------------------------------------------ +- (unsigned int) workingCount +{ + if (fJobGroupCountsNeedUpdating) + [self recalculateJobGroupCounts]; + return fWorkingCount; +} + +#pragma mark - #pragma mark UI Updating //------------------------------------------------------------------------------------ @@ -1167,19 +1183,43 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe } //------------------------------------------------------------------------------------ +// Marks the icon region of a job group in the queue view as needing display. +//------------------------------------------------------------------------------------ +- (void) updateJobGroupIconInQueue:(HBJobGroup*)aJobGroup +{ + int row = [fOutlineView rowForItem: aJobGroup]; + int col = [fOutlineView columnWithIdentifier: @"icon"]; + if (row != -1 && col != -1) + { + NSRect frame = [fOutlineView frameOfCellAtColumn:col row:row]; + [fOutlineView setNeedsDisplayInRect: frame]; + } +} + +//------------------------------------------------------------------------------------ +// Marks the entire region of a job group in the queue view as needing display. +//------------------------------------------------------------------------------------ +- (void) updateJobGroupInQueue:(HBJobGroup*)aJobGroup +{ + int row = [fOutlineView rowForItem: aJobGroup]; + if (row != -1) + { + NSRect frame = [fOutlineView rectOfRow:row]; + [fOutlineView setNeedsDisplayInRect: frame]; + } +} + +//------------------------------------------------------------------------------------ // If a job is currently processing, its job icon in the queue outline view is // animated to its next state. //------------------------------------------------------------------------------------ - (void) animateCurrentJobGroupInQueue:(NSTimer*)theTimer { - int row = [fOutlineView rowForItem: fCurrentJobGroup]; - int col = [fOutlineView columnWithIdentifier: @"icon"]; - if (row != -1 && col != -1) + if (fCurrentJobGroup) { fAnimationIndex++; fAnimationIndex %= 6; // there are 6 animation images; see outlineView:objectValueForTableColumn:byItem: below. - NSRect frame = [fOutlineView frameOfCellAtColumn:col row:row]; - [fOutlineView setNeedsDisplayInRect: frame]; + [self updateJobGroupIconInQueue: fCurrentJobGroup]; } } @@ -1374,13 +1414,21 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe - (void)updateQueueCountField { NSString * msg; - int jobCount; - - 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]; + int jobCount = [fJobGroups count]; + int pendingCount = [self pendingCount]; + if (jobCount == 0) + msg = NSLocalizedString(@"No encodes", nil); + else if ((jobCount == 1) && (pendingCount == 0)) + msg = NSLocalizedString(@"1 encode", nil); + else if (jobCount == pendingCount) // ie, all jobs listed are pending + { + if (jobCount == 1) + msg = NSLocalizedString(@"1 pending encode", nil); + else + msg = [NSString stringWithFormat:NSLocalizedString(@"%d pending encodes", nil), pendingCount]; + } + else // some completed, some pending + msg = [NSString stringWithFormat:NSLocalizedString(@"%d encodes (%d pending)", nil), jobCount, pendingCount]; [fQueueCountField setStringValue:msg]; } @@ -1470,13 +1518,22 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe } //------------------------------------------------------------------------------------ -// 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. +// Notifies HBQueuecontroller that the contents of fJobGroups is about to be modified. +// HBQueuecontroller remembers the state of the UI (selection and expanded items). //------------------------------------------------------------------------------------ -- (void)updateQueueUI +- (void) beginEditingJobGroupsArray { [self saveOutlineViewState]; - [self rebuildJobGroups]; +} + +//------------------------------------------------------------------------------------ +// Notifies HBQueuecontroller that modifications to fJobGroups as indicated by a prior +// call to beginEditingJobGroupsArray have been completed. HBQueuecontroller reloads +// the queue view and restores the state of the UI (selection and expanded items). +//------------------------------------------------------------------------------------ +- (void) endEditingJobGroupsArray +{ + [self setJobGroupCountsNeedUpdating:YES]; [fOutlineView noteNumberOfRowsChanged]; [fOutlineView reloadData]; [self restoreOutlineViewState]; @@ -1497,23 +1554,31 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe int row = [selectedRows firstIndex]; if (row != NSNotFound) { + [self beginEditingJobGroupsArray]; while (row != NSNotFound) { HBJobGroup * jobGroup = [fOutlineView itemAtRow: row]; switch ([jobGroup status]) { - case HBStatusComplete: + case HBStatusCompleted: case HBStatusCanceled: - [fCompleted removeObject: jobGroup]; + [fJobGroups removeObject: jobGroup]; break; case HBStatusWorking: [self cancelCurrentJob: sender]; break; case HBStatusPending: - HBJob * job = [jobGroup jobAtIndex: 0]; - hb_job_t * libhbJob = [self findLibhbJobWithID:job->sequence_id]; - if (libhbJob) - hb_rem_group( fHandle, libhbJob ); + // Remove from libhb + HBJob * job; + NSEnumerator * e = [jobGroup jobEnumerator]; + while (job = [e nextObject]) + { + hb_job_t * libhbJob = [self findLibhbJobWithID:job->sequence_id]; + if (libhbJob) + hb_rem( fHandle, libhbJob ); + } + // Remove from our list + [fJobGroups removeObject: jobGroup]; break; case HBStatusNone: break; @@ -1521,8 +1586,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe row = [selectedRows indexGreaterThanIndex: row]; } - - [self hblibJobListChanged]; + [self endEditingJobGroupsArray]; } } @@ -1552,7 +1616,7 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe // Calls HBController Cancel: which displays an alert asking user if they want to // cancel encoding of current job. cancelCurrentJob: returns immediately after posting // the alert. Later, when the user acknowledges the alert, HBController will call -// hblib to cancel the job. +// libhb to cancel the job. //------------------------------------------------------------------------------------ - (IBAction)cancelCurrentJob: (id)sender { @@ -1572,12 +1636,12 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe 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 (hb_group_count(fHandle) > 0) + else if ([self pendingCount] > 0) [fHBController doRip]; } //------------------------------------------------------------------------------------ -// Toggles the pause/resume state of hblib +// Toggles the pause/resume state of libhb //------------------------------------------------------------------------------------ - (IBAction)togglePauseResume: (id)sender { @@ -1593,10 +1657,23 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe } #pragma mark - -#pragma mark Synchronizing with hblib +#pragma mark Synchronizing with libhb + +//------------------------------------------------------------------------------------ +// Queues a job group. The job group's status is set to HBStatusPending. +//------------------------------------------------------------------------------------ +- (void) addJobGroup: (HBJobGroup *) aJobGroup +{ + NSAssert(![fJobGroups containsObject:aJobGroup], @"Duplicate job group"); + [aJobGroup setStatus:HBStatusPending]; + + [self beginEditingJobGroupsArray]; + [fJobGroups addObject:aJobGroup]; + [self endEditingJobGroupsArray]; +} //------------------------------------------------------------------------------------ -// Notifies HBQueueController that hblib's current job has changed +// Notifies HBQueueController that libhb's current job has changed //------------------------------------------------------------------------------------ - (void)currentJobChanged: (HBJob *) currentJob { @@ -1604,6 +1681,11 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe [fCurrentJob release]; fCurrentJob = currentJob; + // Log info about the preset name. We do this for each job, since libhb logs each + // job separately. The preset name is found in the job's job group object. + if (fCurrentJob && [fCurrentJob jobGroup] && ([[[fCurrentJob jobGroup] presetName] length] > 0)) + [fHBController writeToActivityLog: "Using preset: %s", [[[fCurrentJob jobGroup] presetName] UTF8String]]; + // Check to see if this is also a change in Job Group HBJobGroup * theJobGroup = [currentJob jobGroup]; @@ -1613,18 +1695,16 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe 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 + // the status will have already been set to canceled by libhbWillStop. 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]; + [fCurrentJobGroup setStatus:HBStatusCompleted]; } // Set the new group [self setCurrentJobGroup: theJobGroup]; - + // Update the UI [self updateCurrentJobDescription]; [self updateCurrentJobProgress]; @@ -1633,8 +1713,6 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe [self startAnimatingCurrentJobGroupInQueue]; else [self stopAnimatingCurrentJobGroupInQueue]; - - [self hblibJobListChanged]; } else // start a new job/pass in the same group @@ -1652,34 +1730,23 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe // let HBQueueController know when a job group has been cancelled. Otherwise, we'd // have no way of knowing if a job was canceled or completed sucessfully. //------------------------------------------------------------------------------------ -- (void)hblibWillStop +- (void)libhbWillStop { if (fCurrentJobGroup) [fCurrentJobGroup setStatus: HBStatusCanceled]; } //------------------------------------------------------------------------------------ -// Notifies HBQueueController that hblib's job list has been modified +// Notifies HBQueueController that libhb's state has changed //------------------------------------------------------------------------------------ -- (void)hblibJobListChanged -{ - // This message is received from HBController after it has added a job group to - // hblib's job list. It is also received from self when a job group is deleted by - // the user. - [self updateQueueUI]; -} - -//------------------------------------------------------------------------------------ -// Notifies HBQueueController that hblib's state has changed -//------------------------------------------------------------------------------------ -- (void)hblibStateChanged: (hb_state_t &)state +- (void)libhbStateChanged: (hb_state_t &)state { switch( state.state ) { case HB_STATE_WORKING: { //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 + // First check to see if libhb 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) @@ -1712,12 +1779,13 @@ static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseRe case HB_STATE_WORKDONE: { - // HB_STATE_WORKDONE means that hblib has finished processing all the jobs + // HB_STATE_WORKDONE means that libhb 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; + break; } } @@ -1738,6 +1806,21 @@ static float spacingWidth = 3.0; } #endif +#pragma mark - + +//------------------------------------------------------------------------------------ +// Receives notification whenever an HBJobGroup's status is changed. +//------------------------------------------------------------------------------------ +- (void) jobGroupStatusNotification:(NSNotification *)notification +{ + [self setJobGroupCountsNeedUpdating: YES]; +// HBQueueJobGroupStatus oldStatus = (HBQueueJobGroupStatus) [[[notification userInfo] objectForKey:@"HBOldJobGroupStatus"] intValue]; + HBJobGroup * jobGroup = [notification object]; + if (jobGroup) + [self updateJobGroupInQueue:jobGroup]; + [self updateQueueCountField]; +} + #pragma mark - #pragma mark Toolbar @@ -1870,7 +1953,7 @@ static float spacingWidth = 3.0; [toolbarItem setToolTip: @"Stop Encoding"]; } - else if (hb_count(fHandle) > 0) + else if ([self pendingCount] > 0) { enable = YES; [toolbarItem setImage:[NSImage imageNamed: @"Play"]]; @@ -1950,6 +2033,8 @@ static float spacingWidth = 3.0; // Show/hide UI elements fCurrentJobPaneShown = YES; // it's shown in the nib [self showCurrentJobPane:NO]; + + [self updateQueueCountField]; } @@ -2062,8 +2147,12 @@ static float spacingWidth = 3.0; return [item lastDescriptionHeight]; float width = [[outlineView tableColumnWithIdentifier: @"desc"] width]; - // Column width is NOT what is ultimately used - width -= 47; // 26 pixels for disclosure triangle, 20 for icon, 1 for intercell spacing + // 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 float height = [item heightOfDescriptionForWidth: width]; return height; @@ -2086,7 +2175,7 @@ static float spacingWidth = 3.0; case HBStatusCanceled: return [NSImage imageNamed:@"EncodeCanceled"]; break; - case HBStatusComplete: + case HBStatusCompleted: return [NSImage imageNamed:@"EncodeComplete"]; break; case HBStatusWorking: @@ -2122,7 +2211,7 @@ static float spacingWidth = 3.0; { [cell setEnabled: YES]; BOOL highlighted = [outlineView isRowSelected:[outlineView rowForItem: item]] && [[outlineView window] isKeyWindow] && ([[outlineView window] firstResponder] == outlineView); - if ([(HBJobGroup*)item status] == HBStatusComplete) + if ([(HBJobGroup*)item status] == HBStatusCompleted) { [cell setAction: @selector(revealSelectedJobGroups:)]; if (highlighted) |