OSDN Git Service

MacGui: Queue improvements from travistex
authordynaflash <dynaflash@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Mon, 17 Sep 2007 14:46:36 +0000 (14:46 +0000)
committerdynaflash <dynaflash@b64f7644-9d1e-0410-96f1-a4d463321fa5>
Mon, 17 Sep 2007 14:46:36 +0000 (14:46 +0000)
- Detail info for each pass has been cleaned up. Each pass only displays info relevant to its pass. No line wrapping yet. :-(
- In the gui, "subtitle scan" changed to "in-depth scan". Is that what we want to call it?
- Fixed cases where single pass jobs were identified incorrectly in the queue.
- Removed incessant updating of the queue gui. The gui now only updates when something changes.

git-svn-id: svn://localhost/HandBrake/trunk@968 b64f7644-9d1e-0410-96f1-a4d463321fa5

macosx/English.lproj/Queue.nib/info.nib
macosx/English.lproj/Queue.nib/keyedobjects.nib
macosx/HBQueueController.h
macosx/HBQueueController.mm

index 9db2ce5..48b7c4b 100644 (file)
@@ -3,7 +3,7 @@
 <plist version="1.0">
 <dict>
        <key>IBDocumentLocation</key>
-       <string>121 594 453 434 0 0 1680 1028 </string>
+       <string>36 41 453 434 0 0 1680 1028 </string>
        <key>IBFramework Version</key>
        <string>446.1</string>
        <key>IBLockedObjects</key>
index 504ed1b..aeb7029 100644 (file)
Binary files a/macosx/English.lproj/Queue.nib/keyedobjects.nib and b/macosx/English.lproj/Queue.nib/keyedobjects.nib differ
index 1d5dd58..1afd58f 100644 (file)
     BOOL                         fShowsJobsAsGroups;
     BOOL                         fShowsDetail;
 #if HB_OUTLINE_QUEUE
-    NSMutableArray               *fEncodes;   // hblib's job list organized in a hierarchy. Contents are HBJobs.
+    NSMutableArray               *fEncodes;   // hblib's job list organized in a hierarchy. Contents are NSArrays of HBJobs.
     NSMutableIndexSet            *fSavedExpandedItems;
     unsigned int                 fSavedSelectedItem;
+    hb_job_t                     *fLastKnownCurrentJob;
 #endif
     
     //  +---------------fQueueWindow----------------+
index 09c73ec..d657fc8 100644 (file)
 // disappers.
 #define HB_UNI_QUEUE 0             // <--- NOT COMPLETELY FUNCTIONAL YET
 
-#define HB_ROW_HEIGHT_DETAIL       98.0
-#define HB_ROW_HEIGHT_NO_DETAIL    17.0
-#define HB_ROW_HEIGHT_ACTIVE_JOB   60.0
+#define HB_ROW_HEIGHT_TITLE_ONLY           17.0
+#define HB_ROW_HEIGHT_TITLE_WITH_SUMMARY   45.0
+#define HB_ROW_HEIGHT_INDEPTH_PASS         17.0
+#define HB_ROW_HEIGHT_1ST_PASS             54.0
+#define HB_ROW_HEIGHT_2ND_PASS             67.0
+
+//#define HB_ROW_HEIGHT_NO_DETAIL    17.0
+//#define HB_ROW_HEIGHT_ACTIVE_JOB   60.0
 
 //------------------------------------------------------------------------------------
 #pragma mark Job group functions
@@ -351,6 +356,7 @@ static NSString*    HBShowGroupsToolbarIdentifier             = @"HBQueueShowGro
     switch (pass)
     {
         case -1: return [NSImage imageNamed: @"JobPassSubtitleSmall"];
+        case  0: return [NSImage imageNamed: @"JobPassFirstSmall"];
         case  1: return [NSImage imageNamed: @"JobPassFirstSmall"];
         case  2: return [NSImage imageNamed: @"JobPassSecondSmall"];
         default: return [NSImage imageNamed: @"JobPassUnknownSmall"];
@@ -365,6 +371,7 @@ static NSString*    HBShowGroupsToolbarIdentifier             = @"HBQueueShowGro
     switch (pass)
     {
         case -1: return [NSImage imageNamed: @"JobPassSubtitleLarge"];
+        case  0: return [NSImage imageNamed: @"JobPassFirstLarge"];
         case  1: return [NSImage imageNamed: @"JobPassFirstLarge"];
         case  2: return [NSImage imageNamed: @"JobPassSecondLarge"];
         default: return [NSImage imageNamed: @"JobPassUnknownLarge"];
@@ -406,10 +413,10 @@ static NSString*    HBShowGroupsToolbarIdentifier             = @"HBQueueShowGro
 
 #if HB_OUTLINE_QUEUE
 //------------------------------------------------------------------------------------
-// Saves the state of the items that are currently expanded. Calling restoreExpandedItems
-// will restore the state of all items to match what was saved by saveExpandedItems.
+// Saves the state of the items that are currently expanded. Calling restoreOutlineViewState
+// will restore the state of all items to match what was saved by saveOutlineViewState.
 //------------------------------------------------------------------------------------
-- (void) saveExpandedItems
+- (void) saveOutlineViewState
 {
     if (!fSavedExpandedItems)
         fSavedExpandedItems = [[NSMutableIndexSet alloc] init];
@@ -456,9 +463,9 @@ static NSString*    HBShowGroupsToolbarIdentifier             = @"HBQueueShowGro
 #if HB_OUTLINE_QUEUE
 //------------------------------------------------------------------------------------
 // Restores the expanded state of items in the outline view to match those saved by a
-// previous call to saveExpandedItems.
+// previous call to saveOutlineViewState.
 //------------------------------------------------------------------------------------
-- (void) restoreExpandedItems
+- (void) restoreOutlineViewState
 {
     if (fSavedExpandedItems)
     {
@@ -533,12 +540,12 @@ static NSString*    HBShowGroupsToolbarIdentifier             = @"HBQueueShowGro
     [ps setLineBreakMode:NSLineBreakByClipping];
 
     static NSDictionary* detailAttribute = [[NSDictionary dictionaryWithObjectsAndKeys:
-                [NSFont systemFontOfSize:10.0], NSFontAttributeName,
+                [NSFont systemFontOfSize:11.0], NSFontAttributeName,
                 [NSColor darkGrayColor], NSForegroundColorAttributeName,
                 ps, NSParagraphStyleAttributeName,
                 nil] retain];
     static NSDictionary* detailHighlightedAttribute = [[NSDictionary dictionaryWithObjectsAndKeys:
-                [NSFont systemFontOfSize:10.0], NSFontAttributeName,
+                [NSFont systemFontOfSize:11.0], NSFontAttributeName,
                 [NSColor whiteColor], NSForegroundColorAttributeName,
                 ps, NSParagraphStyleAttributeName,
                 nil] retain];
@@ -589,7 +596,7 @@ static NSString*    HBShowGroupsToolbarIdentifier             = @"HBQueueShowGro
         if (job->pass == -1)
         {
             [aMutableString appendString:[NSString stringWithFormat:
-                    @"  (Title %d, %@, Subtitle Scan)", title->index, chapterString]];
+                    @"  (Title %d, %@, In-depth Scan)", title->index, chapterString]];
         }
         else
         {
@@ -793,6 +800,291 @@ static NSString*    HBShowGroupsToolbarIdentifier             = @"HBQueueShowGro
     return finalString;
 }
 
+
+
+- (NSAttributedString *)attributedDescriptionForJob: (hb_job_t *)job
+                                          withTitle: (BOOL)withTitle
+                                       withPassName: (BOOL)withPassName
+                                     withFormatInfo: (BOOL)withFormatInfo
+                                    withDestination: (BOOL)withDestination
+                                    withPictureInfo: (BOOL)withPictureInfo
+                                      withVideoInfo: (BOOL)withVideoInfo
+                                       withx264Info: (BOOL)withx264Info
+                                      withAudioInfo: (BOOL)withAudioInfo
+                                   withHighlighting: (BOOL)highlighted
+{
+    NSMutableArray * stringParts = [NSMutableArray arrayWithCapacity:0];
+    
+    hb_title_t * title = job->title;
+    
+    // Attributes
+    static NSMutableParagraphStyle *ps = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
+    [ps setLineBreakMode:NSLineBreakByClipping];
+
+    static NSDictionary* detailAttribute = [[NSDictionary dictionaryWithObjectsAndKeys:
+                [NSFont systemFontOfSize:10.0], NSFontAttributeName,
+                [NSColor darkGrayColor], NSForegroundColorAttributeName,
+                ps, NSParagraphStyleAttributeName,
+                nil] retain];
+    static NSDictionary* detailHighlightedAttribute = [[NSDictionary dictionaryWithObjectsAndKeys:
+                [NSFont systemFontOfSize:10.0], NSFontAttributeName,
+                [NSColor whiteColor], NSForegroundColorAttributeName,
+                ps, NSParagraphStyleAttributeName,
+                nil] retain];
+    static NSDictionary* titleAttribute = [[NSDictionary dictionaryWithObjectsAndKeys:
+                [NSFont systemFontOfSize:[NSFont systemFontSize]], NSFontAttributeName,
+                ps, NSParagraphStyleAttributeName,
+                nil] retain];
+
+
+    // Title with summary
+    NSString * titleString;
+    if (withTitle)
+    {
+        // Note: use title->name instead of title->dvd since name is just the chosen
+        // folder, instead of dvd which is the full path
+        titleString = [NSString stringWithUTF8String:title->name];
+
+        NSString * summaryInfo;
+    
+        NSString * chapterString = (job->chapter_start == job->chapter_end) ?
+                [NSString stringWithFormat:@"Chapter %d", job->chapter_start] :
+                [NSString stringWithFormat:@"Chapters %d through %d", job->chapter_start, job->chapter_end];
+
+        BOOL hasIndepthScan = (job->pass == -1);
+        int numVideoPasses = 0;
+
+        // To determine number of video passes, we need to skip past the in-depth scan.
+        if (fShowsJobsAsGroups && hasIndepthScan)
+        {
+            // When job is the one currently being processed, then the next in its group
+            // is the the first job in the queue.
+            hb_job_t * nextjob;
+            if (job == hb_current_job(fHandle))
+                nextjob = hb_job(fHandle, 0);
+            else
+                nextjob = hb_next_job(fHandle, job);
+            if (nextjob)    // Overly cautious in case there is no next job!
+                numVideoPasses = MIN( 2, nextjob->pass + 1 );
+        }
+        else
+            numVideoPasses = MIN( 2, job->pass + 1 );
+
+        if (hasIndepthScan && numVideoPasses == 1)
+            summaryInfo = [NSString stringWithFormat: @"  (Title %d, %@, In-depth Scan, Single Video Pass)", title->index, chapterString];
+        else if (hasIndepthScan && numVideoPasses > 1)
+            summaryInfo = [NSString stringWithFormat: @"  (Title %d, %@, In-depth Scan, %d Video Passes)", title->index, chapterString, numVideoPasses];
+        else if (numVideoPasses == 1)
+            summaryInfo = [NSString stringWithFormat: @"  (Title %d, %@, Single Video Pass)", title->index, chapterString];
+        else
+            summaryInfo = [NSString stringWithFormat: @"  (Title %d, %@, %d Video Passes)", title->index, chapterString, numVideoPasses];
+
+        [stringParts addObject: [NSString stringWithFormat:@"%@%@", titleString, summaryInfo]];
+    }
+    
+    // End of title stuff
+    
+
+    // Pass Name
+    if (withPassName)
+    {
+        NSString * jobPassName;
+        if (job->pass == -1)
+            jobPassName = NSLocalizedString (@"In-depth Scan", nil);
+        else
+        {
+            int passNum = MAX( 1, job->pass );
+            if (passNum == 0)
+                jobPassName = NSLocalizedString (@"Encode 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];
+        }
+        [stringParts addObject: jobPassName];
+    }
+
+    // Video Codec needed by FormatInfo and withVideoInfo
+    NSString * jobVideoCodec;
+    if (withFormatInfo || withVideoInfo)
+    {
+        // 2097152
+        /* Video Codec settings (Encoder in the gui) */
+        if (job->vcodec == 1)
+            jobVideoCodec = @"FFmpeg"; // HB_VCODEC_FFMPEG
+        else if (job->vcodec == 2)
+            jobVideoCodec = @"XviD"; // HB_VCODEC_XVID
+        else if (job->vcodec == 4)
+        {
+            /* Deterimine for sure how we are now setting iPod uuid atom */
+            if (job->h264_level) // We are encoding for iPod
+                jobVideoCodec = @"x264 (H.264 iPod)"; // HB_VCODEC_X264    
+            else
+                jobVideoCodec = @"x264 (H.264 Main)"; // HB_VCODEC_X264
+        }
+        else
+            jobVideoCodec = @"unknown";
+    }
+    
+    // Audio Codec needed by FormatInfo and AudioInfo
+    NSString * jobAudioCodec;
+    if (withFormatInfo || withAudioInfo)
+    {
+        if (job->acodec == 256)
+            jobAudioCodec = @"AAC"; // HB_ACODEC_FAAC
+        else if (job->acodec == 512)
+            jobAudioCodec = @"MP3"; // HB_ACODEC_LAME
+        else if (job->acodec == 1024)
+            jobAudioCodec = @"Vorbis"; // HB_ACODEC_VORBIS
+        else if (job->acodec == 2048)
+            jobAudioCodec = @"AC3"; // HB_ACODEC_AC3
+        else
+            jobAudioCodec = @"unknown";
+    }
+
+
+    if (withFormatInfo)
+    {
+        NSString * jobFormatInfo;
+        // Muxer settings (File Format in the gui)
+        if (job->mux == 65536 || job->mux == 131072 || job->mux == 1048576)
+            jobFormatInfo = @"MP4"; // HB_MUX_MP4,HB_MUX_PSP,HB_MUX_IPOD
+        else if (job->mux == 262144)
+            jobFormatInfo = @"AVI"; // HB_MUX_AVI
+        else if (job->mux == 524288)
+            jobFormatInfo = @"OGM"; // HB_MUX_OGM
+        else if (job->mux == 2097152)
+            jobFormatInfo = @"MKV"; // HB_MUX_MKV
+        else
+            jobFormatInfo = @"unknown";
+                
+        if (job->chapter_markers == 1)
+            jobFormatInfo = [NSString stringWithFormat:@"Format: %@ Container, %@ Video + %@ Audio, Chapter Markers", jobFormatInfo, jobVideoCodec, jobAudioCodec];
+        else
+            jobFormatInfo = [NSString stringWithFormat:@"Format: %@ Container, %@ Video + %@ Audio", jobFormatInfo, jobVideoCodec, jobAudioCodec];
+            
+        [stringParts addObject: jobFormatInfo];
+    }
+
+    if (withDestination)
+    {
+        NSString * jobDestinationInfo = [NSString stringWithFormat:@"Destination: %@", [NSString stringWithUTF8String:job->file]];
+        [stringParts addObject: jobDestinationInfo];
+    }
+
+
+    if (withPictureInfo)
+    {
+        NSString * jobPictureInfo;
+        /*integers for picture values deinterlace, crop[4], keep_ratio, grayscale, pixel_ratio, pixel_aspect_width, pixel_aspect_height,
+         maxWidth, maxHeight */
+        if (job->pixel_ratio == 1)
+        {
+            int titlewidth = title->width - job->crop[2] - job->crop[3];
+            int displayparwidth = titlewidth * job->pixel_aspect_width / job->pixel_aspect_height;
+            int displayparheight = title->height - job->crop[0] - job->crop[1];
+            jobPictureInfo = [NSString stringWithFormat:@"Picture: %dx%d (%dx%d Anamorphic)", displayparwidth, displayparheight, job->width, displayparheight];
+        }
+        else
+            jobPictureInfo = [NSString stringWithFormat:@"Picture: %dx%d", job->width, job->height];
+        if (job->keep_ratio == 1)
+            jobPictureInfo = [jobPictureInfo stringByAppendingString:@" Keep Aspect Ratio"];
+        
+        if (job->grayscale == 1)
+            jobPictureInfo = [jobPictureInfo stringByAppendingString:@", Grayscale"];
+        
+        if (job->deinterlace == 1)
+            jobPictureInfo = [jobPictureInfo stringByAppendingString:@", Deinterlace"];
+        [stringParts addObject: jobPictureInfo];
+    }
+    
+    if (withVideoInfo)
+    {
+        NSString * jobVideoQuality;
+        NSString * jobVideoDetail;
+        
+        if (job->vquality <= 0 || job->vquality >= 1)
+            jobVideoQuality = [NSString stringWithFormat:@"%d kbps", job->vbitrate];
+        else
+        {
+            NSNumber * vidQuality;
+            vidQuality = [NSNumber numberWithInt:job->vquality * 100];
+            // this is screwed up kind of. Needs to be formatted properly.
+            if (job->crf == 1)
+                jobVideoQuality = [NSString stringWithFormat:@"%@%% CRF", vidQuality];            
+            else
+                jobVideoQuality = [NSString stringWithFormat:@"%@%% CQP", vidQuality];
+        }
+        
+        if (job->vrate_base == 1126125)
+        {
+            /* NTSC FILM 23.976 */
+            jobVideoDetail = [NSString stringWithFormat:@"Video: %@, %@, 23.976 fps", jobVideoCodec, jobVideoQuality];
+        }
+        else if (job->vrate_base == 900900)
+        {
+            /* NTSC 29.97 */
+            jobVideoDetail = [NSString stringWithFormat:@"Video: %@, %@, 29.97 fps", jobVideoCodec, jobVideoQuality];
+        }
+        else
+        {
+            /* Everything else */
+            jobVideoDetail = [NSString stringWithFormat:@"Video: %@, %@, %d fps", jobVideoCodec, jobVideoQuality, job->vrate / job->vrate_base];
+        }
+        [stringParts addObject: jobVideoDetail];
+    }
+    
+    if (withx264Info)
+    {
+        NSString * jobx264Info;
+        if (job->x264opts)
+        {
+            jobx264Info = [NSString stringWithFormat:@"x264 Options: %@", [NSString stringWithUTF8String:job->x264opts]];
+            [stringParts addObject: jobx264Info];
+        }
+    }
+
+    if (withAudioInfo)
+    {
+        NSString * jobAudioInfo;
+        if ([jobAudioCodec isEqualToString: @"AC3"])
+            jobAudioInfo = [NSString stringWithFormat:@"Audio: %@, Pass-Through", jobAudioCodec];
+        else
+            jobAudioInfo = [NSString stringWithFormat:@"Audio: %@, %d kbps, %d Hz", jobAudioCodec, job->abitrate, job->arate];
+        
+        /* we now get the audio mixdown info for each of the two gui audio tracks */
+        /* lets do it the long way here to get a handle on things.
+            Hardcoded for two tracks for gui: audio_mixdowns[i] audio_mixdowns[i] */
+        int ai; // counter for each audios [] , macgui only allows for two audio tracks currently
+        for( ai = 0; ai < 2; ai++ )
+        {
+            if (job->audio_mixdowns[ai] == HB_AMIXDOWN_MONO)
+                jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Mono", ai + 1]];
+            if (job->audio_mixdowns[ai] == HB_AMIXDOWN_STEREO)
+                jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Stereo", ai + 1]];
+            if (job->audio_mixdowns[ai] == HB_AMIXDOWN_DOLBY)
+                jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Dolby Surround", ai + 1]];
+            if (job->audio_mixdowns[ai] == HB_AMIXDOWN_DOLBYPLII)
+                jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: Dolby Pro Logic II", ai + 1]];
+            if (job->audio_mixdowns[ai] == HB_AMIXDOWN_6CH)
+                jobAudioInfo = [jobAudioInfo stringByAppendingString:[NSString stringWithFormat:@", Track %d: 6-channel discreet", ai + 1]];
+        }
+        [stringParts addObject: jobAudioInfo];
+    }
+    
+    
+    NSMutableAttributedString * anAttributedString = [[[NSMutableAttributedString alloc]
+        initWithString:[stringParts componentsJoinedByString:@"\n"]
+        attributes:highlighted ? detailHighlightedAttribute : detailAttribute] autorelease];
+
+    if (withTitle)
+        [anAttributedString setAttributes: titleAttribute range: NSMakeRange(0, [titleString length])];
+            
+    return anAttributedString;
+}
+
 //------------------------------------------------------------------------------------
 // Generate string to display in UI.
 //------------------------------------------------------------------------------------
@@ -984,11 +1276,71 @@ static NSString*    HBShowGroupsToolbarIdentifier             = @"HBQueueShowGro
 
     if (job)
     {
-        [fJobDescTextField setAttributedStringValue:[self attributedDescriptionForJob:job withTitle:YES withDetail:YES withHighlighting:NO]];
+        if (fLastKnownCurrentJob != job)
+        {
+            switch (job->pass)
+            {
+                case -1:  // in-depth scan
+                    [fJobDescTextField setAttributedStringValue:
+                        [self attributedDescriptionForJob:job
+                                    withTitle: YES
+                                 withPassName: YES
+                               withFormatInfo: NO
+                              withDestination: NO
+                              withPictureInfo: NO
+                                withVideoInfo: NO
+                                 withx264Info: NO
+                                withAudioInfo: NO
+                             withHighlighting: NO]];
+                    break;
+                    
+                case 1:  // video 1st pass
+                    [fJobDescTextField setAttributedStringValue:
+                        [self attributedDescriptionForJob:job
+                                    withTitle: YES
+                                 withPassName: YES
+                               withFormatInfo: NO
+                              withDestination: NO
+                              withPictureInfo: YES
+                                withVideoInfo: YES
+                                 withx264Info: YES
+                                withAudioInfo: NO
+                             withHighlighting: NO]];
+                    break;
+                
+                case 0:  // single pass
+                case 2:  // video 2nd pass + audio
+                    [fJobDescTextField setAttributedStringValue:
+                        [self attributedDescriptionForJob:job
+                                    withTitle: YES
+                                 withPassName: YES
+                               withFormatInfo: NO
+                              withDestination: NO
+                              withPictureInfo: YES
+                                withVideoInfo: YES
+                                 withx264Info: YES
+                                withAudioInfo: YES
+                             withHighlighting: NO]];
+                    break;
+                
+                default: // unknown
+                    [fJobDescTextField setAttributedStringValue:
+                        [self attributedDescriptionForJob:job
+                                    withTitle: YES
+                                 withPassName: YES
+                               withFormatInfo: NO
+                              withDestination: NO
+                              withPictureInfo: YES
+                                withVideoInfo: YES
+                                 withx264Info: YES
+                                withAudioInfo: YES
+                             withHighlighting: NO]];
+            }
+
+            [self showCurrentJobPane:YES];
+            [fJobIconView setImage: fShowsJobsAsGroups ? [NSImage imageNamed:@"JobLarge"] : [self largeImageForPass: job->pass] ];
+        }
 
-        [self showCurrentJobPane:YES];
-        [fJobIconView setImage: fShowsJobsAsGroups ? [NSImage imageNamed:@"JobLarge"] : [self largeImageForPass: job->pass] ];
-        
         NSString * statusMsg = [self progressStatusStringForJob:job state:&s];
         NSString * timeMsg = [self progressTimeRemainingStringForJob:job state:&s];
         if ([timeMsg length] > 0)
@@ -1003,6 +1355,8 @@ static NSString*    HBShowGroupsToolbarIdentifier             = @"HBQueueShowGro
         [self showCurrentJobPane:NO];
         [fProgressBar stopAnimation:nil];    // just in case in was animating
     }
+        
+    fLastKnownCurrentJob = job;
 }
 
 //------------------------------------------------------------------------------------
@@ -1012,11 +1366,11 @@ static NSString*    HBShowGroupsToolbarIdentifier             = @"HBQueueShowGro
 - (void)updateQueueUI
 {
 #if HB_OUTLINE_QUEUE
-    [self saveExpandedItems];
+    [self saveOutlineViewState];
     [self rebuildEncodes];
     [fOutlineView noteNumberOfRowsChanged];
     [fOutlineView reloadData];
-    [self restoreExpandedItems];
+    [self restoreOutlineViewState];
 #else
     [fTaskView noteNumberOfRowsChanged];
     [fTaskView reloadData];
@@ -1738,13 +2092,22 @@ static float spacingWidth = 3.0;
     {
         hb_job_t * j = [item job];
         NSAssert (j != nil, @"job is nil");
-        if (j->pass != -1)
-            return HB_ROW_HEIGHT_DETAIL;
+        if (j->pass == -1)
+            return HB_ROW_HEIGHT_INDEPTH_PASS;
+        else if (j->pass == 1)
+            return HB_ROW_HEIGHT_1ST_PASS;
+        else if ((j->pass == 2) || (j->pass == 0))
+            return HB_ROW_HEIGHT_2ND_PASS;
         else
-            return HB_ROW_HEIGHT_NO_DETAIL;
+            return HB_ROW_HEIGHT_TITLE_ONLY;    // unknown!
     }
     else
-        return HB_ROW_HEIGHT_NO_DETAIL;
+    {
+        if ([outlineView isItemExpanded: item])
+            return HB_ROW_HEIGHT_TITLE_WITH_SUMMARY;
+        else
+            return HB_ROW_HEIGHT_TITLE_ONLY;
+    }
 }
 
 - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
@@ -1755,20 +2118,52 @@ static float spacingWidth = 3.0;
         if ([[tableColumn identifier] isEqualToString:@"desc"])
         {
             hb_job_t * job = [item job];
-            return [self attributedDescriptionForJob:job withTitle:NO withDetail:fShowsDetail withHighlighting:highlighted];
-/*
-            if (job->pass == -1)
-                return @"Subtitle Scan";
-            else
+            switch (job->pass)
             {
-                int passNum = MAX( 1, job->pass );
-                if (passNum == 1)
-                    return @"1st Pass";
-                if (passNum == 2)
-                    return @"2nd Pass";
-                return [NSString stringWithFormat: @"Pass %d", passNum];
+                case -1:  // in-depth scan
+                    return [self attributedDescriptionForJob:job
+                                    withTitle: NO
+                                 withPassName: YES
+                               withFormatInfo: NO
+                              withDestination: NO
+                              withPictureInfo: NO
+                                withVideoInfo: NO
+                                 withx264Info: NO
+                                withAudioInfo: NO
+                             withHighlighting: highlighted];
+                    break;
+                
+                case 1:  // video 1st pass
+                    return [self attributedDescriptionForJob:job
+                                    withTitle: NO
+                                 withPassName: YES
+                               withFormatInfo: NO
+                              withDestination: NO
+                              withPictureInfo: YES
+                                withVideoInfo: YES
+                                 withx264Info: YES
+                                withAudioInfo: NO
+                             withHighlighting: highlighted];
+                    break;
+                
+                case 0:  // single pass
+                case 2:  // video 2nd pass + audio
+                    return [self attributedDescriptionForJob:job
+                                    withTitle: NO
+                                 withPassName: YES
+                               withFormatInfo: NO
+                              withDestination: NO
+                              withPictureInfo: YES
+                                withVideoInfo: YES
+                                 withx264Info: YES
+                                withAudioInfo: YES
+                             withHighlighting: highlighted];
+                    break;
+                
+                default:
+                    return @"unknown";
             }
-*/
+            
         }
     }
     
@@ -1776,7 +2171,31 @@ static float spacingWidth = 3.0;
     {
         hb_job_t * job = [[item objectAtIndex:0] job];
         if ([[tableColumn identifier] isEqualToString:@"desc"])
-            return [self attributedDescriptionForJob:job withTitle:YES withDetail:NO withHighlighting:highlighted];    
+        {
+            if ([fOutlineView isItemExpanded: item])
+                return [self attributedDescriptionForJob:job
+                                        withTitle: YES
+                                     withPassName: NO
+                                   withFormatInfo: YES
+                                  withDestination: YES
+                                  withPictureInfo: NO
+                                    withVideoInfo: NO
+                                     withx264Info: NO
+                                    withAudioInfo: NO
+                                 withHighlighting: highlighted];
+            else
+                return [self attributedDescriptionForJob:job
+                                        withTitle: YES
+                                     withPassName: NO
+                                   withFormatInfo: NO
+                                  withDestination: NO
+                                  withPictureInfo: NO
+                                    withVideoInfo: NO
+                                     withx264Info: NO
+                                    withAudioInfo: NO
+                                 withHighlighting: highlighted];
+        }
+        
     }
 
     return @"";
@@ -1822,6 +2241,16 @@ static float spacingWidth = 3.0;
     }
 }
 
+- (void)outlineView:(NSOutlineView *)outlineView willDisplayOutlineCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+    // By default, the discolsure image gets centered vertically in the cell. We want
+    // always at the top.
+    if ([outlineView isItemExpanded: item])
+        [cell setImagePosition: NSImageAbove];
+    else
+        [cell setImagePosition: NSImageOnly];
+}
+
 #endif
 
 @end