]> git.sesse.net Git - vlc/blobdiff - modules/gui/wxwidgets/dialogs/playlist.cpp
playlist: Make sure we don't pl_Release(p_playlist).
[vlc] / modules / gui / wxwidgets / dialogs / playlist.cpp
index ba132cfac0f686d8f192f3005c414e40136e0437..9ca6fc98ff4a4cf1cc62e92e66a56a2cd23cddf5 100644 (file)
@@ -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,7 +47,7 @@
 #include <wx/imaglist.h>
 
 #include <vlc_meta.h>
-#include "charset.h"
+#include "vlc_charset.h"
 
 #define HELP_SHUFFLE N_( "Shuffle" )
 #define HELP_LOOP N_( "Repeat All" )
@@ -103,6 +102,7 @@ enum
     Search_Event,
 
     /* controls */
+    Source_Event,
     TreeCtrl_Event,
 
     Browse_Event,  /* For export playlist */
@@ -115,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,
@@ -157,6 +158,8 @@ BEGIN_EVENT_TABLE(Playlist, wxFrame)
     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 )
@@ -188,9 +191,11 @@ 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;
@@ -210,10 +215,9 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
     pp_sds = NULL;
     i_update_counter = 0;
     i_sort_mode = MODE_NONE;
-    b_need_update = VLC_FALSE;
+    b_need_update = false;
     i_items_to_append = 0;
-    p_playlist = (playlist_t *)vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
-                                                FIND_ANYWHERE );
+    p_playlist = pl_Yield( p_intf );
     if( p_playlist == NULL ) return;
 
     SetIcon( *p_intf->p_sys->p_icon );
@@ -221,8 +225,8 @@ 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;
+    p_current_viewroot = p_playlist->p_root_category;
+    p_current_treeroot = NULL;
 
     i_title_sorted = 0;
     i_group_sorted = 0;
@@ -236,9 +240,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...")) );
@@ -248,10 +252,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;
@@ -273,12 +277,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")) );
+    node_popup->Append( PopupAddNode_Event, wxU(_("Add Node")) );
 
     item_popup = new wxMenu;
     item_popup->Append( PopupPlay_Event, wxU(_("Play")) );
@@ -332,6 +336,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,14 +365,13 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
     p_images->Add( wxIcon( type_node_xpm ) );
     treectrl->AssignImageList( p_images );
 
-    treectrl->AddRoot( wxU(_("root" )), -1, -1, NULL );
-
     /* Reduce font size */
     wxFont font= treectrl->GetFont();
     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();
 
@@ -376,12 +384,12 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
 #if wxUSE_DRAG_AND_DROP
     /* Associate drop targets with the playlist */
     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 );
@@ -396,13 +404,18 @@ Playlist::Playlist( intf_thread_t *_p_intf, wxWindow *p_parent ):
     var_AddCallback( p_playlist, "item-deleted", ItemDeleted, this );
 
     /* Update the playlist */
-    Rebuild( VLC_TRUE );
-
+    p_current_treeroot = p_playlist->p_local_category;
+    Rebuild( true );
 }
 
 Playlist::~Playlist()
 {
-    if( pp_sds != NULL ) free( pp_sds );
+    if( pp_sds != NULL )
+    {
+        char **pp_sd = pp_sds;
+        for( ; *pp_sd; pp_sd++ ) free( *pp_sd );
+        free( pp_sds );
+    }
 
     if( p_playlist == NULL ) return;
 
@@ -442,7 +455,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 );
 
 }
 
@@ -450,9 +463,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 );
 }
