playlist.cpp
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:41k
源码类别:

多媒体

开发平台:

MultiPlatform

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