Playtree: handle delete nicely
authorClément Stenac <zorglub@videolan.org>
Sun, 12 Feb 2006 11:18:43 +0000 (11:18 +0000)
committerClément Stenac <zorglub@videolan.org>
Sun, 12 Feb 2006 11:18:43 +0000 (11:18 +0000)
modules/gui/skins2/commands/cmd_vars.cpp
modules/gui/skins2/commands/cmd_vars.hpp
modules/gui/skins2/controls/ctrl_tree.cpp
modules/gui/skins2/src/vlcproc.cpp
modules/gui/skins2/src/vlcproc.hpp
modules/gui/skins2/utils/var_tree.cpp
modules/gui/skins2/utils/var_tree.hpp
modules/gui/skins2/vars/playtree.cpp
modules/gui/skins2/vars/playtree.hpp

index 33b4a35..ce08f35 100644 (file)
@@ -71,6 +71,13 @@ void CmdPlaytreeAppend::execute()
     rVar.onAppend( m_pAdd );
 }
 
+void CmdPlaytreeDelete::execute()
+{
+    // Notify  the playtree variable
+    Playtree &rVar = VlcProc::instance( getIntf() )->getPlaytreeVar();
+    rVar.onDelete( m_id );
+}
+
 void CmdSetText::execute()
 {
     // Change the text variable
index ae93a80..608ee4e 100644 (file)
@@ -77,6 +77,26 @@ class CmdPlaytreeAppend: public CmdGeneric
         playlist_add_t * m_pAdd;
 };
 
+/// Command to notify the playtree of an item deletion
+class CmdPlaytreeDelete: public CmdGeneric
+{
+    public:
+        CmdPlaytreeDelete( intf_thread_t *pIntf, int i_id ) :
+            CmdGeneric( pIntf ), m_id( i_id ) {}
+        virtual ~CmdPlaytreeDelete() {}
+
+        /// This method does the real job of the command
+        virtual void execute();
+
+        /// Return the type of the command
+        virtual string getType() const { return "playtree append"; }
+
+    private:
+        int m_id;
+};
+
+
+
 
 /// Command to set a text variable
 class CmdSetText: public CmdGeneric
index e7272b3..86863a6 100644 (file)
@@ -150,7 +150,22 @@ void CtrlTree::onUpdate( Subject<VarTree, tree_update*> &rTree,
     }
     else if ( arg->i_type == 2 ) // Item-append
     {
-        /// \todo Check if the item is really visible in the view (we only check if it in the document)
+        /// \todo Check if the item is really visible in the view
+        // (we only check if it in the document)
+        if( arg->b_visible == true )
+        {
+            makeImage();
+        }
+    }
+    else if( arg->i_type == 3 ) // item-del
+    {
+        /* Make sure firstPos and lastSelected are still valid */
+        while( m_firstPos->m_deleted && m_firstPos != m_rTree.root()->begin() )
+        {
+            m_firstPos = m_rTree.getPrevVisibleItem( m_firstPos );
+        }
+        if( m_firstPos->m_deleted ) m_firstPos = m_rTree.root()->begin();
+
         if( arg->b_visible == true )
         {
             makeImage();
@@ -453,27 +468,30 @@ void CtrlTree::handleEvent( EvtGeneric &rEvent )
                  string::npos )
         {
             it = findItemAtPos(yPos);
-            if( it->size() && xPos > (it->depth() - 1) * itemImageWidth()
-                && xPos < it->depth() * itemImageWidth() )
-            {
-                // Fold/unfold the item
-                it->m_expanded = !it->m_expanded;
-                bChangedPosition = true;
-            }
-            else
+            if( it != m_rTree.end() )
             {
-                // Unselect any previously selected item
-                VarTree::Iterator it2;
-                for( it2 = m_rTree.begin(); it2 != m_rTree.end();
-                     it2 = m_rTree.getNextVisibleItem( it2 ) )
+                if( it->size() && xPos > (it->depth() - 1) * itemImageWidth()
+                    && xPos < it->depth() * itemImageWidth() )
                 {
-                    it2->m_selected = false;
+                    // Fold/unfold the item
+                    it->m_expanded = !it->m_expanded;
+                    bChangedPosition = true;
                 }
-                // Select the new item
-                if( it != m_rTree.end() )
+                else
                 {
-                    it->m_selected = true;
-                    m_pLastSelected = &*it;
+                    // Unselect any previously selected item
+                    VarTree::Iterator it2;
+                    for( it2 = m_rTree.begin(); it2 != m_rTree.end();
+                         it2 = m_rTree.getNextVisibleItem( it2 ) )
+                    {
+                        it2->m_selected = false;
+                    }
+                    // Select the new item
+                    if( it != m_rTree.end() )
+                    {
+                        it->m_selected = true;
+                        m_pLastSelected = &*it;
+                    }
                 }
             }
         }
@@ -666,7 +684,10 @@ void CtrlTree::makeImage()
                     m_pImage->fillRect( 0, yPos, width, rectHeight,
                                         m_selColor );
                 }
