playlist.cpp 39.6 KB
Newer Older
1
/*****************************************************************************
gbazin's avatar
 
gbazin committed
2
 * playlist.cpp : wxWindows plugin for vlc
3
 *****************************************************************************
4
 * Copyright (C) 2000-2004 VideoLAN
gbazin's avatar
 
gbazin committed
5
 * $Id: playlist.cpp,v 1.44 2004/02/26 00:23:04 gbazin Exp $
6 7 8 9 10 11 12
 *
 * Authors: Olivier Teulire <ipkiss@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
gbazin's avatar
 
gbazin committed
13
 *
14 15 16 17 18 19 20 21 22 23 24 25 26
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
27
#include <vlc/vlc.h>
gbazin's avatar
 
gbazin committed
28
#include <vlc/intf.h>
29 30 31

#include "wxwindows.h"

gbazin's avatar
 
gbazin committed
32 33 34
/* Callback prototype */
int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
                     vlc_value_t old_val, vlc_value_t new_val, void *param );
zorglub's avatar
zorglub committed
35 36 37 38
int PlaylistNext( vlc_object_t *p_this, const char *psz_variable,
                     vlc_value_t old_val, vlc_value_t new_val, void *param );
int ItemChanged( vlc_object_t *p_this, const char *psz_variable,
                     vlc_value_t old_val, vlc_value_t new_val, void *param );
gbazin's avatar
 
gbazin committed
39

40 41 42 43 44 45 46 47
/*****************************************************************************
 * Event Table.
 *****************************************************************************/

/* IDs for the controls and the menu commands */
enum
{
    /* menu items */
gbazin's avatar
 
gbazin committed
48 49
    AddFile_Event = 1,
    AddMRL_Event,
50
    Close_Event,
gbazin's avatar
 
gbazin committed
51 52
    Open_Event,
    Save_Event,
53

zorglub's avatar
zorglub committed
54 55 56 57 58 59
    SortTitle_Event,
    RSortTitle_Event,
    SortAuthor_Event,
    RSortAuthor_Event,
    SortGroup_Event,
    RSortGroup_Event,
zorglub's avatar
zorglub committed
60
    Randomize_Event,
zorglub's avatar
zorglub committed
61

zorglub's avatar
zorglub committed
62 63 64
    EnableSelection_Event,
    DisableSelection_Event,

65 66
    InvertSelection_Event,
    DeleteSelection_Event,
67 68
    Random_Event,
    Loop_Event,
69
    Repeat_Event,
70 71
    SelectAll_Event,

zorglub's avatar
zorglub committed
72 73
    EnableGroup_Event,
    DisableGroup_Event,
zorglub's avatar
zorglub committed
74

zorglub's avatar
zorglub committed
75 76
    Up_Event,
    Down_Event,
zorglub's avatar
zorglub committed
77 78
    Infos_Event,

zorglub's avatar
zorglub committed
79 80 81 82 83
    PopupPlay_Event,
    PopupDel_Event,
    PopupEna_Event,
    PopupInfo_Event,

zorglub's avatar
zorglub committed
84 85 86
    SearchText_Event,
    Search_Event,

87
    /* controls */
zorglub's avatar
zorglub committed
88 89 90
    ListView_Event,

    Browse_Event,  /* For export playlist */
91 92 93

    /* custom events */
    UpdateItem_Event
94 95
};

96 97
DEFINE_LOCAL_EVENT_TYPE( wxEVT_PLAYLIST );

98 99
BEGIN_EVENT_TABLE(Playlist, wxFrame)
    /* Menu events */
gbazin's avatar
 
gbazin committed
100
    EVT_MENU(AddFile_Event, Playlist::OnAddFile)
gbazin's avatar
 
gbazin committed
101
    EVT_MENU(AddMRL_Event, Playlist::OnAddMRL)
102
    EVT_MENU(Close_Event, Playlist::OnClose)
gbazin's avatar
 
gbazin committed
103 104
    EVT_MENU(Open_Event, Playlist::OnOpen)
    EVT_MENU(Save_Event, Playlist::OnSave)
zorglub's avatar
zorglub committed
105 106 107 108 109 110 111 112

    EVT_MENU(SortTitle_Event, Playlist::OnSort)
    EVT_MENU(RSortTitle_Event, Playlist::OnSort)
    EVT_MENU(SortAuthor_Event, Playlist::OnSort)
    EVT_MENU(RSortAuthor_Event, Playlist::OnSort)
    EVT_MENU(SortGroup_Event, Playlist::OnSort)
    EVT_MENU(RSortGroup_Event, Playlist::OnSort)

zorglub's avatar
zorglub committed
113 114
    EVT_MENU(Randomize_Event, Playlist::OnSort)

zorglub's avatar
zorglub committed
115 116
    EVT_MENU(EnableSelection_Event, Playlist::OnEnableSelection)
    EVT_MENU(DisableSelection_Event, Playlist::OnDisableSelection)
117 118 119
    EVT_MENU(InvertSelection_Event, Playlist::OnInvertSelection)
    EVT_MENU(DeleteSelection_Event, Playlist::OnDeleteSelection)
    EVT_MENU(SelectAll_Event, Playlist::OnSelectAll)
zorglub's avatar
zorglub committed
120
    EVT_MENU(Infos_Event, Playlist::OnInfos)
121
    EVT_CHECKBOX(Random_Event, Playlist::OnRandom)
122
    EVT_CHECKBOX(Repeat_Event, Playlist::OnRepeat)
123
    EVT_CHECKBOX(Loop_Event, Playlist::OnLoop)
