OSDN Git Service

dvdnav: fix crash when poorly masterd disc has no menus
[handbrake-jp/handbrake-jp-git.git] / macosx / InstantHandBrake / ExpressController.m
index c22912e..37ab8b0 100644 (file)
@@ -1,7 +1,18 @@
+/* This file is part of the HandBrake source code.
+   Homepage: <http://handbrake.fr/>.
+   It may be used under the terms of the GNU General Public License. */
+
 #import "ExpressController.h"
-#import "DriveDetector.h"
 
-#define INSERT_STRING @"Insert a DVD"
+#define INSERT_STRING       @"Insert a DVD"
+#define TOOLBAR_START       @"TOOLBAR_START"
+#define TOOLBAR_PAUSE       @"TOOLBAR_PAUSE"
+#define TOOLBAR_OPEN        @"TOOLBAR_OPEN"
+#define TOOLBAR_ADVANCED    @"TOOLBAR_ADVANCED"
+
+#define p fState->param
+
+#import "Device.h"
 
 @interface ExpressController (Private)
 
 - (void) openBrowseDidEnd: (NSOpenPanel *) sheet returnCode: (int)
     returnCode contextInfo: (void *) contextInfo;
 - (void) openEnable: (BOOL) b;
-- (void) openTimer: (NSTimer *) timer;
 
+- (id) updatePopUpIcon: (id) value;
 - (void) convertShow;
 - (void) convertEnable: (BOOL) b;
