X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fwxwidgets%2Fdialogs%2Fplaylist.cpp;h=81565fa3ef2bc36ef4123507636092cb50b33344;hb=7f779f6a64eadd10b2e2b98bcf85fdd38c0cdfa5;hp=9f4cfa00c37025a57ff8a8efd2dcd2c4584a0a92;hpb=b03c31e488d275c94853a70417a0ac31fc0377af;p=vlc diff --git a/modules/gui/wxwidgets/dialogs/playlist.cpp b/modules/gui/wxwidgets/dialogs/playlist.cpp index 9f4cfa00c3..81565fa3ef 100644 --- a/modules/gui/wxwidgets/dialogs/playlist.cpp +++ b/modules/gui/wxwidgets/dialogs/playlist.cpp @@ -4,8 +4,8 @@ * Copyright (C) 2000-2005 the VideoLAN team * $Id$ * - * Authors: Olivier Teulière - * Clément Stenac + * Authors: Olivier Teulière + * Clément Stenac * * This program is free software; you can redistribute it and/OR MODIFy * it under the terms of the GNU General Public License as published by @@ -27,7 +27,6 @@ *****************************************************************************/ #include "dialogs/playlist.hpp" #include "dialogs/iteminfo.hpp" -#include "interface.hpp" // Needed for D&D - TODO: Split #include "bitmaps/shuffle.xpm" #include "bitmaps/repeat.xpm" @@ -48,6 +47,7 @@ #include #include +#include "charset.h" #define HELP_SHUFFLE N_( "Shuffle" ) #define HELP_LOOP N_( "Repeat All" ) @@ -62,9 +62,9 @@ static int PlaylistNext( vlc_object_t *, const char *, static int ItemChanged( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * ); static int ItemAppended( vlc_object_t *p_this, const char *psz_variable, - vlc_value_t oval, vlc_value_t nval, void *param ); + vlc_value_t oval, vlc_value_t nval, void *param ); static int ItemDeleted( vlc_object_t *p_this, const char *psz_variable, - vlc_value_t oval, vlc_value_t nval, void *param ); + vlc_value_t oval, vlc_value_t nval, void *param ); /***************************************************************************** * Event Table. @@ -96,11 +96,13 @@ enum PopupSort_Event, PopupDel_Event, PopupInfo_Event, + PopupAddNode_Event, SearchText_Event, Search_Event, /* controls */ + Source_Event, TreeCtrl_Event, Browse_Event, /* For export playlist */ @@ -113,6 +115,7 @@ enum MenuDummy_Event = wxID_HIGHEST + 999, FirstView_Event = wxID_HIGHEST + 1000, + CategoryView_Event, OneLevelView_Event, LastView_Event = wxID_HIGHEST + 1100, FirstSD_Event = wxID_HIGHEST + 2000, @@ -153,10 +156,15 @@ BEGIN_EVENT_TABLE(Playlist, wxFrame) EVT_MENU( PopupSort_Event, Playlist::OnPopupSort) EVT_MENU( PopupDel_Event, Playlist::OnPopupDel) EVT_MENU( PopupInfo_Event, Playlist::OnPopupInfo) + EVT_MENU( PopupAddNode_Event, Playlist::OnPopupAddNode) + /* Source selector */ + EVT_LIST_ITEM_SELECTED( Source_Event, Playlist::OnSourceSelected ) /* Tree control events */ EVT_TREE_ITEM_ACTIVATED( TreeCtrl_Event, Playlist::OnActivateItem ) EVT_TREE_KEY_DOWN( -1, Playlist::OnKeyDown ) + EVT_TREE_BEGIN_DRAG( TreeCtrl_Event, Playlist::OnDragItemBegin ) + EVT_TREE_END_DRAG( TreeCtrl_Event, Playlist::OnDragItemEnd ) EVT_CONTEXT_MENU( Playlist::OnPopup ) @@ -183,11 +191,14 @@ class PlaylistItem : public wxTreeItemData public: PlaylistItem( playlist_item_t *p_item ) : wxTreeItemData() { - i_id = p_item->input.i_id; + i_id = p_item->i_id; + i_input_id = p_item->p_input->i_id; } protected: + int i_input_id; int i_id; friend class Playlist; +friend class PlaylistFileDropTarget; }; /***************************************************************************** @@ -215,8 +226,9 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ): p_view_menu = NULL; p_sd_menu = SDMenu(); - i_current_view = VIEW_CATEGORY; - b_changed_view = VLC_FALSE; +// i_current_view = VIEW_ONELEVEL; + p_current_viewroot = p_playlist->p_root_onelevel; + p_current_treeroot = p_playlist->p_local_onelevel; i_title_sorted = 0; i_group_sorted = 0; @@ -230,9 +242,9 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ): wxMenu *manage_menu = new wxMenu; manage_menu->Append( AddFile_Event, wxU(_("&Simple Add File...")) ); manage_menu->Append( AddDir_Event, wxU(_("Add &Directory...")) ); - manage_menu->Append( AddMRL_Event, wxU(_("&Add MRL...")) ); + manage_menu->Append( AddMRL_Event, wxU(_("&Add URL...")) ); manage_menu->AppendSeparator(); - manage_menu->Append( MenuDummy_Event, wxU(_("Services discovery")), + manage_menu->Append( MenuDummy_Event, wxU(_("Services Discovery")), p_sd_menu ); manage_menu->AppendSeparator(); manage_menu->Append( Open_Event, wxU(_("&Open Playlist...")) ); @@ -242,10 +254,10 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ): /* Create our "Sort" menu */ wxMenu *sort_menu = new wxMenu; - sort_menu->Append( SortTitle_Event, wxU(_("Sort by &title")) ); - sort_menu->Append( RSortTitle_Event, wxU(_("&Reverse sort by title")) ); + sort_menu->Append( SortTitle_Event, wxU(_("Sort by &Title")) ); + sort_menu->Append( RSortTitle_Event, wxU(_("&Reverse Sort by Title")) ); sort_menu->AppendSeparator(); - sort_menu->Append( Randomize_Event, wxU(_("&Shuffle Playlist")) ); + sort_menu->Append( Randomize_Event, wxU(_("&Shuffle")) ); /* Create our "Selection" menu */ wxMenu *selection_menu = new wxMenu; @@ -267,11 +279,12 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ): /* Create the popup menu */ node_popup = new wxMenu; node_popup->Append( PopupPlay_Event, wxU(_("Play")) ); - node_popup->Append( PopupPlayThis_Event, wxU(_("Play this branch")) ); + node_popup->Append( PopupPlayThis_Event, wxU(_("Play this Branch")) ); node_popup->Append( PopupPreparse_Event, wxU(_("Preparse")) ); - node_popup->Append( PopupSort_Event, wxU(_("Sort this branch")) ); + node_popup->Append( PopupSort_Event, wxU(_("Sort this Branch")) ); node_popup->Append( PopupDel_Event, wxU(_("Delete")) ); node_popup->Append( PopupInfo_Event, wxU(_("Info")) ); + node_popup->Append( PopupAddNode_Event, wxU(_("Add Node")) ); item_popup = new wxMenu; item_popup->Append( PopupPlay_Event, wxU(_("Play")) ); @@ -325,6 +338,11 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ): search_button->SetDefault(); toolbar->Realize(); + /* Create teh source selector */ + source_sel = new wxListView( playlist_panel, Source_Event, + wxDefaultPosition, wxDefaultSize, + wxLC_AUTOARRANGE|wxLC_SINGLE_SEL ); + /* Create the tree */ treectrl = new wxTreeCtrl( playlist_panel, TreeCtrl_Event, wxDefaultPosition, wxDefaultSize, @@ -356,7 +374,8 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ): font.SetPointSize(9); treectrl->SetFont( font ); - wxBoxSizer *panel_sizer = new wxBoxSizer( wxVERTICAL ); + wxBoxSizer *panel_sizer = new wxBoxSizer( wxHORIZONTAL ); + panel_sizer->Add( source_sel, 0, wxALL | wxEXPAND, 5 ); panel_sizer->Add( treectrl, 1, wxEXPAND | wxALL, 5 ); panel_sizer->Layout(); @@ -368,13 +387,13 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ): #if wxUSE_DRAG_AND_DROP /* Associate drop targets with the playlist */ - SetDropTarget( new DragAndDrop( p_intf, VLC_TRUE ) ); + SetDropTarget( new PlaylistFileDropTarget( this ) ); + menubar->SetDropTarget( new PlaylistFileDropTarget( this ) ); + toolbar->SetDropTarget( new PlaylistFileDropTarget( this ) ); #endif i_saved_id = -1; - - - /* We want to be noticed of playlist changes */ + i_saved_input_id = -1; /* Some global changes happened -> Rebuild all */ var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this ); @@ -435,7 +454,7 @@ void Playlist::UpdateNode( playlist_item_t *p_node, wxTreeItemId node ) child = treectrl->GetNextChild( node, cookie ); } } - treectrl->SetItemImage( node, p_node->input.i_type ); + treectrl->SetItemImage( node, p_node->p_input->i_type ); } @@ -443,9 +462,9 @@ void Playlist::UpdateNode( playlist_item_t *p_node, wxTreeItemId node ) void Playlist::CreateNode( playlist_item_t *p_node, wxTreeItemId parent ) { wxTreeItemId node = - treectrl->AppendItem( parent, wxL2U( p_node->input.psz_name ), + treectrl->AppendItem( parent, wxL2U( p_node->p_input->psz_name ), -1,-1, new PlaylistItem( p_node ) ); - treectrl->SetItemImage( node, p_node->input.i_type ); + treectrl->SetItemImage( node, p_node->p_input->i_type ); UpdateNodeChildren( p_node, node ); } @@ -454,18 +473,20 @@ void Playlist::CreateNode( playlist_item_t *p_node, wxTreeItemId parent ) void Playlist::UpdateNodeChildren( playlist_item_t *p_node, wxTreeItemId node ) { - for( int i = 0; i< p_node->i_children ; i++ ) { /* Append the item */ if( p_node->pp_children[i]->i_children == -1 ) { - wxTreeItemId item = - treectrl->AppendItem( node, - wxL2U( p_node->pp_children[i]->input.psz_name ), -1,-1, + if( !(p_node->pp_children[i]->i_flags & PLAYLIST_DBL_FLAG) ) + { + wxTreeItemId item = + treectrl->AppendItem( node, + wxL2U( p_node->pp_children[i]->p_input->psz_name ), -1,-1, new PlaylistItem( p_node->pp_children[i]) ); - UpdateTreeItem( item ); + UpdateTreeItem( item ); + } } else { @@ -477,12 +498,12 @@ void Playlist::UpdateNodeChildren( playlist_item_t *p_node, /* Update an item in the tree */ void Playlist::UpdateTreeItem( wxTreeItemId item ) { + LockPlaylist( p_intf->p_sys, p_playlist ); if( ! item.IsOk() ) return; wxTreeItemData *p_data = treectrl->GetItemData( item ); if( !p_data ) return; - LockPlaylist( p_intf->p_sys, p_playlist ); playlist_item_t *p_item = playlist_ItemGetById( p_playlist, ((PlaylistItem *)p_data)->i_id ); if( !p_item ) @@ -493,17 +514,19 @@ void Playlist::UpdateTreeItem( wxTreeItemId item ) wxString msg; wxString duration = wxU( "" ); - char *psz_author = vlc_input_item_GetInfo( &p_item->input, - _("Meta-information"), - VLC_META_ARTIST ); - if( !psz_author ) + + char *psz_artist; + if( p_item->p_input->p_meta ) { - UnlockPlaylist( p_intf->p_sys, p_playlist ); - return; + psz_artist= p_item->p_input->p_meta->psz_artist ? + strdup( p_item->p_input->p_meta->psz_artist ) : + strdup(""); } + else + psz_artist = strdup( "" ); char psz_duration[MSTRTIME_MAX_SIZE]; - mtime_t dur = p_item->input.i_duration; + mtime_t dur = p_item->p_input->i_duration; if( dur != -1 ) { @@ -512,18 +535,18 @@ void Playlist::UpdateTreeItem( wxTreeItemId item ) wxU( " )" ) ); } - if( !strcmp( psz_author, "" ) || p_item->input.b_fixed_name == VLC_TRUE ) + if( !strcmp( psz_artist, "" ) || p_item->p_input->b_fixed_name == VLC_TRUE ) { - msg = wxString( wxU( p_item->input.psz_name ) ) + duration; + msg = wxString( wxU( p_item->p_input->psz_name ) ) + duration; } else { - msg = wxString(wxU( psz_author )) + wxT(" - ") + - wxString(wxU(p_item->input.psz_name)) + duration; + msg = wxString(wxU( psz_artist )) + wxT(" - ") + + wxString(wxU(p_item->p_input->psz_name)) + duration; } - free( psz_author ); + free( psz_artist ); treectrl->SetItemText( item , msg ); - treectrl->SetItemImage( item, p_item->input.i_type ); + treectrl->SetItemImage( item, p_item->p_input->i_type ); if( p_playlist->status.p_item == p_item ) { @@ -531,7 +554,9 @@ void Playlist::UpdateTreeItem( wxTreeItemId item ) while( treectrl->GetItemParent( item ).IsOk() ) { item = treectrl->GetItemParent( item ); - treectrl->Expand( item ); + if( ! (item == treectrl->GetRootItem() && + treectrl->HasFlag( wxTR_HIDE_ROOT ) ) ) + treectrl->Expand( item ); } } else @@ -553,21 +578,20 @@ void Playlist::AppendItem( wxCommandEvent& event ) /* No need to do anything if the playlist is going to be rebuilt */ if( b_need_update ) return; - if( p_add->i_view != i_current_view ) goto update; - node = FindItem( treectrl->GetRootItem(), p_add->i_node ); if( !node.IsOk() ) goto update; p_item = playlist_ItemGetById( p_playlist, p_add->i_item ); if( !p_item ) goto update; + if( (p_item->i_flags & PLAYLIST_DBL_FLAG ) ) goto update; item = FindItem( treectrl->GetRootItem(), p_add->i_item ); if( item.IsOk() ) goto update; item = treectrl->AppendItem( node, - wxL2U( p_item->input.psz_name ), -1,-1, + wxL2U( p_item->p_input->psz_name ), -1,-1, new PlaylistItem( p_item ) ); - treectrl->SetItemImage( item, p_item->input.i_type ); + treectrl->SetItemImage( item, p_item->p_input->i_type ); if( item.IsOk() && p_item->i_children == -1 ) { @@ -576,26 +600,8 @@ void Playlist::AppendItem( wxCommandEvent& event ) update: int i_count = CountItems( treectrl->GetRootItem()); - if( i_count != p_playlist->i_size ) - { - statusbar->SetStatusText( wxString::Format( wxU(_( - "%i items in playlist (%i not shown)")), - p_playlist->i_size, - p_playlist->i_size - i_count ) ); - if( !b_changed_view ) - { - i_current_view = VIEW_CATEGORY; - b_changed_view = VLC_TRUE; - b_need_update = VLC_TRUE; - } - } - else - { - statusbar->SetStatusText( wxString::Format( wxU(_( - "%i items in playlist")), - p_playlist->i_size ), 0 ); - } - + statusbar->SetStatusText( wxString::Format( wxU(_( + "%i items in playlist" ) ), i_count ) ); return; } @@ -603,9 +609,7 @@ update: void Playlist::UpdateItem( int i ) { if( i < 0 ) return; /* Sanity check */ - - wxTreeItemId item = FindItem( treectrl->GetRootItem(), i ); - + wxTreeItemId item = FindItemByInput( treectrl->GetRootItem(), i ); if( item.IsOk() ) { UpdateTreeItem( item ); @@ -617,6 +621,11 @@ void Playlist::RemoveItem( int i ) if( i <= 0 ) return; /* Sanity check */ if( i == i_saved_id ) i_saved_id = -1; + /* Hack: always invalidate input item cache */ + i_saved_input_id = -1; + + /// \todo Check if it is in the source selector */ + wxTreeItemId item = FindItem( treectrl->GetRootItem(), i ); if( item.IsOk() ) @@ -632,6 +641,16 @@ void Playlist::RemoveItem( int i ) /* Find a wxItem from a playlist id */ wxTreeItemId Playlist::FindItem( wxTreeItemId root, int i_id ) +{ + return FindItemInner( root, i_id, false ); +} + +wxTreeItemId Playlist::FindItemByInput( wxTreeItemId root, int i_input_id ) +{ + return FindItemInner( root, i_input_id, true ); +} + +wxTreeItemId Playlist::FindItemInner( wxTreeItemId root, int i_id, bool b_byinput ) { wxTreeItemIdValue cookie; PlaylistItem *p_wxcurrent; @@ -643,51 +662,70 @@ wxTreeItemId Playlist::FindItem( wxTreeItemId root, int i_id ) if( i_id < 0 ) { - wxTreeItemId dummy; - return dummy; + wxTreeItemId dummy; dummy.Unset(); return dummy; } - if( i_saved_id == i_id ) - { + if( b_byinput && i_saved_input_id == i_id ) + return saved_input_tree_item; + if( !b_byinput && i_saved_id == i_id) return saved_tree_item; - } if( !p_wxcurrent ) { - wxTreeItemId dummy; - return dummy; + wxTreeItemId dummy; dummy.Unset(); return dummy; } - if( p_wxcurrent->i_id == i_id ) + if( !b_byinput && p_wxcurrent->i_id == i_id ) { i_saved_id = i_id; saved_tree_item = root; return root; } + if( b_byinput && p_wxcurrent->i_input_id == i_id ) + { + i_saved_input_id = i_id; + saved_input_tree_item = root; + return root; + } while( item.IsOk() ) { p_wxcurrent = (PlaylistItem *)treectrl->GetItemData( item ); - if( p_wxcurrent->i_id == i_id ) + if( !b_byinput && p_wxcurrent->i_id == i_id ) { i_saved_id = i_id; saved_tree_item = item; return item; } + else if( b_byinput && p_wxcurrent->i_input_id == i_id ) + { + i_saved_input_id = i_id; + saved_input_tree_item = item; + return item; + } if( treectrl->ItemHasChildren( item ) ) { - wxTreeItemId search = FindItem( item, i_id ); + wxTreeItemId search = FindItemInner( item, i_id, b_byinput ); if( search.IsOk() ) { - i_saved_id = i_id; - saved_tree_item = search; - return search; + if( !b_byinput ) + { + i_saved_id = i_id; + saved_tree_item = search; + return search; + } + else + { + i_saved_input_id = i_id; + saved_input_tree_item = search; + return search; + + } } } item = treectrl->GetNextChild( root, cookie ); } /* Not found */ - wxTreeItemId dummy; - return dummy; + wxTreeItemId dummy; dummy.Unset(); return dummy; } int Playlist::CountItems( wxTreeItemId root ) @@ -750,7 +788,7 @@ wxTreeItemId Playlist::FindItemByName( wxTreeItemId root, wxString search_string item = treectrl->GetNextChild( root, cookie); } /* Not found */ - wxTreeItemId dummy; + wxTreeItemId dummy; dummy.Unset(); return dummy; } @@ -759,8 +797,6 @@ wxTreeItemId Playlist::FindItemByName( wxTreeItemId root, wxString search_string **********************************************************************/ void Playlist::Rebuild( vlc_bool_t b_root ) { - playlist_view_t *p_view; - i_items_to_append = 0; /* We can remove the callbacks before locking, anyway, we won't @@ -776,39 +812,36 @@ void Playlist::Rebuild( vlc_bool_t b_root ) /* ...and rebuild it */ LockPlaylist( p_intf->p_sys, p_playlist ); } + /* Invalidate cache */ i_saved_id = -1; + i_saved_input_id = -1; - p_view = playlist_ViewFind( p_playlist, i_current_view ); /* FIXME */ + /* Rebuild the list */ + source_sel->ClearAll(); + for( int i = 0 ; i< p_current_viewroot->i_children ; i++ ) + { + source_sel->InsertItem( i, + wxL2U( p_current_viewroot->pp_children[i]->p_input->psz_name) ); + source_sel->SetItemData( i, + p_current_viewroot->pp_children[i]->i_id ); + if( p_current_viewroot->pp_children[i] == p_current_treeroot ) + source_sel->Select( i ); + } /* HACK we should really get new*/ treectrl->DeleteAllItems(); treectrl->AddRoot( wxU(_("root" )), -1, -1, - new PlaylistItem( p_view->p_root) ); + new PlaylistItem( p_current_treeroot ) ); wxTreeItemId root = treectrl->GetRootItem(); - UpdateNode( p_view->p_root, root ); + //UpdateNode( p_current_treeroot, root ); + //CreateNode( p_current_treeroot, root ); + UpdateNodeChildren( p_current_treeroot, root ); int i_count = CountItems( treectrl->GetRootItem() ); - if( i_count < p_playlist->i_size && !b_changed_view ) - { - i_current_view = VIEW_CATEGORY; - b_changed_view = VLC_TRUE; - Rebuild( VLC_FALSE ); - } - else if( i_count != p_playlist->i_size ) - { - statusbar->SetStatusText( wxString::Format( wxU(_( - "%i items in playlist (%i not shown)")), - p_playlist->i_size, - p_playlist->i_size - i_count ) ); - } - else - { - statusbar->SetStatusText( wxString::Format( wxU(_( - "%i items in playlist")), - p_playlist->i_size ), 0 ); - } + statusbar->SetStatusText( wxString::Format( wxU(_( + "%i items in playlist")), i_count ), 0 ); if( b_root ) { @@ -823,8 +856,6 @@ void Playlist::Rebuild( vlc_bool_t b_root ) } } - - void Playlist::ShowPlaylist( bool show ) { if( show ) Rebuild( VLC_TRUE ); @@ -867,16 +898,16 @@ void Playlist::DeleteTreeItem( wxTreeItemId item ) return; } - if( p_item->i_children == -1 ) DeleteItem( p_item->input.i_id ); + if( p_item->i_children == -1 ) DeleteItem( p_item->p_input->i_id ); else DeleteNode( p_item ); - RemoveItem( item ); + RemoveItem( p_item->i_id ); UnlockPlaylist( p_intf->p_sys, p_playlist ); } void Playlist::DeleteItem( int item_id ) { - playlist_Delete( p_playlist, item_id ); + playlist_DeleteAllFromInput( p_playlist, item_id ); } void Playlist::DeleteNode( playlist_item_t *p_item ) @@ -901,7 +932,9 @@ void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) ) char *psz_desc; char *psz_filter; char *psz_module; - } formats[] = {{ _("M3U file"), "*.m3u", "export-m3u" }}; + } formats[] = {//{ _("M3U file"), "*.m3u", "export-m3u" }, + { _("XSPF playlist"), "*.xspf", "export-xspf"} + }; wxString filter = wxT(""); @@ -926,8 +959,13 @@ void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) ) { if( dialog.GetPath().mb_str() ) { - playlist_Export( p_playlist, dialog.GetPath().mb_str(), - formats[dialog.GetFilterIndex()].psz_module ); + /* what root should we export? */ + if( p_playlist->p_root_category->i_children > 0 ) + { + playlist_Export( p_playlist, dialog.GetPath().mb_str(), + p_playlist->p_root_category->pp_children[0], + formats[dialog.GetFilterIndex()].psz_module ); + } } } @@ -936,11 +974,13 @@ void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) ) void Playlist::OnOpen( wxCommandEvent& WXUNUSED(event) ) { wxFileDialog dialog( this, wxU(_("Open playlist")), wxT(""), wxT(""), - wxT("All playlists|*.pls;*.m3u;*.asx;*.b4s|M3U files|*.m3u"), wxOPEN ); + wxT("All playlists|" EXTENSIONS_PLAYLIST "|XSPF playlist|*.xspf|M3U files|*.m3u"), wxOPEN ); if( dialog.ShowModal() == wxID_OK ) { - playlist_Import( p_playlist, dialog.GetPath().mb_str() ); + playlist_Import( p_playlist, dialog.GetPath().mb_str(), + /*FIXME: where do we want to insert ? */ + p_playlist->p_local_category, VLC_TRUE ); } } @@ -999,28 +1039,16 @@ void Playlist::OnSort( wxCommandEvent& event ) void Playlist::OnSearch( wxCommandEvent& WXUNUSED(event) ) { wxString search_string = search_text->GetValue(); + PlaylistItem *p_wxroot; + p_wxroot = (PlaylistItem *)treectrl->GetItemData( treectrl->GetRootItem() ); + playlist_item_t *p_root = playlist_ItemGetById( p_playlist, p_wxroot->i_id ); - vlc_bool_t pb_found = VLC_FALSE; - - wxTreeItemId found = - FindItemByName( treectrl->GetRootItem(), search_string, - search_current, &pb_found ); - - if( !found.IsOk() ) - { - wxTreeItemId dummy; - search_current = dummy; - found = FindItemByName( treectrl->GetRootItem(), search_string, - search_current, &pb_found ); - } + assert( p_root ); + char *psz_name = wxFromLocale( search_string ); + playlist_LiveSearchUpdate( p_playlist, p_root, psz_name ); + Rebuild( VLC_TRUE ); - if( found.IsOk() ) - { - search_current = found; - treectrl->EnsureVisible( found ); - treectrl->UnselectAll(); - treectrl->SelectItem( found, true ); - } + wxLocaleFree( psz_name ); } /********************************************************************** @@ -1077,46 +1105,32 @@ void Playlist::OnRepeat( wxCommandEvent& event ) ********************************************************************/ void Playlist::OnActivateItem( wxTreeEvent& event ) { - playlist_item_t *p_item,*p_node,*p_item2,*p_node2; + playlist_item_t *p_item, *p_parent; PlaylistItem *p_wxitem = (PlaylistItem *)treectrl->GetItemData( event.GetItem() ); - wxTreeItemId parent = treectrl->GetItemParent( event.GetItem() ); - - PlaylistItem *p_wxparent = (PlaylistItem *)treectrl->GetItemData( parent ); LockPlaylist( p_intf->p_sys, p_playlist ); - if( !( p_wxitem && p_wxparent ) ) + if( !( p_wxitem ) ) { UnlockPlaylist( p_intf->p_sys, p_playlist ); return; } + p_item = playlist_ItemGetById( p_playlist, p_wxitem->i_id ); - p_item2 = playlist_ItemGetById(p_playlist, p_wxitem->i_id); - p_node2 = playlist_ItemGetById(p_playlist, p_wxparent->i_id); - if( p_item2 && p_item2->i_children == -1 ) + p_parent = p_item; + while( p_parent ) { - p_node = p_node2; - p_item = p_item2; + if( p_parent == p_current_treeroot ) + break; + p_parent = p_parent->p_parent; } - else + + if( p_parent ) { - p_node = p_item2; - p_item = NULL; -/* if( p_node && p_node->i_children > 0 && - p_node->pp_children[0]->i_children == -1) - { - p_item = p_node->pp_children[0]; - } - else - { - p_item = NULL; - }*/ + playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, p_parent, p_item ); } - - playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, i_current_view, - p_node, p_item ); UnlockPlaylist( p_intf->p_sys, p_playlist ); } @@ -1129,17 +1143,182 @@ void Playlist::OnKeyDown( wxTreeEvent& event ) /* We send a dummy event */ OnDeleteSelection( event ); } + /* Work around wxWin32 bug */ + else if( keycode == WXK_RETURN ) + { + wxArrayTreeItemIds items; + if( treectrl->GetSelections( items ) > 0 ) + { + wxTreeEvent event; + event.SetItem( items.Item( 0 ) ); + OnActivateItem( event ); + } + } else { event.Skip(); } } -void Playlist::OnEnDis( wxCommandEvent& event ) +void Playlist::OnDragItemBegin( wxTreeEvent& event ) { - msg_Warn( p_intf, "not implemented" ); + event.Allow(); + draged_tree_item = event.GetItem(); } +void Playlist::OnDragItemEnd( wxTreeEvent& event ) +{ + wxTreeItemId dest_tree_item = event.GetItem(); + + if( !dest_tree_item.IsOk() ) return; + + /* check that we're not trying to move a node into one of it's children */ + wxTreeItemId parent = dest_tree_item; + while( parent != treectrl->GetRootItem() ) + { + if( draged_tree_item == parent ) return; + parent = treectrl->GetItemParent( parent ); + } + + LockPlaylist( p_intf->p_sys, p_playlist ); + + PlaylistItem *p_wxdrageditem = + (PlaylistItem *)treectrl->GetItemData( draged_tree_item ); + PlaylistItem *p_wxdestitem = + (PlaylistItem *)treectrl->GetItemData( dest_tree_item ); + if( !p_wxdrageditem || !p_wxdestitem ) + { + UnlockPlaylist( p_intf->p_sys, p_playlist ); + return; + } + + playlist_item_t *p_drageditem = + playlist_ItemGetById(p_playlist, p_wxdrageditem->i_id ); + playlist_item_t *p_destitem = + playlist_ItemGetById(p_playlist, p_wxdestitem->i_id ); + if( !p_drageditem || !p_destitem ) + { + UnlockPlaylist( p_intf->p_sys, p_playlist ); + return; + } + + if( p_destitem->i_children == -1 ) + /* this is a leaf */ + { + parent = treectrl->GetItemParent( dest_tree_item ); + PlaylistItem *p_parent = + (PlaylistItem *)treectrl->GetItemData( parent ); + if( !p_parent ) + { + UnlockPlaylist( p_intf->p_sys, p_playlist ); + return; + } + playlist_item_t *p_destitem2 = + playlist_ItemGetById( p_playlist, p_parent->i_id ); + if( !p_destitem2 ) + { + UnlockPlaylist( p_intf->p_sys, p_playlist ); + return; + } + int i; + for( i = 0; i < p_destitem2->i_children; i++ ) + { + if( p_destitem2->pp_children[i] == p_destitem ) break; + } + playlist_TreeMove( p_playlist, p_drageditem, p_destitem2, i ); + } + else + /* this is a node */ + { + playlist_TreeMove( p_playlist, p_drageditem, p_destitem, 0 ); + } + + UnlockPlaylist( p_intf->p_sys, p_playlist ); + + /* FIXME: having this Rebuild() is dirty */ + Rebuild( VLC_TRUE ); +} + +#if wxUSE_DRAG_AND_DROP +PlaylistFileDropTarget::PlaylistFileDropTarget( Playlist *p ):p( p ){} + +/******************************************************************** + * File Drag And Drop handling + ********************************************************************/ +bool PlaylistFileDropTarget::OnDropFiles( wxCoord x, wxCoord y, + const wxArrayString& filenames ) +{ + int i_pos = 0; + playlist_item_t *p_dest; + + LockPlaylist( p->p_intf->p_sys, p->p_playlist ); + + /* find the destination node and position in that node */ + const wxPoint pt( x, y ); + wxTreeItemId item = p->treectrl->HitTest( pt ); + + if( !item.IsOk() ) + { + /* We were droped below the last item so we append to the + * general node */ + msg_Err( p->p_playlist, "USE OF P_GENERAL" ); + p_dest = p->p_playlist->p_local_category; + i_pos = PLAYLIST_END; + } + else + { + PlaylistItem *p_plitem = + (PlaylistItem *)p->treectrl->GetItemData( item ); + p_dest = playlist_ItemGetById( p->p_playlist, p_plitem->i_id ); + + if( p_dest->i_children == -1 ) + { + /* This is a leaf. Append right after it + * We thus need to find the parrent node and the position of the + * leaf in it's children list */ + wxTreeItemId parent = p->treectrl->GetItemParent( item ); + PlaylistItem *p_parent = + (PlaylistItem *)p->treectrl->GetItemData( parent ); + if( !p_parent ) + { + UnlockPlaylist( p->p_intf->p_sys, p->p_playlist ); + return FALSE; + } + playlist_item_t *p_node = + playlist_ItemGetById( p->p_playlist, p_parent->i_id ); + if( !p_node ) + { + UnlockPlaylist( p->p_intf->p_sys, p->p_playlist ); + return FALSE; + } + for( i_pos = 0; i_pos < p_node->i_children; i_pos++ ) + { + if( p_node->pp_children[i_pos] == p_dest ) break; + } + p_dest = p_node; + } + } + + UnlockPlaylist( p->p_intf->p_sys, p->p_playlist ); + + /* Put the items in the playlist node */ + for( size_t i = 0; i < filenames.GetCount(); i++ ) + { + char *psz_utf8 = wxDnDFromLocale( filenames[i] ); + input_item_t *p_input = input_ItemNew( p->p_playlist, + psz_utf8, psz_utf8 ); + playlist_NodeAddInput( p->p_playlist, p_input, + p_dest, PLAYLIST_PREPARSE, i_pos ); + wxDnDLocaleFree( psz_utf8 ); + } + + /* FIXME: having this Rebuild() is dirty */ + p->Rebuild( VLC_TRUE ); + + return TRUE; +} +#endif + /********************************************************************** * Menu **********************************************************************/ @@ -1168,30 +1347,37 @@ void Playlist::OnMenuEvent( wxCommandEvent& event ) } else if( event.GetId() < LastView_Event ) { - - int i_new_view = event.GetId() - FirstView_Event; - - playlist_view_t *p_view = playlist_ViewFind( p_playlist, i_new_view ); - - if( p_view != NULL ) + if( event.GetId() == CategoryView_Event ) { - b_changed_view = VLC_TRUE; - i_current_view = i_new_view; - playlist_ViewUpdate( p_playlist, i_new_view ); - Rebuild( VLC_TRUE ); - return; + p_current_viewroot = p_playlist->p_root_category; + if( p_current_treeroot == p_playlist->p_local_category || + p_current_treeroot == p_playlist->p_local_onelevel ) + { + p_current_treeroot = p_playlist->p_local_category; + } + else if( p_current_treeroot == p_playlist->p_ml_category || + p_current_treeroot == p_playlist->p_ml_onelevel ) + { + p_current_treeroot = p_playlist->p_ml_category; + } } - else if( i_new_view >= VIEW_FIRST_SORTED && - i_new_view <= VIEW_LAST_SORTED ) + else if( event.GetId() == OneLevelView_Event ) { - b_changed_view = VLC_TRUE; - playlist_ViewInsert( p_playlist, i_new_view, "View" ); - playlist_ViewUpdate( p_playlist, i_new_view ); - - i_current_view = i_new_view; - - Rebuild( VLC_TRUE ); + p_current_viewroot = p_playlist->p_root_onelevel; + if( p_current_treeroot == p_playlist->p_local_category || + p_current_treeroot == p_playlist->p_local_onelevel ) + { + p_current_treeroot = p_playlist->p_local_onelevel; + } + else if( p_current_treeroot == p_playlist->p_ml_category || + p_current_treeroot == p_playlist->p_ml_onelevel ) + { + p_current_treeroot = p_playlist->p_ml_onelevel; + } } + wxCommandEvent event; + OnSearch( event ); + return; } else if( event.GetId() >= FirstSD_Event && event.GetId() < LastSD_Event ) { @@ -1228,14 +1414,8 @@ wxMenu * Playlist::ViewMenu() } } - /* FIXME : have a list of "should have" views */ - p_view_menu->Append( FirstView_Event + VIEW_CATEGORY, - wxU(_("Normal") ) ); - p_view_menu->Append( FirstView_Event + VIEW_S_AUTHOR, - wxU(_("Sorted by artist") ) ); - p_view_menu->Append( FirstView_Event + VIEW_S_ALBUM, - wxU(_("Sorted by Album") ) ); - + p_view_menu->Append( CategoryView_Event, wxU(_("Normal") ) ); + p_view_menu->Append( OneLevelView_Event, wxU(_("One level") ) ); return p_view_menu; } @@ -1268,13 +1448,19 @@ wxMenu *Playlist::SDMenu() (p_parser->psz_shortname ? p_parser->psz_shortname : p_parser->psz_object_name) ) ); + /* hack to handle submodules properly */ + int i = -1; + while( p_parser->pp_shortcuts[++i] != NULL ); + i--; if( playlist_IsServicesDiscoveryLoaded( p_playlist, - p_parser->psz_object_name ) ) + i>=0?p_parser->pp_shortcuts[i] + :p_parser->psz_object_name ) ) { p_sd_menu->Check( FirstSD_Event + i_number, TRUE ); } - pp_sds[i_number++] = p_parser->psz_object_name; + pp_sds[i_number++] = i>=0?p_parser->pp_shortcuts[i] + :p_parser->psz_object_name; } } vlc_list_release( p_list ); @@ -1329,33 +1515,19 @@ void Playlist::OnPopupPlay( wxCommandEvent& event ) playlist_item_t *p_popup_item, *p_popup_parent; LockPlaylist( p_intf->p_sys, p_playlist ); p_popup_item = playlist_ItemGetById( p_playlist, i_popup_item ); - p_popup_parent = playlist_ItemGetById( p_playlist, i_popup_parent ); - if( p_popup_item != NULL ) + + p_popup_parent = p_popup_item; + while( p_popup_parent ) { - if( p_popup_item->i_children > -1 ) - { - if( event.GetId() == PopupPlay_Event && - p_popup_item->i_children > 0 ) - { - playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, - i_current_view, p_popup_item, - p_popup_item->pp_children[0] ); - } - else - { - playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, - i_current_view, p_popup_item, NULL ); - } - } - else - { - if( event.GetId() == PopupPlay_Event ) - { - playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, - i_current_view, p_popup_parent, - p_popup_item ); - } - } + if( p_popup_parent == p_current_treeroot ) + break; + p_popup_parent = p_popup_parent->p_parent; + } + + if( p_popup_parent ) + { + playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, p_popup_parent, + p_popup_item ); } UnlockPlaylist( p_intf->p_sys, p_playlist ); } @@ -1375,7 +1547,7 @@ void Playlist::Preparse() { if( p_popup_item->i_children == -1 ) { - playlist_PreparseEnqueue( p_playlist, &p_popup_item->input ); + playlist_PreparseEnqueue( p_playlist, p_popup_item->p_input ); } else { @@ -1385,8 +1557,8 @@ void Playlist::Preparse() { wxMenuEvent dummy; i_wx_popup_item = FindItem( treectrl->GetRootItem(), - p_parent->pp_children[i]->input.i_id ); - i_popup_item = p_parent->pp_children[i]->input.i_id; + p_parent->pp_children[i]->i_id ); + i_popup_item = p_parent->pp_children[i]->i_id; Preparse(); } } @@ -1414,7 +1586,7 @@ void Playlist::OnPopupSort( wxCommandEvent& event ) SORT_TITLE_NODES_FIRST, ORDER_NORMAL ); treectrl->DeleteChildren( i_wx_popup_item ); - i_saved_id = -1; + i_saved_id = -1; i_saved_input_id = -1; UpdateNodeChildren( p_item, i_wx_popup_item ); } @@ -1437,6 +1609,42 @@ void Playlist::OnPopupInfo( wxCommandEvent& event ) UnlockPlaylist( p_intf->p_sys, p_playlist ); } +void Playlist::OnPopupAddNode( wxCommandEvent& event ) +{ + wxTextEntryDialog text( NULL, wxU(_( "Please enter node name" )), + wxU(_( "Add node" )), wxU(_( "New node" )) ); + if( text.ShowModal() != wxID_OK ) return; + + char *psz_name = wxFromLocale( text.GetValue() ); + + LockPlaylist( p_intf->p_sys, p_playlist ); + + PlaylistItem *p_wxitem; + playlist_item_t *p_item; + + p_wxitem = (PlaylistItem *)treectrl->GetItemData( i_wx_popup_item ); + + p_item = playlist_ItemGetById( p_playlist, p_wxitem->i_id ); + + playlist_NodeCreate( p_playlist, psz_name, p_item ); + + UnlockPlaylist( p_intf->p_sys, p_playlist ); + Rebuild( VLC_TRUE ); + + wxLocaleFree( psz_name ); +} + +void Playlist::OnSourceSelected( wxListEvent &event ) +{ + int i_id = event.GetData(); + + if( p_current_treeroot && i_id != p_current_treeroot->i_id ) + { + playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_id ); + if( p_item ) p_current_treeroot = p_item; + Rebuild( VLC_TRUE ); + } +} /***************************************************************************** * Custom events management @@ -1521,7 +1729,7 @@ static int ItemAppended( vlc_object_t *p_this, const char *psz_variable, playlist_add_t *p_add = (playlist_add_t *)malloc(sizeof( playlist_add_t)); memcpy( p_add, nval.p_address, sizeof( playlist_add_t ) ); - if( p_playlist_dialog->i_items_to_append++ > 50 ) + if( ++p_playlist_dialog->i_items_to_append >= 50 ) { /* Too many items waiting to be added, it will be quicker to rebuild * the whole playlist */