124

zorglub's avatar
zorglub committed
125 126 127
    EVT_MENU(EnableGroup_Event, Playlist::OnEnDis)
    EVT_MENU(DisableGroup_Event, Playlist::OnEnDis)

128 129
    /* Listview events */
    EVT_LIST_ITEM_ACTIVATED(ListView_Event, Playlist::OnActivateItem)
sigmunau's avatar
sigmunau committed
130
    EVT_LIST_COL_CLICK(ListView_Event, Playlist::OnColSelect)
131
    EVT_LIST_KEY_DOWN(ListView_Event, Playlist::OnKeyDown)
zorglub's avatar
zorglub committed
132 133 134 135 136 137 138 139
    EVT_LIST_ITEM_RIGHT_CLICK(ListView_Event, Playlist::OnPopup)

    /* Popup events */
    EVT_MENU( PopupPlay_Event, Playlist::OnPopupPlay)
    EVT_MENU( PopupDel_Event, Playlist::OnPopupDel)
    EVT_MENU( PopupEna_Event, Playlist::OnPopupEna)
    EVT_MENU( PopupInfo_Event, Playlist::OnPopupInfo)

140 141

    /* Button events */
zorglub's avatar
zorglub committed
142
    EVT_BUTTON( Search_Event, Playlist::OnSearch)
gbazin's avatar
 
gbazin committed
143
    EVT_BUTTON( Save_Event, Playlist::OnSave)
zorglub's avatar
zorglub committed
144
    EVT_BUTTON( Infos_Event, Playlist::OnInfos)
145

zorglub's avatar
zorglub committed
146 147 148
    EVT_BUTTON( Up_Event, Playlist::OnUp)
    EVT_BUTTON( Down_Event, Playlist::OnDown)

zorglub's avatar
zorglub committed
149 150
    EVT_TEXT(SearchText_Event, Playlist::OnSearchTextChange)

151 152 153
    /* Custom events */
    EVT_COMMAND(-1, wxEVT_PLAYLIST, Playlist::OnPlaylistEvent)

154 155 156 157 158
    /* Special events : we don't want to destroy the window when the user
     * clicks on (X) */
    EVT_CLOSE(Playlist::OnClose)
END_EVENT_TABLE()

zorglub's avatar
zorglub committed
159 160 161 162 163 164 165

/* Event Table for the Newgroup class */
BEGIN_EVENT_TABLE(NewGroup, wxDialog)
    EVT_BUTTON( wxID_OK, NewGroup::OnOk)
    EVT_BUTTON( wxID_CANCEL, NewGroup::OnCancel)
END_EVENT_TABLE()

zorglub's avatar
zorglub committed
166

167 168 169
/*****************************************************************************
 * Constructor.
 *****************************************************************************/
gbazin's avatar
 
gbazin committed
170 171
Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
    wxFrame( p_parent, -1, wxU(_("Playlist")), wxDefaultPosition,
gbazin's avatar
 
gbazin committed
172
             wxDefaultSize, wxDEFAULT_FRAME_STYLE )