-- (void) convertTimer: (NSTimer *) timer;
 
 @end
 
 - (void) awakeFromNib
 {
     NSEnumerator * enumerator;
-
+    
+    /* NSToolbar initializations */
+    fToolbar = [[NSToolbar alloc] initWithIdentifier: @"InstantHandBrake Toolbar"];
+    [fToolbar setDelegate: self];
+    [fToolbar setAllowsUserCustomization: NO];
+    [fToolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
+    [fToolbar setVisible:NO];
+    [fWindow setShowsToolbarButton:NO];
+    [fWindow setToolbar: fToolbar];
+        
     /* Show the "Open DVD" interface */
     fDriveDetector = [[DriveDetector alloc] initWithCallback: self
         selector: @selector( openUpdateDrives: )];
     [tableColumn setDataCell: buttonCell];
 
     /* Preferences */
-    fConvertFolderString = [@"~/Movies" stringByExpandingTildeInPath];
+    fConvertFolderString = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"];
     [fConvertFolderString retain];
 }
 
 - (void) applicationWillFinishLaunching: (NSNotification *) n
 {
-    fHandle = hb_init_express( HB_DEBUG_NONE, 0 );
+    fCore = [[HBCore alloc] init];
+    [fCore openInDebugMode:NO checkForUpdates:NO];
+    fHandle = [fCore hb_handle];
+    fState = [fCore hb_state];
     fList   = hb_get_titles( fHandle );
+    
+    fDevice = [[DeviceController alloc] init];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+    selector:@selector(scanningSource:)
+    name:@"HBCoreScanningNotification" object:nil];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+    selector:@selector(scanDone:)
+    name:@"HBCoreScanDoneNotification" object:nil];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+    selector:@selector(muxing:)
+    name:@"HBCoreMuxingNotification" object:nil];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+    selector:@selector(working:)
+    name:@"HBCoreWorkingNotification" object:nil];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self
+    selector:@selector(workDone:)
+    name:@"HBCoreWorkDoneNotification" object:nil];
+    
+    [GrowlApplicationBridge setGrowlDelegate: self];
 }
 
 - (void) applicationWillTerminate: (NSNotification *) n
 {
-    hb_close( &fHandle );
+    [fCore close];
+}
+
+- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
+{
+    if( !flag ) {
+        [fWindow  makeKeyAndOrderFront:nil];
+        return YES;
+    }
+    return NO;
+}
+
+- (NSToolbarItem *) toolbar: (NSToolbar *) toolbar itemForItemIdentifier: (NSString *) ident
+                    willBeInsertedIntoToolbar: (BOOL) flag
+{
+    NSToolbarItem * item;
+    item = [[NSToolbarItem alloc] initWithItemIdentifier: ident];
+
+    if ([ident isEqualToString: TOOLBAR_START])
+    {
+        [item setLabel: NSLocalizedString(@"Convert", "Convert")];
+        [item setPaletteLabel: NSLocalizedString(@"Convert/Cancel", @"Convert/Cancel")];
+        [item setImage: [NSImage imageNamed: @"Play"]];
+        [item setTarget: self];
+        [item setAction: @selector(convertGo:)];
+    }
+    else if ([ident isEqualToString: TOOLBAR_PAUSE])
+    {
+        [item setLabel: NSLocalizedString(@"Pause", "Pause")];
+        [item setPaletteLabel: NSLocalizedString(@"Pause/Resume", @"Pause/Resume")];
+        [item setImage: [NSImage imageNamed: @"Pause"]];
+        [item setTarget: self];
+        [item setAction: @selector(pauseGo:)];
+    }
+    else if ([ident isEqualToString: TOOLBAR_OPEN])
+    {
+        [item setLabel: NSLocalizedString(@"Open...", "Open...")];
+        [item setPaletteLabel: NSLocalizedString(@"Open Another Source", "Open Another Source")];
+        [item setImage: [NSImage imageNamed: @"Open"]];
+        [item setTarget: self];
+        [item setAction: @selector(openShow:)];
+    }
+    else
+    {
+        [item release];
+        return nil;
+    }
+
+    return item;
+}
+
+- (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
+{
+    return [NSArray arrayWithObjects: TOOLBAR_START, TOOLBAR_PAUSE,
+                                    NSToolbarFlexibleSpaceItemIdentifier, TOOLBAR_OPEN, nil];
+}
+
+- (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
+{
+    return [NSArray arrayWithObjects: TOOLBAR_START, TOOLBAR_PAUSE,
+                                        TOOLBAR_OPEN, NSToolbarFlexibleSpaceItemIdentifier, nil];
 }
 
 /***********************************************************************
                         title->seconds];
             }
         }
+        else if( [[col identifier] isEqualToString: @"Size"] )
+        {
+            return [NSString stringWithFormat:@"-"];
+        }
     }
     return nil;
 }
 - (void) openShow: (id) sender
 {
     NSRect frame  = [fWindow frame];
-    float  offset = [fConvertView frame].size.height -
-                    [fOpenView frame].size.height;
+    float  offset = [fConvertView frame].size.height -
+                    [fOpenView frame].size.height ) * [fWindow userSpaceScaleFactor];
 
     frame.origin.y    += offset;
     frame.size.height -= offset;
     [fWindow setContentView: fEmptyView];
     [fWindow setFrame: frame display: YES animate: YES];
+    [fToolbar setVisible:NO];
+    [fOpenProgressField setStringValue: @""];
     [fWindow setContentView: fOpenView];
 
     [fDriveDetector run];
     [self openEnable: NO];
     [fOpenIndicator setIndeterminate: YES];
     [fOpenIndicator startAnimation: nil];
-    [fOpenProgressField setStringValue: @"Opening..."];
+    [fOpenProgressField setStringValue: NSLocalizedString( @"Opening...", @"Opening...") ];
     [fDriveDetector stop];
 
     if( [fOpenMatrix selectedRow] )
         hb_scan( fHandle, [[fDrives objectForKey: [fOpenPopUp
                  titleOfSelectedItem]] UTF8String], 0 );
     }
+}
+
+- (void) selectFolderSheetShow: (id) sender
+{
+    NSOpenPanel * panel = [NSOpenPanel openPanel];
+
+    [panel setPrompt: NSLocalizedString(@"Select", @"Convert -> Save panel prompt")];
+    [panel setAllowsMultipleSelection: NO];
+    [panel setCanChooseFiles: NO];
+    [panel setCanChooseDirectories: YES];
+    [panel setCanCreateDirectories: YES];
+
+    [panel beginSheetForDirectory: nil file: nil types: nil
+        modalForWindow: fWindow modalDelegate: self didEndSelector:
+        @selector(selectFolderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
+}
+
+- (void) selectFolderSheetClosed: (NSOpenPanel *) sheet returnCode: (int)
+    returnCode contextInfo: (void *) contextInfo
+{
+    if( returnCode != NSOKButton )
+        return;
 
-    NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval: 2.0
-        target: self selector: @selector( openTimer: ) userInfo: nil
-        repeats: YES];
+    if( fConvertFolderString )
+        [fConvertFolderString release];
+    fConvertFolderString = [[[sheet filenames] objectAtIndex: 0] retain];
+    [[fConvertFolderPopUp itemAtIndex: 0] setTitle: [fConvertFolderString lastPathComponent]];
+    [fConvertFolderPopUp selectItemAtIndex:0];
+    
+    NSMenuItem * item = [fConvertFolderPopUp itemAtIndex: 0];
+    [item setImage: [self updatePopUpIcon:fConvertFolderString]];
+    
 }
 
 - (void) convertGo: (id) sender
 {
     int i, j;
+    Preset * currentPreset = [[[fDevice devicesList] objectAtIndex:[fConvertFormatPopUp indexOfSelectedItem]] firstPreset];
 
     for( i = 0; i < hb_list_count( fList ); i++ )
     {
         hb_title_t * title = hb_list_item( fList, i );
         hb_job_t   * job   = title->job;
 
-        int pixels = 307200;
+               int maxwidth = [currentPreset maxWidth];
+        int maxheight = [currentPreset maxHeight];
+        int pixels = maxwidth * maxheight;
                int aspect = title->aspect;
-               if( [fConvertAspectPopUp indexOfSelectedItem] == 1)
+        
+               if( [fConvertAspectPopUp indexOfSelectedItem] == 1 )
                {
             aspect = 4 * HB_ASPECT_BASE / 3;
                }
+        else if ( [fConvertAspectPopUp indexOfSelectedItem] == 2 )
+        {
+            aspect = 16 * HB_ASPECT_BASE / 9;
+        }
 
-               int maxwidth = 640;
-               job->vbitrate = 1000;
-               if( [fConvertMaxWidthPopUp indexOfSelectedItem] == 1)
-               {
-            maxwidth = 320;
-                       job->vbitrate = 500;
-               }
-               job->deinterlace = 1;
+               job->vbitrate = [currentPreset videoBitRate];
                
-               do
+        if( [fConvertMaxWidthPopUp indexOfSelectedItem] == 2 )
                {
-                       hb_set_size( job, aspect, pixels );
-                       pixels -= 10;
-               } while(job->width > maxwidth);
-               
-        if( [fConvertFormatPopUp indexOfSelectedItem] == 0 )
+            maxwidth = 480;
+                       job->vbitrate /= 1.5;
+        }
+        else if ( [fConvertMaxWidthPopUp indexOfSelectedItem] == 3 )
         {
-            /* iPod / H.264 */
-            job->mux      = HB_MUX_IPOD;
-            job->vcodec   = HB_VCODEC_X264;
-                       job->h264_level = 30;
+            maxwidth = 320;
+                       job->vbitrate /= 2;
         }
-        else if( [fConvertFormatPopUp indexOfSelectedItem] == 1 )
+        
+        if ( [fConvertAspectPopUp indexOfSelectedItem] > 0 )
         {
-            /* iPod / MPEG-4 */
-            job->mux      = HB_MUX_MP4;
-            job->vcodec   = HB_VCODEC_FFMPEG;
+            do
+            {
+                hb_set_size( job, aspect, pixels );
+                pixels -= 10;
+            } while(job->width > maxwidth || job->height > maxheight);
         }
         else
         {
-            /* PSP / MPEG-4 */
-            job->mux        = HB_MUX_PSP;
-            job->vrate      = 27000000;
-            job->vrate_base = 900900;   /* 29.97 fps */
-            job->vcodec     = HB_VCODEC_FFMPEG;
-            job->vbitrate   = 600;
-            pixels          = 76800;
-            job->arate      = 24000;
-            job->abitrate   = 96;
-            aspect          = 16 * HB_ASPECT_BASE / 9;
-
-                       if( [fConvertAspectPopUp indexOfSelectedItem] )
-                       {
-                               aspect = -1;
-                       }
-
-                       hb_set_size( job, aspect, pixels );
+            /* Reset job->crop values */
+            memcpy( job->crop, job->title->crop, 4 * sizeof( int ) );
+            job->width = maxwidth;
+            hb_fix_aspect( job, HB_KEEP_WIDTH );
         }
-
+               
+        job->mux        = [currentPreset muxer];
+        job->vcodec     = [currentPreset videoCodec];
+        job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */  
+        strcpy(job->x264opts, [[currentPreset videoCodecOptions] UTF8String]);
+        job->chapter_markers = 1;
         job->vquality = -1.0;
 
         const char * lang;
 
     hb_start( fHandle );
 
-    NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval: 2.0
-        target: self selector: @selector( convertTimer: ) userInfo: nil
-        repeats: YES];
-
     [self convertEnable: NO];
 }
 
     [self openGo: self];
 }
 