@@ -461,18 +474,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
         {
@@ -484,14 +499,14 @@ 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 );
+                                    ((PlaylistItem *)p_data)->i_id, true );
     if( !p_item )
     {
         UnlockPlaylist( p_intf->p_sys, p_playlist );
@@ -500,16 +515,12 @@ void Playlist::UpdateTreeItem( wxTreeItemId item )
 
     wxString msg;
     wxString duration = wxU( "" );
-    char *psz_author = vlc_input_item_GetInfo( &p_item->input,
-                                               _(VLC_META_INFO_CAT), _(VLC_META_ARTIST) );
-    if( !psz_author )
-    {
-        UnlockPlaylist( p_intf->p_sys, p_playlist );
-        return;
-    }
+
+    char *psz_artist = input_item_GetArtist( p_item->p_input );
+    char *psz_name = input_item_GetName( p_item->p_input );
 
     char psz_duration[MSTRTIME_MAX_SIZE];
-    mtime_t dur = p_item->input.i_duration;
+    mtime_t dur = input_item_GetDuration( p_item->p_input );
 
     if( dur != -1 )
     {
@@ -518,18 +529,19 @@ void Playlist::UpdateTreeItem( wxTreeItemId item )
                          wxU( " )" ) );
     }
 
-    if( !strcmp( psz_author, "" ) || p_item->input.b_fixed_name == VLC_TRUE )
+    if( !psz_artist || !strcmp( psz_artist, "" ) || p_item->p_input->b_fixed_name == true )
     {
-        msg = wxString( wxU( p_item->input.psz_name ) ) + duration;
+        msg = wxString( wxU( 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(psz_name)) + duration;
     }
-    free( psz_author );
+    free( psz_artist );
+    free( psz_name );
     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 )
     {
@@ -537,7 +549,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
@@ -559,21 +573,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 );
+    p_item = playlist_ItemGetById( p_playlist, p_add->i_item, true );
     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 )
     {
@@ -582,26 +595,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;
 }
 
@@ -609,9 +604,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 );
@@ -623,6 +616,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() )
@@ -638,6 +636,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;
@@ -649,51 +657,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 )
@@ -712,7 +739,7 @@ int Playlist::CountItems( wxTreeItemId root )
         {
             playlist_item_t *p_item;
             LockPlaylist( p_intf->p_sys, p_playlist );
-            p_item = playlist_ItemGetById( p_playlist, ((PlaylistItem *)treectrl->GetItemData( item ))->i_id );
+            p_item = playlist_ItemGetById( p_playlist, ((PlaylistItem *)treectrl->GetItemData( item ))->i_id, true );
             if( p_item && p_item->i_children == -1 )
                 count++;
             UnlockPlaylist( p_intf->p_sys, p_playlist );
@@ -723,7 +750,7 @@ int Playlist::CountItems( wxTreeItemId root )
 }
 
 /* Find a wxItem from a name (from current) */