173
{
gbazin's avatar
 
gbazin committed
174 175
    vlc_value_t val;

176
    /* Initializations */
zorglub's avatar
zorglub committed
177
    iteminfo_dialog = NULL;
178
    p_intf = _p_intf;
gbazin's avatar
 
gbazin committed
179
    i_update_counter = 0;
zorglub's avatar
zorglub committed
180
    i_sort_mode = MODE_NONE;
gbazin's avatar
 
gbazin committed
181 182
    b_need_update = VLC_FALSE;
    vlc_mutex_init( p_intf, &lock );
gbazin's avatar
 
gbazin committed
183
    SetIcon( *p_intf->p_sys->p_icon );
184

185 186 187
    i_title_sorted = 0;
    i_author_sorted = 0;
    i_group_sorted = 0;
zorglub's avatar
zorglub committed
188
    i_duration_sorted = 0;
189

hartman's avatar
hartman committed
190 191 192
    var_Create( p_intf, "random", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_intf, "loop", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_intf, "repeat", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );;
193

194 195
    /* Create our "Manage" menu */
    wxMenu *manage_menu = new wxMenu;
gbazin's avatar
 
gbazin committed
196
    manage_menu->Append( AddFile_Event, wxU(_("&Simple Add...")) );
gbazin's avatar
 
gbazin committed
197
    manage_menu->Append( AddMRL_Event, wxU(_("&Add MRL...")) );
zorglub's avatar
zorglub committed
198
    manage_menu->AppendSeparator();
gbazin's avatar
 
gbazin committed
199 200
    manage_menu->Append( Open_Event, wxU(_("&Open Playlist...")) );
    manage_menu->Append( Save_Event, wxU(_("&Save Playlist...")) );
201
    manage_menu->AppendSeparator();
gbazin's avatar
 
gbazin committed
202
    manage_menu->Append( Close_Event, wxU(_("&Close")) );
203

zorglub's avatar
zorglub committed
204 205
    /* Create our "Sort" menu */
    wxMenu *sort_menu = new wxMenu;
zorglub's avatar
zorglub committed
206
    sort_menu->Append( SortTitle_Event, wxU(_("Sort by &title")) );
zorglub's avatar
zorglub committed
207 208
    sort_menu->Append( RSortTitle_Event, wxU(_("&Reverse sort by title")) );
    sort_menu->AppendSeparator();
zorglub's avatar
zorglub committed
209
    sort_menu->Append( SortAuthor_Event, wxU(_("Sort by &author")) );
hartman's avatar
hartman committed
210
    sort_menu->Append( RSortAuthor_Event, wxU(_("Reverse sort by author")) );
zorglub's avatar
zorglub committed
211
    sort_menu->AppendSeparator();
zorglub's avatar
zorglub committed
212
    sort_menu->Append( SortGroup_Event, wxU(_("Sort by &group")) );
hartman's avatar
hartman committed
213
    sort_menu->Append( RSortGroup_Event, wxU(_("Reverse sort by group")) );
zorglub's avatar
zorglub committed
214
    sort_menu->AppendSeparator();
hartman's avatar
hartman committed
215
    sort_menu->Append( Randomize_Event, wxU(_("&Shuffle Playlist")) );
zorglub's avatar
zorglub committed
216

217 218
    /* Create our "Selection" menu */
    wxMenu *selection_menu = new wxMenu;
zorglub's avatar
zorglub committed
219 220 221
    selection_menu->Append( EnableSelection_Event, wxU(_("&Enable")) );
    selection_menu->Append( DisableSelection_Event, wxU(_("&Disable")) );
    selection_menu->AppendSeparator();
gbazin's avatar
 
gbazin committed
222
    selection_menu->Append( InvertSelection_Event, wxU(_("&Invert")) );
hartman's avatar
hartman committed
223
    selection_menu->Append( DeleteSelection_Event, wxU(_("D&elete")) );
gbazin's avatar
 
gbazin committed
224
    selection_menu->Append( SelectAll_Event, wxU(_("&Select All")) );
225

zorglub's avatar
zorglub committed
226 227 228 229 230 231
    /* Create our "Group" menu */
    wxMenu *group_menu = new wxMenu;
    group_menu->Append( EnableGroup_Event, wxU(_("&Enable all group items")) );
    group_menu->Append( DisableGroup_Event,
                        wxU(_("&Disable all group items")) );

232 233
    /* Append the freshly created menus to the menu bar */
    wxMenuBar *menubar = new wxMenuBar( wxMB_DOCKABLE );
gbazin's avatar
 
gbazin committed
234
    menubar->Append( manage_menu, wxU(_("&Manage")) );
zorglub's avatar
zorglub committed
235
    menubar->Append( sort_menu, wxU(_("S&ort")) );
gbazin's avatar
 
gbazin committed
236
    menubar->Append( selection_menu, wxU(_("&Selection")) );
zorglub's avatar
zorglub committed
237
    menubar->Append( group_menu, wxU(_("&Groups")) );
238 239 240 241

    /* Attach the menu bar to the frame */
    SetMenuBar( menubar );

zorglub's avatar
zorglub committed
242 243
    /* Create the popup menu */
    popup_menu = new wxMenu;
hartman's avatar
hartman committed
244 245
    popup_menu->Append( PopupPlay_Event, wxU(_("Play")) );
    popup_menu->Append( PopupDel_Event, wxU(_("Delete")) );
zorglub's avatar
zorglub committed
246
    popup_menu->Append( PopupEna_Event, wxU(_("Toggle enabled")) );
hartman's avatar
hartman committed
247
    popup_menu->Append( PopupInfo_Event, wxU(_("Info")) );
zorglub's avatar
zorglub committed
248

gbazin's avatar
 
gbazin committed
249 250 251 252
    /* Create a panel to put everything in */
    wxPanel *playlist_panel = new wxPanel( this, -1 );
    playlist_panel->SetAutoLayout( TRUE );

253
    /* Create the Random checkbox */
zorglub's avatar
zorglub committed
254
    wxCheckBox *random_checkbox =
255
        new wxCheckBox( playlist_panel, Random_Event, wxU(_("Random")) );
gbazin's avatar
 
gbazin committed
256
    var_Get( p_intf, "random", &val );
257
    vlc_bool_t b_random = val.b_bool;
gbazin's avatar
 
gbazin committed
258
    random_checkbox->SetValue( b_random == VLC_FALSE ? 0 : 1 );
259 260

    /* Create the Loop Checkbox */
zorglub's avatar
zorglub committed
261
    wxCheckBox *loop_checkbox =
hartman's avatar
hartman committed
262
        new wxCheckBox( playlist_panel, Loop_Event, wxU(_("Repeat All")) );
263
    var_Get( p_intf, "loop", &val );
zorglub's avatar
zorglub committed
264
    int b_loop = val.b_bool ;
265
    loop_checkbox->SetValue( b_loop );
266

267
    /* Create the Repeat one checkbox */
zorglub's avatar
zorglub committed
268
    wxCheckBox *repeat_checkbox =
hartman's avatar
hartman committed
269
        new wxCheckBox( playlist_panel, Repeat_Event, wxU(_("Repeat One")) );
270
    var_Get( p_intf, "repeat", &val );
zorglub's avatar
zorglub committed
271
    int b_repeat = val.b_bool ;
272 273
    repeat_checkbox->SetValue( b_repeat );

zorglub's avatar
zorglub committed
274 275
    /* Create the Search Textbox */
    search_text =
zorglub's avatar
zorglub committed
276
        new wxTextCtrl( playlist_panel, SearchText_Event, wxT(""),
gbazin's avatar
 
gbazin committed
277
                        wxDefaultPosition, wxSize(140, -1),
zorglub's avatar
zorglub committed
278
                        wxTE_PROCESS_ENTER);
zorglub's avatar
zorglub committed
279 280

    /* Create the search button */
zorglub's avatar
zorglub committed
281 282
    search_button =
        new wxButton( playlist_panel, Search_Event, wxU(_("Search")) );
zorglub's avatar
zorglub committed
283

284

zorglub's avatar
zorglub committed
285 286 287 288 289 290 291 292 293 294
    /* Create the listview */
    /* FIXME: the given size is arbitrary, and prevents us from resizing
     * the window to smaller dimensions. But the sizers don't seem to adjust
     * themselves to the size of a listview, and with a wxDefaultSize the
     * playlist window is ridiculously small */
    listview = new wxListView( playlist_panel, ListView_Event,
                               wxDefaultPosition, wxSize( 500, 300 ),
                               wxLC_REPORT | wxSUNKEN_BORDER );
    listview->InsertColumn( 0, wxU(_("Name")) );
    listview->InsertColumn( 1, wxU(_("Author")) );
zorglub's avatar
zorglub committed
295 296
    listview->InsertColumn( 2, wxU(_("Duration")) );
    listview->InsertColumn( 3, wxU(_("Group")) );
zorglub's avatar
zorglub committed
297 298 299 300 301 302 303 304 305 306 307 308
    listview->SetColumnWidth( 0, 270 );
    listview->SetColumnWidth( 1, 150 );
    listview->SetColumnWidth( 2, 80 );

    /* Create the Up-Down buttons */
    wxButton *up_button =
        new wxButton( playlist_panel, Up_Event, wxU(_("Up") ) );

    wxButton *down_button =
        new wxButton( playlist_panel, Down_Event, wxU(_("Down") ) );

    /* Create the iteminfo button */
zorglub's avatar
zorglub committed
309
    wxButton *iteminfo_button =
Sam Hocevar's avatar
Sam Hocevar committed
310
        new wxButton( playlist_panel, Infos_Event, wxU(_("Item info") ) );
zorglub's avatar
zorglub committed
311

zorglub's avatar
zorglub committed
312 313 314
    /* Place everything in sizers */
    wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
    button_sizer->Add( iteminfo_button, 0, wxALIGN_CENTER|wxLEFT , 5);
315 316
    button_sizer->Layout();

zorglub's avatar
zorglub committed
317 318 319 320
    wxBoxSizer *updown_sizer = new wxBoxSizer( wxHORIZONTAL );
    updown_sizer->Add( up_button, 0, wxALIGN_LEFT|wxRIGHT, 3);
    updown_sizer->Add( down_button, 0, wxALIGN_LEFT|wxLEFT, 3);
    updown_sizer->Layout();
zorglub's avatar
zorglub committed
321 322 323

    wxBoxSizer *checkbox_sizer = new wxBoxSizer( wxHORIZONTAL );
    checkbox_sizer->Add( random_checkbox, 0,
gbazin's avatar
 
gbazin committed
324
                         wxEXPAND | wxALIGN_RIGHT | wxALL, 5);
zorglub's avatar
zorglub committed
325
    checkbox_sizer->Add( loop_checkbox, 0,
gbazin's avatar
 
gbazin committed
326
                         wxEXPAND | wxALIGN_RIGHT | wxALL, 5);
zorglub's avatar
zorglub committed
327
    checkbox_sizer->Add( repeat_checkbox, 0,
gbazin's avatar
 
gbazin committed
328
                         wxEXPAND | wxALIGN_RIGHT | wxALL, 5);
zorglub's avatar
zorglub committed
329 330 331
    checkbox_sizer->Layout();

    wxBoxSizer *search_sizer = new wxBoxSizer( wxHORIZONTAL );
zorglub's avatar
zorglub committed
332 333
    search_sizer->Add( search_text, 0, wxRIGHT|wxALIGN_CENTER, 3);
    search_sizer->Add( search_button, 0, wxLEFT|wxALIGN_CENTER, 3);
zorglub's avatar
zorglub committed
334 335
    search_sizer->Layout();

zorglub's avatar
zorglub committed
336 337
    /* The top and bottom sizers */
    wxBoxSizer *top_sizer = new wxBoxSizer( wxHORIZONTAL );
gbazin's avatar
 
gbazin committed
338 339
    top_sizer->Add( checkbox_sizer, 1, wxLEFT|wxRIGHT|wxALIGN_LEFT, 4 );
    top_sizer->Add( search_sizer, 1, wxLEFT|wxRIGHT|wxALIGN_RIGHT, 4 );
zorglub's avatar
zorglub committed
340
    top_sizer->Layout();
zorglub's avatar
zorglub committed
341

zorglub's avatar
zorglub committed
342
    wxBoxSizer *bottom_sizer = new wxBoxSizer( wxHORIZONTAL );
gbazin's avatar
 
gbazin committed
343 344 345 346
    bottom_sizer->Add( updown_sizer, 0,
                       wxEXPAND |wxRIGHT | wxLEFT | wxALIGN_LEFT, 4 );
    bottom_sizer->Add( button_sizer , 0,
                       wxEXPAND|wxLEFT | wxRIGHT | wxALIGN_RIGHT, 4 );
347 348
    bottom_sizer->Layout();

349
    wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
zorglub's avatar
zorglub committed
350

gbazin's avatar
 
gbazin committed
351
    wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
zorglub's avatar
zorglub committed
352
    panel_sizer->Add( top_sizer, 0, wxEXPAND | wxALL, 5 );
gbazin's avatar
 
gbazin committed
353
    panel_sizer->Add( listview, 1, wxEXPAND | wxALL, 5 );
zorglub's avatar
zorglub committed
354
    panel_sizer->Add( bottom_sizer, 0 , wxEXPAND | wxALL, 5);
gbazin's avatar
 
gbazin committed
355
    panel_sizer->Layout();
zorglub's avatar
zorglub committed
356

gbazin's avatar
 
gbazin committed
357 358 359
    playlist_panel->SetSizerAndFit( panel_sizer );
    main_sizer->Add( playlist_panel, 1, wxGROW, 0 );
    main_sizer->Layout();
360
    SetSizerAndFit( main_sizer );
gbazin's avatar
 
gbazin committed
361

gbazin's avatar
 
gbazin committed
362
#if !defined(__WXX11__)
gbazin's avatar
 
gbazin committed
363
    /* Associate drop targets with the playlist */
gbazin's avatar
 
gbazin committed
364
    SetDropTarget( new DragAndDrop( p_intf, VLC_TRUE ) );
gbazin's avatar
 
gbazin committed
365
#endif
gbazin's avatar
 
gbazin committed
366

gbazin's avatar
 
gbazin committed
367 368 369 370 371 372 373 374
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

zorglub's avatar
zorglub committed
375
    /* We want to be noticed of playlist changes */
zorglub's avatar
zorglub committed
376 377

    /* Some global changes happened -> Rebuild all */
gbazin's avatar
 
gbazin committed
378
    var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this );
