]> git.sesse.net Git - vlc/blob - modules/gui/macosx/playlist.m
* modules/gui/macosx/playlist.m: 10.1 is archaic. i don't know why i bother ;)
[vlc] / modules / gui / macosx / playlist.m
1 /*****************************************************************************
2  * playlist.m: MacOS X interface plugin
3  *****************************************************************************
4  * Copyright (C) 2002-2003 VideoLAN
5  * $Id: playlist.m,v 1.26 2003/06/29 00:14:50 hartman Exp $
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Derk-Jan Hartman <thedj@users.sourceforge.net>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  * 
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <stdlib.h>                                      /* malloc(), free() */
29 #include <sys/param.h>                                    /* for MAXPATHLEN */
30 #include <string.h>
31 #include <math.h>
32
33 #include "intf.h"
34 #include "playlist.h"
35
36 int MacVersion102 = -1;
37
38 /*****************************************************************************
39  * VLCPlaylistView implementation 
40  *****************************************************************************/
41 @implementation VLCPlaylistView
42
43 - (void)dealloc
44 {
45     if( o_striped_row_color != nil )
46     {
47         [o_striped_row_color release];
48     }
49     [super dealloc];
50 }
51
52 - (NSMenu *)menuForEvent:(NSEvent *)o_event
53 {
54     return( [[self delegate] menuForEvent: o_event] );
55 }
56
57 - (void)keyDown:(NSEvent *)o_event
58 {
59     unichar key = 0;
60     int i_row;
61     playlist_t * p_playlist;
62     intf_thread_t * p_intf = [NSApp getIntf];
63
64     if( [[o_event characters] length] )
65     {
66         key = [[o_event characters] characterAtIndex: 0];
67     }
68
69     p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
70                                           FIND_ANYWHERE );
71     
72     if ( p_playlist == NULL )
73     {
74         return;
75     }
76     
77     switch( key )
78     {
79         case ' ':
80             vlc_mutex_lock( &p_playlist->object_lock );
81             if( p_playlist->p_input != NULL )
82             {
83                 input_SetStatus( p_playlist->p_input, INPUT_STATUS_PAUSE );
84             }
85             vlc_mutex_unlock( &p_playlist->object_lock );
86             break;
87
88         case NSDeleteCharacter:
89         case NSDeleteFunctionKey:
90         case NSDeleteCharFunctionKey:
91         case NSBackspaceCharacter:
92             while( ( i_row = [self selectedRow] ) != -1 )
93             {
94                 if( p_playlist->i_index == i_row && p_playlist->i_status )
95                 {
96                     playlist_Stop( p_playlist );
97                 }
98         
99                 playlist_Delete( p_playlist, i_row ); 
100         
101                 [self deselectRow: i_row];
102             }
103             [self reloadData];
104             break;
105             
106         default:
107             [super keyDown: o_event];
108             break;
109     }
110
111     if( p_playlist != NULL )
112     {
113         vlc_object_release( p_playlist );
114     }
115 }
116
117 - (void)highlightSelectionInClipRect:(NSRect)o_rect {
118     NSRect o_new_rect;
119     float f_height = [self rowHeight] + [self intercellSpacing].height;
120     float f_origin_y = NSMaxY( o_rect );
121     int i_row = o_rect.origin.y / f_height;
122     
123     if ( i_row % 2 == 0 )
124     {
125         i_row++;
126     }
127     
128     o_new_rect.size.width = o_rect.size.width;
129     o_new_rect.size.height = f_height;
130     o_new_rect.origin.x = o_rect.origin.x;
131     o_new_rect.origin.y = i_row * f_height;
132    
133     if( ( MacVersion102 < 0 ) && ( floor( NSAppKitVersionNumber ) > NSAppKitVersionNumber10_1 ) )
134     {
135         MacVersion102 = 102;
136     }
137  
138     if ( MacVersion102 == 102 && o_striped_row_color == nil )
139     {
140         o_striped_row_color = [[[NSColor alternateSelectedControlColor]
141                                 highlightWithLevel: 0.90] retain];
142         
143     }
144     else if ( o_striped_row_color == nil )
145     {
146         /* OSX 10.1 and before ain't that smart ;) */
147         o_striped_row_color = [[NSColor whiteColor] retain];
148     }
149
150     [o_striped_row_color set];
151     
152     while ( o_new_rect.origin.y < f_origin_y ) {
153         NSRectFill( o_new_rect );
154         o_new_rect.origin.y += f_height * 2.0;
155     }
156     [super highlightSelectionInClipRect:o_rect];
157 }
158
159 @end
160
161 /*****************************************************************************
162  * VLCPlaylist implementation 
163  *****************************************************************************/
164 @implementation VLCPlaylist
165
166 - (id)init
167 {
168     self = [super init];
169     if ( self !=nil )
170     {
171         i_moveRow = -1;
172     }
173     return self;
174 }
175
176 - (void)awakeFromNib
177 {
178     [o_table_view setTarget: self];
179     [o_table_view setDelegate: self];
180     [o_table_view setDataSource: self];
181
182     [o_table_view setDoubleAction: @selector(playItem:)];
183
184     [o_table_view registerForDraggedTypes: 
185         [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
186
187     [o_mi_play setTitle: _NS("Play")];
188     [o_mi_delete setTitle: _NS("Delete")];
189     [o_mi_selectall setTitle: _NS("Select All")];
190     
191     [o_btn_add setToolTip: _NS("Add")];
192     [o_btn_remove setToolTip: _NS("Delete")];
193 }
194
195 - (BOOL)tableView:(NSTableView *)o_tv 
196                   shouldEditTableColumn:(NSTableColumn *)o_tc
197                   row:(int)i_row
198 {
199     return( NO );
200 }
201
202 - (NSMenu *)menuForEvent:(NSEvent *)o_event
203 {
204     NSPoint pt;
205     vlc_bool_t b_rows;
206     vlc_bool_t b_item_sel;
207
208     pt = [o_table_view convertPoint: [o_event locationInWindow] 
209                                                  fromView: nil];
210     b_item_sel = ( [o_table_view rowAtPoint: pt] != -1 &&
211                    [o_table_view selectedRow] != -1 );
212     b_rows = [o_table_view numberOfRows] != 0;
213
214     [o_mi_play setEnabled: b_item_sel];
215     [o_mi_delete setEnabled: b_item_sel];
216     [o_mi_selectall setEnabled: b_rows];
217
218     return( o_ctx_menu );
219 }
220
221 - (IBAction)playItem:(id)sender
222 {
223     intf_thread_t * p_intf = [NSApp getIntf];
224     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
225                                                        FIND_ANYWHERE );
226
227     if( p_playlist == NULL )
228     {
229         return;
230     }
231
232     playlist_Goto( p_playlist, [o_table_view selectedRow] );
233
234     vlc_object_release( p_playlist );
235 }
236
237 - (IBAction)deleteItems:(id)sender
238 {
239     int i_row;
240
241     intf_thread_t * p_intf = [NSApp getIntf];
242     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
243                                                        FIND_ANYWHERE );
244
245     if( p_playlist == NULL )
246     {
247         return;
248     }
249
250     while( ( i_row = [o_table_view selectedRow] ) != -1 )
251     {
252         if( p_playlist->i_index == i_row && p_playlist->i_status )
253         {
254             playlist_Stop( p_playlist );
255         }
256
257         playlist_Delete( p_playlist, i_row ); 
258
259         [o_table_view deselectRow: i_row];
260     }
261
262     vlc_object_release( p_playlist );
263
264     /* this is actually duplicity, because the intf.m manage also updates the view
265      * when the playlist changes. we do this on purpose, because else there is a 
266      * delay of .5 sec or so when we delete an item */
267     [self playlistUpdated];
268     [self updateRowSelection];
269 }
270
271 - (IBAction)selectAll:(id)sender
272 {
273     [o_table_view selectAll: nil];
274 }
275
276 - (void)appendArray:(NSArray*)o_array atPos:(int)i_pos enqueue:(BOOL)b_enqueue
277 {
278     int i_items;
279     NSString * o_value;
280     NSEnumerator * o_enum;
281     intf_thread_t * p_intf = [NSApp getIntf];
282     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
283                                                        FIND_ANYWHERE );
284
285     if( p_playlist == NULL )
286     {
287         return;
288     }
289
290     i_items = 0;
291     o_enum = [o_array objectEnumerator];
292     while( ( o_value = [o_enum nextObject] ) )
293     {
294         NSURL * o_url;
295
296         int i_mode = PLAYLIST_INSERT;
297         
298         if (i_items == 0 && !b_enqueue)
299             i_mode |= PLAYLIST_GO;
300
301         playlist_Add( p_playlist, [o_value fileSystemRepresentation],
302             i_mode, i_pos == -1 ? PLAYLIST_END : i_pos + i_items );
303
304         o_url = [NSURL fileURLWithPath: o_value];
305         if( o_url != nil )
306         { 
307             [[NSDocumentController sharedDocumentController]
308                 noteNewRecentDocumentURL: o_url]; 
309         }
310
311         i_items++;
312     }
313
314     vlc_object_release( p_playlist );
315 }
316
317 - (void)playlistUpdated
318 {
319     [o_table_view reloadData];
320 }
321
322 - (void)updateRowSelection
323 {
324     int i_row;
325
326     intf_thread_t * p_intf = [NSApp getIntf];
327     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
328                                                        FIND_ANYWHERE );
329
330     if( p_playlist == NULL )
331     {
332         return;
333     }
334
335     vlc_mutex_lock( &p_playlist->object_lock );    
336     i_row = p_playlist->i_index;
337     vlc_mutex_unlock( &p_playlist->object_lock );
338     vlc_object_release( p_playlist );
339
340     [o_table_view selectRow: i_row byExtendingSelection: NO];
341     [o_table_view scrollRowToVisible: i_row];
342 }
343
344 @end
345
346 @implementation VLCPlaylist (NSTableDataSource)
347
348 - (int)numberOfRowsInTableView:(NSTableView *)o_tv
349 {
350     int i_count = 0;
351     intf_thread_t * p_intf = [NSApp getIntf];
352     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
353                                                        FIND_ANYWHERE );
354
355     if( p_playlist != NULL )
356     {
357         vlc_mutex_lock( &p_playlist->object_lock );
358         i_count = p_playlist->i_size;
359         vlc_mutex_unlock( &p_playlist->object_lock );
360         vlc_object_release( p_playlist );
361     }
362
363     return( i_count );
364 }
365
366 - (id)tableView:(NSTableView *)o_tv 
367                 objectValueForTableColumn:(NSTableColumn *)o_tc 
368                 row:(int)i_row
369 {
370     id o_value = nil;
371     intf_thread_t * p_intf = [NSApp getIntf];
372     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
373                                                FIND_ANYWHERE );
374
375     if( p_playlist == NULL )
376     {
377         return( nil );
378     }
379
380     vlc_mutex_lock( &p_playlist->object_lock );
381     o_value = [[NSString stringWithUTF8String: 
382         p_playlist->pp_items[i_row]->psz_name] lastPathComponent]; 
383     vlc_mutex_unlock( &p_playlist->object_lock ); 
384
385     vlc_object_release( p_playlist );
386
387     return( o_value );
388 }
389
390 - (BOOL)tableView:(NSTableView *)o_tv
391                     writeRows:(NSArray*)o_rows
392                     toPasteboard:(NSPasteboard*)o_pasteboard 
393 {
394     int i_rows = [o_rows count];
395     NSArray *o_filenames = [NSArray array];
396     
397     [o_pasteboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:self];
398     [o_pasteboard setPropertyList:o_filenames forType:NSFilenamesPboardType];
399     if ( i_rows == 1 )
400     {
401         i_moveRow = [[o_rows objectAtIndex:0]intValue];
402         return YES;
403     }
404     return NO;
405 }
406
407 - (NSDragOperation)tableView:(NSTableView*)o_tv
408                     validateDrop:(id <NSDraggingInfo>)o_info
409                     proposedRow:(int)i_row
410                     proposedDropOperation:(NSTableViewDropOperation)o_operation 
411 {
412     if ( o_operation == NSTableViewDropAbove )
413     {
414         if ( i_moveRow >= 0 )
415         {
416             if ( i_row != i_moveRow )
417             {
418                 return NSDragOperationMove;
419             }
420             /* what if in the previous run, the row wasn't actually moved? 
421                then we can't drop new files on this location */
422             return NSDragOperationNone;
423         }
424         return NSDragOperationGeneric;
425     }
426     return NSDragOperationNone;
427 }
428
429 - (BOOL)tableView:(NSTableView*)o_tv
430                     acceptDrop:(id <NSDraggingInfo>)o_info
431                     row:(int)i_proposed_row
432                     dropOperation:(NSTableViewDropOperation)o_operation 
433 {
434     if (  i_moveRow >= 0 )
435     {
436         if (i_moveRow != -1 && i_proposed_row != -1)
437         {
438             intf_thread_t * p_intf = [NSApp getIntf];
439             playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
440                                                             FIND_ANYWHERE );
441         
442             if( p_playlist == NULL )
443             {
444                 i_moveRow = -1;
445                 return NO;
446             }
447     
448             playlist_Move( p_playlist, i_moveRow, i_proposed_row ); 
449         
450             vlc_object_release( p_playlist );
451         }
452         [self playlistUpdated];
453         i_moveRow = -1;
454         return YES;
455     }
456     else
457     {
458         NSArray * o_values;
459         NSPasteboard * o_pasteboard;
460         
461         intf_thread_t * p_intf = [NSApp getIntf];
462         o_pasteboard = [o_info draggingPasteboard];
463         
464         if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
465         {
466             o_values = [[o_pasteboard propertyListForType: NSFilenamesPboardType]
467                         sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
468
469             config_PutPsz( p_intf, "sub-file", "" );
470             config_PutInt( p_intf, "sub-delay", 0 );
471             config_PutFloat( p_intf, "sub-fps", 0.0 );
472             config_PutPsz( p_intf, "sout", "" );
473
474             [self appendArray: o_values atPos: i_proposed_row enqueue:YES];
475
476             return( YES );
477         }
478         
479         return( NO );
480     }
481     [self updateRowSelection];
482 }
483
484 @end
485