+- (BOOL)validateToolbarItem: (NSToolbarItem *) toolbarItem
+{
+    NSString * ident = [toolbarItem itemIdentifier];
+    
+    if ([ident isEqualToString: TOOLBAR_START] && [HBStateWorking isEqualToString:[fCore state]])
+    {
+        [toolbarItem setAction: @selector(convertCancel:)];
+        [toolbarItem setLabel:NSLocalizedString(@"Cancel", @"Cancel")];
+        return YES;
+    }
+    else if ([ident isEqualToString: TOOLBAR_START] && [HBStateWorkDone isEqualToString:[fCore state]])
+    {
+        [toolbarItem setAction: @selector(convertGo:)];
+        [toolbarItem setLabel:NSLocalizedString(@"Convert", @"Convert")];
+        return YES;
+    }
+    else if ([ident isEqualToString: TOOLBAR_OPEN] && [HBStateWorking isEqualToString:[fCore state]])
+    {
+        return NO;
+    }
+    
+    return YES;
+}
+
 - (void) openEnable: (BOOL) b
 {
     [fOpenMatrix       setEnabled: b];
     [fOpenPopUp        setEnabled: b];
     [fOpenFolderField  setEnabled: b];
     [fOpenBrowseButton setEnabled: b];
-    [fOpenGoButton     setEnabled: b];
+    [fOpenGoButton     setEnabled: b]; 
 
     if( b )
     {
     }
 }
 
