From d7b7a711d3aca998300780199a2ff89e85b9f784 Mon Sep 17 00:00:00 2001
From: Jakob Leben <jakob.leben@gmail.com>
Date: Mon, 17 Aug 2009 01:57:01 +0200
Subject: [PATCH] playlist: new function playlist_TreeMoveMany

Add new function which simplifies moving more then one item at a time and increases
performance of such action. Also refactor a bit old playlist_TreeMove.
Use new function in Qt4 playlist model.
---
 include/vlc_playlist.h                             |    1 +
 .../gui/qt4/components/playlist/playlist_model.cpp |   71 ++++++++--------
 src/libvlccore.sym                                 |    1 +
 src/playlist/item.c                                |   85 +++++++++++++-------
 4 files changed, 95 insertions(+), 63 deletions(-)

diff --git a/include/vlc_playlist.h b/include/vlc_playlist.h
index b98e13c..0c63d8d 100644
--- a/include/vlc_playlist.h
+++ b/include/vlc_playlist.h
@@ -300,6 +300,7 @@ VLC_EXPORT( int, playlist_AskForArtEnqueue, (playlist_t *, input_item_t *, bool
 
 /* Playlist sorting */
 VLC_EXPORT( int,  playlist_TreeMove, ( playlist_t *, playlist_item_t *, playlist_item_t *, int ) );
+VLC_EXPORT( int,  playlist_TreeMoveMany, ( playlist_t *, int, playlist_item_t **, playlist_item_t *, int ) );
 VLC_EXPORT( int,  playlist_RecursiveNodeSort, ( playlist_t *, playlist_item_t *,int, int ) );
 
 VLC_EXPORT( playlist_item_t *,  playlist_CurrentPlayingItem, ( playlist_t * ) );
diff --git a/modules/gui/qt4/components/playlist/playlist_model.cpp b/modules/gui/qt4/components/playlist/playlist_model.cpp
index 3553103..9b66bc8 100644
--- a/modules/gui/qt4/components/playlist/playlist_model.cpp
+++ b/modules/gui/qt4/components/playlist/playlist_model.cpp
@@ -213,22 +213,16 @@ bool PLModel::dropMimeData( const QMimeData *data, Qt::DropAction action,
         if( !parent.isValid())
         {
             if( row > -1)
-            {
-                // dropped into top node
                 p_parent = playlist_ItemGetById( p_playlist, rootItem->i_id );
-            }
             else
             {
-                // dropped outside any item
                 PL_UNLOCK;
                 return true;
             }
         }
         else
-        {
-            // dropped into/onto an item (depends on (row = -1) or (row > -1))
             p_parent = playlist_ItemGetById( p_playlist, itemId ( parent ) );
-        }
+
         if( !p_parent || p_parent->i_children == -1 )
         {
             PL_UNLOCK;
@@ -244,45 +238,52 @@ bool PLModel::dropMimeData( const QMimeData *data, Qt::DropAction action,
         QByteArray encodedData = data->data( "vlc/playlist-item-id" );
         QDataStream stream( &encodedData, QIODevice::ReadOnly );
 
-        /* easiest way to never miss the right index to move to is to
-        track the previously moved item */
-        playlist_item_t *p_target = NULL;
-
-        while( !stream.atEnd() )
+        if( copy )
         {
-            int src_id;
-            stream >> src_id;
-            playlist_item_t *p_src = playlist_ItemGetById( p_playlist, src_id );
-
-            if( !p_src )
-            {
-                PL_UNLOCK;
-                return false;
-            }
-            if( copy )
+            while( !stream.atEnd() )
             {
-                input_item_t *input = p_src->p_input;
+                int i_id;
+                stream >> i_id;
+                playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_id );
+                if( !p_item )
+                {
+                    PL_UNLOCK;
+                    return false;
+                }
+                input_item_t *p_input = p_item->p_input;
                 playlist_AddExt ( p_playlist,
-                    p_src->p_input->psz_uri, p_src->p_input->psz_name,
+                    p_input->psz_uri, p_input->psz_name,
                     PLAYLIST_APPEND | PLAYLIST_SPREPARSE, PLAYLIST_END,
-                    input->i_duration,
-                    input->i_options, input->ppsz_options, input->optflagc,
+                    p_input->i_duration,
+                    p_input->i_options, p_input->ppsz_options, p_input->optflagc,
                     p_parent == p_playlist->p_local_category, true );
-                continue;
             }
-            if( !p_target )
+        }
+        else
+        {
+            QList<int> ids;
+            while( !stream.atEnd() )
             {
-                if ( row == -1 ) row = p_parent->i_children;
-                playlist_TreeMove( p_playlist, p_src, p_parent, row );
+                int id;
+                stream >> id;
+                ids.append(id);
             }
-            else
+            int count = ids.size();
+            playlist_item_t *items[count];
+            for( int i = 0; i < count; i++ )
             {
-                for( row = 0 ; row < p_target->p_parent->i_children ; row++ )
-                    if( p_target->p_parent->pp_children[row] == p_target ) break;
-                playlist_TreeMove( p_playlist, p_src, p_parent, row + 1 );
+                playlist_item_t *item = playlist_ItemGetById( p_playlist, ids[i] );
+                if( !item )
+                {
+                    PL_UNLOCK;
+                    return false;
+                }
+                items[i] = item;
             }
-            p_target = p_src;
+            playlist_TreeMoveMany( p_playlist, count, items, p_parent,
+                (row == -1 ? p_parent->i_children : row) );
         }
+
         PL_UNLOCK;
         /*TODO: That's not a good idea to rebuild the playlist */
         rebuild();
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 94cf635..6381f5d 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -334,6 +334,7 @@ playlist_ServicesDiscoveryAdd
 playlist_ServicesDiscoveryRemove
 playlist_Status
 playlist_TreeMove
+playlist_TreeMoveMany
 playlist_Unlock
 __pl_Hold
 __pl_Release
diff --git a/src/playlist/item.c b/src/playlist/item.c
index 4051a82..d9ea120 100644
--- a/src/playlist/item.c
+++ b/src/playlist/item.c
@@ -672,57 +672,86 @@ playlist_item_t *playlist_ItemFindFromInputAndRoot( playlist_t *p_playlist,
 }
 
 
-static int TreeMove( playlist_t *p_playlist, playlist_item_t *p_item,
-                     playlist_item_t *p_node, int i_newpos )
+static int ItemIndex ( playlist_item_t *p_item )
 {
-    int j;
-    playlist_item_t *p_detach = p_item->p_parent;
-    (void)p_playlist;
+    for( int i = 0; i < p_item->p_parent->i_children; i++ )
+        if( p_item->p_parent->pp_children[i] == p_item ) return i;
+    return -1;
+}
+
+/**
+ * Moves an item
+ *
+ * This function must be entered with the playlist lock
+ *
+ * \param p_playlist the playlist
+ * \param p_item the item to move
+ * \param p_node the new parent of the item
+ * \param i_newpos the new position under this new parent
+ * \return VLC_SUCCESS or an error
+ */
+int playlist_TreeMove( playlist_t * p_playlist, playlist_item_t *p_item,
+                       playlist_item_t *p_node, int i_newpos )
+{
+    PL_ASSERT_LOCKED;
 
     if( p_node->i_children == -1 ) return VLC_EGENERIC;
 
-    for( j = 0; j < p_detach->i_children; j++ )
-    {
-         if( p_detach->pp_children[j] == p_item ) break;
-    }
-    REMOVE_ELEM( p_detach->pp_children, p_detach->i_children, j );
+    playlist_item_t *p_detach = p_item->p_parent;
+    int i_index = ItemIndex( p_item );
 
-    /* If j < i_newpos, we are moving the element from the top to the
-     * down of the playlist. So when removing the element we have
-     * to change the position as we loose one element
-     */
-    if( p_detach == p_node && j < i_newpos )
+    REMOVE_ELEM( p_detach->pp_children, p_detach->i_children, i_index );
+
+    if( p_detach == p_node && i_index < i_newpos )
         i_newpos--;
 
-    /* Attach to new parent */
     INSERT_ELEM( p_node->pp_children, p_node->i_children, i_newpos, p_item );
     p_item->p_parent = p_node;
 
+    pl_priv( p_playlist )->b_reset_currently_playing = true;
+    vlc_cond_signal( &pl_priv( p_playlist )->signal );
     return VLC_SUCCESS;
 }
 
 /**
- * Moves an item
+ * Moves an array of items
  *
  * This function must be entered with the playlist lock
  *
  * \param p_playlist the playlist
- * \param p_item the item to move
- * \param p_node the new parent of the item
- * \param i_newpos the new position under this new parent
+ * \param i_items the number of indexes to move
+ * \param pp_items the array of indexes to move
+ * \param p_node the target node
+ * \param i_newpos the target position under this node
  * \return VLC_SUCCESS or an error
  */
-int playlist_TreeMove( playlist_t * p_playlist, playlist_item_t *p_item,
-                       playlist_item_t *p_node, int i_newpos )
+int playlist_TreeMoveMany( playlist_t *p_playlist,
+                            int i_items, playlist_item_t **pp_items,
+                            playlist_item_t *p_node, int i_newpos )
 {
-    int i_ret;
     PL_ASSERT_LOCKED;
 
-    if( p_node != p_item->p_parent ) return VLC_SUCCESS;
-    i_ret = TreeMove( p_playlist, p_item, p_node, i_newpos );
-    pl_priv(p_playlist)->b_reset_currently_playing = true;
-    vlc_cond_signal( &pl_priv(p_playlist)->signal );
-    return i_ret;
+    if ( p_node->i_children == -1 ) return VLC_EGENERIC;
+
+    int i;
+    for( i = 0; i < i_items; i++ )
+    {
+        playlist_item_t *p_item = pp_items[i];
+        int i_index = ItemIndex( p_item );
+        playlist_item_t *p_parent = p_item->p_parent;
+        REMOVE_ELEM( p_parent->pp_children, p_parent->i_children, i_index );
+        if ( p_parent == p_node && i_index < i_newpos ) i_newpos--;
+    }
+    for( i = i_items - 1; i >= 0; i-- )
+    {
+        playlist_item_t *p_item = pp_items[i];
+        INSERT_ELEM( p_node->pp_children, p_node->i_children, i_newpos, p_item );
+        p_item->p_parent = p_node;
+    }
+
+    pl_priv( p_playlist )->b_reset_currently_playing = true;
+    vlc_cond_signal( &pl_priv( p_playlist )->signal );
+    return VLC_SUCCESS;
 }
 
 /**
-- 
1.6.0.4