-wxTreeItemId Playlist::FindItemByName( wxTreeItemId root, wxString search_string, wxTreeItemId current, vlc_bool_t *pb_current_found )
+wxTreeItemId Playlist::FindItemByName( wxTreeItemId root, wxString search_string, wxTreeItemId current, bool *pb_current_found )
 {
     wxTreeItemIdValue cookie;
     wxTreeItemId search;
@@ -735,13 +762,13 @@ wxTreeItemId Playlist::FindItemByName( wxTreeItemId root, wxString search_string
         if( treectrl->GetItemText( item).Lower().Contains(
                                                  search_string.Lower() ) )
         {
-            if( !current.IsOk() || *pb_current_found == VLC_TRUE )
+            if( !current.IsOk() || *pb_current_found == true )
             {
                 return item;
             }
             else if( current.IsOk() && item == current )
             {
-                *pb_current_found = VLC_TRUE;
+                *pb_current_found = true;
             }
         }
         if( treectrl->ItemHasChildren( item ) )
@@ -756,84 +783,54 @@ wxTreeItemId Playlist::FindItemByName( wxTreeItemId root, wxString search_string
         item = treectrl->GetNextChild( root, cookie);
     }
     /* Not found */
-    wxTreeItemId dummy;
+    wxTreeItemId dummy; dummy.Unset();
     return dummy;
 }
 
 /**********************************************************************
  * Rebuild the playlist
  **********************************************************************/
-void Playlist::Rebuild( vlc_bool_t b_root )
+void Playlist::Rebuild( bool b_root )
 {
-    playlist_view_t *p_view;
-
     i_items_to_append = 0;
 
-    /* We can remove the callbacks before locking, anyway, we won't
-     * miss anything */
-    if( b_root )
-    {
-        var_DelCallback( p_playlist, "item-change", ItemChanged, this );
-        var_DelCallback( p_playlist, "playlist-current", PlaylistNext, this );
-        var_DelCallback( p_playlist, "intf-change", PlaylistChanged, this );
-        var_DelCallback( p_playlist, "item-append", ItemAppended, this );
-        var_DelCallback( p_playlist, "item-deleted", ItemDeleted, this );
+    LockPlaylist( p_intf->p_sys, p_playlist );
 
-        /* ...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 );
+    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 );
-    }
-
-    if( b_root )
-    {
-        /* Put callbacks back online */
-        var_AddCallback( p_playlist, "intf-change", PlaylistChanged, this );
-        var_AddCallback( p_playlist, "playlist-current", PlaylistNext, this );
-        var_AddCallback( p_playlist, "item-change", ItemChanged, this );
-        var_AddCallback( p_playlist, "item-append", ItemAppended, this );
-        var_AddCallback( p_playlist, "item-deleted", ItemDeleted, this );
+    statusbar->SetStatusText( wxString::Format( wxU(_(
+                              "%i items in playlist")), i_count ), 0 );
 
-        UnlockPlaylist( p_intf->p_sys, p_playlist );
-    }
+    UnlockPlaylist( p_intf->p_sys, p_playlist );
 }
 
-
-
 void Playlist::ShowPlaylist( bool show )
 {
-    if( show ) Rebuild( VLC_TRUE );
+    if( show ) Rebuild( true );
     Show( show );
 }
 
@@ -847,8 +844,8 @@ void Playlist::UpdatePlaylist()
 
     if( this->b_need_update )
     {
-        this->b_need_update = VLC_FALSE;
-        Rebuild( VLC_TRUE );
+        this->b_need_update = false;
+        Rebuild( true );
     }
 
     /* Updating the playing status every 0.5s is enough */
@@ -865,7 +862,7 @@ void Playlist::DeleteTreeItem( wxTreeItemId item )
    p_wxitem = (PlaylistItem *)treectrl->GetItemData( item );
 
    LockPlaylist( p_intf->p_sys, p_playlist );
-   p_item = playlist_ItemGetById( p_playlist, p_wxitem->i_id );
+   p_item = playlist_ItemGetById( p_playlist, p_wxitem->i_id, true );
 
    if( !p_item )
    {
@@ -873,21 +870,21 @@ 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_DeleteFromInput( p_playlist, item_id, true );
 }
 
 void Playlist::DeleteNode( playlist_item_t *p_item )
 {
-    playlist_NodeDelete( p_playlist, p_item, VLC_TRUE , VLC_FALSE );
+    playlist_NodeDelete( p_playlist, p_item, true , false );
 }
 
 void Playlist::OnMenuClose( wxCommandEvent& event )
@@ -907,11 +904,13 @@ 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("");
 
-    if( p_playlist->i_size == 0 )
+    if( playlist_IsEmpty( p_playlist ) )
     {
         wxMessageBox( wxU(_("Playlist is empty") ), wxU(_("Can't save")),
                       wxICON_WARNING | wxOK, this );
@@ -930,10 +929,15 @@ void Playlist::OnSave( wxCommandEvent& WXUNUSED(event) )
 
     if( dialog.ShowModal() == wxID_OK )
     {
-        if( dialog.GetPath().mb_str() )
+        if( dialog.GetPath().mb_str(wxConvUTF8) )
         {
-            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(wxConvUTF8),
+                                 p_playlist->p_root_category->pp_children[0],
+                                 formats[dialog.GetFilterIndex()].psz_module );
+            }
         }
     }
 
@@ -942,11 +946,11 @@ 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(wxConvUTF8) );
     }
 }
 