-- (void) openTimer: (NSTimer *) timer
+- (void) scanningSource: (NSNotification *) n
 {
-    hb_state_t s;
-    hb_get_state( fHandle, &s );
-    switch( s.state )
-    {
-#define p s.param.scanning
-        case HB_STATE_SCANNING:
-            [fOpenIndicator setIndeterminate: NO];
-            [fOpenIndicator setDoubleValue: 100.0 *
-                ( (float) p.title_cur - 0.5 ) / p.title_count];
-            [fOpenProgressField setStringValue: [NSString
-                stringWithFormat: @"Scanning title %d of %d...",
-                p.title_cur, p.title_count]];
-            break;
-#undef p
-
-        case HB_STATE_SCANDONE:
-            [timer invalidate];
-
-            [fOpenIndicator setIndeterminate: NO];
-            [fOpenIndicator setDoubleValue: 0.0];
-            [self openEnable: YES];
-
-            if( hb_list_count( fList ) )
-            {
-                [self convertShow];
-            }
-            else
-            {
-                [fDriveDetector run];
-            }
-            break;
+    [fOpenIndicator setIndeterminate: NO];
+    [fOpenIndicator setDoubleValue: 100.0 *
+            ( (float) p.scanning.title_cur - 0.5 ) / p.scanning.title_count];
+    [fOpenProgressField setStringValue: [NSString
+            stringWithFormat: @"Scanning title %d of %d...",
+            p.scanning.title_cur, p.scanning.title_count]];
+}
 
-        default:
-            break;
+- (void) scanDone: (NSNotification *) n
+{    
+    [fOpenIndicator setIndeterminate: NO];
+    [fOpenIndicator setDoubleValue: 0.0];
+   
+     [self openEnable: YES];
+
+    if( hb_list_count( fList ) )
+    {
+        [self convertShow];
+    }
+    else
+    {
+        [fDriveDetector run];
+        [fOpenProgressField setStringValue: NSLocalizedString(@"No Title Found...",@"No Title Found...")];
     }
 }
 
                 [NSString stringWithUTF8String: audio->lang_simple]];
         }
                [fConvertAudioPopUp selectItemWithTitle: @"English"];
