playlist.cpp 32.7 KB
Newer Older
1
/*****************************************************************************
Gildas Bazin's avatar
 
Gildas Bazin committed
2
 * playlist.cpp : wxWindows plugin for vlc
3 4
 *****************************************************************************
 * Copyright (C) 2000-2001 VideoLAN
5
 * $Id: playlist.cpp,v 1.25 2003/11/21 13:20:41 zorglub 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.
Gildas Bazin's avatar
 
Gildas Bazin committed
13
 *
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
 * 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
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
#include <errno.h>                                                 /* ENOMEM */
#include <string.h>                                            /* strerror() */
#include <stdio.h>

Gildas Bazin's avatar
 
Gildas Bazin committed
32
#include <vlc/vlc.h>
Gildas Bazin's avatar
 
Gildas Bazin committed
33
#include <vlc/intf.h>
34 35

#include "wxwindows.h"
36
#include <wx/listctrl.h>
37

Gildas Bazin's avatar
 
Gildas Bazin committed
38 39 40 41
/* 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 );

42 43 44 45 46 47 48 49
/*****************************************************************************
 * Event Table.
 *****************************************************************************/

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

56 57 58 59 60 61 62
    SortTitle_Event,
    RSortTitle_Event,
    SortAuthor_Event,
    RSortAuthor_Event,
    SortGroup_Event,
    RSortGroup_Event,

Clément Stenac's avatar
Clément Stenac committed
63 64 65
    EnableSelection_Event,
    DisableSelection_Event,

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

73 74
    EnableGroup_Event,
    DisableGroup_Event,
Clément Stenac's avatar
Clément Stenac committed
75

76 77
    Up_Event,
    Down_Event,
Clément Stenac's avatar
Clément Stenac committed
78 79
    Infos_Event,

Clément Stenac's avatar
Clément Stenac committed
80 81 82
    SearchText_Event,
    Search_Event,

83 84 85 86 87 88
    /* controls */
    ListView_Event
};

BEGIN_EVENT_TABLE(Playlist, wxFrame)
    /* Menu events */
Gildas Bazin's avatar
 
Gildas Bazin committed
89
    EVT_MENU(AddFile_Event, Playlist::OnAddFile)
Gildas Bazin's avatar
 
Gildas Bazin committed
90
    EVT_MENU(AddMRL_Event, Playlist::OnAddMRL)
91
    EVT_MENU(Close_Event, Playlist::OnClose)
Gildas Bazin's avatar
 
Gildas Bazin committed
92 93
    EVT_MENU(Open_Event, Playlist::OnOpen)
    EVT_MENU(Save_Event, Playlist::OnSave)
94 95 96 97 98 99 100 101

    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)

Clément Stenac's avatar
Clément Stenac committed
102 103
    EVT_MENU(EnableSelection_Event, Playlist::OnEnableSelection)
    EVT_MENU(DisableSelection_Event, Playlist::OnDisableSelection)
104 105 106
    EVT_MENU(InvertSelection_Event, Playlist::OnInvertSelection)
    EVT_MENU(DeleteSelection_Event, Playlist::OnDeleteSelection)
    EVT_MENU(SelectAll_Event, Playlist::OnSelectAll)
Clément Stenac's avatar
Clément Stenac committed
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 113 114
    EVT_MENU(EnableGroup_Event, Playlist::OnEnDis)
    EVT_MENU(DisableGroup_Event, Playlist::OnEnDis)

115 116
    /* Listview events */
    EVT_LIST_ITEM_ACTIVATED(ListView_Event, Playlist::OnActivateItem)
117
    EVT_LIST_COL_CLICK(ListView_Event, Playlist::OnColSelect)
118 119 120
    EVT_LIST_KEY_DOWN(ListView_Event, Playlist::OnKeyDown)

    /* Button events */
Clément Stenac's avatar
Clément Stenac committed
121
    EVT_BUTTON( Search_Event, Playlist::OnSearch)
Gildas Bazin's avatar
 
Gildas Bazin committed
122
    EVT_BUTTON( Save_Event, Playlist::OnSave)
Clément Stenac's avatar
Clément Stenac committed
123
    EVT_BUTTON( Infos_Event, Playlist::OnInfos)
124

125 126 127
    EVT_BUTTON( Up_Event, Playlist::OnUp)
    EVT_BUTTON( Down_Event, Playlist::OnDown)

