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