OSDN Git Service

6775851bdd97503682bb7a81a5dda0fc8a40d0c5
[handbrake-jp/handbrake-jp-git.git] / macosx / InstantHandBrake / ExpressController.m
1 /* This file is part of the HandBrake source code.
2    Homepage: <http://handbrake.fr/>.
3    It may be used under the terms of the GNU General Public License. */
4
5 #import "ExpressController.h"
6
7 #define INSERT_STRING       @"Insert a DVD"
8 #define TOOLBAR_START       @"TOOLBAR_START"
9 #define TOOLBAR_PAUSE       @"TOOLBAR_PAUSE"
10 #define TOOLBAR_OPEN        @"TOOLBAR_OPEN"
11 #define TOOLBAR_ADVANCED    @"TOOLBAR_ADVANCED"
12
13 #define p fState->param
14
15 #import "Device.h"
16
17 @interface ExpressController (Private)
18
19 - (void) openUpdateDrives: (NSDictionary *) drives;
20 - (void) openBrowseDidEnd: (NSOpenPanel *) sheet returnCode: (int)
21     returnCode contextInfo: (void *) contextInfo;
22 - (void) openEnable: (BOOL) b;
23
24 - (id) updatePopUpIcon: (id) value;
25 - (void) convertShow;
26 - (void) convertEnable: (BOOL) b;
27
28 @end
29
30 @implementation ExpressController
31
32 /***********************************************************************
33  * Application delegate methods
34  **********************************************************************/
35 - (void) awakeFromNib
36 {
37     NSEnumerator * enumerator;
38     
39     /* NSToolbar initializations */
40     fToolbar = [[NSToolbar alloc] initWithIdentifier: @"InstantHandBrake Toolbar"];
41     [fToolbar setDelegate: self];
42     [fToolbar setAllowsUserCustomization: NO];
43     [fToolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
44     [fToolbar setVisible:NO];
45     [fWindow setShowsToolbarButton:NO];
46     [fWindow setToolbar: fToolbar];
47         
48     /* Show the "Open DVD" interface */
49     fDriveDetector = [[DriveDetector alloc] initWithCallback: self
50         selector: @selector( openUpdateDrives: )];
51     [fDriveDetector run];
52     [self openEnable: YES];
53     [fWindow setContentSize: [fOpenView frame].size];
54     [fWindow setContentView: fOpenView];
55     [fWindow center];
56     [fWindow makeKeyAndOrderFront: nil];
57
58     /* NSTableView initializations */
59      NSButtonCell * buttonCell;
60      NSTableColumn * tableColumn;
61      enumerator = [[fConvertTableView tableColumns] objectEnumerator];
62      while( ( tableColumn = [enumerator nextObject] ) )
63      {
64          [tableColumn setEditable: NO];
65      }
66      tableColumn = [fConvertTableView tableColumnWithIdentifier: @"Check"];
67      buttonCell = [[[NSButtonCell alloc] initTextCell: @""] autorelease];
68     [buttonCell setEditable: YES];
69     [buttonCell setButtonType: NSSwitchButton];
70     [tableColumn setDataCell: buttonCell];
71
72     /* Preferences */
73     fConvertFolderString = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"];
74     [fConvertFolderString retain];
75 }
76
77 - (void) applicationWillFinishLaunching: (NSNotification *) n
78 {
79     fCore = [[HBCore alloc] init];
80     [fCore openInDebugMode:NO checkForUpdates:NO];
81     fHandle = [fCore hb_handle];
82     fState = [fCore hb_state];
83     fList   = hb_get_titles( fHandle );
84     
85     fDevice = [[DeviceController alloc] init];
86     
87     [[NSNotificationCenter defaultCenter] addObserver:self
88     selector:@selector(scanningSource:)
89     name:@"HBCoreScanningNotification" object:nil];
90     
91     [[NSNotificationCenter defaultCenter] addObserver:self
92     selector:@selector(scanDone:)
93     name:@"HBCoreScanDoneNotification" object:nil];
94     
95     [[NSNotificationCenter defaultCenter] addObserver:self
96     selector:@selector(muxing:)
97     name:@"HBCoreMuxingNotification" object:nil];
98     
99     [[NSNotificationCenter defaultCenter] addObserver:self
100     selector:@selector(working:)
101     name:@"HBCoreWorkingNotification" object:nil];
102     
103     [[NSNotificationCenter defaultCenter] addObserver:self
104     selector:@selector(workDone:)
105     name:@"HBCoreWorkDoneNotification" object:nil];
106 }
107
108 - (void) applicationWillTerminate: (NSNotification *) n
109 {
110     [fCore close];
111 }
112
113 - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag
114 {
115     if( !flag ) {
116         [fWindow  makeKeyAndOrderFront:nil];
117         return YES;
118     }
119     return NO;
120 }
121
122 - (NSToolbarItem *) toolbar: (NSToolbar *) toolbar itemForItemIdentifier: (NSString *) ident
123                     willBeInsertedIntoToolbar: (BOOL) flag
124 {
125     NSToolbarItem * item;
126     item = [[NSToolbarItem alloc] initWithItemIdentifier: ident];
127
128     if ([ident isEqualToString: TOOLBAR_START])
129     {
130         [item setLabel: NSLocalizedString(@"Convert", "Convert")];
131         [item setPaletteLabel: NSLocalizedString(@"Convert/Cancel", @"Convert/Cancel")];
132         [item setImage: [NSImage imageNamed: @"Play"]];
133         [item setTarget: self];
134         [item setAction: @selector(convertGo:)];
135     }
136     else if ([ident isEqualToString: TOOLBAR_PAUSE])
137     {
138         [item setLabel: NSLocalizedString(@"Pause", "Pause")];
139         [item setPaletteLabel: NSLocalizedString(@"Pause/Resume", @"Pause/Resume")];
140         [item setImage: [NSImage imageNamed: @"Pause"]];
141         [item setTarget: self];
142         [item setAction: @selector(pauseGo:)];
143     }
144     else if ([ident isEqualToString: TOOLBAR_OPEN])
145     {
146         [item setLabel: NSLocalizedString(@"Open...", "Open...")];
147         [item setPaletteLabel: NSLocalizedString(@"Open Another Source", "Open Another Source")];
148         [item setImage: [NSImage imageNamed: @"Open"]];
149         [item setTarget: self];
150         [item setAction: @selector(openShow:)];
151     }
152     else
153     {
154         [item release];
155         return nil;
156     }
157
158     return item;
159 }
160
161 - (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
162 {
163     return [NSArray arrayWithObjects: TOOLBAR_START, TOOLBAR_PAUSE,
164                                     NSToolbarFlexibleSpaceItemIdentifier, TOOLBAR_OPEN, nil];
165 }
166
167 - (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
168 {
169     return [NSArray arrayWithObjects: TOOLBAR_START, TOOLBAR_PAUSE,
170                                         TOOLBAR_OPEN, NSToolbarFlexibleSpaceItemIdentifier, nil];
171 }
172
173 /***********************************************************************
174  * Tableview datasource methods
175  **********************************************************************/
176 - (int) numberOfRowsInTableView: (NSTableView *) t
177 {
178     if( !fHandle )
179         return 0;
180
181     return hb_list_count( fList );
182 }
183
184 - (id) tableView:(NSTableView *) t objectValueForTableColumn:
185     (NSTableColumn *) col row: (int) row
186 {
187     if( [[col identifier] isEqualToString: @"Check"] )
188     {
189         return [fConvertCheckArray objectAtIndex: row];
190     }
191     else
192     {
193         hb_title_t * title = hb_list_item( fList, row );
194         if( [[col identifier] isEqualToString: @"Title"] )
195         {
196             return [@"Title " stringByAppendingFormat: @"%d",
197                     title->index];
198         }
199         else if( [[col identifier] isEqualToString: @"Duration"] )
200         {
201             if( title->hours > 0 )
202             {
203                 return [NSString stringWithFormat:
204                     @"%d hour%s %d min%s", title->hours,
205                     title->hours > 1 ? "s" : "", title->minutes,
206                     title->minutes > 1 ? "s": ""];
207             }
208             else if( title->minutes > 0 )
209             {
210                 return [NSString stringWithFormat:
211                     @"%d min%s %d sec%s", title->minutes,
212                     title->minutes > 1 ? "s" : "", title->seconds,
213                     title->seconds > 1 ? "s": ""];
214             }
215             else
216             {
217                 return [NSString stringWithFormat: @"%d seconds",
218                         title->seconds];
219             }
220         }
221     }
222     return nil;
223 }
224
225 - (void) tableView: (NSTableView *) t setObjectValue: (id) object
226     forTableColumn: (NSTableColumn *) col row: (int) row
227 {
228     if( [[col identifier] isEqualToString: @"Check"] )
229     {
230         [fConvertCheckArray replaceObjectAtIndex: row withObject: object];
231     }
232 }
233
234 /***********************************************************************
235  * User events methods
236  **********************************************************************/
237 - (void) openShow: (id) sender
238 {
239     NSRect frame  = [fWindow frame];
240     float  offset = ( [fConvertView frame].size.height -
241                     [fOpenView frame].size.height ) * [fWindow userSpaceScaleFactor];
242
243     frame.origin.y    += offset;
244     frame.size.height -= offset;
245     [fWindow setContentView: fEmptyView];
246     [fWindow setFrame: frame display: YES animate: YES];
247     [fToolbar setVisible:NO];
248     [fOpenProgressField setStringValue: @""];
249     [fWindow setContentView: fOpenView];
250
251     [fDriveDetector run];
252 }
253
254 - (void) openMatrixChanged: (id) sender
255 {
256     [self openEnable: YES];
257     if( [fOpenMatrix selectedRow] )
258     {
259         [self openBrowse: self];
260     }
261 }
262
263 - (void) openBrowse: (id) sender
264 {
265     NSOpenPanel * panel = [NSOpenPanel openPanel];
266     [panel setAllowsMultipleSelection: NO];
267     [panel setCanChooseFiles: YES];
268     [panel setCanChooseDirectories: YES ];
269     [panel beginSheetForDirectory: nil file: nil types: nil
270         modalForWindow: fWindow modalDelegate: self
271         didEndSelector: @selector( openBrowseDidEnd:returnCode:contextInfo: )
272         contextInfo: nil];                                                      
273 }
274
275 - (void) openGo: (id) sender
276 {
277     [self openEnable: NO];
278     [fOpenIndicator setIndeterminate: YES];
279     [fOpenIndicator startAnimation: nil];
280     [fOpenProgressField setStringValue: NSLocalizedString( @"Opening...", @"Opening...") ];
281     [fDriveDetector stop];
282
283     if( [fOpenMatrix selectedRow] )
284     {
285         hb_scan( fHandle, [fOpenFolderString UTF8String], 0 );
286     }
287     else
288     {
289         hb_scan( fHandle, [[fDrives objectForKey: [fOpenPopUp
290                  titleOfSelectedItem]] UTF8String], 0 );
291     }
292 }
293
294 - (void) selectFolderSheetShow: (id) sender
295 {
296     NSOpenPanel * panel = [NSOpenPanel openPanel];
297
298     [panel setPrompt: NSLocalizedString(@"Select", @"Convert -> Save panel prompt")];
299     [panel setAllowsMultipleSelection: NO];
300     [panel setCanChooseFiles: NO];
301     [panel setCanChooseDirectories: YES];
302     [panel setCanCreateDirectories: YES];
303
304     [panel beginSheetForDirectory: nil file: nil types: nil
305         modalForWindow: fWindow modalDelegate: self didEndSelector:
306         @selector(selectFolderSheetClosed:returnCode:contextInfo:) contextInfo: nil];
307 }
308
309 - (void) selectFolderSheetClosed: (NSOpenPanel *) sheet returnCode: (int)
310     returnCode contextInfo: (void *) contextInfo
311 {
312     if( returnCode != NSOKButton )
313         return;
314
315     if( fConvertFolderString )
316         [fConvertFolderString release];
317     fConvertFolderString = [[[sheet filenames] objectAtIndex: 0] retain];
318     [[fConvertFolderPopUp itemAtIndex: 0] setTitle: [fConvertFolderString lastPathComponent]];
319     [fConvertFolderPopUp selectItemAtIndex:0];
320     
321     NSMenuItem * item = [fConvertFolderPopUp itemAtIndex: 0];
322     [item setImage: [self updatePopUpIcon:fConvertFolderString]];
323     
324 }
325
326 - (void) convertGo: (id) sender
327 {
328     int i, j;
329     Preset * currentPreset = [[[fDevice devicesList] objectAtIndex:[fConvertFormatPopUp indexOfSelectedItem]] firstPreset];
330
331     for( i = 0; i < hb_list_count( fList ); i++ )
332     {
333         if( ![[fConvertCheckArray objectAtIndex: i] boolValue] )
334             continue;
335
336         hb_title_t * title = hb_list_item( fList, i );
337         hb_job_t   * job   = title->job;
338
339                 int maxwidth = [currentPreset maxWidth];
340         int maxheight = [currentPreset maxHeight];
341         int pixels = maxwidth * maxheight;
342                 int aspect = title->aspect;
343         
344                 if( [fConvertAspectPopUp indexOfSelectedItem] == 1 )
345                 {
346             aspect = 4 * HB_ASPECT_BASE / 3;
347                 }
348         else if ( [fConvertAspectPopUp indexOfSelectedItem] == 2 )
349         {
350             aspect = 16 * HB_ASPECT_BASE / 9;
351         }
352
353                 job->vbitrate = [currentPreset videoBitRate];
354                 
355         if( [fConvertMaxWidthPopUp indexOfSelectedItem] == 2 )
356                 {
357             maxwidth = 480;
358                         job->vbitrate /= 1.5;
359         }
360         else if ( [fConvertMaxWidthPopUp indexOfSelectedItem] == 3 )
361         {
362             maxwidth = 320;
363                         job->vbitrate /= 2;
364         }
365         
366         if ( [fConvertAspectPopUp indexOfSelectedItem] )
367         {
368             do
369             {
370                 hb_set_size( job, aspect, pixels );
371                 pixels -= 10;
372             } while(job->width > maxwidth || job->height > maxheight);
373         }
374         else
375         {
376             job->width = maxwidth;
377             hb_fix_aspect( job, HB_KEEP_WIDTH );
378         }
379                 
380         job->mux        = [currentPreset muxer];
381         job->vcodec     = [currentPreset videoCodec];
382         job->x264opts = (char *)calloc(1024, 1); /* Fixme, this just leaks */  
383         strcpy(job->x264opts, [[currentPreset videoCodecOptions] UTF8String]);
384         job->chapter_markers = 1;
385         job->vquality = -1.0;
386
387         const char * lang;
388
389         /* Audio selection */
390         hb_audio_t * audio;
391         lang = [[fConvertAudioPopUp titleOfSelectedItem] UTF8String];
392         job->audios[0] = -1;
393         for( j = 0; j < hb_list_count( title->list_audio ); j++ )
394         {
395             /* Choose the first track that matches the language */
396             audio = hb_list_item( title->list_audio, j );
397             if( !strcmp( lang, audio->lang_simple ) )
398             {
399                 job->audios[0] = j;
400                 break;
401             }
402         }
403         if( job->audios[0] == -1 )
404         {
405             /* If the language isn't available in this title, choose
406                the first track */
407             job->audios[0] = 0;
408         }
409         job->audios[1] = -1;
410
411         job->audio_mixdowns[0] = HB_AMIXDOWN_DOLBYPLII;
412         
413         /* Subtitle selection */
414         hb_subtitle_t * subtitle;
415         lang = [[fConvertSubtitlePopUp titleOfSelectedItem] UTF8String];
416         job->subtitle = -1;
417         for( j = 0; j < hb_list_count( title->list_subtitle ); j++ )
418         {
419             /* Choose the first track that matches the language */
420             subtitle = hb_list_item( title->list_subtitle, j );
421             if( !strcmp( lang, subtitle->lang ) )
422             {
423                 job->subtitle = j;
424                 break;
425             }
426         }
427         
428         job->file = strdup( [[NSString stringWithFormat:                 
429                 @"%@/%s - Title %d.m4v", fConvertFolderString,      
430                 title->name, title->index] UTF8String] );
431         hb_add( fHandle, job );
432     }
433
434     hb_start( fHandle );
435
436     [self convertEnable: NO];
437 }
438
439 - (void) convertCancel: (id) sender
440 {
441     hb_stop( fHandle );
442     [self convertEnable: YES];
443 }
444
445 @end
446
447 /***********************************************************************
448  * Private methods
449  **********************************************************************/
450
451 @implementation ExpressController (Private)
452
453 - (void) openUpdateDrives: (NSDictionary *) drives
454 {
455     if( fDrives )
456     {
457         [fDrives release];
458     }
459     fDrives = [[NSDictionary alloc] initWithDictionary: drives];
460
461     NSString * device;
462     NSEnumerator * enumerator = [fDrives keyEnumerator];
463     [fOpenPopUp removeAllItems];
464     while( ( device = [enumerator nextObject] ) )
465     {
466         [fOpenPopUp addItemWithTitle: device];
467     }
468
469     if( ![fOpenPopUp numberOfItems] )
470     {
471         [fOpenPopUp addItemWithTitle: INSERT_STRING];
472     }
473     [fOpenPopUp selectItemAtIndex: 0];
474     if( [fOpenMatrix isEnabled] )
475     {
476         [self openEnable: YES];
477     }
478 }
479
480 - (void) openBrowseDidEnd: (NSOpenPanel *) sheet returnCode: (int)
481     returnCode contextInfo: (void *) contextInfo
482 {
483     if( returnCode != NSOKButton )
484         return;
485
486     if( fOpenFolderString )
487         [fOpenFolderString release];
488     fOpenFolderString = [[[sheet filenames] objectAtIndex: 0] retain];
489     [fOpenFolderField setStringValue: [fOpenFolderString lastPathComponent]];
490     [self openGo: self];
491 }
492
493 - (BOOL)validateToolbarItem: (NSToolbarItem *) toolbarItem
494 {
495     NSString * ident = [toolbarItem itemIdentifier];
496     
497     if ([ident isEqualToString: TOOLBAR_START] && [HBStateWorking isEqualToString:[fCore state]])
498     {
499         [toolbarItem setAction: @selector(convertCancel:)];
500         [toolbarItem setLabel:NSLocalizedString(@"Cancel", @"Cancel")];
501         return YES;
502     }
503     else if ([ident isEqualToString: TOOLBAR_START] && [HBStateWorkDone isEqualToString:[fCore state]])
504     {
505         [toolbarItem setAction: @selector(convertGo:)];
506         [toolbarItem setLabel:NSLocalizedString(@"Convert", @"Convert")];
507         return YES;
508     }
509     else if ([ident isEqualToString: TOOLBAR_OPEN] && [HBStateWorking isEqualToString:[fCore state]])
510     {
511         return NO;
512     }
513     
514     return YES;
515 }
516
517 - (void) openEnable: (BOOL) b
518 {
519     [fOpenMatrix       setEnabled: b];
520     [fOpenPopUp        setEnabled: b];
521     [fOpenFolderField  setEnabled: b];
522     [fOpenBrowseButton setEnabled: b];
523     [fOpenGoButton     setEnabled: b]; 
524
525     if( b )
526     {
527         if( [fOpenMatrix selectedRow] )
528         {
529             [fOpenPopUp setEnabled: NO];
530         }
531         else
532         {
533             [fOpenFolderField  setEnabled: NO];
534             [fOpenBrowseButton setEnabled: NO];
535             if( [[fOpenPopUp titleOfSelectedItem]
536                     isEqualToString: INSERT_STRING] )
537             {
538                 [fOpenGoButton setEnabled: NO];
539             }
540         }
541     }
542 }
543
544 - (void) scanningSource: (NSNotification *) n
545 {
546     [fOpenIndicator setIndeterminate: NO];
547     [fOpenIndicator setDoubleValue: 100.0 *
548             ( (float) p.scanning.title_cur - 0.5 ) / p.scanning.title_count];
549     [fOpenProgressField setStringValue: [NSString
550             stringWithFormat: @"Scanning title %d of %d...",
551             p.scanning.title_cur, p.scanning.title_count]];
552 }
553
554 - (void) scanDone: (NSNotification *) n
555 {    
556     [fOpenIndicator setIndeterminate: NO];
557     [fOpenIndicator setDoubleValue: 0.0];
558    
559      [self openEnable: YES];
560
561     if( hb_list_count( fList ) )
562     {
563         [self convertShow];
564     }
565     else
566     {
567         [fDriveDetector run];
568         [fOpenProgressField setStringValue: NSLocalizedString(@"No Title Found...",@"No Title Found...")];
569     }
570 }
571
572 - (void) convertShow
573 {
574     int i, j;
575
576     fConvertCheckArray = [[NSMutableArray alloc] initWithCapacity:
577         hb_list_count( fList )];
578     [fConvertAudioPopUp removeAllItems];
579     [fConvertSubtitlePopUp removeAllItems];
580     [fConvertSubtitlePopUp addItemWithTitle: @"None"];
581     for( i = 0; i < hb_list_count( fList ); i++ )
582     {
583         /* Default is to convert titles longer than 30 minutes. */
584         hb_title_t * title = hb_list_item( fList, i );
585         [fConvertCheckArray addObject: [NSNumber numberWithBool:
586             ( 60 * title->hours + title->minutes > 30 )]];
587
588         /* Update audio popup */
589         hb_audio_t * audio;
590         for( j = 0; j < hb_list_count( title->list_audio ); j++ )
591         {
592             audio = hb_list_item( title->list_audio, j );
593             [fConvertAudioPopUp addItemWithTitle:
594                 [NSString stringWithUTF8String: audio->lang_simple]];
595         }
596                 [fConvertAudioPopUp selectItemWithTitle: @"English"];
597         
598         if ( [fConvertAudioPopUp selectedItem] == nil )
599             [fConvertAudioPopUp selectItemAtIndex:0];
600
601         /* Update subtitle popup */
602         hb_subtitle_t * subtitle;
603         for( j = 0; j < hb_list_count( title->list_subtitle ); j++ )
604         {
605             subtitle = hb_list_item( title->list_subtitle, j );
606             [fConvertSubtitlePopUp addItemWithTitle:
607                 [NSString stringWithUTF8String: subtitle->lang]];
608         }
609     }
610     [fConvertTableView reloadData];
611     
612     NSEnumerator * enumerator;
613     Device * device;
614     enumerator = [[fDevice devicesList] objectEnumerator];
615     
616     while( ( device = [enumerator nextObject] ) )
617         [fConvertFormatPopUp addItemWithTitle:[device name]];
618
619     NSRect frame  = [fWindow frame];
620     float  offset = ( [fConvertView frame].size.height -
621                     [fOpenView frame].size.height ) * [fWindow userSpaceScaleFactor];;
622     frame.origin.y    -= offset;
623     frame.size.height += offset;
624     [fWindow setContentView: fEmptyView];
625     [fWindow setFrame: frame display: YES animate: YES];
626     [fToolbar setVisible:YES];
627     [fWindow setContentView: fConvertView];
628
629     NSMenuItem * item = [fConvertFolderPopUp itemAtIndex: 0];
630     [item setTitle: [fConvertFolderString lastPathComponent]];
631     [item setImage: [self updatePopUpIcon:fConvertFolderString]];
632     
633     [self convertEnable: YES];
634 }
635
636 - (void) convertEnable: (BOOL) b
637 {
638     [fConvertTableView setEnabled: b];
639     [fConvertFolderPopUp setEnabled: b];
640     [fConvertFormatPopUp setEnabled: b];
641     [fConvertAspectPopUp setEnabled: b];
642     [fConvertMaxWidthPopUp setEnabled: b];
643     [fConvertAudioPopUp setEnabled: b];
644     [fConvertSubtitlePopUp setEnabled: b];
645 }
646
647 /***********************************************************************
648 * UpdateDockIcon
649 ***********************************************************************
650 * Shows a progression bar on the dock icon, filled according to
651 * 'progress' (0.0 <= progress <= 1.0).
652 * Called with progress < 0.0 or progress > 1.0, restores the original
653 * icon.
654 **********************************************************************/
655 - (void) UpdateDockIcon: (float) progress
656 {
657     NSImage * icon;
658     NSData * tiff;
659     NSBitmapImageRep * bmp;
660     uint32_t * pen;
661     uint32_t black = htonl( 0x000000FF );
662     uint32_t red   = htonl( 0xFF0000FF );
663     uint32_t white = htonl( 0xFFFFFFFF );
664     int row_start, row_end;
665     int i, j;
666         
667     /* Get application original icon */
668     icon = [NSImage imageNamed: @"NSApplicationIcon"];
669         
670     if( progress < 0.0 || progress > 1.0 )
671     {
672         [NSApp setApplicationIconImage: icon];
673         return;
674     }
675         
676     /* Get it in a raw bitmap form */
677     tiff = [icon TIFFRepresentationUsingCompression:
678                                            NSTIFFCompressionNone factor: 1.0];
679     bmp = [NSBitmapImageRep imageRepWithData: tiff];
680     
681     /* Draw the progression bar */
682     /* It's pretty simple (ugly?) now, but I'm no designer */
683         
684     row_start = 3 * (int) [bmp size].height / 4;
685     row_end   = 7 * (int) [bmp size].height / 8;
686         
687     for( i = row_start; i < row_start + 2; i++ )
688     {
689         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
690         for( j = 0; j < (int) [bmp size].width; j++ )
691         {
692             pen[j] = black;
693         }
694     }
695     for( i = row_start + 2; i < row_end - 2; i++ )
696     {
697         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
698         pen[0] = black;
699         pen[1] = black;
700         for( j = 2; j < (int) [bmp size].width - 2; j++ )
701         {
702             if( j < 2 + (int) ( ( [bmp size].width - 4.0 ) * progress ) )
703             {
704                 pen[j] = red;
705             }
706             else
707             {
708                 pen[j] = white;
709             }
710         }
711         pen[j]   = black;
712         pen[j+1] = black;
713     }
714     for( i = row_end - 2; i < row_end; i++ )
715     {
716         pen = (uint32_t *) ( [bmp bitmapData] + i * [bmp bytesPerRow] );
717         for( j = 0; j < (int) [bmp size].width; j++ )
718         {
719             pen[j] = black;
720         }
721     }
722         
723     /* Now update the dock icon */
724     tiff = [bmp TIFFRepresentationUsingCompression:
725                                           NSTIFFCompressionNone factor: 1.0];
726     icon = [[NSImage alloc] initWithData: tiff];
727     [NSApp setApplicationIconImage: icon];
728     [icon release];
729 }
730
731 - (id) updatePopUpIcon: (id) value
732 {
733     if (!value)
734         return nil;
735     
736     NSImage * icon;
737     
738     icon = [[NSWorkspace sharedWorkspace] iconForFile: value];
739     
740     [icon setScalesWhenResized: YES];
741     [icon setSize: NSMakeSize(16.0 , 16.0)];
742     
743     return icon;
744 }
745
746 - (void) working: (NSNotification *) n
747 {
748    float progress_total = ( p.working.progress + p.working.job_cur - 1 ) / p.working.job_count;
749     NSMutableString * string = [NSMutableString stringWithFormat: @"Converting: %.1f %%", 100.0 * progress_total];
750     
751     if( p.working.seconds > -1 )
752     {
753         [string appendFormat: @" (%.1f fps, ", p.working.rate_avg];
754         if( p.working.hours > 0 )
755         {
756         [string appendFormat: @"%d hour%s %d min%s",
757             p.working.hours, p.working.hours == 1 ? "" : "s",
758             p.working.minutes, p.working.minutes == 1 ? "" : "s"];
759         }
760         else if( p.working.minutes > 0 )
761         {
762             [string appendFormat: @"%d min%s %d sec%s",
763                 p.working.minutes, p.working.minutes == 1 ? "" : "s",
764                 p.working.seconds, p.working.seconds == 1 ? "" : "s"];
765         }
766         else
767         {
768             [string appendFormat: @"%d second%s",
769                 p.working.seconds, p.working.seconds == 1 ? "" : "s"];
770         }
771             [string appendString: @" left)"];
772     }
773     
774     [fConvertInfoString setStringValue: string];
775     [fConvertIndicator setIndeterminate: NO];
776     [fConvertIndicator setDoubleValue: 100.0 * progress_total];
777     [self UpdateDockIcon: progress_total];
778 }
779
780 - (void) muxing: (NSNotification *) n
781 {
782     [fConvertInfoString setStringValue: NSLocalizedString(@"Muxing...",@"Muxing...")];
783     [fConvertIndicator setIndeterminate: YES];
784     [fConvertIndicator startAnimation: nil];
785     [self UpdateDockIcon: 1.0];
786 }
787
788 - (void) workDone: (NSNotification *) n
789 {    
790     [fConvertIndicator setIndeterminate: NO];
791     [fConvertIndicator setDoubleValue: 0.0];
792     [self UpdateDockIcon: -1.0];
793     [self convertEnable: YES];
794         
795     [fConvertInfoString setStringValue: NSLocalizedString(@"Done.",@"Done.")];
796
797     [fCore removeAllJobs];
798 }
799
800 @end