playtree.cpp 9.66 KB
Newer Older
1 2 3
/*****************************************************************************
 * playtree.cpp
 *****************************************************************************
Clément Stenac's avatar
Clément Stenac committed
4
 * Copyright (C) 2005 the VideoLAN team
5
 * $Id$
6 7
 *
 * Authors: Antoine Cellerier <dionoea@videolan.org>
Clément Stenac's avatar
Clément Stenac committed
8
 *          Clément Stenac <zorglub@videolan.org>
9
 *          Erwan Tulou    <erwan10@videolan.org>
10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
23
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
24 25
 *****************************************************************************/

26 27 28 29
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

30
#include <vlc_common.h>
31 32

#include "playtree.hpp"
Clément Stenac's avatar
Clément Stenac committed
33
#include <vlc_playlist.h>
34
#include <vlc_input_item.h>
35
#include <vlc_url.h>
36 37
#include "../utils/ustring.hpp"

38 39
Playtree::Playtree( intf_thread_t *pIntf )
    : VarTree( pIntf ), m_pPlaylist( pIntf->p_sys->p_playlist )
40
{
41
    getPositionVar().addObserver( this );
42 43 44 45 46
    buildTree();
}

Playtree::~Playtree()
{
47
    getPositionVar().delObserver( this );
48 49 50 51
}

void Playtree::delSelected()
{
52
    for( Iterator it = m_children.begin(); it != m_children.end(); )
53
    {
Erwan Tulou's avatar
Erwan Tulou committed
54
        if( it->isSelected() && !it->isReadonly() )
55
        {
56 57 58 59 60
            playlist_Lock( m_pPlaylist );

            playlist_item_t *pItem =
                playlist_ItemGetById( m_pPlaylist, it->getId() );
            if( pItem )
61
            {
62 63 64 65 66 67 68 69 70
                if( pItem->i_children == -1 )
                {
                    playlist_DeleteFromInput( m_pPlaylist, pItem->p_input,
                                              pl_Locked );
                }
                else
                {
                    playlist_NodeDelete( m_pPlaylist, pItem, true, false );
                }
71
            }
72 73 74
            playlist_Unlock( m_pPlaylist );

            it = it->getNextSiblingOrUncle();
75
        }
76 77
        else
        {
78
            it = getNextItem( it );
79
        }
80
    }
81 82
}

83
void Playtree::action( VarTree *pElem )
84
{
85
    playlist_Lock( m_pPlaylist );
86

87 88 89
    playlist_item_t *pItem =
        playlist_ItemGetById( m_pPlaylist, pElem->getId() );
    if( pItem )
90
    {
91 92
        playlist_Control( m_pPlaylist, PLAYLIST_VIEWPLAY,
                          pl_Locked, pItem->p_parent, pItem );
93 94
    }

95
    playlist_Unlock( m_pPlaylist );
96 97 98 99 100
}

void Playtree::onChange()
{
    buildTree();
101
    tree_update descr( tree_update::ResetAll, end() );
Clément Stenac's avatar
Clément Stenac committed
102
    notify( &descr );
103 104
}

Clément Stenac's avatar
Clément Stenac committed
105
void Playtree::onUpdateItem( int id )
106
{
107
    Iterator it = findById( id );
108
    if( it != m_children.end() )
109
    {
110
        // Update the item
111 112 113 114 115 116 117 118 119
        playlist_Lock( m_pPlaylist );
        playlist_item_t *pNode =
            playlist_ItemGetById( m_pPlaylist, it->getId() );
        if( !pNode )
        {
            playlist_Unlock( m_pPlaylist );
            return;
        }

120
        UString *pName = getTitle( pNode->p_input );
121
        playlist_Unlock( m_pPlaylist );
Erwan Tulou's avatar
Erwan Tulou committed
122

123 124 125 126 127 128 129 130
        if( *pName != *(it->getString()) )
        {
            it->setString( UStringPtr( pName ) );

            tree_update descr(
                tree_update::ItemUpdated, IteratorVisible( it, this ) );
            notify( &descr );
        }
Erwan Tulou's avatar
Erwan Tulou committed
131 132 133 134 135
        else
        {
            delete pName;
        }

136 137 138
    }
    else
    {
139
        msg_Warn( getIntf(), "cannot find node with id %d", id );
140
    }
Clément Stenac's avatar
Clément Stenac committed
141 142
}