zorglub's avatar
zorglub committed
379 380 381 382 383 384 385 386

    /* We went to the next item */
    var_AddCallback( p_playlist, "playlist-current", PlaylistNext, this );

    /* One item has been updated */
    var_AddCallback( p_playlist, "item-change", ItemChanged, this );


gbazin's avatar
 
gbazin committed
387 388
    vlc_object_release( p_playlist );

gbazin's avatar
 
gbazin committed
389 390
    /* Update the playlist */
    Rebuild();
391 392 393 394
}

Playlist::~Playlist()
{
gbazin's avatar
 
gbazin committed
395 396 397 398 399 400 401 402
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

zorglub's avatar
zorglub committed
403 404
    delete iteminfo_dialog;

hartman's avatar
hartman committed
405 406
    var_DelCallback( p_playlist, "item-change", ItemChanged, this );
    var_DelCallback( p_playlist, "playlist-current", PlaylistNext, this );
gbazin's avatar
 
gbazin committed
407 408
    var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this );
    vlc_object_release( p_playlist );
409 410
}

zorglub's avatar
zorglub committed
411 412 413 414 415
/**********************************************************************
 * Update one playlist item
 **********************************************************************/
void Playlist::UpdateItem( int i )
{
gbazin's avatar
 
gbazin committed
416 417
    if( i < 0 ) return; /* Sanity check */

zorglub's avatar
zorglub committed
418 419 420
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
421

zorglub's avatar
zorglub committed
422 423 424 425
    if( p_playlist == NULL )
    {
        return;
    }
426 427 428 429

    playlist_item_t *p_item = playlist_ItemGetByPos( p_playlist, i );

    if( !p_item )
zorglub's avatar
zorglub committed
430 431 432 433
    {
        vlc_object_release(p_playlist);
        return;
    }
434 435 436

    listview->SetItem( i, 0, wxL2U(p_item->psz_name) );
    listview->SetItem( i, 1, wxU( playlist_ItemGetInfo( p_item,
zorglub's avatar
zorglub committed
437
                                       _("General") , _("Author") ) ) );
sigmunau's avatar
sigmunau committed
438
    char *psz_group = playlist_FindGroup(p_playlist,
439
                                         p_item->i_group);
zorglub's avatar
zorglub committed
440
    listview->SetItem( i, 3,
zorglub's avatar
zorglub committed
441
             wxL2U( psz_group ? psz_group : _("Normal") ) );
zorglub's avatar
zorglub committed
442

443
    if( p_item->b_enabled == VLC_FALSE )
zorglub's avatar
zorglub committed
444 445 446 447 448 449 450 451
    {
        wxListItem listitem;
        listitem.m_itemId = i;
        listitem.SetTextColour( *wxLIGHT_GREY);
        listview->SetItem(listitem);
    }

    char psz_duration[MSTRTIME_MAX_SIZE];
452
    mtime_t dur = p_item->i_duration;
zorglub's avatar
zorglub committed
453 454
    if( dur != -1 ) secstotimestr( psz_duration, dur/1000000 );
    else memcpy( psz_duration , "-:--:--", sizeof("-:--:--") );
zorglub's avatar
zorglub committed
455
    listview->SetItem( i, 2, wxU(psz_duration) );
zorglub's avatar
zorglub committed
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472

    /* Change the colour for the currenty played stream */
    wxListItem listitem;
    listitem.m_itemId = i;
    if( i == p_playlist->i_index )
    {
        listitem.SetTextColour( *wxRED );
    }
    else
    {
        listitem.SetTextColour( *wxBLACK );
    }
    listview->SetItem( listitem );

    vlc_object_release(p_playlist);
}

