playlist.cpp 40.5 KB
Newer Older
1
/*****************************************************************************
gbazin's avatar
 
gbazin committed
2
 * playlist.cpp : wxWindows plugin for vlc
3
 *****************************************************************************
4
 * Copyright (C) 2000-2004 VideoLAN
zorglub's avatar
zorglub committed
5
 * $Id$
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
/* Callback prototype */
33 34 35 36 37 38
static int PlaylistChanged( vlc_object_t *, const char *,
                            vlc_value_t, vlc_value_t, void * );
static int PlaylistNext( vlc_object_t *, const char *,
                         vlc_value_t, vlc_value_t, void * );
static int ItemChanged( vlc_object_t *, const char *,
                        vlc_value_t, vlc_value_t, void * );
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
    b_need_update = VLC_FALSE;
gbazin's avatar
 
gbazin committed
182
    SetIcon( *p_intf->p_sys->p_icon );
183

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

hartman's avatar
hartman committed
189 190 191
    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 );;
192

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

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

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

zorglub's avatar
zorglub committed
225 226 227 228 229 230
    /* 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")) );

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

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

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

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

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

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

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

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

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

283

zorglub's avatar
zorglub committed
284 285 286 287 288 289 290 291 292 293
    /* 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
294 295
    listview->InsertColumn( 2, wxU(_("Duration")) );
    listview->InsertColumn( 3, wxU(_("Group")) );
zorglub's avatar
zorglub committed
296 297 298 299 300 301 302 303 304 305 306 307
    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
308
    wxButton *iteminfo_button =
Sam Hocevar's avatar
Sam Hocevar committed
309
        new wxButton( playlist_panel, Infos_Event, wxU(_("Item info") ) );
zorglub's avatar
zorglub committed
310

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

zorglub's avatar
zorglub committed
316 317 318 319
    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
320 321 322

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

    wxBoxSizer *search_sizer = new wxBoxSizer( wxHORIZONTAL );
zorglub's avatar
zorglub committed
331 332
    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
333 334
    search_sizer->Layout();

zorglub's avatar
zorglub committed
335 336
    /* The top and bottom sizers */
    wxBoxSizer *top_sizer = new wxBoxSizer( wxHORIZONTAL );
gbazin's avatar
 
gbazin committed
337 338
    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
339
    top_sizer->Layout();
zorglub's avatar
zorglub committed
340

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

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

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

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

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

gbazin's avatar
 
gbazin committed
366 367 368 369 370 371 372 373
    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
374
    /* We want to be noticed of playlist changes */
zorglub's avatar
zorglub committed
375 376

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

    /* 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
386 387
    vlc_object_release( p_playlist );

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

Playlist::~Playlist()
{
gbazin's avatar
 
gbazin committed
394 395 396 397 398 399 400 401
    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
402 403
    delete iteminfo_dialog;

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

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

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

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

    playlist_item_t *p_item = playlist_ItemGetByPos( p_playlist, i );

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

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

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

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

    /* 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
472 473 474
/**********************************************************************
 * Rebuild the playlist
 **********************************************************************/
475 476 477 478 479 480 481 482 483 484
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
485 486
    int i_focused = listview->GetFocusedItem();

487 488 489 490 491 492 493
    /* 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++ )
    {
494
        wxString filename = wxL2U(p_playlist->pp_items[i]->input.psz_name);
495
        listview->InsertItem( i, filename );
zorglub's avatar
zorglub committed
496
        UpdateItem( i );
497 498 499
    }
    vlc_mutex_unlock( &p_playlist->object_lock );

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

510 511 512
    vlc_object_release( p_playlist );
}

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

void Playlist::UpdatePlaylist()
{
    i_update_counter++;

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

    if( this->b_need_update )
    {
        this->b_need_update = VLC_FALSE;
zorglub's avatar
zorglub committed
529 530
        Rebuild();
    }
gbazin's avatar
 
gbazin committed
531 532 533 534

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

535 536 537 538 539 540 541 542
    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
543
    /* Update the colour of items */
gbazin's avatar
 
gbazin committed
544 545
    int i_playlist_index = p_playlist->i_index;
    if( p_intf->p_sys->i_playing != i_playlist_index )
546 547
    {
        wxListItem listitem;
gbazin's avatar
 
gbazin committed
548
        listitem.m_itemId = i_playlist_index;
549 550 551 552 553 554 555 556 557
        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 );
        }
gbazin's avatar
 
gbazin committed
558
        p_intf->p_sys->i_playing = i_playlist_index;
559
    }
gbazin's avatar
 
gbazin committed
560

561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
    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
