diff options
author | dynaflash <[email protected]> | 2007-09-11 15:03:01 +0000 |
---|---|---|
committer | dynaflash <[email protected]> | 2007-09-11 15:03:01 +0000 |
commit | 35c3cb421abbf6c79d640b5b9695198a75fe963b (patch) | |
tree | efa9f276410ef07b228c2203ebbed132b516d0cd /macosx/Controller.mm | |
parent | ba95beda3b2a3ab8454f7d57d2fe3bc03100fbbc (diff) |
MacGui: New queue enhancements
- clean up work related to starting and stopping of jobs to make sure the behavior is the same in both the queue window and the main window
- No longer adds jobs to queue when you've hit Start but then canceled the overwrite warning.
- Added overwrite alert when doing an Add to Queue. Was only happening previously when you did a Start.
- Stopping a job from either the Queue window or the Main window now goes through the same code path and so the behavior will be identical.
- In the main window, the Start button now changes to Start Queue once you've added things to the queue. This helps clear up any ambiguity about what that button will do
- Cancel button now named Stop. Recommended by BradleyS and/or hawkman I think because this button no longer cancels everything in the queue, just the current job. Wording in the stop warning dialog has been improved (mentions job title).
- The "Show Alert When Done" options now work when you have started the queue from the Queue window.
- Uses the term "passes" in main window
- Added unique icons for each pass type.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@949 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'macosx/Controller.mm')
-rw-r--r-- | macosx/Controller.mm | 426 |
1 files changed, 257 insertions, 169 deletions
diff --git a/macosx/Controller.mm b/macosx/Controller.mm index 297eaf7e2..86d18ff13 100644 --- a/macosx/Controller.mm +++ b/macosx/Controller.mm @@ -51,23 +51,6 @@ static NSString * AddToQueueIdentifier = @"Add to Queue Ite static NSString * ShowActivityIdentifier = @"Debug Output Item Identifier"; static NSString * ChooseSourceIdentifier = @"Choose Source Item Identifier"; -/** - * 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 (job->sequence_id == 0) - count++; - } - return count; -} /******************************* * HBController implementation * @@ -101,6 +84,7 @@ static int hb_group_count(hb_handle_t * h) /* Init others controllers */ [fPictureController SetHandle: fHandle]; [fQueueController setHandle: fHandle]; + [fQueueController setHBController: self]; fChapterTitlesDelegate = [[ChapterTitles alloc] init]; [fChapterTable setDataSource:fChapterTitlesDelegate]; @@ -433,7 +417,7 @@ static int hb_group_count(hb_handle_t * h) { return [NSArray arrayWithObjects: StartEncodingIdentifier, PauseEncodingIdentifier, AddToQueueIdentifier, ChooseSourceIdentifier, ShowQueueIdentifier, ShowActivityIdentifier, ToggleDrawerIdentifier, - NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, + NSToolbarCustomizeToolbarItemIdentifier, NSToolbarFlexibleSpaceItemIdentifier, NSToolbarSpaceItemIdentifier, NSToolbarSeparatorItemIdentifier, nil]; } @@ -451,9 +435,9 @@ static int hb_group_count(hb_handle_t * h) if ([ident isEqualToString: StartEncodingIdentifier]) { [toolbarItem setImage: [NSImage imageNamed: @"Stop"]]; - [toolbarItem setLabel: @"Cancel"]; - [toolbarItem setPaletteLabel: @"Cancel"]; - [toolbarItem setToolTip: @"Cancel Encoding"]; + [toolbarItem setLabel: @"Stop"]; + [toolbarItem setPaletteLabel: @"Stop"]; + [toolbarItem setToolTip: @"Stop Encoding"]; return YES; } if ([ident isEqualToString: PauseEncodingIdentifier]) @@ -490,7 +474,10 @@ static int hb_group_count(hb_handle_t * h) if ([ident isEqualToString: StartEncodingIdentifier]) { [toolbarItem setImage: [NSImage imageNamed: @"Play"]]; - [toolbarItem setLabel: @"Start"]; + if (hb_count(fHandle) > 0) + [toolbarItem setLabel: @"Start Queue"]; + else + [toolbarItem setLabel: @"Start"]; [toolbarItem setPaletteLabel: @"Start Encoding"]; [toolbarItem setToolTip: @"Start Encoding"]; return YES; @@ -707,8 +694,6 @@ static int hb_group_count(hb_handle_t * h) [self showNewScan: NULL]; } - BOOL jobGroups = [[NSUserDefaults standardUserDefaults] boolForKey:@"QueueShowsJobsAsGroups"]; - hb_state_t s; hb_get_state( fHandle, &s ); @@ -768,7 +753,7 @@ static int hb_group_count(hb_handle_t * h) [fRipIndicator setDoubleValue: 100.0 * progress_total]; // If progress bar hasn't been revealed at the bottom of the window, do - // that now. This code used to be in _Rip. I moved it to here to handle + // that now. This code used to be in doRip. I moved it to here to handle // the case where hb_start is called by HBQueueController and not from // HBController. if (!fRipIndicatorShown) @@ -832,6 +817,27 @@ static int hb_group_count(hb_handle_t * h) case HB_STATE_WORKDONE: { + // HB_STATE_WORKDONE happpens as a result of hblib 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. + + // Delete all remaining scans of this job, ie, delete whole encodes. + hb_job_t * job; + while( ( job = hb_job( fHandle, 0 ) ) && (job->sequence_id != 0) ) + hb_rem( fHandle, job ); + + // Start processing back up if jobs still left in queue + if (hb_count(fHandle) > 0) + { + hb_start(fHandle); + fEncodeState = 1; + // Validate the toolbar (hack). The toolbar will usually get autovalidated + // before we had the chance to restart the queue, hence it will now be in + // the wrong state. + [toolbar validateVisibleItems]; + break; + } + [fStatusField setStringValue: _( @"Done." )]; [fRipIndicator setIndeterminate: NO]; [fRipIndicator setDoubleValue: 0.0]; @@ -840,21 +846,6 @@ static int hb_group_count(hb_handle_t * h) /* Restore dock icon */ [self UpdateDockIcon: -1.0]; - if (jobGroups) - { - // Delete all remaining scans of this job - hb_job_t * job; - while( ( job = hb_job( fHandle, 0 ) ) && (job->sequence_id != 0) ) - hb_rem( fHandle, job ); - } - - // Start processing back up if jobs still left in queue - if (hb_count(fHandle) > 0) - { - hb_start(fHandle); - break; - } - if (fRipIndicatorShown) { NSRect frame = [fWindow frame]; @@ -888,7 +879,7 @@ static int hb_group_count(hb_handle_t * h) /*On Screen Notification*/ int status; NSBeep(); - status = NSRunAlertPanel(@"Put down that cocktail...",@"your HandBrake encode is done!", @"OK", nil, nil); + status = NSRunAlertPanel(@"Put down that cocktail...",@"Your HandBrake encode is done!", @"OK", nil, nil); [NSApp requestUserAttention:NSCriticalRequest]; if ( status == NSAlertDefaultReturn ) { @@ -943,12 +934,12 @@ static int hb_group_count(hb_handle_t * h) } /* Lets show the queue status here in the main window */ - int queue_count = jobGroups ? hb_group_count( fHandle ) : hb_count( fHandle ); + int queue_count = hb_count( fHandle ); if( queue_count ) { [fQueueStatus setStringValue: [NSString stringWithFormat: - @"%d task%s in the queue", - queue_count, ( queue_count > 1 ) ? "s" : ""]]; + @"%d pass%s in the queue", + queue_count, ( queue_count > 1 ) ? "es" : ""]]; } else { @@ -1540,114 +1531,142 @@ static int hb_group_count(hb_handle_t * h) +/* addToQueue: puts up an alert before ultimately calling doAddToQueue +*/ - (IBAction) addToQueue: (id) sender { -/* We get the destination directory from the destingation field here */ + /* We get the destination directory from the destination field here */ NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; /* We check for a valid destination here */ if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) { NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil); + return; } - else - { - - hb_list_t * list = hb_get_titles( fHandle ); - hb_title_t * title = (hb_title_t *) hb_list_item( list, - [fSrcTitlePopUp indexOfSelectedItem] ); - hb_job_t * job = title->job; - - // Assign a sequence number, starting at zero, to each job added so they can - // be lumped together in the UI. - job->sequence_id = -1; - - [self PrepareJob]; - - /* Destination file */ - job->file = [[fDstFile2Field stringValue] UTF8String]; - if( [fSubForcedCheck state] == NSOnState ) - { - job->subtitle_force = 1; - } else { - job->subtitle_force = 0; - } + /* We check for duplicate name here */ + if( [[NSFileManager defaultManager] fileExistsAtPath: + [fDstFile2Field stringValue]] ) + { + NSBeginCriticalAlertSheet( _( @"File already exists" ), + _( @"Cancel" ), _( @"Overwrite" ), NULL, fWindow, self, + @selector( overwriteAddToQueueAlertDone:returnCode:contextInfo: ), + NULL, NULL, [NSString stringWithFormat: + _( @"Do you want to overwrite %@?" ), + [fDstFile2Field stringValue]] ); + // overwriteAddToQueueAlertDone: will be called when the alert is dismissed. + } + else + { + [self doAddToQueue]; + } +} - /* - * subtitle of -1 is a scan - */ - if( job->subtitle == -1 ) - { - char *x264opts_tmp; - - /* - * When subtitle scan is enabled do a fast pre-scan job - * which will determine which subtitles to enable, if any. - */ - job->pass = -1; - x264opts_tmp = job->x264opts; - job->subtitle = -1; - - job->x264opts = NULL; - - job->indepth_scan = 1; - - job->select_subtitle = (hb_subtitle_t**)malloc(sizeof(hb_subtitle_t*)); - *(job->select_subtitle) = NULL; - - /* - * Add the pre-scan job - */ - job->sequence_id++; // for job grouping - hb_add( fHandle, job ); - - job->x264opts = x264opts_tmp; - } else { - job->select_subtitle = NULL; - } +/* overwriteAddToQueueAlertDone: called from the alert posted by addToQueue that asks + the user if they want to overwrite an exiting movie file. +*/ +- (void) overwriteAddToQueueAlertDone: (NSWindow *) sheet + returnCode: (int) returnCode contextInfo: (void *) contextInfo +{ + if( returnCode == NSAlertAlternateReturn ) + [self doAddToQueue]; +} - /* No subtitle were selected, so reset the subtitle to -1 (which before - * this point meant we were scanning - */ - if( job->subtitle == -2 ) - { - job->subtitle = -1; - } +- (void) doAddToQueue +{ + hb_list_t * list = hb_get_titles( fHandle ); + hb_title_t * title = (hb_title_t *) hb_list_item( list, [fSrcTitlePopUp indexOfSelectedItem] ); + hb_job_t * job = title->job; - if( [fVidTwoPassCheck state] == NSOnState ) - { - hb_subtitle_t **subtitle_tmp = job->select_subtitle; - job->indepth_scan = 0; + // Assign a sequence number, starting at zero, to each job added so they can + // be lumped together in the UI. + job->sequence_id = -1; - job->pass = 1; - job->sequence_id++; // for job grouping - hb_add( fHandle, job ); - - job->pass = 2; - job->sequence_id++; // for job grouping - - job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */ - strcpy(job->x264opts, [[fAdvancedOptions optionsString] UTF8String]); + [self PrepareJob]; - job->select_subtitle = subtitle_tmp; + /* Destination file */ + job->file = [[fDstFile2Field stringValue] UTF8String]; - hb_add( fHandle, job ); - } - else - { - job->indepth_scan = 0; - job->pass = 0; - job->sequence_id++; // for job grouping - hb_add( fHandle, job ); - } + if( [fSubForcedCheck state] == NSOnState ) + job->subtitle_force = 1; + else + job->subtitle_force = 0; + + /* + * subtitle of -1 is a scan + */ + if( job->subtitle == -1 ) + { + char *x264opts_tmp; + + /* + * When subtitle scan is enabled do a fast pre-scan job + * which will determine which subtitles to enable, if any. + */ + job->pass = -1; + x264opts_tmp = job->x264opts; + job->subtitle = -1; + + job->x264opts = NULL; + + job->indepth_scan = 1; + + job->select_subtitle = (hb_subtitle_t**)malloc(sizeof(hb_subtitle_t*)); + *(job->select_subtitle) = NULL; + + /* + * Add the pre-scan job + */ + job->sequence_id++; // for job grouping + hb_add( fHandle, job ); + + job->x264opts = x264opts_tmp; + } + else + job->select_subtitle = NULL; + + /* No subtitle were selected, so reset the subtitle to -1 (which before + * this point meant we were scanning + */ + if( job->subtitle == -2 ) + job->subtitle = -1; + + if( [fVidTwoPassCheck state] == NSOnState ) + { + hb_subtitle_t **subtitle_tmp = job->select_subtitle; + job->indepth_scan = 0; + + job->pass = 1; + job->sequence_id++; // for job grouping + hb_add( fHandle, job ); + + job->pass = 2; + job->sequence_id++; // for job grouping + + job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */ + strcpy(job->x264opts, [[fAdvancedOptions optionsString] UTF8String]); + + job->select_subtitle = subtitle_tmp; + + hb_add( fHandle, job ); + } + else + { + job->indepth_scan = 0; + job->pass = 0; + job->sequence_id++; // for job grouping + hb_add( fHandle, job ); + } + NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"]; /* Lets try to update stuff, taken from remove in the queue controller */ [fQueueController performSelectorOnMainThread: @selector( updateQueueUI ) withObject: NULL waitUntilDone: NO]; - } } +/* Rip: puts up an alert before ultimately calling doRip +*/ - (IBAction) Rip: (id) sender { /* Rip or Cancel ? */ @@ -1659,17 +1678,26 @@ static int hb_group_count(hb_handle_t * h) [self Cancel: sender]; return; } - /* if there is no job in the queue, then add it to the queue and rip - otherwise, there are already jobs in queue, so just rip the queue */ - int count = hb_count( fHandle ); - if( count < 1 ) - { - [self addToQueue: sender]; - } - /* We check for duplicate name here */ - if( [[NSFileManager defaultManager] fileExistsAtPath: - [fDstFile2Field stringValue]] ) + // If there are jobs in the queue, then this is a rip the queue + + if (hb_count( fHandle ) > 0) + { + [self doRip]; + return; + } + + // Before adding jobs to the queue, check for a valid destination. + + NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; + if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) + { + NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil); + return; + } + + /* We check for duplicate name here */ + if( [[NSFileManager defaultManager] fileExistsAtPath:[fDstFile2Field stringValue]] ) { NSBeginCriticalAlertSheet( _( @"File already exists" ), _( @"Cancel" ), _( @"Overwrite" ), NULL, fWindow, self, @@ -1677,31 +1705,34 @@ static int hb_group_count(hb_handle_t * h) NULL, NULL, [NSString stringWithFormat: _( @"Do you want to overwrite %@?" ), [fDstFile2Field stringValue]] ); - return; + + // overWriteAlertDone: will be called when the alert is dismissed. It will call doRip. + } + else + { + [self doRip]; } - /* We get the destination directory from the destination field here */ - NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; - /* We check for a valid destination here */ - if ([[NSFileManager defaultManager] fileExistsAtPath:destinationDirectory] == 0) - { - NSRunAlertPanel(@"Warning!", @"This is not a valid destination directory!", @"OK", nil, nil); - } - else - { - [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"]; - [self _Rip]; - } - - - } +/* overWriteAlertDone: called from the alert posted by Rip: that asks the user if they + want to overwrite an exiting movie file. +*/ - (void) overWriteAlertDone: (NSWindow *) sheet returnCode: (int) returnCode contextInfo: (void *) contextInfo { if( returnCode == NSAlertAlternateReturn ) { - [self _Rip]; + /* if there is no job in the queue, then add it to the queue and rip + otherwise, there are already jobs in queue, so just rip the queue */ + int count = hb_count( fHandle ); + if( count == 0 ) + { + [self doAddToQueue]; + } + + NSString *destinationDirectory = [[fDstFile2Field stringValue] stringByDeletingLastPathComponent]; + [[NSUserDefaults standardUserDefaults] setObject:destinationDirectory forKey:@"LastDestinationDirectory"]; + [self doRip]; } } @@ -1721,7 +1752,7 @@ static int hb_group_count(hb_handle_t * h) [NSApp terminate: self]; } -- (void) _Rip +- (void) doRip { /* Let libhb do the job */ hb_start( fHandle ); @@ -1729,25 +1760,82 @@ static int hb_group_count(hb_handle_t * h) fEncodeState = 1; } -- (IBAction) Cancel: (id) sender + + + + +//------------------------------------------------------------------------------------ +// Cancels the current job and proceeds with the next one in the queue. +//------------------------------------------------------------------------------------ +- (void) doCancelCurrentJob { - NSBeginCriticalAlertSheet( _( @"Cancel - Are you sure?" ), - _( @"Keep working" ), _( @"Cancel encoding" ), NULL, fWindow, self, - @selector( _Cancel:returnCode:contextInfo: ), NULL, NULL, - _( @"Encoding won't be recoverable." ) ); + // Stop the current job. hb_stop will only cancel the current pass and then set + // its state to HB_STATE_WORKDONE. It also does this asynchronously. So when we + // see the state has changed to HB_STATE_WORKDONE (in updateUI), we'll delete the + // remaining passes of the job and then start the queue back up if there are any + // remaining jobs. + + hb_stop( fHandle ); + fEncodeState = 2; // don't alert at end of processing since this was a cancel + } -- (void) _Cancel: (NSWindow *) sheet - returnCode: (int) returnCode contextInfo: (void *) contextInfo +//------------------------------------------------------------------------------------ +// Displays an alert asking user if the want to cancel encoding of current job. +// Cancel: returns immediately after posting the alert. Later, when the user +// acknowledges the alert, doCancelCurrentJob is called. +//------------------------------------------------------------------------------------ +- (IBAction)Cancel: (id)sender { - if( returnCode == NSAlertAlternateReturn ) + if (!fHandle) return; + + hb_job_t * job = hb_current_job(fHandle); + if (!job) return; + + // If command key is down, don't prompt + BOOL hasCmdKeyMask = ([[NSApp currentEvent] modifierFlags] & NSCommandKeyMask) != 0; + if (hasCmdKeyMask) + [self doCancelCurrentJob]; + else { - hb_stop( fHandle ); - /*set the fEncodeState State */ - fEncodeState = 2; + NSString * alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Do you want to stop encoding of %@?", nil), + [NSString stringWithUTF8String:job->title->name]]; + + // Which window to attach the sheet to? + NSWindow * docWindow; + if ([sender respondsToSelector: @selector(window)]) + docWindow = [sender window]; + else + docWindow = fWindow; + + NSBeginCriticalAlertSheet( + alertTitle, + NSLocalizedString(@"Keep Encoding", nil), NSLocalizedString(@"Stop Encoding", nil), nil, docWindow, self, + nil, @selector(didDimissCancelCurrentJob:returnCode:contextInfo:), nil, + NSLocalizedString(@"Your movie will be lost if you don't continue encoding.", nil), + [NSString stringWithUTF8String:job->title->name]); + + // didDimissCancelCurrentJob:returnCode:contextInfo: will be called when the dialog is dismissed + + // N.B.: didDimissCancelCurrentJob:returnCode:contextInfo: is designated as the dismiss + // selector to prevent a crash. As a dismiss selector, the alert window will + // have already be dismissed. If we don't do it this way, the dismissing of + // the alert window will cause the table view to be redrawn at a point where + // current job has been deleted by hblib but we don't know about it yet. This + // is a prime example of wy we need to NOT be relying on hb_current_job!!!! } } +- (void) didDimissCancelCurrentJob: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo +{ + if (returnCode == NSAlertAlternateReturn) + [self doCancelCurrentJob]; +} + + + + + - (IBAction) Pause: (id) sender { hb_state_t s; |