-                it = m_rTree.getNextVisibleItem( it );
+                do
+                {
+                    it = m_rTree.getNextVisibleItem( it );
+                } while( it->m_deleted );
             }
         }
     }
@@ -683,7 +704,10 @@ void CtrlTree::makeImage()
             {
                 uint32_t color = ( it->m_selected ? m_selColor : bgColor );
                 m_pImage->fillRect( 0, yPos, width, rectHeight, color );
-                it = m_rTree.getNextVisibleItem( it );
+                do
+                {
+                    it = m_rTree.getNextVisibleItem( it );
+                } while( it->m_deleted );
             }
             else
             {
@@ -746,7 +770,9 @@ void CtrlTree::makeImage()
             yPos += (pText->getHeight() - ySrc );
             delete pText;
         }
+        do {
         it = m_rTree.getNextVisibleItem( it );
+        } while( it->m_deleted );
     }
 }
 
index 5def142..ee0840c 100644 (file)
@@ -128,7 +128,7 @@ VlcProc::VlcProc( intf_thread_t *pIntf ): SkinObject( pIntf ),
     // Called when a playlist item is deleted
     // TODO: properly handle item-deleted
     var_AddCallback( pIntf->p_sys->p_playlist, "item-deleted",
-                     onIntfChange, this );
+                     onItemDelete, this );
     // Called when the "interface shower" wants us to show the skin
     var_AddCallback( pIntf->p_sys->p_playlist, "intf-show",
                      onIntfShow, this );
@@ -174,7 +174,7 @@ VlcProc::~VlcProc()
     var_DelCallback( getIntf()->p_sys->p_playlist, "item-append",
                      onItemAppend, this );
     var_DelCallback( getIntf()->p_sys->p_playlist, "item-deleted",
-                     onIntfChange, this );
+                     onItemDelete, this );
     var_DelCallback( getIntf()->p_sys->p_playlist, "intf-show",
                      onIntfShow, this );
     var_DelCallback( getIntf()->p_sys->p_playlist, "playlist-current",
@@ -443,6 +443,31 @@ int VlcProc::onItemAppend( vlc_object_t *pObj, const char *pVariable,
     return VLC_SUCCESS;
 }
 
+int VlcProc::onItemDelete( vlc_object_t *pObj, const char *pVariable,
+                           vlc_value_t oldVal, vlc_value_t newVal,
+                           void *pParam )
+{
+    VlcProc *pThis = (VlcProc*)pParam;
+
+    int i_id = newVal.i_int;
+
+    CmdGenericPtr ptrTree;
+    CmdPlaytreeDelete *pCmdTree = new CmdPlaytreeDelete( pThis->getIntf(),
+                                                         i_id);
+    ptrTree = CmdGenericPtr( pCmdTree );
+
+    // Create a playlist notify command (for old style playlist)
+    CmdNotifyPlaylist *pCmd = new CmdNotifyPlaylist( pThis->getIntf() );
+
+    // Push the command in the asynchronous command queue
+    AsyncQueue *pQueue = AsyncQueue::instance( pThis->getIntf() );
+    pQueue->push( CmdGenericPtr( pCmd ) );
+    pQueue->push( ptrTree , false );
+
+    return VLC_SUCCESS;
+}
+
+
 
 
 int VlcProc::onPlaylistChange( vlc_object_t *pObj, const char *pVariable,
index 9b65fc8..363b233 100644 (file)
@@ -173,6 +173,12 @@ class VlcProc: public SkinObject
                                  vlc_value_t oldVal, vlc_value_t newVal,
                                  void *pParam );
 
+        /// Callback for item-change variable
+        static int onItemDelete( vlc_object_t *pObj, const char *pVariable,
+                                 vlc_value_t oldVal, vlc_value_t newVal,
+                                 void *pParam );
+
+
         /// Callback for playlist-current variable
         static int onPlaylistChange( vlc_object_t *pObj, const char *pVariable,
                                      vlc_value_t oldVal, vlc_value_t newVal,
index e6d8c11..230c187 100644 (file)
@@ -28,7 +28,8 @@ const string VarTree::m_type = "tree";
 
 VarTree::VarTree( intf_thread_t *pIntf )
     : Variable( pIntf ), m_id( 0 ), m_selected( false ), m_playing( false ),
-    m_expanded( false ), m_pData( NULL ), m_pParent( NULL )
+    m_expanded( false ), m_deleted( false ), m_readonly( false),
+    m_pData( NULL ), m_pParent( NULL )
 {
     // Create the position variable
     m_cPosition = VariablePtr( new VarPercent( pIntf ) );
@@ -37,11 +38,14 @@ VarTree::VarTree( intf_thread_t *pIntf )
 
 VarTree::VarTree( intf_thread_t *pIntf, VarTree *pParent, int id,
                   const UStringPtr &rcString, bool selected, bool playing,
-                  bool expanded, void *pData )
+                  bool expanded, bool readonly,
+                  void *pData )
     : Variable( pIntf ), m_id( id ), m_cString( rcString ),
     m_selected( selected ), m_playing( playing ), m_expanded( expanded ),
+    m_deleted( false ), m_readonly( readonly ),
     m_pData( pData ), m_pParent( pParent )
 {
+    fprintf( stderr, "Expanded is %i - RO %i\n", m_expanded, m_readonly );
     // Create the position variable
     m_cPosition = VariablePtr( new VarPercent( pIntf ) );
     getPositionVar().set( 1.0 );
@@ -53,10 +57,12 @@ VarTree::~VarTree()
 }
 
 void VarTree::add( int id, const UStringPtr &rcString, bool selected,
-                   bool playing, bool expanded, void *pData )
+                   bool playing, bool expanded, bool readonly,
+                   void *pData )
 {
     m_children.push_back( VarTree( getIntf(), this, id, rcString, selected,
-                                   playing, expanded, pData ) );
+                                   playing, expanded, readonly,
+                                   pData ) );
 }
 
 void VarTree::delSelected()