Clément Stenac's avatar
Clément Stenac committed
128 129
    EVT_TEXT(SearchText_Event, Playlist::OnSearchTextChange)

130 131 132 133 134
    /* Special events : we don't want to destroy the window when the user
     * clicks on (X) */
    EVT_CLOSE(Playlist::OnClose)
END_EVENT_TABLE()

135 136 137 138 139 140 141

/* 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()

142 143 144
/*****************************************************************************
 * Constructor.
 *****************************************************************************/
Gildas Bazin's avatar
 
Gildas Bazin committed
145 146
Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
    wxFrame( p_parent, -1, wxU(_("Playlist")), wxDefaultPosition,
Gildas Bazin's avatar
 
Gildas Bazin committed
147
             wxDefaultSize, wxDEFAULT_FRAME_STYLE )
148 149
{
    /* Initializations */
Clément Stenac's avatar
Clément Stenac committed
150
    iteminfo_dialog = NULL;
151
    p_intf = _p_intf;
152
    vlc_value_t  val;
Gildas Bazin's avatar
 
Gildas Bazin committed
153
    i_update_counter = 0;
154
    i_sort_mode = MODE_NONE;
Gildas Bazin's avatar
 
Gildas Bazin committed
155 156
    b_need_update = VLC_FALSE;
    vlc_mutex_init( p_intf, &lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
157
    SetIcon( *p_intf->p_sys->p_icon );
158

159 160 161 162 163
    i_title_sorted = 0;
    i_author_sorted = 0;
    i_group_sorted = 0;


164 165 166 167 168 169 170
    var_Create( p_intf, "random", VLC_VAR_BOOL );
    var_Change( p_intf, "random", VLC_VAR_INHERITVALUE, & val, NULL );
    var_Create( p_intf, "loop", VLC_VAR_BOOL );
    var_Create( p_intf, "loop", VLC_VAR_BOOL );
    var_Change( p_intf, "repeat", VLC_VAR_INHERITVALUE, & val, NULL );
    var_Change( p_intf, "repeat", VLC_VAR_INHERITVALUE, & val, NULL );

171 172
    /* Create our "Manage" menu */
    wxMenu *manage_menu = new wxMenu;
Gildas Bazin's avatar
 
Gildas Bazin committed
173
    manage_menu->Append( AddFile_Event, wxU(_("&Simple Add...")) );
Gildas Bazin's avatar
 
Gildas Bazin committed
174
    manage_menu->Append( AddMRL_Event, wxU(_("&Add MRL...")) );
175
    manage_menu->AppendSeparator();
Gildas Bazin's avatar
 
Gildas Bazin committed
176 177
    manage_menu->Append( Open_Event, wxU(_("&Open Playlist...")) );
    manage_menu->Append( Save_Event, wxU(_("&Save Playlist...")) );
178
    manage_menu->AppendSeparator();
Gildas Bazin's avatar
 
Gildas Bazin committed
179
    manage_menu->Append( Close_Event, wxU(_("&Close")) );
180

181 182 183 184 185 186 187 188 189 190 191
    /* Create our "Sort" menu */
    wxMenu *sort_menu = new wxMenu;
    sort_menu->Append( SortTitle_Event, wxU(_("&Sort by title")) );
    sort_menu->Append( RSortTitle_Event, wxU(_("&Reverse sort by title")) );
    sort_menu->AppendSeparator();
    sort_menu->Append( SortAuthor_Event, wxU(_("&Sort by author")) );
    sort_menu->Append( RSortAuthor_Event, wxU(_("&Reverse sort by author")) );
    sort_menu->AppendSeparator();
    sort_menu->Append( SortGroup_Event, wxU(_("&Sort by group")) );
    sort_menu->Append( RSortGroup_Event, wxU(_("&Reverse sort by group")) );

192 193
    /* Create our "Selection" menu */
    wxMenu *selection_menu = new wxMenu;
Clément Stenac's avatar
Clément Stenac committed
194 195 196
    selection_menu->Append( EnableSelection_Event, wxU(_("&Enable")) );
    selection_menu->Append( DisableSelection_Event, wxU(_("&Disable")) );
    selection_menu->AppendSeparator();
Gildas Bazin's avatar
 
Gildas Bazin committed
197 198 199
    selection_menu->Append( InvertSelection_Event, wxU(_("&Invert")) );
    selection_menu->Append( DeleteSelection_Event, wxU(_("&Delete")) );
    selection_menu->Append( SelectAll_Event, wxU(_("&Select All")) );
200

201 202 203 204 205 206
    /* 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")) );

207 208
    /* Append the freshly created menus to the menu bar */
    wxMenuBar *menubar = new wxMenuBar( wxMB_DOCKABLE );
Gildas Bazin's avatar
 
Gildas Bazin committed
209
    menubar->Append( manage_menu, wxU(_("&Manage")) );
210
    menubar->Append( sort_menu, wxU(_("S&ort")) );
Gildas Bazin's avatar
 
Gildas Bazin committed
211
    menubar->Append( selection_menu, wxU(_("&Selection")) );
212
    menubar->Append( group_menu, wxU(_("&Groups")) );
213 214 215 216

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

217

Gildas Bazin's avatar
 
Gildas Bazin committed
218 219 220 221
    /* Create a panel to put everything in */
    wxPanel *playlist_panel = new wxPanel( this, -1 );
    playlist_panel->SetAutoLayout( TRUE );

222
    /* Create the Random checkbox */
Clément Stenac's avatar
Clément Stenac committed
223
    wxCheckBox *random_checkbox =
224
        new wxCheckBox( playlist_panel, Random_Event, wxU(_("Random")) );
225 226 227
    var_Get( p_intf, "random", &val);
    vlc_bool_t b_random = val.b_bool;
    random_checkbox->SetValue( b_random == VLC_FALSE ? 0 : 1);
228 229

    /* Create the Loop Checkbox */
Clément Stenac's avatar
Clément Stenac committed
230
    wxCheckBox *loop_checkbox =
231
        new wxCheckBox( playlist_panel, Loop_Event, wxU(_("Loop")) );
232
    var_Get( p_intf, "loop", &val );
Clément Stenac's avatar
Clément Stenac committed
233
    int b_loop = val.b_bool ;
234
    loop_checkbox->SetValue( b_loop );
235

236
    /* Create the Repeat one checkbox */
Clément Stenac's avatar
Clément Stenac committed
237 238
    wxCheckBox *repeat_checkbox =
        new wxCheckBox( playlist_panel, Repeat_Event, wxU(_("Repeat one")) );
239
    var_Get( p_intf, "repeat", &val );
Clément Stenac's avatar
Clément Stenac committed
240
    int b_repeat = val.b_bool ;
241 242
    repeat_checkbox->SetValue( b_repeat );

Clément Stenac's avatar
Clément Stenac committed
243 244
    /* Create the Search Textbox */
    search_text =
Clément Stenac's avatar
Clément Stenac committed
245 246 247
        new wxTextCtrl( playlist_panel, SearchText_Event, wxT(""),
                        wxDefaultPosition, wxSize( 140, -1),
                        wxTE_PROCESS_ENTER);
Clément Stenac's avatar
Clément Stenac committed
248 249

    /* Create the search button */
Clément Stenac's avatar
Clément Stenac committed
250 251
    search_button =
        new wxButton( playlist_panel, Search_Event, wxU(_("Search")) );
Clément Stenac's avatar
Clément Stenac committed
252

253

254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279
    /* 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")) );
    #if 0
        listview->InsertColumn( 1, wxU(_("Duration")) );
    #endif
    listview->InsertColumn( 1, wxU(_("Author")) );
    listview->InsertColumn( 2, wxU(_("Group")) );
    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 */
Clément Stenac's avatar
Clément Stenac committed
280 281
    wxButton *iteminfo_button =
        new wxButton( playlist_panel, Infos_Event, wxU(_("Item Infos") ) );
282

Clément Stenac's avatar
Clément Stenac committed
283 284 285
    /* Place everything in sizers */
    wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );
    button_sizer->Add( iteminfo_button, 0, wxALIGN_CENTER|wxLEFT , 5);
286 287
    button_sizer->Layout();

288 289 290 291
    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();
Clément Stenac's avatar
Clément Stenac committed
292 293 294 295 296 297 298 299 300 301 302

    wxBoxSizer *checkbox_sizer = new wxBoxSizer( wxHORIZONTAL );
    checkbox_sizer->Add( random_checkbox, 0,
                       wxEXPAND|wxALIGN_RIGHT, 5);
    checkbox_sizer->Add( loop_checkbox, 0,
                       wxEXPAND|wxALIGN_RIGHT, 5);
    checkbox_sizer->Add( repeat_checkbox, 0,
                       wxEXPAND|wxALIGN_RIGHT, 5);
    checkbox_sizer->Layout();

    wxBoxSizer *search_sizer = new wxBoxSizer( wxHORIZONTAL );
303 304
    search_sizer->Add( search_text, 0, wxRIGHT|wxALIGN_CENTER, 3);
    search_sizer->Add( search_button, 0, wxLEFT|wxALIGN_CENTER, 3);
Clément Stenac's avatar
Clément Stenac committed
305 306
    search_sizer->Layout();

307 308 309 310 311
    /* The top and bottom sizers */
    wxBoxSizer *top_sizer = new wxBoxSizer( wxHORIZONTAL );
    top_sizer->Add( checkbox_sizer, 0, wxLEFT|wxRIGHT|wxALIGN_LEFT, 4 );
    top_sizer->Add( search_sizer, 0, wxLEFT|wxRIGHT|wxALIGN_RIGHT, 4 );
    top_sizer->Layout();
Clément Stenac's avatar
Clément Stenac committed
312

313 314 315
    wxBoxSizer *bottom_sizer = new wxBoxSizer( wxHORIZONTAL );
    bottom_sizer->Add( updown_sizer, 0, wxEXPAND |wxRIGHT | wxLEFT | wxALIGN_LEFT, 4);
    bottom_sizer->Add( button_sizer , 0, wxEXPAND|wxLEFT | wxRIGHT | wxALIGN_RIGHT, 4 );
316 317
    bottom_sizer->Layout();

318
    wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
Clément Stenac's avatar
Clément Stenac committed
319

Gildas Bazin's avatar
 
Gildas Bazin committed
320
    wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
321
    panel_sizer->Add( top_sizer, 0, wxEXPAND | wxALL, 5 );
Gildas Bazin's avatar
 
Gildas Bazin committed
322
    panel_sizer->Add( listview, 1, wxEXPAND | wxALL, 5 );
323
    panel_sizer->Add( bottom_sizer, 0 , wxEXPAND | wxALL, 5);
Gildas Bazin's avatar
 
Gildas Bazin committed
324
    panel_sizer->Layout();
Clément Stenac's avatar
Clément Stenac committed
325

Gildas Bazin's avatar
 
Gildas Bazin committed
326 327 328
    playlist_panel->SetSizerAndFit( panel_sizer );
    main_sizer->Add( playlist_panel, 1, wxGROW, 0 );
    main_sizer->Layout();
329
    SetSizerAndFit( main_sizer );
Gildas Bazin's avatar
 
Gildas Bazin committed
330

Gildas Bazin's avatar
 
Gildas Bazin committed
331
#if !defined(__WXX11__)
Gildas Bazin's avatar
 
Gildas Bazin committed
332 333
    /* Associate drop targets with the playlist */
    SetDropTarget( new DragAndDrop( p_intf ) );
Gildas Bazin's avatar
 
Gildas Bazin committed
334
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
335

Gildas Bazin's avatar
 
Gildas Bazin committed
336 337 338 339 340 341 342 343
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

344
    /* We want to be noticed of playlist changes */
Gildas Bazin's avatar
 
Gildas Bazin committed
345 346 347
    var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this );
    vlc_object_release( p_playlist );

