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