zorglub's avatar
zorglub committed
473 474 475
/**********************************************************************
 * Rebuild the playlist
 **********************************************************************/
476 477 478 479 480 481 482 483 484 485
void Playlist::Rebuild()
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

zorglub's avatar
zorglub committed
486 487
    int i_focused = listview->GetFocusedItem();

488 489 490 491 492 493 494
    /* Clear the list... */
    listview->DeleteAllItems();

    /* ...and rebuild it */
    vlc_mutex_lock( &p_playlist->object_lock );
    for( int i = 0; i < p_playlist->i_size; i++ )
    {
gbazin's avatar
 
gbazin committed
495
        wxString filename = wxL2U(p_playlist->pp_items[i]->psz_name);
496
        listview->InsertItem( i, filename );
zorglub's avatar
zorglub committed
497
        UpdateItem( i );
498 499 500
    }
    vlc_mutex_unlock( &p_playlist->object_lock );

gbazin's avatar
 
gbazin committed
501
    if( i_focused >= 0 && i_focused < p_playlist->i_size )
zorglub's avatar
zorglub committed
502 503 504 505
    {
        listview->Focus( i_focused );
        listview->Select( i_focused );
    }
gbazin's avatar
 
gbazin committed
506
    else if( p_playlist->i_index >= 0 )
