From af5af111f978c0ff59205f8114293b533e073197 Mon Sep 17 00:00:00 2001
From: Jakob Leben <jleben@videolan.org>
Date: Thu, 11 Mar 2010 19:26:53 +0100
Subject: [PATCH 2/3] playlist: new playlist_NodeAddCopy(), modified playlist_NodeCreate()

- New function to copy a playlist item and all its children.
- Allow node creation at any position in parent.
---
 include/vlc_playlist.h |    3 +-
 src/libvlccore.sym     |    1 +
 src/playlist/item.c    |   90 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/playlist/tree.c    |    8 +++--
 4 files changed, 98 insertions(+), 4 deletions(-)

diff --git a/include/vlc_playlist.h b/include/vlc_playlist.h
index 181e529..f6cb8a9 100644
--- a/include/vlc_playlist.h
+++ b/include/vlc_playlist.h
@@ -348,6 +348,7 @@ VLC_EXPORT( int,  playlist_Add,    ( playlist_t *, const char *, const char *, i
 VLC_EXPORT( int,  playlist_AddExt, ( playlist_t *, const char *, const char *, int, int, mtime_t, int, const char *const *, unsigned, bool, bool ) );
 VLC_EXPORT( int, playlist_AddInput, ( playlist_t *, input_item_t *, int, int, bool, bool ) );
 VLC_EXPORT( playlist_item_t *, playlist_NodeAddInput, ( playlist_t *, input_item_t *, playlist_item_t *, int, int, bool ) );
+VLC_EXPORT( int, playlist_NodeAddCopy, ( playlist_t *, playlist_item_t *, playlist_item_t *, int ) );
 
 /********************************** Item search *************************/
 VLC_EXPORT( playlist_item_t *, playlist_ItemGetById, (playlist_t *, int ) );
@@ -359,7 +360,7 @@ VLC_EXPORT( int, playlist_LiveSearchUpdate, (playlist_t *, playlist_item_t *, co
  * Tree management
  ********************************************************/
 /* Node management */
-VLC_EXPORT( playlist_item_t *, playlist_NodeCreate, ( playlist_t *, const char *, playlist_item_t * p_parent, int i_flags, input_item_t * ) );
+VLC_EXPORT( playlist_item_t *, playlist_NodeCreate, ( playlist_t *, const char *, playlist_item_t * p_parent, int i_pos, int i_flags, input_item_t * ) );
 VLC_EXPORT( int, playlist_NodeAppend, (playlist_t *,playlist_item_t*,playlist_item_t *) );
 VLC_EXPORT( int, playlist_NodeInsert, (playlist_t *,playlist_item_t*,playlist_item_t *, int) );
 VLC_EXPORT( int, playlist_NodeRemoveItem, (playlist_t *,playlist_item_t*,playlist_item_t *) );
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 4343aa1..1e60cba 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -337,6 +337,7 @@ playlist_ItemGetById
 playlist_ItemGetByInput
 playlist_LiveSearchUpdate
 playlist_Lock
+playlist_NodeAddCopy
 playlist_NodeAddInput
 playlist_NodeAppend
 playlist_NodeCreate
diff --git a/src/playlist/item.c b/src/playlist/item.c
index 9b8a469..64d8131 100644
--- a/src/playlist/item.c
+++ b/src/playlist/item.c
@@ -40,6 +40,9 @@ static int RecursiveAddIntoParent (
                 playlist_t *p_playlist, playlist_item_t *p_parent,
                 input_item_node_t *p_node, int i_pos, bool b_flat,
                 playlist_item_t **pp_first_leaf );
+static int RecursiveInsertCopy (
+                playlist_t *p_playlist, playlist_item_t *p_item,
+                playlist_item_t *p_parent, int i_pos, bool b_flat );
 
 /*****************************************************************************
  * An input item has gained subitems (Event Callback)
@@ -453,6 +456,45 @@ playlist_item_t * playlist_NodeAddInput( playlist_t *p_playlist,
 }
 
 /**
+ * Copy an item (and all its children, if any) into another node
+ *
+ * \param p_playlist the playlist to operate on
+ * \param p_item the playlist item to copy
+ * \param p_parent the parent item to copy into
+ * \param i_pos the position in the parent item for the new copy;
+ *              if this is PLAYLIST_END, the copy is appended after all
+ *              parent's children
+ * \return the position in parent item just behind the last new item inserted
+ */
+int playlist_NodeAddCopy (
+    playlist_t *p_playlist, playlist_item_t *p_item,
+    playlist_item_t *p_parent, int i_pos )
+{
+    PL_ASSERT_LOCKED;
+    assert( p_parent != NULL && p_item != NULL );
+    assert( p_parent->i_children > -1 );
+
+    if( i_pos == PLAYLIST_END ) i_pos = p_parent->i_children;
+
+    bool b_flat = false;
+
+    playlist_item_t *p_up = p_parent;
+    while( p_up )
+    {
+        if( p_up == p_playlist->p_playing )
+            if( !pl_priv(p_playlist)->b_tree ) b_flat = true;
+        if( p_up == p_item )
+            /* TODO: We don't support copying a node into itself (yet),
+            because we insert items as we copy. Instead, we should copy
+            all items first and then insert. */
+            return i_pos;
+        p_up = p_up->p_parent;
+    }
+
+    return RecursiveInsertCopy( p_playlist, p_item, p_parent, i_pos, b_flat );
+}
+
+/**
  * Insert a tree of input items into a given playlist node
  *
  * \param p_playlist the playlist to insert into
@@ -474,6 +516,7 @@ playlist_item_t *playlist_InsertInputItemTree (
   return p_first_leaf;
 }
 
+
 /*****************************************************************************
  * Playlist item misc operations
  *****************************************************************************/
@@ -790,3 +833,50 @@ static int RecursiveAddIntoParent (
   }
   return i_pos;
 }
+
+static int RecursiveInsertCopy (
+    playlist_t *p_playlist, playlist_item_t *p_item,
+    playlist_item_t *p_parent, int i_pos, bool b_flat )
+{
+    PL_ASSERT_LOCKED;
+    assert( p_parent != NULL && p_item != NULL );
+
+    if( p_item == p_parent ) return i_pos;
+
+    input_item_t *p_input = p_item->p_input;
+
+    if( !(p_item->i_children != -1 && b_flat) )
+    {
+        input_item_t *p_new_input = input_item_Copy( VLC_OBJECT(p_playlist),
+                                                     p_input );
+        if( !p_new_input ) return i_pos;
+
+        playlist_item_t *p_new_item = NULL;
+        if( p_item->i_children == -1 )
+            p_new_item = playlist_NodeAddInput( p_playlist, p_new_input,
+                                   p_parent, PLAYLIST_INSERT, i_pos,
+                                   pl_Locked );
+        else
+            p_new_item = playlist_NodeCreate( p_playlist, NULL,
+                                 p_parent, i_pos, 0, p_new_input );
+        vlc_gc_decref( p_new_input );
+        if( !p_new_item ) return i_pos;
+
+        i_pos++;
+
+        if( p_new_item->i_children != -1 )
+            p_parent = p_new_item;
+    }
+
+    for( int i = 0; i < p_item->i_children; i++ )
+    {
+        if( b_flat )
+            i_pos = RecursiveInsertCopy( p_playlist, p_item->pp_children[i],
+                                         p_parent, i_pos, true );
+        else
+            RecursiveInsertCopy( p_playlist, p_item->pp_children[i],
+                                 p_parent, p_parent->i_children, false );
+    }
+
+    return i_pos;
+}
diff --git a/src/playlist/tree.c b/src/playlist/tree.c
index ce93971..eae53bd 100644
--- a/src/playlist/tree.c
+++ b/src/playlist/tree.c
@@ -50,14 +50,15 @@ playlist_item_t *GetPrevItem( playlist_t *p_playlist,
  * \param p_playlist the playlist
  * \param psz_name the name of the node
  * \param p_parent the parent node to attach to or NULL if no attach
+ * \param i_pos position of the node in the parent, PLAYLIST_END to append to end.
  * \param p_flags miscellaneous flags
  * \param p_input the input_item to attach to or NULL if it has to be created
  * \return the new node
  */
 playlist_item_t * playlist_NodeCreate( playlist_t *p_playlist,
                                        const char *psz_name,
-                                       playlist_item_t *p_parent, int i_flags,
-                                       input_item_t *p_input )
+                                       playlist_item_t *p_parent, int i_pos,
+                                       int i_flags, input_item_t *p_input )
 {
     input_item_t *p_new_input = NULL;
     playlist_item_t *p_item;
@@ -79,7 +80,8 @@ playlist_item_t * playlist_NodeCreate( playlist_t *p_playlist,
     ARRAY_APPEND(p_playlist->all_items, p_item);
 
     if( p_parent != NULL )
-        playlist_NodeAppend( p_playlist, p_item, p_parent );
+        playlist_NodeInsert( p_playlist, p_item, p_parent,
+                             i_pos == PLAYLIST_END ? -1 : i_pos );
     playlist_SendAddNotify( p_playlist, p_item->i_id,
                             p_parent ? p_parent->i_id : -1,
                             !( i_flags & PLAYLIST_NO_REBUILD ));
-- 
1.6.3.3