143
void Playtree::onUpdateCurrent( bool b_active )
144
{
Erwan Tulou's avatar
Erwan Tulou committed
145
    if( b_active )
146 147
    {
        playlist_Lock( m_pPlaylist );
148

149 150 151 152 153 154 155 156
        playlist_item_t* current = playlist_CurrentPlayingItem( m_pPlaylist );
        if( !current )
        {
            playlist_Unlock( m_pPlaylist );
            return;
        }

        Iterator it = findById( current->i_id );
157 158
        if( it != m_children.end() )
        {
Erwan Tulou's avatar
Erwan Tulou committed
159
            it->setPlaying( true );
160

161 162 163 164 165
            tree_update descr(
                tree_update::ItemUpdated, IteratorVisible( it, this ) );
            notify( &descr );
        }

166
        playlist_Unlock( m_pPlaylist );
167 168 169 170 171 172 173 174 175
    }
    else
    {
        for( Iterator it = m_children.begin(); it != m_children.end();
             it = getNextItem( it ) )
        {
            if( it->isPlaying() )
            {
                it->setPlaying( false );
176

177 178 179 180 181 182
                tree_update descr(
                    tree_update::ItemUpdated, IteratorVisible( it, this ) );
                notify( &descr );
                break;
            }
        }
Erwan Tulou's avatar
Erwan Tulou committed
183
    }
184 185
}

186 187
void Playtree::onDelete( int i_id )
{
188 189
    Iterator it = findById( i_id ) ;
    if( it != m_children.end() )
190
    {
191 192 193 194 195 196
        VarTree* parent = it->parent();
        if( parent )
        {
            tree_update descr(
                tree_update::DeletingItem, IteratorVisible( it, this ) );
            notify( &descr );
197

198 199
            parent->removeChild( it );
            m_allItems.erase( i_id );
200

201 202 203 204
            tree_update descr2(
                tree_update::ItemDeleted, end() );
            notify( &descr2 );
        }
205 206 207
    }
}

Clément Stenac's avatar
Clément Stenac committed
208 209
void Playtree::onAppend( playlist_add_t *p_add )
{
210 211
    Iterator it_node = findById( p_add->i_node );
    if( it_node != m_children.end() )
Clément Stenac's avatar
Clément Stenac committed
212
    {
213
        playlist_Lock( m_pPlaylist );
214
        playlist_item_t *pItem =
Erwan Tulou's avatar
Erwan Tulou committed
215
            playlist_ItemGetById( m_pPlaylist, p_add->i_item );
216
        if( !pItem )
Clément Stenac's avatar
Clément Stenac committed
217
        {
218
            playlist_Unlock( m_pPlaylist );
219
            return;
Clément Stenac's avatar
Clément Stenac committed
220
        }
Erwan Tulou's avatar
Erwan Tulou committed
221

222 223 224 225
        int pos;
        for( pos = 0; pos < pItem->p_parent->i_children; pos++ )
            if( pItem->p_parent->pp_children[pos] == pItem ) break;

226
        UString *pName = getTitle( pItem->p_input );
227 228 229 230 231 232 233 234
        playlist_item_t* current = playlist_CurrentPlayingItem( m_pPlaylist );

        Iterator it = it_node->add(
            p_add->i_item, UStringPtr( pName ), false, pItem == current,
            false, pItem->i_flags & PLAYLIST_RO_FLAG, pos );

        m_allItems[pItem->i_id] = &*it;

235
        playlist_Unlock( m_pPlaylist );
Erwan Tulou's avatar
Erwan Tulou committed
236

237 238 239
        tree_update descr(
            tree_update::ItemInserted,
            IteratorVisible( it, this ) );
Erwan Tulou's avatar
Erwan Tulou committed
240
        notify( &descr );
Clément Stenac's avatar
Clément Stenac committed
241
    }
242 243 244 245
}