@@ -105,6 +111,22 @@ VarTree::ConstIterator VarTree::operator[]( int n ) const
     return it;
 }
 
+VarTree::Iterator VarTree::getNextSibling( VarTree::Iterator current )
+{
+    VarTree *p_parent = current->parent();
+    if( p_parent  && current != p_parent->end() )
+    {
+        Iterator it = current->parent()->begin();
+        while( it != p_parent->end() && it != current ) it++;
+        if( it != p_parent->end() )
+        {
+            it++;
+        }
+        return root()->end();
+    }
+    return root()->end();
+}
+
 /* find iterator to next ancestor
  * ... which means parent++ or grandparent++ or grandgrandparent++ ... */
 VarTree::Iterator VarTree::next_uncle()
index 96cd19b..ef2cd4f 100644 (file)
@@ -49,7 +49,7 @@ class VarTree: public Variable, public Subject<VarTree, tree_update*>
 
         VarTree( intf_thread_t *pIntf, VarTree *pParent, int id,
                  const UStringPtr &rcString, bool selected, bool playing,
-                 bool expanded, void *pData );
+                 bool expanded,bool readonly, void *pData );
 
         virtual ~VarTree();
 
@@ -58,7 +58,8 @@ class VarTree: public Variable, public Subject<VarTree, tree_update*>
 
         /// Add a pointer on string in the children's list
         virtual void add( int id, const UStringPtr &rcString, bool selected,
-                          bool playing, bool expanded, void *pData );
+                          bool playing, bool expanded, bool readonly,
+                          void *pData );
 
         /// Remove the selected item from the children's list
         virtual void delSelected();
@@ -72,8 +73,11 @@ class VarTree: public Variable, public Subject<VarTree, tree_update*>
         bool m_selected;
         bool m_playing;
         bool m_expanded;
+        bool m_deleted;
         void *m_pData;
 
+        inline bool isReadonly() { return m_readonly; };
+
         /// Get the number of children
         int size() const { return m_children.size(); }
 
@@ -100,6 +104,9 @@ class VarTree: public Variable, public Subject<VarTree, tree_update*>
         VarTree *parent() { return m_pParent; }
         void checkParents( VarTree *pParent );
 
+        /// Get next sibling
+        Iterator getNextSibling( Iterator );
+
         Iterator next_uncle();
         Iterator prev_uncle();
 
@@ -122,6 +129,11 @@ class VarTree: public Variable, public Subject<VarTree, tree_update*>
             return depth;
         }
 
+        void removeChild( VarTree::Iterator item )
+        {
+            m_children.erase( item );
+        }
+
         /// Execute the action associated to this item
         virtual void action( VarTree *pItem ) {}
 