+        
+        if ( [fConvertAudioPopUp selectedItem] == nil )
+            [fConvertAudioPopUp selectItemAtIndex:0];
 
         /* Update subtitle popup */
         hb_subtitle_t * subtitle;
         }
     }
     [fConvertTableView reloadData];
+    
+    NSEnumerator * enumerator;
+    Device * device;
+    enumerator = [[fDevice devicesList] objectEnumerator];
+    
+    while( ( device = [enumerator nextObject] ) )
+        [fConvertFormatPopUp addItemWithTitle:[device name]];
 
     NSRect frame  = [fWindow frame];
-    float  offset = [fConvertView frame].size.height -
-                    [fOpenView frame].size.height;
+    float  offset = [fConvertView frame].size.height -
+                    [fOpenView frame].size.height ) * [fWindow userSpaceScaleFactor];;
     frame.origin.y    -= offset;
     frame.size.height += offset;
     [fWindow setContentView: fEmptyView];
     [fWindow setFrame: frame display: YES animate: YES];
+    [fToolbar setVisible:YES];
     [fWindow setContentView: fConvertView];
 
-    /* Folder popup */
     NSMenuItem * item = [fConvertFolderPopUp itemAtIndex: 0];
     [item setTitle: [fConvertFolderString lastPathComponent]];
-    NSImage * image32 = [[NSWorkspace sharedWorkspace] iconForFile:
-        fConvertFolderString];
-    NSImage * image16 = [[NSImage alloc] initWithSize:
-        NSMakeSize(16,16)];
-    [image16 lockFocus];
-    [[NSGraphicsContext currentContext]
-        setImageInterpolation: NSImageInterpolationHigh];
-    [image32 drawInRect: NSMakeRect(0,0,16,16)
-        fromRect: NSMakeRect(0,0,32,32) operation: NSCompositeCopy
-        fraction: 1.0];
-    [image16 unlockFocus];                                                      
-    [item setImage: image16];
-    [image16 release];
-
+    [item setImage: [self updatePopUpIcon:fConvertFolderString]];
+    
     [self convertEnable: YES];
 }
 
     [fConvertMaxWidthPopUp setEnabled: b];
     [fConvertAudioPopUp setEnabled: b];
     [fConvertSubtitlePopUp setEnabled: b];