void Playtree::buildNode( playlist_item_t *pNode, VarTree &rTree )
{
246
    UString *pName = getTitle( pNode->p_input );
247 248 249 250 251 252
    Iterator it = rTree.add(
        pNode->i_id, UStringPtr( pName ), false,
        playlist_CurrentPlayingItem(m_pPlaylist) == pNode,
        false, pNode->i_flags & PLAYLIST_RO_FLAG );
    m_allItems[pNode->i_id] = &*it;

253 254
    for( int i = 0; i < pNode->i_children; i++ )
    {
255
        buildNode( pNode->pp_children[i], *it );
256 257 258 259 260 261
    }
}

void Playtree::buildTree()
{
    clear();
262
    playlist_Lock( m_pPlaylist );
263

264 265 266 267
    for( int i = 0; i < m_pPlaylist->p_root->i_children; i++ )
    {
        buildNode( m_pPlaylist->p_root->pp_children[i], *this );
    }
268

269 270
    playlist_Unlock( m_pPlaylist );
}
271

272 273 274 275 276
void Playtree::onUpdateSlider()
{
    tree_update descr( tree_update::SliderChanged, end() );
    notify( &descr );
}
277

278
void Playtree::insertItems( VarTree& elem, const std::list<std::string>& files, bool start )
279 280 281 282 283 284 285
{
    bool first = true;
    VarTree* p_elem = &elem;
    playlist_item_t* p_node = NULL;
    int i_pos = -1;

    playlist_Lock( m_pPlaylist );
286

287 288 289 290
    if( p_elem == this )
    {
        for( Iterator it = m_children.begin(); it != m_children.end(); ++it )
        {
291
            if( it->getId() == m_pPlaylist->p_playing->i_id )
292 293 294 295 296 297 298
            {
                p_elem = &*it;
                break;
            }
        }
    }

299
    if( p_elem->getId() == m_pPlaylist->p_playing->i_id )
300
    {
301
        p_node = m_pPlaylist->p_playing;
302
        i_pos = 0;
303
        p_elem->setExpanded( true );
304
    }
305
    else if( p_elem->getId() == m_pPlaylist->p_media_library->i_id )
306
    {
307
        p_node = m_pPlaylist->p_media_library;
308
        i_pos = 0;
309
        p_elem->setExpanded( true );
310
    }
Erwan Tulou's avatar
Erwan Tulou committed
311
    else if( p_elem->size() && p_elem->isExpanded() )
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
    {
        p_node = playlist_ItemGetById( m_pPlaylist, p_elem->getId() );
        i_pos = 0;
    }
    else
    {
        p_node = playlist_ItemGetById( m_pPlaylist,
                                       p_elem->parent()->getId() );
        i_pos = p_elem->getIndex();
        i_pos++;
    }

    if( !p_node )
        goto fin;

327
    for( std::list<std::string>::const_iterator it = files.begin();
328 329
         it != files.end(); ++it, i_pos++, first = false )
    {
330
        input_item_t *pItem;
331

332 333 334
        if( strstr( it->c_str(), "://" ) )
            pItem = input_item_New( it->c_str(), NULL );
        else
335
        {
336 337 338 339 340
            char *psz_uri = vlc_path2uri( it->c_str(), NULL );
            if( psz_uri == NULL )
                continue;
            pItem = input_item_New( psz_uri, NULL );
            free( psz_uri );
341
        }
342 343 344 345 346 347 348 349 350 351

        if( pItem == NULL)
            continue;

        int i_mode = PLAYLIST_APPEND;
        if( first && start )
            i_mode |= PLAYLIST_GO;

        playlist_NodeAddInput( m_pPlaylist, pItem, p_node,
                               i_mode, i_pos, pl_Locked );
352 353 354
    }

fin:
355
    playlist_Unlock( m_pPlaylist );
356
}
357

358 359 360

UString* Playtree::getTitle( input_item_t *pItem )
{
Erwan Tulou's avatar
Erwan Tulou committed
361
    char *psz_name = input_item_GetTitleFbName( pItem );
362 363 364 365 366 367
    UString *pTitle = new UString( getIntf(), psz_name );
    free( psz_name );
    return pTitle;
}


368 369
VarTree::Iterator Playtree::findById( int id )
{
370
    std::map<int,VarTree*>::iterator it = m_allItems.find( id );
371 372 373 374 375
    if( it == m_allItems.end() )
        return m_children.end();
    else
        return it->second->getSelf();
}