@@ -981,17 +985,19 @@ void Playlist::OnSort( wxCommandEvent& event )
     {
         case SortTitle_Event:
             playlist_RecursiveNodeSort( p_playlist,
-                            playlist_ItemGetById( p_playlist, p_wxitem->i_id ),
+                            playlist_ItemGetById( p_playlist, p_wxitem->i_id,
+                                                  true ),
                             SORT_TITLE_NODES_FIRST, ORDER_NORMAL );
             break;
         case RSortTitle_Event:
             playlist_RecursiveNodeSort( p_playlist,
-                            playlist_ItemGetById( p_playlist, p_wxitem->i_id ),
+                            playlist_ItemGetById( p_playlist, p_wxitem->i_id,
+                                                  true ),
                             SORT_TITLE_NODES_FIRST, ORDER_REVERSE );
     }
     UnlockPlaylist( p_intf->p_sys, p_playlist );
 
-    Rebuild( VLC_TRUE );
+    Rebuild( true );
 }
 
 /**********************************************************************
@@ -1005,28 +1011,17 @@ 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,
+                                                    true );
 
-    vlc_bool_t pb_found = VLC_FALSE;
+    assert( p_root );
+    char *psz_name = wxFromLocale( search_string );
+    playlist_LiveSearchUpdate( p_playlist, p_root, psz_name );
+    Rebuild( true );
 
-    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 );
-    }
-
-    if( found.IsOk() )
-    {
-        search_current = found;
-        treectrl->EnsureVisible( found );
-        treectrl->UnselectAll();
-        treectrl->SelectItem( found, true );
-    }
+    wxLocaleFree( psz_name );
 }
 
 /**********************************************************************
@@ -1036,16 +1031,23 @@ void Playlist::RecursiveDeleteSelection(  wxTreeItemId root )
 {
     wxTreeItemIdValue cookie;
     wxTreeItemId child = treectrl->GetFirstChild( root, cookie );
+    wxTreeItemId nextchild;
+    bool childIsSelected = FALSE;
+    bool nextchildIsSelected = FALSE;
+
+    if( child.IsOk() ) childIsSelected = treectrl->IsSelected( child );
+
     while( child.IsOk() )
     {
-        if( treectrl->ItemHasChildren( child ) )
-        {
-            RecursiveDeleteSelection( child );
-            if( treectrl->IsSelected(child ) ) DeleteTreeItem( child );
-        }
-        else if( treectrl->IsSelected( child ) )
+        nextchild = treectrl->GetNextChild( root, cookie );
+        if( nextchild.IsOk() )
+            nextchildIsSelected = treectrl->IsSelected( nextchild );
+        if( childIsSelected )
             DeleteTreeItem( child );
-        child = treectrl->GetNextChild( root, cookie );
+        else if( treectrl->ItemHasChildren( child ) )
+            RecursiveDeleteSelection( child );
+        child = nextchild;
+        childIsSelected = nextchildIsSelected;
     }
 }
 
@@ -1083,46 +1085,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, true );
 
-    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, true, p_parent, p_item );
     }
-
-    playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, i_current_view,
-                      p_node, p_item );
     UnlockPlaylist( p_intf->p_sys, p_playlist );
 }
 
@@ -1130,22 +1118,28 @@ void Playlist::OnKeyDown( wxTreeEvent& event )
 {
     long keycode = event.GetKeyCode();
     /* Delete selected items */
