]> git.sesse.net Git - vlc/blob - modules/gui/macosx/playlist.m
* deleteItem: method
[vlc] / modules / gui / macosx / playlist.m
1 /*****************************************************************************
2  * playlist.m: MacOS X interface module
3  *****************************************************************************
4  * Copyright (C) 2002-2004 VideoLAN
5  * $Id$
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 /* TODO
27  * connect delegates, actions and outlets in IB
28  * implement delete by backspace
29  * implement playlist item rightclick menu
30  * implement sorting
31  * add 'icons' for different types of nodes? (http://www.cocoadev.com/index.pl?IconAndTextInTableCell)
32  * create a new 'playlist toggle' that hides the playlist and in effect give you the old controller
33  * create a new search field build with pictures from the 'regular' search field, so it can be emulated on 10.2
34  * create toggle buttons for the shuffle, repeat one, repeat all functions.
35  * implement drag and drop and item reordering.
36  * reimplement enable/disable item
37  * create a new 'tool' button (see the gear button in the Finder window) for 'actions'
38    (adding service discovery, other views, new node/playlist, save node/playlist) stuff like that
39  */
40
41
42
43 /*****************************************************************************
44  * Preamble
45  *****************************************************************************/
46 #include <stdlib.h>                                      /* malloc(), free() */
47 #include <sys/param.h>                                    /* for MAXPATHLEN */
48 #include <string.h>
49 #include <math.h>
50 #include <sys/mount.h>
51 #include <vlc_keys.h>
52
53 #include "intf.h"
54 #include "playlist.h"
55 #include "controls.h"
56 #include <OSD.h>
57
58 /*****************************************************************************
59  * VLCPlaylistView implementation 
60  *****************************************************************************/
61 @implementation VLCPlaylistView
62
63 - (NSMenu *)menuForEvent:(NSEvent *)o_event
64 {
65     return( [[self delegate] menuForEvent: o_event] );
66 }
67
68 - (void)keyDown:(NSEvent *)o_event
69 {
70     unichar key = 0;
71
72     if( [[o_event characters] length] )
73     {
74         key = [[o_event characters] characterAtIndex: 0];
75     }
76
77     switch( key )
78     {
79         case NSDeleteCharacter:
80         case NSDeleteFunctionKey:
81         case NSDeleteCharFunctionKey:
82         case NSBackspaceCharacter:
83             [[self delegate] deleteItem:self];
84             break;
85
86         default:
87             [super keyDown: o_event];
88             break;
89     }
90 }
91
92 @end
93
94 /*****************************************************************************
95  * VLCPlaylist implementation 
96  *****************************************************************************/
97 @implementation VLCPlaylist
98
99 - (id)init
100 {
101     self = [super init];
102     if ( self !=nil )
103     {
104         //i_moveRow = -1;
105     }
106     return self;
107 }
108
109 - (void)awakeFromNib
110 {
111     [o_outline_view setTarget: self];
112     [o_outline_view setDelegate: self];
113     [o_outline_view setDataSource: self];
114
115     [o_outline_view setDoubleAction: @selector(playItem:)];
116
117     [o_outline_view registerForDraggedTypes: 
118         [NSArray arrayWithObjects: NSFilenamesPboardType, nil]];
119     [o_outline_view setIntercellSpacing: NSMakeSize (0.0, 1.0)];
120
121 /* We need to check whether _defaultTableHeaderSortImage exists, since it 
122 belongs to an Apple hidden private API, and then can "disapear" at any time*/
123
124     if( [[NSOutlineView class] respondsToSelector:@selector(_defaultTableHeaderSortImage)] )
125     {
126         o_ascendingSortingImage = [[NSOutlineView class] _defaultTableHeaderSortImage];
127     }
128     else
129     {
130         o_ascendingSortingImage = nil;
131     }
132
133     if( [[NSOutlineView class] respondsToSelector:@selector(_defaultTableHeaderReverseSortImage)] )
134     {
135         o_descendingSortingImage = [[NSOutlineView class] _defaultTableHeaderReverseSortImage];
136     }
137     else
138     {
139         o_descendingSortingImage = nil;
140     }
141
142     o_outline_dict = [[NSMutableDictionary alloc] init];
143
144     [self initStrings];
145     //[self playlistUpdated];
146 }
147
148 - (void)initStrings
149 {
150     [o_mi_save_playlist setTitle: _NS("Save Playlist...")];
151     [o_mi_play setTitle: _NS("Play")];
152     [o_mi_delete setTitle: _NS("Delete")];
153     [o_mi_selectall setTitle: _NS("Select All")];
154     [o_mi_info setTitle: _NS("Properties")];
155     [[o_tc_name headerCell] setStringValue:_NS("Name")];
156     [[o_tc_author headerCell] setStringValue:_NS("Author")];
157     [[o_tc_duration headerCell] setStringValue:_NS("Duration")];
158     [o_status_field setStringValue: [NSString stringWithFormat:
159                         _NS("0 items in playlist")]];
160
161     [o_random_ckb setTitle: _NS("Random")];
162 #if 0
163     [o_search_button setTitle: _NS("Search")];
164 #endif
165     [o_btn_playlist setToolTip: _NS("Playlist")];
166     [[o_loop_popup itemAtIndex:0] setTitle: _NS("Standard Play")];
167     [[o_loop_popup itemAtIndex:1] setTitle: _NS("Repeat One")];
168     [[o_loop_popup itemAtIndex:2] setTitle: _NS("Repeat All")];
169 }
170
171 - (void)playlistUpdated
172 {
173     [o_outline_dict removeAllObjects];
174     [o_outline_view reloadData];
175 }
176
177 - (bool)isItem:(playlist_item_t *)p_item inNode:(playlist_item_t *)p_node
178 {
179     playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
180                                           FIND_ANYWHERE );
181     playlist_item_t * p_temp_item = p_item;
182
183     if ( p_playlist == NULL )
184     {
185         return NO;
186     }
187
188     while ( p_temp_item->i_parents > 0 )
189     {
190         int i;
191         for (i = 0; i < p_temp_item->i_parents ; i++)
192         {
193             if (p_temp_item->pp_parents[i]->i_view == VIEW_SIMPLE)
194             {
195                 if (p_temp_item->pp_parents[i]->p_parent == p_node)
196                 {
197                     vlc_object_release(p_playlist);
198                     return YES;
199                 }
200                 else
201                 {
202                     p_temp_item = p_temp_item->pp_parents[i]->p_parent;
203                     break;
204                 }
205             }
206         }
207     }
208
209     vlc_object_release(p_playlist);
210     return NO;
211 }
212
213
214 - (IBAction)playItem:(id)sender
215 {
216     intf_thread_t * p_intf = VLCIntf;
217     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
218                                                        FIND_ANYWHERE );
219
220     if( p_playlist != NULL )
221     {
222         playlist_item_t *p_item;
223         playlist_item_t *p_node = NULL;
224         int i;
225
226         p_item = [[o_outline_view itemAtRow:[o_outline_view selectedRow]] pointerValue];
227
228         if( p_item )
229         {
230             if (p_item->i_children == -1)
231             {
232                 for (i = 0 ; i < p_item->i_parents ; i++)
233                 {
234                     if (p_item->pp_parents[i]->i_view == VIEW_SIMPLE)
235                     {
236                         p_node = p_item->pp_parents[i]->p_parent;
237                     }
238                 }
239             }
240             else
241             {
242                 p_node = p_item;
243                 if (p_node->pp_children[0]->i_children == -1 &&
244                     p_node->i_children > 0)
245                 {
246                     p_item = p_node->pp_children[0];
247                 }
248                 else
249                 {
250                     p_item = NULL;
251                 }
252             }
253
254 //        p_view = playlist_ViewFind( p_playlist, VIEW_SIMPLE );
255
256
257             playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, VIEW_SIMPLE, p_node, p_item );
258 //            playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, VIEW_SIMPLE, p_view ? p_view->p_root : NULL, p_item );
259         }
260         vlc_object_release( p_playlist );
261     }
262 }
263
264 - (IBAction)selectAll:(id)sender
265 {
266     [o_outline_view selectAll: nil];
267 }
268
269 - (IBAction)deleteItem:(id)sender
270 {
271     int i, c, i_row;
272     NSMutableArray *o_to_delete;
273     NSNumber *o_number;
274
275     playlist_t * p_playlist;
276     intf_thread_t * p_intf = VLCIntf;
277
278     p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
279                                           FIND_ANYWHERE );
280
281     if ( p_playlist == NULL )
282     {
283         return;
284     }
285     o_to_delete = [NSMutableArray arrayWithArray:[[o_outline_view selectedRowEnumerator] allObjects]];
286     c = [o_to_delete count];
287
288     for( i = 0; i < c; i++ ) {
289         playlist_item_t * p_item;
290         o_number = [o_to_delete lastObject];
291         i_row = [o_number intValue];
292
293         [o_to_delete removeObject: o_number];
294         [o_outline_view deselectRow: i_row];
295         p_item = (playlist_item_t *)[[o_outline_view itemAtRow: i_row]pointerValue];
296         if (p_item->i_children > -1)
297         {
298             if (p_playlist->status.i_status)
299             {
300                 if ([self isItem:p_playlist->status.p_item inNode: p_item]
301                                     == YES && p_playlist->status.i_status)
302                 {
303                     playlist_Stop( p_playlist );
304                 }
305             }
306             playlist_NodeDelete( p_playlist, p_item, VLC_TRUE);
307         }
308         else
309         {
310             if( p_playlist->status.p_item == [[o_outline_view itemAtRow: i_row]
311                         pointerValue] && p_playlist->status.i_status )
312             {
313                 playlist_Stop( p_playlist );
314             }
315             playlist_Delete( p_playlist, p_item->input.i_id );
316         }
317         [self playlistUpdated];
318     }
319 }
320
321 - (void)appendArray:(NSArray*)o_array atPos:(int)i_position enqueue:(BOOL)b_enqueue
322 {
323     int i_item;
324     intf_thread_t * p_intf = VLCIntf;
325     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
326                                                        FIND_ANYWHERE );
327
328     if( p_playlist == NULL )
329     {
330         return;
331     }
332
333     for ( i_item = 0; i_item < (int)[o_array count]; i_item++ )
334     {
335         /* One item */
336         NSDictionary *o_one_item;
337         int j, i_total_options = 0, i_new_id = -1;
338         int i_mode = PLAYLIST_INSERT;
339         BOOL b_rem = FALSE, b_dir = FALSE;
340         NSString *o_uri, *o_name;
341         NSArray *o_options;
342         NSURL *o_true_file;
343         char **ppsz_options = NULL;
344
345         /* Get the item */
346         o_one_item = [o_array objectAtIndex: i_item];
347         o_uri = (NSString *)[o_one_item objectForKey: @"ITEM_URL"];
348         o_name = (NSString *)[o_one_item objectForKey: @"ITEM_NAME"];
349         o_options = (NSArray *)[o_one_item objectForKey: @"ITEM_OPTIONS"];
350
351         /* If no name, then make a guess */
352         if( !o_name) o_name = [[NSFileManager defaultManager] displayNameAtPath: o_uri];
353
354         if( [[NSFileManager defaultManager] fileExistsAtPath:o_uri isDirectory:&b_dir] && b_dir &&
355             [[NSWorkspace sharedWorkspace] getFileSystemInfoForPath: o_uri isRemovable: &b_rem
356                     isWritable:NULL isUnmountable:NULL description:NULL type:NULL] && b_rem   )
357         {
358             /* All of this is to make sure CD's play when you D&D them on VLC */
359             /* Converts mountpoint to a /dev file */
360             struct statfs *buf;
361             char *psz_dev;
362             buf = (struct statfs *) malloc (sizeof(struct statfs));
363             statfs( [o_uri fileSystemRepresentation], buf );
364             psz_dev = strdup(buf->f_mntfromname);
365             o_uri = [NSString stringWithCString: psz_dev ];
366         }
367
368         if( o_options && [o_options count] > 0 )
369         {
370             /* Count the input options */
371             i_total_options = [o_options count];
372
373             /* Allocate ppsz_options */
374             for( j = 0; j < i_total_options; j++ )
375             {
376                 if( !ppsz_options )
377                     ppsz_options = (char **)malloc( sizeof(char *) * i_total_options );
378
379                 ppsz_options[j] = strdup([[o_options objectAtIndex:j] UTF8String]);
380             }
381         }
382
383         /* Add the item */
384         i_new_id = playlist_AddExt( p_playlist, [o_uri fileSystemRepresentation],
385                       [o_name UTF8String], i_mode,
386                       i_position == -1 ? PLAYLIST_END : i_position + i_item,
387                       0, (ppsz_options != NULL ) ? (const char **)ppsz_options : 0, i_total_options );
388
389         /* clean up
390         for( j = 0; j < i_total_options; j++ )
391             free( ppsz_options[j] );
392         if( ppsz_options ) free( ppsz_options ); */
393
394         /* Recent documents menu */
395         o_true_file = [NSURL fileURLWithPath: o_uri];
396         if( o_true_file != nil )
397         {
398             [[NSDocumentController sharedDocumentController]
399                 noteNewRecentDocumentURL: o_true_file];
400         }
401
402         if( i_item == 0 && !b_enqueue )
403         {
404             playlist_Goto( p_playlist, playlist_GetPositionById( p_playlist, i_new_id ) );
405             playlist_Play( p_playlist );
406         }
407     }
408
409     vlc_object_release( p_playlist );
410 }
411
412 - (IBAction)handlePopUp:(id)sender
413
414 {
415              intf_thread_t * p_intf = VLCIntf;
416              vlc_value_t val1,val2;
417              playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
418                                                         FIND_ANYWHERE );
419              if( p_playlist == NULL )
420              {
421                  return;
422              }
423
424     switch ([o_loop_popup indexOfSelectedItem])
425     {
426         case 1:
427
428              val1.b_bool = 0;
429              var_Set( p_playlist, "loop", val1 );
430              val1.b_bool = 1;
431              var_Set( p_playlist, "repeat", val1 );
432              vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Repeat One" ) );
433         break;
434
435         case 2:
436              val1.b_bool = 0;
437              var_Set( p_playlist, "repeat", val1 );
438              val1.b_bool = 1;
439              var_Set( p_playlist, "loop", val1 );
440              vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Repeat All" ) );
441         break;
442
443         default:
444              var_Get( p_playlist, "repeat", &val1 );
445              var_Get( p_playlist, "loop", &val2 );
446              if (val1.b_bool || val2.b_bool)
447              {
448                   val1.b_bool = 0;
449                   var_Set( p_playlist, "repeat", val1 );
450                   var_Set( p_playlist, "loop", val1 );
451                   vout_OSDMessage( p_intf, DEFAULT_CHAN, _( "Repeat Off" ) );
452              }
453          break;
454      }
455      vlc_object_release( p_playlist );
456      [self playlistUpdated];
457 }
458
459 - (NSMutableArray *)subSearchItem:(playlist_item_t *)p_item
460 {
461     playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
462                                                        FIND_ANYWHERE );
463     playlist_item_t * p_selected_item;
464     int i_current, i_selected_row;
465
466     if (!p_playlist)
467         return NULL;
468
469     i_selected_row = [o_outline_view selectedRow];
470     if (i_selected_row < 0)
471         i_selected_row = 0;
472
473     p_selected_item = (playlist_item_t *)[[o_outline_view itemAtRow:
474                                             i_selected_row] pointerValue];
475
476     for (i_current = 0; i_current < p_item->i_children ; i_current++)
477     {
478         char * psz_temp;
479         NSString * o_current_name, * o_current_author;
480
481         vlc_mutex_lock( &p_playlist->object_lock );
482         o_current_name = [NSString stringWithUTF8String:
483             p_item->pp_children[i_current]->input.psz_name];
484         psz_temp = playlist_ItemGetInfo(p_item ,_("Meta-information"),_("Author") );
485         o_current_author = [NSString stringWithUTF8String: psz_temp];
486         free( psz_temp);
487         vlc_mutex_unlock( &p_playlist->object_lock );
488
489         if (p_selected_item == p_item->pp_children[i_current] &&
490                     b_selected_item_met == NO)
491         {
492             b_selected_item_met = YES;
493         }
494         else if (p_selected_item == p_item->pp_children[i_current] &&
495                     b_selected_item_met == YES)
496         {
497             vlc_object_release(p_playlist);
498             return NULL;
499         }
500         else if (b_selected_item_met == YES &&
501                     ([o_current_name rangeOfString:[o_search_field
502                         stringValue] options:NSCaseInsensitiveSearch ].length ||
503                     [o_current_author rangeOfString:[o_search_field
504                         stringValue] options:NSCaseInsensitiveSearch ].length))
505         {
506             vlc_object_release(p_playlist);
507             /*Adds the parent items in the result array as well, so that we can
508             expand the tree*/
509             return [NSMutableArray arrayWithObject: [NSValue
510                             valueWithPointer: p_item->pp_children[i_current]]];
511         }
512         if (p_item->pp_children[i_current]->i_children > 0)
513         {
514             id o_result = [self subSearchItem:
515                                             p_item->pp_children[i_current]];
516             if (o_result != NULL)
517             {
518                 vlc_object_release(p_playlist);
519                 [o_result insertObject: [NSValue valueWithPointer:
520                                 p_item->pp_children[i_current]] atIndex:0];
521                 return o_result;
522             }
523         }
524     }
525     vlc_object_release(p_playlist);
526     return NULL;
527 }
528
529 - (IBAction)searchItem:(id)sender
530 {
531     playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
532                                                        FIND_ANYWHERE );
533     playlist_view_t * p_view;
534     id o_result;
535
536     unsigned int i;
537     int i_row = -1;
538
539     b_selected_item_met = NO;
540
541     if( p_playlist == NULL )
542         return;
543
544     p_view = playlist_ViewFind( p_playlist, VIEW_SIMPLE );
545
546     if (p_view)
547     {
548         /*First, only search after the selected item:*
549          *(b_selected_item_met = NO)                 */
550         o_result = [self subSearchItem:p_view->p_root];
551         if (o_result == NULL)
552         {
553             /* If the first search failed, search again from the beginning */
554             o_result = [self subSearchItem:p_view->p_root];
555         }
556         if (o_result != NULL)
557         {
558             for (i = 0 ; i < [o_result count] - 1 ; i++)
559             {
560                 [o_outline_view expandItem: [o_outline_dict objectForKey:
561                             [NSString stringWithFormat: @"%p",
562                             [[o_result objectAtIndex: i] pointerValue]]]];
563             }
564             i_row = [o_outline_view rowForItem: [o_outline_dict objectForKey:
565                             [NSString stringWithFormat: @"%p",
566                             [[o_result objectAtIndex: [o_result count] - 1 ]
567                             pointerValue]]]];
568         }
569         if (i_row > -1)
570         {
571             [o_outline_view selectRow:i_row byExtendingSelection: NO];
572             [o_outline_view scrollRowToVisible: i_row];
573         }
574     }
575     vlc_object_release(p_playlist);
576
577 }
578
579 - (NSMenu *)menuForEvent:(NSEvent *)o_event
580 {
581     NSPoint pt;
582     vlc_bool_t b_rows;
583     vlc_bool_t b_item_sel;
584
585     pt = [o_outline_view convertPoint: [o_event locationInWindow]
586                                                  fromView: nil];
587     b_item_sel = ( [o_outline_view rowAtPoint: pt] != -1 &&
588                    [o_outline_view selectedRow] != -1 );
589     b_rows = [o_outline_view numberOfRows] != 0;
590
591     [o_mi_play setEnabled: b_item_sel];
592     [o_mi_delete setEnabled: b_item_sel];
593     [o_mi_selectall setEnabled: b_rows];
594     [o_mi_info setEnabled: b_item_sel];
595
596     return( o_ctx_menu );
597 }
598
599 - (playlist_item_t *)selectedPlaylistItem
600 {
601     return [[o_outline_view itemAtRow: [o_outline_view selectedRow]]
602                                                                 pointerValue];
603 }
604
605 @end
606
607 @implementation VLCPlaylist (NSOutlineViewDataSource)
608
609 /* return the number of children for Obj-C pointer item */ /* DONE */
610 - (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
611 {
612     int i_return = 0;
613     playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
614                                                        FIND_ANYWHERE );
615     if( p_playlist == NULL )
616         return 0;
617
618     if( item == nil )
619     {
620         /* root object */
621         playlist_view_t *p_view;
622         p_view = playlist_ViewFind( p_playlist, VIEW_SIMPLE );
623         if( p_view && p_view->p_root )
624             i_return = p_view->p_root->i_children;
625     }
626     else
627     {
628         playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
629         if( p_item )
630             i_return = p_item->i_children;
631     }
632     vlc_object_release( p_playlist );
633     if( i_return == -1 ) i_return = 0;
634     msg_Dbg( p_playlist, "I have %d children", i_return );
635     return i_return;
636 }
637
638 /* return the child at index for the Obj-C pointer item */ /* DONE */
639 - (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
640 {
641     playlist_item_t *p_return = NULL;
642     playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
643                                                        FIND_ANYWHERE );
644     NSValue * o_value;
645
646     if( p_playlist == NULL )
647         return nil;
648
649     if( item == nil )
650     {
651         /* root object */
652         playlist_view_t *p_view;
653         p_view = playlist_ViewFind( p_playlist, VIEW_SIMPLE );
654         if( p_view && index < p_view->p_root->i_children )
655             p_return = p_view->p_root->pp_children[index];
656     }
657     else
658     {
659         playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
660         if( p_item && index < p_item->i_children )
661         {
662             p_return = p_item->pp_children[index];
663         }
664     }
665
666     [o_status_field setStringValue: [NSString stringWithFormat:
667                         _NS("%i items in playlist"), p_playlist->i_size]];
668
669     vlc_object_release( p_playlist );
670     msg_Dbg( p_playlist, "childitem with index %d", index );
671
672     o_value = [NSValue valueWithPointer: p_return];
673
674     [o_outline_dict setObject:o_value forKey:[NSString stringWithFormat:@"%p",                                                                      p_return]];
675     return o_value;
676 }
677
678 /* is the item expandable */
679 - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
680 {
681     int i_return = 0;
682     playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
683                                                        FIND_ANYWHERE );
684     if( p_playlist == NULL )
685         return NO;
686
687     if( item == nil )
688     {
689         /* root object */
690         playlist_view_t *p_view;
691         p_view = playlist_ViewFind( p_playlist, VIEW_SIMPLE );
692         if( p_view && p_view->p_root )
693             i_return = p_view->p_root->i_children;
694     }
695     else
696     {
697         playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
698         if( p_item )
699             i_return = p_item->i_children;
700     }
701     vlc_object_release( p_playlist );
702
703     if( i_return == -1 || i_return == 0 )
704         return NO;
705     else
706         return YES;
707 }
708
709 /* retrieve the string values for the cells */
710 - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)o_tc byItem:(id)item
711 {
712     id o_value = nil;
713     intf_thread_t * p_intf = VLCIntf;
714     playlist_t * p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
715                                                FIND_ANYWHERE );
716     playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
717
718     if( p_playlist == NULL || p_item == NULL )
719     {
720         return( @"error" );
721     }
722
723     if( [[o_tc identifier] isEqualToString:@"1"] )
724     {
725         o_value = [NSString stringWithUTF8String:
726             p_item->input.psz_name];
727         if( o_value == NULL )
728             o_value = [NSString stringWithCString:
729                 p_item->input.psz_name];
730     }
731     else if( [[o_tc identifier] isEqualToString:@"2"] )
732     {
733         char *psz_temp;
734         psz_temp = playlist_ItemGetInfo( p_item ,_("Meta-information"),_("Artist") );
735
736         if( psz_temp == NULL )
737             o_value = @"";
738         else
739         {
740             o_value = [NSString stringWithUTF8String: psz_temp];
741             if( o_value == NULL )
742             {
743                 o_value = [NSString stringWithCString: psz_temp];
744             }
745             free( psz_temp );
746         }
747     }
748     else if( [[o_tc identifier] isEqualToString:@"3"] )
749     {
750         char psz_duration[MSTRTIME_MAX_SIZE];
751         mtime_t dur = p_item->input.i_duration;
752         if( dur != -1 )
753         {
754             secstotimestr( psz_duration, dur/1000000 );
755             o_value = [NSString stringWithUTF8String: psz_duration];
756         }
757         else
758         {
759             o_value = @"-:--:--";
760         }
761     }
762
763     vlc_object_release( p_playlist );
764
765     return( o_value );
766 }
767
768 /* Required for drag & drop and reordering */
769 - (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard
770 {
771     return NO;
772 }
773
774 - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(int)index
775 {
776     return NSDragOperationNone;
777 }
778
779 /* Delegate method of NSWindow */
780 - (void)windowWillClose:(NSNotification *)aNotification
781 {
782     [o_btn_playlist setState: NSOffState];
783 }
784
785 @end
786
787