Gildas Bazin's avatar
 
Gildas Bazin committed
348 349
    /* Update the playlist */
    Rebuild();
350 351 352 353
}

Playlist::~Playlist()
{
Gildas Bazin's avatar
 
Gildas Bazin committed
354 355 356 357 358 359 360 361
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

Clément Stenac's avatar
Clément Stenac committed
362 363
    delete iteminfo_dialog;

Gildas Bazin's avatar
 
Gildas Bazin committed
364 365
    var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this );
    vlc_object_release( p_playlist );
366 367
}

368 369 370
/**********************************************************************
 * Rebuild the playlist
 **********************************************************************/
371 372 373 374 375 376 377 378 379 380
void Playlist::Rebuild()
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

381 382
    int i_focused = listview->GetFocusedItem();

383 384 385 386 387 388 389
    /* 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++ )
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
390
        wxString filename = wxU(p_playlist->pp_items[i]->psz_name);
391
        listview->InsertItem( i, filename );
392 393 394 395
        listview->SetItem( i, 1, wxU(p_playlist->pp_items[i]->psz_author));
        listview->SetItem( i, 2,
                 wxU(playlist_FindGroup(p_playlist,p_playlist->
                                        pp_items[i]->i_group)));
Clément Stenac's avatar
Clément Stenac committed
396 397 398 399 400 401 402
        if( p_playlist->pp_items[i]->b_enabled == VLC_FALSE )
        {
            wxListItem listitem;
            listitem.m_itemId = i;
            listitem.SetTextColour( *wxLIGHT_GREY);
            listview->SetItem(listitem);
        }
403
        /* FIXME: we should try to find the actual duration... */