-    if( keycode == WXK_BACK || keycode == WXK_DELETE )
+    if( keycode == WXK_BACK || keycode == WXK_DELETE || keycode == WXK_NUMPAD_DELETE )
     {
         /* 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 )
-{
-    msg_Warn( p_intf, "not implemented" );
-}
-
 void Playlist::OnDragItemBegin( wxTreeEvent& event )
 {
     event.Allow();
@@ -1158,7 +1152,7 @@ void Playlist::OnDragItemEnd( wxTreeEvent& event )
 
     if( !dest_tree_item.IsOk() ) return;
 
-    /* check that we're not trying to move a node into one of it's children */
+    /* check that we're not trying to move a node into one of its children */
     wxTreeItemId parent = dest_tree_item;
     while( parent != treectrl->GetRootItem() )
     {
@@ -1179,9 +1173,9 @@ void Playlist::OnDragItemEnd( wxTreeEvent& event )
     }
 
     playlist_item_t *p_drageditem =
-        playlist_ItemGetById(p_playlist, p_wxdrageditem->i_id );
+        playlist_ItemGetById(p_playlist, p_wxdrageditem->i_id, true );
     playlist_item_t *p_destitem =
-        playlist_ItemGetById(p_playlist, p_wxdestitem->i_id );
+        playlist_ItemGetById(p_playlist, p_wxdestitem->i_id, true );
     if( !p_drageditem || !p_destitem )
     {
         UnlockPlaylist( p_intf->p_sys, p_playlist );
@@ -1200,7 +1194,7 @@ void Playlist::OnDragItemEnd( wxTreeEvent& event )
             return;
         }
         playlist_item_t *p_destitem2 =
-            playlist_ItemGetById( p_playlist, p_parent->i_id );
+            playlist_ItemGetById( p_playlist, p_parent->i_id, true );
         if( !p_destitem2 )
         {
             UnlockPlaylist( p_intf->p_sys, p_playlist );
@@ -1211,20 +1205,18 @@ void Playlist::OnDragItemEnd( wxTreeEvent& event )
         {
             if( p_destitem2->pp_children[i] == p_destitem ) break;
         }
-        playlist_TreeMove( p_playlist, p_drageditem, p_destitem2,
-                           i, i_current_view );
+        playlist_TreeMove( p_playlist, p_drageditem, p_destitem2, i );
     }
     else
     /* this is a node */
     {
-        playlist_TreeMove( p_playlist, p_drageditem, p_destitem,
-                           0, i_current_view );
+        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 );
+    Rebuild( true );
 }
 
 #if wxUSE_DRAG_AND_DROP
