-@end
-
-//------------------------------------------------------------------------------------
-#pragma mark -
-//------------------------------------------------------------------------------------
-
-@implementation HBQueueOutlineView
-
-- (void)viewDidEndLiveResize
-{
- // Since we disabled calculating row heights during a live resize, force them to
- // recalculate now.
- [self noteHeightOfRowsWithIndexesChanged:
- [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [self numberOfRows])]];
- [super viewDidEndLiveResize];
-}
-
-#if HB_QUEUE_DRAGGING
-- (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray *)tableColumns event:(NSEvent*)dragEvent offset:(NSPointPointer)dragImageOffset
-{
- // Set the fIsDragging flag so that other's know that a drag operation is being
- // performed.
- fIsDragging = YES;
-
- // By default, NSTableView only drags an image of the first column. Change this to
- // drag an image of the queue's icon and desc columns.
- NSArray * cols = [NSArray arrayWithObjects: [self tableColumnWithIdentifier:@"icon"], [self tableColumnWithIdentifier:@"desc"], nil];
- return [super dragImageForRowsWithIndexes:dragRows tableColumns:cols event:dragEvent offset:dragImageOffset];
-}
-#endif
-
-#if HB_QUEUE_DRAGGING
-- (void) mouseDown:(NSEvent *)theEvent
-{
- // After a drag operation, reset fIsDragging back to NO. This is really the only way
- // for us to detect when a drag has finished. You can't do it in acceptDrop because
- // that won't be called if the dragged item is released outside the view.
- [super mouseDown:theEvent];
- fIsDragging = NO;
-}
-#endif
-
-#if HB_QUEUE_DRAGGING
-- (BOOL) isDragging;
-{
- return fIsDragging;
-}
-#endif
-
-@end
-
-#pragma mark -
-
-//------------------------------------------------------------------------------------
-// HBJob
-//------------------------------------------------------------------------------------
-
-static NSMutableParagraphStyle * _descriptionParagraphStyle = nil;
-static NSDictionary* _detailAttribute = nil;
-static NSDictionary* _detailBoldAttribute = nil;
-static NSDictionary* _titleAttribute = nil;
-static NSDictionary* _shortHeightAttribute = nil;
-
-@implementation HBJob
-
-+ (HBJob*) jobWithLibhbJob: (hb_job_t *) job
-{
- return [[[HBJob alloc] initWithLibhbJob:job] autorelease];
-}
-
-- (id) initWithLibhbJob: (hb_job_t *) job
-{
- if (self = [super init])
- {
- 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];
- /* So, with the advent of job->list_audio's I decided why not just use an NSString and concatanate
- all of the info we need for all of the audio values to display right into an NSString here ? So I
- did. I have no idea why we are reading libhb stuff just to display it in the queue gui. So here we
- are with a huge string. But its easy to change and saves alot of messing about. Maybe we move a bunch
- of other display stuff into strings for display for each job. It's not like they have to actually do
- anything.*/
- hb_audio_config_t * audio;
- NSString * thisJobAudioCodecs = [NSString stringWithFormat:@""];
- NSString * thisJobAudioInfo = [NSString stringWithFormat:@""];
- int i;
- for( i = 0; i < hb_list_count(job->list_audio); i++ )
- {
- audio = (hb_audio_config_t *) hb_list_audio_config_item( job->list_audio, i );
- /* Output Codec */
- NSString *outputCodec;
- if (audio->out.codec == HB_ACODEC_AC3)
- outputCodec = @"AC3";
- else if (audio->out.codec == HB_ACODEC_FAAC)
- outputCodec = @"AAC";
- else if (audio->out.codec == HB_ACODEC_LAME)
- outputCodec = @"MP3";
- else if (audio->out.codec == HB_ACODEC_VORBIS)
- outputCodec = @"Vorbis";
- else
- outputCodec = @"Unknown Codec";
- /* Add the codec to the audio codecs list ( We should check against dupes)*/
- thisJobAudioCodecs = [thisJobAudioCodecs stringByAppendingString:[NSString stringWithFormat:@" %@,",outputCodec]];
- if (i > 0)
- {
- /* Insert a line break so that we get each track on a separate line */
- /* Wicked HACK alert!!, use 18 whitespaces to align offset in display for list > 2 to offset "Audio" in the queue display
- Please Fix Me because this is embarrassing (but it works) */
- thisJobAudioInfo = [thisJobAudioInfo stringByAppendingString:@"\n "];
- }
- /* Detailed Job audio track info*/
- /* Track Number and Mixdown Info */
- if (audio->out.mixdown == HB_ACODEC_AC3)// Remember for ac3 passthru the mixdown uses the source codec
- thisJobAudioInfo = [thisJobAudioInfo stringByAppendingString:[NSString stringWithFormat:@"Track %d: Source: %@ Output: %@, Pass-Thru", i + 1, [NSString stringWithUTF8String:audio->lang.description], outputCodec]];
- else if (audio->out.mixdown == HB_AMIXDOWN_MONO)
- thisJobAudioInfo = [thisJobAudioInfo stringByAppendingString:[NSString stringWithFormat:@"Track %d: Source: %@ Output: %@, Mono", i + 1, [NSString stringWithUTF8String:audio->lang.description], outputCodec]];
- else if (audio->out.mixdown == HB_AMIXDOWN_STEREO)
- thisJobAudioInfo = [thisJobAudioInfo stringByAppendingString:[NSString stringWithFormat:@"Track %d: Source: %@ Output: %@, Stereo", i + 1, [NSString stringWithUTF8String:audio->lang.description], outputCodec]];
- else if (audio->out.mixdown == HB_AMIXDOWN_DOLBY)
- thisJobAudioInfo = [thisJobAudioInfo stringByAppendingString:[NSString stringWithFormat:@"Track %d: Source: %@ Output: %@, Dolby Surround", i + 1, [NSString stringWithUTF8String:audio->lang.description], outputCodec]];
- else if (audio->out.mixdown == HB_AMIXDOWN_DOLBYPLII)
- thisJobAudioInfo = [thisJobAudioInfo stringByAppendingString:[NSString stringWithFormat:@"Track %d: Source: %@ Output: %@, Dolby Pro Logic II", i + 1, [NSString stringWithUTF8String:audio->lang.description], outputCodec]];
- else if (audio->out.mixdown == HB_AMIXDOWN_6CH)
- thisJobAudioInfo = [thisJobAudioInfo stringByAppendingString:[NSString stringWithFormat:@"Track %d: Source: %@ Output: %@, 6 Channel Discreet", i + 1, [NSString stringWithUTF8String:audio->lang.description], outputCodec]];
- else
- thisJobAudioInfo = [thisJobAudioInfo stringByAppendingString:[NSString stringWithFormat:@"Track %d: Source: %@ Output: Unknown Codec Info", i + 1, [NSString stringWithUTF8String:audio->lang.description]]];
-
- thisJobAudioInfo = [thisJobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", %d kbps, %d Hz", audio->out.bitrate, audio->out.samplerate]];
-
- }
- audioinfo_summary = [[NSString stringWithFormat:@"%@",thisJobAudioInfo]retain];
- audioinfo_codecs = [[NSString stringWithFormat:@"%@",thisJobAudioCodecs]retain];
-
- 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, job->subtitle);
- if (aSubtitle)
- subtitleLang = [[NSString stringWithUTF8String:aSubtitle->lang] retain];
- }
-
- // Calculate and store output dimensions and anamorphic dimensions
- if (pixel_ratio == 1) // Original PAR Implementation, now called Strict Anamorphic
- {
- output_width = titleWidth - crop[2] - crop[3];
- output_height = titleHeight - crop[0] - crop[1];
- anamorphic_width = output_width * pixel_aspect_width / pixel_aspect_height;
- anamorphic_height = output_height;
- }
- else if (pixel_ratio == 2) // Loose Anamorphic
- {
- // call hb_set_anamorphic_size to do a "dry run" to get the values to be
- // used by libhb for loose anamorphic.
- int par_width, par_height;
- hb_set_anamorphic_size(job, &output_width, &output_height, &par_width, &par_height);
- anamorphic_width = output_width * par_width / par_height;
- anamorphic_height = output_height;
- }
- else // No Anamorphic
- {
- output_width = width;
- output_height = height;
- anamorphic_width = 0; // not needed for this case
- anamorphic_height = 0; // not needed for this case
- }
-
- }
- return self;
-}
-
-- (void) dealloc
-{
- // jobGroup is a weak reference and does not need to be deleted
- [x264opts release];
- [file release];
- [titleName release];
- [subtitleLang release];
- [audioinfo_summary release];
- [audioinfo_codecs release];
- [super dealloc];
-}
-
-- (HBJobGroup *) jobGroup
-{
- 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 *) attributedDescriptionWithIcon: (BOOL)withIcon
- withTitle: (BOOL)withTitle
- withPassName: (BOOL)withPassName
- withFormatInfo: (BOOL)withFormatInfo
- withDestination: (BOOL)withDestination
- withPictureInfo: (BOOL)withPictureInfo
- withVideoInfo: (BOOL)withVideoInfo
- withx264Info: (BOOL)withx264Info
- withAudioInfo: (BOOL)withAudioInfo
- withSubtitleInfo: (BOOL)withSubtitleInfo
-
-{
- NSMutableAttributedString * finalString = [[[NSMutableAttributedString alloc] initWithString: @""] autorelease];
-
- // Attributes
- 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)
- {
- if (withIcon)
- {
- NSFileWrapper * wrapper = [[[NSFileWrapper alloc] initWithPath:[[NSBundle mainBundle] pathForImageResource: @"JobSmall"]] autorelease];
- NSTextAttachment * imageAttachment = [[[NSTextAttachment alloc] initWithFileWrapper:wrapper] autorelease];
-
- NSDictionary* imageAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithFloat: -2.0], NSBaselineOffsetAttributeName,
- imageAttachment, NSAttachmentAttributeName,
- ps, NSParagraphStyleAttributeName,
- nil];
-
- NSAttributedString * imageAsString = [[[NSAttributedString alloc]
- initWithString: [NSString stringWithFormat:@"%C%C", NSAttachmentCharacter, NSTabCharacter]
- attributes: imageAttributes] autorelease];
-
- [finalString appendAttributedString:imageAsString];
- }
-
- // 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:titleAttr];
-
- NSString * summaryInfo;
-
- NSString * chapterString = (chapter_start == chapter_end) ?
- [NSString stringWithFormat:@"Chapter %d", chapter_start] :
- [NSString stringWithFormat:@"Chapters %d through %d", chapter_start, chapter_end];
-
- BOOL hasIndepthScan = (pass == -1);
- int numVideoPasses = 0;
-
- // To determine number of video passes, we need to skip past the subtitle scan.
- if (hasIndepthScan)
- {
- // When job is the one currently being processed, then the next in its group
- // is the the first job in the queue.
- HBJob * nextjob = nil;
- NSUInteger 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, pass + 1 );
-
- if (hasIndepthScan && numVideoPasses == 1)
- 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)", titleIndex, chapterString, numVideoPasses];
- else if (numVideoPasses == 1)
- summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, Single Video Pass)", titleIndex, chapterString];
- else
- summaryInfo = [NSString stringWithFormat: @" (Title %d, %@, %d Video Passes)", titleIndex, chapterString, numVideoPasses];
-
- [finalString appendString:[NSString stringWithFormat:@"%@\n", summaryInfo] withAttributes:detailAttr];
-
- // Insert a short-in-height line to put some white space after the title
- [finalString appendString:@"\n" withAttributes:shortHeightAttr];
- }
-
- // End of title stuff
-
-
- // Pass Name
- if (withPassName)
- {
- if (withIcon)
- {
- NSString * imageName;
- switch (pass)
- {
- case -1: imageName = @"JobPassSubtitleSmall"; break;
- case 0: imageName = @"JobPassFirstSmall"; break;
- case 1: imageName = @"JobPassFirstSmall"; break;
- case 2: imageName = @"JobPassSecondSmall"; break;
- default: imageName = @"JobPassUnknownSmall"; break;
- }
-
- NSFileWrapper * wrapper = [[[NSFileWrapper alloc] initWithPath:[[NSBundle mainBundle] pathForImageResource: imageName]] autorelease];
- NSTextAttachment * imageAttachment = [[[NSTextAttachment alloc] initWithFileWrapper:wrapper] autorelease];
-
- NSDictionary* imageAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithFloat: -2.0], NSBaselineOffsetAttributeName,
- imageAttachment, NSAttachmentAttributeName,
- ps, NSParagraphStyleAttributeName,
- nil];
-
- NSAttributedString * imageAsString = [[[NSAttributedString alloc]
- initWithString: [NSString stringWithFormat:@"%C%C", NSAttachmentCharacter, NSTabCharacter]
- attributes: imageAttributes] autorelease];
-
- [finalString appendAttributedString:imageAsString];
- }
-
- NSString * jobPassName;
- if (pass == -1)
- jobPassName = NSLocalizedString (@"Deep Scan", nil);
- else
- {
- int passNum = MAX( 1, pass );
- if (passNum == 0)
- jobPassName = NSLocalizedString (@"1st Pass", nil);
- else if (passNum == 1)
- jobPassName = NSLocalizedString (@"1st Pass", nil);
- else if (passNum == 2)
- jobPassName = NSLocalizedString (@"2nd Pass", nil);
- else
- jobPassName = [NSString stringWithFormat: NSLocalizedString(@"Pass %d", nil), passNum];
- }
- [finalString appendString:[NSString stringWithFormat:@"%@\n", jobPassName] withAttributes:detailBoldAttr];
- }
-
- // Video Codec needed by FormatInfo and withVideoInfo
- NSString * jobVideoCodec = nil;
- if (withFormatInfo || withVideoInfo)
- {
- // 2097152
- // Video Codec settings (Encoder in the gui)
- if (vcodec == HB_VCODEC_FFMPEG)
- jobVideoCodec = @"FFmpeg"; // HB_VCODEC_FFMPEG
- else if (vcodec == HB_VCODEC_XVID)
- jobVideoCodec = @"XviD"; // HB_VCODEC_XVID
- else if (vcodec == HB_VCODEC_X264)
- {
- // Deterimine for sure how we are now setting iPod uuid atom
- 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
- }
- }
- if (jobVideoCodec == nil)
- jobVideoCodec = @"unknown";
-
- if (withFormatInfo)
- {
- NSString * jobFormatInfo;
- // Muxer settings (File Format in the gui)
- if (mux == 65536 || mux == 131072 || mux == 1048576)
- jobFormatInfo = @"MP4"; // HB_MUX_MP4,HB_MUX_PSP,HB_MUX_IPOD
- else if (mux == 262144)
- jobFormatInfo = @"AVI"; // HB_MUX_AVI
- else if (mux == 524288)
- jobFormatInfo = @"OGM"; // HB_MUX_OGM
- else if (mux == 2097152)
- jobFormatInfo = @"MKV"; // HB_MUX_MKV
- else
- jobFormatInfo = @"unknown";
-
- if (chapter_markers == 1)
- jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video + %@ Audio, Chapter Markers\n", jobFormatInfo, jobVideoCodec, audioinfo_codecs];
- else
- jobFormatInfo = [NSString stringWithFormat:@"%@ Container, %@ Video + %@ Audio\n", jobFormatInfo, jobVideoCodec, audioinfo_codecs];
-
- [finalString appendString: @"Format: " withAttributes:detailBoldAttr];
- [finalString appendString: jobFormatInfo withAttributes:detailAttr];
- }
-
- if (withDestination)
- {
- [finalString appendString: @"Destination: " withAttributes:detailBoldAttr];
- [finalString appendString:[NSString stringWithFormat:@"%@\n", file] withAttributes:detailAttr];
- }
-
-
- if (withPictureInfo)
- {
- NSString * jobPictureInfo;
- if (pixel_ratio == 1) // Original PAR Implementation, now called Strict Anamorphic
- jobPictureInfo = [NSString stringWithFormat:@"%d x %d (%d x %d Strict Anamorphic)", output_width, output_height, anamorphic_width, anamorphic_height];
- else if (pixel_ratio == 2) // Loose Anamorphic
- jobPictureInfo = [NSString stringWithFormat:@"%d x %d (%d x %d Loose Anamorphic)", output_width, output_height, anamorphic_width, anamorphic_height];
- else
- jobPictureInfo = [NSString stringWithFormat:@"%d x %d", output_width, output_height];
- if (keep_ratio == 1)
- jobPictureInfo = [jobPictureInfo stringByAppendingString:@" Keep Aspect Ratio"];
-
- if (grayscale == 1)
- jobPictureInfo = [jobPictureInfo stringByAppendingString:@", Grayscale"];
-
- if (deinterlace == 1)
- jobPictureInfo = [jobPictureInfo stringByAppendingString:@", Deinterlace"];
- if (withIcon) // implies indent the info
- [finalString appendString: @"\t" withAttributes:detailBoldAttr];
- [finalString appendString: @"Picture: " withAttributes:detailBoldAttr];
- [finalString appendString:[NSString stringWithFormat:@"%@\n", jobPictureInfo] withAttributes:detailAttr];
- }
-
- if (withVideoInfo)
- {
- NSString * jobVideoQuality;
- NSString * jobVideoDetail;
-
- if (vquality <= 0 || vquality >= 1)
- jobVideoQuality = [NSString stringWithFormat:@"%d kbps", vbitrate];
- else
- {
- NSNumber * vidQuality;
- vidQuality = [NSNumber numberWithInt:vquality * 100];
- // this is screwed up kind of. Needs to be formatted properly.
- if (crf == 1)
- jobVideoQuality = [NSString stringWithFormat:@"%@%% CRF", vidQuality];
- else
- jobVideoQuality = [NSString stringWithFormat:@"%@%% CQP", vidQuality];
- }
-
- if (vrate_base == 1126125)
- {
- // NTSC FILM 23.976
- jobVideoDetail = [NSString stringWithFormat:@"%@, %@, 23.976 fps", jobVideoCodec, jobVideoQuality];
- }
- else if (vrate_base == 900900)
- {
- // NTSC 29.97
- jobVideoDetail = [NSString stringWithFormat:@"%@, %@, 29.97 fps", jobVideoCodec, jobVideoQuality];
- }
- else
- {
- // Everything else
- jobVideoDetail = [NSString stringWithFormat:@"%@, %@, %d fps", jobVideoCodec, jobVideoQuality, vrate / vrate_base];
- }
- if (withIcon) // implies indent the info
- [finalString appendString: @"\t" withAttributes:detailBoldAttr];
- [finalString appendString: @"Video: " withAttributes:detailBoldAttr];
- [finalString appendString:[NSString stringWithFormat:@"%@\n", jobVideoDetail] withAttributes:detailAttr];
- }
-
- if (withx264Info)
- {
- if (vcodec == HB_VCODEC_X264 && x264opts)
- {
- if (withIcon) // implies indent the info
- [finalString appendString: @"\t" withAttributes:detailBoldAttr];
- [finalString appendString: @"x264 Options: " withAttributes:detailBoldAttr];
- [finalString appendString:[NSString stringWithFormat:@"%@\n", x264opts] withAttributes:detailAttr];
- }
- }
-
- if (withAudioInfo)
- {
- if (withIcon) // implies indent the info
- [finalString appendString: @"\t" withAttributes:detailBoldAttr];
- [finalString appendString: @"Audio: " withAttributes:detailBoldAttr];
- [finalString appendString:[NSString stringWithFormat:@"%@\n", audioinfo_summary] withAttributes:detailAttr];
- }
-
- if (withSubtitleInfo)
- {
- // subtitle scan == -1 in two cases:
- // autoselect: when pass == -1
- // none: when pass != -1
- if ((subtitle == -1) && (pass == -1))
- {
- if (withIcon) // implies indent the info
- [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:detailBoldAttr];
- [finalString appendString: @"Subtitles: " withAttributes:detailBoldAttr];
- [finalString appendString: subtitleLang withAttributes:detailAttr];
- }
- }
- }
-
-
- if ([[finalString string] hasSuffix: @"\n"])
- [finalString deleteCharactersInRange: NSMakeRange([[finalString string] length]-1, 1)];
-
- 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 -
-
-//------------------------------------------------------------------------------------
-// HBJobGroup
-//------------------------------------------------------------------------------------
-
-// Notification sent from HBJobGroup setStatus whenever the status changes.
-NSString *HBJobGroupStatusNotification = @"HBJobGroupStatusNotification";
-
-@implementation HBJobGroup
-
-+ (HBJobGroup *) jobGroup;
-{
- return [[[HBJobGroup alloc] init] autorelease];
-}
-
-- (id) init
-{
- if (self = [super init])
- {
- fJobs = [[NSMutableArray arrayWithCapacity:0] retain];
- fDescription = [[NSMutableAttributedString alloc] initWithString: @""];
- [self setNeedsDescription: NO];
- fStatus = HBStatusNone;
- }
- return self;
-}
-
-- (void) dealloc
-{
- [fPresetName release];
- [fJobs release];
- [super dealloc];
-}
-
-- (unsigned int) count
-{
- return [fJobs count];
-}
-
-- (void) addJob: (HBJob *)aJob
-{
- [aJob setJobGroup:self];
- [fJobs addObject: aJob];
- [self setNeedsDescription: YES];
- fLastDescriptionHeight = 0;
- fLastDescriptionWidth = 0;
-}
-
-- (HBJob *) jobAtIndex: (unsigned)index
-{
- return [fJobs objectAtIndex: index];
-}
-
-- (unsigned) indexOfJob: (HBJob *)aJob;
-{
- return [fJobs indexOfObject: aJob];
-}
-
-- (NSMutableArray *) fJobs
-{
- return fJobs;
-}
-
-- (void) setNeedsDescription: (BOOL)flag
-{
- fNeedsDescription = flag;
-}
-
-- (void) updateDescription
-{
- fNeedsDescription = NO;
-
- [fDescription deleteCharactersInRange: NSMakeRange(0, [fDescription length])];
-
- if ([self count] == 0)
- {
- NSAssert(NO, @" jobgroup with no jobs");
- return;
- }
-
- 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
- withVideoInfo: NO
- withx264Info: NO
- withAudioInfo: NO
- withSubtitleInfo: NO]];
-
-
- NSAttributedString * carriageReturn = [[NSAttributedString alloc] initWithString:@"\n"];
-
- for( job in fJobs )
- {
- int pass = job->pass;
- [fDescription appendAttributedString:carriageReturn];
- [fDescription appendAttributedString:
- [job attributedDescriptionWithIcon: YES
- withTitle: NO
- withPassName: YES
- withFormatInfo: NO
- withDestination: NO
- withPictureInfo: pass != -1
- withVideoInfo: pass != -1
- withx264Info: pass != -1
- withAudioInfo: pass == 0 || pass == 2
- withSubtitleInfo: YES]];
- }
-
-}
-
-- (NSMutableAttributedString *) attributedDescription
-{
- if (fNeedsDescription)
- [self updateDescription];
- return fDescription;
-}
-
-- (CGFloat) heightOfDescriptionForWidth:(CGFloat)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 updateDescription];
-
- // Calculate the height
- NSRect bounds = [fDescription boundingRectWithSize:NSMakeSize(width, 10000) options:NSStringDrawingUsesLineFragmentOrigin];
- fLastDescriptionHeight = bounds.size.height + 6.0; // add some border to bottom
- fLastDescriptionWidth = width;
- return fLastDescriptionHeight;
-
-/* supposedly another way to do this, in case boundingRectWithSize isn't working
- NSTextView* tmpView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, width, 1)];
- [[tmpView textStorage] setAttributedString:aString];
- [tmpView setHorizontallyResizable:NO];
- [tmpView setVerticallyResizable:YES];
-// [[tmpView textContainer] setHeightTracksTextView: YES];
-// [[tmpView textContainer] setContainerSize: NSMakeSize(width, 10000)];
- [tmpView sizeToFit];
- float height = [tmpView frame].size.height;
- [tmpView release];
- return height;
-*/
-}
-
-- (CGFloat) lastDescriptionHeight
-{
- return fLastDescriptionHeight;
-}
-
-- (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
-{
- return self->fStatus;
-}
-
-- (void) setPresetName: (NSString *)name
-{
- [name retain];
- [fPresetName release];
- fPresetName = name;
-}
-
-- (NSString *) presetName
-{
- return fPresetName;
-}
-
-- (NSString *) name
-{
- HBJob * firstJob = [self jobAtIndex:0];
- return firstJob ? firstJob->titleName : nil;
-}
-
-- (NSString *) destinationPath
-{
- HBJob * firstJob = [self jobAtIndex:0];
- return firstJob ? firstJob->file : nil;
-}
-
-@end
-
-
-#pragma mark -
-
-// Toolbar identifiers
-static NSString* HBQueueToolbar = @"HBQueueToolbar1";
-static NSString* HBQueueStartCancelToolbarIdentifier = @"HBQueueStartCancelToolbarIdentifier";
-static NSString* HBQueuePauseResumeToolbarIdentifier = @"HBQueuePauseResumeToolbarIdentifier";
-
-#pragma mark -
-
-@implementation HBQueueController
-
-//------------------------------------------------------------------------------------
-// init
-//------------------------------------------------------------------------------------
-- (id)init
-{
- if (self = [super initWithWindowNibName:@"Queue"])
- {
- // NSWindowController likes to lazily load its window nib. Since this
- // controller tries to touch the outlets before accessing the window, we
- // need to force it to load immadiately by invoking its accessor.
- //
- // If/when we switch to using bindings, this can probably go away.
- [self window];
-
- // Our defaults
- [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
- @"NO", @"QueueWindowIsOpen",
- @"NO", @"QueueShowsDetail",
- @"YES", @"QueueShowsJobsAsGroups",
- nil]];
-
- fJobGroups = [[NSMutableArray arrayWithCapacity:0] retain];
-
- // Register for HBJobGroup status changes
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(jobGroupStatusNotification:) name:HBJobGroupStatusNotification object:nil];
- }
- return self;
-}
-
-//------------------------------------------------------------------------------------
-// dealloc
-//------------------------------------------------------------------------------------
-- (void)dealloc
-{
- // clear the delegate so that windowWillClose is not attempted
- if( [[self window] delegate] == self )
- [[self window] setDelegate:nil];
-
- [fJobGroups release];
- [fCurrentJobGroup release];
- [fSavedExpandedItems release];
- [fSavedSelectedItems release];
-
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
- [super dealloc];
-}
-
-//------------------------------------------------------------------------------------
-// Receive HB handle
-//------------------------------------------------------------------------------------
-- (void)setHandle: (hb_handle_t *)handle
-{
- fHandle = handle;
-}
-
-//------------------------------------------------------------------------------------
-// Receive HBController
-//------------------------------------------------------------------------------------
-- (void)setHBController: (HBController *)controller
-{
- 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.
-//------------------------------------------------------------------------------------
-- (HBJobGroup *) currentJobGroup;
-{
- return fCurrentJobGroup;
-}
-
-//------------------------------------------------------------------------------------
-// Returns the HBJob (pass) that is currently being encoded; nil if no encoding is
-// occurring.
-//------------------------------------------------------------------------------------
-- (HBJob *) currentJob
-{
- return fCurrentJob;
-}
-
-#pragma mark -
-
-//------------------------------------------------------------------------------------
-// Displays and brings the queue window to the front
-//------------------------------------------------------------------------------------
-- (IBAction) showQueueWindow: (id)sender
-{
- [self showWindow:sender];
- [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"QueueWindowIsOpen"];
-}
-
-//------------------------------------------------------------------------------------
-// Show or hide the current job pane (fCurrentJobPane).
-//------------------------------------------------------------------------------------
-- (void) showCurrentJobPane: (BOOL)showPane
-{
- if (showPane == fCurrentJobPaneShown)
- return;
-
- // Things to keep in mind:
- // - When the current job pane is shown, it occupies the upper portion of the
- // window with the queue occupying the bottom portion of the window.
- // - When the current job pane is hidden, it slides up and out of view.
- // NSView setHidden is NOT used. The queue pane is resized to occupy the full
- // window.
-
- NSRect windowFrame = [[fCurrentJobPane superview] frame];
- NSRect queueFrame, jobFrame;
- if (showPane)
- NSDivideRect(windowFrame, &jobFrame, &queueFrame, NSHeight([fCurrentJobPane frame]), NSMaxYEdge);
- else
- {
- queueFrame = windowFrame;
- jobFrame = [fCurrentJobPane frame];
- jobFrame.origin.y = NSHeight(windowFrame);
- }
-
- // Move fCurrentJobPane
- NSDictionary * dict1 = [NSDictionary dictionaryWithObjectsAndKeys:
- fCurrentJobPane, NSViewAnimationTargetKey,
- [NSValue valueWithRect:jobFrame], NSViewAnimationEndFrameKey,
- nil];
-
- // Resize fQueuePane
- NSDictionary * dict2 = [NSDictionary dictionaryWithObjectsAndKeys:
- fQueuePane, NSViewAnimationTargetKey,
- [NSValue valueWithRect:queueFrame], NSViewAnimationEndFrameKey,
- nil];
-
- NSViewAnimation * anAnimation = [[[NSViewAnimation alloc] initWithViewAnimations:nil] autorelease];
- [anAnimation setViewAnimations:[NSArray arrayWithObjects:dict1, dict2, nil]];
- [anAnimation setDuration:0.25];
- [anAnimation setAnimationBlockingMode:NSAnimationBlocking]; // prevent user from resizing the window during an animation
- [anAnimation startAnimation];
-
- fCurrentJobPaneShown = showPane;
-}
-
-//------------------------------------------------------------------------------------
-// Sets fCurrentJobGroup to a new job group.
-//------------------------------------------------------------------------------------
-- (void) setCurrentJobGroup: (HBJobGroup *)aJobGroup
-{
- if (aJobGroup)
- [aJobGroup setStatus: HBStatusWorking];
-
- [aJobGroup retain];
- [fCurrentJobGroup release];
- fCurrentJobGroup = aJobGroup;
-}
-
-#pragma mark - Finding job groups
-
-//------------------------------------------------------------------------------------
-// Returns the first pending job with a specified destination path or nil if no such
-// job exists.
-//------------------------------------------------------------------------------------
-- (HBJobGroup *) pendingJobGroupWithDestinationPath: (NSString *)path
-{
- for( HBJobGroup * aJobGroup in fJobGroups )
- {
- if ([[aJobGroup destinationPath] isEqualToString: path])
- return aJobGroup;
- }
- return nil;
-}
-
-//------------------------------------------------------------------------------------
-// Locates and returns a HBJob whose sequence_id matches a specified value.
-//------------------------------------------------------------------------------------
-- (HBJob *) findJobWithID: (int)aJobID
-{
- for( HBJobGroup * aJobGroup in fJobGroups )
- {
- for( HBJob * job in [aJobGroup fJobs] )
- {
- if (job->sequence_id == aJobID)
- return job;
- }
- }
- return nil;
-}
-
-//------------------------------------------------------------------------------------
-// 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;
- }
- return nil;
-}
-
-#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;
-
- for( HBJobGroup * aJobGroup in fJobGroups )
- {
- 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
-
-//------------------------------------------------------------------------------------
-// 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
-{
- if (!fSavedExpandedItems)
- fSavedExpandedItems = [[NSMutableIndexSet alloc] init];
- else
- [fSavedExpandedItems removeAllIndexes];
-
- // 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;
- for( aJobGroup in fJobGroups )
- {
- if ([fOutlineView isItemExpanded: aJobGroup])
- [fSavedExpandedItems addIndex: [aJobGroup jobAtIndex:0]->sequence_id];
- }
-
- // Save the selection also.
-
- if (!fSavedSelectedItems)
- fSavedSelectedItems = [[NSMutableIndexSet alloc] init];
- else
- [fSavedSelectedItems removeAllIndexes];
-
- NSIndexSet * selectedRows = [fOutlineView selectedRowIndexes];
- NSInteger row = [selectedRows firstIndex];
- while (row != NSNotFound)
- {
- aJobGroup = [fOutlineView itemAtRow: row];
- [fSavedSelectedItems addIndex: [aJobGroup jobAtIndex:0]->sequence_id];
- row = [selectedRows indexGreaterThanIndex: row];
- }
-
-}
-
-//------------------------------------------------------------------------------------
-// Restores the expanded state of items in the outline view to match those saved by a
-// previous call to saveOutlineViewState.
-//------------------------------------------------------------------------------------
-- (void) restoreOutlineViewState
-{
- if (fSavedExpandedItems)
- {
- for( HBJobGroup * aJobGroup in fJobGroups )
- {
- HBJob * job = [aJobGroup jobAtIndex:0];
- if (job && [fSavedExpandedItems containsIndex: job->sequence_id])
- [fOutlineView expandItem: aJobGroup];
- }
- }
-
- if (fSavedSelectedItems)
- {
- NSMutableIndexSet * rowsToSelect = [[[NSMutableIndexSet alloc] init] autorelease];
- NSInteger i = 0;
- for( HBJobGroup * aJobGroup in fJobGroups )
- {
- HBJob * job = [aJobGroup jobAtIndex:0];
- if (job && [fSavedSelectedItems containsIndex: job->sequence_id])
- [rowsToSelect addIndex: i];
- i++;
- }
- if ([rowsToSelect count] == 0)
- [fOutlineView deselectAll: nil];
- else
- [fOutlineView selectRowIndexes:rowsToSelect byExtendingSelection:NO];
- }
-}
-
-//------------------------------------------------------------------------------------
-// Marks the icon region of a job group in the queue view as needing display.
-//------------------------------------------------------------------------------------
-- (void) updateJobGroupIconInQueue:(HBJobGroup*)aJobGroup
-{
- NSInteger row = [fOutlineView rowForItem: aJobGroup];
- NSInteger 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
-{
- NSInteger 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
-{
- if (fCurrentJobGroup)
- {
- fAnimationIndex++;
- fAnimationIndex %= 6; // there are 6 animation images; see outlineView:objectValueForTableColumn:byItem: below.
- [self updateJobGroupIconInQueue: fCurrentJobGroup];
- }
-}
-
-//------------------------------------------------------------------------------------
-// Starts animating the job icon of the currently processing job in the queue outline
-// view.
-//------------------------------------------------------------------------------------
-- (void) startAnimatingCurrentJobGroupInQueue
-{
- if (!fAnimationTimer)
- fAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0/12.0 // 1/12 because there are 6 images in the animation cycle
- target:self
- selector:@selector(animateCurrentJobGroupInQueue:)
- userInfo:nil
- repeats:YES] retain];
-}
-
-//------------------------------------------------------------------------------------
-// Stops animating the job icon of the currently processing job in the queue outline
-// view.
-//------------------------------------------------------------------------------------
-- (void) stopAnimatingCurrentJobGroupInQueue
-{
- if (fAnimationTimer && [fAnimationTimer isValid])
- {
- [fAnimationTimer invalidate];
- [fAnimationTimer release];
- fAnimationTimer = nil;
- }
-}
-
-//------------------------------------------------------------------------------------
-// Generate string to display in UI.
-//------------------------------------------------------------------------------------
-- (NSString *) progressStatusStringForJob: (HBJob *)job state: (hb_state_t *)s
-{
- if (s->state == HB_STATE_WORKING)
- {
- NSString * msg;
- if (job->pass == -1)
- msg = NSLocalizedString( @"Deep Scan", nil );
- else if (job->pass == 1)
- msg = NSLocalizedString( @"Analyzing video", nil );
- else if ((job->pass == 0) || (job->pass == 2))
- msg = NSLocalizedString( @"Encoding movie", nil );
- else
- return @""; // unknown condition!
-
- if( s->param.working.seconds > -1 )
- {
- return [NSString stringWithFormat:
- NSLocalizedString( @"%@ (%.2f fps, avg %.2f fps)", nil ),
- msg, s->param.working.rate_cur, s->param.working.rate_avg];
- }
- else
- return msg;
-
- }
-
- else if (s->state == HB_STATE_MUXING)
- return NSLocalizedString( @"Muxing", nil );
-
- else if (s->state == HB_STATE_PAUSED)
- return NSLocalizedString( @"Paused", nil );
-
- else if (s->state == HB_STATE_WORKDONE)
- return NSLocalizedString( @"Done", nil );
-
- return @"";
-}
-
-//------------------------------------------------------------------------------------
-// Generate string to display in UI.
-//------------------------------------------------------------------------------------
-- (NSString *) progressTimeRemainingStringForJob: (HBJob *)job state: (hb_state_t *)s
-{
- if (s->state == HB_STATE_WORKING)
- {
- #define p s->param.working
- if (p.seconds < 0)
- return @"";
-
- // Minutes always needed
- NSString * minutes;
- if (p.minutes > 1)
- minutes = [NSString stringWithFormat:NSLocalizedString( @"%d minutes ", nil ), p.minutes];
- else if (p.minutes == 1)
- minutes = NSLocalizedString( @"1 minute ", nil );
- else
- minutes = @"";
-
- if (p.hours >= 1)
- {
- NSString * hours;
- if (p.hours > 1)
- hours = [NSString stringWithFormat:NSLocalizedString( @"%d hours ", nil ), p.hours];
- else
- hours = NSLocalizedString( @"1 hour ", nil );
-
- return [NSString stringWithFormat:NSLocalizedString( @"%@%@remaining", nil ), hours, minutes];
- }
-
- else
- {
- NSString * seconds;
- if (p.seconds > 1)
- seconds = [NSString stringWithFormat:NSLocalizedString( @"%d seconds ", nil ), p.seconds];
- else
- seconds = NSLocalizedString( @"1 second ", nil );
-
- return [NSString stringWithFormat:NSLocalizedString( @"%@%@remaining", nil ), minutes, seconds];
- }
-
-/* here is code that does it more like the Finder
- if( p.seconds > -1 )
- {
- float estHours = (p.hours + (p.minutes / 60.0));
- float estMinutes = (p.minutes + (p.seconds / 60.0));
-
- if (estHours > 1.5)
- return [NSString stringWithFormat:NSLocalizedString( @"Time remaining: About %d hours", nil ), lrintf(estHours)];
- else if (estHours > 0.983) // 59 minutes
- return NSLocalizedString( @"Time remaining: About 1 hour", nil );
- else if (estMinutes > 1.5)
- return [NSString stringWithFormat:NSLocalizedString( @"Time remaining: About %d minutes", nil ), lrintf(estMinutes)];
- else if (estMinutes > 0.983) // 59 seconds
- return NSLocalizedString( @"Time remaining: About 1 minute", nil );
- else if (p.seconds <= 5)
- return NSLocalizedString( @"Time remaining: Less than 5 seconds", nil );
- else if (p.seconds <= 10)
- return NSLocalizedString( @"Time remaining: Less than 10 seconds", nil );
- else
- return NSLocalizedString( @"Time remaining: Less than 1 minute", nil );
- }
- else
- return NSLocalizedString( @"Time remaining: Calculating...", nil );
-*/
- #undef p
- }
-
- return @"";
-}
-
-//------------------------------------------------------------------------------------
-// Refresh progress bar (fProgressTextField) from current state.
-//------------------------------------------------------------------------------------
-- (void) updateProgressTextForJob: (HBJob *)job state: (hb_state_t *)s
-{
- NSString * statusMsg = [self progressStatusStringForJob:job state:s];
- NSString * timeMsg = [self progressTimeRemainingStringForJob:job state:s];
- if ([timeMsg length] > 0)
- statusMsg = [NSString stringWithFormat:@"%@ - %@", statusMsg, timeMsg];
- [fProgressTextField setStringValue:statusMsg];
-}
-
-//------------------------------------------------------------------------------------
-// Refresh progress bar (fProgressBar) from current state.
-//------------------------------------------------------------------------------------
-- (void) updateProgressBarWithState: (hb_state_t *)s
-{
- if (s->state == HB_STATE_WORKING)
- {
- #define p s->param.working
- [fProgressBar setIndeterminate:NO];
- float progress_total = 100.0 * ( p.progress + p.job_cur - 1 ) / p.job_count;
- [fProgressBar setDoubleValue:progress_total];
- #undef p
- }
-
- else if (s->state == HB_STATE_MUXING)
- {
- #define p s->param.muxing
- [fProgressBar setIndeterminate:YES];
- [fProgressBar startAnimation:nil];
- #undef p
- }
-
- else if (s->state == HB_STATE_WORKDONE)
- {
- [fProgressBar setIndeterminate:NO];
- [fProgressBar stopAnimation:nil];
- [fProgressBar setDoubleValue:0.0];
- }
-
- else
- [fProgressBar stopAnimation:nil]; // just in case in was animating
-}
-
-//------------------------------------------------------------------------------------
-// Refresh queue count text field (fQueueCountField).
-//------------------------------------------------------------------------------------
-- (void)updateQueueCountField
-{
- NSString * msg;
- 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];
-}
-
-//------------------------------------------------------------------------------------
-// Refresh the UI in the current job pane. Should be called whenever the current job
-// being processed has changed.
-//------------------------------------------------------------------------------------
-- (void)updateCurrentJobDescription
-{
- if (fCurrentJob)
- {
- switch (fCurrentJob->pass)
- {
- case -1: // Subtitle scan
- [fJobDescTextField setAttributedStringValue:
- [fCurrentJob attributedDescriptionWithIcon: NO
- withTitle: YES
- withPassName: YES
- withFormatInfo: NO
- withDestination: NO
- withPictureInfo: NO
- withVideoInfo: NO
- withx264Info: NO
- withAudioInfo: NO
- withSubtitleInfo: YES]];
- break;
-
- case 1: // video 1st pass
- [fJobDescTextField setAttributedStringValue:
- [fCurrentJob attributedDescriptionWithIcon: NO
- withTitle: YES
- withPassName: YES
- withFormatInfo: NO
- withDestination: NO
- withPictureInfo: YES
- withVideoInfo: YES
- withx264Info: YES
- withAudioInfo: NO
- withSubtitleInfo: NO]];
- break;
-
- case 0: // single pass
- case 2: // video 2nd pass + audio
- [fJobDescTextField setAttributedStringValue:
- [fCurrentJob attributedDescriptionWithIcon: NO
- withTitle: YES
- withPassName: YES
- withFormatInfo: NO
- withDestination: NO
- withPictureInfo: YES
- withVideoInfo: YES
- withx264Info: YES
- withAudioInfo: YES
- withSubtitleInfo: YES]];
- break;
-
- default: // unknown
- [fJobDescTextField setAttributedStringValue:
- [fCurrentJob attributedDescriptionWithIcon: NO
- withTitle: YES
- withPassName: YES
- withFormatInfo: NO
- withDestination: NO
- withPictureInfo: YES
- withVideoInfo: YES
- withx264Info: YES
- withAudioInfo: YES
- withSubtitleInfo: YES]];
- }
- }
- else
- {
- [fJobDescTextField setStringValue: @"No encodes pending"];