Clément Stenac's avatar
Clément Stenac committed
404 405 406 407
        /* While we don't use it, hide it, it's ugly */
        #if 0
            listview->SetItem( i, 1, wxU(_("no info")) );
        #endif
408 409 410 411 412 413 414 415 416
    }
    vlc_mutex_unlock( &p_playlist->object_lock );

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

417 418 419 420 421 422 423 424 425
    if( i_focused )
    {
        listview->Focus( i_focused );
        listview->Select( i_focused );
    }
    else
    {
        listview->Focus( p_playlist->i_index );
    }
426

427 428 429
    vlc_object_release( p_playlist );
}

Gildas Bazin's avatar
 
Gildas Bazin committed
430
void Playlist::ShowPlaylist( bool show )
431
{
Gildas Bazin's avatar
 
Gildas Bazin committed
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446
    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 )
    {
447
        b_need_update =VLC_TRUE;
Gildas Bazin's avatar
 
Gildas Bazin committed
448 449 450 451
        this->b_need_update = VLC_FALSE;
    }
    vlc_mutex_unlock( &lock );

452 453 454 455
    if( b_need_update )
    {
        Rebuild();
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
456 457 458 459

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

460 461 462 463 464 465 466 467
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
468
    /* Update the colour of items */
469

470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513
    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 );
    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();
}

