Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

playlist.cpp

00001 /*****************************************************************************
00002  * playlist.cpp : wxWindows plugin for vlc
00003  *****************************************************************************
00004  * Copyright (C) 2000-2005 the VideoLAN team
00005  * $Id: playlist.cpp 13298 2005-11-20 21:52:59Z zorglub $
00006  *
00007  * Authors: Olivier Teulière <[email protected]>
00008  *          Clément Stenac <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/OR MODIFy
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Preamble
00027  *****************************************************************************/
00028 #include <vlc/vlc.h>
00029 #include <vlc/intf.h>
00030 
00031 #include "wxwidgets.h"
00032 
00033 #include "bitmaps/shuffle.xpm"
00034 #include "bitmaps/repeat.xpm"
00035 #include "bitmaps/loop.xpm"
00036 
00037 #include "bitmaps/type_unknown.xpm"
00038 #include "bitmaps/type_afile.xpm"
00039 #include "bitmaps/type_vfile.xpm"
00040 #include "bitmaps/type_net.xpm"
00041 #include "bitmaps/type_card.xpm"
00042 #include "bitmaps/type_disc.xpm"
00043 #include "bitmaps/type_cdda.xpm"
00044 #include "bitmaps/type_directory.xpm"
00045 #include "bitmaps/type_playlist.xpm"
00046 #include "bitmaps/type_node.xpm"
00047 
00048 #include <wx/dynarray.h>
00049 #include <wx/imaglist.h>
00050 
00051 #define HELP_SHUFFLE N_( "Shuffle" )
00052 #define HELP_LOOP N_( "Repeat All" )
00053 #define HELP_REPEAT N_( "Repeat One" )
00054 
00055 namespace wxvlc {
00056 /* Callback prototype */
00057 static int PlaylistChanged( vlc_object_t *, const char *,
00058                             vlc_value_t, vlc_value_t, void * );
00059 static int PlaylistNext( vlc_object_t *, const char *,
00060                          vlc_value_t, vlc_value_t, void * );
00061 static int ItemChanged( vlc_object_t *, const char *,
00062                         vlc_value_t, vlc_value_t, void * );
00063 static int ItemAppended( vlc_object_t *p_this, const char *psz_variable,
00064                       vlc_value_t oval, vlc_value_t nval, void *param );
00065 static int ItemDeleted( vlc_object_t *p_this, const char *psz_variable,
00066                       vlc_value_t oval, vlc_value_t nval, void *param );
00067 
00068 /*****************************************************************************
00069  * Event Table.
00070  *****************************************************************************/
00071 
00072 /* IDs for the controls and the menu commands */
00073 enum
00074 {
00075     /* menu items */
00076     AddFile_Event = 1,
00077     AddDir_Event,
00078     AddMRL_Event,
00079     Close_Event,
00080     Open_Event,
00081     Save_Event,
00082 
00083     SortTitle_Event,
00084     RSortTitle_Event,
00085     Randomize_Event,
00086 
00087     DeleteSelection_Event,
00088     Random_Event,
00089     Loop_Event,
00090     Repeat_Event,
00091 
00092     PopupPlay_Event,
00093     PopupPlayThis_Event,
00094     PopupPreparse_Event,
00095     PopupSort_Event,
00096     PopupDel_Event,
00097     PopupInfo_Event,
00098 
00099     SearchText_Event,
00100     Search_Event,
00101 
00102     /* controls */
00103     TreeCtrl_Event,
00104 
00105     Browse_Event,  /* For export playlist */
00106 
00107     /* custom events */
00108     UpdateItem_Event,
00109     AppendItem_Event,
00110     RemoveItem_Event,
00111 
00112     MenuDummy_Event = wxID_HIGHEST + 999,
00113 
00114     FirstView_Event = wxID_HIGHEST + 1000,
00115     LastView_Event = wxID_HIGHEST + 1100,
00116 
00117     FirstSD_Event = wxID_HIGHEST + 2000,
00118     LastSD_Event = wxID_HIGHEST + 2100,
00119 };
00120 
00121 DEFINE_LOCAL_EVENT_TYPE( wxEVT_PLAYLIST );
00122 
00123 BEGIN_EVENT_TABLE(Playlist, wxFrame)
00124     EVT_SIZE(Playlist::OnSize)
00125 
00126     /* Menu events */
00127     EVT_MENU(AddFile_Event, Playlist::OnAddFile)
00128     EVT_MENU(AddDir_Event, Playlist::OnAddDir)
00129     EVT_MENU(AddMRL_Event, Playlist::OnAddMRL)
00130     EVT_MENU(Close_Event, Playlist::OnMenuClose)
00131     EVT_MENU(Open_Event, Playlist::OnOpen)
00132     EVT_MENU(Save_Event, Playlist::OnSave)
00133 
00134     EVT_MENU(SortTitle_Event, Playlist::OnSort)
00135     EVT_MENU(RSortTitle_Event, Playlist::OnSort)
00136 
00137     EVT_MENU(Randomize_Event, Playlist::OnSort)
00138 
00139     EVT_MENU(DeleteSelection_Event, Playlist::OnDeleteSelection)
00140 
00141     EVT_MENU_OPEN( Playlist::OnMenuOpen )
00142     EVT_MENU( -1, Playlist::OnMenuEvent )
00143 
00144     EVT_TOOL(Random_Event, Playlist::OnRandom)
00145     EVT_TOOL(Repeat_Event, Playlist::OnRepeat)
00146     EVT_TOOL(Loop_Event, Playlist::OnLoop)
00147 
00148     /* Popup events */
00149     EVT_MENU( PopupPlay_Event, Playlist::OnPopupPlay)
00150     EVT_MENU( PopupPlayThis_Event, Playlist::OnPopupPlay)
00151     EVT_MENU( PopupPreparse_Event, Playlist::OnPopupPreparse)
00152     EVT_MENU( PopupSort_Event, Playlist::OnPopupSort)
00153     EVT_MENU( PopupDel_Event, Playlist::OnPopupDel)
00154     EVT_MENU( PopupInfo_Event, Playlist::OnPopupInfo)
00155 
00156     /* Tree control events */
00157     EVT_TREE_ITEM_ACTIVATED( TreeCtrl_Event, Playlist::OnActivateItem )
00158     EVT_TREE_KEY_DOWN( -1, Playlist::OnKeyDown )
00159 
00160     EVT_CONTEXT_MENU( Playlist::OnPopup )
00161 
00162     /* Button events */
00163     EVT_BUTTON( Search_Event, Playlist::OnSearch)
00164     EVT_BUTTON( Save_Event, Playlist::OnSave)
00165 
00166     /*EVT_TEXT( SearchText_Event, Playlist::OnSearchTextChange )*/
00167     EVT_TEXT_ENTER( SearchText_Event, Playlist::OnSearch )
00168 
00169     /* Custom events */
00170     EVT_COMMAND(-1, wxEVT_PLAYLIST, Playlist::OnPlaylistEvent)
00171 
00172     /* Special events : we don't want to destroy the window when the user
00173      * clicks on (X) */
00174     EVT_CLOSE(Playlist::OnClose)
00175 END_EVENT_TABLE()
00176 
00177 /*****************************************************************************
00178  * PlaylistItem class
00179  ****************************************************************************/
00180 class PlaylistItem : public wxTreeItemData
00181 {
00182 public:
00183     PlaylistItem( playlist_item_t *p_item ) : wxTreeItemData()
00184     {
00185         i_id = p_item->input.i_id;
00186     }
00187 protected:
00188     int i_id;
00189 friend class Playlist;
00190 };
00191 
00192 /*****************************************************************************
00193  * Constructor.
00194  *****************************************************************************/
00195 Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
00196     wxFrame( p_parent, -1, wxU(_("Playlist")), wxDefaultPosition,
00197              wxSize(500,300), wxDEFAULT_FRAME_STYLE )
00198 {
00199     vlc_value_t val;
00200 
00201     /* Initializations */
00202     p_intf = _p_intf;
00203     pp_sds = NULL;
00204     i_update_counter = 0;
00205     i_sort_mode = MODE_NONE;
00206     b_need_update = VLC_FALSE;
00207     i_items_to_append = 0;
00208     p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
00209                                                 FIND_ANYWHERE );
00210     if( p_playlist == NULL ) return;
00211 
00212     SetIcon( *p_intf->p_sys->p_icon );
00213 
00214     p_view_menu = NULL;
00215     p_sd_menu = SDMenu();
00216 
00217     i_current_view = VIEW_CATEGORY;
00218     b_changed_view = VLC_FALSE;
00219 
00220     i_title_sorted = 0;
00221     i_group_sorted = 0;
00222     i_duration_sorted = 0;
00223 
00224     var_Create( p_intf, "random", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00225     var_Create( p_intf, "loop", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
00226     var_Create( p_intf, "repeat", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );;
00227 
00228     /* Create our "Manage" menu */
00229     wxMenu *manage_menu = new wxMenu;
00230     manage_menu->Append( AddFile_Event, wxU(_("&Simple Add File...")) );
00231     manage_menu->Append( AddDir_Event, wxU(_("Add &Directory...")) );
00232     manage_menu->Append( AddMRL_Event, wxU(_("&Add MRL...")) );
00233     manage_menu->AppendSeparator();
00234     manage_menu->Append( MenuDummy_Event, wxU(_("Services discovery")),
00235                          p_sd_menu );
00236     manage_menu->AppendSeparator();
00237     manage_menu->Append( Open_Event, wxU(_("&Open Playlist...")) );
00238     manage_menu->Append( Save_Event, wxU(_("&Save Playlist...")) );
00239     manage_menu->AppendSeparator();
00240     manage_menu->Append( Close_Event, wxU(_("&Close")) );
00241 
00242     /* Create our "Sort" menu */
00243     wxMenu *sort_menu = new wxMenu;
00244     sort_menu->Append( SortTitle_Event, wxU(_("Sort by &title")) );
00245     sort_menu->Append( RSortTitle_Event, wxU(_("&Reverse sort by title")) );
00246     sort_menu->AppendSeparator();
00247     sort_menu->Append( Randomize_Event, wxU(_("&Shuffle Playlist")) );
00248 
00249     /* Create our "Selection" menu */
00250     wxMenu *selection_menu = new wxMenu;
00251     selection_menu->Append( DeleteSelection_Event, wxU(_("D&elete")) );
00252 
00253     /* Create our "View" menu */
00254     ViewMenu();
00255 
00256     /* Append the freshly created menus to the menu bar */
00257     wxMenuBar *menubar = new wxMenuBar();
00258     menubar->Append( manage_menu, wxU(_("&Manage")) );
00259     menubar->Append( sort_menu, wxU(_("S&ort")) );
00260     menubar->Append( selection_menu, wxU(_("&Selection")) );
00261     menubar->Append( p_view_menu, wxU(_("&View items") ) );
00262 
00263     /* Attach the menu bar to the frame */
00264     SetMenuBar( menubar );
00265 
00266     /* Create the popup menu */
00267     node_popup = new wxMenu;
00268     node_popup->Append( PopupPlay_Event, wxU(_("Play")) );
00269     node_popup->Append( PopupPlayThis_Event, wxU(_("Play this branch")) );
00270     node_popup->Append( PopupPreparse_Event, wxU(_("Preparse")) );
00271     node_popup->Append( PopupSort_Event, wxU(_("Sort this branch")) );
00272     node_popup->Append( PopupDel_Event, wxU(_("Delete")) );
00273     node_popup->Append( PopupInfo_Event, wxU(_("Info")) );
00274 
00275     item_popup = new wxMenu;
00276     item_popup->Append( PopupPlay_Event, wxU(_("Play")) );
00277     item_popup->Append( PopupPreparse_Event, wxU(_("Preparse")) );
00278     item_popup->Append( PopupDel_Event, wxU(_("Delete")) );
00279     item_popup->Append( PopupInfo_Event, wxU(_("Info")) );
00280 
00281     /* Create a panel to put everything in */
00282     wxPanel *playlist_panel = new wxPanel( this, -1 );
00283     playlist_panel->SetAutoLayout( TRUE );
00284 
00285     /* Create the toolbar */
00286     wxToolBar *toolbar =
00287         CreateToolBar( wxTB_HORIZONTAL | wxTB_FLAT );
00288 
00289     /* Create the random tool */
00290     toolbar->AddTool( Random_Event, wxT(""), wxBitmap(shuffle_on_xpm),
00291                        wxBitmap(shuffle_on_xpm), wxITEM_CHECK,
00292                        wxU(_(HELP_SHUFFLE) ) );
00293     var_Get( p_intf, "random", &val );
00294     toolbar->ToggleTool( Random_Event, val.b_bool );
00295 
00296     /* Create the Loop tool */
00297     toolbar->AddTool( Loop_Event, wxT(""), wxBitmap( loop_xpm),
00298                       wxBitmap( loop_xpm), wxITEM_CHECK,
00299                       wxU(_(HELP_LOOP )  ) );
00300     var_Get( p_intf, "loop", &val );
00301     toolbar->ToggleTool( Loop_Event, val.b_bool );
00302 
00303     /* Create the Repeat one checkbox */
00304     toolbar->AddTool( Repeat_Event, wxT(""), wxBitmap( repeat_xpm),
00305                       wxBitmap( repeat_xpm), wxITEM_CHECK,
00306                       wxU(_(HELP_REPEAT )  ) );
00307     var_Get( p_intf, "repeat", &val );
00308     toolbar->ToggleTool( Repeat_Event, val.b_bool ) ;
00309 
00310     /* Create the Search Textbox */
00311     search_text = new wxTextCtrl( toolbar, SearchText_Event, wxT(""),
00312                                   wxDefaultPosition, wxSize(100, -1),
00313                                   wxTE_PROCESS_ENTER);
00314 
00315     /* Create the search button */
00316     search_button = new wxButton( toolbar , Search_Event, wxU(_("Search")) );
00317 
00318     toolbar->AddControl( new wxControl( toolbar, -1, wxDefaultPosition,
00319                          wxSize(16, 16), wxBORDER_NONE ) );
00320     toolbar->AddControl( search_text );
00321     toolbar->AddControl( new wxControl( toolbar, -1, wxDefaultPosition,
00322                          wxSize(5, 5), wxBORDER_NONE ) );
00323     toolbar->AddControl( search_button );
00324     search_button->SetDefault();
00325     toolbar->Realize();
00326 
00327     /* Create the tree */
00328     treectrl = new wxTreeCtrl( playlist_panel, TreeCtrl_Event,
00329                                wxDefaultPosition, wxDefaultSize,
00330                                wxTR_HIDE_ROOT | wxTR_LINES_AT_ROOT|
00331                                wxTR_NO_LINES |
00332                                wxTR_HAS_BUTTONS | wxTR_TWIST_BUTTONS |
00333                                wxTR_MULTIPLE | wxTR_EXTENDED );
00334 
00335     /* Create image list */
00336     wxImageList *p_images = new wxImageList( 16 , 16, TRUE );
00337 
00338     /* FIXME: absolutely needs to be in the right order FIXME */
00339     p_images->Add( wxIcon( type_unknown_xpm ) );
00340     p_images->Add( wxIcon( type_afile_xpm ) );
00341     p_images->Add( wxIcon( type_vfile_xpm ) );
00342     p_images->Add( wxIcon( type_directory_xpm ) );
00343     p_images->Add( wxIcon( type_disc_xpm ) );
00344     p_images->Add( wxIcon( type_cdda_xpm ) );
00345     p_images->Add( wxIcon( type_card_xpm ) );
00346     p_images->Add( wxIcon( type_net_xpm ) );
00347     p_images->Add( wxIcon( type_playlist_xpm ) );
00348     p_images->Add( wxIcon( type_node_xpm ) );
00349     treectrl->AssignImageList( p_images );
00350 
00351     treectrl->AddRoot( wxU(_("root" )), -1, -1, NULL );
00352 
00353     /* Reduce font size */
00354     wxFont font= treectrl->GetFont();
00355     font.SetPointSize(9);
00356     treectrl->SetFont( font );
00357 
00358     wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL );
00359     panel_sizer->Add( treectrl, 1, wxEXPAND | wxALL, 5 );
00360     panel_sizer->Layout();
00361 
00362     playlist_panel->SetSizerAndFit( panel_sizer );
00363 
00364     int pi_widths[1] =  { -1 };
00365     statusbar = CreateStatusBar( 1 );
00366     statusbar->SetStatusWidths( 1, pi_widths );
00367 
00368 #if wxUSE_DRAG_AND_DROP
00369     /* Associate drop targets with the playlist */
00370     SetDropTarget( new DragAndDrop( p_intf, VLC_TRUE ) );
00371 #endif
00372 
00373     i_saved_id = -1;
00374 
00375 
00376     /* We want to be noticed of playlist changes */
00377 
00378     /* Some global changes happened -> Rebuild all */
00379     var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this );
00380 
00381     /* We went to the next item */
00382     var_AddCallback( p_playlist, "playlist-current", PlaylistNext, this );
00383 
00384     /* One item has been updated */
00385     var_AddCallback( p_playlist, "item-change", ItemChanged, this );
00386 
00387     var_AddCallback( p_playlist, "item-append", ItemAppended, this );
00388     var_AddCallback( p_playlist, "item-deleted", ItemDeleted, this );
00389 
00390     /* Update the playlist */
00391     Rebuild( VLC_TRUE );
00392 
00393 }
00394 
00395 Playlist::~Playlist()
00396 {
00397     if( pp_sds != NULL ) free( pp_sds );
00398 
00399     if( p_playlist == NULL ) return;
00400 
00401     var_DelCallback( p_playlist, "item-change", ItemChanged, this );
00402     var_DelCallback( p_playlist, "playlist-current", PlaylistNext, this );
00403     var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this );
00404     var_DelCallback( p_playlist, "item-append", ItemAppended, this );
00405     var_DelCallback( p_playlist, "item-deleted", ItemDeleted, this );
00406     vlc_object_release( p_playlist );
00407 }
00408 
00409 /**********************************************************************
00410  * Update functions
00411  **********************************************************************/
00412 
00413 /* Update a node */
00414 void Playlist::UpdateNode( playlist_item_t *p_node, wxTreeItemId node )
00415 {
00416     wxTreeItemIdValue cookie;
00417     wxTreeItemId child;
00418     for( int i = 0; i< p_node->i_children ; i++ )
00419     {
00420         if( i == 0 )
00421         {
00422             child = treectrl->GetFirstChild( node, cookie);
00423         }
00424         else
00425         {
00426             child = treectrl->GetNextChild( node, cookie );
00427         }
00428 
00429         if( !child.IsOk() )
00430         {
00431             /* Not enough children */
00432             CreateNode( p_node->pp_children[i], node );
00433             /* Keep the tree pointer up to date */
00434             child = treectrl->GetNextChild( node, cookie );
00435         }
00436     }
00437     treectrl->SetItemImage( node, p_node->input.i_type );
00438 
00439 }
00440 
00441 /* Creates the node p_node as last child of parent */
00442 void Playlist::CreateNode( playlist_item_t *p_node, wxTreeItemId parent )
00443 {
00444     wxTreeItemId node =
00445         treectrl->AppendItem( parent, wxL2U( p_node->input.psz_name ),
00446                               -1,-1, new PlaylistItem( p_node ) );
00447     treectrl->SetItemImage( node, p_node->input.i_type );
00448 
00449     UpdateNodeChildren( p_node, node );
00450 }
00451 
00452 /* Update all children (recursively) of this node */
00453 void Playlist::UpdateNodeChildren( playlist_item_t *p_node,
00454                                    wxTreeItemId node )
00455 {
00456 
00457     for( int i = 0; i< p_node->i_children ; i++ )
00458     {
00459         /* Append the item */
00460         if( p_node->pp_children[i]->i_children == -1 )
00461         {
00462             wxTreeItemId item =
00463                 treectrl->AppendItem( node,
00464                     wxL2U( p_node->pp_children[i]->input.psz_name ), -1,-1,
00465                            new PlaylistItem( p_node->pp_children[i]) );
00466 
00467             UpdateTreeItem( item );
00468         }
00469         else
00470         {
00471             CreateNode( p_node->pp_children[i], node );
00472         }
00473     }
00474 }
00475 
00476 /* Update an item in the tree */
00477 void Playlist::UpdateTreeItem( wxTreeItemId item )
00478 {
00479     if( ! item.IsOk() ) return;
00480 
00481     wxTreeItemData *p_data = treectrl->GetItemData( item );
00482     if( !p_data ) return;
00483 
00484     LockPlaylist( p_intf->p_sys, p_playlist );
00485     playlist_item_t *p_item = playlist_ItemGetById( p_playlist,
00486                                           ((PlaylistItem *)p_data)->i_id );
00487     if( !p_item )
00488     {
00489         UnlockPlaylist( p_intf->p_sys, p_playlist );
00490         return;
00491     }
00492 
00493     wxString msg;
00494     wxString duration = wxU( "" );
00495     char *psz_author = vlc_input_item_GetInfo( &p_item->input,
00496                                                      _("Meta-information"),
00497                                                      _("Artist"));
00498     if( !psz_author )
00499     {
00500         UnlockPlaylist( p_intf->p_sys, p_playlist );
00501         return;
00502     }
00503 
00504     char psz_duration[MSTRTIME_MAX_SIZE];
00505     mtime_t dur = p_item->input.i_duration;
00506 
00507     if( dur != -1 )
00508     {
00509         secstotimestr( psz_duration, dur/1000000 );
00510         duration.Append( wxU( " ( " ) +  wxString( wxU( psz_duration ) ) +
00511                          wxU( " )" ) );
00512     }
00513 
00514     if( !strcmp( psz_author, "" ) || p_item->input.b_fixed_name == VLC_TRUE )
00515     {
00516         msg = wxString( wxU( p_item->input.psz_name ) ) + duration;
00517     }
00518     else
00519     {
00520         msg = wxString(wxU( psz_author )) + wxT(" - ") +
00521                     wxString(wxU(p_item->input.psz_name)) + duration;
00522     }
00523     free( psz_author );
00524     treectrl->SetItemText( item , msg );
00525     treectrl->SetItemImage( item, p_item->input.i_type );
00526 
00527     if( p_playlist->status.p_item == p_item )
00528     {
00529         treectrl->SetItemBold( item, true );
00530         while( treectrl->GetItemParent( item ).IsOk() )
00531         {
00532             item = treectrl->GetItemParent( item );
00533             treectrl->Expand( item );
00534         }
00535     }
00536     else
00537     {
00538         treectrl->SetItemBold( item, false );
00539     }
00540     UnlockPlaylist( p_intf->p_sys, p_playlist );
00541 }
00542 
00543 /* Process a AppendIt em request */
00544 void Playlist::AppendItem( wxCommandEvent& event )
00545 {
00546     playlist_add_t *p_add = (playlist_add_t *)event.GetClientData();
00547     playlist_item_t *p_item = NULL;
00548     wxTreeItemId item, node;
00549 
00550     i_items_to_append--;
00551 
00552     /* No need to do anything if the playlist is going to be rebuilt */
00553     if( b_need_update ) return;
00554 
00555     if( p_add->i_view != i_current_view ) goto update;
00556 
00557     node = FindItem( treectrl->GetRootItem(), p_add->i_node );
00558     if( !node.IsOk() ) goto update;
00559 
00560     p_item = playlist_ItemGetById( p_playlist, p_add->i_item );
00561     if( !p_item ) goto update;
00562 
00563     item = FindItem( treectrl->GetRootItem(), p_add->i_item );
00564     if( item.IsOk() ) goto update;
00565 
00566     item = treectrl->AppendItem( node,
00567                                  wxL2U( p_item->input.psz_name ), -1,-1,
00568                                  new PlaylistItem( p_item ) );
00569     treectrl->SetItemImage( item, p_item->input.i_type );
00570 
00571     if( item.IsOk() && p_item->i_children == -1 )
00572     {
00573         UpdateTreeItem( item );
00574     }
00575 
00576 update:
00577     int i_count = CountItems( treectrl->GetRootItem());
00578     if( i_count != p_playlist->i_size )
00579     {
00580         statusbar->SetStatusText( wxString::Format( wxU(_(
00581                                   "%i items in playlist (%i not shown)")),
00582                                   p_playlist->i_size,
00583                                   p_playlist->i_size - i_count ) );
00584         if( !b_changed_view )
00585         {
00586             i_current_view = VIEW_CATEGORY;
00587             b_changed_view = VLC_TRUE;
00588             b_need_update = VLC_TRUE;
00589         }
00590     }
00591     else
00592     {
00593         statusbar->SetStatusText( wxString::Format( wxU(_(
00594                                   "%i items in playlist")),
00595                                   p_playlist->i_size ), 0 );
00596     }
00597 
00598     return;
00599 }
00600 
00601 /* Process a updateitem request */
00602 void Playlist::UpdateItem( int i )
00603 {
00604     if( i < 0 ) return; /* Sanity check */
00605 
00606     wxTreeItemId item = FindItem( treectrl->GetRootItem(), i );
00607 
00608     if( item.IsOk() )
00609     {
00610         UpdateTreeItem( item );
00611     }
00612 }
00613 
00614 void Playlist::RemoveItem( int i )
00615 {
00616     if( i <= 0 ) return; /* Sanity check */
00617     if( i == i_saved_id ) i_saved_id = -1;
00618 
00619     wxTreeItemId item = FindItem( treectrl->GetRootItem(), i );
00620 
00621     if( item.IsOk() )
00622     {
00623         treectrl->Delete( item );
00624     }
00625 }
00626 
00627 
00628 /**********************************************************************
00629  * Search functions (internal)
00630  **********************************************************************/
00631 
00632 /* Find a wxItem from a playlist id */
00633 wxTreeItemId Playlist::FindItem( wxTreeItemId root, int i_id )
00634 {
00635     wxTreeItemIdValue cookie;
00636     PlaylistItem *p_wxcurrent;
00637     wxTreeItemId search;
00638     wxTreeItemId item = treectrl->GetFirstChild( root, cookie );
00639     wxTreeItemId child;
00640 
00641     p_wxcurrent = (PlaylistItem *)treectrl->GetItemData( root );
00642 
00643     if( i_id < 0 )
00644     {
00645         wxTreeItemId dummy;
00646         return dummy;
00647     }
00648     if( i_saved_id == i_id )
00649     {
00650         return saved_tree_item;
00651     }
00652 
00653     if( !p_wxcurrent )
00654     {
00655         wxTreeItemId dummy;
00656         return dummy;
00657     }
00658 
00659     if( p_wxcurrent->i_id == i_id )
00660     {
00661         i_saved_id = i_id;
00662         saved_tree_item = root;
00663         return root;
00664     }
00665 
00666     while( item.IsOk() )
00667     {
00668         p_wxcurrent = (PlaylistItem *)treectrl->GetItemData( item );
00669         if( p_wxcurrent->i_id == i_id )
00670         {
00671             i_saved_id = i_id;
00672             saved_tree_item = item;
00673             return item;
00674         }
00675         if( treectrl->ItemHasChildren( item ) )
00676         {
00677             wxTreeItemId search = FindItem( item, i_id );
00678             if( search.IsOk() )
00679             {
00680                 i_saved_id = i_id;
00681                 saved_tree_item = search;
00682                 return search;
00683             }
00684         }
00685         item = treectrl->GetNextChild( root, cookie );
00686     }
00687     /* Not found */
00688     wxTreeItemId dummy;
00689     return dummy;
00690 }
00691 
00692 int Playlist::CountItems( wxTreeItemId root )
00693 {
00694     wxTreeItemIdValue cookie;
00695     int count = 0;
00696     wxTreeItemId item = treectrl->GetFirstChild( root, cookie );
00697 
00698     while( item.IsOk() )
00699     {
00700         if( treectrl->ItemHasChildren( item ) )
00701         {
00702             count += CountItems( item );
00703         }
00704         else
00705         {
00706             playlist_item_t *p_item;
00707             LockPlaylist( p_intf->p_sys, p_playlist );
00708             p_item = playlist_ItemGetById( p_playlist, ((PlaylistItem *)treectrl->GetItemData( item ))->i_id );
00709             if( p_item && p_item->i_children == -1 )
00710                 count++;
00711             UnlockPlaylist( p_intf->p_sys, p_playlist );
00712         }
00713         item = treectrl->GetNextChild( root, cookie );
00714     }
00715     return count;
00716 }
00717 
00718 /* Find a wxItem from a name (from current) */
00719 wxTreeItemId Playlist::FindItemByName( wxTreeItemId root, wxString search_string, wxTreeItemId current, vlc_bool_t *pb_current_found )
00720 {
00721     wxTreeItemIdValue cookie;
00722     wxTreeItemId search;
00723     wxTreeItemId item = treectrl->GetFirstChild( root, cookie );
00724     wxTreeItemId child;
00725 
00726     while( item.IsOk() )
00727     {
00728         if( treectrl->GetItemText( item).Lower().Contains(
00729                                                  search_string.Lower() ) )
00730         {
00731             if( !current.IsOk() || *pb_current_found == VLC_TRUE )
00732             {
00733                 return item;
00734             }
00735             else if( current.IsOk() && item == current )
00736             {
00737                 *pb_current_found = VLC_TRUE;
00738             }
00739         }
00740         if( treectrl->ItemHasChildren( item ) )
00741         {
00742             wxTreeItemId search = FindItemByName( item, search_string, current,
00743                                                   pb_current_found );
00744             if( search.IsOk() )
00745             {
00746                 return search;
00747             }
00748         }
00749         item = treectrl->GetNextChild( root, cookie);
00750     }
00751     /* Not found */
00752     wxTreeItemId dummy;
00753     return dummy;
00754 }
00755 
00756 /**********************************************************************
00757  * Rebuild the playlist
00758  **********************************************************************/
00759 void Playlist::Rebuild( vlc_bool_t b_root )
00760 {
00761     playlist_view_t *p_view;
00762 
00763     i_items_to_append = 0;
00764 
00765     /* We can remove the callbacks before locking, anyway, we won't
00766      * miss anything */
00767     if( b_root )
00768     {
00769         var_DelCallback( p_playlist, "item-change", ItemChanged, this );
00770         var_DelCallback( p_playlist, "playlist-current", PlaylistNext, this );
00771         var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this );
00772         var_DelCallback( p_playlist, "item-append", ItemAppended, this );
00773         var_DelCallback( p_playlist, "item-deleted", ItemDeleted, this );
00774 
00775         /* ...and rebuild it */
00776         LockPlaylist( p_intf->p_sys, p_playlist );
00777     }
00778     i_saved_id = -1;
00779 
00780     p_view = playlist_ViewFind( p_playlist, i_current_view ); /* FIXME */
00781 
00782     /* HACK we should really get new*/
00783     treectrl->DeleteAllItems();
00784     treectrl->AddRoot( wxU(_("root" )), -1, -1,
00785                          new PlaylistItem( p_view->p_root) );
00786 
00787     wxTreeItemId root = treectrl->GetRootItem();
00788     UpdateNode( p_view->p_root, root );
00789 
00790     int i_count = CountItems( treectrl->GetRootItem() );
00791 
00792     if( i_count < p_playlist->i_size && !b_changed_view )
00793     {
00794         i_current_view = VIEW_CATEGORY;
00795         b_changed_view = VLC_TRUE;
00796         Rebuild( VLC_FALSE );
00797     }
00798     else if( i_count != p_playlist->i_size )
00799     {
00800         statusbar->SetStatusText( wxString::Format( wxU(_(
00801                                   "%i items in playlist (%i not shown)")),
00802                                   p_playlist->i_size,
00803                                   p_playlist->i_size - i_count ) );
00804     }
00805     else
00806     {
00807         statusbar->SetStatusText( wxString::Format( wxU(_(
00808                                   "%i items in playlist")),
00809                                   p_playlist->i_size ), 0 );
00810     }
00811 
00812     if( b_root )
00813     {
00814         /* Put callbacks back online */
00815         var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this );
00816         var_AddCallback( p_playlist, "playlist-current", PlaylistNext, this );
00817         var_AddCallback( p_playlist, "item-change", ItemChanged, this );
00818         var_AddCallback( p_playlist, "item-append", ItemAppended, this );
00819         var_AddCallback( p_playlist, "item-deleted", ItemDeleted, this );
00820 
00821         UnlockPlaylist( p_intf->p_sys, p_playlist );
00822     }
00823 }
00824 
00825 
00826 
00827 void Playlist::ShowPlaylist( bool show )
00828 {
00829     if( show ) Rebuild( VLC_TRUE );
00830     Show( show );
00831 }
00832 
00833 /* This function is called on a regular basis */
00834 void Playlist::UpdatePlaylist()
00835 {
00836     i_update_counter++;
00837 
00838     /* If the playlist isn't show there's no need to update it */
00839     if( !IsShown() ) return;
00840 
00841     if( this->b_need_update )
00842     {
00843         this->b_need_update = VLC_FALSE;
00844         Rebuild( VLC_TRUE );
00845     }
00846 
00847     /* Updating the playing status every 0.5s is enough */
00848     if( i_update_counter % 5 ) return;
00849 }
00850 
00851 /*****************************************************************************
00852  * Private methods.
00853  *****************************************************************************/
00854 void Playlist::DeleteTreeItem( wxTreeItemId item )
00855 {
00856    PlaylistItem *p_wxitem;
00857    playlist_item_t *p_item;
00858    p_wxitem = (PlaylistItem *)treectrl->GetItemData( item );
00859 
00860    LockPlaylist( p_intf->p_sys, p_playlist );
00861    p_item = playlist_ItemGetById( p_playlist, p_wxitem->i_id );
00862 
00863    if( !p_item )
00864    {
00865        UnlockPlaylist( p_intf->p_sys, p_playlist );
00866        return;
00867    }
00868 
00869    if( p_item->i_children == -1 ) DeleteItem( p_item->input.i_id );
00870    else DeleteNode( p_item );
00871 
00872    RemoveItem( item );
00873    UnlockPlaylist( p_intf->p_sys, p_playlist );
00874 }
00875 
00876 void Playlist::DeleteItem( int item_id )
00877 {
00878     playlist_LockDelete( p_playlist, item_id );
00879 }
00880 
00881 void Playlist::DeleteNode( playlist_item_t *p_item )
00882 {
00883     playlist_NodeDelete( p_playlist, p_item, VLC_TRUE , VLC_FALSE );
00884 }
00885 
00886 void Playlist::OnMenuClose( wxCommandEvent& event )
00887 {
00888     wxCloseEvent cevent;
00889     OnClose(cevent);
00890 }
00891 
00892 void Playlist::OnClose( wxCloseEvent& WXUNUSED(event) )
00893 {
00894     Hide();
00895 }
00896 
00897 void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) )
00898 {
00899     struct {
00900         char *psz_desc;
00901         char *psz_filter;
00902         char *psz_module;
00903     } formats[] = {{ _("M3U file"), "*.m3u", "export-m3u" }};
00904 
00905     wxString filter = wxT("");
00906 
00907     if( p_playlist->i_size == 0 )
00908     {
00909         wxMessageBox( wxU(_("Playlist is empty") ), wxU(_("Can't save")),
00910                       wxICON_WARNING | wxOK, this );
00911         return;
00912     }
00913 
00914     for( unsigned int i = 0; i < sizeof(formats)/sizeof(formats[0]); i++)
00915     {
00916         filter.Append( wxU(formats[i].psz_desc) );
00917         filter.Append( wxT("|") );
00918         filter.Append( wxU(formats[i].psz_filter) );
00919         filter.Append( wxT("|") );
00920     }
00921     wxFileDialog dialog( this, wxU(_("Save playlist")),
00922                          wxT(""), wxT(""), filter, wxSAVE );
00923 
00924     if( dialog.ShowModal() == wxID_OK )
00925     {
00926         if( dialog.GetPath().mb_str() )
00927         {
00928             playlist_Export( p_playlist, dialog.GetPath().mb_str(),
00929                              formats[dialog.GetFilterIndex()].psz_module );
00930         }
00931     }
00932 
00933 }
00934 
00935 void Playlist::OnOpen( wxCommandEvent& WXUNUSED(event) )
00936 {
00937     wxFileDialog dialog( this, wxU(_("Open playlist")), wxT(""), wxT(""),
00938         wxT("All playlists|*.pls;*.m3u;*.asx;*.b4s|M3U files|*.m3u"), wxOPEN );
00939 
00940     if( dialog.ShowModal() == wxID_OK )
00941     {
00942         playlist_Import( p_playlist, dialog.GetPath().mb_str() );
00943     }
00944 }
00945 
00946 void Playlist::OnAddFile( wxCommandEvent& WXUNUSED(event) )
00947 {
00948     p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE_SIMPLE, 0, 0 );
00949 
00950 }
00951 
00952 void Playlist::OnAddDir( wxCommandEvent& WXUNUSED(event) )
00953 {
00954     p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_DIRECTORY, 0, 0 );
00955 
00956 }
00957 
00958 void Playlist::OnAddMRL( wxCommandEvent& WXUNUSED(event) )
00959 {
00960     p_intf->p_sys->pf_show_dialog( p_intf, INTF_DIALOG_FILE, 0, 0 );
00961 
00962 }
00963 
00964 /********************************************************************
00965  * Sorting functions
00966  ********************************************************************/
00967 void Playlist::OnSort( wxCommandEvent& event )
00968 {
00969     PlaylistItem *p_wxitem;
00970     p_wxitem = (PlaylistItem *)treectrl->GetItemData( treectrl->GetRootItem() );
00971 
00972     LockPlaylist( p_intf->p_sys, p_playlist );
00973     switch( event.GetId() )
00974     {
00975         case SortTitle_Event:
00976             playlist_RecursiveNodeSort( p_playlist,
00977                             playlist_ItemGetById( p_playlist, p_wxitem->i_id ),
00978                             SORT_TITLE_NODES_FIRST, ORDER_NORMAL );
00979             break;
00980         case RSortTitle_Event:
00981             playlist_RecursiveNodeSort( p_playlist,
00982                             playlist_ItemGetById( p_playlist, p_wxitem->i_id ),
00983                             SORT_TITLE_NODES_FIRST, ORDER_REVERSE );
00984     }
00985     UnlockPlaylist( p_intf->p_sys, p_playlist );
00986 
00987     Rebuild( VLC_TRUE );
00988 }
00989 
00990 /**********************************************************************
00991  * Search functions (user)
00992  **********************************************************************/
00993 /*void Playlist::OnSearchTextChange( wxCommandEvent& WXUNUSED(event) )
00994 {
00995    search_button->SetDefault();
00996 }*/
00997 
00998 void Playlist::OnSearch( wxCommandEvent& WXUNUSED(event) )
00999 {
01000     wxString search_string = search_text->GetValue();
01001 
01002     vlc_bool_t pb_found = VLC_FALSE;
01003 
01004     wxTreeItemId found =
01005      FindItemByName( treectrl->GetRootItem(), search_string,
01006                      search_current, &pb_found );
01007 
01008     if( !found.IsOk() )
01009     {
01010         wxTreeItemId dummy;
01011         search_current = dummy;
01012         found =  FindItemByName( treectrl->GetRootItem(), search_string,
01013                                  search_current, &pb_found );
01014     }
01015 
01016     if( found.IsOk() )
01017     {
01018         search_current = found;
01019         treectrl->EnsureVisible( found );
01020         treectrl->UnselectAll();
01021         treectrl->SelectItem( found, true );
01022     }
01023 }
01024 
01025 /**********************************************************************
01026  * Selection functions
01027  **********************************************************************/
01028 void Playlist::RecursiveDeleteSelection(  wxTreeItemId root )
01029 {
01030     wxTreeItemIdValue cookie;
01031     wxTreeItemId child = treectrl->GetFirstChild( root, cookie );
01032     while( child.IsOk() )
01033     {
01034         if( treectrl->ItemHasChildren( child ) )
01035         {
01036             RecursiveDeleteSelection( child );
01037             if( treectrl->IsSelected(child ) ) DeleteTreeItem( child );
01038         }
01039         else if( treectrl->IsSelected( child ) )
01040             DeleteTreeItem( child );
01041         child = treectrl->GetNextChild( root, cookie );
01042     }
01043 }
01044 
01045 void Playlist::OnDeleteSelection( wxCommandEvent& WXUNUSED(event) )
01046 {
01047     RecursiveDeleteSelection( treectrl->GetRootItem() );
01048 }
01049 
01050 /**********************************************************************
01051  * Playlist mode functions
01052  **********************************************************************/
01053 void Playlist::OnRandom( wxCommandEvent& event )
01054 {
01055     vlc_value_t val;
01056     val.b_bool = event.IsChecked();
01057     var_Set( p_playlist, "random", val);
01058 }
01059 
01060 void Playlist::OnLoop( wxCommandEvent& event )
01061 {
01062     vlc_value_t val;
01063     val.b_bool = event.IsChecked();
01064     var_Set( p_playlist, "loop", val);
01065 }
01066 
01067 void Playlist::OnRepeat( wxCommandEvent& event )
01068 {
01069     vlc_value_t val;
01070     val.b_bool = event.IsChecked();
01071     var_Set( p_playlist, "repeat", val);
01072 }
01073 
01074 /********************************************************************
01075  * Event
01076  ********************************************************************/
01077 void Playlist::OnActivateItem( wxTreeEvent& event )
01078 {
01079     playlist_item_t *p_item,*p_node,*p_item2,*p_node2;
01080 
01081     PlaylistItem *p_wxitem = (PlaylistItem *)treectrl->GetItemData(
01082                                                             event.GetItem() );
01083     wxTreeItemId parent = treectrl->GetItemParent( event.GetItem() );
01084 
01085     PlaylistItem *p_wxparent = (PlaylistItem *)treectrl->GetItemData( parent );
01086 
01087     LockPlaylist( p_intf->p_sys, p_playlist );
01088 
01089     if( !( p_wxitem && p_wxparent ) )
01090     {
01091         UnlockPlaylist( p_intf->p_sys, p_playlist );
01092         return;
01093     }
01094 
01095     p_item2 = playlist_ItemGetById(p_playlist, p_wxitem->i_id);
01096     p_node2 = playlist_ItemGetById(p_playlist, p_wxparent->i_id);
01097     if( p_item2 && p_item2->i_children == -1 )
01098     {
01099         p_node = p_node2;
01100         p_item = p_item2;
01101     }
01102     else
01103     {
01104         p_node = p_item2;
01105         if( p_node && p_node->i_children > 0 &&
01106             p_node->pp_children[0]->i_children == -1)
01107         {
01108             p_item = p_node->pp_children[0];
01109         }
01110         else
01111         {
01112             p_item = NULL;
01113         }
01114     }
01115 
01116     playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, i_current_view,
01117                       p_node, p_item );
01118     UnlockPlaylist( p_intf->p_sys, p_playlist );
01119 }
01120 
01121 void Playlist::OnKeyDown( wxTreeEvent& event )
01122 {
01123     long keycode = event.GetKeyCode();
01124     /* Delete selected items */
01125     if( keycode == WXK_BACK || keycode == WXK_DELETE )
01126     {
01127         /* We send a dummy event */
01128         OnDeleteSelection( event );
01129     }
01130     else
01131     {
01132         event.Skip();
01133     }
01134 }
01135 
01136 void Playlist::OnEnDis( wxCommandEvent& event )
01137 {
01138     msg_Warn( p_intf, "not implemented" );
01139 }
01140 
01141 /**********************************************************************
01142  * Menu
01143  **********************************************************************/
01144 
01145 void Playlist::OnMenuOpen( wxMenuEvent& event)
01146 {
01147 #if defined( __WXMSW__ )
01148 #   define GetEventObject GetMenu
01149 #endif
01150 
01151     if( event.GetEventObject() == p_view_menu )
01152     {
01153         p_view_menu = ViewMenu();
01154     }
01155 #if defined( __WXMSW__ )
01156 #   undef GetEventObject
01157 #endif
01158 }
01159 
01160 void Playlist::OnMenuEvent( wxCommandEvent& event )
01161 {
01162     if( event.GetId() < FirstView_Event )
01163     {
01164         event.Skip();
01165         return;
01166     }
01167     else if( event.GetId() < LastView_Event )
01168     {
01169 
01170         int i_new_view = event.GetId() - FirstView_Event;
01171 
01172         playlist_view_t *p_view = playlist_ViewFind( p_playlist, i_new_view );
01173 
01174         if( p_view != NULL )
01175         {
01176             b_changed_view = VLC_TRUE;
01177             i_current_view = i_new_view;
01178             playlist_ViewUpdate( p_playlist, i_new_view );
01179             Rebuild( VLC_TRUE );
01180             return;
01181         }
01182         else if( i_new_view >= VIEW_FIRST_SORTED &&
01183                  i_new_view <= VIEW_LAST_SORTED )
01184         {
01185             b_changed_view = VLC_TRUE;
01186             playlist_ViewInsert( p_playlist, i_new_view, "View" );
01187             playlist_ViewUpdate( p_playlist, i_new_view );
01188 
01189             i_current_view = i_new_view;
01190 
01191             Rebuild( VLC_TRUE );
01192         }
01193     }
01194     else if( event.GetId() >= FirstSD_Event && event.GetId() < LastSD_Event )
01195     {
01196         if( !playlist_IsServicesDiscoveryLoaded( p_playlist,
01197                                 pp_sds[event.GetId() - FirstSD_Event] ) )
01198         {
01199             playlist_ServicesDiscoveryAdd( p_playlist,
01200                             pp_sds[event.GetId() - FirstSD_Event] );
01201         }
01202         else
01203         {
01204             //wxMutexGuiLeave();
01205             playlist_ServicesDiscoveryRemove( p_playlist,
01206                             pp_sds[event.GetId() - FirstSD_Event] );
01207             //wxMutexGuiEnter();
01208         }
01209     }
01210 }
01211 
01212 wxMenu * Playlist::ViewMenu()
01213 {
01214     if( !p_view_menu )
01215     {
01216         p_view_menu = new wxMenu;
01217     }
01218     else
01219     {
01220         wxMenuItemList::Node *node = p_view_menu->GetMenuItems().GetFirst();
01221         for( ; node; )
01222         {
01223             wxMenuItem *item = node->GetData();
01224             node = node->GetNext();
01225             p_view_menu->Delete( item );
01226         }
01227     }
01228 
01229     /* FIXME : have a list of "should have" views */
01230     p_view_menu->Append( FirstView_Event + VIEW_CATEGORY,
01231                            wxU(_("Normal") ) );
01232     p_view_menu->Append( FirstView_Event + VIEW_S_AUTHOR,
01233                            wxU(_("Sorted by artist") ) );
01234     p_view_menu->Append( FirstView_Event + VIEW_S_ALBUM,
01235                            wxU(_("Sorted by Album") ) );
01236 
01237     return p_view_menu;
01238 }
01239 
01240 wxMenu *Playlist::SDMenu()
01241 {
01242     p_sd_menu = new wxMenu;
01243 
01244     vlc_list_t *p_list = vlc_list_find( p_playlist, VLC_OBJECT_MODULE,
01245                                         FIND_ANYWHERE );
01246 
01247     int i_number = 0;
01248     for( int i_index = 0; i_index < p_list->i_count; i_index++ )
01249     {
01250         module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object ;
01251 
01252         if( !strcmp( p_parser->psz_capability, "services_discovery" ) )
01253             i_number++;
01254     }
01255     if( i_number ) pp_sds = (char **)calloc( i_number, sizeof(void *) );
01256 
01257     i_number = 0;
01258     for( int i_index = 0; i_index < p_list->i_count; i_index++ )
01259     {
01260         module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object ;
01261 
01262         if( !strcmp( p_parser->psz_capability, "services_discovery" ) )
01263         {
01264             p_sd_menu->AppendCheckItem( FirstSD_Event + i_number ,
01265                 wxU( p_parser->psz_longname ? p_parser->psz_longname :
01266                      (p_parser->psz_shortname ?
01267                       p_parser->psz_shortname : p_parser->psz_object_name) ) );
01268 
01269             if( playlist_IsServicesDiscoveryLoaded( p_playlist,
01270                                     p_parser->psz_object_name ) )
01271             {
01272                 p_sd_menu->Check( FirstSD_Event + i_number, TRUE );
01273             }
01274 
01275             pp_sds[i_number++] = p_parser->psz_object_name;
01276         }
01277     }
01278     vlc_list_release( p_list );
01279     return p_sd_menu;
01280 }
01281 
01282 
01283 /*****************************************************************************
01284  * Popup management functions
01285  *****************************************************************************/
01286 void Playlist::OnPopup( wxContextMenuEvent& event )
01287 {
01288     wxPoint pt = event.GetPosition();
01289     playlist_item_t *p_item;
01290 
01291     i_wx_popup_item = treectrl->HitTest( ScreenToClient( pt ) );
01292     if( i_wx_popup_item.IsOk() )
01293     {
01294         PlaylistItem *p_wxitem = (PlaylistItem *)treectrl->GetItemData(
01295                                                             i_wx_popup_item );
01296         PlaylistItem *p_wxparent= (PlaylistItem *)treectrl->GetItemData(
01297                                   treectrl->GetItemParent( i_wx_popup_item ) );
01298         i_popup_item = p_wxitem->i_id;
01299         i_popup_parent = p_wxparent->i_id;
01300         treectrl->SelectItem( i_wx_popup_item );
01301 
01302         LockPlaylist( p_intf->p_sys, p_playlist );
01303         p_item = playlist_ItemGetById( p_playlist, i_popup_item );
01304 
01305         if( !p_item )
01306         {
01307             UnlockPlaylist( p_intf->p_sys, p_playlist );
01308             return;
01309         }
01310         if( p_item->i_children == -1 )
01311         {
01312             UnlockPlaylist( p_intf->p_sys, p_playlist );
01313             Playlist::PopupMenu( item_popup,
01314                                  ScreenToClient( wxGetMousePosition() ) );
01315         }
01316         else
01317         {
01318             UnlockPlaylist( p_intf->p_sys, p_playlist );
01319             Playlist::PopupMenu( node_popup,
01320                                  ScreenToClient( wxGetMousePosition() ) );
01321         }
01322     }
01323 }
01324 
01325 void Playlist::OnPopupPlay( wxCommandEvent& event )
01326 {
01327     playlist_item_t *p_popup_item, *p_popup_parent;
01328     LockPlaylist( p_intf->p_sys, p_playlist );
01329     p_popup_item = playlist_ItemGetById( p_playlist, i_popup_item );
01330     p_popup_parent = playlist_ItemGetById( p_playlist, i_popup_parent );
01331     if( p_popup_item != NULL )
01332     {
01333         if( p_popup_item->i_children > -1 )
01334         {
01335             if( event.GetId() == PopupPlay_Event &&
01336                 p_popup_item->i_children > 0 )
01337             {
01338                 playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
01339                                   i_current_view, p_popup_item,
01340                                   p_popup_item->pp_children[0] );
01341             }
01342             else
01343             {
01344                 playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
01345                                   i_current_view, p_popup_item, NULL );
01346             }
01347         }
01348         else
01349         {
01350             if( event.GetId() == PopupPlay_Event )
01351             {
01352                 playlist_Control( p_playlist, PLAYLIST_VIEWPLAY,
01353                                   i_current_view, p_popup_parent,
01354                                   p_popup_item );
01355             }
01356         }
01357     }
01358     UnlockPlaylist( p_intf->p_sys, p_playlist );
01359 }
01360 
01361 void Playlist::OnPopupPreparse( wxCommandEvent& event )
01362 {
01363     Preparse();
01364 }
01365 
01366 void Playlist::Preparse()
01367 {
01368     playlist_item_t *p_popup_item;
01369     LockPlaylist( p_intf->p_sys, p_playlist );
01370     p_popup_item = playlist_ItemGetById( p_playlist, i_popup_item );
01371 
01372     if( p_popup_item != NULL )
01373     {
01374         if( p_popup_item->i_children == -1 )
01375         {
01376             playlist_PreparseEnqueue( p_playlist, &p_popup_item->input );
01377         }
01378         else
01379         {
01380             int i = 0;
01381             playlist_item_t *p_parent = p_popup_item;
01382             for( i = 0; i< p_parent->i_children ; i++ )
01383             {
01384                 wxMenuEvent dummy;
01385                 i_wx_popup_item = FindItem( treectrl->GetRootItem(),
01386                                          p_parent->pp_children[i]->input.i_id );
01387                 i_popup_item = p_parent->pp_children[i]->input.i_id;
01388                 Preparse();
01389             }
01390         }
01391     }
01392     UnlockPlaylist( p_intf->p_sys, p_playlist );
01393 }
01394 
01395 void Playlist::OnPopupDel( wxCommandEvent& event )
01396 {
01397     DeleteTreeItem( i_wx_popup_item );
01398 }
01399 
01400 void Playlist::OnPopupSort( wxCommandEvent& event )
01401 {
01402     PlaylistItem *p_wxitem;
01403     playlist_item_t *p_item;
01404 
01405     p_wxitem = (PlaylistItem *)treectrl->GetItemData( i_wx_popup_item );
01406     LockPlaylist( p_intf->p_sys, p_playlist );
01407 
01408     p_item = playlist_ItemGetById( p_playlist, p_wxitem->i_id );
01409     if( p_item->i_children >= 0 )
01410     {
01411         playlist_RecursiveNodeSort( p_playlist, p_item,
01412                                     SORT_TITLE_NODES_FIRST, ORDER_NORMAL );
01413 
01414         treectrl->DeleteChildren( i_wx_popup_item );
01415         i_saved_id = -1;
01416         UpdateNodeChildren( p_item, i_wx_popup_item );
01417 
01418     }
01419     UnlockPlaylist( p_intf->p_sys, p_playlist );
01420 }
01421 
01422 void Playlist::OnPopupInfo( wxCommandEvent& event )
01423 {
01424     LockPlaylist( p_intf->p_sys, p_playlist );
01425     playlist_item_t *p_popup_item = playlist_ItemGetById( p_playlist, i_popup_item );
01426     if( p_popup_item )
01427     {
01428         iteminfo_dialog = new ItemInfoDialog( p_intf, p_popup_item, this );
01429         if( iteminfo_dialog->ShowModal() == wxID_OK )
01430         {
01431             UpdateItem( i_wx_popup_item );
01432         }
01433         delete iteminfo_dialog;
01434     }
01435     UnlockPlaylist( p_intf->p_sys, p_playlist );
01436 }
01437 
01438 
01439 /*****************************************************************************
01440  * Custom events management
01441  *****************************************************************************/
01442 void Playlist::OnPlaylistEvent( wxCommandEvent& event )
01443 {
01444     switch( event.GetId() )
01445     {
01446         case UpdateItem_Event:
01447             UpdateItem( event.GetInt() );
01448             break;
01449         case AppendItem_Event:
01450             AppendItem( event );
01451             break;
01452         case RemoveItem_Event:
01453             RemoveItem( event.GetInt() );
01454             break;
01455     }
01456 }
01457 
01458 /*****************************************************************************
01459  * PlaylistChanged: callback triggered by the intf-change playlist variable
01460  *  We don't rebuild the playlist directly here because we don't want the
01461  *  caller to block for a too long time.
01462  *****************************************************************************/
01463 static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
01464                             vlc_value_t oval, vlc_value_t nval, void *param )
01465 {
01466     Playlist *p_playlist_dialog = (Playlist *)param;
01467     p_playlist_dialog->b_need_update = VLC_TRUE;
01468     return VLC_SUCCESS;
01469 }
01470 
01471 /*****************************************************************************
01472  * Next: callback triggered by the playlist-current playlist variable
01473  *****************************************************************************/
01474 static int PlaylistNext( vlc_object_t *p_this, const char *psz_variable,
01475                          vlc_value_t oval, vlc_value_t nval, void *param )
01476 {
01477     Playlist *p_playlist_dialog = (Playlist *)param;
01478 
01479     wxCommandEvent event( wxEVT_PLAYLIST, UpdateItem_Event );
01480     event.SetInt( oval.i_int );
01481     p_playlist_dialog->AddPendingEvent( event );
01482     event.SetInt( nval.i_int );
01483     p_playlist_dialog->AddPendingEvent( event );
01484 
01485     return 0;
01486 }
01487 
01488 /*****************************************************************************
01489  * ItemChanged: callback triggered by the item-change playlist variable
01490  *****************************************************************************/
01491 static int ItemChanged( vlc_object_t *p_this, const char *psz_variable,
01492                         vlc_value_t old_val, vlc_value_t new_val, void *param )
01493 {
01494     Playlist *p_playlist_dialog = (Playlist *)param;
01495 
01496     wxCommandEvent event( wxEVT_PLAYLIST, UpdateItem_Event );
01497     event.SetInt( new_val.i_int );
01498     p_playlist_dialog->AddPendingEvent( event );
01499 
01500     return 0;
01501 }
01502 static int ItemDeleted( vlc_object_t *p_this, const char *psz_variable,
01503                         vlc_value_t old_val, vlc_value_t new_val, void *param )
01504 {
01505     Playlist *p_playlist_dialog = (Playlist *)param;
01506 
01507     wxCommandEvent event( wxEVT_PLAYLIST, RemoveItem_Event );
01508     event.SetInt( new_val.i_int );
01509     p_playlist_dialog->AddPendingEvent( event );
01510 
01511     return 0;
01512 }
01513 
01514 static int ItemAppended( vlc_object_t *p_this, const char *psz_variable,
01515                          vlc_value_t oval, vlc_value_t nval, void *param )
01516 {
01517     Playlist *p_playlist_dialog = (Playlist *)param;
01518 
01519     playlist_add_t *p_add = (playlist_add_t *)malloc(sizeof( playlist_add_t));
01520     memcpy( p_add, nval.p_address, sizeof( playlist_add_t ) );
01521 
01522     if( p_playlist_dialog->i_items_to_append++ > 50 )
01523     {
01524         /* Too many items waiting to be added, it will be quicker to rebuild
01525          * the whole playlist */
01526         p_playlist_dialog->b_need_update = VLC_TRUE;
01527         return VLC_SUCCESS;
01528     }
01529 
01530     wxCommandEvent event( wxEVT_PLAYLIST, AppendItem_Event );
01531     event.SetClientData( (void *)p_add );
01532     p_playlist_dialog->AddPendingEvent( event );
01533 
01534     return VLC_SUCCESS;
01535 }
01536 }

Generated on Tue Dec 20 10:14:43 2005 for vlc-0.8.4a by  doxygen 1.4.2