1 /*****************************************************************************
2 * playlist.m: MacOS X interface plugin
3 *****************************************************************************
4 * Copyright (C) 2002-2003 VideoLAN
5 * $Id: playlist.m,v 1.15 2003/03/17 17:10:21 hartman Exp $
7 * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8 * Derk-Jan Hartman <thedj@users.sourceforge.net>
9 * Thanks: Andrew Stone for documenting the row reordering methods on the net
10 * http://www.omnigroup.com/mailman/archive/macosx-dev/
11 * 2001-January/008195.html
12 * Apple Computer for documenting the Alternating row colors
13 * http://developer.apple.com/samplecode/Sample_Code/Cocoa/
14 * MP3_Player/MyTableView.m.htm
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
29 *****************************************************************************/
31 /*****************************************************************************
33 *****************************************************************************/
34 #include <stdlib.h> /* malloc(), free() */
35 #include <sys/param.h> /* for MAXPATHLEN */
41 // RGB values for stripe color (light blue)
42 #define STRIPE_RED (237.0 / 255.0)
43 #define STRIPE_GREEN (243.0 / 255.0)
44 #define STRIPE_BLUE (254.0 / 255.0)
45 static NSColor *sStripeColor = nil;
47 /*****************************************************************************
48 * VLCPlaylistView implementation
49 *****************************************************************************/
50 @implementation VLCPlaylistView
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 );
118 /* This is called after the table background is filled in, but before the cell contents are drawn.
119 * We override it so we can do our own light-blue row stripes a la iTunes.
121 - (void) highlightSelectionInClipRect:(NSRect)rect {
122 [self drawStripesInRect:rect];
123 [super highlightSelectionInClipRect:rect];
126 /* This routine does the actual blue stripe drawing, filling in every other row of the table
127 * with a blue background so you can follow the rows easier with your eyes.
129 - (void) drawStripesInRect:(NSRect)clipRect {
131 float fullRowHeight = [self rowHeight] + [self intercellSpacing].height;
132 float clipBottom = NSMaxY(clipRect);
133 int firstStripe = clipRect.origin.y / fullRowHeight;
134 if (firstStripe % 2 == 0)
135 firstStripe++; // we're only interested in drawing the stripes
137 stripeRect.origin.x = clipRect.origin.x;
138 stripeRect.origin.y = firstStripe * fullRowHeight;
139 stripeRect.size.width = clipRect.size.width;
140 stripeRect.size.height = fullRowHeight;
142 if (sStripeColor == nil)
143 sStripeColor = [[NSColor colorWithCalibratedRed:STRIPE_RED green:STRIPE_GREEN blue:STRIPE_BLUE alpha:1.0] retain];
145 // and draw the stripes
146 while (stripeRect.origin.y < clipBottom) {
147 NSRectFill(stripeRect);
148 stripeRect.origin.y += fullRowHeight * 2.0;
154 /*****************************************************************************
155 * VLCPlaylist implementation
156 *****************************************************************************/
157 @implementation VLCPlaylist
161 [o_table_view setTarget: self];
162 [o_table_view setDelegate: self];
163 [o_table_view setDataSource: self];
165 [o_table_view setDoubleAction: @selector(playItem:)];
167 [o_table_view registerForDraggedTypes:
168 [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
170 [o_mi_play setTitle: _NS("Play")];
171 [o_mi_delete setTitle: _NS("Delete")];
172 [o_mi_selectall setTitle: _NS("Select All")];
174 [o_btn_add setToolTip: _NS("Add")];
175 [o_btn_remove setToolTip: _NS("Delete")];
178 - (BOOL)tableView:(NSTableView *)o_tv
179 shouldEditTableColumn:(NSTableColumn *)o_tc
185 - (NSMenu *)menuForEvent:(NSEvent *)o_event
189 vlc_bool_t b_item_sel;
191 pt = [o_table_view convertPoint: [o_event locationInWindow]
193 b_item_sel = ( [o_table_view rowAtPoint: pt] != -1 &&
194 [o_table_view selectedRow] != -1 );
195 b_rows = [o_table_view numberOfRows] != 0;
197 [o_mi_play setEnabled: b_item_sel];
198 [o_mi_delete setEnabled: b_item_sel];
199 [o_mi_selectall setEnabled: b_rows];
201 return( o_ctx_menu );
204 - (IBAction)playItem:(id)sender
206 intf_thread_t * p_intf = [NSApp getIntf];
207 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
210 if( p_playlist == NULL )
215 playlist_Goto( p_playlist, [o_table_view selectedRow] );
217 vlc_object_release( p_playlist );
220 - (IBAction)deleteItems:(id)sender
224 intf_thread_t * p_intf = [NSApp getIntf];
225 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
228 if( p_playlist == NULL )
233 while( ( i_row = [o_table_view selectedRow] ) != -1 )
235 if( p_playlist->i_index == i_row && p_playlist->i_status )
237 playlist_Stop( p_playlist );
240 playlist_Delete( p_playlist, i_row );
242 [o_table_view deselectRow: i_row];
245 vlc_object_release( p_playlist );
247 /* this is actually duplicity, because the intf.m manage also updates the view
248 * when the playlist changes. we do this on purpose, because else there is a
249 * delay of .5 sec or so when we delete an item */
250 [self playlistUpdated];
253 - (IBAction)selectAll:(id)sender
255 [o_table_view selectAll: nil];
258 - (void)appendArray:(NSArray*)o_array atPos:(int)i_pos enqueue:(BOOL)b_enqueue
262 NSEnumerator * o_enum;
263 intf_thread_t * p_intf = [NSApp getIntf];
264 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
267 if( p_playlist == NULL )
273 o_enum = [o_array objectEnumerator];
274 while( ( o_value = [o_enum nextObject] ) )
278 int i_mode = PLAYLIST_INSERT;
280 if (i_items == 0 && !b_enqueue)
281 i_mode |= PLAYLIST_GO;
283 playlist_Add( p_playlist, [o_value fileSystemRepresentation],
284 i_mode, i_pos == -1 ? PLAYLIST_END : i_pos + i_items );
286 o_url = [NSURL fileURLWithPath: o_value];
289 [[NSDocumentController sharedDocumentController]
290 noteNewRecentDocumentURL: o_url];
296 vlc_object_release( p_playlist );
299 - (void)playlistUpdated
301 [o_table_view reloadData];
304 - (void)updateRowSelection
308 intf_thread_t * p_intf = [NSApp getIntf];
309 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
312 if( p_playlist == NULL )
317 vlc_mutex_lock( &p_playlist->object_lock );
318 i_row = p_playlist->i_index;
319 vlc_mutex_unlock( &p_playlist->object_lock );
320 vlc_object_release( p_playlist );
322 [o_table_view selectRow: i_row byExtendingSelection: NO];
323 [o_table_view scrollRowToVisible: i_row];
328 @implementation VLCPlaylist (NSTableDataSource)
330 - (int)numberOfRowsInTableView:(NSTableView *)o_tv
333 intf_thread_t * p_intf = [NSApp getIntf];
334 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
337 if( p_playlist != NULL )
339 vlc_mutex_lock( &p_playlist->object_lock );
340 i_count = p_playlist->i_size;
341 vlc_mutex_unlock( &p_playlist->object_lock );
342 vlc_object_release( p_playlist );
348 - (id)tableView:(NSTableView *)o_tv
349 objectValueForTableColumn:(NSTableColumn *)o_tc
353 intf_thread_t * p_intf = [NSApp getIntf];
354 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
357 if( p_playlist == NULL )
362 vlc_mutex_lock( &p_playlist->object_lock );
363 o_value = [[NSString stringWithUTF8String:
364 p_playlist->pp_items[i_row]->psz_name] lastPathComponent];
365 vlc_mutex_unlock( &p_playlist->object_lock );
367 vlc_object_release( p_playlist );
372 // NEW API for Dragging in TableView:
373 // typedef enum { NSTableViewDropOn, NSTableViewDropAbove } NSTableViewDropOperation;
374 // In drag and drop, used to specify a dropOperation. For example, given a table with N rows (numbered with row 0 at the top visually), a row of N-1 and operation of NSTableViewDropOn would specify a drop on the last row. To specify a drop below the last row, one would use a row of N and NSTableViewDropAbove for the operation.
376 static int _moveRow = -1;
378 - (BOOL)tableView:(NSTableView *)tv
379 writeRows:(NSArray*)rows
380 toPasteboard:(NSPasteboard*)pboard
381 // This method is called after it has been determined that a drag should begin, but before the drag has been started. To refuse the drag, return NO. To start a drag, return YES and place the drag data onto the pasteboard (data, owner, etc...). The drag image and other drag related information will be set up and provided by the table view once this call returns with YES. The rows array is the list of row numbers that will be participating in the drag.
383 int rowCount = [rows count];
384 NSArray *o_filenames = [NSArray array];
386 // we should allow group selection and copy between windows: PENDING
387 [pboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:self];
388 [pboard setPropertyList:o_filenames forType:NSFilenamesPboardType];
391 _moveRow = [[rows objectAtIndex:0]intValue];
397 - (NSDragOperation)tableView:(NSTableView*)tv
398 validateDrop:(id <NSDraggingInfo>)info
400 proposedDropOperation:(NSTableViewDropOperation)op
401 // This method is used by NSTableView to determine a valid drop target. Based on the mouse position, the table view will suggest a proposed drop location. This method must return a value that indicates which dragging operation the data source will perform. The data source may "re-target" a drop if desired by calling setDropRow:dropOperation: and returning something other than NSDragOperationNone. One may choose to re-target for various reasons (eg. for better visual feedback when inserting into a sorted position).
403 if ( op == NSTableViewDropAbove )
405 if ( row != _moveRow && _moveRow >= 0 )
407 return NSDragOperationMove;
409 return NSDragOperationLink;
411 return NSDragOperationNone;
414 - (BOOL)tableView:(NSTableView*)tv
415 acceptDrop:(id <NSDraggingInfo>)info
417 dropOperation:(NSTableViewDropOperation)op
418 // This method is called when the mouse is released over an outline view that previously decided to allow a drop via the validateDrop method. The data source should incorporate the data from the dragging pasteboard at this time.
422 BOOL result = [self tableView:tv didDepositRow:_moveRow at:(int)i_row];
423 [self playlistUpdated];
430 NSPasteboard * o_pasteboard;
432 o_pasteboard = [info draggingPasteboard];
434 if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
436 o_values = [o_pasteboard propertyListForType: NSFilenamesPboardType];
438 [self appendArray: o_values atPos: i_row enqueue:YES];
447 - (BOOL)tableView:(NSTableView *)tv didDepositRow:(int)i_row at:(int)i_newrow
449 if (i_row != -1 && i_newrow != -1)
451 intf_thread_t * p_intf = [NSApp getIntf];
452 playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
455 if( p_playlist == NULL )
460 playlist_Move( p_playlist, i_row, i_newrow );
462 vlc_object_release( p_playlist );