Gildas Bazin's avatar
 
Gildas Bazin committed
514 515 516 517 518 519 520 521 522 523 524
void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) )
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

    wxFileDialog dialog( this, wxU(_("Save playlist")),
Gildas Bazin's avatar
 
Gildas Bazin committed
525
                         wxT(""), wxT(""), wxT("*"), wxSAVE );
Gildas Bazin's avatar
 
Gildas Bazin committed
526 527 528 529 530 531 532 533 534 535

    if( dialog.ShowModal() == wxID_OK )
    {
        playlist_SaveFile( p_playlist, dialog.GetPath().mb_str() );
    }

    vlc_object_release( p_playlist );
}

void Playlist::OnOpen( wxCommandEvent& WXUNUSED(event) )
536
{
Gildas Bazin's avatar
 
Gildas Bazin committed
537 538 539 540 541 542 543 544 545
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

    wxFileDialog dialog( this, wxU(_("Open playlist")),
Gildas Bazin's avatar
 
Gildas Bazin committed
546
                         wxT(""), wxT(""), wxT("*"), wxOPEN );
Gildas Bazin's avatar
 
Gildas Bazin committed
547 548 549 550 551 552 553

    if( dialog.ShowModal() == wxID_OK )
    {
        playlist_LoadFile( p_playlist, dialog.GetPath().mb_str() );
    }

    vlc_object_release( p_playlist );
554 555
}

Gildas Bazin's avatar
 
Gildas Bazin committed
556 557
void Playlist::OnAddFile( wxCommandEvent& WXUNUSED(event) )
{
Gildas Bazin's avatar
 
Gildas Bazin committed
558
    p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE_SIMPLE, 0, 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
559

Gildas Bazin's avatar
 
Gildas Bazin committed
560
#if 0
Gildas Bazin's avatar
 
Gildas Bazin committed
561
    Rebuild();
Gildas Bazin's avatar
 
Gildas Bazin committed
562
#endif
Gildas Bazin's avatar
 
Gildas Bazin committed
563 564
}

Gildas Bazin's avatar
 
Gildas Bazin committed
565
void Playlist::OnAddMRL( wxCommandEvent& WXUNUSED(event) )
566
{
Gildas Bazin's avatar
 
Gildas Bazin committed
567
    p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE, 0, 0 );
Gildas Bazin's avatar
 
Gildas Bazin committed
568

Gildas Bazin's avatar
 
Gildas Bazin committed
569
#if 0
Gildas Bazin's avatar
 
Gildas Bazin committed
570
    Rebuild();
Gildas Bazin's avatar
 
Gildas Bazin committed
571
#endif
572 573
}

574 575 576 577
/********************************************************************
 * Move functions
 ********************************************************************/
