OSDN Git Service

f1bd2617f40ce9b55bf6a89aa2893172bbb0a18c
[handbrake-jp/handbrake-jp.git] / macosx / HBQueueController.mm
1 /* HBQueueController
2
3     This file is part of the HandBrake source code.
4     Homepage: <http://handbrake.fr/>.
5     It may be used under the terms of the GNU General Public License. */
6
7 #import "HBQueueController.h"
8 #import "Controller.h"
9 #import "HBImageAndTextCell.h"
10
11 #define HB_ROW_HEIGHT_TITLE_ONLY           17.0
12 #define HB_ROW_HEIGHT_FULL_DESCRIPTION           200.0
13 // Pasteboard type for or drag operations
14 #define DragDropSimplePboardType        @"MyCustomOutlineViewPboardType"
15
16 //------------------------------------------------------------------------------------
17 #pragma mark -
18 //------------------------------------------------------------------------------------
19
20 //------------------------------------------------------------------------------------
21 // NSMutableAttributedString (HBAdditions)
22 //------------------------------------------------------------------------------------
23
24 @interface NSMutableAttributedString (HBAdditions)
25 - (void) appendString: (NSString*)aString withAttributes: (NSDictionary *)aDictionary;
26 @end
27
28 @implementation NSMutableAttributedString (HBAdditions)
29 - (void) appendString: (NSString*)aString withAttributes: (NSDictionary *)aDictionary
30 {
31     NSAttributedString * s = [[[NSAttributedString alloc]
32         initWithString: aString
33         attributes: aDictionary] autorelease];
34     [self appendAttributedString: s];
35 }
36 @end
37
38
39 @implementation HBQueueOutlineView
40
41 - (void)viewDidEndLiveResize
42 {
43     // Since we disabled calculating row heights during a live resize, force them to
44     // recalculate now.
45     [self noteHeightOfRowsWithIndexesChanged:
46             [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [self numberOfRows])]];
47     [super viewDidEndLiveResize];
48 }
49
50
51
52 /* This should be for dragging, we take this info from the presets right now */
53 - (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows tableColumns:(NSArray *)tableColumns event:(NSEvent*)dragEvent offset:(NSPointPointer)dragImageOffset
54 {
55     fIsDragging = YES;
56
57     // By default, NSTableView only drags an image of the first column. Change this to
58     // drag an image of the queue's icon and desc and action columns.
59     NSArray * cols = [NSArray arrayWithObjects: [self tableColumnWithIdentifier:@"desc"], [self tableColumnWithIdentifier:@"icon"],[self tableColumnWithIdentifier:@"action"], nil];
60     return [super dragImageForRowsWithIndexes:dragRows tableColumns:cols event:dragEvent offset:dragImageOffset];
61 }
62
63
64
65 - (void) mouseDown:(NSEvent *)theEvent
66 {
67     [super mouseDown:theEvent];
68         fIsDragging = NO;
69 }
70
71
72
73 - (BOOL) isDragging;
74 {
75     return fIsDragging;
76 }
77
78
79
80 @end
81
82 #pragma mark Toolbar Identifiers
83 // Toolbar identifiers
84 static NSString*    HBQueueToolbar                            = @"HBQueueToolbar1";
85 static NSString*    HBQueueStartCancelToolbarIdentifier       = @"HBQueueStartCancelToolbarIdentifier";
86 static NSString*    HBQueuePauseResumeToolbarIdentifier       = @"HBQueuePauseResumeToolbarIdentifier";
87
88 #pragma mark -
89
90 @implementation HBQueueController
91
92 //------------------------------------------------------------------------------------
93 // init
94 //------------------------------------------------------------------------------------
95 - (id)init
96 {
97     if (self = [super initWithWindowNibName:@"Queue"])
98     {
99         // NSWindowController likes to lazily load its window nib. Since this
100         // controller tries to touch the outlets before accessing the window, we
101         // need to force it to load immadiately by invoking its accessor.
102         //
103         // If/when we switch to using bindings, this can probably go away.
104         [self window];
105
106         // Our defaults
107         [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
108             @"NO",      @"QueueWindowIsOpen",
109             @"NO",      @"QueueShowsDetail",
110             @"YES",     @"QueueShowsJobsAsGroups",
111             nil]];
112
113         fJobGroups = [[NSMutableArray arrayWithCapacity:0] retain];
114        } 
115         return self;
116 }
117
118 - (void)setQueueArray: (NSMutableArray *)QueueFileArray
119 {
120     [fJobGroups setArray:QueueFileArray];
121     fIsDragging = NO; 
122     /* First stop any timer working now */
123     [self stopAnimatingCurrentJobGroupInQueue];
124     [fOutlineView reloadData];
125     
126     
127     
128     /* lets get the stats on the status of the queue array */
129     
130     fEncodingQueueItem = 0;
131     fPendingCount = 0;
132     fCompletedCount = 0;
133     fCanceledCount = 0;
134     fWorkingCount = 0;
135     
136     /* We use a number system to set the encode status of the queue item
137      * in controller.mm
138      * 0 == already encoded
139      * 1 == is being encoded
140      * 2 == is yet to be encoded
141      * 3 == cancelled
142      */
143     
144         int i = 0;
145     NSEnumerator *enumerator = [fJobGroups objectEnumerator];
146         id tempObject;
147         while (tempObject = [enumerator nextObject])
148         {
149                 NSDictionary *thisQueueDict = tempObject;
150                 if ([[thisQueueDict objectForKey:@"Status"] intValue] == 0) // Completed
151                 {
152                         fCompletedCount++;      
153                 }
154                 if ([[thisQueueDict objectForKey:@"Status"] intValue] == 1) // being encoded
155                 {
156                         fWorkingCount++;
157             fEncodingQueueItem = i;     
158                 }
159         if ([[thisQueueDict objectForKey:@"Status"] intValue] == 2) // pending          
160         {
161                         fPendingCount++;
162                 }
163         if ([[thisQueueDict objectForKey:@"Status"] intValue] == 3) // cancelled                
164         {
165                         fCanceledCount++;
166                 }
167                 i++;
168         }
169     
170     /* We should fire up the encoding timer here based on fWorkingCount */
171     
172     if (fWorkingCount > 0)
173     {
174         /* we have an encoding job so, lets start the animation timer */
175         [self startAnimatingCurrentWorkingEncodeInQueue];
176     }
177     
178     /* Set the queue status field in the queue window */
179     NSMutableString * string;
180     if (fPendingCount == 1)
181     {
182         string = [NSMutableString stringWithFormat: NSLocalizedStringFromTable( @"%d encode pending", @"Queue", @"" ), fPendingCount];
183     }
184     else
185     {
186         string = [NSMutableString stringWithFormat: NSLocalizedStringFromTable( @"%d encode(s) pending", @"Queue", @"" ), fPendingCount];
187     }
188     [fQueueCountField setStringValue:string];
189     
190 }
191 /* This method sets the status string in the queue window
192  * and is called from Controller.mm (fHBController)
193  * instead of running another timer here polling libhb
194  * for encoding status
195  */
196 - (void)setQueueStatusString: (NSString *)statusString
197 {
198 [fProgressTextField setStringValue:statusString];
199 }
200
201 //------------------------------------------------------------------------------------
202 // dealloc
203 //------------------------------------------------------------------------------------
204 - (void)dealloc
205 {
206     // clear the delegate so that windowWillClose is not attempted
207     if( [[self window] delegate] == self )
208         [[self window] setDelegate:nil];
209
210     [fJobGroups release];
211
212     [fSavedExpandedItems release];
213     [fSavedSelectedItems release];
214
215     [[NSNotificationCenter defaultCenter] removeObserver:self];
216
217     [super dealloc];
218 }
219
220 //------------------------------------------------------------------------------------
221 // Receive HB handle
222 //------------------------------------------------------------------------------------
223 - (void)setHandle: (hb_handle_t *)handle
224 {
225     fQueueEncodeLibhb = handle;
226 }
227
228 //------------------------------------------------------------------------------------
229 // Receive HBController
230 //------------------------------------------------------------------------------------
231 - (void)setHBController: (HBController *)controller
232 {
233     fHBController = controller;
234 }
235
236 #pragma mark -
237
238 //------------------------------------------------------------------------------------
239 // Displays and brings the queue window to the front
240 //------------------------------------------------------------------------------------
241 - (IBAction) showQueueWindow: (id)sender
242 {
243     [self showWindow:sender];
244     [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"QueueWindowIsOpen"];
245 }
246
247
248
249 //------------------------------------------------------------------------------------
250 // awakeFromNib
251 //------------------------------------------------------------------------------------
252 - (void)awakeFromNib
253 {
254     [self setupToolbar];
255
256     if( ![[self window] setFrameUsingName:@"Queue"] )
257         [[self window] center];
258     [self setWindowFrameAutosaveName:@"Queue"];
259     [[self window] setExcludedFromWindowsMenu:YES];
260
261     /* lets setup our queue list outline view for drag and drop here */
262     [fOutlineView registerForDraggedTypes: [NSArray arrayWithObject:DragDropSimplePboardType] ];
263     [fOutlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES];
264     [fOutlineView setVerticalMotionCanBeginDrag: YES];
265
266
267     // Don't allow autoresizing of main column, else the "delete" column will get
268     // pushed out of view.
269     [fOutlineView setAutoresizesOutlineColumn: NO];
270
271 #if HB_OUTLINE_METRIC_CONTROLS
272     [fIndentation setHidden: NO];
273     [fSpacing setHidden: NO];
274     [fIndentation setIntegerValue:[fOutlineView indentationPerLevel]];  // debug
275     [fSpacing setIntegerValue:3];       // debug
276 #endif
277
278     // Show/hide UI elements
279     fCurrentJobPaneShown = NO;     // it's shown in the nib
280     //[self showCurrentJobPane:NO];
281
282     //[self updateQueueCountField];
283 }
284
285
286 //------------------------------------------------------------------------------------
287 // windowWillClose
288 //------------------------------------------------------------------------------------
289 - (void)windowWillClose:(NSNotification *)aNotification
290 {
291     [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"QueueWindowIsOpen"];
292 }
293
294 #pragma mark Toolbar
295
296 //------------------------------------------------------------------------------------
297 // setupToolbar
298 //------------------------------------------------------------------------------------
299 - (void)setupToolbar
300 {
301     // Create a new toolbar instance, and attach it to our window
302     NSToolbar *toolbar = [[[NSToolbar alloc] initWithIdentifier: HBQueueToolbar] autorelease];
303
304     // Set up toolbar properties: Allow customization, give a default display mode, and remember state in user defaults
305     [toolbar setAllowsUserCustomization: YES];
306     [toolbar setAutosavesConfiguration: YES];
307     [toolbar setDisplayMode: NSToolbarDisplayModeIconAndLabel];
308
309     // We are the delegate
310     [toolbar setDelegate: self];
311
312     // Attach the toolbar to our window
313     [[self window] setToolbar:toolbar];
314 }
315
316 //------------------------------------------------------------------------------------
317 // toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:
318 //------------------------------------------------------------------------------------
319 - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar
320         itemForItemIdentifier:(NSString *)itemIdentifier
321         willBeInsertedIntoToolbar:(BOOL)flag
322 {
323     // Required delegate method: Given an item identifier, this method returns an item.
324     // The toolbar will use this method to obtain toolbar items that can be displayed
325     // in the customization sheet, or in the toolbar itself.
326
327     NSToolbarItem *toolbarItem = nil;
328
329     if ([itemIdentifier isEqual: HBQueueStartCancelToolbarIdentifier])
330     {
331         toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
332
333         // Set the text label to be displayed in the toolbar and customization palette
334         [toolbarItem setLabel: NSLocalizedStringFromTable(@"Start", @"Queue",@"")];
335         [toolbarItem setPaletteLabel: NSLocalizedStringFromTable(@"Start/Cancel", @"Queue",@"")];
336
337         // Set up a reasonable tooltip, and image
338         [toolbarItem setToolTip: NSLocalizedStringFromTable(@"Start Encoding", @"Queue",@"")];
339         [toolbarItem setImage: [NSImage imageNamed: @"Play"]];
340
341         // Tell the item what message to send when it is clicked
342         [toolbarItem setTarget: self];
343         [toolbarItem setAction: @selector(toggleStartCancel:)];
344     }
345
346     if ([itemIdentifier isEqual: HBQueuePauseResumeToolbarIdentifier])
347     {
348         toolbarItem = [[[NSToolbarItem alloc] initWithItemIdentifier: itemIdentifier] autorelease];
349
350         // Set the text label to be displayed in the toolbar and customization palette
351         [toolbarItem setLabel: NSLocalizedStringFromTable(@"Pause", @"Queue",@"")];
352         [toolbarItem setPaletteLabel: NSLocalizedStringFromTable(@"Pause/Resume", @"Queue",@"")];
353
354         // Set up a reasonable tooltip, and image
355         [toolbarItem setToolTip: NSLocalizedStringFromTable(@"Pause Encoding", @"Queue",@"")];
356         [toolbarItem setImage: [NSImage imageNamed: @"Pause"]];
357
358         // Tell the item what message to send when it is clicked
359         [toolbarItem setTarget: self];
360         [toolbarItem setAction: @selector(togglePauseResume:)];
361     }
362
363     return toolbarItem;
364 }
365
366 //------------------------------------------------------------------------------------
367 // toolbarDefaultItemIdentifiers:
368 //------------------------------------------------------------------------------------
369 - (NSArray *) toolbarDefaultItemIdentifiers: (NSToolbar *) toolbar
370 {
371     // Required delegate method: Returns the ordered list of items to be shown in the
372     // toolbar by default.
373
374     return [NSArray arrayWithObjects:
375         HBQueueStartCancelToolbarIdentifier,
376         HBQueuePauseResumeToolbarIdentifier,
377         nil];
378 }
379
380 //------------------------------------------------------------------------------------
381 // toolbarAllowedItemIdentifiers:
382 //------------------------------------------------------------------------------------
383 - (NSArray *) toolbarAllowedItemIdentifiers: (NSToolbar *) toolbar
384 {
385     // Required delegate method: Returns the list of all allowed items by identifier.
386     // By default, the toolbar does not assume any items are allowed, even the
387     // separator. So, every allowed item must be explicitly listed.
388
389     return [NSArray arrayWithObjects:
390         HBQueueStartCancelToolbarIdentifier,
391         HBQueuePauseResumeToolbarIdentifier,
392         NSToolbarCustomizeToolbarItemIdentifier,
393         NSToolbarFlexibleSpaceItemIdentifier,
394         NSToolbarSpaceItemIdentifier,
395         NSToolbarSeparatorItemIdentifier,
396         nil];
397 }
398
399 //------------------------------------------------------------------------------------
400 // validateToolbarItem:
401 //------------------------------------------------------------------------------------
402 - (BOOL) validateToolbarItem: (NSToolbarItem *) toolbarItem
403 {
404     // Optional method: This message is sent to us since we are the target of some
405     // toolbar item actions.
406
407     if (!fQueueEncodeLibhb) return NO;
408
409     BOOL enable = NO;
410
411     hb_state_t s;
412     hb_get_state2 (fQueueEncodeLibhb, &s);
413
414     if ([[toolbarItem itemIdentifier] isEqual: HBQueueStartCancelToolbarIdentifier])
415     {
416         if ((s.state == HB_STATE_PAUSED) || (s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING))
417         {
418             enable = YES;
419             [toolbarItem setImage:[NSImage imageNamed: @"Stop"]];
420             [toolbarItem setLabel: NSLocalizedStringFromTable(@"Stop", @"Queue",@"")];
421             [toolbarItem setToolTip: NSLocalizedStringFromTable(@"Stop Encoding", @"Queue",@"")];
422         }
423
424         else if (fPendingCount > 0)
425         {
426             enable = YES;
427             [toolbarItem setImage:[NSImage imageNamed: @"Play"]];
428             [toolbarItem setLabel: NSLocalizedStringFromTable(@"Start", @"Queue",@"")];
429             [toolbarItem setToolTip: NSLocalizedStringFromTable(@"Start Encoding", @"Queue",@"")];
430         }
431
432         else
433         {
434             enable = NO;
435             [toolbarItem setImage:[NSImage imageNamed: @"Play"]];
436             [toolbarItem setLabel: NSLocalizedStringFromTable(@"Start", @"Queue",@"")];
437             [toolbarItem setToolTip: NSLocalizedStringFromTable(@"Start Encoding", @"Queue",@"")];
438         }
439     }
440
441     if ([[toolbarItem itemIdentifier] isEqual: HBQueuePauseResumeToolbarIdentifier])
442     {
443         if (s.state == HB_STATE_PAUSED)
444         {
445             enable = YES;
446             [toolbarItem setImage:[NSImage imageNamed: @"Play"]];
447             [toolbarItem setLabel: NSLocalizedStringFromTable(@"Resume", @"Queue",@"")];
448             [toolbarItem setToolTip: NSLocalizedStringFromTable(@"Resume Encoding", @"Queue",@"")];
449        }
450
451         else if ((s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING))
452         {
453             enable = YES;
454             [toolbarItem setImage:[NSImage imageNamed: @"Pause"]];
455             [toolbarItem setLabel: NSLocalizedStringFromTable(@"Pause", @"Queue",@"")];
456             [toolbarItem setToolTip: NSLocalizedStringFromTable(@"Pause Encoding", @"Queue",@"")];
457         }
458         else
459         {
460             enable = NO;
461             [toolbarItem setImage:[NSImage imageNamed: @"Pause"]];
462             [toolbarItem setLabel: NSLocalizedStringFromTable(@"Pause", @"Queue",@"")];
463             [toolbarItem setToolTip: NSLocalizedStringFromTable(@"Pause Encoding", @"Queue",@"")];
464         }
465     }
466
467     return enable;
468 }
469
470 #pragma mark -
471
472
473 #pragma mark Queue Item Controls
474 //------------------------------------------------------------------------------------
475 // Delete encodes from the queue window and accompanying array
476 // Also handling first cancelling the encode if in fact its currently encoding.
477 //------------------------------------------------------------------------------------
478 - (IBAction)removeSelectedQueueItem: (id)sender
479 {
480     NSIndexSet * selectedRows = [fOutlineView selectedRowIndexes];
481     int row = [selectedRows firstIndex];
482     /* if this is a currently encoding job, we need to be sure to alert the user,
483      * to let them decide to cancel it first, then if they do, we can come back and
484      * remove it */
485     
486     if ([[[fJobGroups objectAtIndex:row] objectForKey:@"Status"] intValue] == 1)
487     {
488        /* We pause the encode here so that it doesn't finish right after and then
489         * screw up the sync while the window is open
490         */
491        [fHBController Pause:NULL];
492          NSString * alertTitle = [NSString stringWithFormat:NSLocalizedStringFromTable(@"Stop This Encode and Remove It ?", @"Queue", nil)];
493         // Which window to attach the sheet to?
494         NSWindow * docWindow;
495         if ([sender respondsToSelector: @selector(window)])
496             docWindow = [sender window];
497         
498         
499         NSBeginCriticalAlertSheet(
500                                   alertTitle,
501                                   NSLocalizedStringFromTable(@"Keep Encoding", @"Queue", nil),
502                                   nil,
503                                   NSLocalizedStringFromTable(@"Stop Encoding and Delete", @"Queue", nil),
504                                   docWindow, self,
505                                   nil, @selector(didDimissCancelCurrentJob:returnCode:contextInfo:), nil,
506                                   NSLocalizedStringFromTable(@"Your movie will be lost if you don't continue encoding.", @"Queue", nil));
507         
508         // didDimissCancelCurrentJob:returnCode:contextInfo: will be called when the dialog is dismissed
509     }
510     else
511     { 
512     /* since we are not a currently encoding item, we can just be cancelled */
513             [fHBController removeQueueFileItem:row];
514     }
515 }
516
517 - (void) didDimissCancelCurrentJob: (NSWindow *)sheet returnCode: (int)returnCode contextInfo: (void *)contextInfo
518 {
519     /* We resume encoding and perform the appropriate actions 
520      * Note: Pause: is a toggle type method based on hb's current
521      * state, if it paused, it will resume encoding and vice versa.
522      * In this case, we are paused from the calling window, so calling
523      * [fHBController Pause:NULL]; Again will resume encoding
524      */
525        [fHBController Pause:NULL];
526     if (returnCode == NSAlertOtherReturn)
527     {
528     /* We need to save the currently encoding item number first */
529     int encodingItemToRemove = fEncodingQueueItem;
530     /* Since we are encoding, we need to let fHBController Cancel this job
531      * upon which it will move to the next one if there is one
532      */
533     [fHBController doCancelCurrentJob];
534     /* Now, we can go ahead and remove the job we just cancelled since
535      * we have its item number from above
536      */
537     [fHBController removeQueueFileItem:encodingItemToRemove];
538     }
539     
540 }
541
542 //------------------------------------------------------------------------------------
543 // Show the finished encode in the finder
544 //------------------------------------------------------------------------------------
545 - (IBAction)revealSelectedQueueItem: (id)sender
546 {
547     NSIndexSet * selectedRows = [fOutlineView selectedRowIndexes];
548     NSInteger row = [selectedRows firstIndex];
549     if (row != NSNotFound)
550     {
551         while (row != NSNotFound)
552         {
553            NSMutableDictionary *queueItemToOpen = [fOutlineView itemAtRow: row];
554          [[NSWorkspace sharedWorkspace] selectFile:[queueItemToOpen objectForKey:@"DestinationPath"] inFileViewerRootedAtPath:nil];
555
556             row = [selectedRows indexGreaterThanIndex: row];
557         }
558     }
559 }
560
561
562 //------------------------------------------------------------------------------------
563 // Starts or cancels the processing of jobs depending on the current state
564 //------------------------------------------------------------------------------------
565 - (IBAction)toggleStartCancel: (id)sender
566 {
567     if (!fQueueEncodeLibhb) return;
568
569     hb_state_t s;
570     hb_get_state2 (fQueueEncodeLibhb, &s);
571
572     if ((s.state == HB_STATE_PAUSED) || (s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING))
573         [fHBController Cancel: fQueuePane]; // sender == fQueuePane so that warning alert shows up on queue window
574
575     else if (fPendingCount > 0)
576         [fHBController Rip: NULL];
577 }
578
579 //------------------------------------------------------------------------------------
580 // Toggles the pause/resume state of libhb
581 //------------------------------------------------------------------------------------
582 - (IBAction)togglePauseResume: (id)sender
583 {
584     if (!fQueueEncodeLibhb) return;
585
586     hb_state_t s;
587     hb_get_state2 (fQueueEncodeLibhb, &s);
588
589     if (s.state == HB_STATE_PAUSED)
590         hb_resume (fQueueEncodeLibhb);
591     else if ((s.state == HB_STATE_WORKING) || (s.state == HB_STATE_MUXING))
592         hb_pause (fQueueEncodeLibhb);
593 }
594
595 #pragma mark -
596
597
598 #pragma mark Animate Endcoding Item
599
600
601
602
603 //------------------------------------------------------------------------------------
604 // Starts animating the job icon of the currently processing job in the queue outline
605 // view.
606 //------------------------------------------------------------------------------------
607 - (void) startAnimatingCurrentWorkingEncodeInQueue
608 {
609     if (!fAnimationTimer)
610         fAnimationTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0/12.0     // 1/12 because there are 6 images in the animation cycle
611                 target:self
612                 selector:@selector(animateWorkingEncodeInQueue:)
613                 userInfo:nil
614                 repeats:YES] retain];
615 }
616
617 //------------------------------------------------------------------------------------
618 // If a job is currently processing, its job icon in the queue outline view is
619 // animated to its next state.
620 //------------------------------------------------------------------------------------
621 - (void) animateWorkingEncodeInQueue:(NSTimer*)theTimer
622 {
623     if (fWorkingCount > 0)
624     {
625         fAnimationIndex++;
626         fAnimationIndex %= 6;   // there are 6 animation images; see outlineView:objectValueForTableColumn:byItem: below.
627         [self animateWorkingEncodeIconInQueue];
628     }
629 }
630
631
632 - (void) animateWorkingEncodeIconInQueue
633 {
634     NSInteger row = fEncodingQueueItem; /// need to set to fEncodingQueueItem
635     NSInteger col = [fOutlineView columnWithIdentifier: @"icon"];
636     if (row != -1 && col != -1)
637     {
638         NSRect frame = [fOutlineView frameOfCellAtColumn:col row:row];
639         [fOutlineView setNeedsDisplayInRect: frame];
640     }
641 }
642
643 //------------------------------------------------------------------------------------
644 // Stops animating the job icon of the currently processing job in the queue outline
645 // view.
646 //------------------------------------------------------------------------------------
647 - (void) stopAnimatingCurrentJobGroupInQueue
648 {
649     if (fAnimationTimer && [fAnimationTimer isValid])
650     {
651         [fAnimationTimer invalidate];
652         [fAnimationTimer release];
653         fAnimationTimer = nil;
654     }
655 }
656
657
658 #pragma mark -
659
660 - (void)moveObjectsInArray:(NSMutableArray *)array fromIndexes:(NSIndexSet *)indexSet toIndex:(NSUInteger)insertIndex
661 {
662     NSUInteger index = [indexSet lastIndex];
663     NSUInteger aboveInsertIndexCount = 0;
664
665     while (index != NSNotFound)
666     {
667         NSUInteger removeIndex;
668
669         if (index >= insertIndex)
670         {
671             removeIndex = index + aboveInsertIndexCount;
672             aboveInsertIndexCount++;
673         }
674         else
675         {
676             removeIndex = index;
677             insertIndex--;
678         }
679
680         id object = [[array objectAtIndex:removeIndex] retain];
681         [array removeObjectAtIndex:removeIndex];
682         [array insertObject:object atIndex:insertIndex];
683         [object release];
684
685         index = [indexSet indexLessThanIndex:index];
686     }
687 }
688
689
690 #pragma mark -
691 #pragma mark NSOutlineView delegate
692
693
694 - (id)outlineView:(NSOutlineView *)fOutlineView child:(NSInteger)index ofItem:(id)item
695 {
696     if (item == nil)
697         return [fJobGroups objectAtIndex:index];
698
699     // We are only one level deep, so we can't be asked about children
700     NSAssert (NO, @"HBQueueController outlineView:child:ofItem: can't handle nested items.");
701     return nil;
702 }
703
704 - (BOOL)outlineView:(NSOutlineView *)fOutlineView isItemExpandable:(id)item
705 {
706     // Our outline view has no levels, but we can still expand every item. Doing so
707     // just makes the row taller. See heightOfRowByItem below.
708     return YES;
709 }
710
711 - (BOOL)outlineView:(NSOutlineView *)outlineView shouldExpandItem:(id)item
712 {
713     // Our outline view has no levels, but we can still expand every item. Doing so
714     // just makes the row taller. See heightOfRowByItem below.
715 return ![(HBQueueOutlineView*)outlineView isDragging];
716 }
717
718 - (NSInteger)outlineView:(NSOutlineView *)fOutlineView numberOfChildrenOfItem:(id)item
719 {
720     // Our outline view has no levels, so number of children will be zero for all
721     // top-level items.
722     if (item == nil)
723         return [fJobGroups count];
724     else
725         return 0;
726 }
727
728 - (void)outlineViewItemDidCollapse:(NSNotification *)notification
729 {
730     id item = [[notification userInfo] objectForKey:@"NSObject"];
731     NSInteger row = [fOutlineView rowForItem:item];
732     [fOutlineView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row,1)]];
733 }
734
735 - (void)outlineViewItemDidExpand:(NSNotification *)notification
736 {
737     id item = [[notification userInfo] objectForKey:@"NSObject"];
738     NSInteger row = [fOutlineView rowForItem:item];
739     [fOutlineView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row,1)]];
740 }
741
742 - (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item
743 {
744     if ([outlineView isItemExpanded: item])
745     {
746         // Short-circuit here if in a live resize primarily to fix a bug but also to
747         // increase resposivness during a resize. There's a bug in NSTableView that
748         // causes row heights to get messed up if you try to change them during a live
749         // resize. So if in a live resize, simply return the previously calculated
750         // height. The row heights will get fixed up after the resize because we have
751         // implemented viewDidEndLiveResize to force all of them to be recalculated.
752         // if ([outlineView inLiveResize] && [item lastDescriptionHeight] > 0)
753          //   return [item lastDescriptionHeight];
754
755         // CGFloat width = [[outlineView tableColumnWithIdentifier: @"desc"] width];
756         // Column width is NOT what is ultimately used. I can't quite figure out what
757         // width to use for calculating text metrics. No matter how I tweak this value,
758         // there are a few conditions in which the drawn text extends below the bounds
759         // of the row cell. In previous versions, which ran under Tiger, I was
760         // reducing width by 47 pixles.
761         // width -= 2;     // (?) for intercell spacing
762
763         // CGFloat height = [item heightOfDescriptionForWidth: width];
764         // return height;
765         
766         return HB_ROW_HEIGHT_FULL_DESCRIPTION;
767     }
768     else
769         return HB_ROW_HEIGHT_TITLE_ONLY;
770 }
771
772 - (CGFloat) heightOfDescriptionForWidth:(CGFloat)width
773 {
774     // Try to return the cached value if no changes have happened since the last time
775     //if ((width == fLastDescriptionWidth) && (fLastDescriptionHeight != 0) && !fNeedsDescription)
776        // return fLastDescriptionHeight;
777
778     //if (fNeedsDescription)
779     //    [self updateDescription];
780
781     // Calculate the height
782     //NSRect bounds = [fDescription boundingRectWithSize:NSMakeSize(width, 10000) options:NSStringDrawingUsesLineFragmentOrigin];
783     //fLastDescriptionHeight = bounds.size.height + 6.0; // add some border to bottom
784     //fLastDescriptionWidth = width;
785     return HB_ROW_HEIGHT_FULL_DESCRIPTION;
786
787 /* supposedly another way to do this, in case boundingRectWithSize isn't working
788     NSTextView* tmpView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, width, 1)];
789     [[tmpView textStorage] setAttributedString:aString];
790     [tmpView setHorizontallyResizable:NO];
791     [tmpView setVerticallyResizable:YES];
792 //    [[tmpView textContainer] setHeightTracksTextView: YES];
793 //    [[tmpView textContainer] setContainerSize: NSMakeSize(width, 10000)];
794     [tmpView sizeToFit];
795     float height = [tmpView frame].size.height;
796     [tmpView release];
797     return height;
798 */
799 }
800
801 - (CGFloat) lastDescriptionHeight
802 {
803     return HB_ROW_HEIGHT_FULL_DESCRIPTION;
804 }
805
806 - (id)outlineView:(NSOutlineView *)fOutlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
807 {
808     // nb: The "desc" column is currently an HBImageAndTextCell. However, we are longer
809     // using the image portion of the cell so we could switch back to a regular NSTextFieldCell.
810     
811     if ([[tableColumn identifier] isEqualToString:@"desc"])
812     {
813         /* This should have caused the description we wanted to show*/
814         //return [item objectForKey:@"SourceName"];
815         
816         /* code to build the description as per old queue */
817         //return [self formatEncodeItemDescription:item];
818         
819         /* Below should be put into a separate method but I am way too f'ing lazy right now */
820         NSMutableAttributedString * finalString = [[[NSMutableAttributedString alloc] initWithString: @""] autorelease];
821         // Attributes
822         NSMutableParagraphStyle * ps = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] retain];
823         [ps setHeadIndent: 40.0];
824         [ps setParagraphSpacing: 1.0];
825         [ps setTabStops:[NSArray array]];    // clear all tabs
826         [ps addTabStop: [[[NSTextTab alloc] initWithType: NSLeftTabStopType location: 20.0] autorelease]];
827         
828         
829         NSDictionary* detailAttr = [NSDictionary dictionaryWithObjectsAndKeys:
830                                     [NSFont systemFontOfSize:10.0], NSFontAttributeName,
831                                     ps, NSParagraphStyleAttributeName,
832                                     nil];
833         
834         NSDictionary* detailBoldAttr = [NSDictionary dictionaryWithObjectsAndKeys:
835                                         [NSFont boldSystemFontOfSize:10.0], NSFontAttributeName,
836                                         ps, NSParagraphStyleAttributeName,
837                                         nil];
838         
839         NSDictionary* titleAttr = [NSDictionary dictionaryWithObjectsAndKeys:
840                                    [NSFont systemFontOfSize:[NSFont systemFontSize]], NSFontAttributeName,
841                                    ps, NSParagraphStyleAttributeName,
842                                    nil];
843         
844         NSDictionary* shortHeightAttr = [NSDictionary dictionaryWithObjectsAndKeys:
845                                          [NSFont systemFontOfSize:2.0], NSFontAttributeName,
846                                          nil];
847         
848         /* First line, we should strip the destination path and just show the file name and add the title num and chapters (if any) */
849         //finalDescription = [finalDescription stringByAppendingString:[NSString stringWithFormat:@"Source: %@ Output: %@\n", [item objectForKey:@"SourceName"],[item objectForKey:@"DestinationPath"]]];
850         NSString * summaryInfo;
851         
852         NSString * titleString = [NSString stringWithFormat:NSLocalizedStringFromTable(@"Title %d", @"Queue",@""), [[item objectForKey:@"TitleNumber"] intValue]];
853         
854         NSString * chapterString = ([[item objectForKey:@"ChapterStart"] intValue] == [[item objectForKey:@"ChapterEnd"] intValue]) ?
855         [NSString stringWithFormat:NSLocalizedStringFromTable(@"Chapter %d", @"Queue",@""), [[item objectForKey:@"ChapterStart"] intValue]] :
856         [NSString stringWithFormat:NSLocalizedStringFromTable(@"Chapters %d through %d", @"Queue",@""), [[item objectForKey:@"ChapterStart"] intValue], [[item objectForKey:@"ChapterEnd"] intValue]];
857         
858         NSString * passesString;
859         if ([[item objectForKey:@"VideoTwoPass"] intValue] == 0)
860         {
861             passesString = [NSString stringWithFormat:NSLocalizedStringFromTable(@"1 Video Pass", @"Queue",@"")];
862         }
863         else
864         {
865             if ([[item objectForKey:@"VideoTurboTwoPass"] intValue] == 1)
866             {
867                 passesString = [NSString stringWithFormat:NSLocalizedStringFromTable(@"2 Video Passes Turbo", @"Queue",@"")];
868             }
869             else
870             {
871                 passesString = [NSString stringWithFormat:NSLocalizedStringFromTable(@"2 Video Passes", @"Queue",@"")];
872             }
873         }
874         
875         [finalString appendString:[NSString stringWithFormat:@"%@", [item objectForKey:@"SourceName"]] withAttributes:titleAttr];
876         
877         /* lets add the output file name to the title string here */
878         NSString * outputFilenameString = [[item objectForKey:@"DestinationPath"] lastPathComponent];
879         
880         summaryInfo = [NSString stringWithFormat: @" (%@, %@, %@) -> %@", titleString, chapterString, passesString, outputFilenameString];
881         
882         [finalString appendString:[NSString stringWithFormat:@"%@\n", summaryInfo] withAttributes:detailAttr];  
883         
884         // Insert a short-in-height line to put some white space after the title
885         [finalString appendString:@"\n" withAttributes:shortHeightAttr];
886         // End of Title Stuff
887         
888         /* Second Line  (Preset Name)*/
889         [finalString appendString: NSLocalizedStringFromTable(@"Preset: ", @"Queue",@"") withAttributes:detailBoldAttr];
890         [finalString appendString:[NSString stringWithFormat:@"%@\n", [item objectForKey:@"PresetName"]] withAttributes:detailAttr];
891         
892         /* Third Line  (Format Summary) */
893         NSString * audioCodecSummary = @"";
894         /* Lets also get our audio track detail since we are going through the logic for use later */
895         NSString * audioDetail1 = @"None";
896         NSString * audioDetail2 = @"None";
897         NSString * audioDetail3 = @"None";
898         NSString * audioDetail4 = @"None";
899         if ([[item objectForKey:@"Audio1Track"] intValue] > 0)
900         {
901             audioCodecSummary = [NSString stringWithFormat:@"%@", [item objectForKey:@"Audio1Encoder"]];
902             audioDetail1 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps)", @"Queue",@""),
903                             [item objectForKey:@"Audio1TrackDescription"] ,
904                             [item objectForKey:@"Audio1Encoder"],
905                             [item objectForKey:@"Audio1Mixdown"] ,
906                             [item objectForKey:@"Audio1Samplerate"],
907                             [item objectForKey:@"Audio1Bitrate"]];
908             
909             if ([[item objectForKey:@"Audio1TrackDRCSlider"] floatValue] > 1.00)
910             {
911                 audioDetail1 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@, DRC: %@", @"Queue",@""),audioDetail1,[item objectForKey:@"Audio1TrackDRCSlider"]];
912             }
913             else
914             {
915                 audioDetail1 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@, DRC: Off", @"Queue",@""),audioDetail1];
916             }
917         }
918         
919         if ([[item objectForKey:@"Audio2Track"] intValue] > 0)
920         {
921             audioCodecSummary = [NSString stringWithFormat:@"%@, %@",audioCodecSummary ,[item objectForKey:@"Audio2Encoder"]];
922             audioDetail2 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps)", @"Queue",@""),
923                             [item objectForKey:@"Audio2TrackDescription"] ,
924                             [item objectForKey:@"Audio2Encoder"],
925                             [item objectForKey:@"Audio2Mixdown"] ,
926                             [item objectForKey:@"Audio2Samplerate"],
927                             [item objectForKey:@"Audio2Bitrate"]];
928             
929             if ([[item objectForKey:@"Audio2TrackDRCSlider"] floatValue] > 1.00)
930             {
931                 audioDetail2 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@, DRC: %@", @"Queue",@""),audioDetail2,[item objectForKey:@"Audio2TrackDRCSlider"]];
932             }
933             else
934             {
935                 audioDetail2 = [NSString stringWithFormat:@"%@, DRC: Off",audioDetail2];
936             }
937         }
938         
939         if ([[item objectForKey:@"Audio3Track"] intValue] > 0)
940         {
941             audioCodecSummary = [NSString stringWithFormat:@"%@, %@",audioCodecSummary ,[item objectForKey:@"Audio3Encoder"]];
942             audioDetail3 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps)", @"Queue",@""),
943                             [item objectForKey:@"Audio3TrackDescription"] ,
944                             [item objectForKey:@"Audio3Encoder"],
945                             [item objectForKey:@"Audio3Mixdown"] ,
946                             [item objectForKey:@"Audio3Samplerate"],
947                             [item objectForKey:@"Audio3Bitrate"]];
948             
949             if ([[item objectForKey:@"Audio3TrackDRCSlider"] floatValue] > 1.00)
950             {
951                 audioDetail3 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@, DRC: %@", @"Queue",@""),audioDetail3,[item objectForKey:@"Audio3TrackDRCSlider"]];
952             }
953             else
954             {
955                 audioDetail3 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@, DRC: Off", @"Queue",@""),audioDetail3];
956             }
957         }
958         
959         if ([[item objectForKey:@"Audio4Track"] intValue] > 0)
960         {
961             audioCodecSummary = [NSString stringWithFormat:@"%@, %@",audioCodecSummary ,[item objectForKey:@"Audio3Encoder"]];
962             audioDetail4 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Encoder: %@ Mixdown: %@ SampleRate: %@(khz) Bitrate: %@(kbps)", @"Queue",@""),
963                             [item objectForKey:@"Audio4TrackDescription"] ,
964                             [item objectForKey:@"Audio4Encoder"],
965                             [item objectForKey:@"Audio4Mixdown"] ,
966                             [item objectForKey:@"Audio4Samplerate"],
967                             [item objectForKey:@"Audio4Bitrate"]];
968             
969             if ([[item objectForKey:@"Audio4TrackDRCSlider"] floatValue] > 1.00)
970             {
971                 audioDetail4 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@, DRC: %@", @"Queue",@""),audioDetail4,[item objectForKey:@"Audio4TrackDRCSlider"]];
972             }
973             else
974             {
975                 audioDetail4 = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@, DRC: Off", @"Queue",@""),audioDetail4];
976             }
977         }
978         
979         NSString * jobFormatInfo;
980         if ([[item objectForKey:@"ChapterMarkers"] intValue] == 1)
981             jobFormatInfo = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Container, %@ Video  %@ Audio, Chapter Markers\n", @"Queue",@""), [item objectForKey:@"FileFormat"], [item objectForKey:@"VideoEncoder"], audioCodecSummary];
982         else
983             jobFormatInfo = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Container, %@ Video  %@ Audio\n", @"Queue",@""), [item objectForKey:@"FileFormat"], [item objectForKey:@"VideoEncoder"], audioCodecSummary];
984         
985         
986         [finalString appendString: NSLocalizedStringFromTable(@"Format: ", @"Queue",@"") withAttributes:detailBoldAttr];
987         [finalString appendString: jobFormatInfo withAttributes:detailAttr];
988         
989         /* Optional String for mp4 options */
990         if ([[item objectForKey:@"FileFormat"] isEqualToString: NSLocalizedStringFromTable(@"MP4 file", @"Queue",@"")])
991         {
992             NSString * MP4Opts = @"";
993             BOOL mp4OptsPresent = NO;
994             if( [[item objectForKey:@"Mp4LargeFile"] intValue] == 1)
995             {
996                 mp4OptsPresent = YES;
997                 MP4Opts = [MP4Opts stringByAppendingString:NSLocalizedStringFromTable(@" - Large file size", @"Queue",@"")];
998             }
999             if( [[item objectForKey:@"Mp4HttpOptimize"] intValue] == 1)
1000             {
1001                 mp4OptsPresent = YES;
1002                 MP4Opts = [MP4Opts stringByAppendingString:NSLocalizedStringFromTable(@" - Web optimized", @"Queue",@"")];
1003             }
1004             
1005             if( [[item objectForKey:@"Mp4iPodCompatible"] intValue] == 1)
1006             {
1007                 mp4OptsPresent = YES;
1008                 MP4Opts = [MP4Opts stringByAppendingString:NSLocalizedStringFromTable(@" - iPod 5G support ", @"Queue",@"")];
1009             }
1010             if (mp4OptsPresent == YES)
1011             {
1012                 [finalString appendString: NSLocalizedStringFromTable(@"MP4 Options: ", @"Queue",@"") withAttributes:detailBoldAttr];
1013                 [finalString appendString: MP4Opts withAttributes:detailAttr];
1014                 [finalString appendString:@"\n" withAttributes:detailAttr];
1015             }
1016         }
1017         
1018         /* Fourth Line (Destination Path)*/
1019         [finalString appendString: NSLocalizedStringFromTable(@"Destination: ", @"Queue",@"") withAttributes:detailBoldAttr];
1020         [finalString appendString: [item objectForKey:@"DestinationPath"] withAttributes:detailAttr];
1021         [finalString appendString:@"\n" withAttributes:detailAttr];
1022         /* Fifth Line Picture Details*/
1023         NSString * pictureInfo;
1024         pictureInfo = [NSString stringWithFormat:@"%@", [item objectForKey:@"PictureSizingSummary"]];
1025         if ([[item objectForKey:@"PictureKeepRatio"] intValue] == 1)
1026         {
1027             pictureInfo = [pictureInfo stringByAppendingString:NSLocalizedStringFromTable(@" Keep Aspect Ratio", @"Queue",@"")];
1028         }
1029         if ([[item objectForKey:@"VideoGrayScale"] intValue] == 1)
1030         {
1031             pictureInfo = [pictureInfo stringByAppendingString:NSLocalizedStringFromTable(@", Grayscale", @"Queue",@"")];
1032         }
1033         
1034         [finalString appendString: NSLocalizedStringFromTable(@"Picture: ", @"Queue",@"") withAttributes:detailBoldAttr];
1035         [finalString appendString: pictureInfo withAttributes:detailAttr];
1036         [finalString appendString:@"\n" withAttributes:detailAttr];
1037         
1038         /* Optional String for Picture Filters */
1039         
1040         NSString * pictureFilters = @"";
1041         BOOL pictureFiltersPresent = NO;
1042         if( [[item objectForKey:@"VFR"] intValue] == 1)
1043         {
1044             pictureFiltersPresent = YES;
1045             pictureFilters = [pictureFilters stringByAppendingString:NSLocalizedStringFromTable(@" - VFR", @"Queue",@"")];
1046         }
1047         if( [[item objectForKey:@"PictureDetelecine"] intValue] == 1 )
1048         {
1049             pictureFiltersPresent = YES;
1050             pictureFilters = [pictureFilters stringByAppendingString:NSLocalizedStringFromTable(@" - Detelecine", @"Queue",@"")];
1051         }
1052         
1053         if( [[item objectForKey:@"PictureDecomb"] intValue] == 1)
1054         {
1055             pictureFiltersPresent = YES;
1056             pictureFilters = [pictureFilters stringByAppendingString:NSLocalizedStringFromTable(@" - Decomb ", @"Queue",@"")];
1057         }
1058         
1059         if ([[item objectForKey:@"PictureDeinterlace"] intValue] != 0)
1060         {
1061             pictureFiltersPresent = YES;
1062             if ([[item objectForKey:@"PictureDeinterlace"] intValue] == 1)
1063             {
1064                 pictureFilters = [pictureFilters stringByAppendingString:NSLocalizedStringFromTable(@" - Deinterlace: Fast ", @"Queue",@"")];
1065             }
1066             else if ([[item objectForKey:@"PictureDeinterlace"] intValue] == 2)
1067             {
1068                 pictureFilters = [pictureFilters stringByAppendingString:NSLocalizedStringFromTable(@" - Deinterlace: Slow ", @"Queue",@"")];           
1069             }
1070             else if ([[item objectForKey:@"PictureDeinterlace"] intValue] == 3)
1071             {
1072                 pictureFilters = [pictureFilters stringByAppendingString:NSLocalizedStringFromTable(@" - Deinterlace: Slower ", @"Queue",@"")];            
1073             }
1074             
1075         }
1076         if ([[item objectForKey:@"PictureDenoise"] intValue] != 0)
1077         {
1078             pictureFiltersPresent = YES;
1079             if ([[item objectForKey:@"PictureDenoise"] intValue] == 1)
1080             {
1081                 pictureFilters = [pictureFilters stringByAppendingString:NSLocalizedStringFromTable(@" - Denoise: Weak ", @"Queue",@"")];
1082             }
1083             else if ([[item objectForKey:@"PictureDenoise"] intValue] == 2)
1084             {
1085                 pictureFilters = [pictureFilters stringByAppendingString:NSLocalizedStringFromTable(@" - Denoise: Medium ", @"Queue",@"")];           
1086             }
1087             else if ([[item objectForKey:@"PictureDenoise"] intValue] == 3)
1088             {
1089                 pictureFilters = [pictureFilters stringByAppendingString:NSLocalizedStringFromTable(@" - Denoise: Strong ", @"Queue",@"")];            
1090             }
1091             
1092         }
1093         if ([[item objectForKey:@"PictureDeblock"] intValue] != 0)
1094         {
1095             pictureFiltersPresent = YES;
1096             pictureFilters = [pictureFilters stringByAppendingString: [NSString stringWithFormat:NSLocalizedStringFromTable(@" - Deblock (pp7) (%d) ", @"Queue",@""),[[item objectForKey:@"PictureDeblock"] intValue]]];
1097         }
1098         if (pictureFiltersPresent == YES)
1099         {
1100             [finalString appendString: NSLocalizedStringFromTable(@"Filters: ", @"Queue",@"") withAttributes:detailBoldAttr];
1101             [finalString appendString: pictureFilters withAttributes:detailAttr];
1102             [finalString appendString:@"\n" withAttributes:detailAttr];
1103         }
1104         
1105         /* Sixth Line Video Details*/
1106         NSString * videoInfo;
1107         videoInfo = [NSString stringWithFormat:NSLocalizedStringFromTable(@"Encoder: %@", @"Queue",@""), [item objectForKey:@"VideoEncoder"]];
1108         
1109         /* for framerate look to see if we are using vfr detelecine */
1110         if ([[item objectForKey:@"JobIndexVideoFramerate"] intValue] == 0)
1111         {
1112             if ([[item objectForKey:@"PictureDetelecine"] intValue] == 1)
1113             {
1114                 /* we are using same as source with vfr detelecine */
1115                 videoInfo = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Framerate: Same as source (vfr detelecine)", @"Queue",@""), videoInfo];
1116             }
1117             else
1118             {
1119                 /* we are using a variable framerate without dropping frames */
1120                 videoInfo = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Framerate: Same as source (variable)", @"Queue",@""), videoInfo];
1121             }
1122         }
1123         else
1124         {
1125             /* we have a specified, constant framerate */
1126             videoInfo = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Framerate: %@ (constant framerate)", @"Queue",@""), videoInfo ,[item objectForKey:@"VideoFramerate"]];
1127         }
1128         
1129         if ([[item objectForKey:@"VideoQualityType"] intValue] == 0)// Target Size MB
1130         {
1131             videoInfo = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Target Size: %@(MB) (%d(kbps) abr)", @"Queue",@""), videoInfo ,[item objectForKey:@"VideoTargetSize"],[[item objectForKey:@"VideoAvgBitrate"] intValue]];
1132         }
1133         else if ([[item objectForKey:@"VideoQualityType"] intValue] == 1) // ABR
1134         {
1135             videoInfo = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Bitrate: %d(kbps)", @"Queue",@""), videoInfo ,[[item objectForKey:@"VideoAvgBitrate"] intValue]];
1136         }
1137         else // CRF
1138         {
1139             videoInfo = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Constant Quality: %.0f %%", @"Queue",@""), videoInfo ,[[item objectForKey:@"VideoQualitySlider"] floatValue] * 100];
1140         }
1141         
1142         [finalString appendString: NSLocalizedStringFromTable(@"Video: ", @"Queue",@"") withAttributes:detailBoldAttr];
1143         [finalString appendString: videoInfo withAttributes:detailAttr];
1144         [finalString appendString:@"\n" withAttributes:detailAttr];
1145         
1146         if ([[item objectForKey:@"VideoEncoder"] isEqualToString: NSLocalizedStringFromTable(@"H.264 (x264)", @"Queue",@"")])
1147         {
1148             [finalString appendString: NSLocalizedStringFromTable(@"x264 Options: ", @"Queue",@"") withAttributes:detailBoldAttr];
1149             [finalString appendString: [item objectForKey:@"x264Option"] withAttributes:detailAttr];
1150             [finalString appendString:@"\n" withAttributes:detailAttr];
1151         }
1152         
1153         
1154         /* Seventh Line Audio Details*/
1155         [finalString appendString: NSLocalizedStringFromTable(@"Audio Track 1: ", @"Queue",@"") withAttributes:detailBoldAttr];
1156         [finalString appendString: audioDetail1 withAttributes:detailAttr];
1157         [finalString appendString:@"\n" withAttributes:detailAttr];
1158         
1159         [finalString appendString: NSLocalizedStringFromTable(@"Audio Track 2: ", @"Queue",@"") withAttributes:detailBoldAttr];
1160         [finalString appendString: audioDetail2 withAttributes:detailAttr];
1161         [finalString appendString:@"\n" withAttributes:detailAttr];
1162         
1163         [finalString appendString: NSLocalizedStringFromTable(@"Audio Track 3: ", @"Queue",@"") withAttributes:detailBoldAttr];
1164         [finalString appendString: audioDetail3 withAttributes:detailAttr];
1165         [finalString appendString:@"\n" withAttributes:detailAttr];
1166         
1167         [finalString appendString: NSLocalizedStringFromTable(@"Audio Track 4: ", @"Queue",@"") withAttributes:detailBoldAttr];
1168         [finalString appendString: audioDetail4 withAttributes:detailAttr];
1169         
1170         return finalString;
1171     }
1172     else if ([[tableColumn identifier] isEqualToString:@"icon"])
1173     {
1174         if ([[item objectForKey:@"Status"] intValue] == 0)
1175         {
1176             return [NSImage imageNamed:@"EncodeComplete"];
1177         }
1178         else if ([[item objectForKey:@"Status"] intValue] == 1)
1179         {
1180             return [NSImage imageNamed: [NSString stringWithFormat: NSLocalizedStringFromTable(@"EncodeWorking%d", @"Queue",@""), fAnimationIndex]];
1181         }
1182         else if ([[item objectForKey:@"Status"] intValue] == 3)
1183         {
1184             return [NSImage imageNamed:@"EncodeCanceled"];
1185         }
1186         else
1187         {
1188             return [NSImage imageNamed:@"JobSmall"];
1189         }
1190         
1191     }
1192     else
1193     {
1194         return @"";
1195     }
1196 }
1197
1198 - (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
1199 {
1200     if ([[tableColumn identifier] isEqualToString:@"desc"])
1201     {
1202
1203
1204         // nb: The "desc" column is currently an HBImageAndTextCell. However, we are longer
1205         // using the image portion of the cell so we could switch back to a regular NSTextFieldCell.
1206
1207         // Set the image here since the value returned from outlineView:objectValueForTableColumn: didn't specify the image part
1208         [cell setImage:nil];
1209     }
1210     else if ([[tableColumn identifier] isEqualToString:@"action"])
1211     {
1212         [cell setEnabled: YES];
1213         BOOL highlighted = [outlineView isRowSelected:[outlineView rowForItem: item]] && [[outlineView window] isKeyWindow] && ([[outlineView window] firstResponder] == outlineView);
1214         if ([[item objectForKey:@"Status"] intValue] == 0)
1215         {
1216             [cell setAction: @selector(revealSelectedQueueItem:)];
1217             if (highlighted)
1218             {
1219                 [cell setImage:[NSImage imageNamed:@"RevealHighlight"]];
1220                 [cell setAlternateImage:[NSImage imageNamed:@"RevealHighlightPressed"]];
1221             }
1222             else
1223                 [cell setImage:[NSImage imageNamed:@"Reveal"]];
1224         }
1225         else
1226         {
1227             [cell setAction: @selector(removeSelectedQueueItem:)];
1228             if (highlighted)
1229             {
1230                 [cell setImage:[NSImage imageNamed:@"DeleteHighlight"]];
1231                 [cell setAlternateImage:[NSImage imageNamed:@"DeleteHighlightPressed"]];
1232             }
1233             else
1234                 [cell setImage:[NSImage imageNamed:@"Delete"]];
1235         }
1236     }
1237 }
1238
1239 - (void)outlineView:(NSOutlineView *)outlineView willDisplayOutlineCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
1240 {
1241     // By default, the discolsure image gets centered vertically in the cell. We want
1242     // always at the top.
1243     if ([outlineView isItemExpanded: item])
1244         [cell setImagePosition: NSImageAbove];
1245     else
1246         [cell setImagePosition: NSImageOnly];
1247 }
1248
1249 #pragma mark -
1250 #pragma mark NSOutlineView delegate (dragging related)
1251
1252 //------------------------------------------------------------------------------------
1253 // NSTableView delegate
1254 //------------------------------------------------------------------------------------
1255
1256
1257 - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard
1258 {
1259     // Dragging is only allowed of the pending items.
1260     if ([[[fJobGroups objectAtIndex:[outlineView selectedRow]] objectForKey:@"Status"] intValue] != 2) // 2 is pending
1261     {
1262         return NO;
1263     }
1264     
1265     // Don't retain since this is just holding temporaral drag information, and it is
1266     //only used during a drag!  We could put this in the pboard actually.
1267     fDraggedNodes = items;
1268     
1269     // Provide data for our custom type, and simple NSStrings.
1270     [pboard declareTypes:[NSArray arrayWithObjects: DragDropSimplePboardType, nil] owner:self];
1271     
1272     // the actual data doesn't matter since DragDropSimplePboardType drags aren't recognized by anyone but us!.
1273     [pboard setData:[NSData data] forType:DragDropSimplePboardType];
1274     
1275     return YES;
1276 }
1277
1278
1279 /* This method is used to validate the drops. */
1280 - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index
1281 {
1282     // Don't allow dropping ONTO an item since they can't really contain any children.
1283     BOOL isOnDropTypeProposal = index == NSOutlineViewDropOnItemIndex;
1284     if (isOnDropTypeProposal)
1285     {
1286         return NSDragOperationNone;
1287     }
1288     
1289     // Don't allow dropping INTO an item since they can't really contain any children.
1290     if (item != nil)
1291     {
1292         index = [fOutlineView rowForItem: item] + 1;
1293         item = nil;
1294     }
1295     
1296     // NOTE: Should we allow dropping a pending job *above* the
1297     // finished or already encoded jobs ?
1298     // We do not let the user drop a pending job before or *above*
1299     // already finished or currently encoding jobs.
1300     if (index <= fEncodingQueueItem)
1301     {
1302         return NSDragOperationNone;
1303         index = MAX (index, fEncodingQueueItem);
1304         }
1305     
1306     [outlineView setDropItem:item dropChildIndex:index];
1307     return NSDragOperationGeneric;
1308 }
1309
1310
1311
1312 - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index
1313 {
1314         NSMutableIndexSet *moveItems = [NSMutableIndexSet indexSet];
1315     
1316     id obj;
1317     NSEnumerator *enumerator = [fDraggedNodes objectEnumerator];
1318     while (obj = [enumerator nextObject])
1319     {
1320         [moveItems addIndex:[fJobGroups indexOfObject:obj]];
1321     }
1322     // Successful drop, we use moveObjectsInQueueArray:... in fHBController
1323     // to properly rearrange the queue array, save it to plist and then send it back here.
1324     // since Controller.mm is handling all queue array manipulation.
1325     // We *could do this here, but I think we are better served keeping that code together.
1326     [fHBController moveObjectsInQueueArray:fJobGroups fromIndexes:moveItems toIndex: index];
1327     return YES;
1328 }
1329
1330
1331 @end