588 589
void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) )
{
sigmunau's avatar
sigmunau committed
590 591 592 593
    struct {
        char *psz_desc;
        char *psz_filter;
        char *psz_module;
zorglub's avatar
Cancel  
zorglub committed
594
    } formats[] = {{ _("M3U file"), "*.m3u", "export-m3u" },
sigmunau's avatar
sigmunau committed
595 596
                   { _("PLS file"), "*.pls", "export-pls" }};
    wxString filter = wxT("");
zorglub's avatar
zorglub committed
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613

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

    if( ! p_playlist )
    {
        return;
    }
    if( p_playlist->i_size == 0 )
    {
        wxMessageBox( wxU(_("Playlist is empty") ), wxU(_("Can't save")),
                      wxICON_WARNING | wxOK, this );
        vlc_object_release( p_playlist );
        return;
    }

sigmunau's avatar
sigmunau committed
614 615
    for( unsigned int i = 0; i < sizeof(formats)/sizeof(formats[0]); i++)
    {
gbazin's avatar
 
gbazin committed
616
        filter.Append( wxU(formats[i].psz_desc) );
sigmunau's avatar
sigmunau committed
617
        filter.Append( wxT("|") );
gbazin's avatar
 
gbazin committed
618
        filter.Append( wxU(formats[i].psz_filter) );
sigmunau's avatar
sigmunau committed
619 620 621 622 623 624 625
        filter.Append( wxT("|") );
    }
    wxFileDialog dialog( this, wxU(_("Save playlist")),
                         wxT(""), wxT(""), filter, wxSAVE );

    if( dialog.ShowModal() == wxID_OK )
    {
626
        if( dialog.GetPath().mb_str() )
sigmunau's avatar
sigmunau committed
627
        {
628
            playlist_Export( p_playlist, dialog.GetPath().mb_str(),
zorglub's avatar
zorglub committed
629
                             formats[dialog.GetFilterIndex()].psz_module );
sigmunau's avatar
sigmunau committed
630
        }
zorglub's avatar
zorglub committed
631
    }
632

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

gbazin's avatar
 
gbazin committed
635 636 637
}

void Playlist::OnOpen( wxCommandEvent& WXUNUSED(event) )
638
{
gbazin's avatar
 
gbazin committed
639 640 641 642 643 644 645 646
    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
647 648
    wxFileDialog dialog( this, wxU(_("Open playlist")), wxT(""), wxT(""),
        wxT("All playlists|*.pls;*.m3u;*.asx;*.b4s|M3U files|*.m3u"), wxOPEN );
gbazin's avatar
 
gbazin committed
649 650 651

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

    vlc_object_release( p_playlist );
656 657
}

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

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

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

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

zorglub's avatar
zorglub committed
676 677 678
/********************************************************************
 * Move functions
 ********************************************************************/
gbazin's avatar
 
gbazin committed
679
void Playlist::OnUp( wxCommandEvent& event )
zorglub's avatar
zorglub committed
680 681 682 683 684 685 686 687 688
{
    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
689
    /* We use the first selected item, so find it */
gbazin's avatar
 
gbazin committed
690
    long i_item = listview->GetNextItem( -1, wxLIST_NEXT_ALL,
gbazin's avatar
 
gbazin committed
691
                                         wxLIST_STATE_SELECTED);
zorglub's avatar
zorglub committed
692 693
    if( i_item > 0 && i_item < p_playlist->i_size )
    {
gbazin's avatar
 
gbazin committed
694 695
        playlist_Move( p_playlist, i_item, i_item - 1 );
        listview->Focus( i_item - 1 );
zorglub's avatar
zorglub committed
696
    }
zorglub's avatar
zorglub committed
697 698 699 700
    vlc_object_release( p_playlist );
    return;
}

gbazin's avatar
 
