]> git.sesse.net Git - vlc/blob - modules/gui/macosx/playlist.m
- Repeat and loop are now mutually exclusive
[vlc] / modules / gui / macosx / playlist.m
1 /*****************************************************************************
2  * playlist.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2002-2004 VideoLAN
5  * $Id: playlist.m,v 1.59 2004/03/03 11:34:19 bigben Exp $
6  *
7  * Authors: Jon Lech Johansen <jon-vl@nanocrew.net>
8  *          Derk-Jan Hartman <hartman at videolan dot org>
9  *          Benjamin Pracht <bigben at videolab dot org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include <stdlib.h>                                      /* malloc(), free() */
30 #include <sys/param.h>                                    /* for MAXPATHLEN */
31 #include <string.h>
32 #include <math.h>
33 #include <sys/mount.h>
34 #include <vlc_keys.h>
35
36 #include "intf.h"
37 #include "playlist.h"
38 #include "controls.h"
39 #include <OSD.h>
40
41 /*****************************************************************************
42  * VLCPlaylistView implementation 
43  *****************************************************************************/
44 @implementation VLCPlaylistView
45
46 - (NSMenu *)menuForEvent:(NSEvent *)o_event
47 {
48     return( [[self delegate] menuForEvent: o_event] );
49 }
50
51 - (void)keyDown:(NSEvent *)o_event
52 {
53     unichar key = 0;
54     int i, c, i_row;
55     NSMutableArray *o_to_delete;
56     NSNumber *o_number;
57     
58     playlist_t * p_playlist;
59     intf_thread_t * p_intf = [NSApp getIntf];
60
61     if( [[o_event characters] length] )
62     {
63         key = [[o_event characters] characterAtIndex: 0];
64     }
65
66     p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
67                                           FIND_ANYWHERE );
68     
69     if ( p_playlist == NULL )
70     {
71         return;
72     }
73     
74     switch( key )
75     {
76         case NSDeleteCharacter:
77         case NSDeleteFunctionKey:
78         case NSDeleteCharFunctionKey:
79         case NSBackspaceCharacter:
80             o_to_delete = [NSMutableArray arrayWithArray:[[self selectedRowEnumerator] allObjects]];
81             c = [o_to_delete count];
82             
83             for( i = 0; i < c; i++ ) {
84                 o_number = [o_to_delete lastObject];
85                 i_row = [o_number intValue];
86                 
87                 if( p_playlist->i_index == i_row && p_playlist->i_status )
88                 {
89                     playlist_Stop( p_playlist );
90                 }
91                 [o_to_delete removeObject: o_number];
92                 [self deselectRow: i_row];
93                 playlist_Delete( p_playlist, i_row );
94             }
95             [self reloadData];
96             break;
97             
98         default:
99             [super keyDown: o_event];
100             break;
101     }
102
103     if( p_playlist != NULL )
104     {
105         vlc_object_release( p_playlist );
106     }
107 }
108
109
110 @end
111
112 /*****************************************************************************
113  * VLCPlaylist implementation 
114  *****************************************************************************/
115 @implementation VLCPlaylist
116
117 - (id)init
118 {
119     self = [super init];
120     if ( self !=nil )
121     {
122         i_moveRow = -1;
123     }
124     return self;
125 }
126
127 - (void)awakeFromNib
128 {
129     [o_table_view setTarget: self];
130     [o_table_view setDelegate: self];
131     [o_table_view setDataSource: self];
132
133     [o_table_view setDoubleAction: @selector(playItem:)];
134
135     [o_table_view registerForDraggedTypes: 
136         [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
137     [o_table_view setIntercellSpacing: NSMakeSize (0.0, 1.0)];
138     [o_window setExcludedFromWindowsMenu: TRUE];
139
140 /* We need to check whether _defaultTableHeaderSortImage exists, since it 
141 belongs to an Apple hidden private API, and then can "disapear" at any time*/
142
143     if( [[NSTableView class] respondsToSelector:@selector(_defaultTableHeaderSortImage)] )
144     {
145         o_ascendingSortingImage = [[NSTableView class] _defaultTableHeaderSortImage];
146     }
147     else
148     {
149         o_ascendingSortingImage = nil;
150     }
151
152     if( [[NSTableView class] respondsToSelector:@selector(_defaultTableHeaderReverseSortImage)] )
153     {
154         o_descendingSortingImage = [[NSTableView class] _defaultTableHeaderReverseSortImage];
155     }
156     else
157     {
158         o_descendingSortingImage = nil;
159     }
160
161     [self initStrings];
162     [self playlistUpdated];
163 }
164
165 - (void)initStrings
166 {
167     [o_window setTitle: _NS("Playlist")];
168     [o_mi_save_playlist setTitle: _NS("Save Playlist...")];
169     [o_mi_play setTitle: _NS("Play")];
170     [o_mi_delete setTitle: _NS("Delete")];
171     [o_mi_selectall setTitle: _NS("Select All")];
172     [[o_tc_name headerCell] setStringValue:_NS("Name")];
173     [[o_tc_author headerCell] setStringValue:_NS("Author")];
174     [[o_tc_duration headerCell] setStringValue:_NS("Duration")];
175     [o_random_ckb setTitle: _NS("Random")];
176     [o_search_button setTitle: _NS("Search")];
177     [o_btn_playlist setToolTip: _NS("Playlist")];
178     [[o_loop_popup itemAtIndex:0] setTitle: _NS("Standard Play")];
179     [[o_loop_popup itemAtIndex:1] setTitle: _NS("Repeat One")];
180     [[o_loop_popup itemAtIndex:2] setTitle: _NS("Repeat All")];
181 }
182
183 - (void) tableView:(NSTableView*)o_tv
184                   didClickTableColumn:(NSTableColumn *)o_tc
185 {
186     intf_thread_t * p_intf = [NSApp getIntf];
187     playlist_t *p_playlist =
188         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
189                                        FIND_ANYWHERE );
190
191     int max = [[o_table_view tableColumns] count];
192     int i;
193
194     if( p_playlist == NULL )
195     {
196         return;
197     }
198
199     if( o_tc_sortColumn == o_tc )
200     { 
201         b_isSortDescending = !b_isSortDescending;
202     }
203     else if( o_tc == o_tc_name || o_tc == o_tc_author || 
204         o_tc == o_tc_id )
205     {
206         b_isSortDescending = VLC_FALSE;
207         [o_table_view setHighlightedTableColumn:o_tc];
208         o_tc_sortColumn = o_tc;
209         for( i=0 ; i<max ; i++ )
210         {
211             [o_table_view setIndicatorImage:nil inTableColumn:[[o_table_view tableColumns] objectAtIndex:i]];
212         }
213     }
214
215     if( o_tc_id == o_tc && !b_isSortDescending )
216     {    
217         playlist_SortID( p_playlist , ORDER_NORMAL );
218         [o_table_view setIndicatorImage:o_ascendingSortingImage inTableColumn:o_tc];    
219     }
220     else if( o_tc_name == o_tc && !b_isSortDescending )
221     {    
222         playlist_SortTitle( p_playlist , ORDER_NORMAL );
223         [o_table_view setIndicatorImage:o_ascendingSortingImage inTableColumn:o_tc];    
224     }
225     else if( o_tc_author == o_tc && !b_isSortDescending )
226     {
227         playlist_SortAuthor( p_playlist , ORDER_NORMAL );
228         [o_table_view setIndicatorImage:o_ascendingSortingImage inTableColumn:o_tc];
229     }
230     else if( o_tc_id == o_tc && b_isSortDescending )
231     {    
232         playlist_SortID( p_playlist , ORDER_REVERSE );
233         [o_table_view setIndicatorImage:o_ascendingSortingImage inTableColumn:o_tc];    
234     }
235     else if( o_tc_name == o_tc && b_isSortDescending )
236     {    
237         playlist_SortTitle( p_playlist , ORDER_REVERSE );
238         [o_table_view setIndicatorImage:o_descendingSortingImage inTableColumn:o_tc];
239     }
240     else if( o_tc_author == o_tc && b_isSortDescending )
241     {
242         playlist_SortAuthor( p_playlist , ORDER_REVERSE );
243         [o_table_view setIndicatorImage:o_descendingSortingImage inTableColumn:o_tc];
244     } 
245     vlc_object_release( p_playlist );
246     [self playlistUpdated];
247 }
248
249
250 - (BOOL)tableView:(NSTableView *)o_tv 
251                   shouldEditTableColumn:(NSTableColumn *)o_tc
252                   row:(int)i_row
253 {
254     return( NO );
255 }
256
257 - (NSMenu *)menuForEvent:(NSEvent *)o_event
258 {
259     NSPoint pt;
260     vlc_bool_t b_rows;
261     vlc_bool_t b_item_sel;
262
263     pt = [o_table_view convertPoint: [o_event locationInWindow] 
264                                                  fromView: nil];
265     b_item_sel = ( [o_table_view rowAtPoint: pt] != -1 &&
266                    [o_table_view selectedRow] != -1 );
267     b_rows = [o_table_view numberOfRows] != 0;
268
269     [o_mi_play setEnabled: b_item_sel];
270     [o_mi_delete setEnabled: b_item_sel];
271     [o_mi_selectall setEnabled: b_rows];
272
273     return( o_ctx_menu );
274 }
275
276 - (IBAction)toggleWindow:(id)sender
277 {
278     if( [o_window isVisible] )
279     {
280         [o_window orderOut:sender];
281         [o_btn_playlist setState:NSOffState];
282     }
283     else
284     {
285         [o_window makeKeyAndOrderFront:sender];
286         [o_btn_playlist setState:NSOnState];
287     }
288 }
289
290 - (IBAction)savePlaylist:(id)sender
291 {
292     intf_thread_t * p_intf = [NSApp getIntf];
293     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
294                                                        FIND_ANYWHERE );
295     
296     NSSavePanel *o_save_panel = [NSSavePanel savePanel];
297     NSString * o_name = [NSString stringWithFormat: @"%@.m3u", _NS("Untitled")];
298     [o_save_panel setTitle: _NS("Save Playlist")];
299     [o_save_panel setPrompt: _NS("Save")];
300
301     if( [o_save_panel runModalForDirectory: nil
302             file: o_name] == NSOKButton )
303     {
304         playlist_Export( p_playlist, [[o_save_panel filename] fileSystemRepresentation], "export-m3u" );
305     }
306
307 }
308
309 - (IBAction)playItem:(id)sender
310 {
311     intf_thread_t * p_intf = [NSApp getIntf];
312     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
313                                                        FIND_ANYWHERE );
314
315     if( p_playlist != NULL )
316     {
317         playlist_Goto( p_playlist, [o_table_view selectedRow] );
318         vlc_object_release( p_playlist );
319     }
320 }
321
322 - (IBAction)deleteItems:(id)sender
323 {
324     int i, c, i_row;
325     NSMutableArray *o_to_delete;
326     NSNumber *o_number;
327
328     intf_thread_t * p_intf = [NSApp getIntf];
329     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
330                                                        FIND_ANYWHERE );
331
332     if( p_playlist == NULL )
333     {
334         return;
335     }
336     
337     o_to_delete = [NSMutableArray arrayWithArray:[[o_table_view selectedRowEnumerator] allObjects]];
338     c = (int)[o_to_delete count];
339     
340     for( i = 0; i < c; i++ ) {
341         o_number = [o_to_delete lastObject];
342         i_row = [o_number intValue];
343         
344         if( p_playlist->i_index == i_row && p_playlist->i_status )
345         {
346             playlist_Stop( p_playlist );
347         }
348         [o_to_delete removeObject: o_number];
349         [o_table_view deselectRow: i_row];
350         playlist_Delete( p_playlist, i_row );
351     }
352
353     vlc_object_release( p_playlist );
354
355     /* this is actually duplicity, because the intf.m manage also updates the view
356      * when the playlist changes. we do this on purpose, because else there is a 
357      * delay of .5 sec or so when we delete an item */
358     [self playlistUpdated];
359     [self updateRowSelection];
360 }
361
362 - (IBAction)selectAll:(id)sender
363 {
364     [o_table_view selectAll: nil];
365 }
366
367
368 - (IBAction)searchItem:(id)sender
369 {
370     int i_current = -1;
371     NSString *o_current_name;
372     NSString *o_current_author;
373
374     intf_thread_t * p_intf = [NSApp getIntf];
375     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
376                                                FIND_ANYWHERE );
377     
378     if( p_playlist == NULL )
379     {
380         return;
381     }
382     if( [o_table_view numberOfRows] < 1 )
383     {
384         return;
385     }
386
387     if( [o_table_view selectedRow] == [o_table_view numberOfRows]-1 )
388     {
389         i_current = -1;
390     }
391     else
392     {
393         i_current = [o_table_view selectedRow]; 
394     }
395
396     do
397     {
398         i_current++;
399
400         vlc_mutex_lock( &p_playlist->object_lock );
401         o_current_name = [NSString stringWithUTF8String: 
402             p_playlist->pp_items[i_current]->psz_name];
403         o_current_author = [NSString stringWithUTF8String: 
404             playlist_GetInfo(p_playlist, i_current ,_("General"),_("Author") )];
405         vlc_mutex_unlock( &p_playlist->object_lock );
406
407
408         if( [o_current_name rangeOfString:[o_search_keyword stringValue] options:NSCaseInsensitiveSearch ].length ||
409              [o_current_author rangeOfString:[o_search_keyword stringValue] options:NSCaseInsensitiveSearch ].length )
410         {
411              [o_table_view selectRow: i_current byExtendingSelection: NO];
412              [o_table_view scrollRowToVisible: i_current];
413              break;
414         }
415         if( i_current == [o_table_view numberOfRows] - 1 )
416         {
417              i_current = -1;
418         }
419     }
420     while (i_current != [o_table_view selectedRow]);
421     vlc_object_release( p_playlist );
422 }
423
424
425 - (IBAction)handlePopUp:(id)sender
426
427 {
428              intf_thread_t * p_intf = [NSApp getIntf];
429              vlc_value_t val1,val2;
430              playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
431                                                         FIND_ANYWHERE );
432              if( p_playlist == NULL )
433              {
434                  return;
435              }
436
437     switch ([o_loop_popup indexOfSelectedItem])
438     {
439         case 1:
440
441              val1.b_bool = 0;
442              var_Set( p_playlist, "loop", val1 );
443              val1.b_bool = 1;
444              var_Set( p_playlist, "repeat", val1 );
445              vout_OSDMessage( p_intf, _( "Repeat One" ) );
446         break;
447
448         case 2:
449              val1.b_bool = 0;
450              var_Set( p_playlist, "repeat", val1 );
451              val1.b_bool = 1;
452              var_Set( p_playlist, "loop", val1 );
453              vout_OSDMessage( p_intf, _( "Repeat All" ) );
454         break;
455
456         default:
457              var_Get( p_playlist, "repeat", &val1 );
458              var_Get( p_playlist, "loop", &val2 );
459              if (val1.b_bool || val2.b_bool)
460              {
461                   val1.b_bool = 0;
462                   var_Set( p_playlist, "repeat", val1 );
463                   var_Set( p_playlist, "loop", val1 );
464                   vout_OSDMessage( p_intf, _( "Repeat Off" ) );
465              }
466          break;
467      }
468      vlc_object_release( p_playlist );
469      [self playlistUpdated];
470 }
471
472
473 - (void)appendArray:(NSArray*)o_array atPos:(int)i_position enqueue:(BOOL)b_enqueue
474 {
475     int i_item;
476     intf_thread_t * p_intf = [NSApp getIntf];
477     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
478                                                        FIND_ANYWHERE );
479
480     if( p_playlist == NULL )
481     {
482         return;
483     }
484
485     for ( i_item = 0; i_item < (int)[o_array count]; i_item++ )
486     {
487         /* One item */
488         NSDictionary *o_one_item;
489         int j, i_total_options = 0, i_new_id = -1;
490         int i_mode = PLAYLIST_INSERT;
491         BOOL b_rem = FALSE, b_dir = FALSE;
492         NSString *o_uri, *o_name;
493         NSArray *o_options;
494         NSURL *o_true_file;
495         char **ppsz_options = NULL;
496     
497         /* Get the item */
498         o_one_item = [o_array objectAtIndex: i_item];
499         o_uri = (NSString *)[o_one_item objectForKey: @"ITEM_URL"];
500         o_name = (NSString *)[o_one_item objectForKey: @"ITEM_NAME"];
501         o_options = (NSArray *)[o_one_item objectForKey: @"ITEM_OPTIONS"];
502         
503         /* If no name, then make a guess */
504         if( !o_name) o_name = [[NSFileManager defaultManager] displayNameAtPath: o_uri];
505     
506         if( [[NSFileManager defaultManager] fileExistsAtPath:o_uri isDirectory:&b_dir] && b_dir &&
507             [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath: o_uri isRemovable: &b_rem
508                     isWritable:NULL isUnmountable:NULL description:NULL type:NULL] && b_rem   )
509         {
510             /* All of this is to make sure CD's play when you D&D them on VLC */
511             /* Converts mountpoint to a /dev file */
512             struct statfs *buf;
513             char *psz_dev;
514             buf = (struct statfs *) malloc (sizeof(struct statfs));
515             statfs( [o_uri fileSystemRepresentation], buf );
516             psz_dev = strdup(buf->f_mntfromname);
517             o_uri = [NSString stringWithCString: psz_dev ];
518         }
519
520         if( o_options && [o_options count] > 0 )
521         {
522             /* Count the input options */
523             i_total_options = [o_options count];
524     
525             /* Allocate ppsz_options */
526             for( j = 0; j < i_total_options; j++ )
527             {
528                 if( !ppsz_options )
529                     ppsz_options = (char **)malloc( sizeof(char *) * i_total_options );
530     
531                 ppsz_options[j] = strdup([[o_options objectAtIndex:j] UTF8String]);
532             }
533         }
534
535         /* Add the item */
536         i_new_id = playlist_AddExt( p_playlist, [o_uri fileSystemRepresentation], 
537                       [o_name UTF8String], i_mode, 
538                       i_position == -1 ? PLAYLIST_END : i_position + i_item,
539                       0, (ppsz_options != NULL ) ? (const char **)ppsz_options : 0, i_total_options );
540
541         /* clean up 
542         for( j = 0; j < i_total_options; j++ )
543             free( ppsz_options[j] );
544         if( ppsz_options ) free( ppsz_options ); */
545
546         /* Recent documents menu */
547         o_true_file = [NSURL fileURLWithPath: o_uri];
548         if( o_true_file != nil )
549         { 
550             [[NSDocumentController sharedDocumentController]
551                 noteNewRecentDocumentURL: o_true_file]; 
552         }
553         
554         if( i_item == 0 && !b_enqueue )
555         {
556             playlist_Goto( p_playlist, playlist_GetPositionById( p_playlist, i_new_id ) );
557             playlist_Play( p_playlist );
558         }
559     }
560
561     vlc_object_release( p_playlist );
562 }
563
564 - (void)playlistUpdated
565 {
566     vlc_value_t val1, val2;
567     intf_thread_t * p_intf = [NSApp getIntf];
568     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
569                                                        FIND_ANYWHERE );
570     if( p_playlist != NULL )
571     {
572         var_Get( p_playlist, "random", &val1 );
573         [o_random_ckb setState: val1.b_bool];
574
575         var_Get( p_playlist, "repeat", &val1 );
576         var_Get( p_playlist, "loop", &val2 );
577         if(val1.b_bool)
578         {
579             [o_loop_popup selectItemAtIndex:1];
580         }
581         else if(val2.b_bool)
582         {
583             [o_loop_popup selectItemAtIndex:2];
584         }
585         else
586         {
587             [o_loop_popup selectItemAtIndex:0];
588         }
589         vlc_object_release( p_playlist );
590     }
591     [o_table_view reloadData];
592 }
593
594 - (void)updateRowSelection
595 {
596     int i_row;
597
598     intf_thread_t * p_intf = [NSApp getIntf];
599     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
600                                                        FIND_ANYWHERE );
601
602     if( p_playlist == NULL )
603     {
604         return;
605     }
606
607     i_row = p_playlist->i_index;
608     vlc_object_release( p_playlist );
609
610     [o_table_view selectRow: i_row byExtendingSelection: NO];
611     [o_table_view scrollRowToVisible: i_row];
612 }
613
614
615 @end
616
617 @implementation VLCPlaylist (NSTableDataSource)
618
619 - (int)numberOfRowsInTableView:(NSTableView *)o_tv
620 {
621     int i_count = 0;
622     intf_thread_t * p_intf = [NSApp getIntf];
623     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
624                                                        FIND_ANYWHERE );
625
626     if( p_playlist != NULL )
627     {
628         vlc_mutex_lock( &p_playlist->object_lock );
629         i_count = p_playlist->i_size;
630         vlc_mutex_unlock( &p_playlist->object_lock );
631         vlc_object_release( p_playlist );
632     }
633     [o_status_field setStringValue: [NSString stringWithFormat:_NS("%i items in playlist"), i_count]];
634     return( i_count );
635 }
636
637 - (id)tableView:(NSTableView *)o_tv 
638                 objectValueForTableColumn:(NSTableColumn *)o_tc 
639                 row:(int)i_row
640 {
641     id o_value = nil;
642     intf_thread_t * p_intf = [NSApp getIntf];
643     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
644                                                FIND_ANYWHERE );
645
646     if( p_playlist == NULL )
647     {
648         return( nil );
649     }
650
651     if( [[o_tc identifier] isEqualToString:@"0"] )
652     {
653         o_value = [NSString stringWithFormat:@"%i", i_row + 1];
654     }
655     else if( [[o_tc identifier] isEqualToString:@"1"] )
656     {
657         vlc_mutex_lock( &p_playlist->object_lock );
658         o_value = [NSString stringWithUTF8String: 
659             p_playlist->pp_items[i_row]->psz_name];
660         vlc_mutex_unlock( &p_playlist->object_lock );
661     }
662     else if( [[o_tc identifier] isEqualToString:@"2"] )
663     {
664         vlc_mutex_lock( &p_playlist->object_lock );
665         o_value = [NSString stringWithUTF8String: 
666             playlist_GetInfo(p_playlist, i_row ,_("General"),_("Author") )];
667         vlc_mutex_unlock( &p_playlist->object_lock );
668     }
669     else if( [[o_tc identifier] isEqualToString:@"3"] )
670     {
671         char psz_duration[MSTRTIME_MAX_SIZE];
672         mtime_t dur = p_playlist->pp_items[i_row]->i_duration;
673         if( dur != -1 )
674         {
675             secstotimestr( psz_duration, dur/1000000 );
676             o_value = [NSString stringWithUTF8String: psz_duration];
677         }
678         else
679         {
680             o_value = @"-:--:--";
681         }
682     }
683
684     vlc_object_release( p_playlist );
685
686     return( o_value );
687 }
688
689 - (void)tableView:(NSTableView *)o_tv
690                     willDisplayCell:(id)o_cell
691                     forTableColumn:(NSTableColumn *)o_tc
692                     row:(int)o_rows
693 {
694     intf_thread_t * p_intf = [NSApp getIntf];
695     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
696                                                FIND_ANYWHERE );
697     if ((p_playlist->i_groups) > 1 )
698     {
699        [o_cell setDrawsBackground: VLC_TRUE];
700        switch ( p_playlist->pp_items[o_rows]->i_group % 8 )
701        {
702             case 1:
703               /*white*/
704               [o_cell setBackgroundColor: [NSColor colorWithDeviceRed:1.0 green:1.0 blue:1.0 alpha:1.0]];
705               break;
706
707             case 2:
708               /*red*/
709              [o_cell setBackgroundColor: [NSColor colorWithDeviceRed:1.0 green:0.76471 blue:0.76471 alpha:1.0]];
710             break;
711
712             case 3:
713               /*dark blue*/
714                    [o_cell setBackgroundColor: [NSColor colorWithDeviceRed:0.76471 green:0.76471 blue:1.0 alpha:1.0]];
715             break; 
716
717             case 4:
718                /*orange*/
719                    [o_cell setBackgroundColor: [NSColor colorWithDeviceRed:1.0 green:0.89804 blue:0.76471 alpha:1.0]];
720             break;
721
722             case 5:
723                 /*purple*/
724                    [o_cell setBackgroundColor: [NSColor colorWithDeviceRed:1.0 green:0.76471 blue:1.0 alpha:1.0]];
725             break;
726  
727             case 6:
728                 /*green*/
729                    [o_cell setBackgroundColor: [NSColor colorWithDeviceRed:0.76471 green:1.0 blue:0.76471 alpha:1.0]];
730             break; 
731
732             case 7:
733                /*light blue*/
734                    [o_cell setBackgroundColor: [NSColor colorWithDeviceRed:0.76471 green:1.0 blue:1.0 alpha:1.0]];
735             break;
736
737             case 0:
738                /*yellow*/
739                    [o_cell setBackgroundColor: [NSColor colorWithDeviceRed:1.0 green:1.0 blue:0.76471 alpha:1.0]];
740             break;
741         }
742      
743     }
744 vlc_object_release( p_playlist );
745 }
746
747 - (BOOL)tableView:(NSTableView *)o_tv
748                     writeRows:(NSArray*)o_rows
749                     toPasteboard:(NSPasteboard*)o_pasteboard 
750 {
751     int i_rows = [o_rows count];
752     NSArray *o_filenames = [NSArray array];
753     
754     [o_pasteboard declareTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:self];
755     [o_pasteboard setPropertyList:o_filenames forType:NSFilenamesPboardType];
756     if ( i_rows == 1 )
757     {
758         i_moveRow = [[o_rows objectAtIndex:0]intValue];
759         return YES;
760     }
761     return NO;
762 }
763
764 - (NSDragOperation)tableView:(NSTableView*)o_tv
765                     validateDrop:(id <NSDraggingInfo>)o_info
766                     proposedRow:(int)i_row
767                     proposedDropOperation:(NSTableViewDropOperation)o_operation 
768 {
769     if ( o_operation == NSTableViewDropAbove )
770     {
771         if ( i_moveRow >= 0 )
772         {
773             if ( i_row != i_moveRow )
774             {
775                 return NSDragOperationMove;
776             }
777             /* what if in the previous run, the row wasn't actually moved? 
778                then we can't drop new files on this location */
779             return NSDragOperationNone;
780         }
781         return NSDragOperationGeneric;
782     }
783     return NSDragOperationNone;
784 }
785
786 - (BOOL)tableView:(NSTableView*)o_tv
787                     acceptDrop:(id <NSDraggingInfo>)o_info
788                     row:(int)i_proposed_row
789                     dropOperation:(NSTableViewDropOperation)o_operation 
790 {
791     if (  i_moveRow >= 0 )
792     {
793         if (i_moveRow != -1 && i_proposed_row != -1)
794         {
795             intf_thread_t * p_intf = [NSApp getIntf];
796             playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
797                                                             FIND_ANYWHERE );
798         
799             if( p_playlist == NULL )
800             {
801                 i_moveRow = -1;
802                 return NO;
803             }
804     
805             playlist_Move( p_playlist, i_moveRow, i_proposed_row ); 
806         
807             vlc_object_release( p_playlist );
808         }
809         [self playlistUpdated];
810         i_moveRow = -1;
811         return YES;
812     }
813     else
814     {
815         NSPasteboard * o_pasteboard;
816         o_pasteboard = [o_info draggingPasteboard];
817         
818         if( [[o_pasteboard types] containsObject: NSFilenamesPboardType] )
819         {
820             int i;
821             NSArray *o_array = [NSArray array];
822             NSArray *o_values = [[o_pasteboard propertyListForType: NSFilenamesPboardType]
823                         sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
824
825             for( i = 0; i < (int)[o_values count]; i++)
826             {
827                 NSDictionary *o_dic;
828                 o_dic = [NSDictionary dictionaryWithObject:[o_values objectAtIndex:i] forKey:@"ITEM_URL"];
829                 o_array = [o_array arrayByAddingObject: o_dic];
830             }
831             [self appendArray: o_array atPos: i_proposed_row enqueue:YES];
832             return YES;
833         }
834         return NO;
835     }
836     [self updateRowSelection];
837 }
838
839 /* Delegate method of NSWindow */
840 - (void)windowWillClose:(NSNotification *)aNotification
841 {
842     [o_btn_playlist setState: NSOffState];
843 }
844
845 @end
846