void Playlist::OnUp( wxCommandEvent& event)
Clément Stenac's avatar
Clément Stenac committed
578 579 580 581 582 583 584 585 586
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
    /* We use the first selected item, so find it */
    long i_item = -1;
    i_item = listview->GetNextItem(i_item,
                     wxLIST_NEXT_ALL,
                     wxLIST_STATE_SELECTED);
    if( i_item > 0 && i_item < p_playlist->i_size )
    {
        playlist_Move( p_playlist , i_item, i_item - 1);
        if( i_item > 1 )
        {
            listview->Focus( i_item - 1 );
        }
        else
        {
            listview->Focus(0);
        }
    }
Clément Stenac's avatar
Clément Stenac committed
604 605 606 607
    vlc_object_release( p_playlist );
    return;
}

608
void Playlist::OnDown( wxCommandEvent& event)
Clément Stenac's avatar
Clément Stenac committed
609 610 611 612 613 614 615 616 617
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

618 619 620 621 622 623 624 625 626 627 628 629 630
    /* We use the first selected item, so find it */
    long i_item = -1;
    i_item = listview->GetNextItem(i_item,
                     wxLIST_NEXT_ALL,
                     wxLIST_STATE_SELECTED);
    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;
}
Clément Stenac's avatar
Clément Stenac committed
631

632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
/********************************************************************
 * 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:
           playlist_SortTitle( p_playlist , 0 );
           break;
        case RSortTitle_Event:
           playlist_SortTitle( p_playlist , 1 );
           break;
        case SortAuthor_Event:
           playlist_SortAuthor(p_playlist , 0 );
           break;
        case RSortAuthor_Event:
           playlist_SortAuthor( p_playlist , 1 );
           break;
        case SortGroup_Event:
           playlist_SortGroup( p_playlist , 0 );
           break;
        case RSortGroup_Event:
           playlist_SortGroup( p_playlist , 1 );
           break;
    }
Clément Stenac's avatar
Clément Stenac committed
665 666 667 668 669 670 671
    vlc_object_release( p_playlist );

    Rebuild();

    return;
}

672 673 674 675 676 677 678 679 680 681 682 683
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:
684 685 686 687 688 689 690 691 692 693
            if( i_title_sorted != 1 )
            {
                playlist_SortTitle( p_playlist, 0 );
                i_title_sorted = 1;
            }
            else
            {
                playlist_SortTitle( p_playlist, 1 );
                i_title_sorted = -1;
            }
694 695
            break;
        case 1:
696 697 698 699 700 701 702 703 704 705
            if( i_author_sorted != 1 )
            {
                playlist_SortAuthor( p_playlist, 0 );
                i_author_sorted = 1;
            }
            else
            {
                playlist_SortAuthor( p_playlist, 1 );
                i_author_sorted = -1;
            }
706 707
            break;
        case 2:
708 709 710 711 712 713 714 715 716 717
            if( i_group_sorted != 1 )
            {
                playlist_SortGroup( p_playlist, 0 );
                i_group_sorted = 1;
            }
            else
            {
                playlist_SortGroup( p_playlist, 1 );
                i_group_sorted = -1;
            }
718 719 720 721 722 723 724 725 726 727 728
            break;
        default:
            break;
    }
    vlc_object_release( p_playlist );

    Rebuild();

    return;
}

729 730 731
/**********************************************************************
 * Search functions
 **********************************************************************/
Clément Stenac's avatar
Clément Stenac committed
732 733
void Playlist::OnSearchTextChange( wxCommandEvent& WXUNUSED(event) )
{
Clément Stenac's avatar
Clément Stenac committed
734
   search_button->SetDefault();
Clément Stenac's avatar
Clément Stenac committed
735 736 737 738 739 740 741
}

