1 /*****************************************************************************
2  * playtree.cpp
3  *****************************************************************************
4  * Copyright (C) 2005 the VideoLAN team
5  * $Id: c0d2fda468e0548ba22d234834edf872d4978884 $
6  *
7  * Authors: Antoine Cellerier <dionoea@videolan.org>
8  *          Clément Stenac <zorglub@videolan.org>
9  *          Erwan Tulou    <erwan10@videolan.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24  *****************************************************************************/
25 
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29 
30 #include <vlc_common.h>
31 
32 #include "playtree.hpp"
33 #include <vlc_playlist.h>
34 #include <vlc_input_item.h>
35 #include <vlc_url.h>
36 #include "../utils/ustring.hpp"
37 
Playtree(intf_thread_t * pIntf)38 Playtree::Playtree( intf_thread_t *pIntf )
39     : VarTree( pIntf ), m_pPlaylist( pl_Get(pIntf) )
40 {
41     getPositionVar().addObserver( this );
42     buildTree();
43 }
44 
~Playtree()45 Playtree::~Playtree()
46 {
47     getPositionVar().delObserver( this );
48 }
49 
delSelected()50 void Playtree::delSelected()
51 {
52     for( Iterator it = m_children.begin(); it != m_children.end(); )
53     {
54         if( it->isSelected() && !it->isReadonly() )
55         {
56             playlist_Lock( m_pPlaylist );
57 
58             playlist_item_t *pItem =
59                 playlist_ItemGetById( m_pPlaylist, it->getId() );
60             if( pItem )
61             {
62                 playlist_NodeDelete( m_pPlaylist, pItem );
63             }
64             playlist_Unlock( m_pPlaylist );
65 
66             it = it->getNextSiblingOrUncle();
67         }
68         else
69         {
70             it = getNextItem( it );
71         }
72     }
73 }
74 
action(VarTree * pElem)75 void Playtree::action( VarTree *pElem )
76 {
77     playlist_Lock( m_pPlaylist );
78 
79     playlist_item_t *pItem =
80         playlist_ItemGetById( m_pPlaylist, pElem->getId() );
81     if( pItem )
82     {
83         playlist_ViewPlay( m_pPlaylist, pItem->p_parent, pItem );
84     }
85 
86     playlist_Unlock( m_pPlaylist );
87 }
88 
onChange()89 void Playtree::onChange()
90 {
91     buildTree();
92     tree_update descr( tree_update::ResetAll, end() );
93     notify( &descr );
94 }
95 
onUpdateItem(int id)96 void Playtree::onUpdateItem( int id )
97 {
98     Iterator it = findById( id );
99     if( it != m_children.end() )
100     {
101         // Update the item
102         playlist_Lock( m_pPlaylist );
103         playlist_item_t *pNode =
104             playlist_ItemGetById( m_pPlaylist, it->getId() );
105         if( !pNode )
106         {
107             playlist_Unlock( m_pPlaylist );
108             return;
109         }
110 
111         UString *pName = getTitle( pNode->p_input );
112         playlist_Unlock( m_pPlaylist );
113 
114         if( *pName != *(it->getString()) )
115         {
116             it->setString( UStringPtr( pName ) );
117 
118             tree_update descr(
119                 tree_update::ItemUpdated, IteratorVisible( it, this ) );
120             notify( &descr );
121         }
122         else
123         {
124             delete pName;
125         }
126 
127     }
128     else
129     {
130         msg_Warn( getIntf(), "cannot find node with id %d", id );
131     }
132 }
133 
onUpdateCurrent(bool b_active)134 void Playtree::onUpdateCurrent( bool b_active )
135 {
136     if( b_active )
137     {
138         playlist_Lock( m_pPlaylist );
139 
140         playlist_item_t* current = playlist_CurrentPlayingItem( m_pPlaylist );
141         if( !current )
142         {
143             playlist_Unlock( m_pPlaylist );
144             return;
145         }
146 
147         Iterator it = findById( current->i_id );
148         if( it != m_children.end() )
149         {
150             it->setPlaying( true );
151 
152             tree_update descr(
153                 tree_update::ItemUpdated, IteratorVisible( it, this ) );
154             notify( &descr );
155         }
156 
157         playlist_Unlock( m_pPlaylist );
158     }
159     else
160     {
161         for( Iterator it = m_children.begin(); it != m_children.end();
162              it = getNextItem( it ) )
163         {
164             if( it->isPlaying() )
165             {
166                 it->setPlaying( false );
167 
168                 tree_update descr(
169                     tree_update::ItemUpdated, IteratorVisible( it, this ) );
170                 notify( &descr );
171                 break;
172             }
173         }
174     }
175 }
176 
onDelete(int i_id)177 void Playtree::onDelete( int i_id )
178 {
179     Iterator it = findById( i_id ) ;
180     if( it != m_children.end() )
181     {
182         VarTree* parent = it->parent();
183         if( parent )
184         {
185             tree_update descr(
186                 tree_update::DeletingItem, IteratorVisible( it, this ) );
187             notify( &descr );
188 
189             parent->removeChild( it );
190             m_allItems.erase( i_id );
191 
192             tree_update descr2(
193                 tree_update::ItemDeleted, end() );
194             notify( &descr2 );
195         }
196     }
197 }
198 
onAppend(int i_id)199 void Playtree::onAppend( int i_id )
200 {
201     playlist_item_t *pItem;
202 
203     playlist_Lock( m_pPlaylist );
204     pItem = playlist_ItemGetById( m_pPlaylist, i_id );
205     if( !pItem || !pItem->p_parent )
206     {
207         playlist_Unlock( m_pPlaylist );
208         return;
209     }
210 
211     Iterator it_node = findById( pItem->p_parent->i_id );
212     if( it_node == m_children.end() )
213     {
214         playlist_Unlock( m_pPlaylist );
215         return;
216     }
217 
218     int pos;
219     for( pos = 0; pos < pItem->p_parent->i_children; pos++ )
220         if( pItem->p_parent->pp_children[pos] == pItem ) break;
221 
222     UString *pName = getTitle( pItem->p_input );
223     playlist_item_t* current = playlist_CurrentPlayingItem( m_pPlaylist );
224 
225     Iterator it = it_node->add(
226         i_id, UStringPtr( pName ), false, pItem == current,
227         false, pItem->i_flags & PLAYLIST_RO_FLAG, pos );
228 
229     m_allItems[i_id] = &*it;
230 
231     playlist_Unlock( m_pPlaylist );
232 
233     tree_update descr( tree_update::ItemInserted,
234                        IteratorVisible( it, this ) );
235     notify( &descr );
236 }
237 
buildNode(playlist_item_t * pNode,VarTree & rTree)238 void Playtree::buildNode( playlist_item_t *pNode, VarTree &rTree )
239 {
240     UString *pName = getTitle( pNode->p_input );
241     Iterator it = rTree.add(
242         pNode->i_id, UStringPtr( pName ), false,
243         playlist_CurrentPlayingItem(m_pPlaylist) == pNode,
244         false, pNode->i_flags & PLAYLIST_RO_FLAG );
245     m_allItems[pNode->i_id] = &*it;
246 
247     for( int i = 0; i < pNode->i_children; i++ )
248     {
249         buildNode( pNode->pp_children[i], *it );
250     }
251 }
252 
buildTree()253 void Playtree::buildTree()
254 {
255     clear();
256     playlist_Lock( m_pPlaylist );
257 
258     for( int i = 0; i < m_pPlaylist->root.i_children; i++ )
259     {
260         buildNode( m_pPlaylist->root.pp_children[i], *this );
261     }
262 
263     playlist_Unlock( m_pPlaylist );
264 }
265 
onUpdateSlider()266 void Playtree::onUpdateSlider()
267 {
268     tree_update descr( tree_update::SliderChanged, end() );
269     notify( &descr );
270 }
271 
insertItems(VarTree & elem,const std::list<std::string> & files,bool start)272 void Playtree::insertItems( VarTree& elem, const std::list<std::string>& files, bool start )
273 {
274     bool first = start;
275     VarTree* p_elem = &elem;
276     playlist_item_t* p_node = NULL;
277     int i_pos = -1;
278 
279     playlist_Lock( m_pPlaylist );
280 
281     if( p_elem == this )
282     {
283         for( Iterator it = m_children.begin(); it != m_children.end(); ++it )
284         {
285             if( it->getId() == m_pPlaylist->p_playing->i_id )
286             {
287                 p_elem = &*it;
288                 break;
289             }
290         }
291     }
292 
293     if( p_elem->getId() == m_pPlaylist->p_playing->i_id )
294     {
295         p_node = m_pPlaylist->p_playing;
296         i_pos = 0;
297         p_elem->setExpanded( true );
298     }
299     else if( p_elem->getId() == m_pPlaylist->p_media_library->i_id )
300     {
301         p_node = m_pPlaylist->p_media_library;
302         i_pos = 0;
303         p_elem->setExpanded( true );
304     }
305     else if( p_elem->size() && p_elem->isExpanded() )
306     {
307         p_node = playlist_ItemGetById( m_pPlaylist, p_elem->getId() );
308         i_pos = 0;
309     }
310     else
311     {
312         p_node = playlist_ItemGetById( m_pPlaylist,
313                                        p_elem->parent()->getId() );
314         i_pos = p_elem->getIndex();
315         i_pos++;
316     }
317 
318     if( !p_node )
319         goto fin;
320 
321     for( std::list<std::string>::const_iterator it = files.begin();
322          it != files.end(); ++it, i_pos++ )
323     {
324         input_item_t *pItem;
325         playlist_item_t *pPlItem;
326 
327         if( strstr( it->c_str(), "://" ) )
328             pItem = input_item_New( it->c_str(), NULL );
329         else
330         {
331             char *psz_uri = vlc_path2uri( it->c_str(), NULL );
332             if( psz_uri == NULL )
333                 continue;
334             pItem = input_item_New( psz_uri, NULL );
335             free( psz_uri );
336         }
337 
338         if( pItem == NULL)
339             continue;
340 
341         pPlItem = playlist_NodeAddInput( m_pPlaylist, pItem, p_node, i_pos );
342 
343         if( likely(pPlItem != NULL) && first )
344         {
345             first = false;
346             playlist_ViewPlay( m_pPlaylist, NULL, pPlItem );
347         }
348     }
349 
350 fin:
351     playlist_Unlock( m_pPlaylist );
352 }
353 
354 
getTitle(input_item_t * pItem)355 UString* Playtree::getTitle( input_item_t *pItem )
356 {
357     char *psz_name = input_item_GetTitleFbName( pItem );
358     UString *pTitle = new UString( getIntf(), psz_name );
359     free( psz_name );
360     return pTitle;
361 }
362 
363 
findById(int id)364 VarTree::Iterator Playtree::findById( int id )
365 {
366     std::map<int,VarTree*>::iterator it = m_allItems.find( id );
367     if( it == m_allItems.end() )
368         return m_children.end();
369     else
370         return it->second->getSelf();
371 }
372