@@ -1243,35 +1235,27 @@ bool PlaylistFileDropTarget::OnDropFiles( wxCoord x, wxCoord y,
 
     /* find the destination node and position in that node */
     const wxPoint pt( x, y );
-    int flags = 0;
-    wxTreeItemId item = p->treectrl->HitTest( pt, flags );
+    wxTreeItemId item = p->treectrl->HitTest( pt );
 
-    if( flags & wxTREE_HITTEST_NOWHERE )
+    if( !item.IsOk() )
     {
         /* We were droped below the last item so we append to the
          * general node */
-        p_dest = p->p_playlist->p_general;
+        msg_Err( p->p_playlist, "USE OF P_GENERAL" );
+        p_dest = p->p_playlist->p_local_category;
         i_pos = PLAYLIST_END;
     }
     else
     {
-        /* We were droped on an item */
-        if( !item.IsOk() )
-        {
-            printf("Arf ....\n" );
-            UnlockPlaylist( p->p_intf->p_sys, p->p_playlist );
-            return FALSE;
-        }
-
         PlaylistItem *p_plitem =
             (PlaylistItem *)p->treectrl->GetItemData( item );
-        p_dest = playlist_ItemGetById( p->p_playlist, p_plitem->i_id );
+        p_dest = playlist_ItemGetById( p->p_playlist, p_plitem->i_id, true );
 
         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 */
+             * leaf in its children list */
             wxTreeItemId parent = p->treectrl->GetItemParent( item );
             PlaylistItem *p_parent =
                 (PlaylistItem *)p->treectrl->GetItemData( parent );
@@ -1281,7 +1265,7 @@ bool PlaylistFileDropTarget::OnDropFiles( wxCoord x, wxCoord y,
                 return FALSE;
             }
             playlist_item_t *p_node =
-                playlist_ItemGetById( p->p_playlist, p_parent->i_id );
+                playlist_ItemGetById( p->p_playlist, p_parent->i_id, true );
             if( !p_node )
             {
                 UnlockPlaylist( p->p_intf->p_sys, p->p_playlist );
@@ -1300,16 +1284,19 @@ bool PlaylistFileDropTarget::OnDropFiles( wxCoord x, wxCoord y,
     /* Put the items in the playlist node */
     for( size_t i = 0; i < filenames.GetCount(); i++ )
     {
-        const char *psz_utf8 = wxDnDFromLocale( filenames[i] );
-        playlist_item_t *p_item =
-            playlist_ItemNew( p->p_playlist, psz_utf8, psz_utf8 );
-        playlist_NodeAddItem( p->p_playlist, p_item, p->i_current_view,
-                              p_dest, PLAYLIST_PREPARSE, i_pos );
+        char *psz_utf8 = wxDnDFromLocale( filenames[i] );
+        input_item_t *p_input = input_ItemNew( p->p_playlist,
+                                              psz_utf8, psz_utf8 );
+        int i_ret = ( playlist_BothAddInput( p->p_playlist, p_input, p_dest,
+                PLAYLIST_PREPARSE, i_pos, NULL, NULL, pl_Unlocked ) != VLC_SUCCESS );
+        vlc_gc_decref( p_input );
         wxDnDLocaleFree( psz_utf8 );
+        if( i_ret != VLC_SUCCESS )
+            return FALSE;
     }
 
     /* FIXME: having this Rebuild() is dirty */
-    p->Rebuild( VLC_TRUE );
+    p->Rebuild( true );
 
     return TRUE;
 }
@@ -1343,30 +1330,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 )
     {
@@ -1403,14 +1397,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;
 }
 
@@ -1418,41 +1406,28 @@ wxMenu *Playlist::SDMenu()
 {
     p_sd_menu = new wxMenu;
 
-    vlc_list_t *p_list = vlc_list_find( p_playlist, VLC_OBJECT_MODULE,
-                                        FIND_ANYWHERE );
+    char **ppsz_longnames;
+    char **ppsz_names = services_discovery_GetServicesNames( p_playlist,
+                                                             &ppsz_longnames );
+    if( !ppsz_names )
+        return p_sd_menu;
 
-    int i_number = 0;
-    for( int i_index = 0; i_index < p_list->i_count; i_index++ )
-    {
-        module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object ;
+    char **ppsz_name = ppsz_names, **ppsz_longname = ppsz_longnames;
 
-        if( !strcmp( p_parser->psz_capability, "services_discovery" ) )
-            i_number++;
-    }
-    if( i_number ) pp_sds = (char **)calloc( i_number, sizeof(void *) );
+    int i_number = 0;
 
-    i_number = 0;
-    for( int i_index = 0; i_index < p_list->i_count; i_index++ )
+    for( ; *ppsz_name; ppsz_name++, ppsz_longname++ )
     {
-        module_t * p_parser = (module_t *)p_list->p_values[i_index].p_object ;
+        p_sd_menu->AppendCheckItem( FirstSD_Event + i_number++ ,
+                                    wxU( *ppsz_longname ) );
 
-        if( !strcmp( p_parser->psz_capability, "services_discovery" ) )
-        {
-            p_sd_menu->AppendCheckItem( FirstSD_Event + i_number ,
-                wxU( p_parser->psz_longname ? p_parser->psz_longname :
-                     (p_parser->psz_shortname ?
-                      p_parser->psz_shortname : p_parser->psz_object_name) ) );
+        if( playlist_IsServicesDiscoveryLoaded( p_playlist, *ppsz_name ) )
+            p_sd_menu->Check( FirstSD_Event + i_number, TRUE );
 
-            if( playlist_IsServicesDiscoveryLoaded( p_playlist,
-                                    p_parser->psz_object_name ) )
-            {
-                p_sd_menu->Check( FirstSD_Event + i_number, TRUE );
-            }
-
-            pp_sds[i_number++] = p_parser->psz_object_name;
-        }
+        free( *ppsz_longname );
     }
-    vlc_list_release( p_list );
+    pp_sds = ppsz_names;
+    free( ppsz_longnames );
     return p_sd_menu;
 }
 
@@ -1477,7 +1452,7 @@ void Playlist::OnPopup( wxContextMenuEvent& event )
         treectrl->SelectItem( i_wx_popup_item );
 
         LockPlaylist( p_intf->p_sys, p_playlist );
-        p_item = playlist_ItemGetById( p_playlist, i_popup_item );
+        p_item = playlist_ItemGetById( p_playlist, i_popup_item, true );
 
         if( !p_item )
         {
@@ -1503,34 +1478,20 @@ 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_item = playlist_ItemGetById( p_playlist, i_popup_item, true );
+
+    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, true, p_popup_parent,
+                          p_popup_item );
     }
     UnlockPlaylist( p_intf->p_sys, p_playlist );
 }
