playlist_model.hpp 9.8 KB
Newer Older
Clément Stenac's avatar
Clément Stenac committed
1 2 3
/*****************************************************************************
 * playlist_model.hpp : Model for a playlist tree
 ****************************************************************************
4
 * Copyright (C) 2006-2011 the VideoLAN team
5
 * $Id$
Clément Stenac's avatar
Clément Stenac committed
6 7
 *
 * Authors: Clément Stenac <zorglub@videolan.org>
8
 *          Jakob Leben <jleben@videolan.org>
Clément Stenac's avatar
Clément Stenac committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
 *
 * 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
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#ifndef _PLAYLIST_MODEL_H_
#define _PLAYLIST_MODEL_H_

Christophe Mutricy's avatar
Christophe Mutricy committed
28 29 30 31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
32 33
#include <vlc_input.h>
#include <vlc_playlist.h>
34
#include "vlc_model.hpp"
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
35
#include "playlist_item.hpp"
36

37 38 39
#include <QObject>
#include <QEvent>
#include <QSignalMapper>
40
#include <QMimeData>
41
#include <QAbstractItemModel>
François Cartegnie's avatar
François Cartegnie committed
42
#include <QSortFilterProxyModel>
43
#include <QVariant>
44
#include <QModelIndex>
45 46
#include <QTimer>
#include <QMutex>
François Cartegnie's avatar
François Cartegnie committed
47
#include <QAction>
Clément Stenac's avatar
Clément Stenac committed
48

49
class PLItem;
50
class PLSelector;
51
class PlMimeData;
52

François Cartegnie's avatar
François Cartegnie committed
53 54 55 56 57 58 59 60 61 62
class VLCProxyModel : public QSortFilterProxyModel, public VLCModelSubInterface
{
    Q_OBJECT
public:
    VLCProxyModel( QObject *parent = 0 );
    inline VLCModel *model() const
    {
        return qobject_cast<VLCModel *>( sourceModel() );
    }

63 64
    /* Different Models Handling */

François Cartegnie's avatar
François Cartegnie committed
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
    enum models
    {
        PL_MODEL = 0,
        SQLML_MODEL /* note: keep it last */
    };
    bool switchToModel( models type );
    void setModel( models type, VLCModel *model )
    {
        sourcemodels[ type ] = model;
    }
    QModelIndexList mapListToSource( const QModelIndexList& list );

    /* VLCModelSubInterface Methods */
    virtual void rebuild( playlist_item_t * p = NULL ) { model()->rebuild( p ); }
    virtual void doDelete( QModelIndexList list ) { model()->doDelete( mapListToSource( list ) ); }
    virtual void createNode( QModelIndex a, QString b ) { model()->createNode( mapToSource( a ), b ); }
81
    virtual void removeAll() { model()->removeAll(); }
François Cartegnie's avatar
François Cartegnie committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

    virtual QModelIndex rootIndex() const { return mapFromSource( model()->rootIndex() ); }
    virtual void filter( const QString& text, const QModelIndex & root, bool b_recursive )
    {
        model()->filter( text, mapToSource( root ), b_recursive );
    }

    virtual QModelIndex currentIndex() const { return mapFromSource( model()->currentIndex() ); }
    virtual QModelIndex indexByPLID( const int i_plid, const int c ) const { return mapFromSource( model()->indexByPLID( i_plid, c ) ); }
    virtual QModelIndex indexByInputItemID( const int i_inputitem_id, const int c ) const { return mapFromSource( model()->indexByInputItemID( i_inputitem_id, c ) ); }
    virtual int itemId( const QModelIndex &index, int type ) const { return model()->itemId( mapToSource( index ), type ); }
    virtual bool isTree() const { return model()->isTree();  }
    virtual bool canEdit() const { return model()->canEdit(); }

    virtual QString getURI( const QModelIndex &index ) const { return model()->getURI( mapToSource( index ) ); }
    virtual input_item_t *getInputItem( const QModelIndex &index ) const { return model()->getInputItem( mapToSource( index ) ); }
    virtual QString getTitle( const QModelIndex &index ) const { return model()->getTitle( mapToSource( index ) ); }
99
    virtual bool action( QAction *action, const QModelIndexList &indexes )
François Cartegnie's avatar
François Cartegnie committed
100
    {
101
        return model()->action( action, mapListToSource( indexes ) );
François Cartegnie's avatar
François Cartegnie committed
102
    }