void Playlist::OnSearch( wxCommandEvent& WXUNUSED(event) )
{
    wxString search_string= search_text->GetValue();

    int i_current;
Clément Stenac's avatar
Clément Stenac committed
742
    int i_first = 0 ;
Clément Stenac's avatar
Clément Stenac committed
743 744
    int i_item = -1;

745
    for( i_current = 0 ; i_current <= listview->GetItemCount() ; i_current++ )
Clément Stenac's avatar
Clément Stenac committed
746
    {
Clément Stenac's avatar
Clément Stenac committed
747 748 749 750 751 752
        if( listview->GetItemState( i_current, wxLIST_STATE_SELECTED)
                   == wxLIST_STATE_SELECTED )
        {
            i_first = i_current;
            break;
        }
Clément Stenac's avatar
Clément Stenac committed
753 754
    }

755
    for ( i_current = i_first + 1; i_current <= listview->GetItemCount() ;
Clément Stenac's avatar
Clément Stenac committed
756
          i_current++ )
Clément Stenac's avatar
Clément Stenac committed
757
    {
Clément Stenac's avatar
Clément Stenac committed
758 759 760 761 762 763 764 765
        wxListItem listitem;
        listitem.SetId( i_current );
        listview->GetItem( listitem );
        if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
        {
            i_item = i_current;
            break;
        }
Clément Stenac's avatar
Clément Stenac committed
766 767 768 769 770
    }
    for( long item = 0; item < listview->GetItemCount(); item++ )
    {
        listview->Select( item, FALSE );
    }
771

Clément Stenac's avatar
Clément Stenac committed
772 773 774 775 776 777 778 779
    wxListItem listitem;
    listitem.SetId(i_item);
    listitem.m_state = wxLIST_STATE_SELECTED;
    listview->Select( i_item, TRUE );
    listview->Focus( i_item );

}

780 781 782
/**********************************************************************
 * Selection functions
 **********************************************************************/
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804
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();
}

Clément Stenac's avatar
Clément Stenac committed
805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
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 ) )
        {
            playlist_Enable( p_playlist, item );
        }
    }
    vlc_object_release( p_playlist);
    Rebuild();
}

void Playlist::OnDisableSelection( 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 ) )
        {
            playlist_Disable( p_playlist, item );
        }
    }
    vlc_object_release( p_playlist);
    Rebuild();
}

847 848 849 850 851 852 853 854 855 856 857
void Playlist::OnSelectAll( wxCommandEvent& WXUNUSED(event) )
{
    for( long item = 0; item < listview->GetItemCount(); item++ )
    {
        listview->Select( item, TRUE );
    }
}

/**********************************************************************
 * Playlist mode functions
 **********************************************************************/
858 859
void Playlist::OnRandom( wxCommandEvent& event )
{
860 861 862 863 864 865 866 867 868 869 870
    vlc_value_t val;
    val.b_bool = event.IsChecked();
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }
    var_Set( p_playlist , "random", val);
    vlc_object_release( p_playlist );
871 872 873
}
void Playlist::OnLoop ( wxCommandEvent& event )
{
874 875 876 877 878 879 880 881 882 883 884 885
    vlc_value_t val;
    val.b_bool = event.IsChecked();
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }
    var_Set( p_playlist , "loop", val);
    vlc_object_release( p_playlist );
}
886

887 888 889 890 891 892 893 894 895 896 897 898 899
void Playlist::OnRepeat ( wxCommandEvent& event )
{
    vlc_value_t val;
    val.b_bool = event.IsChecked();
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }
    var_Set( p_playlist , "repeat", val);
    vlc_object_release( p_playlist );
900 901
}

902

903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926

void Playlist::OnActivateItem( wxListEvent& event )
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }
    playlist_Goto( p_playlist, event.GetIndex() );

    vlc_object_release( p_playlist );
}
void Playlist::OnKeyDown( wxListEvent& event )
{
    long keycode = event.GetKeyCode();
    /* Delete selected items */
    if( keycode == WXK_BACK || keycode == WXK_DELETE )
    {
        /* We send a dummy event */
        OnDeleteSelection( event );
    }
}
Gildas Bazin's avatar
 
Gildas Bazin committed
927

Clément Stenac's avatar
Clément Stenac committed
928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957
void Playlist::OnInfos( wxCommandEvent& WXUNUSED(event) )
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

    if( iteminfo_dialog == NULL )
    {
        /* We use the first selected item, so find it */
        long i_item = -1;
        i_item = listview->GetNextItem(i_item,
                         wxLIST_NEXT_ALL,
                         wxLIST_STATE_SELECTED);
        if( i_item >= 0 && i_item < p_playlist->i_size )
        {
            iteminfo_dialog = new ItemInfoDialog(
                              p_intf, p_playlist->pp_items[i_item], this );
            if( iteminfo_dialog->ShowModal()  == wxID_OK )
                Rebuild();
            delete iteminfo_dialog;
            iteminfo_dialog = NULL;
        }
    }
    vlc_object_release( p_playlist );
}