gbazin committed
701
void Playlist::OnDown( wxCommandEvent& event )
zorglub's avatar
zorglub committed
702 703 704 705 706 707 708 709 710
{
    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
711
    /* We use the first selected item, so find it */
gbazin's avatar
 
gbazin committed
712
    long i_item = listview->GetNextItem( -1, wxLIST_NEXT_ALL,
gbazin's avatar
 
gbazin committed
713
                                         wxLIST_STATE_SELECTED );
zorglub's avatar
zorglub committed
714 715 716 717 718 719 720 721
    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
722

zorglub's avatar
zorglub committed
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737
/********************************************************************
 * 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
738
           playlist_SortTitle( p_playlist , ORDER_NORMAL );
zorglub's avatar
zorglub committed
739 740
           break;
        case RSortTitle_Event:
hartman's avatar
hartman committed
741
           playlist_SortTitle( p_playlist , ORDER_REVERSE );
zorglub's avatar
zorglub committed
742 743
           break;
        case SortAuthor_Event:
hartman's avatar
hartman committed
744
           playlist_SortAuthor(p_playlist , ORDER_NORMAL );
zorglub's avatar
zorglub committed
745 746
           break;
        case RSortAuthor_Event:
hartman's avatar
hartman committed
747
           playlist_SortAuthor( p_playlist , ORDER_REVERSE );
zorglub's avatar
zorglub committed
748 749
           break;
        case SortGroup_Event:
hartman's avatar
hartman committed
750
           playlist_SortGroup( p_playlist , ORDER_NORMAL );
zorglub's avatar
zorglub committed
751 752
           break;
        case RSortGroup_Event:
hartman's avatar
hartman committed
753
           playlist_SortGroup( p_playlist , ORDER_REVERSE );
zorglub's avatar
zorglub committed
754
           break;
zorglub's avatar
zorglub committed
755
        case Randomize_Event:
756
           playlist_Sort( p_playlist , SORT_RANDOM, ORDER_NORMAL );
zorglub's avatar
zorglub committed
757
           break;
zorglub's avatar
zorglub committed
758
    }
zorglub's avatar
zorglub committed
759 760 761 762 763 764 765
    vlc_object_release( p_playlist );

    Rebuild();

    return;
}

sigmunau's avatar
sigmunau committed
766 767 768 769 770 771 772 773 774 775 776 777
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:
778 779
            if( i_title_sorted != 1 )
            {
hartman's avatar
hartman committed
780
                playlist_SortTitle( p_playlist, ORDER_NORMAL );
781 782 783 784
                i_title_sorted = 1;
            }
            else
            {
hartman's avatar
hartman committed
785
                playlist_SortTitle( p_playlist, ORDER_REVERSE );
786 787
                i_title_sorted = -1;
            }
sigmunau's avatar
sigmunau committed
788 789
            break;
        case 1:
790 791
            if( i_author_sorted != 1 )
            {
hartman's avatar
hartman committed
792
                playlist_SortAuthor( p_playlist, ORDER_NORMAL );
793 794 795 796
                i_author_sorted = 1;
            }
            else
            {
hartman's avatar
hartman committed
797
                playlist_SortAuthor( p_playlist, ORDER_REVERSE );
798 799
                i_author_sorted = -1;
            }
sigmunau's avatar
sigmunau committed
800 801
            break;
        case 2:
zorglub's avatar
zorglub committed
802 803 804 805 806 807 808 809 810 811 812 813
            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:
814 815
            if( i_group_sorted != 1 )
            {
hartman's avatar
hartman committed
816
                playlist_SortGroup( p_playlist, ORDER_NORMAL );
817 818 819 820
                i_group_sorted = 1;
            }
            else
            {
hartman's avatar
hartman committed
821
                playlist_SortGroup( p_playlist, ORDER_REVERSE );
822 823
                i_group_sorted = -1;
            }
sigmunau's avatar
sigmunau committed
824 825 826 827 828 829 830 831 832 833 834
            break;
        default:
            break;
    }
    vlc_object_release( p_playlist );

    Rebuild();

    return;
}

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

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

zorglub's avatar
zorglub committed
847
    bool b_ok = false;
zorglub's avatar
zorglub committed
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
    }

zorglub's avatar
zorglub committed
862 863 864 865 866
    if( i_first == listview->GetItemCount() )
    {
        i_first = -1;
    }

gbazin's avatar
 
gbazin committed
867 868
    for( i_current = i_first + 1; i_current < listview->GetItemCount();
         i_current++ )
zorglub's avatar
zorglub committed
869
    {
zorglub's avatar
zorglub committed
870 871 872 873 874 875
        wxListItem listitem;
        listitem.SetId( i_current );
        listview->GetItem( listitem );
        if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
        {
            i_item = i_current;
zorglub's avatar
zorglub committed
876
            b_ok = true;
zorglub's avatar
zorglub committed
877 878
            break;
        }
zorglub's avatar
zorglub committed
879 880 881 882 883 884 885 886
        listitem.SetColumn( 1 );
        listview->GetItem( listitem );
        if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
        {
            i_item = i_current;
            b_ok = true;
            break;
        }
zorglub's avatar
zorglub committed
887
    }
zorglub's avatar
zorglub committed
888 889 890 891 892 893 894 895 896 897 898 899 900 901
    if( !b_ok )
    {
        for( i_current = -1 ; i_current < i_first - 1;
             i_current++ )
        {
            wxListItem listitem;
            listitem.SetId( i_current );
            listview->GetItem( listitem );
            if( listitem.m_text.Lower().Contains( search_string.Lower() ) )
            {
                i_item = i_current;
                b_ok = true;
                break;
            }
zorglub's avatar
zorglub committed
902 903 904 905 906 907 908 909
            listitem.SetColumn( 1 );
            listview->GetItem( listitem );
            if( listitem.m_text.Lower().Contains( search_string.Lower