103
    virtual bool isSupportedAction( actions action, const QModelIndex &index ) const { return model()->isSupportedAction( action, mapToSource( index ) ); }
François Cartegnie's avatar
François Cartegnie committed
104 105 106
    /* Indirect slots handlers */
    virtual void activateItem( const QModelIndex &index ) { model()->activateItem( mapToSource( index ) ); }
    virtual void ensureArtRequested( const QModelIndex &index ) { model()->ensureArtRequested( mapToSource( index ) ); }
107 108 109

    /* AbstractItemModel subclassing */
    virtual void sort( const int column, Qt::SortOrder order = Qt::AscendingOrder );
François Cartegnie's avatar
François Cartegnie committed
110 111 112 113 114 115 116 117 118 119 120 121 122 123

    /* Local signals for index conversion */
public slots:
    void currentIndexChanged_IndexConversion( const QModelIndex &index )
    {
        emit currentIndexChanged_Converted( mapFromSource( index ) );
    }

signals:
    void currentIndexChanged_Converted( const QModelIndex & );
private:
    VLCModel * sourcemodels[SQLML_MODEL + 1];
};

124
class PLModel : public VLCModel
Clément Stenac's avatar
Clément Stenac committed
125 126 127 128
{
    Q_OBJECT

public:
129
    PLModel( playlist_t *, intf_thread_t *,
130
             playlist_item_t *, QObject *parent = 0 );
131
    virtual ~PLModel();
Clément Stenac's avatar
Clément Stenac committed
132

133
    /* Qt4 main PLModel */
134 135 136 137 138 139 140 141 142 143 144 145 146
    static PLModel* getPLModel( intf_thread_t *p_intf )
    {
        if(!p_intf->p_sys->pl_model )
        {
            playlist_Lock( THEPL );
            playlist_item_t *p_root = THEPL->p_playing;
            playlist_Unlock( THEPL );
            p_intf->p_sys->pl_model = new PLModel( THEPL, p_intf, p_root, NULL );
        }

        return p_intf->p_sys->pl_model;
    }

147
    /*** QAbstractItemModel subclassing ***/
Jakob Leben's avatar
Jakob Leben committed
148 149

    /* Data structure */
150 151 152 153 154
    virtual QVariant data( const QModelIndex &index, const int role ) const;
    virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const;
    virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
    virtual QModelIndex index( const int r, const int c, const QModelIndex &parent ) const;
    virtual QModelIndex parent( const QModelIndex &index ) const;
Clément Stenac's avatar
Clément Stenac committed
155

Jakob Leben's avatar
Jakob Leben committed
156
    /* Drag and Drop */
157 158 159
    virtual Qt::DropActions supportedDropActions() const;
    virtual QMimeData* mimeData( const QModelIndexList &indexes ) const;
    virtual bool dropMimeData( const QMimeData *data, Qt::DropAction action,
Jakob Leben's avatar
Jakob Leben committed
160
                      int row, int column, const QModelIndex &target );
161
    virtual QStringList mimeTypes() const;
162

163 164 165
    /* Sort */
    virtual void sort( const int column, Qt::SortOrder order = Qt::AscendingOrder );

François Cartegnie's avatar
François Cartegnie committed
166 167 168 169
    /*** VLCModelSubInterface subclassing ***/
    virtual void rebuild( playlist_item_t * p = NULL );
    virtual void doDelete( QModelIndexList selected );
    virtual void createNode( QModelIndex index, QString name );
170
    virtual void removeAll();
Jakob Leben's avatar
Jakob Leben committed
171 172

    /* Lookups */
173
    virtual QModelIndex rootIndex() const;
François Cartegnie's avatar
François Cartegnie committed
174 175 176 177
    virtual void filter( const QString& search_text, const QModelIndex & root, bool b_recursive );
    virtual QModelIndex currentIndex() const;
    virtual QModelIndex indexByPLID( const int i_plid, const int c ) const;
    virtual QModelIndex indexByInputItemID( const int i_inputitem_id, const int c ) const;
178 179
    virtual bool isTree() const;
    virtual bool canEdit() const;
180 181
    virtual bool action( QAction *action, const QModelIndexList &indexes );
    virtual bool isSupportedAction( actions action, const QModelIndex & ) const;
Clément Stenac's avatar
Clément Stenac committed
182

François Cartegnie's avatar
François Cartegnie committed
183
    /* VLCModelSubInterface indirect slots */
184
    virtual void activateItem( const QModelIndex &index );
François Cartegnie's avatar
François Cartegnie committed
185 186 187 188 189 190

protected:
    /* VLCModel subclassing */
    bool isParent( const QModelIndex &index, const QModelIndex &current) const;
    bool isLeaf( const QModelIndex &index ) const;
    PLItem *getItem( const QModelIndex & index ) const;
191

Jakob Leben's avatar
Jakob Leben committed
192
private:
Jakob Leben's avatar
Jakob Leben committed
193
    /* General */
Clément Stenac's avatar
Clément Stenac committed
194 195 196 197
    PLItem *rootItem;

    playlist_t *p_playlist;

198 199 200 201 202 203 204 205 206 207
    /* single row linear inserts agregation */
    void bufferedRowInsert( PLItem *item, PLItem *parent, int pos );
    bool isBufferedForInsert( PLItem *parent, int i_item );
    PLItem *insertBufferRoot;
    int insertbuffer_firstrow;
    int insertbuffer_lastrow;
    QTimer insertBufferCommitTimer;
    QList<PLItem *> insertBuffer;
    QMutex insertBufferMutex;

208 209 210 211
    /* Custom model private methods */
    /* Lookups */
    QModelIndex index( PLItem *, const int c ) const;

Jakob Leben's avatar
Jakob Leben committed
212
    /* Shallow actions (do not affect core playlist) */
213
    void updateTreeItem( PLItem * );
214
    void removeItem ( PLItem * );
215
    void recurseDelete( QList<AbstractPLItem*> children, QModelIndexList *fullList );
Jakob Leben's avatar
Jakob Leben committed
216 217
    void takeItem( PLItem * ); //will not delete item
    void insertChildren( PLItem *node, QList<PLItem*>& items, int i_pos );
Jakob Leben's avatar
Jakob Leben committed
218
    /* ...of which  the following will not update the views */
Jakob Leben's avatar
Jakob Leben committed
219 220
    void updateChildren( PLItem * );
    void updateChildren( playlist_item_t *, PLItem * );
Clément Stenac's avatar
Clément Stenac committed
221

Jakob Leben's avatar
Jakob Leben committed
222
    /* Deep actions (affect core playlist) */
223
    void dropAppendCopy( const PlMimeData * data, PLItem *target, int pos );
224
    void dropMove( const PlMimeData * data, PLItem *target, int new_pos );
Jakob Leben's avatar
Jakob Leben committed
225

226
    /* */
227
    void sort( QModelIndex caller, QModelIndex rootIndex, const int column, Qt::SortOrder order );
Clément Stenac's avatar
Clément Stenac committed
228

Clément Stenac's avatar
Clément Stenac committed
229
    /* Lookups */
François Cartegnie's avatar
François Cartegnie committed
230 231 232
    PLItem *findByPLId( PLItem *, int i_plitemid ) const;
    PLItem *findByInputId( PLItem *, int i_input_itemid ) const;
    PLItem *findInner(PLItem *, int i_id, bool b_isinputid ) const;
233 234 235 236 237 238
    enum pl_nodetype
    {
        ROOTTYPE_CURRENT_PLAYING,
        ROOTTYPE_MEDIA_LIBRARY
    };
    pl_nodetype getPLRootType() const;
Jakob Leben's avatar
Jakob Leben committed
239

240 241 242
    /* */
    QString latestSearch;

Clément Stenac's avatar
Clément Stenac committed
243
private slots:
Jakob Leben's avatar
Jakob Leben committed
244 245
    void processInputItemUpdate( input_item_t *);
    void processInputItemUpdate( input_thread_t* p_input );
François Cartegnie's avatar
François Cartegnie committed
246 247
    void processItemRemoval( int i_pl_itemid );
    void processItemAppend( int i_pl_itemid, int i_pl_itemidparent );
248
    void commitBufferedRowInserts();
249
    void activateItem( playlist_item_t *p_item );
Clément Stenac's avatar
Clément Stenac committed
250 251
};

252
class PlMimeData : public QMimeData
253
{
François Cartegnie's avatar
François Cartegnie committed
254
    Q_OBJECT
255

256
public:
257
    PlMimeData() {}
258 259
    ~PlMimeData();
    void appendItem( input_item_t *p_item );
260 261
    QList<input_item_t*> inputItems() const;
    QStringList formats () const;
262 263 264 265 266 267

private:
    QList<input_item_t*> _inputItems;
    QMimeData *_mimeData;
};

Clément Stenac's avatar
Clément Stenac committed
268
#endif