958
void Playlist::OnEnDis( wxCommandEvent& event )
Clément Stenac's avatar
Clément Stenac committed
959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974
{
    playlist_t *p_playlist =
        (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
                                       FIND_ANYWHERE );
    if( p_playlist == NULL )
    {
        return;
    }

    long i_item = -1;
    i_item = listview->GetNextItem(i_item,
                       wxLIST_NEXT_ALL,
                       wxLIST_STATE_SELECTED);

    if( i_item >= 0 && i_item < p_playlist->i_size )
    {
975 976 977 978
       switch( event.GetId() )
       {
           case EnableGroup_Event:
               playlist_EnableGroup( p_playlist ,
Clément Stenac's avatar
Clément Stenac committed
979
                                  p_playlist->pp_items[i_item]->i_group );
980 981 982
               break;
           case DisableGroup_Event:
               playlist_DisableGroup( p_playlist ,
Clément Stenac's avatar
Clément Stenac committed
983
                                  p_playlist->pp_items[i_item]->i_group );
984 985
               break;
       }
Clément Stenac's avatar
Clément Stenac committed
986 987 988 989 990
       Rebuild();
    }

    vlc_object_release( p_playlist );
}
991

Gildas Bazin's avatar
 
Gildas Bazin committed
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
/*****************************************************************************
 * PlaylistChanged: callback triggered by the intf-change playlist variable
 *  We don't rebuild the playlist directly here because we don't want the
 *  caller to block for a too long time.
 *****************************************************************************/
int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
                     vlc_value_t old_val, vlc_value_t new_val, void *param )
{
    Playlist *p_playlist_dialog = (Playlist *)param;
    vlc_mutex_lock( &p_playlist_dialog->lock );
    p_playlist_dialog->b_need_update = VLC_TRUE;
    vlc_mutex_unlock( &p_playlist_dialog->lock );
    return VLC_SUCCESS;
}
1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083


/***************************************************************************
 * NewGroup
 ***************************************************************************/
NewGroup::NewGroup( intf_thread_t *_p_intf, wxWindow *_p_parent ):
    wxDialog( _p_parent, -1, wxU(_("New Group")), wxDefaultPosition,
             wxDefaultSize, wxDEFAULT_FRAME_STYLE )
{
    /* Initializations */
    p_intf = _p_intf;
    psz_name = NULL;
    SetIcon( *p_intf->p_sys->p_icon );

    /* Create a panel to put everything in*/
    wxPanel *panel = new wxPanel( this, -1 );
    panel->SetAutoLayout( TRUE );

    wxStaticText *group_label =
            new wxStaticText( panel , -1,
                wxU(_("Enter the name for the new group")));

    groupname = new wxTextCtrl(panel, -1, wxU(""),wxDefaultPosition,
                               wxSize(80,27),wxTE_PROCESS_ENTER);

    wxButton *ok_button = new wxButton(panel, wxID_OK, wxU(_("OK")) );
    ok_button->SetDefault();
    wxButton *cancel_button = new wxButton( panel, wxID_CANCEL,
                                            wxU(_("Cancel")) );

    wxBoxSizer *button_sizer = new wxBoxSizer( wxHORIZONTAL );

    button_sizer->Add( ok_button, 0, wxALL, 5 );
    button_sizer->Add( cancel_button, 0, wxALL, 5 );
    button_sizer->Layout();

    wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
    panel_sizer->Add( group_label, 0, wxEXPAND | wxALL, 5 );
    panel_sizer->Add( groupname, 0, wxEXPAND | wxALL, 5 );
    panel_sizer->Add( button_sizer, 0, wxEXPAND | wxALL, 5 );
    panel_sizer->Layout();

    panel->SetSizerAndFit( panel_sizer );

    wxBoxSizer *main_sizer = new wxBoxSizer( wxVERTICAL );
    main_sizer->Add( panel, 1, wxEXPAND, 0 );
    main_sizer->Layout();
    SetSizerAndFit( main_sizer );
}

NewGroup::~NewGroup()
{
}

void NewGroup::OnOk( wxCommandEvent& event )
{
    psz_name = strdup( groupname->GetLineText(0).mb_str() );

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

    if( p_playlist )
    {
        if( !playlist_CreateGroup( p_playlist, psz_name ) )
        {
            psz_name = NULL;
        }
    }

    vlc_object_release( p_playlist );
    EndModal( wxID_OK );
}

void NewGroup::OnCancel( wxCommandEvent& WXUNUSED(event) )
{
    EndModal( wxID_CANCEL );
}