@@ -1544,13 +1505,13 @@ void Playlist::Preparse()
 {
     playlist_item_t *p_popup_item;
     LockPlaylist( p_intf->p_sys, p_playlist );
-    p_popup_item = playlist_ItemGetById( p_playlist, i_popup_item );
+    p_popup_item = playlist_ItemGetById( p_playlist, i_popup_item, true );
 
     if( p_popup_item != NULL )
     {
         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
         {
@@ -1560,8 +1521,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();
             }
         }
@@ -1582,14 +1543,14 @@ void Playlist::OnPopupSort( wxCommandEvent& event )
     p_wxitem = (PlaylistItem *)treectrl->GetItemData( i_wx_popup_item );
     LockPlaylist( p_intf->p_sys, p_playlist );
 
-    p_item = playlist_ItemGetById( p_playlist, p_wxitem->i_id );
+    p_item = playlist_ItemGetById( p_playlist, p_wxitem->i_id, true );
     if( p_item->i_children >= 0 )
     {
         playlist_RecursiveNodeSort( p_playlist, p_item,
                                     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 );
 
     }
@@ -1599,7 +1560,9 @@ void Playlist::OnPopupSort( wxCommandEvent& event )
 void Playlist::OnPopupInfo( wxCommandEvent& event )
 {
     LockPlaylist( p_intf->p_sys, p_playlist );
-    playlist_item_t *p_popup_item = playlist_ItemGetById( p_playlist, i_popup_item );
+    playlist_item_t *p_popup_item = playlist_ItemGetById( p_playlist,
+                                                          i_popup_item,
+                                                          true );
     if( p_popup_item )
     {
         iteminfo_dialog = new ItemInfoDialog( p_intf, p_popup_item, this );
@@ -1627,16 +1590,28 @@ void Playlist::OnPopupAddNode( wxCommandEvent& event )
 
     p_wxitem = (PlaylistItem *)treectrl->GetItemData( i_wx_popup_item );
 
-    p_item = playlist_ItemGetById( p_playlist, p_wxitem->i_id );
+    p_item = playlist_ItemGetById( p_playlist, p_wxitem->i_id, true );
 
-    playlist_NodeCreate( p_playlist, i_current_view, psz_name, p_item );
+    playlist_NodeCreate( p_playlist, psz_name, p_item, 0, NULL );
 
     UnlockPlaylist( p_intf->p_sys, p_playlist );
-    Rebuild( VLC_TRUE );
+    Rebuild( 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,
+                                                       true );
+       if( p_item ) p_current_treeroot = p_item;
+       Rebuild( true );
+   }
+}
 
 /*****************************************************************************
  * Custom events management
@@ -1666,7 +1641,7 @@ static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable,
                             vlc_value_t oval, vlc_value_t nval, void *param )
 {
     Playlist *p_playlist_dialog = (Playlist *)param;
-    p_playlist_dialog->b_need_update = VLC_TRUE;
+    p_playlist_dialog->b_need_update = true;
     return VLC_SUCCESS;
 }
 
@@ -1725,7 +1700,7 @@ static int ItemAppended( vlc_object_t *p_this, const char *psz_variable,
     {
         /* Too many items waiting to be added, it will be quicker to rebuild
          * the whole playlist */
-        p_playlist_dialog->b_need_update = VLC_TRUE;
+        p_playlist_dialog->b_need_update = true;
         return VLC_SUCCESS;
     }