zorglub's avatar
zorglub committed
507 508 509
    {
        listview->Focus( p_playlist->i_index );
    }
510

511 512 513
    vlc_object_release( p_playlist );
}

gbazin's avatar
 
gbazin committed
514
void Playlist::ShowPlaylist( bool show )
515
{
gbazin's avatar
 
gbazin committed
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
    if( show ) Rebuild();
    Show( show );
}

void Playlist::UpdatePlaylist()
{
    vlc_bool_t b_need_update = VLC_FALSE;
    i_update_counter++;

    /* If the playlist isn't show there's no need to update it */
    if( !IsShown() ) return;

    vlc_mutex_lock( &lock );
    if( this->b_need_update )
    {
gbazin's avatar
 
gbazin committed
531
        b_need_update = VLC_TRUE;
gbazin's avatar
 
gbazin committed
532 533 534 535
        this->b_need_update = VLC_FALSE;
    }
    vlc_mutex_unlock( &lock );

zorglub's avatar
zorglub committed
536 537 538 539
    if( b_need_update )
    {
        Rebuild();
    }
gbazin's avatar
 
gbazin committed
540 541 542 543

    /* Updating the playing status every 0.5s is enough */
    if( i_update_counter % 5 ) return;

544 545 546 547 548 549 550 551
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

gbazin's avatar
 
gbazin committed
552
    /* Update the colour of items */
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
    vlc_mutex_lock( &p_playlist->object_lock );
    if( p_intf->p_sys->i_playing != p_playlist->i_index )
    {
        wxListItem listitem;
        listitem.m_itemId = p_playlist->i_index;
        listitem.SetTextColour( *wxRED );
        listview->SetItem( listitem );

        if( p_intf->p_sys->i_playing != -1 )
        {
            listitem.m_itemId = p_intf->p_sys->i_playing;
            listitem.SetTextColour( *wxBLACK );
            listview->SetItem( listitem );
        }
        p_intf->p_sys->i_playing = p_playlist->i_index;
    }
    vlc_mutex_unlock( &p_playlist->object_lock );
gbazin's avatar
 
gbazin committed
570

571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597
    vlc_object_release( p_playlist );
}

/*****************************************************************************
 * Private methods.
 *****************************************************************************/
void Playlist::DeleteItem( int item )
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

    playlist_Delete( p_playlist, item );
    listview->DeleteItem( item );

    vlc_object_release( p_playlist );
}

void Playlist::OnClose( wxCommandEvent& WXUNUSED(event) )
{
    Hide();
}

gbazin's avatar
 
gbazin committed
598 599
void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) )
{
sigmunau's avatar
sigmunau committed
600 601 602 603 604 605 606 607 608
    struct {
        char *psz_desc;
        char *psz_filter;
        char *psz_module;
    } formats[] = {{ _("M3U file"), "*.m3u", "export-m3u" },
                   { _("PLS file"), "*.pls", "export-pls" }};
    wxString filter = wxT("");
    for( unsigned int i = 0; i < sizeof(formats)/sizeof(formats[0]); i++)
    {
gbazin's avatar
 
gbazin committed
609
        filter.Append( wxU(formats[i].psz_desc) );
sigmunau's avatar
sigmunau committed
610
        filter.Append( wxT("|") );
gbazin's avatar
 
gbazin committed
611
        filter.Append( wxU(formats[i].psz_filter) );
sigmunau's avatar
sigmunau committed
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631
        filter.Append( wxT("|") );
    }
    wxFileDialog dialog( this, wxU(_("Save playlist")),
                         wxT(""), wxT(""), filter, wxSAVE );

    if( dialog.ShowModal() == wxID_OK )
    {

        playlist_t * p_playlist =
            (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                           FIND_ANYWHERE );

        if( p_playlist )
        {
            if( dialog.GetFilename().mb_str() )
            {
                playlist_Export( p_playlist, dialog.GetFilename().mb_str(),
                                 formats[dialog.GetFilterIndex()].psz_module );
            }
        }
632

sigmunau's avatar
sigmunau committed
633
        vlc_object_release( p_playlist );
634

sigmunau's avatar
sigmunau committed
635
    }
gbazin's avatar
 
gbazin committed
636 637 638
}

void Playlist::OnOpen( wxCommandEvent& WXUNUSED(event) )
639
{
gbazin's avatar
 
gbazin committed
640 641 642 643 644 645 646 647
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

gbazin's avatar
 
gbazin committed
648 649
    wxFileDialog dialog( this, wxU(_("Open playlist")), wxT(""), wxT(""),
        wxT("All playlists|*.pls;*.m3u;*.asx;*.b4s|M3U files|*.m3u"), wxOPEN );
gbazin's avatar
 
gbazin committed
650 651 652

    if( dialog.ShowModal() == wxID_OK )
    {
zorglub's avatar
zorglub committed
653
        playlist_Import( p_playlist, dialog.GetPath().mb_str() );
gbazin's avatar
 
gbazin committed
654 655 656
    }

    vlc_object_release( p_playlist );
657 658
}

gbazin's avatar
 