-    [fConvertOpenButton setEnabled: b];
-    if( b )
-    {
-        [fConvertGoButton setTitle: @"Convert"];
-        [fConvertGoButton setAction: @selector(convertGo:)];
-    }
-    else
-    {
-        [fConvertGoButton setTitle: @"Cancel"];
-        [fConvertGoButton setAction: @selector(convertCancel:)];
-    }
 }
 
 /***********************************************************************
     [icon release];
 }
 
-- (void) convertTimer: (NSTimer *) timer
+- (id) updatePopUpIcon: (id) value
 {
-    hb_state_t s;
-    hb_get_state( fHandle, &s );
-    switch( s.state )
+    if (!value)
+        return nil;
+    
+    NSImage * icon;
+    
+    icon = [[NSWorkspace sharedWorkspace] iconForFile: value];
+    
+    [icon setScalesWhenResized: YES];
+    [icon setSize: NSMakeSize(16.0 , 16.0)];
+    
+    return icon;
+}
+
+- (void) working: (NSNotification *) n
+{
+   float progress_total = ( p.working.progress + p.working.job_cur - 1 ) / p.working.job_count;
+    NSMutableString * string = [NSMutableString stringWithFormat: @"Converting: %.1f %%", 100.0 * progress_total];
+    
+    if( p.working.seconds > -1 )
     {
-#define p s.param.working
-        case HB_STATE_WORKING:
+        [string appendFormat: @" (%.1f fps, ", p.working.rate_avg];
+        if( p.working.hours > 0 )
         {
-            float progress_total = ( p.progress + p.job_cur - 1 ) / p.job_count;
-            NSMutableString * string = [NSMutableString
-                stringWithFormat: @"Converting: %.1f %%",
-                100.0 * progress_total];
-            if( p.seconds > -1 )
-            {
-                [string appendFormat: @" (%.1f fps, ", p.rate_avg];
-                if( p.hours > 0 )
-                {
-                    [string appendFormat: @"%d hour%s %d min%s",
-                        p.hours, p.hours == 1 ? "" : "s",
-                        p.minutes, p.minutes == 1 ? "" : "s"];
-                }
-                else if( p.minutes > 0 )
-                {
-                    [string appendFormat: @"%d min%s %d sec%s",
-                        p.minutes, p.minutes == 1 ? "" : "s",
-                        p.seconds, p.seconds == 1 ? "" : "s"];
-                }
-                else
-                {
-                    [string appendFormat: @"%d second%s",
-                        p.seconds, p.seconds == 1 ? "" : "s"];
-                }
-                [string appendString: @" left)"];
-            }
-            [fConvertInfoString setStringValue: string];
-            [fConvertIndicator setIndeterminate: NO];
-            [fConvertIndicator setDoubleValue: 100.0 * progress_total];
-            [self UpdateDockIcon: progress_total];
-                       break;
+        [string appendFormat: @"%d hour%s %d min%s",
+            p.working.hours, p.working.hours == 1 ? "" : "s",
+            p.working.minutes, p.working.minutes == 1 ? "" : "s"];
         }
-#undef p
-
-#define p s.param.muxing
-        case HB_STATE_MUXING:
+        else if( p.working.minutes > 0 )
         {
-            NSMutableString * string = [NSMutableString
-                stringWithFormat: @"Muxing..."];
-            [fConvertInfoString setStringValue: string];
-            [fConvertIndicator setIndeterminate: YES];
-            [fConvertIndicator startAnimation: nil];
-            [self UpdateDockIcon: 1.0];
-            break;
+            [string appendFormat: @"%d min%s %d sec%s",
+                p.working.minutes, p.working.minutes == 1 ? "" : "s",
+                p.working.seconds, p.working.seconds == 1 ? "" : "s"];
         }
-#undef p
-
-        case HB_STATE_WORKDONE:
-               {
-                       [timer invalidate];
-            [fConvertIndicator setIndeterminate: NO];
-            [fConvertIndicator setDoubleValue: 0.0];
-            [self UpdateDockIcon: -1.0];
-            [self convertEnable: YES];
-                       
-#define p s.param.workdone
-                       switch(p.error)
-                       {
-                               case HB_ERROR_NONE:
-                                       [fConvertInfoString setStringValue: @"Done."];
-                                       break;
-                               case HB_ERROR_CANCELED:
-                                       [fConvertInfoString setStringValue: @"Canceled."];
-                                       break;
-                               case HB_ERROR_UNKNOWN:
-                                       [fConvertInfoString setStringValue: @"Unknown Error."];
-                                       break;
-                       }
-#undef p
-
-                       hb_job_t * job;
-            while( ( job = hb_job( fHandle, 0 ) ) )
-            {
-                hb_rem( fHandle, job );
-            }
-                       break;
-               }
-        default:
-            break;
+        else
+        {
+            [string appendFormat: @"%d second%s",
+                p.working.seconds, p.working.seconds == 1 ? "" : "s"];
+        }
+            [string appendString: @" left)"];
     }
+    
+    [fConvertInfoString setStringValue: string];
+    [fConvertIndicator setIndeterminate: NO];
+    [fConvertIndicator setDoubleValue: 100.0 * progress_total];
+    [self UpdateDockIcon: progress_total];
+}
+
+- (void) muxing: (NSNotification *) n
+{
+    [fConvertInfoString setStringValue: NSLocalizedString(@"Muxing...",@"Muxing...")];
+    [fConvertIndicator setIndeterminate: YES];
+    [fConvertIndicator startAnimation: nil];
+    [self UpdateDockIcon: 1.0];
+}
+
+- (void) workDone: (NSNotification *) n
+{    
+    [fConvertIndicator setIndeterminate: NO];
+    [fConvertIndicator setDoubleValue: 0.0];
+    [self UpdateDockIcon: -1.0];
+    [self convertEnable: YES];
+        
+    [fConvertInfoString setStringValue: NSLocalizedString(@"Done.",@"Done.")];
+
+    [fCore removeAllJobs];
 }
 
 @end