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 $
7 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8 * Derk-Jan Hartman <thedj@users.sourceforge.net>
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.
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.
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 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
28 #include <stdlib.h> /* malloc(), free() */
29 #include <sys/param.h> /* for MAXPATHLEN */
36 int MacVersion102 = -1;
38 /*****************************************************************************
39 * VLCPlaylistView implementation
40 *****************************************************************************/
41 @implementation VLCPlaylistView
45 if( o_striped_row_color != nil )
47 [o_striped_row_color release];
52 - (NSMenu *)menuForEvent:(NSEvent *)o_event
54 return( [[self delegate] menuForEvent: o_event] );
57 - (void)keyDown:(NSEvent *)o_event
61 playlist_t * p_playlist;
62 intf_thread_t * p_intf = [NSApp getIntf];
64 if( [[o_event characters] length] )
66 key = [[o_event characters] characterAtIndex: 0];
69 p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
72 if ( p_playlist == NULL )
80 vlc_mutex_lock( &p_playlist->object_lock );
81 if( p_playlist->p_input != NULL )
83 input_SetStatus( p_playlist->p_input, INPUT_STATUS_PAUSE );
85 vlc_mutex_unlock( &p_playlist->object_lock );
88 case NSDeleteCharacter:
89 case NSDeleteFunctionKey:
90 case NSDeleteCharFunctionKey:
91 case NSBackspaceCharacter:
92 while( ( i_row = [self selectedRow] ) != -1 )
94 if( p_playlist->i_index == i_row && p_playlist->i_status )
96 playlist_Stop( p_playlist );
99 playlist_Delete( p_playlist, i_row );
101 [self deselectRow: i_row];
107 [super keyDown: o_event];
111 if( p_playlist != NULL )
113 vlc_object_release( p_playlist );
117 - (void)highlightSelectionInClipRect:(NSRect)o_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;
123 if ( i_row % 2 == 0 )
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;
133 if( ( MacVersion102 < 0 ) && ( floor( NSAppKitVersionNumber ) > NSAppKitVersionNumber10_1 ) )
138 if ( MacVersion102 == 102 && o_striped_row_color == nil )
140 o_striped_row_color = [[[NSColor alternateSelectedControlColor]
141 highlightWithLevel: 0.90] retain];
144 else if ( o_striped_row_color == nil )
146 /* OSX 10.1 and before ain't that smart ;) */
147 o_striped_row_color = [[NSColor whiteColor] retain];
150 [o_striped_row_color set];
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;
156 [super highlightSelectionInClipRect:o_rect];
161 /*****************************************************************************
162 * VLCPlaylist implementation
163 *****************************************************************************/
164 @implementation VLCPlaylist
178 [o_table_view setTarget: self];
179 [o_table_view setDelegate: self];
180 [o_table_view setDataSource: self];
182 [o_table_view setDoubleAction: @selector(playItem:)];
184 [o_table_view registerForDraggedTypes:
185 [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
187 [o_mi_play setTitle: _NS("Play")];
188 [o_mi_delete setTitle: _NS("Delete")];
189 [o_mi_selectall setTitle: _NS("Select All")];
191 [o_btn_add setToolTip: _NS("Add")];
192 [o_btn_remove setToolTip: _NS("Delete")];
195 - (BOOL)tableView:(NSTableView *)o_tv
196 shouldEditTableColumn:(NSTableColumn *)o_tc
202 - (NSMenu *)menuForEvent:(NSEvent *)o_event
206 vlc_bool_t b_item_sel;
208 pt = [o_table_view convertPoint: [o_event locationInWindow]
210 b_item_sel = ( [o_table_view rowAtPoint: pt] != -1 &&
211 [o_table_view selectedRow] != -1 );
212 b_rows = [o_table_view numberOfRows] != 0;
214 [o_mi_play setEnabled: b_item_sel];
215 [o_mi_delete setEnabled: b_item_sel];
216 [o_mi_selectall setEnabled: b_rows];
218 return( o_ctx_menu );
221 - (IBAction)playItem:(id)sender
223 intf_thread_t * p_intf = [NSApp getIntf];
224 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
227 if( p_playlist == NULL )
232 playlist_Goto( p_playlist, [o_table_view selectedRow] );
234 vlc_object_release( p_playlist );
237 - (IBAction)deleteItems:(id)sender
241 intf_thread_t * p_intf = [NSApp getIntf];
242 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
245 if( p_playlist == NULL )
250 while( ( i_row = [o_table_view selectedRow] ) != -1 )
252 if( p_playlist->i_index == i_row && p_playlist->i_status )
254 playlist_Stop( p_playlist );
257 playlist_Delete( p_playlist, i_row );
259 [o_table_view deselectRow: i_row];
262 vlc_object_release( p_playlist );
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];
271 - (IBAction)selectAll:(id)sender
273 [o_table_view selectAll: nil];
276 - (void)appendArray:(NSArray*)o_array atPos:(int)i_pos enqueue:(BOOL)b_enqueue
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,
285 if( p_playlist == NULL )
291 o_enum = [o_array objectEnumerator];
292 while( ( o_value = [o_enum nextObject] ) )
296 int i_mode = PLAYLIST_INSERT;
298 if (i_items == 0 && !b_enqueue)
299 i_mode |= PLAYLIST_GO;
301 playlist_Add( p_playlist, [o_value fileSystemRepresentation],
302 i_mode, i_pos == -1 ? PLAYLIST_END : i_pos + i_items );
304 o_url = [NSURL fileURLWithPath: o_value];
307 [[NSDocumentController sharedDocumentController]
308 noteNewRecentDocumentURL: o_url];
314 vlc_object_release( p_playlist );
317 - (void)playlistUpdated
319 [o_table_view reloadData];
322 - (void)updateRowSelection
326 intf_thread_t * p_intf = [NSApp getIntf];
327 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
330 if( p_playlist == NULL )
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 );
340 [o_table_view selectRow: i_row byExtendingSelection: NO];
341 [o_table_view scrollRowToVisible: i_row];
346 @implementation VLCPlaylist (NSTableDataSource)
348 - (int)numberOfRowsInTableView:(NSTableView *)o_tv
351 intf_thread_t * p_intf = [NSApp getIntf];
352 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
355 if( p_playlist != NULL )
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 );
366 - (id)tableView:(NSTableView *)o_tv
367 objectValueForTableColumn:(NSTableColumn *)o_tc
371 intf_thread_t * p_intf = [NSApp getIntf];
372 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
375 if( p_playlist == NULL )
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 );
385 vlc_object_release( p_playlist );
390 - (BOOL)tableView:(NSTableView *)o_tv
391 writeRows:(NSArray*)o_rows
392 toPasteboard:(NSPasteboard*)o_pasteboard
394 int i_rows = [o_rows count];
395 NSArray *o_filenames = [NSArray array];
397 [o_pasteboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:self];
398 [o_pasteboard setPropertyList:o_filenames forType:NSFilenamesPboardType];
401 i_moveRow = [[o_rows objectAtIndex:0]intValue];
407 - (NSDragOperation)tableView:(NSTableView*)o_tv
408 validateDrop:(id <NSDraggingInfo>)o_info
409 proposedRow:(int)i_row
410 proposedDropOperation:(NSTableViewDropOperation)o_operation
412 if ( o_operation == NSTableViewDropAbove )
414 if ( i_moveRow >= 0 )
416 if ( i_row != i_moveRow )
418 return NSDragOperationMove;
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;
424 return NSDragOperationGeneric;
426 return NSDragOperationNone;
429 - (BOOL)tableView:(NSTableView*)o_tv
430 acceptDrop:(id <NSDraggingInfo>)o_info
431 row:(int)i_proposed_row
432 dropOperation:(NSTableViewDropOperation)o_operation
434 if ( i_moveRow >= 0 )
436 if (i_moveRow != -1 && i_proposed_row != -1)
438 intf_thread_t * p_intf = [NSApp getIntf];
439 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
442 if( p_playlist == NULL )
448 playlist_Move( p_playlist, i_moveRow, i_proposed_row );
450 vlc_object_release( p_playlist );
452 [self playlistUpdated];
459 NSPasteboard * o_pasteboard;
461 intf_thread_t * p_intf = [NSApp getIntf];
462 o_pasteboard = [o_info draggingPasteboard];
464 if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
466 o_values = [[o_pasteboard propertyListForType: NSFilenamesPboardType]
467 sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
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", "" );
474 [self appendArray: o_values atPos: i_proposed_row enqueue:YES];
481 [self updateRowSelection];