gbazin committed
659 660
void Playlist::OnAddFile( wxCommandEvent& WXUNUSED(event) )
{
gbazin's avatar
 
gbazin committed
661
    p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE_SIMPLE, 0, 0 );
gbazin's avatar
 
gbazin committed
662

gbazin's avatar
 
gbazin committed
663
#if 0
gbazin's avatar
 
gbazin committed
664
    Rebuild();
gbazin's avatar
 
gbazin committed
665
#endif
gbazin's avatar
 
gbazin committed
666 667
}

gbazin's avatar
 
gbazin committed
668
void Playlist::OnAddMRL( wxCommandEvent& WXUNUSED(event) )
669
{
gbazin's avatar
 
gbazin committed
670
    p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE, 0, 0 );
gbazin's avatar
 
gbazin committed
671

gbazin's avatar
 
gbazin committed
672
#if 0
gbazin's avatar
 
gbazin committed
673
    Rebuild();
gbazin's avatar
 
gbazin committed
674
#endif
675 676
}

zorglub's avatar
zorglub committed
677 678 679
/********************************************************************
 * Move functions
 ********************************************************************/
gbazin's avatar
 
gbazin committed
680
void Playlist::OnUp( wxCommandEvent& event )
zorglub's avatar
zorglub committed
681 682 683 684 685 686 687 688 689
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

zorglub's avatar
zorglub committed
690
    /* We use the first selected item, so find it */
gbazin's avatar
 
gbazin committed
691
    long i_item = listview->GetNextItem( -1, wxLIST_NEXT_ALL,
gbazin's avatar
 
gbazin committed
692
                                         wxLIST_STATE_SELECTED);
zorglub's avatar
zorglub committed
693 694
    if( i_item > 0 && i_item < p_playlist->i_size )
    {
gbazin's avatar
 
gbazin committed
695 696
        playlist_Move( p_playlist, i_item, i_item - 1 );
        listview->Focus( i_item - 1 );
zorglub's avatar
zorglub committed
697
    }
zorglub's avatar
zorglub committed
698 699 700 701
    vlc_object_release( p_playlist );
    return;
}

gbazin's avatar
 
gbazin committed
702
void Playlist::OnDown( wxCommandEvent& event )
zorglub's avatar
zorglub committed
703 704 705 706 707 708 709 710 711
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

zorglub's avatar
zorglub committed
712
    /* We use the first selected item, so find it */
gbazin's avatar
 
gbazin committed
713
    long i_item = listview->GetNextItem( -1, wxLIST_NEXT_ALL,
gbazin's avatar
 
gbazin committed
714
                                         wxLIST_STATE_SELECTED );
zorglub's avatar
zorglub committed
715 716 717 718 719 720 721 722
    if( i_item >= 0 && i_item < p_playlist->i_size - 1 )
    {
        playlist_Move( p_playlist , i_item, i_item + 2 );
        listview->Focus( i_item + 1 );
    }
    vlc_object_release( p_playlist );
    return;
}
zorglub's avatar
zorglub committed
723

zorglub's avatar
zorglub committed
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
/********************************************************************
 * Sorting functions
 ********************************************************************/
void Playlist::OnSort( wxCommandEvent& event )
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }
    switch( event.GetId() )
    {
        case SortTitle_Event:
hartman's avatar
hartman committed
739
           playlist_SortTitle( p_playlist , ORDER_NORMAL );
zorglub's avatar
zorglub committed
740 741
           break;
        case RSortTitle_Event:
hartman's avatar
hartman committed
742
           playlist_SortTitle( p_playlist , ORDER_REVERSE );
zorglub's avatar
zorglub committed
743 744
           break;
        case SortAuthor_Event:
hartman's avatar
hartman committed
745
           playlist_SortAuthor(p_playlist , ORDER_NORMAL );
zorglub's avatar
zorglub committed
746 747
           break;
        case RSortAuthor_Event:
hartman's avatar
hartman committed
748
           playlist_SortAuthor( p_playlist , ORDER_REVERSE );
zorglub's avatar
zorglub committed
749 750
           break;
        case SortGroup_Event:
hartman's avatar
hartman committed
751
           playlist_SortGroup( p_playlist , ORDER_NORMAL );
zorglub's avatar
zorglub committed
752 753
           break;
        case RSortGroup_Event:
hartman's avatar
hartman committed
754
           playlist_SortGroup( p_playlist , ORDER_REVERSE );
zorglub's avatar
zorglub committed
755
           break;
zorglub's avatar
zorglub committed
756
        case Randomize_Event:
757
           playlist_Sort( p_playlist , SORT_RANDOM, ORDER_NORMAL );
zorglub's avatar
zorglub committed
758
           break;
zorglub's avatar
zorglub committed
759
    }
zorglub's avatar
zorglub committed
760 761 762 763 764 765 766
    vlc_object_release( p_playlist );

    Rebuild();

    return;
}