@@ -160,6 +172,8 @@ class VarTree: public Variable, public Subject<VarTree, tree_update*>
         /// Pointer to parent node
         VarTree *m_pParent;
 
+        bool m_readonly;
+
         /// Variable type
         static const string m_type;
 
index 2ba159e..3b3b922 100644 (file)
@@ -58,31 +58,49 @@ Playtree::~Playtree()
 
 void Playtree::delSelected()
 {
-    Iterator it;
-    for (it = begin(); it != end() ; it = getNextVisibleItem( it ) )
+    Iterator it = begin();
+    vlc_mutex_lock( &getIntf()->p_sys->p_playlist->object_lock );
+    for( it = begin(); it != end(); it = getNextVisibleItem( it ) )
     {
-        if( (*it).m_selected )
+        if( (*it).m_selected && !(*it).isReadonly() )
         {
+            (*it).m_deleted = true;
+        }
+    }
+    /// \todo Do this better (handle item-deleted)
+    tree_update descr;
+    descr.i_type = 3;
+    notify( &descr );
+    it = begin();
+    while( it != end() )
+    {
+        if( (*it).m_deleted )
+        {
+            VarTree::Iterator it2;
             playlist_item_t *p_item = (playlist_item_t *)(it->m_pData);
             if( p_item->i_children == -1 )
             {
-                playlist_LockDelete( getIntf()->p_sys->p_playlist,
+                playlist_Delete( getIntf()->p_sys->p_playlist,
                                      p_item->input.i_id );
+                it2 = getNextVisibleItem( it ) ;
+                it->parent()->removeChild( it );
+                it = it2;
             }
             else
             {
-                vlc_mutex_lock( &getIntf()->p_sys->p_playlist->object_lock );
                 playlist_NodeDelete( getIntf()->p_sys->p_playlist, p_item,
                                      VLC_TRUE, VLC_FALSE );
-                vlc_mutex_unlock( &getIntf()->p_sys->p_playlist->object_lock );
+                it2 = getNextSibling( it );
+                it->parent()->removeChild( it );
+                it = it2;
             }
         }
+        else
+        {
+            it = getNextVisibleItem( it );
+        }
     }
-    /// \todo Do this better (handle item-deleted)
-    buildTree();
-    tree_update descr;
-    descr.i_type = 1;
-    notify( &descr );
+    vlc_mutex_unlock( &getIntf()->p_sys->p_playlist->object_lock );
 }
 
 void Playtree::action( VarTree *pItem )
@@ -137,6 +155,23 @@ void Playtree::onUpdateItem( int id )
     notify( &descr );
 }
 
+/// \todo keep a list of "recently removed" to avoid looking up if we
+//  already removed it
+void Playtree::onDelete( int i_id )
+{
+    tree_update descr;
+    descr.i_id = i_id;
+    descr.i_type = 3;
+    Iterator item = findById( i_id ) ;
+    if( item != end() )
+    {
+        if( item->parent() )
+            item->parent()->removeChild( item );
+        descr.b_visible = item->parent() ? true : item->parent()->m_expanded;
+        notify( &descr );
+    }
+}
+
 void Playtree::onAppend( playlist_add_t *p_add )
 {
     i_items_to_append --;
@@ -152,7 +187,8 @@ void Playtree::onAppend( playlist_add_t *p_add )
             if( !p_item ) return;
             UString *pName = new UString( getIntf(), p_item->input.psz_name );
             node->add( p_add->i_item, UStringPtr( pName ),
-                      false,false, false, p_item );
+                      false,false, false, p_item->i_flags & PLAYLIST_RO_FLAG,
+                      p_item );
         }
     }
     tree_update descr;
@@ -172,7 +208,8 @@ void Playtree::buildNode( playlist_item_t *pNode, VarTree &rTree )
         rTree.add( pNode->pp_children[i]->input.i_id, UStringPtr( pName ),
                      false,
                      m_pPlaylist->status.p_item == pNode->pp_children[i],
-                     false, pNode->pp_children[i] );
+                     false, pNode->pp_children[i]->i_flags & PLAYLIST_RO_FLAG,
+                     pNode->pp_children[i] );
         if( pNode->pp_children[i]->i_children )
         {
             buildNode( pNode->pp_children[i], rTree.back() );
index 294c726..4e39009 100644 (file)
@@ -48,6 +48,9 @@ class Playtree: public VarTree
         /// Function called to notify playlist item  append
         void onAppend( playlist_add_t * );
 
+        /// Function called to notify playlist item delete
+        void onDelete( int );
+
         /// Items waiting to be appended
         int i_items_to_append;