]> git.sesse.net Git - vlc/blob - modules/gui/wxwindows/playlist.cpp
Implement new playlist system in wxWidgets interface
[vlc] / modules / gui / wxwindows / playlist.cpp
1 /*****************************************************************************
2  * playlist.cpp : wxWindows plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2004 VideoLAN
5  * $Id$
6  *
7  * Authors: Olivier Teulière <ipkiss@via.ecp.fr>
8  *          Clément Stenac <zorglub@videolan.org>
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 <vlc/vlc.h>
29 #include <vlc/intf.h>
30
31 #include "wxwindows.h"
32
33 #include "bitmaps/shuffle.xpm"
34 #include "bitmaps/repeat.xpm"
35 #include "bitmaps/loop.xpm"
36
37 #include "bitmaps/type_unknown.xpm"
38 #include "bitmaps/type_net.xpm"
39 #include "bitmaps/type_card.xpm"
40 #include "bitmaps/type_disc.xpm"
41 #include "bitmaps/type_directory.xpm"
42 #include "bitmaps/type_playlist.xpm"
43
44 #include <wx/dynarray.h>
45
46 #define HELP_SHUFFLE N_( "Shuffle" )
47 #define HELP_LOOP N_( "Loop" )
48 #define HELP_REPEAT N_( "Repeat" )
49
50 /* Callback prototype */
51 static int PlaylistChanged( vlc_object_t *, const char *,
52                             vlc_value_t, vlc_value_t, void * );
53 static int PlaylistNext( vlc_object_t *, const char *,
54                          vlc_value_t, vlc_value_t, void * );
55 static int ItemChanged( vlc_object_t *, const char *,
56                         vlc_value_t, vlc_value_t, void * );
57
58 /*****************************************************************************
59  * Event Table.
60  *****************************************************************************/
61
62 /* IDs for the controls and the menu commands */
63 enum
64 {
65     /* menu items */
66     AddFile_Event = 1,
67     AddMRL_Event,
68     Close_Event,
69     Open_Event,
70     Save_Event,
71
72     SortTitle_Event,
73     RSortTitle_Event,
74     SortAuthor_Event,
75     RSortAuthor_Event,
76     Randomize_Event,
77
78     EnableSelection_Event,
79     DisableSelection_Event,
80
81     InvertSelection_Event,
82     DeleteSelection_Event,
83     Random_Event,
84     Loop_Event,
85     Repeat_Event,
86     SelectAll_Event,
87
88     Up_Event,
89     Down_Event,
90     Infos_Event,
91
92     PopupPlay_Event,
93     PopupDel_Event,
94     PopupEna_Event,
95     PopupInfo_Event,
96
97     SearchText_Event,
98     Search_Event,
99
100     /* controls */
101     TreeCtrl_Event,
102
103     Browse_Event,  /* For export playlist */
104
105     /* custom events */
106     UpdateItem_Event,
107
108     FirstView_Event = wxID_HIGHEST + 1000,
109 };
110
111 DEFINE_LOCAL_EVENT_TYPE( wxEVT_PLAYLIST );
112
113 BEGIN_EVENT_TABLE(Playlist, wxFrame)
114     EVT_SIZE(Playlist::OnSize)
115
116     /* Menu events */
117     EVT_MENU(AddFile_Event, Playlist::OnAddFile)
118     EVT_MENU(AddMRL_Event, Playlist::OnAddMRL)
119     EVT_MENU(Close_Event, Playlist::OnClose)
120     EVT_MENU(Open_Event, Playlist::OnOpen)
121     EVT_MENU(Save_Event, Playlist::OnSave)
122
123     EVT_MENU(SortTitle_Event, Playlist::OnSort)
124     EVT_MENU(RSortTitle_Event, Playlist::OnSort)
125     EVT_MENU(SortAuthor_Event, Playlist::OnSort)
126     EVT_MENU(RSortAuthor_Event, Playlist::OnSort)
127
128     EVT_MENU(Randomize_Event, Playlist::OnSort)
129
130     EVT_MENU(EnableSelection_Event, Playlist::OnEnableSelection)
131     EVT_MENU(DisableSelection_Event, Playlist::OnDisableSelection)
132     EVT_MENU(InvertSelection_Event, Playlist::OnInvertSelection)
133     EVT_MENU(DeleteSelection_Event, Playlist::OnDeleteSelection)
134     EVT_MENU(SelectAll_Event, Playlist::OnSelectAll)
135     EVT_MENU(Infos_Event, Playlist::OnInfos)
136
137     EVT_MENU_OPEN( Playlist::OnMenuOpen )
138     EVT_MENU( -1, Playlist::OnMenuEvent )
139
140     EVT_TOOL(Random_Event, Playlist::OnRandom)
141     EVT_TOOL(Repeat_Event, Playlist::OnRepeat)
142     EVT_TOOL(Loop_Event, Playlist::OnLoop)
143
144     /* Popup events */
145     EVT_MENU( PopupPlay_Event, Playlist::OnPopupPlay)
146     EVT_MENU( PopupDel_Event, Playlist::OnPopupDel)
147     EVT_MENU( PopupEna_Event, Playlist::OnPopupEna)
148     EVT_MENU( PopupInfo_Event, Playlist::OnPopupInfo)
149
150     /* Tree control events */
151     EVT_TREE_ITEM_ACTIVATED( TreeCtrl_Event, Playlist::OnActivateItem )
152
153     EVT_CONTEXT_MENU( Playlist::OnPopup )
154
155     /* Button events */
156     EVT_BUTTON( Search_Event, Playlist::OnSearch)
157     EVT_BUTTON( Save_Event, Playlist::OnSave)
158     EVT_BUTTON( Infos_Event, Playlist::OnInfos)
159
160     EVT_BUTTON( Up_Event, Playlist::OnUp)
161     EVT_BUTTON( Down_Event, Playlist::OnDown)
162
163     EVT_TEXT(SearchText_Event, Playlist::OnSearchTextChange)
164
165     /* Custom events */
166     EVT_COMMAND(-1, wxEVT_PLAYLIST, Playlist::OnPlaylistEvent)
167
168     /* Special events : we don't want to destroy the window when the user
169      * clicks on (X) */
170     EVT_CLOSE(Playlist::OnClose)
171 END_EVENT_TABLE()
172
173 /*****************************************************************************
174  * PlaylistItem class
175  ****************************************************************************/
176 class PlaylistItem : public wxTreeItemData
177 {
178 public:
179     PlaylistItem( playlist_item_t *_p_item ) : wxTreeItemData()
180     {
181         p_item = _p_item;
182     }
183 protected:
184     playlist_item_t *p_item;
185 friend class Playlist;
186 };
187
188 /*****************************************************************************
189  * Constructor.
190  *****************************************************************************/
191 Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
192     wxFrame( p_parent, -1, wxU(_("Playlist")), wxDefaultPosition,
193              wxSize(345,400), wxDEFAULT_FRAME_STYLE )
194 {
195     vlc_value_t val;
196
197     /* Initializations */
198     p_intf = _p_intf;
199     i_update_counter = 0;
200     i_sort_mode = MODE_NONE;
201     b_need_update = VLC_FALSE;
202     SetIcon( *p_intf->p_sys->p_icon );
203
204     p_view_menu = NULL;
205
206     i_current_view = VIEW_SIMPLE;
207
208     i_title_sorted = 0;
209     i_author_sorted = 0;
210     i_group_sorted = 0;
211     i_duration_sorted = 0;
212
213     var_Create( p_intf, "random", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
214     var_Create( p_intf, "loop", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
215     var_Create( p_intf, "repeat", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );;
216
217     /* Create our "Manage" menu */
218     wxMenu *manage_menu = new wxMenu;
219     manage_menu->Append( AddFile_Event, wxU(_("&Simple Add...")) );
220     manage_menu->Append( AddMRL_Event, wxU(_("&Add MRL...")) );
221     manage_menu->AppendSeparator();
222     manage_menu->Append( Open_Event, wxU(_("&Open Playlist...")) );
223     manage_menu->Append( Save_Event, wxU(_("&Save Playlist...")) );
224     manage_menu->AppendSeparator();
225     manage_menu->Append( Close_Event, wxU(_("&Close")) );
226
227     /* Create our "Sort" menu */
228     wxMenu *sort_menu = new wxMenu;
229     sort_menu->Append( SortTitle_Event, wxU(_("Sort by &title")) );
230     sort_menu->Append( RSortTitle_Event, wxU(_("&Reverse sort by title")) );
231     sort_menu->AppendSeparator();
232     sort_menu->Append( SortAuthor_Event, wxU(_("Sort by &author")) );
233     sort_menu->Append( RSortAuthor_Event, wxU(_("Reverse sort by author")) );
234     sort_menu->AppendSeparator();
235     sort_menu->Append( Randomize_Event, wxU(_("&Shuffle Playlist")) );
236
237     /* Create our "Selection" menu */
238     wxMenu *selection_menu = new wxMenu;
239     selection_menu->Append( EnableSelection_Event, wxU(_("&Enable")) );
240     selection_menu->Append( DisableSelection_Event, wxU(_("&Disable")) );
241     selection_menu->AppendSeparator();
242     selection_menu->Append( InvertSelection_Event, wxU(_("&Invert")) );
243     selection_menu->Append( DeleteSelection_Event, wxU(_("D&elete")) );
244     selection_menu->Append( SelectAll_Event, wxU(_("&Select All")) );
245
246     /* Create our "View" menu */
247     ViewMenu();
248
249     /* Append the freshly created menus to the menu bar */
250     wxMenuBar *menubar = new wxMenuBar( wxMB_DOCKABLE );
251     menubar->Append( manage_menu, wxU(_("&Manage")) );
252     menubar->Append( sort_menu, wxU(_("S&ort")) );
253     menubar->Append( selection_menu, wxU(_("&Selection")) );
254     menubar->Append( p_view_menu, wxU(_("&View items") ) );
255
256     /* Attach the menu bar to the frame */
257     SetMenuBar( menubar );
258
259     /* Create the popup menu */
260     popup_menu = new wxMenu;
261     popup_menu->Append( PopupPlay_Event, wxU(_("Play")) );
262     popup_menu->Append( PopupDel_Event, wxU(_("Delete")) );
263     popup_menu->Append( PopupEna_Event, wxU(_("Enable/Disable")) );
264     popup_menu->Append( PopupInfo_Event, wxU(_("Info")) );
265
266     /* Create a panel to put everything in */
267     wxPanel *playlist_panel = new wxPanel( this, -1 );
268     playlist_panel->SetAutoLayout( TRUE );
269
270     /* Create the toolbar */
271     wxToolBar *toolbar =
272         CreateToolBar( wxTB_HORIZONTAL | wxTB_FLAT | wxTB_DOCKABLE );
273
274     /* Create the random tool */
275     toolbar->AddTool( Random_Event, wxT(""), wxBitmap(shuffle_on_xpm),
276                        wxBitmap(shuffle_on_xpm), wxITEM_CHECK,
277                        wxU(_(HELP_SHUFFLE) ) );
278     var_Get( p_intf, "random", &val );
279     toolbar->ToggleTool( Random_Event, val.b_bool );
280
281     /* Create the Loop tool */
282     toolbar->AddTool( Loop_Event, wxT(""), wxBitmap( loop_xpm),
283                       wxBitmap( loop_xpm), wxITEM_CHECK,
284                       wxU(_(HELP_LOOP )  ) );
285     var_Get( p_intf, "loop", &val );
286     toolbar->ToggleTool( Loop_Event, val.b_bool );
287
288     /* Create the Repeat one checkbox */
289     toolbar->AddTool( Repeat_Event, wxT(""), wxBitmap( repeat_xpm),
290                       wxBitmap( repeat_xpm), wxITEM_CHECK,
291                       wxU(_(HELP_REPEAT )  ) );
292     var_Get( p_intf, "repeat", &val );
293     toolbar->ToggleTool( Repeat_Event, val.b_bool ) ;
294
295     /* Create the Search Textbox */
296     search_text = new wxTextCtrl( toolbar, SearchText_Event, wxT(""),
297                                   wxDefaultPosition, wxSize(100, -1),
298                                   wxTE_PROCESS_ENTER);
299
300     /* Create the search button */
301     search_button = new wxButton( toolbar , Search_Event, wxU(_("Search")) );
302
303     toolbar->AddControl( new wxControl( toolbar, -1, wxDefaultPosition,
304                          wxSize(16, 16), wxBORDER_NONE ) );
305     toolbar->AddControl( search_text );
306     toolbar->AddControl( new wxControl( toolbar, -1, wxDefaultPosition,
307                          wxSize(5, 5), wxBORDER_NONE ) );
308     toolbar->AddControl( search_button );
309     search_button->SetDefault();
310     toolbar->Realize();
311
312     /* Create the tree */
313     treectrl = new wxTreeCtrl( playlist_panel, TreeCtrl_Event,
314                                wxDefaultPosition, wxDefaultSize,
315                                wxTR_HIDE_ROOT | wxTR_LINES_AT_ROOT|
316                                wxTR_NO_LINES |
317                                wxTR_HAS_BUTTONS | wxTR_TWIST_BUTTONS |
318                                wxTR_MULTIPLE | wxTR_EXTENDED );
319
320     /* Create image list */
321
322     wxImageList *p_images = new wxImageList( 16 , 16, TRUE);
323
324     wxIcon icons[10];
325     icons[ ITEM_TYPE_UNKNOWN ] = wxIcon( type_unknown_xpm );
326     icons[ ITEM_TYPE_DISC ] = wxIcon( type_disc_xpm );
327     icons[ ITEM_TYPE_DIRECTORY ] = wxIcon( type_directory_xpm );
328     icons[ ITEM_TYPE_PLAYLIST ] = wxIcon( type_playlist_xpm );
329     icons[ ITEM_TYPE_NET ] = wxIcon( type_net_xpm );
330     icons[ ITEM_TYPE_CARD ] = wxIcon( type_card_xpm );
331
332     for( int i = 0; i< WXSIZEOF( icons ) ; i++ )
333     {
334        p_images->Add( wxBitmap( wxBitmap(icons[i]).ConvertToImage().Rescale(16,16) ) );
335     }
336
337     treectrl->AssignImageList( p_images );
338
339     treectrl->AddRoot( wxU(_("root" )), -1, -1, NULL );
340
341     /* Reduce font size */
342     wxFont font= treectrl->GetFont();
343     font.SetPointSize(8);
344     treectrl->SetFont( font );
345
346     /* Create the Up-Down buttons */
347 #if 0
348     wxButton *up_button =
349         new wxButton( playlist_panel, Up_Event, wxU(_("Up") ) );
350     wxButton *down_button =
351         new wxButton( playlist_panel, Down_Event, wxU(_("Down") ) );
352
353     wxBoxSizer *updown_sizer = new wxBoxSizer( wxHORIZONTAL );
354     updown_sizer->Layout();
355     /* The top and bottom sizers */
356     wxBoxSizer *bottom_sizer = new wxBoxSizer( wxHORIZONTAL );
357     bottom_sizer->Add( up_button, 0, wxALIGN_LEFT | wxRIGHT, 3);
358     bottom_sizer->Add( down_button, 0, wxALIGN_LEFT | wxLEFT, 3);
359     bottom_sizer->Layout();
360 #endif
361     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
362     panel_sizer->Add( treectrl, 1, wxEXPAND | wxALL, 5 );
363 #if 0
364     panel_sizer->Add( bottom_sizer, 0, wxALL, 5);
365 #endif
366     panel_sizer->Layout();
367
368     playlist_panel->SetSizerAndFit( panel_sizer );
369
370 #if wxUSE_DRAG_AND_DROP
371     /* Associate drop targets with the playlist */
372     SetDropTarget( new DragAndDrop( p_intf, VLC_TRUE ) );
373 #endif
374
375     playlist_t *p_playlist =
376         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
377                                        FIND_ANYWHERE );
378     if( p_playlist == NULL )
379     {
380         return;
381     }
382
383     /* We want to be noticed of playlist changes */
384
385     /* Some global changes happened -> Rebuild all */
386     var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this );
387
388     /* We went to the next item */
389     var_AddCallback( p_playlist, "playlist-current", PlaylistNext, this );
390
391     /* One item has been updated */
392     var_AddCallback( p_playlist, "item-change", ItemChanged, this );
393
394     vlc_object_release( p_playlist );
395
396     /* Update the playlist */
397     Rebuild();
398 }
399
400 void Playlist::OnSize( wxSizeEvent& event)
401 {
402 #if 0
403     wxSize size = GetClientSize();
404     if( listview )
405         listview->SetColumnWidth( 0, size.x - listview->GetColumnWidth(1)
406                         - 15 /* margins */ );
407 #endif
408     event.Skip();
409 }
410
411 Playlist::~Playlist()
412 {
413     playlist_t *p_playlist =
414         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
415                                        FIND_ANYWHERE );
416     if( p_playlist == NULL )
417     {
418         return;
419     }
420
421     var_DelCallback( p_playlist, "item-change", ItemChanged, this );
422     var_DelCallback( p_playlist, "playlist-current", PlaylistNext, this );
423     var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this );
424     vlc_object_release( p_playlist );
425 }
426
427 /**********************************************************************
428  * Update one playlist item
429  **********************************************************************/
430 void Playlist::UpdateNode( playlist_t *p_playlist, playlist_item_t *p_node,
431                            wxTreeItemId node )
432 {
433     long cookie;
434     wxTreeItemId child;
435     for( int i = 0; i< p_node->i_children ; i++ )
436     {
437         if( i == 0 )
438         {
439             child = treectrl->GetFirstChild( node, cookie);
440         }
441         else
442         {
443             child = treectrl->GetNextChild( node, cookie );
444         }
445
446         if( !child.IsOk() )
447         {
448             /* Not enough children */
449             CreateNode( p_playlist, p_node->pp_children[i], node );
450             /* Keep the tree pointer up to date */
451             child = treectrl->GetNextChild( node, cookie );
452         }
453         else
454         {
455         }
456     }
457
458 }
459 /* Creates the node p_node as last child of parent */
460 void Playlist::CreateNode( playlist_t *p_playlist, playlist_item_t *p_node,
461                            wxTreeItemId parent )
462 {
463     long cookie;
464     wxTreeItemId node = treectrl->AppendItem( parent, p_node->input.psz_name,
465                                               -1,-1,
466                                               new PlaylistItem( p_node ) );
467     treectrl->SetItemImage( node, p_node->input.i_type );
468     for( int i = 0; i< p_node->i_children ; i++ )
469     {
470         /* Append the item */
471         if( p_node->pp_children[i]->i_children == -1 )
472         {
473             wxTreeItemId item = treectrl->AppendItem( node,
474                                   p_node->pp_children[i]->input.psz_name,
475                                   -1,-1,
476                                   new PlaylistItem( p_node->pp_children[i]) );
477
478             treectrl->SetItemImage( item,
479                                     p_node->pp_children[i]->input.i_type);
480         }
481         else
482         {
483             CreateNode( p_playlist, p_node->pp_children[i],
484                         node );
485         }
486     }
487 }
488
489 wxTreeItemId Playlist::FindItem( wxTreeItemId root, playlist_item_t *p_item )
490 {
491     long cookie;
492     PlaylistItem *p_wxcurrent;
493     wxTreeItemId search;
494     wxTreeItemId item = treectrl->GetFirstChild( root, cookie );
495     wxTreeItemId child;
496
497     while( item.IsOk() )
498     {
499         p_wxcurrent = (PlaylistItem *)treectrl->GetItemData( item );
500         if( p_wxcurrent->p_item == p_item )
501         {
502             return item;
503         }
504         if( treectrl->ItemHasChildren( item ) )
505         {
506             wxTreeItemId search = FindItem( item, p_item );
507             if( search.IsOk() )
508             {
509                 return search;
510             }
511         }
512         item = treectrl->GetNextChild( root, cookie);
513     }
514     /* Not found */
515     wxTreeItemId dummy;
516     return dummy;
517 }
518
519 /*wxTreeItemId Playlist::FindItemByName( wxTreeItemId root, wxString search_string, wxTreeItemId current )
520 {
521     long cookie;
522     PlaylistItem *p_wxcurrent;
523     wxTreeItemId search;
524     wxTreeItemId item = treectrl->GetFirstChild( root, cookie );
525     wxTreeItemId child;
526
527     while( item.IsOk() )
528     {
529         if( treectrl->GetItemText( item).Lower().Contains(
530                                                  search_string.Lower() ) )
531         {
532             return item;
533         if( treectrl->ItemHasChildren( item ) )
534         {
535             wxTreeItemId search = FindItem( item, p_item );
536             if( search.IsOk() )
537             {
538                 return search;
539             }
540         }
541         item = treectrl->GetNextChild( root, cookie);
542     }
543   */  /* Not found */
544     /*wxTreeItemId dummy;
545     return dummy;
546 }
547 */
548
549
550
551 void Playlist::SetCurrentItem( wxTreeItemId item )
552 {
553     if( item.IsOk() )
554     {
555         treectrl->SetItemBold( item, true );
556         treectrl->EnsureVisible( item );
557     }
558 }
559
560 void Playlist::UpdateItem( int i )
561 {
562     if( i < 0 ) return; /* Sanity check */
563     playlist_item_t *p_item;
564
565     playlist_t *p_playlist =
566         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
567                                        FIND_ANYWHERE );
568
569     if( p_playlist == NULL )
570     {
571         return;
572     }
573
574     p_item = playlist_ItemGetById( p_playlist, i );
575
576     wxTreeItemId item = FindItem( treectrl->GetRootItem(), p_item);
577
578     UpdateTreeItem( p_playlist, item );
579
580     vlc_object_release(p_playlist);
581
582 }
583
584 void Playlist::UpdateTreeItem( playlist_t *p_playlist ,wxTreeItemId item )
585 {
586     playlist_item_t *p_item;
587
588    if( !item.IsOk() )
589    {
590         return;
591    }
592
593     p_item  =  ((PlaylistItem *)treectrl->GetItemData( item ))->p_item;
594
595     if( !p_item )
596     {
597         return;
598     }
599
600     wxString msg;
601     char *psz_author = playlist_ItemGetInfo( p_item, _("Meta-information"),
602                                                          _("Artist"));
603     char psz_duration[MSTRTIME_MAX_SIZE];
604     mtime_t dur = p_item->input.i_duration;
605     if( dur != -1 )
606         secstotimestr( psz_duration, dur/1000000 );
607     else
608         memcpy( psz_duration, "-:--:--", sizeof("-:--:--") );
609
610     if( !strcmp( psz_author, "" ) )
611     {
612         msg.Printf( wxString( wxL2U( p_item->input.psz_name ) ) + wxU( " ( ") +
613                     wxString(wxL2U(psz_duration ) ) + wxU( ")") );
614     }
615     else
616     {
617         msg.Printf( wxString(wxU( psz_author )) + wxT(" - ") +
618                     wxString(wxL2U(p_item->input.psz_name)) + wxU( " ( ") +
619                     wxString(wxL2U(psz_duration ) ) + wxU( ")") );
620     }
621     treectrl->SetItemText( item , msg );
622
623     if( p_playlist->status.p_item == p_item )
624     {
625         SetCurrentItem( item );
626     }
627     else
628     {
629         treectrl->SetItemBold( item, false );
630     }
631 #if 0
632     if( p_item->b_enabled == VLC_FALSE )
633     {
634         wxListItem listitem;
635         listitem.m_itemId = i;
636         listitem.SetTextColour( *wxLIGHT_GREY);
637         listview->SetItem(listitem);
638     }
639 #endif
640 }
641
642 /**********************************************************************
643  * Rebuild the playlist
644  **********************************************************************/
645 void Playlist::Rebuild()
646 {
647     playlist_view_t *p_view;
648     playlist_t *p_playlist =
649         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
650                                        FIND_ANYWHERE );
651     if( p_playlist == NULL )
652     {
653         return;
654     }
655
656     /* ...and rebuild it */
657     vlc_mutex_lock( &p_playlist->object_lock );
658
659     p_view = playlist_ViewFind( p_playlist, i_current_view ); /* FIXME */
660
661     /* HACK we should really get new*/
662     msg_Dbg( p_intf, "rebuilding tree" );
663     treectrl->DeleteAllItems();
664     treectrl->AddRoot( wxU(_("root" )), -1, -1,
665                          new PlaylistItem( p_view->p_root) );
666
667     wxTreeItemId root = treectrl->GetRootItem();
668     UpdateNode( p_playlist, p_view->p_root, root );
669
670     wxTreeItemId item;
671     if( p_playlist->status.p_item != NULL )
672     {
673         item = FindItem( root, p_playlist->status.p_item );
674     }
675     else if( p_playlist->status.p_node != NULL )
676     {
677         item = FindItem( root, p_playlist->status.p_node );
678     }
679     else
680     {
681         item = root;
682     }
683
684     SetCurrentItem( item );
685
686     vlc_mutex_unlock( &p_playlist->object_lock );
687
688     vlc_object_release( p_playlist );
689 }
690
691 void Playlist::ShowPlaylist( bool show )
692 {
693     if( show ) Rebuild();
694     Show( show );
695 }
696
697 void Playlist::UpdatePlaylist()
698 {
699     i_update_counter++;
700
701     /* If the playlist isn't show there's no need to update it */
702     if( !IsShown() ) return;
703
704     if( this->b_need_update )
705     {
706         this->b_need_update = VLC_FALSE;
707         Rebuild();
708     }
709
710     /* Updating the playing status every 0.5s is enough */
711     if( i_update_counter % 5 ) return;
712
713     playlist_t *p_playlist =
714         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
715                                        FIND_ANYWHERE );
716     if( p_playlist == NULL )
717     {
718         return;
719     }
720 #if 0
721     /* Update the colour of items */
722     int i_playlist_index = p_playlist->i_index;
723     if( p_intf->p_sys->i_playing != i_playlist_index )
724     {
725         wxListItem listitem;
726         listitem.m_itemId = i_playlist_index;
727         listitem.SetTextColour( *wxRED );
728         listview->SetItem( listitem );
729
730         if( p_intf->p_sys->i_playing != -1 )
731         {
732             listitem.m_itemId = p_intf->p_sys->i_playing;
733             listitem.SetTextColour( *wxBLACK );
734             listview->SetItem( listitem );
735         }
736         p_intf->p_sys->i_playing = i_playlist_index;
737     }
738 #endif
739     vlc_object_release( p_playlist );
740 }
741
742 /*****************************************************************************
743  * Private methods.
744  *****************************************************************************/
745 void Playlist::DeleteItem( int item_id )
746 {
747     playlist_t *p_playlist =
748         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
749                                        FIND_ANYWHERE );
750     if( p_playlist == NULL )
751     {
752         return;
753     }
754
755     playlist_Delete( p_playlist, item_id );
756
757     vlc_object_release( p_playlist );
758 }
759
760 void Playlist::OnClose( wxCommandEvent& WXUNUSED(event) )
761 {
762     Hide();
763 }
764
765 void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) )
766 {
767     struct {
768         char *psz_desc;
769         char *psz_filter;
770         char *psz_module;
771     } formats[] = {{ _("M3U file"), "*.m3u", "export-m3u" },
772                    { _("PLS file"), "*.pls", "export-pls" }};
773
774     wxString filter = wxT("");
775
776     playlist_t * p_playlist =
777                 (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
778                                                FIND_ANYWHERE );
779
780     if( ! p_playlist )
781     {
782         return;
783     }
784     if( p_playlist->i_size == 0 )
785     {
786         wxMessageBox( wxU(_("Playlist is empty") ), wxU(_("Can't save")),
787                       wxICON_WARNING | wxOK, this );
788         vlc_object_release( p_playlist );
789         return;
790     }
791
792     for( unsigned int i = 0; i < sizeof(formats)/sizeof(formats[0]); i++)
793     {
794         filter.Append( wxU(formats[i].psz_desc) );
795         filter.Append( wxT("|") );
796         filter.Append( wxU(formats[i].psz_filter) );
797         filter.Append( wxT("|") );
798     }
799     wxFileDialog dialog( this, wxU(_("Save playlist")),
800                          wxT(""), wxT(""), filter, wxSAVE );
801
802     if( dialog.ShowModal() == wxID_OK )
803     {
804         if( dialog.GetPath().mb_str() )
805         {
806             playlist_Export( p_playlist, dialog.GetPath().mb_str(),
807                              formats[dialog.GetFilterIndex()].psz_module );
808         }
809     }
810
811     vlc_object_release( p_playlist );
812
813 }
814
815 void Playlist::OnOpen( wxCommandEvent& WXUNUSED(event) )
816 {
817     playlist_t *p_playlist =
818         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
819                                        FIND_ANYWHERE );
820     if( p_playlist == NULL )
821     {
822         return;
823     }
824
825     wxFileDialog dialog( this, wxU(_("Open playlist")), wxT(""), wxT(""),
826         wxT("All playlists|*.pls;*.m3u;*.asx;*.b4s|M3U files|*.m3u"), wxOPEN );
827
828     if( dialog.ShowModal() == wxID_OK )
829     {
830         playlist_Import( p_playlist, dialog.GetPath().mb_str() );
831     }
832
833     vlc_object_release( p_playlist );
834 }
835
836 void Playlist::OnAddFile( wxCommandEvent& WXUNUSED(event) )
837 {
838     p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE_SIMPLE, 0, 0 );
839
840 }
841
842 void Playlist::OnAddMRL( wxCommandEvent& WXUNUSED(event) )
843 {
844     p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE, 0, 0 );
845
846 }
847
848 /********************************************************************
849  * Move functions
850  ********************************************************************/
851 void Playlist::OnUp( wxCommandEvent& event )
852 {
853     playlist_t *p_playlist =
854         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
855                                        FIND_ANYWHERE );
856     if( p_playlist == NULL )
857     {
858         return;
859     }
860 #if 0
861     /* We use the first selected item, so find it */
862     long i_item = listview->GetNextItem( -1, wxLIST_NEXT_ALL,
863                                          wxLIST_STATE_SELECTED);
864     if( i_item > 0 && i_item < p_playlist->i_size )
865     {
866         playlist_Move( p_playlist, i_item, i_item - 1 );
867         listview->Focus( i_item - 1 );
868     }
869 #endif
870     vlc_object_release( p_playlist );
871 }
872
873 void Playlist::OnDown( wxCommandEvent& event )
874 {
875     playlist_t *p_playlist =
876         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
877                                        FIND_ANYWHERE );
878     if( p_playlist == NULL )
879     {
880         return;
881     }
882 #if 0
883     /* We use the first selected item, so find it */
884     long i_item = listview->GetNextItem( -1, wxLIST_NEXT_ALL,
885                                          wxLIST_STATE_SELECTED );
886     if( i_item >= 0 && i_item < p_playlist->i_size - 1 )
887     {
888         playlist_Move( p_playlist, i_item, i_item + 2 );
889         listview->Focus( i_item + 1 );
890     }
891 #endif
892     vlc_object_release( p_playlist );
893 }
894
895 /********************************************************************
896  * Sorting functions
897  ********************************************************************/
898 void Playlist::OnSort( wxCommandEvent& event )
899 {
900     playlist_t *p_playlist =
901         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
902                                        FIND_ANYWHERE );
903     if( p_playlist == NULL )
904     {
905         return;
906     }
907     switch( event.GetId() )
908     {
909         case SortTitle_Event:
910            playlist_SortTitle( p_playlist, ORDER_NORMAL );
911            break;
912         case RSortTitle_Event:
913            playlist_SortTitle( p_playlist, ORDER_REVERSE );
914            break;
915         case SortAuthor_Event:
916            playlist_SortAuthor(p_playlist, ORDER_NORMAL );
917            break;
918         case RSortAuthor_Event:
919            playlist_SortAuthor( p_playlist, ORDER_REVERSE );
920            break;
921         case Randomize_Event:
922            playlist_Sort( p_playlist, SORT_RANDOM, ORDER_NORMAL );
923            break;
924     }
925     vlc_object_release( p_playlist );
926
927     Rebuild();
928 }
929
930 /**********************************************************************
931  * Search functions
932  **********************************************************************/
933 void Playlist::OnSearchTextChange( wxCommandEvent& WXUNUSED(event) )
934 {
935    search_button->SetDefault();
936 }
937
938 void Playlist::OnSearch( wxCommandEvent& WXUNUSED(event) )
939 {
940     wxString search_string = search_text->GetValue();
941
942     bool b_ok = false;
943     int i_current;
944     int i_first = 0 ;
945     int i_item = -1;
946 }
947
948 #if 0
949     for( i_current = 0; i_current < listview->GetItemCount(); i_current++ )
950     {
951         if( listview->GetItemState( i_current, wxLIST_STATE_SELECTED ) ==
952               wxLIST_STATE_SELECTED )
953         {
954             i_first = i_current;
955             break;
956         }
957     }
958
959     if( i_first == listview->GetItemCount() )
960     {
961         i_first = -1;
962     }
963
964     for( i_current = i_first + 1; i_current < listview->GetItemCount();
965          i_current++ )
966     {
967         wxListItem listitem;
968         listitem.SetId( i_current );
969         listview->GetItem( listitem );
970         if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
971         {
972             i_item = i_current;
973             b_ok = true;
974             break;
975         }
976         listitem.SetColumn( 1 );
977         listview->GetItem( listitem );
978         if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
979         {
980             i_item = i_current;
981             b_ok = true;
982             break;
983         }
984     }
985     if( !b_ok )
986     {
987         for( i_current = -1 ; i_current < i_first - 1;
988              i_current++ )
989         {
990             wxListItem listitem;
991             listitem.SetId( i_current );
992             listview->GetItem( listitem );
993             if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
994             {
995                 i_item = i_current;
996                 b_ok = true;
997                 break;
998             }
999             listitem.SetColumn( 1 );
1000             listview->GetItem( listitem );
1001             if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
1002             {
1003                 i_item = i_current;
1004                 b_ok = true;
1005                 break;
1006             }
1007         }
1008     }
1009
1010     if( i_item < 0 || i_item >= listview->GetItemCount() )
1011     {
1012         return;
1013     }
1014
1015     for( long item = 0; item < listview->GetItemCount(); item++ )
1016     {
1017         listview->Select( item, FALSE );
1018     }
1019
1020     wxListItem listitem;
1021     listitem.SetId(i_item);
1022     listitem.m_state = wxLIST_STATE_SELECTED;
1023     listview->Select( i_item, TRUE );
1024     listview->Focus( i_item );
1025 }
1026 #endif
1027
1028 /**********************************************************************
1029  * Selection functions
1030  **********************************************************************/
1031 void Playlist::OnInvertSelection( wxCommandEvent& WXUNUSED(event) )
1032 {
1033 }
1034
1035 void Playlist::OnDeleteSelection( wxCommandEvent& WXUNUSED(event) )
1036 {
1037     Rebuild();
1038 }
1039
1040 void Playlist::OnEnableSelection( wxCommandEvent& WXUNUSED(event) )
1041 {
1042     playlist_t *p_playlist =
1043         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1044                                        FIND_ANYWHERE );
1045     if( p_playlist == NULL )
1046     {
1047         return;
1048     }
1049 #if 0
1050     for( long item = listview->GetItemCount() - 1; item >= 0; item-- )
1051     {
1052         if( listview->IsSelected( item ) )
1053         {
1054             /*XXX*/
1055             playlist_Enable( p_playlist, item );
1056             UpdateItem( item );
1057         }
1058     }
1059 #endif
1060     vlc_object_release( p_playlist);
1061 }
1062
1063 void Playlist::OnDisableSelection( wxCommandEvent& WXUNUSED(event) )
1064 {
1065     playlist_t *p_playlist =
1066         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1067                                        FIND_ANYWHERE );
1068     if( p_playlist == NULL )
1069     {
1070         return;
1071     }
1072 #if 0
1073     for( long item = listview->GetItemCount() - 1; item >= 0; item-- )
1074     {
1075         if( listview->IsSelected( item ) )
1076         {
1077             /*XXX*/
1078             playlist_Disable( p_playlist, item );
1079             UpdateItem( item );
1080         }
1081     }
1082 #endif
1083     vlc_object_release( p_playlist);
1084 }
1085
1086 void Playlist::OnSelectAll( wxCommandEvent& WXUNUSED(event) )
1087 {
1088 #if 0
1089     for( long item = 0; item < listview->GetItemCount(); item++ )
1090     {
1091         listview->Select( item, TRUE );
1092     }
1093 #endif
1094 }
1095
1096 /**********************************************************************
1097  * Playlist mode functions
1098  **********************************************************************/
1099 void Playlist::OnRandom( wxCommandEvent& event )
1100 {
1101     vlc_value_t val;
1102     val.b_bool = event.IsChecked();
1103     playlist_t *p_playlist =
1104         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1105                                        FIND_ANYWHERE );
1106     if( p_playlist == NULL )
1107     {
1108         return;
1109     }
1110     var_Set( p_playlist, "random", val);
1111     vlc_object_release( p_playlist );
1112 }
1113
1114 void Playlist::OnLoop( wxCommandEvent& event )
1115 {
1116     vlc_value_t val;
1117     val.b_bool = event.IsChecked();
1118     playlist_t *p_playlist =
1119         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1120                                        FIND_ANYWHERE );
1121     if( p_playlist == NULL )
1122     {
1123         return;
1124     }
1125     var_Set( p_playlist, "loop", val);
1126     vlc_object_release( p_playlist );
1127 }
1128
1129 void Playlist::OnRepeat( wxCommandEvent& event )
1130 {
1131     vlc_value_t val;
1132     val.b_bool = event.IsChecked();
1133     playlist_t *p_playlist =
1134         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1135                                        FIND_ANYWHERE );
1136     if( p_playlist == NULL )
1137     {
1138         return;
1139     }
1140     var_Set( p_playlist, "repeat", val);
1141     vlc_object_release( p_playlist );
1142 }
1143
1144
1145
1146 void Playlist::OnActivateItem( wxTreeEvent& event )
1147 {
1148     playlist_item_t *p_item,*p_node;
1149     playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_intf,
1150                                  VLC_OBJECT_PLAYLIST,FIND_ANYWHERE );
1151     PlaylistItem *p_wxitem = (PlaylistItem *)treectrl->GetItemData( 
1152                                                    event.GetItem() );
1153     wxTreeItemId parent = treectrl->GetItemParent( event.GetItem() );
1154     if( parent.IsOk() )
1155     {
1156         fprintf(stderr,"Ca gère\n" );
1157     }
1158     else
1159     {
1160         fprintf(stderr,"Ca craint\n" );
1161     }
1162     PlaylistItem *p_wxparent = (PlaylistItem *)treectrl->GetItemData( parent );
1163
1164     if( p_playlist == NULL )
1165     {
1166         return;
1167     }
1168
1169     if( p_wxitem->p_item->i_children == -1 )
1170     {
1171         p_node = p_wxparent->p_item;
1172         p_item = p_wxitem->p_item;
1173     }
1174     else
1175     {
1176         p_node = p_wxitem->p_item;
1177         p_item = NULL;
1178     }
1179
1180     playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, i_current_view,
1181                       p_node, p_item );
1182
1183     vlc_object_release( p_playlist );
1184 }
1185
1186 void Playlist::OnKeyDown( wxTreeEvent& event )
1187 {
1188     long keycode = event.GetKeyCode();
1189     /* Delete selected items */
1190     if( keycode == WXK_BACK || keycode == WXK_DELETE )
1191     {
1192         /* We send a dummy event */
1193         OnDeleteSelection( event );
1194     }
1195 }
1196
1197 void Playlist::ShowInfos( int i_item )
1198 {
1199 }
1200
1201 void Playlist::OnInfos( wxCommandEvent& WXUNUSED(event) )
1202 {
1203     /* We use the first selected item, so find it */
1204 #if 0
1205     long i_item = listview->GetNextItem( -1, wxLIST_NEXT_ALL,
1206                                          wxLIST_STATE_SELECTED );
1207     ShowInfos( i_item );
1208 #endif
1209 }
1210
1211 void Playlist::OnEnDis( wxCommandEvent& event )
1212 {
1213     playlist_t *p_playlist =
1214         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1215                                        FIND_ANYWHERE );
1216     if( p_playlist == NULL )
1217     {
1218         return;
1219     }
1220 #if 0
1221     long i_item = listview->GetNextItem( -1, wxLIST_NEXT_ALL,
1222                                          wxLIST_STATE_SELECTED );
1223
1224     if( i_item >= 0 && i_item < p_playlist->i_size )
1225     {
1226        Rebuild();
1227     }
1228 #endif
1229     vlc_object_release( p_playlist );
1230 }
1231
1232 /**********************************************************************
1233  * Menu
1234  **********************************************************************/
1235
1236 void Playlist::OnMenuOpen( wxMenuEvent& event)
1237 {
1238 #if defined( __WXMSW__ )
1239 #   define GetEventObject GetMenu
1240 #endif
1241
1242     if( event.GetEventObject() == p_view_menu )
1243     {
1244         p_view_menu = ViewMenu();
1245     }
1246 #if defined( __WXMSW__ )
1247 #   undef GetEventObject
1248 #endif
1249 }
1250
1251 void Playlist::OnMenuEvent( wxCommandEvent& event )
1252 {
1253     playlist_t *p_playlist =
1254         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1255                                        FIND_ANYWHERE );
1256     if( p_playlist == NULL )
1257     {
1258         return;
1259     }
1260
1261     if( event.GetId() < FirstView_Event )
1262     {
1263         event.Skip();
1264         return;
1265     }
1266
1267     int i_new_view = event.GetId() - FirstView_Event;
1268
1269     playlist_view_t *p_view = playlist_ViewFind( p_playlist, i_new_view );
1270
1271     if( p_view != NULL )
1272     {
1273         i_current_view = i_new_view;
1274         playlist_ViewUpdate( p_playlist, i_new_view );
1275         Rebuild();
1276         vlc_object_release( p_playlist );
1277         return;
1278     }
1279     else if( i_new_view >= VIEW_FIRST_SORTED && i_new_view <= VIEW_LAST_SORTED )
1280     {
1281         playlist_ViewInsert( p_playlist, i_new_view, "View" );
1282         playlist_ViewUpdate( p_playlist, i_new_view );
1283
1284         i_current_view = i_new_view;
1285
1286         Rebuild();
1287     }
1288
1289     vlc_object_release( p_playlist );
1290 }
1291
1292 wxMenu * Playlist::ViewMenu()
1293 {
1294     playlist_t *p_playlist =
1295         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1296                                        FIND_ANYWHERE );
1297     if( p_playlist == NULL )
1298     {
1299         return NULL;
1300     }
1301
1302     if( !p_view_menu )
1303     {
1304         p_view_menu = new wxMenu;
1305     }
1306     else
1307     {
1308         wxMenuItemList::Node *node = p_view_menu->GetMenuItems().GetFirst();
1309         for( ; node; )
1310         {
1311             wxMenuItem *item = node->GetData();
1312             node = node->GetNext();
1313             p_view_menu->Delete( item );
1314         }
1315     }
1316
1317     /* FIXME : have a list of "should have" views */
1318     p_view_menu->Append( FirstView_Event + VIEW_CATEGORY,
1319                            wxU(_("By category") ) );
1320     p_view_menu->Append( FirstView_Event + VIEW_SIMPLE,
1321                            wxU(_("Manually added") ) );
1322     p_view_menu->Append( FirstView_Event + VIEW_ALL,
1323                            wxU(_("All items, unsorted") ) );
1324     p_view_menu->Append( FirstView_Event + VIEW_S_AUTHOR,
1325                            wxU(_("Sorted by author") ) );
1326 #if 0
1327     for( int i = 0; i< p_playlist->i_views; i++ )
1328     {
1329         p_view_menu->Append( FirstView_Event + p_playlist->pp_views[i]->i_id,
1330                              wxU( p_playlist->pp_views[i]->psz_name ) );
1331     }
1332 #endif
1333
1334     vlc_object_release( p_playlist);
1335
1336     return p_view_menu;
1337 }
1338
1339
1340 /*****************************************************************************
1341  * Popup management functions
1342  *****************************************************************************/
1343 void Playlist::OnPopup( wxContextMenuEvent& event )
1344 {
1345     wxPoint pt = event.GetPosition();
1346
1347     i_popup_item = treectrl->HitTest( ScreenToClient( pt ) );
1348     if( i_popup_item.IsOk() )
1349     {
1350         PlaylistItem *p_wxitem = (PlaylistItem *)treectrl->GetItemData(
1351                                                             i_popup_item );
1352         PlaylistItem *p_wxparent= (PlaylistItem *) treectrl->GetItemData(
1353                                    treectrl->GetItemParent( i_popup_item ) );
1354         p_popup_item = p_wxitem->p_item;
1355         p_popup_parent = p_wxparent->p_item;
1356         treectrl->SelectItem( i_popup_item );
1357         Playlist::PopupMenu( popup_menu,
1358                              ScreenToClient( wxGetMousePosition() ) );
1359     }
1360     else
1361     {
1362     }
1363 }
1364
1365 void Playlist::OnPopupPlay( wxMenuEvent& event )
1366 {
1367     playlist_t *p_playlist =
1368         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1369                                        FIND_ANYWHERE );
1370     if( p_playlist == NULL )
1371     {
1372         return;
1373     }
1374     if( p_popup_item != NULL )
1375     {
1376         playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
1377                           VIEW_SIMPLE, p_popup_parent, p_popup_item );
1378                                 /*FIXME*/
1379     }
1380     vlc_object_release( p_playlist );
1381 }
1382
1383 void Playlist::OnPopupDel( wxMenuEvent& event )
1384 {
1385     PlaylistItem *p_wxitem;
1386
1387     p_wxitem = (PlaylistItem *)treectrl->GetItemData( i_popup_item );
1388
1389     if( p_wxitem->p_item->i_children == -1 )
1390     {
1391         DeleteItem( p_wxitem->p_item->input.i_id );
1392     }
1393     else
1394     {
1395         //DeleteNode( p_wxitem->p_item );
1396     }
1397 }
1398
1399 void Playlist::OnPopupEna( wxMenuEvent& event )
1400 {
1401     playlist_t *p_playlist =
1402         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1403                                        FIND_ANYWHERE );
1404     if( p_playlist == NULL )
1405     {
1406         return;
1407     }
1408
1409     p_popup_item->b_enabled = VLC_TRUE - p_popup_item->b_enabled;
1410
1411     vlc_object_release( p_playlist);
1412     UpdateItem( i_popup_item );
1413 }
1414
1415 void Playlist::OnPopupInfo( wxMenuEvent& event )
1416 {
1417     if( p_popup_item )
1418     {
1419         iteminfo_dialog = new ItemInfoDialog( p_intf, p_popup_item, this );
1420         if( iteminfo_dialog->ShowModal() == wxID_OK )
1421         {
1422             UpdateItem( i_popup_item );
1423         }
1424         delete iteminfo_dialog;
1425     }
1426 }
1427
1428
1429 /*****************************************************************************
1430  * Custom events management
1431  *****************************************************************************/
1432 void Playlist::OnPlaylistEvent( wxCommandEvent& event )
1433 {
1434     switch( event.GetId() )
1435     {
1436     case UpdateItem_Event:
1437         UpdateItem( event.GetInt() );
1438         break;
1439     }
1440 }
1441
1442 /*****************************************************************************
1443  * PlaylistChanged: callback triggered by the intf-change playlist variable
1444  *  We don't rebuild the playlist directly here because we don't want the
1445  *  caller to block for a too long time.
1446  *****************************************************************************/
1447 static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
1448                             vlc_value_t oval, vlc_value_t nval, void *param )
1449 {
1450     Playlist *p_playlist_dialog = (Playlist *)param;
1451     p_playlist_dialog->b_need_update = VLC_TRUE;
1452     return VLC_SUCCESS;
1453 }
1454
1455 /*****************************************************************************
1456  * Next: callback triggered by the playlist-current playlist variable
1457  *****************************************************************************/
1458 static int PlaylistNext( vlc_object_t *p_this, const char *psz_variable,
1459                          vlc_value_t oval, vlc_value_t nval, void *param )
1460 {
1461     Playlist *p_playlist_dialog = (Playlist *)param;
1462
1463     wxCommandEvent event( wxEVT_PLAYLIST, UpdateItem_Event );
1464     event.SetInt( oval.i_int );
1465     p_playlist_dialog->AddPendingEvent( event );
1466     event.SetInt( nval.i_int );
1467     p_playlist_dialog->AddPendingEvent( event );
1468
1469     return 0;
1470 }
1471
1472 /*****************************************************************************
1473  * ItemChanged: callback triggered by the item-change playlist variable
1474  *****************************************************************************/
1475 static int ItemChanged( vlc_object_t *p_this, const char *psz_variable,
1476                         vlc_value_t old_val, vlc_value_t new_val, void *param )
1477 {
1478     Playlist *p_playlist_dialog = (Playlist *)param;
1479
1480     wxCommandEvent event( wxEVT_PLAYLIST, UpdateItem_Event );
1481     event.SetInt( new_val.i_int );
1482     p_playlist_dialog->AddPendingEvent( event );
1483
1484     return 0;
1485 }