sigmunau's avatar
sigmunau committed
767 768 769 770 771 772 773 774 775 776 777 778
void Playlist::OnColSelect( wxListEvent& event )
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }
    switch( event.GetColumn() )
    {
        case 0:
779 780
            if( i_title_sorted != 1 )
            {
hartman's avatar
hartman committed
781
                playlist_SortTitle( p_playlist, ORDER_NORMAL );
782 783 784 785
                i_title_sorted = 1;
            }
            else
            {
hartman's avatar
hartman committed
786
                playlist_SortTitle( p_playlist, ORDER_REVERSE );
787 788
                i_title_sorted = -1;
            }
sigmunau's avatar
sigmunau committed
789 790
            break;
        case 1:
791 792
            if( i_author_sorted != 1 )
            {
hartman's avatar
hartman committed
793
                playlist_SortAuthor( p_playlist, ORDER_NORMAL );
794 795 796 797
                i_author_sorted = 1;
            }
            else
            {
hartman's avatar
hartman committed
798
                playlist_SortAuthor( p_playlist, ORDER_REVERSE );
799 800
                i_author_sorted = -1;
            }
sigmunau's avatar
sigmunau committed
801 802
            break;
        case 2:
zorglub's avatar
zorglub committed
803 804 805 806 807 808 809 810 811 812 813 814
            if( i_duration_sorted != 1 )
            {
                playlist_Sort( p_playlist, SORT_DURATION, ORDER_NORMAL );
                i_duration_sorted = 1;
            }
            else
            {
                playlist_Sort( p_playlist, SORT_DURATION, ORDER_REVERSE );
                i_duration_sorted = -1;
            }
            break;
        case 3:
815 816
            if( i_group_sorted != 1 )
            {
hartman's avatar
hartman committed
817
                playlist_SortGroup( p_playlist, ORDER_NORMAL );
818 819 820 821
                i_group_sorted = 1;
            }
            else
            {
hartman's avatar
hartman committed
822
                playlist_SortGroup( p_playlist, ORDER_REVERSE );
823 824
                i_group_sorted = -1;
            }
sigmunau's avatar
sigmunau committed
825 826 827 828 829 830 831 832 833 834 835
            break;
        default:
            break;
    }
    vlc_object_release( p_playlist );

    Rebuild();

    return;
}

zorglub's avatar
zorglub committed
836 837 838
/**********************************************************************
 * Search functions
 **********************************************************************/
zorglub's avatar
zorglub committed
839 840
void Playlist::OnSearchTextChange( wxCommandEvent& WXUNUSED(event) )
{
zorglub's avatar
zorglub committed
841
   search_button->SetDefault();
zorglub's avatar
zorglub committed
842 843 844 845
}

void Playlist::OnSearch( wxCommandEvent& WXUNUSED(event) )
{
gbazin's avatar
 
gbazin committed
846
    wxString search_string = search_text->GetValue();
zorglub's avatar
zorglub committed
847 848

    int i_current;
zorglub's avatar
zorglub committed
849
    int i_first = 0 ;
zorglub's avatar
zorglub committed
850 851
    int i_item = -1;

gbazin's avatar
 
gbazin committed
852
    for( i_current = 0; i_current < listview->GetItemCount(); i_current++ )
zorglub's avatar
zorglub committed
853
    {
gbazin's avatar
 
gbazin committed
854 855
        if( listview->GetItemState( i_current, wxLIST_STATE_SELECTED ) ==
              wxLIST_STATE_SELECTED )
zorglub's avatar
zorglub committed
856 857 858 859
        {
            i_first = i_current;
            break;
        }
zorglub's avatar
zorglub committed
860 861
    }

gbazin's avatar
 
gbazin committed
862 863
    for( i_current = i_first + 1; i_current < listview->GetItemCount();
         i_current++ )
zorglub's avatar
zorglub committed
864
    {
zorglub's avatar
zorglub committed
865 866 867 868 869 870 871 872
        wxListItem listitem;
        listitem.SetId( i_current );
        listview->GetItem( listitem );
        if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
        {
            i_item = i_current;
            break;
        }
zorglub's avatar
zorglub committed
873
    }
gbazin's avatar
 
gbazin committed
874 875 876

    if( i_item < 0 || i_item >= listview->GetItemCount() ) return;

zorglub's avatar
zorglub committed
877 878 879 880
    for( long item = 0; item < listview->GetItemCount(); item++ )
    {
        listview->Select( item, FALSE );
    }
zorglub's avatar
zorglub committed
881

zorglub's avatar
zorglub committed
882 883 884 885 886 887 888 889
    wxListItem listitem;
    listitem.SetId(i_item);
    listitem.m_state = wxLIST_STATE_SELECTED;
    listview->Select( i_item, TRUE );
    listview->Focus( i_item );

}

zorglub's avatar
zorglub committed
890 891 892
/**********************************************************************
 * Selection functions
 **********************************************************************/
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914
void Playlist::OnInvertSelection( wxCommandEvent& WXUNUSED(event) )
{
    for( long item = 0; item < listview->GetItemCount(); item++ )
    {
        listview->Select( item, ! listview->IsSelected( item ) );
    }
}

void Playlist::OnDeleteSelection( wxCommandEvent& WXUNUSED(event) )
{
    /* Delete from the end to the beginning, to avoid a shift of indices */
    for( long item = listview->GetItemCount() - 1; item >= 0; item-- )
    {
        if( listview->IsSelected( item ) )
        {
            DeleteItem( item );
        }
    }

    Rebuild();
}

zorglub's avatar
zorglub committed
915 916 917 918 919 920 921 922 923 924 925 926 927 928
void Playlist::OnEnableSelection( wxCommandEvent& WXUNUSED(event) )
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

    for( long item = listview->GetItemCount() - 1; item >= 0; item-- )
    {
        if( listview->IsSelected( item ) )
        {
929
            /*XXX*/
zorglub's avatar
zorglub committed
930
            playlist_Enable( p_playlist, item );
zorglub's avatar
zorglub committed
931
            UpdateItem( item );
zorglub's avatar
zorglub committed
932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950
        }
    }
    vlc_object_release( p_playlist);
}

void Playlist::OnDisableSelection( wxCommandEvent& WXUNUSED