OSDN Git Service

c125779e14c8ee2e5f4b8f3ff28dd60132d13034
[handbrake-jp/handbrake-jp-git.git] / macosx / HBSubtitles.m
1 /* $Id: HBSubtitles.m,v 1.35 2005/08/01 14:29:50 titer Exp $
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
8 #import "HBSubtitles.h"
9 #include "hb.h"
10
11 @implementation HBSubtitles
12 - (id)init 
13 {
14     self = [super init];
15     if( self != nil )
16     {
17         fTitle = NULL;
18     }
19     
20     return self;
21 }
22
23
24 - (void)resetWithTitle:(hb_title_t *)title
25 {
26     fTitle = title;
27     
28     if (!title)
29     {
30         return;
31     }
32     
33     if (subtitleArray)
34     {
35         [subtitleArray release];
36     }
37     subtitleArray = [[NSMutableArray alloc] init];
38     [self addSubtitleTrack];
39 }
40
41 #pragma mark -
42 #pragma mark Create new Subtitles
43
44 - (void)addSubtitleTrack
45 {
46     [subtitleArray addObject:[self createSubtitleTrack]];
47 }
48
49 /* Creates a new subtitle track and stores it in an NSMutableDictionary */
50 - (NSDictionary *)createSubtitleTrack
51 {
52     NSMutableDictionary *newSubtitleTrack = [[NSMutableDictionary alloc] init];
53     /* Subtitle Source track popup index */
54     [newSubtitleTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleSourceTrackNum"];
55     /* Subtitle Source track popup language */
56     [newSubtitleTrack setObject:@"None" forKey:@"subtitleSourceTrackName"];
57     /* Subtitle Source track popup isPictureSub */
58     [newSubtitleTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleSourceTrackisPictureSub"];
59     /* Subtitle track forced state */
60     [newSubtitleTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackForced"];
61     /* Subtitle track burned state */
62     [newSubtitleTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackBurned"];
63     /* Subtitle track default state */
64     [newSubtitleTrack setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackDefault"];
65
66     [newSubtitleTrack autorelease];
67     return newSubtitleTrack;
68 }
69
70 - (NSMutableArray*) getSubtitleArray: (NSMutableArray *) subtitlesArray 
71 {
72     //NSMutableArray *returnSubtitlesArray = [[NSMutableArray alloc] init];
73     //[returnSubtitlesArray initWithArray:subtitleArray];
74     //[returnSubtitlesArray autorelease];
75     return subtitleArray;
76 }
77
78 - (void)containerChanged:(int) newContainer
79 {
80 container = newContainer;
81 }
82    
83 #pragma mark -
84 #pragma mark Subtitle Table Delegate Methods
85 /* Table View delegate methods */
86 /* Returns the number of tracks displayed
87  * NOTE: we return one more than the actual number of tracks
88  * specified as we always keep one track set to "None" which is ignored
89  * for setting up tracks, but is used to add tracks.
90  */
91 - (int)numberOfRowsInTableView:(NSTableView *)aTableView
92 {
93     if( fTitle == NULL || ![subtitleArray count])
94     {
95         return 0;
96     }
97     else
98     {
99         return [subtitleArray count];
100     }
101 }
102
103 /* Used to tell the Table view which information is to be displayed per item */
104 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
105 {
106     NSString *cellEntry = @"__DATA ERROR__";
107     
108     /* we setup whats displayed given the column identifier */
109     if ([[aTableColumn identifier] isEqualToString:@"track"])
110     {
111         /* 'track' is a popup of all available source subtitle tracks for the given title */
112         
113         
114         NSPopUpButtonCell *cellTrackPopup = [[NSPopUpButtonCell alloc] init];
115         [cellTrackPopup autorelease];
116         /* Set the Popups properties */
117         /* Following two lines can be used to show kind of a text field with indicator arrows which
118          * will popup when clicked on. Comment out for a standard style popup */
119         //[cellTrackPopup setShowsBorderOnlyWhileMouseInside:YES];
120         //[cellTrackPopup setBordered:NO];
121         
122         [cellTrackPopup setControlSize:NSSmallControlSize];
123         [cellTrackPopup setFont:[NSFont systemFontOfSize:[NSFont systemFontSizeForControlSize:NSSmallControlSize]]];
124         
125         
126         /* Add our initial "None" track which we use to add source tracks or remove tracks.
127          * "None" is always index 0.
128          */
129         [[cellTrackPopup menu] addItemWithTitle: @"None" action: NULL keyEquivalent: @""];
130         
131         /* Foreign Audio Search (index 1 in the popup) is only available for the first track */
132         if (rowIndex == 0)
133         {
134             [[cellTrackPopup menu] addItemWithTitle: @"Foreign Audio Search - (Bitmap)" action: NULL keyEquivalent: @""];
135         }
136         
137         if (fTitle)
138         {
139             hb_subtitle_t *subtitle;
140             hb_subtitle_config_t sub_config;
141             int i;
142             for(i = 0; i < hb_list_count( fTitle->list_subtitle ); i++ )
143             {
144                 NSString * trackTypeString = @"";
145                 subtitle = (hb_subtitle_t *) hb_list_item( fTitle->list_subtitle, i );
146                 sub_config = subtitle->config;
147                 
148                 if (subtitle->format == PICTURESUB)
149                 {
150                     trackTypeString = @"- (Bitmap)";
151                 }
152                 else
153                 {
154                     trackTypeString = @"- (Text)";
155                 }
156                 
157                 
158                 NSString *popupMenuItemDescription = [NSString stringWithFormat:@"%d - %@ %@",i,[NSString stringWithUTF8String:subtitle->lang],trackTypeString];
159                 
160                 [[cellTrackPopup menu] addItemWithTitle: popupMenuItemDescription action: NULL keyEquivalent: @""];
161             }
162         }
163         
164         [aTableColumn setDataCell:cellTrackPopup];
165         
166     }
167     else if ([[aTableColumn identifier] isEqualToString:@"forced"])
168     {
169     /* 'forced' is a checkbox to determine if a given source track is only to be forced */
170     NSButtonCell *cellForcedCheckBox = [[NSButtonCell alloc] init];
171     [cellForcedCheckBox autorelease];
172     [cellForcedCheckBox setButtonType:NSSwitchButton];
173     [cellForcedCheckBox setImagePosition:NSImageOnly];
174     [cellForcedCheckBox setAllowsMixedState:NO];
175     [aTableColumn setDataCell:cellForcedCheckBox];
176
177     }
178     else if ([[aTableColumn identifier] isEqualToString:@"burned"])
179     {
180     /* 'burned' is a checkbox to determine if a given source track is only to be burned */
181     NSButtonCell *cellBurnedCheckBox = [[NSButtonCell alloc] init];
182     [cellBurnedCheckBox autorelease];
183     [cellBurnedCheckBox setButtonType:NSSwitchButton];
184     [cellBurnedCheckBox setImagePosition:NSImageOnly];
185     [cellBurnedCheckBox setAllowsMixedState:NO];
186     [aTableColumn setDataCell:cellBurnedCheckBox];
187     }
188     else if ([[aTableColumn identifier] isEqualToString:@"default"])
189     {
190     NSButtonCell *cellDefaultCheckBox = [[NSButtonCell alloc] init];
191     [cellDefaultCheckBox autorelease];
192     [cellDefaultCheckBox setButtonType:NSSwitchButton];
193     [cellDefaultCheckBox setImagePosition:NSImageOnly];
194     [cellDefaultCheckBox setAllowsMixedState:NO];
195     [aTableColumn setDataCell:cellDefaultCheckBox];
196     }
197     else
198     {
199     cellEntry = nil;    
200     }
201
202     return cellEntry;
203 }
204
205 /* Called whenever a widget in the table is edited or changed, we use it to record the change in the controlling array 
206  * including removing and adding new tracks via the "None" ("track" index of 0) */
207 - (void)tableView:(NSTableView *)aTableView setObjectValue:(id)anObject forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
208 {
209     
210     if ([[aTableColumn identifier] isEqualToString:@"track"])
211     {
212         [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:[anObject intValue]] forKey:@"subtitleSourceTrackNum"];
213         /* Set the array to track if we are vobsub (picture sub) */
214         if ([anObject intValue] != 0)
215         {
216             int sourceSubtitleIndex;
217             bool isPictureSub = FALSE;
218             if (rowIndex == 0)
219             {
220                 sourceSubtitleIndex = [anObject intValue] - 2;
221             }
222             else
223             {
224                 sourceSubtitleIndex = [anObject intValue] - 1;
225             }
226             
227             if (rowIndex == 0 && [anObject intValue] == 1)// we are Foreign Launguage Search, which is inherently bitmap
228             {
229                 isPictureSub = TRUE;
230             }
231             else
232             {
233                 hb_subtitle_t        * subtitle;
234                 hb_subtitle_config_t   sub_config;
235                 subtitle = (hb_subtitle_t *) hb_list_item( fTitle->list_subtitle, sourceSubtitleIndex );
236                 sub_config = subtitle->config;
237                 if (subtitle->format == PICTURESUB)
238                 {
239                     isPictureSub = TRUE;
240                 }
241             }
242             if (isPictureSub == TRUE)
243             {
244                 [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:1] forKey:@"subtitleSourceTrackisPictureSub"];
245             }
246             else
247             {
248                 [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:0] forKey:@"subtitleSourceTrackisPictureSub"];
249                 /* if we are not picture sub, then we must be a text sub, handbrake does not support burning in text subs */
250                 [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackBurned"];
251             }
252         }
253      }
254     else if ([[aTableColumn identifier] isEqualToString:@"forced"])
255     {
256         [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:[anObject intValue]] forKey:@"subtitleTrackForced"];   
257     }
258     else if ([[aTableColumn identifier] isEqualToString:@"burned"])
259     {
260         [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:[anObject intValue]] forKey:@"subtitleTrackBurned"];   
261         /* now we need to make sure no other tracks are set to burned if we have set burned*/
262         if ([anObject intValue] == 1)
263         {
264             int i = 0;
265             NSEnumerator *enumerator = [subtitleArray objectEnumerator];
266             id tempObject;
267             while ( tempObject = [enumerator nextObject] )  
268             {
269                 if (i != rowIndex )
270                 {
271                     [tempObject setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackBurned"];
272                 }
273             i++;
274             }
275         }
276     }
277     else if ([[aTableColumn identifier] isEqualToString:@"default"])
278     {
279         [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:[anObject intValue]] forKey:@"subtitleTrackDefault"];   
280         /* now we need to make sure no other tracks are set to default */
281         if ([anObject intValue] == 1)
282         {
283             int i = 0;
284             NSEnumerator *enumerator = [subtitleArray objectEnumerator];
285             id tempObject;
286             while ( tempObject = [enumerator nextObject] )  
287             {
288                 if (i != rowIndex)
289                 {
290                     [tempObject setObject:[NSNumber numberWithInt:0] forKey:@"subtitleTrackDefault"];
291                 }
292             i++;
293             }
294         }
295         
296     }
297     
298     
299     /* now lets do a bit of logic to add / remove tracks as necessary via the "None" track (index 0) */
300     if ([[aTableColumn identifier] isEqualToString:@"track"])
301     {
302  
303         /* since mp4 only supports burned in vobsubs (bitmap) we need to make sure burned in is specified */
304         if (container == HB_MUX_MP4 && [anObject intValue] != 0)
305         {
306             /* so, if isPictureSub = TRUE and we are mp4, we now have to A) set burned-in to 1 and b) remove any other
307              * tracks specified that are burned in */
308             if ([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackisPictureSub"] intValue] == 1)
309             {
310                 [[subtitleArray objectAtIndex:rowIndex] setObject:[NSNumber numberWithInt:1] forKey:@"subtitleTrackBurned"];
311             }
312         }
313         
314          
315          /* We use the track popup index number (presumes index 0 is "None" which is ignored and only used to remove tracks if need be)
316          * to determine whether to 1 modify an existing track, 2. add a new empty "None" track or 3. remove an existing track.
317          */
318
319         if ([anObject intValue] != 0 && rowIndex == [subtitleArray count] - 1) // if we have a last track which != "None"
320         {
321             /* add a new empty None track */
322             [self addSubtitleTrack];
323         }
324         else if ([anObject intValue] == 0 && rowIndex != ([subtitleArray count] -1))// if this track is none and not the last track displayed
325         {
326             /* we know the user chose to remove this track by setting it to None, so remove it from the array */
327             [subtitleArray removeObjectAtIndex: rowIndex];
328         }
329         
330         
331         
332     }
333     
334     [aTableView reloadData];
335 }
336
337
338 /* Gives fine grained control over the final drawing of the widget, including widget status via the controlling array */
339 - (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
340 {
341     /* we setup whats displayed given the column identifier */
342     if ([[aTableColumn identifier] isEqualToString:@"track"])
343     {
344         /* Set the index of the recorded source track here */
345         [aCell selectItemAtIndex:[[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackNum"] intValue]];
346         /* now that we have actually selected our track, we can grok the titleOfSelectedItem for that track */
347         [[subtitleArray objectAtIndex:rowIndex] setObject:[[aTableColumn dataCellForRow:rowIndex] titleOfSelectedItem] forKey:@"subtitleSourceTrackName"];
348         
349      }
350     else
351     {
352         
353         [aCell setAlignment:NSCenterTextAlignment];
354         /* If the Track is None, we disable the other cells as None is an empty track */
355         if ([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackNum"] intValue] == 0)
356         {
357             [aCell setState:0];
358             [aCell setEnabled:NO];
359         }
360         else
361         {
362             /* Since we have a valid track, we go ahead and enable the rest of the widgets and set them according to the controlling array */
363             [aCell setEnabled:YES];
364         }
365         
366         if ([[aTableColumn identifier] isEqualToString:@"forced"])
367         {
368             [aCell setState:[[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackForced"] intValue]];
369         }
370         else if ([[aTableColumn identifier] isEqualToString:@"burned"])
371         {
372             [aCell setState:[[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackBurned"] intValue]];
373             /* Disable the "Burned-In" checkbox if a) the track is "None", b) the subtitle track is text (we do not support burning in
374              * text subs, or c) we are mp4 and the track is a vobsub (picture sub) */
375             if ([[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackNum"] intValue] == 0 ||
376                 [[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackisPictureSub"] intValue] == 0 ||
377                 (container == HB_MUX_MP4 && [[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleSourceTrackisPictureSub"] intValue] == 1))
378             {
379                 [aCell setEnabled:NO];
380             }
381             else
382             {
383                 [aCell setEnabled:YES];
384             }
385         }
386         else if ([[aTableColumn identifier] isEqualToString:@"default"])
387         {
388             [aCell setState:[[[subtitleArray objectAtIndex:rowIndex] objectForKey:@"subtitleTrackDefault"] intValue]];   
389         }
390         
391     }
392     
393     BOOL useMp4VobsubDelete = YES;
394     if (useMp4VobsubDelete == YES)
395     {
396         if (container == HB_MUX_MP4)
397         {
398             /* now remove any other tracks that are set as burned and are picturesubs */
399             int i = 0;
400             int removedTracks = 0;
401             NSEnumerator *enumerator = [subtitleArray objectEnumerator];
402             id tempObject;
403             NSMutableArray *tempArrayToDelete = [NSMutableArray array];
404             BOOL removeTrack = NO; 
405             while ( tempObject = [enumerator nextObject] )  
406             {
407                 
408                     if ([[tempObject objectForKey:@"subtitleSourceTrackisPictureSub"] intValue] == 1)
409                     {
410                         /* if this is the first vobsub mark it. if not, remove it */
411                         if (removeTrack == NO)
412                         {
413                             /* make sure that this is set to be burned in */
414                             [tempObject setObject:[NSNumber numberWithInt:1] forKey:@"subtitleTrackBurned"];
415                             removeTrack = YES;
416                         }
417                         else
418                         {
419                             [tempArrayToDelete addObject:tempObject];
420                             removedTracks ++;
421                         }
422                     }
423                 
424                 i++;
425             }
426             /* check to see if there are tracks to remove from the array */
427             if ([tempArrayToDelete count] > 0)
428             {
429                 /* Popup a warning that hb only support one pic sub being burned in with mp4 */
430                 int status;
431                 NSBeep();
432                 status = NSRunAlertPanel(@"More than one vobsub is not supported in an mp4...",@"Your first vobsub track will now be used.", @"OK", nil, nil);
433                 [NSApp requestUserAttention:NSCriticalRequest];
434                 
435                 [subtitleArray removeObjectsInArray:tempArrayToDelete];
436                 [aTableView reloadData];
437             }
438         }
439     }
440
441 }
442
443
444 @end