]> git.sesse.net Git - vlc/blob - modules/gui/wxwindows/playlist.cpp
12a30ebe8ac21932b06fc67b3b91d884bec3b32e
[vlc] / modules / gui / wxwindows / playlist.cpp
1 /*****************************************************************************
2  * playlist.cpp : wxWindows plugin for vlc
3  *****************************************************************************
4  * Copyright (C) 2000-2001, 2003 VideoLAN
5  * $Id: playlist.cpp,v 1.30 2003/12/04 18:26:53 gbazin Exp $
6  *
7  * Authors: Olivier Teulière <ipkiss@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <vlc/vlc.h>
28 #include <vlc/intf.h>
29
30 #include "wxwindows.h"
31 #include <wx/listctrl.h>
32
33 /* Callback prototype */
34 int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
35                      vlc_value_t old_val, vlc_value_t new_val, void *param );
36
37 /*****************************************************************************
38  * Event Table.
39  *****************************************************************************/
40
41 /* IDs for the controls and the menu commands */
42 enum
43 {
44     /* menu items */
45     AddFile_Event = 1,
46     AddMRL_Event,
47     Close_Event,
48     Open_Event,
49     Save_Event,
50
51     SortTitle_Event,
52     RSortTitle_Event,
53     SortAuthor_Event,
54     RSortAuthor_Event,
55     SortGroup_Event,
56     RSortGroup_Event,
57     Randomize_Event,
58
59     EnableSelection_Event,
60     DisableSelection_Event,
61
62     InvertSelection_Event,
63     DeleteSelection_Event,
64     Random_Event,
65     Loop_Event,
66     Repeat_Event,
67     SelectAll_Event,
68
69     EnableGroup_Event,
70     DisableGroup_Event,
71
72     Up_Event,
73     Down_Event,
74     Infos_Event,
75
76     SearchText_Event,
77     Search_Event,
78
79     /* controls */
80     ListView_Event
81 };
82
83 BEGIN_EVENT_TABLE(Playlist, wxFrame)
84     /* Menu events */
85     EVT_MENU(AddFile_Event, Playlist::OnAddFile)
86     EVT_MENU(AddMRL_Event, Playlist::OnAddMRL)
87     EVT_MENU(Close_Event, Playlist::OnClose)
88     EVT_MENU(Open_Event, Playlist::OnOpen)
89     EVT_MENU(Save_Event, Playlist::OnSave)
90
91     EVT_MENU(SortTitle_Event, Playlist::OnSort)
92     EVT_MENU(RSortTitle_Event, Playlist::OnSort)
93     EVT_MENU(SortAuthor_Event, Playlist::OnSort)
94     EVT_MENU(RSortAuthor_Event, Playlist::OnSort)
95     EVT_MENU(SortGroup_Event, Playlist::OnSort)
96     EVT_MENU(RSortGroup_Event, Playlist::OnSort)
97
98     EVT_MENU(Randomize_Event, Playlist::OnSort)
99
100     EVT_MENU(EnableSelection_Event, Playlist::OnEnableSelection)
101     EVT_MENU(DisableSelection_Event, Playlist::OnDisableSelection)
102     EVT_MENU(InvertSelection_Event, Playlist::OnInvertSelection)
103     EVT_MENU(DeleteSelection_Event, Playlist::OnDeleteSelection)
104     EVT_MENU(SelectAll_Event, Playlist::OnSelectAll)
105     EVT_MENU(Infos_Event, Playlist::OnInfos)
106     EVT_CHECKBOX(Random_Event, Playlist::OnRandom)
107     EVT_CHECKBOX(Repeat_Event, Playlist::OnRepeat)
108     EVT_CHECKBOX(Loop_Event, Playlist::OnLoop)
109
110     EVT_MENU(EnableGroup_Event, Playlist::OnEnDis)
111     EVT_MENU(DisableGroup_Event, Playlist::OnEnDis)
112
113     /* Listview events */
114     EVT_LIST_ITEM_ACTIVATED(ListView_Event, Playlist::OnActivateItem)
115     EVT_LIST_COL_CLICK(ListView_Event, Playlist::OnColSelect)
116     EVT_LIST_KEY_DOWN(ListView_Event, Playlist::OnKeyDown)
117
118     /* Button events */
119     EVT_BUTTON( Search_Event, Playlist::OnSearch)
120     EVT_BUTTON( Save_Event, Playlist::OnSave)
121     EVT_BUTTON( Infos_Event, Playlist::OnInfos)
122
123     EVT_BUTTON( Up_Event, Playlist::OnUp)
124     EVT_BUTTON( Down_Event, Playlist::OnDown)
125
126     EVT_TEXT(SearchText_Event, Playlist::OnSearchTextChange)
127
128     /* Special events : we don't want to destroy the window when the user
129      * clicks on (X) */
130     EVT_CLOSE(Playlist::OnClose)
131 END_EVENT_TABLE()
132
133
134 /* Event Table for the Newgroup class */
135 BEGIN_EVENT_TABLE(NewGroup, wxDialog)
136     EVT_BUTTON( wxID_OK, NewGroup::OnOk)
137     EVT_BUTTON( wxID_CANCEL, NewGroup::OnCancel)
138 END_EVENT_TABLE()
139
140 /*****************************************************************************
141  * Constructor.
142  *****************************************************************************/
143 Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
144     wxFrame( p_parent, -1, wxU(_("Playlist")), wxDefaultPosition,
145              wxDefaultSize, wxDEFAULT_FRAME_STYLE )
146 {
147     /* Initializations */
148     iteminfo_dialog = NULL;
149     p_intf = _p_intf;
150     vlc_value_t  val;
151     i_update_counter = 0;
152     i_sort_mode = MODE_NONE;
153     b_need_update = VLC_FALSE;
154     vlc_mutex_init( p_intf, &lock );
155     SetIcon( *p_intf->p_sys->p_icon );
156
157     i_title_sorted = 0;
158     i_author_sorted = 0;
159     i_group_sorted = 0;
160
161
162     var_Create( p_intf, "random", VLC_VAR_BOOL );
163     var_Change( p_intf, "random", VLC_VAR_INHERITVALUE, & val, NULL );
164     var_Create( p_intf, "loop", VLC_VAR_BOOL );
165     var_Create( p_intf, "loop", VLC_VAR_BOOL );
166     var_Change( p_intf, "repeat", VLC_VAR_INHERITVALUE, & val, NULL );
167     var_Change( p_intf, "repeat", VLC_VAR_INHERITVALUE, & val, NULL );
168
169     /* Create our "Manage" menu */
170     wxMenu *manage_menu = new wxMenu;
171     manage_menu->Append( AddFile_Event, wxU(_("&Simple Add...")) );
172     manage_menu->Append( AddMRL_Event, wxU(_("&Add MRL...")) );
173     manage_menu->AppendSeparator();
174     manage_menu->Append( Open_Event, wxU(_("&Open Playlist...")) );
175     manage_menu->Append( Save_Event, wxU(_("&Save Playlist...")) );
176     manage_menu->AppendSeparator();
177     manage_menu->Append( Close_Event, wxU(_("&Close")) );
178
179     /* Create our "Sort" menu */
180     wxMenu *sort_menu = new wxMenu;
181     sort_menu->Append( SortTitle_Event, wxU(_("Sort by &title")) );
182     sort_menu->Append( RSortTitle_Event, wxU(_("&Reverse sort by title")) );
183     sort_menu->AppendSeparator();
184     sort_menu->Append( SortAuthor_Event, wxU(_("Sort by &author")) );
185     sort_menu->Append( RSortAuthor_Event, wxU(_("&Reverse sort by author")) );
186     sort_menu->AppendSeparator();
187     sort_menu->Append( SortGroup_Event, wxU(_("Sort by &group")) );
188     sort_menu->Append( RSortGroup_Event, wxU(_("&Reverse sort by group")) );
189     sort_menu->AppendSeparator();
190     sort_menu->Append( Randomize_Event, wxU(_("&Randomize Playlist")) );
191
192     /* Create our "Selection" menu */
193     wxMenu *selection_menu = new wxMenu;
194     selection_menu->Append( EnableSelection_Event, wxU(_("&Enable")) );
195     selection_menu->Append( DisableSelection_Event, wxU(_("&Disable")) );
196     selection_menu->AppendSeparator();
197     selection_menu->Append( InvertSelection_Event, wxU(_("&Invert")) );
198     selection_menu->Append( DeleteSelection_Event, wxU(_("&Delete")) );
199     selection_menu->Append( SelectAll_Event, wxU(_("&Select All")) );
200
201     /* Create our "Group" menu */
202     wxMenu *group_menu = new wxMenu;
203     group_menu->Append( EnableGroup_Event, wxU(_("&Enable all group items")) );
204     group_menu->Append( DisableGroup_Event,
205                         wxU(_("&Disable all group items")) );
206
207     /* Append the freshly created menus to the menu bar */
208     wxMenuBar *menubar = new wxMenuBar( wxMB_DOCKABLE );
209     menubar->Append( manage_menu, wxU(_("&Manage")) );
210     menubar->Append( sort_menu, wxU(_("S&ort")) );
211     menubar->Append( selection_menu, wxU(_("&Selection")) );
212     menubar->Append( group_menu, wxU(_("&Groups")) );
213
214     /* Attach the menu bar to the frame */
215     SetMenuBar( menubar );
216
217
218     /* Create a panel to put everything in */
219     wxPanel *playlist_panel = new wxPanel( this, -1 );
220     playlist_panel->SetAutoLayout( TRUE );
221
222     /* Create the Random checkbox */
223     wxCheckBox *random_checkbox =
224         new wxCheckBox( playlist_panel, Random_Event, wxU(_("Random")) );
225     var_Get( p_intf, "random", &val );
226     vlc_bool_t b_random = val.b_bool;
227     random_checkbox->SetValue( b_random == VLC_FALSE ? 0 : 1 );
228
229     /* Create the Loop Checkbox */
230     wxCheckBox *loop_checkbox =
231         new wxCheckBox( playlist_panel, Loop_Event, wxU(_("Loop")) );
232     var_Get( p_intf, "loop", &val );
233     int b_loop = val.b_bool ;
234     loop_checkbox->SetValue( b_loop );
235
236     /* Create the Repeat one checkbox */
237     wxCheckBox *repeat_checkbox =
238         new wxCheckBox( playlist_panel, Repeat_Event, wxU(_("Repeat one")) );
239     var_Get( p_intf, "repeat", &val );
240     int b_repeat = val.b_bool ;
241     repeat_checkbox->SetValue( b_repeat );
242
243     /* Create the Search Textbox */
244     search_text =
245         new wxTextCtrl( playlist_panel, SearchText_Event, wxT(""),
246                         wxDefaultPosition, wxSize(140, -1),
247                         wxTE_PROCESS_ENTER);
248
249     /* Create the search button */
250     search_button =
251         new wxButton( playlist_panel, Search_Event, wxU(_("Search")) );
252
253
254     /* Create the listview */
255     /* FIXME: the given size is arbitrary, and prevents us from resizing
256      * the window to smaller dimensions. But the sizers don't seem to adjust
257      * themselves to the size of a listview, and with a wxDefaultSize the
258      * playlist window is ridiculously small */
259     listview = new wxListView( playlist_panel, ListView_Event,
260                                wxDefaultPosition, wxSize( 500, 300 ),
261                                wxLC_REPORT | wxSUNKEN_BORDER );
262     listview->InsertColumn( 0, wxU(_("Name")) );
263     listview->InsertColumn( 1, wxU(_("Author")) );
264     listview->InsertColumn( 2, wxU(_("Group")) );
265     listview->InsertColumn( 3, wxU(_("Duration")) );
266     listview->SetColumnWidth( 0, 270 );
267     listview->SetColumnWidth( 1, 150 );
268     listview->SetColumnWidth( 2, 80 );
269
270     /* Create the Up-Down buttons */
271     wxButton *up_button =
272         new wxButton( playlist_panel, Up_Event, wxU(_("Up") ) );
273
274     wxButton *down_button =
275         new wxButton( playlist_panel, Down_Event, wxU(_("Down") ) );
276
277     /* Create the iteminfo button */
278     wxButton *iteminfo_button =
279         new wxButton( playlist_panel, Infos_Event, wxU(_("Item Infos") ) );
280
281     /* Place everything in sizers */
282     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
283     button_sizer->Add( iteminfo_button, 0, wxALIGN_CENTER|wxLEFT , 5);
284     button_sizer->Layout();
285
286     wxBoxSizer *updown_sizer = new wxBoxSizer( wxHORIZONTAL );
287     updown_sizer->Add( up_button, 0, wxALIGN_LEFT|wxRIGHT, 3);
288     updown_sizer->Add( down_button, 0, wxALIGN_LEFT|wxLEFT, 3);
289     updown_sizer->Layout();
290
291     wxBoxSizer *checkbox_sizer = new wxBoxSizer( wxHORIZONTAL );
292     checkbox_sizer->Add( random_checkbox, 0,
293                          wxEXPAND | wxALIGN_RIGHT | wxALL, 5);
294     checkbox_sizer->Add( loop_checkbox, 0,
295                          wxEXPAND | wxALIGN_RIGHT | wxALL, 5);
296     checkbox_sizer->Add( repeat_checkbox, 0,
297                          wxEXPAND | wxALIGN_RIGHT | wxALL, 5);
298     checkbox_sizer->Layout();
299
300     wxBoxSizer *search_sizer = new wxBoxSizer( wxHORIZONTAL );
301     search_sizer->Add( search_text, 0, wxRIGHT|wxALIGN_CENTER, 3);
302     search_sizer->Add( search_button, 0, wxLEFT|wxALIGN_CENTER, 3);
303     search_sizer->Layout();
304
305     /* The top and bottom sizers */
306     wxBoxSizer *top_sizer = new wxBoxSizer( wxHORIZONTAL );
307     top_sizer->Add( checkbox_sizer, 1, wxLEFT|wxRIGHT|wxALIGN_LEFT, 4 );
308     top_sizer->Add( search_sizer, 1, wxLEFT|wxRIGHT|wxALIGN_RIGHT, 4 );
309     top_sizer->Layout();
310
311     wxBoxSizer *bottom_sizer = new wxBoxSizer( wxHORIZONTAL );
312     bottom_sizer->Add( updown_sizer, 0, wxEXPAND |wxRIGHT | wxLEFT | wxALIGN_LEFT, 4);
313     bottom_sizer->Add( button_sizer , 0, wxEXPAND|wxLEFT | wxRIGHT | wxALIGN_RIGHT, 4 );
314     bottom_sizer->Layout();
315
316     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
317
318     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
319     panel_sizer->Add( top_sizer, 0, wxEXPAND | wxALL, 5 );
320     panel_sizer->Add( listview, 1, wxEXPAND | wxALL, 5 );
321     panel_sizer->Add( bottom_sizer, 0 , wxEXPAND | wxALL, 5);
322     panel_sizer->Layout();
323
324     playlist_panel->SetSizerAndFit( panel_sizer );
325     main_sizer->Add( playlist_panel, 1, wxGROW, 0 );
326     main_sizer->Layout();
327     SetSizerAndFit( main_sizer );
328
329 #if !defined(__WXX11__)
330     /* Associate drop targets with the playlist */
331     SetDropTarget( new DragAndDrop( p_intf, VLC_TRUE ) );
332 #endif
333
334     playlist_t *p_playlist =
335         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
336                                        FIND_ANYWHERE );
337     if( p_playlist == NULL )
338     {
339         return;
340     }
341
342     /* We want to be noticed of playlist changes */
343     var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this );
344     vlc_object_release( p_playlist );
345
346     /* Update the playlist */
347     Rebuild();
348 }
349
350 Playlist::~Playlist()
351 {
352     playlist_t *p_playlist =
353         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
354                                        FIND_ANYWHERE );
355     if( p_playlist == NULL )
356     {
357         return;
358     }
359
360     delete iteminfo_dialog;
361
362     var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this );
363     vlc_object_release( p_playlist );
364 }
365
366 /**********************************************************************
367  * Rebuild the playlist
368  **********************************************************************/
369 void Playlist::Rebuild()
370 {
371     playlist_t *p_playlist =
372         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
373                                        FIND_ANYWHERE );
374     if( p_playlist == NULL )
375     {
376         return;
377     }
378
379     int i_focused = listview->GetFocusedItem();
380
381     /* Clear the list... */
382     listview->DeleteAllItems();
383
384     /* ...and rebuild it */
385     vlc_mutex_lock( &p_playlist->object_lock );
386     for( int i = 0; i < p_playlist->i_size; i++ )
387     {
388         wxString filename = wxU(p_playlist->pp_items[i]->psz_name);
389         listview->InsertItem( i, filename );
390         listview->SetItem( i, 1, wxU(p_playlist->pp_items[i]->psz_author));
391         listview->SetItem( i, 2,
392                  wxU(playlist_FindGroup(p_playlist,p_playlist->
393                                         pp_items[i]->i_group)));
394         if( p_playlist->pp_items[i]->b_enabled == VLC_FALSE )
395         {
396             wxListItem listitem;
397             listitem.m_itemId = i;
398             listitem.SetTextColour( *wxLIGHT_GREY);
399             listview->SetItem(listitem);
400         }
401         {
402             char psz_duration[MSTRTIME_MAX_SIZE];
403             mtime_t dur = p_playlist->pp_items[i]->i_duration;
404             if ( dur != -1 )
405             {
406                 secstotimestr( psz_duration, dur/1000000 );
407             }
408             else
409             {
410                 memcpy( psz_duration ,"-:--:--", sizeof("-:--:--"));
411             }
412             listview->SetItem( i, 3, wxU(psz_duration) );
413         }
414         
415     }
416     vlc_mutex_unlock( &p_playlist->object_lock );
417
418     /* Change the colour for the currenty played stream */
419     wxListItem listitem;
420     listitem.m_itemId = p_playlist->i_index;
421     listitem.SetTextColour( *wxRED );
422     listview->SetItem( listitem );
423
424     if( i_focused )
425     {
426         listview->Focus( i_focused );
427         listview->Select( i_focused );
428     }
429     else
430     {
431         listview->Focus( p_playlist->i_index );
432     }
433
434     vlc_object_release( p_playlist );
435 }
436
437 void Playlist::ShowPlaylist( bool show )
438 {
439     if( show ) Rebuild();
440     Show( show );
441 }
442
443 void Playlist::UpdatePlaylist()
444 {
445     vlc_bool_t b_need_update = VLC_FALSE;
446     i_update_counter++;
447
448     /* If the playlist isn't show there's no need to update it */
449     if( !IsShown() ) return;
450
451     vlc_mutex_lock( &lock );
452     if( this->b_need_update )
453     {
454         b_need_update =VLC_TRUE;
455         this->b_need_update = VLC_FALSE;
456     }
457     vlc_mutex_unlock( &lock );
458
459     if( b_need_update )
460     {
461         Rebuild();
462     }
463
464     /* Updating the playing status every 0.5s is enough */
465     if( i_update_counter % 5 ) return;
466
467     playlist_t *p_playlist =
468         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
469                                        FIND_ANYWHERE );
470     if( p_playlist == NULL )
471     {
472         return;
473     }
474
475     /* Update the colour of items */
476
477     vlc_mutex_lock( &p_playlist->object_lock );
478     if( p_intf->p_sys->i_playing != p_playlist->i_index )
479     {
480         wxListItem listitem;
481         listitem.m_itemId = p_playlist->i_index;
482         listitem.SetTextColour( *wxRED );
483         listview->SetItem( listitem );
484
485         if( p_intf->p_sys->i_playing != -1 )
486         {
487             listitem.m_itemId = p_intf->p_sys->i_playing;
488             listitem.SetTextColour( *wxBLACK );
489             listview->SetItem( listitem );
490         }
491         p_intf->p_sys->i_playing = p_playlist->i_index;
492     }
493     vlc_mutex_unlock( &p_playlist->object_lock );
494     vlc_object_release( p_playlist );
495 }
496
497 /*****************************************************************************
498  * Private methods.
499  *****************************************************************************/
500 void Playlist::DeleteItem( int item )
501 {
502     playlist_t *p_playlist =
503         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
504                                        FIND_ANYWHERE );
505     if( p_playlist == NULL )
506     {
507         return;
508     }
509
510     playlist_Delete( p_playlist, item );
511     listview->DeleteItem( item );
512
513     vlc_object_release( p_playlist );
514 }
515
516 void Playlist::OnClose( wxCommandEvent& WXUNUSED(event) )
517 {
518     Hide();
519 }
520
521 void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) )
522 {
523     playlist_t *p_playlist =
524         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
525                                        FIND_ANYWHERE );
526     if( p_playlist == NULL )
527     {
528         return;
529     }
530
531     wxFileDialog dialog( this, wxU(_("Save playlist")),
532                          wxT(""), wxT(""), wxT("*"), wxSAVE );
533
534     if( dialog.ShowModal() == wxID_OK )
535     {
536         playlist_SaveFile( p_playlist, dialog.GetPath().mb_str() );
537     }
538
539     vlc_object_release( p_playlist );
540 }
541
542 void Playlist::OnOpen( wxCommandEvent& WXUNUSED(event) )
543 {
544     playlist_t *p_playlist =
545         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
546                                        FIND_ANYWHERE );
547     if( p_playlist == NULL )
548     {
549         return;
550     }
551
552     wxFileDialog dialog( this, wxU(_("Open playlist")),
553                          wxT(""), wxT(""), wxT("*"), wxOPEN );
554
555     if( dialog.ShowModal() == wxID_OK )
556     {
557         playlist_LoadFile( p_playlist, dialog.GetPath().mb_str() );
558     }
559
560     vlc_object_release( p_playlist );
561 }
562
563 void Playlist::OnAddFile( wxCommandEvent& WXUNUSED(event) )
564 {
565     p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE_SIMPLE, 0, 0 );
566
567 #if 0
568     Rebuild();
569 #endif
570 }
571
572 void Playlist::OnAddMRL( wxCommandEvent& WXUNUSED(event) )
573 {
574     p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE, 0, 0 );
575
576 #if 0
577     Rebuild();
578 #endif
579 }
580
581 /********************************************************************
582  * Move functions
583  ********************************************************************/
584 void Playlist::OnUp( wxCommandEvent& event)
585 {
586     playlist_t *p_playlist =
587         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
588                                        FIND_ANYWHERE );
589     if( p_playlist == NULL )
590     {
591         return;
592     }
593
594     /* We use the first selected item, so find it */
595     long i_item = -1;
596     i_item = listview->GetNextItem(i_item,
597                      wxLIST_NEXT_ALL,
598                      wxLIST_STATE_SELECTED);
599     if( i_item > 0 && i_item < p_playlist->i_size )
600     {
601         playlist_Move( p_playlist , i_item, i_item - 1);
602         if( i_item > 1 )
603         {
604             listview->Focus( i_item - 1 );
605         }
606         else
607         {
608             listview->Focus(0);
609         }
610     }
611     vlc_object_release( p_playlist );
612     return;
613 }
614
615 void Playlist::OnDown( wxCommandEvent& event)
616 {
617     playlist_t *p_playlist =
618         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
619                                        FIND_ANYWHERE );
620     if( p_playlist == NULL )
621     {
622         return;
623     }
624
625     /* We use the first selected item, so find it */
626     long i_item = -1;
627     i_item = listview->GetNextItem(i_item,
628                      wxLIST_NEXT_ALL,
629                      wxLIST_STATE_SELECTED);
630     if( i_item >= 0 && i_item < p_playlist->i_size - 1 )
631     {
632         playlist_Move( p_playlist , i_item, i_item + 2 );
633         listview->Focus( i_item + 1 );
634     }
635     vlc_object_release( p_playlist );
636     return;
637 }
638
639 /********************************************************************
640  * Sorting functions
641  ********************************************************************/
642 void Playlist::OnSort( wxCommandEvent& event )
643 {
644     playlist_t *p_playlist =
645         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
646                                        FIND_ANYWHERE );
647     if( p_playlist == NULL )
648     {
649         return;
650     }
651     switch( event.GetId() )
652     {
653         case SortTitle_Event:
654            playlist_SortTitle( p_playlist , 0 );
655            break;
656         case RSortTitle_Event:
657            playlist_SortTitle( p_playlist , 1 );
658            break;
659         case SortAuthor_Event:
660            playlist_SortAuthor(p_playlist , 0 );
661            break;
662         case RSortAuthor_Event:
663            playlist_SortAuthor( p_playlist , 1 );
664            break;
665         case SortGroup_Event:
666            playlist_SortGroup( p_playlist , 0 );
667            break;
668         case RSortGroup_Event:
669            playlist_SortGroup( p_playlist , 1 );
670            break;
671         case Randomize_Event:
672            playlist_Sort( p_playlist , SORT_RANDOM, SORT_NORMAL );
673            break;
674     }
675     vlc_object_release( p_playlist );
676
677     Rebuild();
678
679     return;
680 }
681
682 void Playlist::OnColSelect( wxListEvent& event )
683 {
684     playlist_t *p_playlist =
685         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
686                                        FIND_ANYWHERE );
687     if( p_playlist == NULL )
688     {
689         return;
690     }
691     switch( event.GetColumn() )
692     {
693         case 0:
694             if( i_title_sorted != 1 )
695             {
696                 playlist_SortTitle( p_playlist, 0 );
697                 i_title_sorted = 1;
698             }
699             else
700             {
701                 playlist_SortTitle( p_playlist, 1 );
702                 i_title_sorted = -1;
703             }
704             break;
705         case 1:
706             if( i_author_sorted != 1 )
707             {
708                 playlist_SortAuthor( p_playlist, 0 );
709                 i_author_sorted = 1;
710             }
711             else
712             {
713                 playlist_SortAuthor( p_playlist, 1 );
714                 i_author_sorted = -1;
715             }
716             break;
717         case 2:
718             if( i_group_sorted != 1 )
719             {
720                 playlist_SortGroup( p_playlist, 0 );
721                 i_group_sorted = 1;
722             }
723             else
724             {
725                 playlist_SortGroup( p_playlist, 1 );
726                 i_group_sorted = -1;
727             }
728             break;
729         default:
730             break;
731     }
732     vlc_object_release( p_playlist );
733
734     Rebuild();
735
736     return;
737 }
738
739 /**********************************************************************
740  * Search functions
741  **********************************************************************/
742 void Playlist::OnSearchTextChange( wxCommandEvent& WXUNUSED(event) )
743 {
744    search_button->SetDefault();
745 }
746
747 void Playlist::OnSearch( wxCommandEvent& WXUNUSED(event) )
748 {
749     wxString search_string= search_text->GetValue();
750
751     int i_current;
752     int i_first = 0 ;
753     int i_item = -1;
754
755     for( i_current = 0 ; i_current <= listview->GetItemCount() ; i_current++ )
756     {
757         if( listview->GetItemState( i_current, wxLIST_STATE_SELECTED)
758                    == wxLIST_STATE_SELECTED )
759         {
760             i_first = i_current;
761             break;
762         }
763     }
764
765     for ( i_current = i_first + 1; i_current <= listview->GetItemCount() ;
766           i_current++ )
767     {
768         wxListItem listitem;
769         listitem.SetId( i_current );
770         listview->GetItem( listitem );
771         if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
772         {
773             i_item = i_current;
774             break;
775         }
776     }
777     for( long item = 0; item < listview->GetItemCount(); item++ )
778     {
779         listview->Select( item, FALSE );
780     }
781
782     wxListItem listitem;
783     listitem.SetId(i_item);
784     listitem.m_state = wxLIST_STATE_SELECTED;
785     listview->Select( i_item, TRUE );
786     listview->Focus( i_item );
787
788 }
789
790 /**********************************************************************
791  * Selection functions
792  **********************************************************************/
793 void Playlist::OnInvertSelection( wxCommandEvent& WXUNUSED(event) )
794 {
795     for( long item = 0; item < listview->GetItemCount(); item++ )
796     {
797         listview->Select( item, ! listview->IsSelected( item ) );
798     }
799 }
800
801 void Playlist::OnDeleteSelection( wxCommandEvent& WXUNUSED(event) )
802 {
803     /* Delete from the end to the beginning, to avoid a shift of indices */
804     for( long item = listview->GetItemCount() - 1; item >= 0; item-- )
805     {
806         if( listview->IsSelected( item ) )
807         {
808             DeleteItem( item );
809         }
810     }
811
812     Rebuild();
813 }
814
815 void Playlist::OnEnableSelection( 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     for( long item = listview->GetItemCount() - 1; item >= 0; item-- )
826     {
827         if( listview->IsSelected( item ) )
828         {
829             playlist_Enable( p_playlist, item );
830         }
831     }
832     vlc_object_release( p_playlist);
833     Rebuild();
834 }
835
836 void Playlist::OnDisableSelection( wxCommandEvent& WXUNUSED(event) )
837 {
838     playlist_t *p_playlist =
839         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
840                                        FIND_ANYWHERE );
841     if( p_playlist == NULL )
842     {
843         return;
844     }
845
846     for( long item = listview->GetItemCount() - 1; item >= 0; item-- )
847     {
848         if( listview->IsSelected( item ) )
849         {
850             playlist_Disable( p_playlist, item );
851         }
852     }
853     vlc_object_release( p_playlist);
854     Rebuild();
855 }
856
857 void Playlist::OnSelectAll( wxCommandEvent& WXUNUSED(event) )
858 {
859     for( long item = 0; item < listview->GetItemCount(); item++ )
860     {
861         listview->Select( item, TRUE );
862     }
863 }
864
865 /**********************************************************************
866  * Playlist mode functions
867  **********************************************************************/
868 void Playlist::OnRandom( wxCommandEvent& event )
869 {
870     vlc_value_t val;
871     val.b_bool = event.IsChecked();
872     playlist_t *p_playlist =
873         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
874                                        FIND_ANYWHERE );
875     if( p_playlist == NULL )
876     {
877         return;
878     }
879     var_Set( p_playlist , "random", val);
880     vlc_object_release( p_playlist );
881 }
882 void Playlist::OnLoop ( wxCommandEvent& event )
883 {
884     vlc_value_t val;
885     val.b_bool = event.IsChecked();
886     playlist_t *p_playlist =
887         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
888                                        FIND_ANYWHERE );
889     if( p_playlist == NULL )
890     {
891         return;
892     }
893     var_Set( p_playlist , "loop", val);
894     vlc_object_release( p_playlist );
895 }
896
897 void Playlist::OnRepeat ( wxCommandEvent& event )
898 {
899     vlc_value_t val;
900     val.b_bool = event.IsChecked();
901     playlist_t *p_playlist =
902         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
903                                        FIND_ANYWHERE );
904     if( p_playlist == NULL )
905     {
906         return;
907     }
908     var_Set( p_playlist , "repeat", val);
909     vlc_object_release( p_playlist );
910 }
911
912
913
914 void Playlist::OnActivateItem( wxListEvent& event )
915 {
916     playlist_t *p_playlist =
917         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
918                                        FIND_ANYWHERE );
919     if( p_playlist == NULL )
920     {
921         return;
922     }
923     playlist_Goto( p_playlist, event.GetIndex() );
924
925     vlc_object_release( p_playlist );
926 }
927 void Playlist::OnKeyDown( wxListEvent& event )
928 {
929     long keycode = event.GetKeyCode();
930     /* Delete selected items */
931     if( keycode == WXK_BACK || keycode == WXK_DELETE )
932     {
933         /* We send a dummy event */
934         OnDeleteSelection( event );
935     }
936 }
937
938 void Playlist::OnInfos( wxCommandEvent& WXUNUSED(event) )
939 {
940     playlist_t *p_playlist =
941         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
942                                        FIND_ANYWHERE );
943     if( p_playlist == NULL )
944     {
945         return;
946     }
947
948     if( iteminfo_dialog == NULL )
949     {
950         /* We use the first selected item, so find it */
951         long i_item = -1;
952         i_item = listview->GetNextItem(i_item,
953                          wxLIST_NEXT_ALL,
954                          wxLIST_STATE_SELECTED);
955         if( i_item >= 0 && i_item < p_playlist->i_size )
956         {
957             iteminfo_dialog = new ItemInfoDialog(
958                               p_intf, p_playlist->pp_items[i_item], this );
959             if( iteminfo_dialog->ShowModal()  == wxID_OK )
960                 Rebuild();
961             delete iteminfo_dialog;
962             iteminfo_dialog = NULL;
963         }
964     }
965     vlc_object_release( p_playlist );
966 }
967
968 void Playlist::OnEnDis( wxCommandEvent& event )
969 {
970     playlist_t *p_playlist =
971         (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
972                                        FIND_ANYWHERE );
973     if( p_playlist == NULL )
974     {
975         return;
976     }
977
978     long i_item = -1;
979     i_item = listview->GetNextItem(i_item,
980                        wxLIST_NEXT_ALL,
981                        wxLIST_STATE_SELECTED);
982
983     if( i_item >= 0 && i_item < p_playlist->i_size )
984     {
985        switch( event.GetId() )
986        {
987            case EnableGroup_Event:
988                playlist_EnableGroup( p_playlist ,
989                                   p_playlist->pp_items[i_item]->i_group );
990                break;
991            case DisableGroup_Event:
992                playlist_DisableGroup( p_playlist ,
993                                   p_playlist->pp_items[i_item]->i_group );
994                break;
995        }
996        Rebuild();
997     }
998
999     vlc_object_release( p_playlist );
1000 }
1001
1002 /*****************************************************************************
1003  * PlaylistChanged: callback triggered by the intf-change playlist variable
1004  *  We don't rebuild the playlist directly here because we don't want the
1005  *  caller to block for a too long time.
1006  *****************************************************************************/
1007 int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
1008                      vlc_value_t old_val, vlc_value_t new_val, void *param )
1009 {
1010     Playlist *p_playlist_dialog = (Playlist *)param;
1011     vlc_mutex_lock( &p_playlist_dialog->lock );
1012     p_playlist_dialog->b_need_update = VLC_TRUE;
1013     vlc_mutex_unlock( &p_playlist_dialog->lock );
1014     return VLC_SUCCESS;
1015 }
1016
1017
1018 /***************************************************************************
1019  * NewGroup
1020  ***************************************************************************/
1021 NewGroup::NewGroup( intf_thread_t *_p_intf, wxWindow *_p_parent ):
1022     wxDialog( _p_parent, -1, wxU(_("New Group")), wxDefaultPosition,
1023              wxDefaultSize, wxDEFAULT_FRAME_STYLE )
1024 {
1025     /* Initializations */
1026     p_intf = _p_intf;
1027     psz_name = NULL;
1028     SetIcon( *p_intf->p_sys->p_icon );
1029
1030     /* Create a panel to put everything in*/
1031     wxPanel *panel = new wxPanel( this, -1 );
1032     panel->SetAutoLayout( TRUE );
1033
1034     wxStaticText *group_label =
1035             new wxStaticText( panel , -1,
1036                 wxU(_("Enter the name for the new group")));
1037
1038     groupname = new wxTextCtrl(panel, -1, wxU(""),wxDefaultPosition,
1039                                wxSize(80,27),wxTE_PROCESS_ENTER);
1040
1041     wxButton *ok_button = new wxButton(panel, wxID_OK, wxU(_("OK")) );
1042     ok_button->SetDefault();
1043     wxButton *cancel_button = new wxButton( panel, wxID_CANCEL,
1044                                             wxU(_("Cancel")) );
1045
1046     wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
1047
1048     button_sizer->Add( ok_button, 0, wxALL, 5 );
1049     button_sizer->Add( cancel_button, 0, wxALL, 5 );
1050     button_sizer->Layout();
1051
1052     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
1053     panel_sizer->Add( group_label, 0, wxEXPAND | wxALL, 5 );
1054     panel_sizer->Add( groupname, 0, wxEXPAND | wxALL, 5 );
1055     panel_sizer->Add( button_sizer, 0, wxEXPAND | wxALL, 5 );
1056     panel_sizer->Layout();
1057
1058     panel->SetSizerAndFit( panel_sizer );
1059
1060     wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
1061     main_sizer->Add( panel, 1, wxEXPAND, 0 );
1062     main_sizer->Layout();
1063     SetSizerAndFit( main_sizer );
1064 }
1065
1066 NewGroup::~NewGroup()
1067 {
1068 }
1069
1070 void NewGroup::OnOk( wxCommandEvent& event )
1071 {
1072     psz_name = strdup( groupname->GetLineText(0).mb_str() );
1073
1074     playlist_t * p_playlist =
1075           (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
1076                                        FIND_ANYWHERE );
1077
1078     if( p_playlist )
1079     {
1080         if( !playlist_CreateGroup( p_playlist, psz_name ) )
1081         {
1082             psz_name = NULL;
1083         }
1084     }
1085
1086     vlc_object_release( p_playlist );
1087     EndModal( wxID_OK );
1088 }
1089
1090 void NewGroup::OnCancel( wxCommandEvent& WXUNUSED(event) )
1091 {
1092     EndModal( wxID_CANCEL );
1093 }