Commit ce837438 authored by Francois Cartegnie's avatar Francois Cartegnie

Qt: Rework Models.

- Separate common methods into interface, allowing multiple
inheritance architecture (to use any implemented AbstractModel)
- Code factorization between PL/ML models (and PL/ML Items)
- Use proxy model for views and redirection to the PL/ML models.
Fixes filtering and also really make use of the current model (only the
PL Model was really used before, models were half switched).
- stop storing/serializing selection indexes
- ML Missing locks and bug fixes
- Move ML callback into event loop
- ML Items leaks fixes
- Code factorization
- Dead code removal
parent 80e95174
...@@ -91,11 +91,9 @@ static int compareMeta( ml_media_t *a, ml_media_t *b, ml_select_e meta ) ...@@ -91,11 +91,9 @@ static int compareMeta( ml_media_t *a, ml_media_t *b, ml_select_e meta )
} }
MLItem::MLItem( const MLModel *p_model, MLItem::MLItem( intf_thread_t* _p_intf,
intf_thread_t* _p_intf,
ml_media_t *p_media, ml_media_t *p_media,
MLItem *p_parent ) MLItem *p_parent )
: p_intf( _p_intf ), model( p_model )
{ {
parentItem = p_parent; parentItem = p_parent;
if( p_media ) if( p_media )
...@@ -119,18 +117,9 @@ AbstractPLItem* MLItem::child( int row ) const ...@@ -119,18 +117,9 @@ AbstractPLItem* MLItem::child( int row ) const
else return children.at( row ); else return children.at( row );
} }
void MLItem::delChild( int row )
{
if( !childCount() ) return; // assert ?
AbstractPLItem *item =
children.takeAt( ( row!=-1 ) ? row : ( children.count()-1 ) );
assert( item );
delete item;
}
input_item_t* MLItem::inputItem() input_item_t* MLItem::inputItem()
{ {
return ml_CreateInputItem( p_ml, id() ); return ml_CreateInputItem( p_ml, id( MLMEDIA_ID ) );
} }
/** /**
...@@ -139,13 +128,12 @@ input_item_t* MLItem::inputItem() ...@@ -139,13 +128,12 @@ input_item_t* MLItem::inputItem()
* @return The QVariant may be formed of a int, QString * @return The QVariant may be formed of a int, QString
* Use toString() to print it on the screen, except for pixmaps * Use toString() to print it on the screen, except for pixmaps
*/ */
QVariant MLItem::data( int column ) const QVariant MLItem::data( ml_select_e columntype ) const
{ {
ml_select_e type = model->columnType( column );
ml_person_t *p_people = NULL, *p_person = NULL; ml_person_t *p_people = NULL, *p_person = NULL;
QString qsz_return; QString qsz_return;
#define sreturn(a) if(media->a) return qfu(media->a); break #define sreturn(a) if(media->a) return qfu(media->a); break
switch( type ) switch( columntype )
{ {
case ML_ALBUM: sreturn( psz_album ); case ML_ALBUM: sreturn( psz_album );
case ML_ALBUM_ID: return media->i_album_id; case ML_ALBUM_ID: return media->i_album_id;
...@@ -166,7 +154,10 @@ QVariant MLItem::data( int column ) const ...@@ -166,7 +154,10 @@ QVariant MLItem::data( int column ) const
break; break;
case ML_COVER: sreturn( psz_cover ); case ML_COVER: sreturn( psz_cover );
case ML_DURATION: case ML_DURATION:
return QTime().addSecs( media->i_duration/1000000 ).toString( "HH:mm:ss" ); if ( media->i_duration )
return QTime().addSecs( media->i_duration/1000000 ).toString( "HH:mm:ss" );
else
return QString();
case ML_EXTRA: sreturn( psz_extra ); case ML_EXTRA: sreturn( psz_extra );
case ML_GENRE: sreturn( psz_genre ); case ML_GENRE: sreturn( psz_genre );
case ML_ID: return media->i_id; case ML_ID: return media->i_id;
...@@ -194,9 +185,11 @@ QVariant MLItem::data( int column ) const ...@@ -194,9 +185,11 @@ QVariant MLItem::data( int column ) const
return qsz_return; return qsz_return;
else else
{ {
vlc_mutex_lock( &media->lock ); QUrl uri = getURI();
QFileInfo p_file = QFileInfo( qfu( media->psz_uri ) ); if ( uri.scheme() != "file" )
vlc_mutex_unlock( &media->lock ); return QUrl::fromPercentEncoding( getURI().toString().toUtf8() );
QFileInfo p_file( uri.toLocalFile() );
return p_file.fileName().isEmpty() ? p_file.absoluteFilePath() return p_file.fileName().isEmpty() ? p_file.absoluteFilePath()
: p_file.fileName(); : p_file.fileName();
} }
...@@ -249,20 +242,21 @@ bool MLItem::setData( ml_select_e meta, const QVariant &data ) ...@@ -249,20 +242,21 @@ bool MLItem::setData( ml_select_e meta, const QVariant &data )
case ML_ARTIST: ml_DeletePersonTypeFromMedia( media, ML_PERSON_ARTIST ); case ML_ARTIST: ml_DeletePersonTypeFromMedia( media, ML_PERSON_ARTIST );
ml_CreateAppendPersonAdv( &media->p_people, ml_CreateAppendPersonAdv( &media->p_people,
ML_PERSON_ARTIST, (char*)qtu(data.toString()), 0 ); ML_PERSON_ARTIST, (char*)qtu(data.toString()), 0 );
return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id(), return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id( MLMEDIA_ID ),
ML_PEOPLE, ML_PERSON_ARTIST, qtu( data.toString() ) ) == VLC_SUCCESS; ML_PEOPLE, ML_PERSON_ARTIST, qtu( data.toString() ) ) == VLC_SUCCESS;
case ML_EXTRA: setmeta( psz_extra ); case ML_EXTRA: setmeta( psz_extra );
case ML_GENRE: setmeta( psz_genre ); case ML_GENRE: setmeta( psz_genre );
case ML_ORIGINAL_TITLE: setmeta( psz_orig_title ); case ML_ORIGINAL_TITLE: setmeta( psz_orig_title );
case ML_TITLE: setmeta( psz_title ); case ML_TITLE: setmeta( psz_title );
update: update:
return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id(), Q_ASSERT( qtu( data.toString() ) );
return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id( MLMEDIA_ID ),
meta, qtu( data.toString() ) ) == VLC_SUCCESS; meta, qtu( data.toString() ) ) == VLC_SUCCESS;
/* Modifiable integers */ /* Modifiable integers */
case ML_TRACK_NUMBER: case ML_TRACK_NUMBER:
case ML_YEAR: case ML_YEAR:
return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id(), return ml_UpdateSimple( p_ml, ML_MEDIA, NULL, id( MLMEDIA_ID ),
meta, data.toInt() ) == VLC_SUCCESS; meta, data.toInt() ) == VLC_SUCCESS;
// TODO case ML_VOTE: // TODO case ML_VOTE:
...@@ -274,9 +268,19 @@ update: ...@@ -274,9 +268,19 @@ update:
# undef setmeta # undef setmeta
} }
int MLItem::id() const int MLItem::id( int type )
{ {
return media->i_id; switch( type )
{
case INPUTITEM_ID:
return inputItem()->i_id;
case MLMEDIA_ID:
return media->i_id;
default:
case PLAYLIST_ID:
assert( NULL );
return -1;
}
} }
ml_media_t* MLItem::getMedia() const ml_media_t* MLItem::getMedia() const
...@@ -284,19 +288,28 @@ ml_media_t* MLItem::getMedia() const ...@@ -284,19 +288,28 @@ ml_media_t* MLItem::getMedia() const
return media; return media;
} }
QUrl MLItem::getUri() const QUrl MLItem::getURI() const
{ {
QString uri; QString uri;
vlc_mutex_lock( &media->lock ); vlc_mutex_lock( &media->lock );
uri = QString( media->psz_uri ); uri = qfu( media->psz_uri );
vlc_mutex_unlock( &media->lock ); vlc_mutex_unlock( &media->lock );
if ( uri.isEmpty() ) return QUrl(); // This should be rootItem if ( uri.isEmpty() ) return QUrl(); // This should be rootItem
QUrl url( uri ); QUrl url = QUrl::fromEncoded( uri.toUtf8(), QUrl::TolerantMode );
if ( url.scheme().isEmpty() ) url.setScheme( "file" ); if ( url.scheme().isEmpty() ) url.setScheme( "file" );
return url; return url;
} }
QString MLItem::getTitle() const
{
QString title;
vlc_mutex_lock( &media->lock );
title = QString( media->psz_title );
vlc_mutex_unlock( &media->lock );
return title;
}
bool MLItem::operator<( MLItem* item ) bool MLItem::operator<( MLItem* item )
{ {
int ret = compareMeta( getMedia(), item->getMedia(), ML_ALBUM ); int ret = compareMeta( getMedia(), item->getMedia(), ML_ALBUM );
......
...@@ -49,28 +49,26 @@ class MLItem : public AbstractPLItem ...@@ -49,28 +49,26 @@ class MLItem : public AbstractPLItem
friend class MLModel; friend class MLModel;
public: public:
MLItem( const MLModel *p_model, intf_thread_t *_p_intf, MLItem( intf_thread_t *_p_intf,
ml_media_t *p_media, MLItem *p_parent ); ml_media_t *p_media, MLItem *p_parent );
virtual ~MLItem(); virtual ~MLItem();
bool operator<( MLItem* item ); bool operator<( MLItem* item );
private: private:
/* AbstractPLItem */ /* AbstractPLItem */
int id() const; int id( int type );
input_item_t *inputItem(); input_item_t *inputItem();
AbstractPLItem* child( int row ) const; AbstractPLItem* child( int row ) const;
virtual QUrl getURI() const;
virtual QString getTitle() const;
/* Local */ /* Local */
void delChild( int row ); QVariant data( ml_select_e meta ) const;
QVariant data( int column ) const;
bool setData( ml_select_e meta, const QVariant &data ); bool setData( ml_select_e meta, const QVariant &data );
// Media structure connections // Media structure connections
ml_media_t* getMedia() const; ml_media_t* getMedia() const;
QUrl getUri() const;
ml_media_t* media; ml_media_t* media;
intf_thread_t* p_intf;
const MLModel *model;
media_library_t* p_ml; media_library_t* p_ml;
}; };
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <QUrl> #include <QUrl>
#include <QMenu> #include <QMenu>
#include <QMimeData> #include <QMimeData>
#include <QApplication>
#include "ml_item.hpp" #include "ml_item.hpp"
#include "ml_model.hpp" #include "ml_model.hpp"
#include "dialogs/playlist.hpp" #include "dialogs/playlist.hpp"
...@@ -54,6 +55,14 @@ static int mediaUpdated( vlc_object_t *p_this, char const *psz_var, ...@@ -54,6 +55,14 @@ static int mediaUpdated( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, vlc_value_t oldval, vlc_value_t newval,
void *data ); void *data );
/* Register ML Events */
const QEvent::Type MLEvent::MediaAdded_Type =
(QEvent::Type)QEvent::registerEventType();
const QEvent::Type MLEvent::MediaRemoved_Type =
(QEvent::Type)QEvent::registerEventType();
const QEvent::Type MLEvent::MediaUpdated_Type =
(QEvent::Type)QEvent::registerEventType();
/** /**
* @brief Definition of the result item model for the result tree * @brief Definition of the result item model for the result tree
* @param parent the parent Qt object * @param parent the parent Qt object
...@@ -65,6 +74,7 @@ MLModel::MLModel( intf_thread_t* _p_intf, QObject *parent ) ...@@ -65,6 +74,7 @@ MLModel::MLModel( intf_thread_t* _p_intf, QObject *parent )
if ( !p_ml ) return; if ( !p_ml ) return;
vlc_array_t *p_result_array = vlc_array_new(); vlc_array_t *p_result_array = vlc_array_new();
if ( p_result_array ) if ( p_result_array )
{ {
ml_Find( p_ml, p_result_array, ML_MEDIA ); ml_Find( p_ml, p_result_array, ML_MEDIA );
...@@ -89,16 +99,35 @@ MLModel::~MLModel() ...@@ -89,16 +99,35 @@ MLModel::~MLModel()
var_DelCallback( p_ml, "media-added", mediaAdded, this ); var_DelCallback( p_ml, "media-added", mediaAdded, this );
} }
void MLModel::clear() void MLModel::clearPlaylist()
{ {
vlc_array_t* p_where = vlc_array_new();
if ( !p_where ) return;
int rows = rowCount(); int rows = rowCount();
if( rows > 0 ) if( rows > 0 )
{ {
beginRemoveRows( createIndex( 0, 0 ), 0, rows-1 ); beginRemoveRows( createIndex( 0, 0 ), 0, rows-1 );
QList< MLItem* >::iterator it = items.begin();
ml_element_t p_find[ items.count() ];
int i = 0;
while( it != items.end() )
{
p_find[i].criteria = ML_ID;
p_find[i].value.i = (*it)->id( MLMEDIA_ID );
vlc_array_append( p_where, & p_find[i++] );
delete *it;
it++;
}
ml_Delete( p_ml, p_where );
items.clear(); items.clear();
endRemoveRows(); endRemoveRows();
emit layoutChanged();
} }
vlc_array_destroy( p_where );
reset();
} }
QModelIndex MLModel::index( int row, int column, QModelIndex MLModel::index( int row, int column,
...@@ -118,6 +147,17 @@ QModelIndex MLModel::parent(const QModelIndex & ) const ...@@ -118,6 +147,17 @@ QModelIndex MLModel::parent(const QModelIndex & ) const
return QModelIndex(); return QModelIndex();
} }
void MLModel::filter( const QString& search_text, const QModelIndex & root, bool b_recursive )
{
Q_UNUSED( search_text ); Q_UNUSED( root ); Q_UNUSED( b_recursive );
/* FIXME */
}
void MLModel::sort( const int column, Qt::SortOrder order )
{
Q_UNUSED( column ); Q_UNUSED( order );
}
/** /**
* @brief Return the index of currently playing item * @brief Return the index of currently playing item
*/ */
...@@ -126,16 +166,33 @@ QModelIndex MLModel::currentIndex() const ...@@ -126,16 +166,33 @@ QModelIndex MLModel::currentIndex() const
input_thread_t *p_input_thread = THEMIM->getInput(); input_thread_t *p_input_thread = THEMIM->getInput();
if( !p_input_thread ) return QModelIndex(); if( !p_input_thread ) return QModelIndex();
/*TODO: O(n) not good */
input_item_t* p_iitem = input_GetItem( p_input_thread ); input_item_t* p_iitem = input_GetItem( p_input_thread );
int i = 0;
foreach( MLItem* item, items ) foreach( MLItem* item, items )
{ {
if( !QString::compare( item->getUri().toString(), if ( item->inputItem() == p_iitem )
QString::fromAscii( p_iitem->psz_uri ) ) ) return index( i, 0 );
return index( items.indexOf( item ), 0 ); i++;
} }
return QModelIndex(); return QModelIndex();
} }
QModelIndex MLModel::indexByPLID( const int i_plid, const int c ) const
{
Q_UNUSED( i_plid ); Q_UNUSED( c );
return QModelIndex(); /* FIXME ? */
}
QModelIndex MLModel::indexByInputItemID( const int i_inputitem_id, const int c ) const
{
Q_UNUSED( c );
foreach( MLItem* item, items )
if ( item->id( INPUTITEM_ID ) == i_inputitem_id )
{
return index( items.indexOf( item ), 0 );
}
return QModelIndex();
}
/** /**
* @brief This returns the type of data shown in the specified column * @brief This returns the type of data shown in the specified column
* @param column must be valid * @param column must be valid
...@@ -147,15 +204,6 @@ ml_select_e MLModel::columnType( int logicalindex ) const ...@@ -147,15 +204,6 @@ ml_select_e MLModel::columnType( int logicalindex ) const
return meta_to_mlmeta( columnToMeta( logicalindex ) ); return meta_to_mlmeta( columnToMeta( logicalindex ) );
} }
QVariant MLModel::headerData( int section, Qt::Orientation orientation,
int role ) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return QVariant( qfu( psz_column_title( columnToMeta( section ) ) ) );
else
return QVariant();
}
Qt::ItemFlags MLModel::flags(const QModelIndex &index) const Qt::ItemFlags MLModel::flags(const QModelIndex &index) const
{ {
if( !index.isValid() ) if( !index.isValid() )
...@@ -214,8 +262,8 @@ QMimeData* MLModel::mimeData( const QModelIndexList &indexes ) const ...@@ -214,8 +262,8 @@ QMimeData* MLModel::mimeData( const QModelIndexList &indexes ) const
if( rows.contains( idx.row() ) ) if( rows.contains( idx.row() ) )
continue; continue;
rows.append( idx.row() ); rows.append( idx.row() );
MLItem* item = static_cast<MLItem*>( idx.internalPointer() ); AbstractPLItem* item = static_cast<AbstractPLItem*>( idx.internalPointer() );
urls.append( item->getUri() ); urls.append( item->getURI() );
} }
QMimeData *data = new QMimeData; QMimeData *data = new QMimeData;
data->setUrls( urls ); data->setUrls( urls );
...@@ -229,41 +277,34 @@ int MLModel::rowCount( const QModelIndex & parent ) const ...@@ -229,41 +277,34 @@ int MLModel::rowCount( const QModelIndex & parent ) const
return 0; return 0;
} }
void MLModel::remove( MLItem *item ) void MLModel::rebuild( playlist_item_t *p )
{ {
int row = items.indexOf( item ); Q_UNUSED( p );
remove( createIndex( row, 0 ) ); emit layoutChanged();
} }
void MLModel::doDelete( QModelIndexList list ) void MLModel::doDelete( QModelIndexList list )
{ {
for (int i = 0; i < list.count(); ++i) for (int i = 0; i < list.count(); ++i)
{ {
int id = itemId( list.at(i) ); const QModelIndex &index = list.at( i );
if ( !index.isValid() ) break;
int id = itemId( list.at(i), MLMEDIA_ID );
ml_DeleteSimple( p_ml, id ); ml_DeleteSimple( p_ml, id );
/* row will be removed by the lib callback */
} }
} }
void MLModel::remove( QModelIndex idx ) bool MLModel::removeRows( int row, int count, const QModelIndex &parent )
{ {
if( !idx.isValid() ) /* !warn probably not a good idea to expose this as public method */
return; if ( row < 0 || count < 0 ) return false;
else beginRemoveRows( parent, row, row );
{ MLItem *item = items.takeAt( row );
beginRemoveRows( createIndex( 0, 0 ), idx.row(), idx.row() ); assert( item );
items.removeAt( idx.row() ); if ( likely( item ) ) delete item;
endRemoveRows(); endRemoveRows();
} return true;
}
int MLModel::itemId( const QModelIndex &index ) const
{
return getItem( index )->id();
}
input_item_t * MLModel::getInputItem( const QModelIndex &index ) const
{
return getItem( index )->inputItem();
} }
QVariant MLModel::data( const QModelIndex &index, const int role ) const QVariant MLModel::data( const QModelIndex &index, const int role ) const
...@@ -274,13 +315,25 @@ QVariant MLModel::data( const QModelIndex &index, const int role ) const ...@@ -274,13 +315,25 @@ QVariant MLModel::data( const QModelIndex &index, const int role ) const
{ {
MLItem *it = static_cast<MLItem*>( index.internalPointer() ); MLItem *it = static_cast<MLItem*>( index.internalPointer() );
if( !it ) return QVariant(); if( !it ) return QVariant();
QVariant tmp = it->data( index.column() ); QVariant tmp = it->data( columnType( index.column() ) );
return tmp; return tmp;
} }
else if( role == Qt::DecorationRole && index.column() == 0 )
{
/*
FIXME: (see ml_type_e)
media->type uses flags for media type information
*/
return QVariant( icons[ getInputItem(index)->i_type ] );
}
else if( role == IsLeafNodeRole ) else if( role == IsLeafNodeRole )
return QVariant( true ); return isLeaf( index );
else if( role == IsCurrentsParentNodeRole ) else if( role == IsCurrentsParentNodeRole )
return QVariant( false ); return isParent( index, currentIndex() );
else if( role == IsCurrentRole )
{
return QVariant( isCurrent( index ) );
}
} }
return QVariant(); return QVariant();
} }
...@@ -299,12 +352,9 @@ bool MLModel::setData( const QModelIndex &idx, const QVariant &value, ...@@ -299,12 +352,9 @@ bool MLModel::setData( const QModelIndex &idx, const QVariant &value,
* @brief Insert a media to the model in a given row * @brief Insert a media to the model in a given row
* @param p_media the media to append * @param p_media the media to append
* @param row the future row for this media, -1 to append at the end * @param row the future row for this media, -1 to append at the end
* @param bSignal signal Qt that the model has been modified,
* should NOT be used by the user
* @return a VLC error code * @return a VLC error code
*/ */
int MLModel::insertMedia( ml_media_t *p_media, int row, int MLModel::insertMedia( ml_media_t *p_media, int row )
bool bSignal )
{ {
// Some checks // Some checks
if( !p_media || row < -1 || row > rowCount() ) if( !p_media || row < -1 || row > rowCount() )
...@@ -313,105 +363,19 @@ int MLModel::insertMedia( ml_media_t *p_media, int row, ...@@ -313,105 +363,19 @@ int MLModel::insertMedia( ml_media_t *p_media, int row,
if( row == -1 ) if( row == -1 )
row = rowCount(); row = rowCount();
if( bSignal )
beginInsertRows( createIndex( -1, -1 ), row, row );
// Create and insert the item // Create and insert the item
MLItem *item = new MLItem( this, p_intf, p_media, NULL ); MLItem *item = new MLItem( p_intf, p_media, NULL );
items.append( item ); items.append( item );
if( bSignal )
endInsertRows();
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/**
* @brief Append a media to the model
* @param p_media the media to append
* @return see insertMedia
* @note Always signals. Do not use in a loop.
*/
int MLModel::appendMedia( ml_media_t *p_media )
{
return insertMedia( p_media, -1, true );
}
/**
* @brief Insert all medias from an array to the model
* @param p_media_array the medias to append
* @return see insertMedia
* @note if bSignal==true, then it signals only once
*/
int MLModel::insertMediaArray( vlc_array_t *p_media_array,
int row, bool bSignal )
{
int i_ok = VLC_SUCCESS;
int count = vlc_array_count( p_media_array );
if( !count )
return i_ok;
if( row == -1 )
row = rowCount();
// Signal Qt that we will insert rows
if( bSignal )
beginInsertRows( createIndex( -1, -1 ), row, row + count-1 );
// Loop
for( int i = 0; i < count; ++i )
{
i_ok = insertMedia( (ml_media_t*)
vlc_array_item_at_index( p_media_array, i ), row + i, false );
if( i_ok != VLC_SUCCESS )
break;
}
if( bSignal )
endInsertRows();
return i_ok;
}
/**
* @brief Insert the media contained in a result to the model
* @param p_result the media to append is p_result->value.p_media
* @param row the future row for this media
* @param bSignal signal Qt that the model has been modified,
* should NOT be used by the user
* @return a VLC error code
*/
int MLModel::insertResult( const ml_result_t *p_result, int row,
bool bSignal )
{
if( !p_result || p_result->type != ML_TYPE_MEDIA )
return VLC_EGENERIC;
else
return insertMedia( p_result->value.p_media, row, bSignal );
}
/**
* @brief Append the media contained in a result to the model
* @param p_result the media to append is p_result->value.p_media
* @param row the future row for this media
* @return a VLC error code
* @note Always signals. Do not use in a loop.
*/
inline int MLModel::appendResult( const ml_result_t *p_result )
{
return insertResult( p_result, -1, true );
}
/** /**
* @brief Insert all medias from a result array to the model * @brief Insert all medias from a result array to the model
* @param p_result_array the medias to append * @param p_result_array the medias to append
* @return see insertMedia * @return see insertMedia
* @note if bSignal==true, then it signals only once
* not media or NULL items are skipped
*/ */
int MLModel::insertResultArray( vlc_array_t *p_result_array, int MLModel::insertResultArray( vlc_array_t *p_result_array, int row )
int row, bool bSignal )
{ {
int i_ok = VLC_SUCCESS; int i_ok = VLC_SUCCESS;
int count = vlc_array_count( p_result_array ); int count = vlc_array_count( p_result_array );
...@@ -419,12 +383,12 @@ int MLModel::insertResultArray( vlc_array_t *p_result_array, ...@@ -419,12 +383,12 @@ int MLModel::insertResultArray( vlc_array_t *p_result_array,
if( !count ) if( !count )
return i_ok; return i_ok;
emit layoutAboutToBeChanged();
if( row == -1 ) if( row == -1 )
row = rowCount(); row = rowCount();
// Signal Qt that we will insert rows // Signal Qt that we will insert rows
if( bSignal ) beginInsertRows( createIndex( -1, -1 ), row, row + count-1 );
beginInsertRows( createIndex( -1, -1 ), row, row + count-1 );
// Loop and insert // Loop and insert
for( int i = 0; i < count; ++i ) for( int i = 0; i < count; ++i )
...@@ -433,17 +397,50 @@ int MLModel::insertResultArray( vlc_array_t *p_result_array, ...@@ -433,17 +397,50 @@ int MLModel::insertResultArray( vlc_array_t *p_result_array,
vlc_array_item_at_index( p_result_array, i ); vlc_array_item_at_index( p_result_array, i );
if( !p_result || p_result->type != ML_TYPE_MEDIA ) if( !p_result || p_result->type != ML_TYPE_MEDIA )
continue; continue;
i_ok = insertMedia( p_result->value.p_media, row + i, false ); i_ok = insertMedia( p_result->value.p_media, row + i );
if( i_ok != VLC_SUCCESS ) if( i_ok != VLC_SUCCESS )
break; break;
} }
// Signal we're done // Signal we're done
if( bSignal ) endInsertRows();
endInsertRows();
emit layoutChanged();
return i_ok; return i_ok;
} }
bool MLModel::event( QEvent *event )
{
if ( event->type() == MLEvent::MediaAdded_Type )
{
event->accept();
MLEvent *e = static_cast<MLEvent *>(event);
vlc_array_t* p_result = vlc_array_new();
if ( ml_FindMedia( e->p_ml, p_result, ML_ID, e->ml_media_id ) == VLC_SUCCESS )
{
insertResultArray( p_result );
ml_DestroyResultArray( p_result );
}
vlc_array_destroy( p_result );
return true;
}
else if( event->type() == MLEvent::MediaRemoved_Type )
{
event->accept();
MLEvent *e = static_cast<MLEvent *>(event);
removeRow( getIndexByMLID( e->ml_media_id ).row() );
return true;
}
else if( event->type() == MLEvent::MediaUpdated_Type )
{
event->accept();
/* Never implemented... */
return true;
}
return VLCModel::event( event );
}
/** ************************************************************************** /** **************************************************************************
* \brief Add a media to the playlist * \brief Add a media to the playlist
* *
...@@ -496,46 +493,33 @@ static void AddItemToPlaylist( int i_media_id, bool bPlay, media_library_t* p_ml ...@@ -496,46 +493,33 @@ static void AddItemToPlaylist( int i_media_id, bool bPlay, media_library_t* p_ml
vlc_gc_decref( p_item ); vlc_gc_decref( p_item );
} }
void MLModel::activateItem( const QModelIndex &index ) void MLModel::activateItem( const QModelIndex &idx )
{ {
play( index ); if( !idx.isValid() ) return;
AddItemToPlaylist( itemId( idx, MLMEDIA_ID ), true, p_ml, true );
} }
void MLModel::play( const QModelIndex &idx ) void MLModel::action( QAction *action, const QModelIndexList &indexes )
{ {
if( !idx.isValid() )
return;
MLItem *item = static_cast< MLItem* >( idx.internalPointer() );
if( !item )
return;
AddItemToPlaylist( item->id(), true, p_ml, true );
}
QString MLModel::getURI( const QModelIndex &index ) const
{
return QString();
}
void MLModel::actionSlot( QAction *action )
{
QString name;
QStringList mrls;
QModelIndex index;
playlist_item_t *p_item;
actionsContainerType a = action->data().value<actionsContainerType>(); actionsContainerType a = action->data().value<actionsContainerType>();
switch ( a.action ) switch ( a.action )
{ {
case actionsContainerType::ACTION_PLAY: case actionsContainerType::ACTION_PLAY:
play( a.indexes.first() ); if ( ! indexes.empty() && indexes.first().isValid() )
activateItem( indexes.first() );
break; break;
case actionsContainerType::ACTION_ADDTOPLAYLIST: case actionsContainerType::ACTION_ADDTOPLAYLIST:
foreach( const QModelIndex &index, indexes )
{
if( !index.isValid() ) break;
AddItemToPlaylist( itemId( index, MLMEDIA_ID ), false, p_ml, true );
}
break; break;
case actionsContainerType::ACTION_REMOVE: case actionsContainerType::ACTION_REMOVE:
doDelete( a.indexes ); doDelete( indexes );
break; break;
case actionsContainerType::ACTION_SORT: case actionsContainerType::ACTION_SORT:
...@@ -563,9 +547,8 @@ bool MLModel::canEdit() const ...@@ -563,9 +547,8 @@ bool MLModel::canEdit() const
bool MLModel::isCurrentItem( const QModelIndex &index, playLocation where ) const bool MLModel::isCurrentItem( const QModelIndex &index, playLocation where ) const
{ {
Q_UNUSED( index ); if ( where == IN_SQLMEDIALIB )
if ( where == IN_MEDIALIBRARY ) return index.isValid();
return true;
return false; return false;
} }
...@@ -575,31 +558,39 @@ QModelIndex MLModel::getIndexByMLID( int id ) const ...@@ -575,31 +558,39 @@ QModelIndex MLModel::getIndexByMLID( int id ) const
{ {
QModelIndex idx = index( i, 0 ); QModelIndex idx = index( i, 0 );
MLItem *item = static_cast< MLItem* >( idx.internalPointer() ); MLItem *item = static_cast< MLItem* >( idx.internalPointer() );
if( item->id() == id ) if( item->id( MLMEDIA_ID ) == id ) return idx;
return idx;
} }
return QModelIndex(); return QModelIndex();
} }
bool MLModel::isParent( const QModelIndex &index, const QModelIndex &current) const
{
Q_UNUSED( index ); Q_UNUSED( current );
return false;
}
bool MLModel::isLeaf( const QModelIndex &index ) const
{
Q_UNUSED( index );
return true;
}
/* ML Callbacks handling */
inline void postMLEvent( vlc_object_t *p_this, QEvent::Type type, void *data, int32_t i )
{
MLModel* p_model = static_cast<MLModel*>(data);
media_library_t *p_ml = (media_library_t *) p_this;
QApplication::postEvent( p_model, new MLEvent( type, p_ml, i ) );
}
static int mediaAdded( vlc_object_t *p_this, char const *psz_var, static int mediaAdded( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, vlc_value_t oldval, vlc_value_t newval,
void *data ) void *data )
{ {
VLC_UNUSED( psz_var ); VLC_UNUSED( oldval ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
postMLEvent( p_this, MLEvent::MediaAdded_Type, data, newval.i_int );
int ret = VLC_SUCCESS;
media_library_t *p_ml = ( media_library_t* )p_this;
MLModel* p_model = ( MLModel* )data;
vlc_array_t* p_result = vlc_array_new();
ret = ml_FindMedia( p_ml, p_result, ML_ID, newval.i_int );
if( ret != VLC_SUCCESS )
{
vlc_array_destroy( p_result );
return VLC_EGENERIC;
}
p_model->insertResultArray( p_result );
ml_DestroyResultArray( p_result );
vlc_array_destroy( p_result );
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -607,12 +598,8 @@ static int mediaDeleted( vlc_object_t *p_this, char const *psz_var, ...@@ -607,12 +598,8 @@ static int mediaDeleted( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, vlc_value_t oldval, vlc_value_t newval,
void *data ) void *data )
{ {
VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
postMLEvent( p_this, MLEvent::MediaRemoved_Type, data, newval.i_int );
MLModel* p_model = ( MLModel* )data;
QModelIndex remove_idx = p_model->getIndexByMLID( newval.i_int );
if( remove_idx.isValid() )
p_model->remove( remove_idx );
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -620,9 +607,8 @@ static int mediaUpdated( vlc_object_t *p_this, char const *psz_var, ...@@ -620,9 +607,8 @@ static int mediaUpdated( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval, vlc_value_t oldval, vlc_value_t newval,
void *data ) void *data )
{ {
VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
VLC_UNUSED( newval ); VLC_UNUSED( data ); postMLEvent( p_this, MLEvent::MediaUpdated_Type, data, newval.i_int );
return VLC_SUCCESS; return VLC_SUCCESS;
} }
......
...@@ -41,8 +41,25 @@ ...@@ -41,8 +41,25 @@
#include "ml_item.hpp" #include "ml_item.hpp"
#include "qt4.hpp" #include "qt4.hpp"
#include <QMutex>
#include <QEvent>
class MLItem; class MLItem;
/** *************************************************************************
* \brief ML Events class because we don't want direct callbacks
****************************************************************************/
class MLEvent : public QEvent
{
public:
static const QEvent::Type MediaAdded_Type;
static const QEvent::Type MediaRemoved_Type;
static const QEvent::Type MediaUpdated_Type;
MLEvent( QEvent::Type type, media_library_t *_p_ml, int32_t _ml_media_id ) :
QEvent( type ), ml_media_id( _ml_media_id ), p_ml( _p_ml ) {};
int32_t ml_media_id;
media_library_t * p_ml; /* store instance */
};
/** ************************************************************************* /** *************************************************************************
* \brief Tree model for the result list * \brief Tree model for the result list
****************************************************************************/ ****************************************************************************/
...@@ -55,69 +72,57 @@ public: ...@@ -55,69 +72,57 @@ public:
MLModel( intf_thread_t *_p_intf, QObject *parent = NULL ); MLModel( intf_thread_t *_p_intf, QObject *parent = NULL );
virtual ~MLModel(); virtual ~MLModel();
virtual int itemId( const QModelIndex & ) const;
virtual input_item_t *getInputItem( const QModelIndex &index ) const;
QVariant data( const QModelIndex &idx, const int role = Qt::DisplayRole ) const; QVariant data( const QModelIndex &idx, const int role = Qt::DisplayRole ) const;
bool setData( const QModelIndex &idx, const QVariant &value, bool setData( const QModelIndex &idx, const QVariant &value,
int role = Qt::EditRole ); int role = Qt::EditRole );
ml_select_e columnType( int column ) const;
QModelIndex index( int row, int column, QModelIndex index( int row, int column,
const QModelIndex & parent = QModelIndex() ) const; const QModelIndex & parent = QModelIndex() ) const;
virtual QModelIndex currentIndex() const;
int rowCount( const QModelIndex & parent = QModelIndex() ) const; int rowCount( const QModelIndex & parent = QModelIndex() ) const;
QModelIndex parent( const QModelIndex& ) const; QModelIndex parent( const QModelIndex& ) const;
QVariant headerData( int, Qt::Orientation, int ) const;
Qt::ItemFlags flags( const QModelIndex& ) const; Qt::ItemFlags flags( const QModelIndex& ) const;
bool isEditable( const QModelIndex& ) const;
// Drag and drop: MIME data
QMimeData* mimeData( const QModelIndexList & indexes ) const; QMimeData* mimeData( const QModelIndexList & indexes ) const;
virtual bool removeRows( int row, int count, const QModelIndex & parent = QModelIndex() );
// Custom functions // Custom functions
int insertMedia( ml_media_t *p_media, int row = -1, bool isEditable( const QModelIndex& ) const;
bool bSignal = true ); ml_select_e columnType( int column ) const;
int appendMedia( ml_media_t *p_media ); virtual bool event( QEvent * e );
int insertMediaArray( vlc_array_t *p_media_array, int row = -1,
bool bSignal = true ); QModelIndex getIndexByMLID( int id ) const;
int insertResult( const ml_result_t *p_result, int row = -1, /* VLCModelSubInterface */
bool bSignal = true ); virtual void rebuild( playlist_item_t * p = NULL );
inline int appendResult( const ml_result_t *p_result ); virtual void doDelete( QModelIndexList selected );
int insertResultArray( vlc_array_t *p_result_array, int row = -1, virtual void createNode( QModelIndex, QString ) {};
bool bSignal = true );
virtual void doDelete( QModelIndexList list );
void remove( QModelIndex idx );
void clear();
void play( const QModelIndex &idx );
virtual QString getURI( const QModelIndex &index ) const;
virtual QModelIndex rootIndex() const; virtual QModelIndex rootIndex() const;
virtual void filter( const QString& search_text, const QModelIndex & root, bool b_recursive );
virtual void sort( const int column, Qt::SortOrder order = Qt::AscendingOrder );
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;
virtual bool isTree() const; virtual bool isTree() const;
virtual bool canEdit() const; virtual bool canEdit() const;
virtual bool isCurrentItem( const QModelIndex &index, playLocation where ) const; virtual bool isCurrentItem( const QModelIndex &index, playLocation where ) const;
QModelIndex getIndexByMLID( int id ) const; virtual void action( QAction *action, const QModelIndexList &indexes );
public slots: /* VLCModelSubInterface virtual slots */
void activateItem( const QModelIndex &index ); virtual void activateItem( const QModelIndex &index );
virtual void actionSlot( QAction *action ); virtual void clearPlaylist();
protected: protected:
void remove( MLItem *item );
inline MLItem *getItem( QModelIndex index ) const /* VLCModel subclassing */
{ bool isParent( const QModelIndex &index, const QModelIndex &current) const;
if( index.isValid() ) bool isLeaf( const QModelIndex &index ) const;
return static_cast<MLItem*>( index.internalPointer() );
else return NULL;
}
private: private:
/* custom */
int insertMedia( ml_media_t *p_media, int row = -1 );
int insertResultArray( vlc_array_t *p_result_array, int row = -1 );
QList< MLItem* > items; QList< MLItem* > items;
media_library_t* p_ml; media_library_t* p_ml;
}; };
#endif #endif
......
...@@ -94,14 +94,19 @@ PlaylistWidget::PlaylistWidget( intf_thread_t *_p_i, QWidget *_par ) ...@@ -94,14 +94,19 @@ PlaylistWidget::PlaylistWidget( intf_thread_t *_p_i, QWidget *_par )
setMinimumWidth( 400 ); setMinimumWidth( 400 );
PLModel *model = PLModel::getPLModel( p_intf ); VLCProxyModel *model = new VLCProxyModel( this );
PLModel *plmodel = PLModel::getPLModel( p_intf );
model->setModel( VLCProxyModel::PL_MODEL, plmodel );
model->switchToModel( VLCProxyModel::PL_MODEL );
#ifdef MEDIA_LIBRARY #ifdef MEDIA_LIBRARY
MLModel *mlmodel = new MLModel( p_intf, this ); MLModel *mlmodel = new MLModel( p_intf, model );
mainView = new StandardPLPanel( this, p_intf, p_root, selector, model, mlmodel ); model->setModel( VLCProxyModel::SQLML_MODEL, mlmodel );
#else
mainView = new StandardPLPanel( this, p_intf, p_root, selector, model, NULL );
#endif #endif
mainView = new StandardPLPanel( this, p_intf, p_root, selector, model );
/* Location Bar */ /* Location Bar */
locationBar = new LocationBar( model ); locationBar = new LocationBar( model );
locationBar->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred ); locationBar->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred );
...@@ -228,20 +233,15 @@ void PlaylistWidget::forceShow() ...@@ -228,20 +233,15 @@ void PlaylistWidget::forceShow()
void PlaylistWidget::changeView( const QModelIndex& index ) void PlaylistWidget::changeView( const QModelIndex& index )
{ {
searchEdit->clear();
locationBar->setIndex( index ); locationBar->setIndex( index );
} }
void PlaylistWidget::clearPlaylist()
{
PLModel::getPLModel( p_intf )->clearPlaylist();
}
#include <QSignalMapper> #include <QSignalMapper>
#include <QMenu> #include <QMenu>
#include <QPainter> #include <QPainter>
LocationBar::LocationBar( PLModel *m ) LocationBar::LocationBar( VLCProxyModel *m )
{ {
model = m; setModel( m );
mapper = new QSignalMapper( this ); mapper = new QSignalMapper( this );
CONNECT( mapper, mapped( int ), this, invoke( int ) ); CONNECT( mapper, mapped( int ), this, invoke( int ) );
...@@ -272,7 +272,7 @@ void LocationBar::setIndex( const QModelIndex &index ) ...@@ -272,7 +272,7 @@ void LocationBar::setIndex( const QModelIndex &index )
actions.append( action ); actions.append( action );
CONNECT( btn, clicked(), action, trigger() ); CONNECT( btn, clicked(), action, trigger() );
mapper->setMapping( action, model->itemId( i ) ); mapper->setMapping( action, model->itemId( i, PLAYLIST_ID ) );
CONNECT( action, triggered(), mapper, map() ); CONNECT( action, triggered(), mapper, map() );
first = false; first = false;
...@@ -298,7 +298,7 @@ void LocationBar::setRootIndex() ...@@ -298,7 +298,7 @@ void LocationBar::setRootIndex()
void LocationBar::invoke( int i_id ) void LocationBar::invoke( int i_id )
{ {
QModelIndex index = model->index( i_id, 0 ); QModelIndex index = model->indexByPLID( i_id, 0 );
emit invoked ( index ); emit invoked ( index );
} }
......
...@@ -77,7 +77,6 @@ protected: ...@@ -77,7 +77,6 @@ protected:
virtual void closeEvent( QCloseEvent * ); virtual void closeEvent( QCloseEvent * );
private slots: private slots:
void changeView( const QModelIndex& index ); void changeView( const QModelIndex& index );
void clearPlaylist();
friend class PlaylistDialog; friend class PlaylistDialog;
}; };
...@@ -119,14 +118,16 @@ private: ...@@ -119,14 +118,16 @@ private:
bool b_arrow; bool b_arrow;
}; };
class PLModel; class VLCProxyModel;
class QHBoxLayout; class QHBoxLayout;
class LocationBar : public QWidget class LocationBar : public QWidget
{ {
Q_OBJECT Q_OBJECT
public: public:
LocationBar( PLModel * ); LocationBar( VLCProxyModel * );
void setIndex( const QModelIndex & ); void setIndex( const QModelIndex & );
void setModel( VLCProxyModel * _model ) { model = _model; };
virtual QSize sizeHint() const; virtual QSize sizeHint() const;
protected: protected:
virtual void resizeEvent ( QResizeEvent * event ); virtual void resizeEvent ( QResizeEvent * event );
...@@ -134,7 +135,7 @@ protected: ...@@ -134,7 +135,7 @@ protected:
private: private:
void layOut( const QSize& size ); void layOut( const QSize& size );
PLModel *model; VLCProxyModel *model;
QSignalMapper *mapper; QSignalMapper *mapper;
QWidgetList buttons; QWidgetList buttons;
QList<QAction*> actions; QList<QAction*> actions;
......
...@@ -41,6 +41,12 @@ void AbstractPLItem::clearChildren() ...@@ -41,6 +41,12 @@ void AbstractPLItem::clearChildren()
children.clear(); children.clear();
} }
void AbstractPLItem::removeChild( AbstractPLItem *item )
{
children.removeOne( item );
delete item;
}
/* /*
Playlist item is just a wrapper, an abstraction of the playlist_item Playlist item is just a wrapper, an abstraction of the playlist_item
in order to be managed by PLModel in order to be managed by PLModel
...@@ -51,8 +57,8 @@ void AbstractPLItem::clearChildren() ...@@ -51,8 +57,8 @@ void AbstractPLItem::clearChildren()
void PLItem::init( playlist_item_t *_playlist_item, PLItem *parent ) void PLItem::init( playlist_item_t *_playlist_item, PLItem *parent )
{ {
parentItem = parent; /* Can be NULL, but only for the rootItem */ parentItem = parent; /* Can be NULL, but only for the rootItem */
i_id = _playlist_item->i_id; /* Playlist item specific id */ i_playlist_id = _playlist_item->i_id; /* Playlist item specific id */
p_input = _playlist_item->p_input; p_input = _playlist_item->p_input;
vlc_gc_incref( p_input ); vlc_gc_incref( p_input );
} }
...@@ -77,10 +83,19 @@ PLItem::~PLItem() ...@@ -77,10 +83,19 @@ PLItem::~PLItem()
children.clear(); children.clear();
} }
void PLItem::removeChild( PLItem *item ) int PLItem::id( int type )
{ {
children.removeOne( item ); switch( type )
delete item; {
case INPUTITEM_ID:
return inputItem()->i_id;
case PLAYLIST_ID:
return i_playlist_id;
default:
case MLMEDIA_ID:
assert( NULL );
return -1;
}
} }
void PLItem::takeChildAt( int index ) void PLItem::takeChildAt( int index )
...@@ -98,7 +113,7 @@ int PLItem::row() ...@@ -98,7 +113,7 @@ int PLItem::row()
return 0; return 0;
} }
bool PLItem::operator< ( PLItem& other ) bool PLItem::operator< ( AbstractPLItem& other )
{ {
AbstractPLItem *item1 = this; AbstractPLItem *item1 = this;
while( item1->parentItem ) while( item1->parentItem )
...@@ -117,3 +132,26 @@ bool PLItem::operator< ( PLItem& other ) ...@@ -117,3 +132,26 @@ bool PLItem::operator< ( PLItem& other )
} }
return false; return false;
} }
QUrl PLItem::getURI() const
{
QString uri;
vlc_mutex_lock( &p_input->lock );
uri = QString( p_input->psz_uri );
vlc_mutex_unlock( &p_input->lock );
return QUrl( uri );
}
QString PLItem::getTitle() const
{
QString title;
char *fb_name = input_item_GetTitle( p_input );
if( EMPTY_STR( fb_name ) )
{
free( fb_name );
fb_name = input_item_GetName( p_input );
}
title = qfu(fb_name);
free(fb_name);
return title;
}
...@@ -29,11 +29,21 @@ ...@@ -29,11 +29,21 @@
#endif #endif
#include <QList> #include <QList>
#include <QString>
#include <QUrl>
enum
{
INPUTITEM_ID = 1,
PLAYLIST_ID,
MLMEDIA_ID
};
class AbstractPLItem class AbstractPLItem
{ {
friend class PLItem; /* super ugly glue stuff */ friend class PLItem; /* super ugly glue stuff */
friend class MLItem; friend class MLItem;
friend class VLCModel;
friend class PLModel; friend class PLModel;
friend class MLModel; friend class MLModel;
...@@ -41,7 +51,7 @@ public: ...@@ -41,7 +51,7 @@ public:
virtual ~AbstractPLItem() {} virtual ~AbstractPLItem() {}
protected: protected:
virtual int id() const = 0; virtual int id( int type ) = 0;
int childCount() const { return children.count(); } int childCount() const { return children.count(); }
int indexOf( AbstractPLItem *item ) const { return children.indexOf( item ); }; int indexOf( AbstractPLItem *item ) const { return children.indexOf( item ); };
int lastIndexOf( AbstractPLItem *item ) const { return children.lastIndexOf( item ); }; int lastIndexOf( AbstractPLItem *item ) const { return children.lastIndexOf( item ); };
...@@ -50,7 +60,10 @@ protected: ...@@ -50,7 +60,10 @@ protected:
void insertChild( AbstractPLItem *item, int pos = -1 ) { children.insert( pos, item ); } void insertChild( AbstractPLItem *item, int pos = -1 ) { children.insert( pos, item ); }
void appendChild( AbstractPLItem *item ) { insertChild( item, children.count() ); } ; void appendChild( AbstractPLItem *item ) { insertChild( item, children.count() ); } ;
virtual AbstractPLItem *child( int id ) const = 0; virtual AbstractPLItem *child( int id ) const = 0;
void removeChild( AbstractPLItem *item );
void clearChildren(); void clearChildren();
virtual QUrl getURI() const = 0;
virtual QString getTitle() const = 0;
QList<AbstractPLItem *> children; QList<AbstractPLItem *> children;
AbstractPLItem *parentItem; AbstractPLItem *parentItem;
...@@ -63,23 +76,24 @@ class PLItem : public AbstractPLItem ...@@ -63,23 +76,24 @@ class PLItem : public AbstractPLItem
public: public:
virtual ~PLItem(); virtual ~PLItem();
bool hasSameParent( PLItem *other ) { return parent() == other->parent(); } bool hasSameParent( PLItem *other ) { return parent() == other->parent(); }
bool operator< ( PLItem& ); bool operator< ( AbstractPLItem& );
private: private:
/* AbstractPLItem */ /* AbstractPLItem */
int id() const { return i_id; }; int id( int type );
input_item_t *inputItem() { return p_input; } input_item_t *inputItem() { return p_input; }
AbstractPLItem *child( int id ) const { return children.value( id ); }; AbstractPLItem *child( int id ) const { return children.value( id ); };
virtual QUrl getURI() const;
virtual QString getTitle() const;
/* Local */ /* Local */
PLItem( playlist_item_t *, PLItem *parent ); PLItem( playlist_item_t *, PLItem *parent );
int row(); int row();
void removeChild( PLItem * );
void takeChildAt( int ); void takeChildAt( int );
PLItem( playlist_item_t * ); PLItem( playlist_item_t * );
void init( playlist_item_t *, PLItem * ); void init( playlist_item_t *, PLItem * );
int i_id; int i_playlist_id;
input_item_t *p_input; input_item_t *p_input;
}; };
......
...@@ -33,17 +33,62 @@ ...@@ -33,17 +33,62 @@
#include <vlc_intf_strings.h> /* I_DIR */ #include <vlc_intf_strings.h> /* I_DIR */
#include "pixmaps/types/type_unknown.xpm"
#include "sorting.h" #include "sorting.h"
#include <assert.h> #include <assert.h>
#include <QIcon>
#include <QFont> #include <QFont>
#include <QTimer> #include <QTimer>
#include <QAction> #include <QAction>
#include <QBuffer> #include <QBuffer>
QIcon PLModel::icons[ITEM_TYPE_NUMBER]; /*************************************************************************
* Proxy model implementation
*************************************************************************/
VLCProxyModel::VLCProxyModel( QObject *parent )
: QSortFilterProxyModel( parent ), VLCModelSubInterface()
{
/* Because we can't directly plug the signal without mapping
the index to the proxy model, we need a conversion step.
*/
connect( this, SIGNAL( currentIndexChanged_Converted(const QModelIndex&) ),
this->sigs, SIGNAL( currentIndexChanged(const QModelIndex&) ) );
}
bool VLCProxyModel::switchToModel( models type )
{
VLCModel *previousModel = model();
VLCModel *newModel = sourcemodels[ type ];
if ( ! newModel /*|| newModel == previousModel*/ ) return false;
setSourceModel( newModel );
if ( previousModel )
{
/* First disconnect previous signals */
disconnect( previousModel->sigs, SIGNAL( currentIndexChanged(const QModelIndex&) ),
this, SIGNAL( currentIndexChanged_IndexConversion(const QModelIndex&) ) );
disconnect( previousModel->sigs, SIGNAL( rootIndexChanged() ),
this->sigs, SIGNAL( rootIndexChanged() ) );
}
/* wire to propagate sourceModel's signals */
connect( model()->sigs, SIGNAL( currentIndexChanged(const QModelIndex&) ),
this, SLOT( currentIndexChanged_IndexConversion(const QModelIndex&) ) );
connect( model()->sigs, SIGNAL( rootIndexChanged() ),
this->sigs, SIGNAL( rootIndexChanged() ) );
return true;
}
QModelIndexList VLCProxyModel::mapListToSource( const QModelIndexList& list )
{
QModelIndexList newlist;
foreach( const QModelIndex &index, list )
{
if ( index.isValid() )
newlist << mapToSource( index );
}
return newlist;
}
/************************************************************************* /*************************************************************************
* Playlist model implementation * Playlist model implementation
...@@ -56,25 +101,10 @@ PLModel::PLModel( playlist_t *_p_playlist, /* THEPL */ ...@@ -56,25 +101,10 @@ PLModel::PLModel( playlist_t *_p_playlist, /* THEPL */
: VLCModel( _p_intf, parent ) : VLCModel( _p_intf, parent )
{ {
p_playlist = _p_playlist; p_playlist = _p_playlist;
i_cached_id = -1;
i_cached_input_id = -1;
rootItem = NULL; /* PLItem rootItem, will be set in rebuild( ) */ rootItem = NULL; /* PLItem rootItem, will be set in rebuild( ) */
latestSearch = QString(); latestSearch = QString();
/* Icons initialization */
#define ADD_ICON(type, x) icons[ITEM_TYPE_##type] = QIcon( x )
ADD_ICON( UNKNOWN , QPixmap( type_unknown_xpm ) );
ADD_ICON( FILE, ":/type/file" );
ADD_ICON( DIRECTORY, ":/type/directory" );
ADD_ICON( DISC, ":/type/disc" );
ADD_ICON( CDDA, ":/type/cdda" );
ADD_ICON( CARD, ":/type/capture-card" );
ADD_ICON( NET, ":/type/net" );
ADD_ICON( PLAYLIST, ":/type/playlist" );
ADD_ICON( NODE, ":/type/node" );
#undef ADD_ICON
rebuild( p_root ); rebuild( p_root );
DCONNECT( THEMIM->getIM(), metaChanged( input_item_t *), DCONNECT( THEMIM->getIM(), metaChanged( input_item_t *),
this, processInputItemUpdate( input_item_t *) ); this, processInputItemUpdate( input_item_t *) );
...@@ -107,7 +137,7 @@ Qt::ItemFlags PLModel::flags( const QModelIndex &index ) const ...@@ -107,7 +137,7 @@ Qt::ItemFlags PLModel::flags( const QModelIndex &index ) const
{ {
PL_LOCK; PL_LOCK;
playlist_item_t *plItem = playlist_item_t *plItem =
playlist_ItemGetById( p_playlist, item->i_id ); playlist_ItemGetById( p_playlist, item->i_playlist_id );
if ( plItem && ( plItem->i_children > -1 ) ) if ( plItem && ( plItem->i_children > -1 ) )
flags |= Qt::ItemIsDropEnabled; flags |= Qt::ItemIsDropEnabled;
...@@ -242,7 +272,7 @@ void PLModel::dropMove( const PlMimeData * plMimeData, PLItem *target, int row ) ...@@ -242,7 +272,7 @@ void PLModel::dropMove( const PlMimeData * plMimeData, PLItem *target, int row )
playlist_item_t *p_item = playlist_ItemGetByInput( p_playlist, p_input ); playlist_item_t *p_item = playlist_ItemGetByInput( p_playlist, p_input );
if( !p_item ) continue; if( !p_item ) continue;
PLItem *item = findByInput( rootItem, p_input->i_id ); PLItem *item = findByInputId( rootItem, p_input->i_id );
if( !item ) continue; if( !item ) continue;
/* Better not try to move a node into itself. /* Better not try to move a node into itself.
...@@ -287,20 +317,13 @@ void PLModel::dropMove( const PlMimeData * plMimeData, PLItem *target, int row ) ...@@ -287,20 +317,13 @@ void PLModel::dropMove( const PlMimeData * plMimeData, PLItem *target, int row )
free( pp_items ); free( pp_items );
} }
/* remove item with its id */
void PLModel::removeItem( int i_id )
{
PLItem *item = findById( rootItem, i_id );
removeItem( item );
}
void PLModel::activateItem( const QModelIndex &index ) void PLModel::activateItem( const QModelIndex &index )
{ {
assert( index.isValid() ); assert( index.isValid() );
const PLItem *item = getItem( index ); const PLItem *item = getItem( index );
assert( item ); assert( item );
PL_LOCK; PL_LOCK;
playlist_item_t *p_item = playlist_ItemGetById( p_playlist, item->i_id ); playlist_item_t *p_item = playlist_ItemGetById( p_playlist, item->i_playlist_id );
activateItem( p_item ); activateItem( p_item );
PL_UNLOCK; PL_UNLOCK;
} }
...@@ -313,7 +336,7 @@ void PLModel::activateItem( playlist_item_t *p_item ) ...@@ -313,7 +336,7 @@ void PLModel::activateItem( playlist_item_t *p_item )
playlist_item_t *p_parent = p_item; playlist_item_t *p_parent = p_item;
while( p_parent ) while( p_parent )
{ {
if( p_parent->i_id == rootItem->id() ) break; if( p_parent->i_id == rootItem->id( PLAYLIST_ID ) ) break;
p_parent = p_parent->p_parent; p_parent = p_parent->p_parent;
} }
if( p_parent ) if( p_parent )
...@@ -360,7 +383,7 @@ QVariant PLModel::data( const QModelIndex &index, const int role ) const ...@@ -360,7 +383,7 @@ QVariant PLModel::data( const QModelIndex &index, const int role ) const
else if( role == Qt::DecorationRole && index.column() == 0 ) else if( role == Qt::DecorationRole && index.column() == 0 )
{ {
/* Used to segfault here because i_type wasn't always initialized */ /* Used to segfault here because i_type wasn't always initialized */
return QVariant( PLModel::icons[item->inputItem()->i_type] ); return QVariant( icons[item->inputItem()->i_type] );
} }
else if( role == Qt::FontRole ) else if( role == Qt::FontRole )
{ {
...@@ -412,16 +435,7 @@ QVariant PLModel::data( const QModelIndex &index, const int role ) const ...@@ -412,16 +435,7 @@ QVariant PLModel::data( const QModelIndex &index, const int role ) const
} }
else if( role == IsLeafNodeRole ) else if( role == IsLeafNodeRole )
{ {
QVariant isLeaf; return QVariant( isLeaf( index ) );
PL_LOCK;
playlist_item_t *plItem =
playlist_ItemGetById( p_playlist, item->i_id );
if( plItem )
isLeaf = plItem->i_children == -1;
PL_UNLOCK;
return isLeaf;
} }
else if( role == IsCurrentsParentNodeRole ) else if( role == IsCurrentsParentNodeRole )
{ {
...@@ -445,74 +459,40 @@ bool PLModel::isParent( const QModelIndex &index, const QModelIndex &current ) c ...@@ -445,74 +459,40 @@ bool PLModel::isParent( const QModelIndex &index, const QModelIndex &current ) c
return isParent( index, current.parent() ); return isParent( index, current.parent() );
} }
bool PLModel::isCurrent( const QModelIndex &index ) const bool PLModel::isLeaf( const QModelIndex &index ) const
{ {
return getItem( index )->inputItem() == THEMIM->currentInputItem(); bool b_isLeaf = false;
} PL_LOCK;
playlist_item_t *plItem =
int PLModel::itemId( const QModelIndex &index ) const playlist_ItemGetById( p_playlist, itemId( index, PLAYLIST_ID ) );
{
return getItem( index )->id();
}
input_item_t * PLModel::getInputItem( const QModelIndex &index ) const
{
return getItem( index )->inputItem();
}
QString PLModel::getURI( const QModelIndex &index ) const if( plItem )
{ b_isLeaf = plItem->i_children == -1;
QString uri; PL_UNLOCK;
input_item_t *p_item = getItem( index )->inputItem(); return b_isLeaf;
/* no PL lock as item gets refcount +1 from PLItem, which only depends of events */
vlc_mutex_lock( &p_item->lock );
uri = qfu( p_item->psz_uri );
vlc_mutex_unlock( &p_item->lock );
return uri;
} }
QString PLModel::getTitle( const QModelIndex &index ) const PLItem* PLModel::getItem( const QModelIndex & index ) const
{ {
QString title; PLItem *item = static_cast<PLItem *>( VLCModel::getItem( index ) );
input_item_t *p_item = getItem( index )->inputItem(); if ( item == NULL ) item = rootItem;
char *fb_name = input_item_GetTitle( p_item ); return item;
if( EMPTY_STR( fb_name ) )
{
free( fb_name );
fb_name = input_item_GetName( p_item );
}
title = qfu(fb_name);
free(fb_name);
return title;
} }
bool PLModel::isCurrentItem( const QModelIndex &index, playLocation where ) const bool PLModel::isCurrentItem( const QModelIndex &index, playLocation where ) const
{ {
if ( where == IN_PLAYLIST ) if ( where == IN_PLAYLIST )
{ {
return itemId( index ) == THEPL->p_playing->i_id; return itemId( index, PLAYLIST_ID ) == THEPL->p_playing->i_id;
} }
else if ( where == IN_MEDIALIBRARY ) else if ( where == IN_MEDIALIBRARY )
{ {
return THEPL->p_media_library && return ( p_playlist->p_media_library &&
itemId( index ) == THEPL->p_media_library->i_id; rootItem->inputItem() == p_playlist->p_media_library->p_input );
} }
return false; return false;
} }
QVariant PLModel::headerData( int section, Qt::Orientation orientation,
int role ) const
{
if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
return QVariant();
int meta_col = columnToMeta( section );
if( meta_col == COLUMN_END ) return QVariant();
return QVariant( qfu( psz_column_title( meta_col ) ) );
}
QModelIndex PLModel::index( const int row, const int column, const QModelIndex &parent ) QModelIndex PLModel::index( const int row, const int column, const QModelIndex &parent )
const const
{ {
...@@ -525,19 +505,24 @@ QModelIndex PLModel::index( const int row, const int column, const QModelIndex & ...@@ -525,19 +505,24 @@ QModelIndex PLModel::index( const int row, const int column, const QModelIndex &
return QModelIndex(); return QModelIndex();
} }
QModelIndex PLModel::index( const int i_id, const int c ) QModelIndex PLModel::indexByPLID( const int i_plid, const int c ) const
{ {
return index( findById( rootItem, i_id ), c ); return index( findByPLId( rootItem, i_plid ), c );
}
QModelIndex PLModel::indexByInputItemID( const int i_inputitem_id, const int c ) const
{
return index( findByInputId( rootItem, i_inputitem_id ), c );
} }
QModelIndex PLModel::rootIndex() const QModelIndex PLModel::rootIndex() const
{ {
return index( findById( rootItem, rootItem->id() ), 0 ); return index( findByPLId( rootItem, rootItem->id( PLAYLIST_ID ) ), 0 );
} }
bool PLModel::isTree() const bool PLModel::isTree() const
{ {
return ( ( rootItem && rootItem->id() != p_playlist->p_playing->i_id ) return ( ( rootItem && rootItem->id( PLAYLIST_ID ) != p_playlist->p_playing->i_id )
|| var_InheritBool( p_intf, "playlist-tree" ) ); || var_InheritBool( p_intf, "playlist-tree" ) );
} }
...@@ -556,7 +541,7 @@ QModelIndex PLModel::currentIndex() const ...@@ -556,7 +541,7 @@ QModelIndex PLModel::currentIndex() const
{ {
input_thread_t *p_input_thread = THEMIM->getInput(); input_thread_t *p_input_thread = THEMIM->getInput();
if( !p_input_thread ) return QModelIndex(); if( !p_input_thread ) return QModelIndex();
PLItem *item = findByInput( rootItem, input_GetItem( p_input_thread )->i_id ); PLItem *item = findByInputId( rootItem, input_GetItem( p_input_thread )->i_id );
return index( item, 0 ); return index( item, 0 );
} }
...@@ -588,40 +573,40 @@ int PLModel::rowCount( const QModelIndex &parent ) const ...@@ -588,40 +573,40 @@ int PLModel::rowCount( const QModelIndex &parent ) const
} }
/************************* Lookups *****************************/ /************************* Lookups *****************************/
PLItem *PLModel::findById( PLItem *root, int i_id ) const PLItem *PLModel::findByPLId( PLItem *root, int i_plitemid ) const
{ {
return findInner( root, i_id, false ); return findInner( root, i_plitemid, false );
} }
PLItem *PLModel::findByInput( PLItem *root, int i_id ) const PLItem *PLModel::findByInputId( PLItem *root, int i_input_itemid ) const
{ {
PLItem *result = findInner( root, i_id, true ); PLItem *result = findInner( root, i_input_itemid, true );
return result; return result;
} }
PLItem * PLModel::findInner( PLItem *root, int i_id, bool b_input ) const PLItem * PLModel::findInner( PLItem *root, int i_id, bool b_isinputid ) const
{ {
if( !root ) return NULL; if( !root ) return NULL;
if( !b_input && root->id() == i_id ) if( !b_isinputid && root->id( PLAYLIST_ID ) == i_id )
return root; return root;
else if( b_input && root->inputItem()->i_id == i_id ) else if( b_isinputid && root->id( INPUTITEM_ID ) == i_id )
return root; return root;
QList<AbstractPLItem *>::iterator it = root->children.begin(); QList<AbstractPLItem *>::iterator it = root->children.begin();
while ( it != root->children.end() ) while ( it != root->children.end() )
{ {
PLItem *item = static_cast<PLItem *>(*it); PLItem *item = static_cast<PLItem *>(*it);
if( !b_input && item->id() == i_id ) if( !b_isinputid && item->id( PLAYLIST_ID ) == i_id )
return item; return item;
else if( b_input && item->inputItem()->i_id == i_id ) else if( b_isinputid && item->id( INPUTITEM_ID ) == i_id )
return item; return item;
if( item->childCount() ) if( item->childCount() )
{ {
PLItem *childFound = findInner( item, i_id, b_input ); PLItem *childFound = findInner( item, i_id, b_isinputid );
if( childFound ) if( childFound )
return childFound; return childFound;
} }
...@@ -649,23 +634,27 @@ void PLModel::processInputItemUpdate( input_thread_t *p_input ) ...@@ -649,23 +634,27 @@ void PLModel::processInputItemUpdate( input_thread_t *p_input )
{ {
if( !p_input ) return; if( !p_input ) return;
PLItem *item = findByInput( rootItem, input_GetItem( p_input )->i_id ); if( p_input && !( p_input->b_dead || !vlc_object_alive( p_input ) ) )
if( item ) emit currentIndexChanged( index( item, 0 ) ); {
PLItem *item = findByInputId( rootItem, input_GetItem( p_input )->i_id );
if( item ) sigs->emit_currentIndexChanged( index( item, 0 ) );
}
processInputItemUpdate( input_GetItem( p_input ) ); processInputItemUpdate( input_GetItem( p_input ) );
} }
void PLModel::processInputItemUpdate( input_item_t *p_item ) void PLModel::processInputItemUpdate( input_item_t *p_item )
{ {
if( !p_item || p_item->i_id <= 0 ) return; if( !p_item || p_item->i_id <= 0 ) return;
PLItem *item = findByInput( rootItem, p_item->i_id ); PLItem *item = findByInputId( rootItem, p_item->i_id );
if( item ) if( item )
updateTreeItem( item ); updateTreeItem( item );
} }
void PLModel::processItemRemoval( int i_id ) void PLModel::processItemRemoval( int i_pl_itemid )
{ {
if( i_id <= 0 ) return; if( i_pl_itemid <= 0 ) return;
removeItem( i_id ); removeItem( findByPLId( rootItem, i_pl_itemid ) );
} }
void PLModel::commitBufferedRowInserts() void PLModel::commitBufferedRowInserts()
...@@ -687,7 +676,7 @@ void PLModel::commitBufferedRowInserts() ...@@ -687,7 +676,7 @@ void PLModel::commitBufferedRowInserts()
} }
insertBufferMutex.unlock(); insertBufferMutex.unlock();
if ( toemit ) if ( toemit )
emit currentIndexChanged( index( toemit, 0 ) ); sigs->emit_currentIndexChanged( index( toemit, 0 ) );
} }
/* /*
...@@ -737,7 +726,7 @@ bool PLModel::isBufferedForInsert( PLItem *parent, int i_item ) ...@@ -737,7 +726,7 @@ bool PLModel::isBufferedForInsert( PLItem *parent, int i_item )
if ( parent == insertBufferRoot ) if ( parent == insertBufferRoot )
{ {
foreach (PLItem *item, insertBuffer) foreach (PLItem *item, insertBuffer)
if ( item->i_id == i_item ) if ( item->i_playlist_id == i_item )
{ {
b_return = true; b_return = true;
break; break;
...@@ -747,29 +736,29 @@ bool PLModel::isBufferedForInsert( PLItem *parent, int i_item ) ...@@ -747,29 +736,29 @@ bool PLModel::isBufferedForInsert( PLItem *parent, int i_item )
return b_return; return b_return;
} }
void PLModel::processItemAppend( int i_item, int i_parent ) void PLModel::processItemAppend( int i_pl_itemid, int i_pl_itemidparent )
{ {
playlist_item_t *p_item = NULL; playlist_item_t *p_item = NULL;
PLItem *newItem = NULL; PLItem *newItem = NULL;
int pos; int pos;
/* Find the Parent */ /* Find the Parent */
PLItem *nodeParentItem = findById( rootItem, i_parent ); PLItem *nodeParentItem = findByPLId( rootItem, i_pl_itemidparent );
if( !nodeParentItem ) if( !nodeParentItem )
{ /* retry as it might have been in buffer */ { /* retry as it might have been in buffer */
commitBufferedRowInserts(); commitBufferedRowInserts();
nodeParentItem = findById( rootItem, i_parent ); nodeParentItem = findByPLId( rootItem, i_pl_itemidparent );
} }
if( !nodeParentItem ) return; if( !nodeParentItem ) return;
/* Search for an already matching children */ /* Search for an already matching children */
if ( isBufferedForInsert( nodeParentItem, i_item ) ) return; if ( isBufferedForInsert( nodeParentItem, i_pl_itemid ) ) return;
foreach( const AbstractPLItem *existing, nodeParentItem->children ) foreach( AbstractPLItem *existing, nodeParentItem->children )
if( existing->id() == i_item ) return; if( existing->id( PLAYLIST_ID ) == i_pl_itemid ) return;
/* Find the child */ /* Find the child */
PL_LOCK; PL_LOCK;
p_item = playlist_ItemGetById( p_playlist, i_item ); p_item = playlist_ItemGetById( p_playlist, i_pl_itemid );
if( !p_item || p_item->i_flags & PLAYLIST_DBL_FLAG ) if( !p_item || p_item->i_flags & PLAYLIST_DBL_FLAG )
{ {
PL_UNLOCK; return; PL_UNLOCK; return;
...@@ -785,23 +774,20 @@ void PLModel::processItemAppend( int i_item, int i_parent ) ...@@ -785,23 +774,20 @@ void PLModel::processItemAppend( int i_item, int i_parent )
bufferedRowInsert( newItem, nodeParentItem, pos ); bufferedRowInsert( newItem, nodeParentItem, pos );
if( latestSearch.isEmpty() ) return; if( latestSearch.isEmpty() ) return;
search( latestSearch, index( rootItem, 0), false /*FIXME*/ ); filter( latestSearch, index( rootItem, 0), false /*FIXME*/ );
} }
void PLModel::rebuild( playlist_item_t *p_root ) void PLModel::rebuild( playlist_item_t *p_root )
{ {
commitBufferedRowInserts(); commitBufferedRowInserts();
/* Invalidate cache */
i_cached_id = i_cached_input_id = -1;
beginResetModel(); beginResetModel();
if( rootItem ) rootItem->clearChildren();
PL_LOCK; PL_LOCK;
if( rootItem ) rootItem->clearChildren();
if( p_root ) // Can be NULL if( p_root ) // Can be NULL
{ {
delete rootItem; if ( rootItem ) delete rootItem;
rootItem = new PLItem( p_root ); rootItem = new PLItem( p_root );
} }
assert( rootItem ); assert( rootItem );
...@@ -811,7 +797,7 @@ void PLModel::rebuild( playlist_item_t *p_root ) ...@@ -811,7 +797,7 @@ void PLModel::rebuild( playlist_item_t *p_root )
/* And signal the view */ /* And signal the view */
endResetModel(); endResetModel();
if( p_root ) emit rootIndexChanged(); if( p_root ) sigs->emit_rootIndexChanged();
} }
void PLModel::takeItem( PLItem *item ) void PLModel::takeItem( PLItem *item )
...@@ -847,9 +833,6 @@ void PLModel::removeItem( PLItem *item ) ...@@ -847,9 +833,6 @@ void PLModel::removeItem( PLItem *item )
if( !item ) return; if( !item ) return;
commitBufferedRowInserts(); commitBufferedRowInserts();
i_cached_id = -1;
i_cached_input_id = -1;
if( item->parent() ) { if( item->parent() ) {
int i = item->parent()->indexOf( item ); int i = item->parent()->indexOf( item );
beginRemoveRows( index( static_cast<PLItem*>(item->parent()), 0), i, i ); beginRemoveRows( index( static_cast<PLItem*>(item->parent()), 0), i, i );
...@@ -869,7 +852,7 @@ void PLModel::removeItem( PLItem *item ) ...@@ -869,7 +852,7 @@ void PLModel::removeItem( PLItem *item )
/* This function must be entered WITH the playlist lock */ /* This function must be entered WITH the playlist lock */
void PLModel::updateChildren( PLItem *root ) void PLModel::updateChildren( PLItem *root )
{ {
playlist_item_t *p_node = playlist_ItemGetById( p_playlist, root->id() ); playlist_item_t *p_node = playlist_ItemGetById( p_playlist, root->id( PLAYLIST_ID ) );
updateChildren( p_node, root ); updateChildren( p_node, root );
} }
...@@ -936,7 +919,7 @@ void PLModel::recurseDelete( QList<AbstractPLItem*> children, QModelIndexList *f ...@@ -936,7 +919,7 @@ void PLModel::recurseDelete( QList<AbstractPLItem*> children, QModelIndexList *f
/******* Volume III: Sorting and searching ********/ /******* Volume III: Sorting and searching ********/
void PLModel::sort( const int column, Qt::SortOrder order ) void PLModel::sort( const int column, Qt::SortOrder order )
{ {
sort( QModelIndex(), index( rootItem->id(), 0 ) , column, order ); sort( QModelIndex(), indexByPLID( rootItem->id( PLAYLIST_ID ), 0 ) , column, order );
} }
void PLModel::sort( QModelIndex caller, QModelIndex rootIndex, const int column, Qt::SortOrder order ) void PLModel::sort( QModelIndex caller, QModelIndex rootIndex, const int column, Qt::SortOrder order )
...@@ -950,7 +933,7 @@ void PLModel::sort( QModelIndex caller, QModelIndex rootIndex, const int column, ...@@ -950,7 +933,7 @@ void PLModel::sort( QModelIndex caller, QModelIndex rootIndex, const int column,
: rootItem; : rootItem;
if( !item ) return; if( !item ) return;
int i_root_id = item->id(); int i_root_id = item->id( PLAYLIST_ID );
commitBufferedRowInserts(); commitBufferedRowInserts();
...@@ -976,8 +959,6 @@ void PLModel::sort( QModelIndex caller, QModelIndex rootIndex, const int column, ...@@ -976,8 +959,6 @@ void PLModel::sort( QModelIndex caller, QModelIndex rootIndex, const int column,
} }
} }
i_cached_id = i_cached_input_id = -1;
if( count ) if( count )
{ {
beginInsertRows( qIndex, 0, count - 1 ); beginInsertRows( qIndex, 0, count - 1 );
...@@ -986,12 +967,12 @@ void PLModel::sort( QModelIndex caller, QModelIndex rootIndex, const int column, ...@@ -986,12 +967,12 @@ void PLModel::sort( QModelIndex caller, QModelIndex rootIndex, const int column,
} }
PL_UNLOCK; PL_UNLOCK;
/* if we have popup item, try to make sure that you keep that item visible */ /* if we have popup item, try to make sure that you keep that item visible */
if( caller.isValid() ) emit currentIndexChanged( caller ); if( caller.isValid() ) sigs->emit_currentIndexChanged( caller );
else if( currentIndex().isValid() ) emit currentIndexChanged( currentIndex() ); else if( currentIndex().isValid() ) sigs->emit_currentIndexChanged( currentIndex() );
} }
void PLModel::search( const QString& search_text, const QModelIndex & idx, bool b_recursive ) void PLModel::filter( const QString& search_text, const QModelIndex & idx, bool b_recursive )
{ {
latestSearch = search_text; latestSearch = search_text;
...@@ -1001,7 +982,7 @@ void PLModel::search( const QString& search_text, const QModelIndex & idx, bool ...@@ -1001,7 +982,7 @@ void PLModel::search( const QString& search_text, const QModelIndex & idx, bool
PL_LOCK; PL_LOCK;
{ {
playlist_item_t *p_root = playlist_ItemGetById( p_playlist, playlist_item_t *p_root = playlist_ItemGetById( p_playlist,
itemId( idx ) ); itemId( idx, PLAYLIST_ID ) );
assert( p_root ); assert( p_root );
playlist_LiveSearchUpdate( p_playlist, p_root, qtu( search_text ), playlist_LiveSearchUpdate( p_playlist, p_root, qtu( search_text ),
b_recursive ); b_recursive );
...@@ -1038,24 +1019,6 @@ void PLModel::clearPlaylist() ...@@ -1038,24 +1019,6 @@ void PLModel::clearPlaylist()
doDelete(l); doDelete(l);
} }
void PLModel::ensureArtRequested( const QModelIndex &index )
{
if ( index.isValid() && hasChildren( index ) )
{
int i_art_policy = var_GetInteger( p_playlist, "album-art" );
if ( i_art_policy != ALBUM_ART_ALL ) return;
int nbnodes = rowCount( index );
QModelIndex child;
for( int row = 0 ; row < nbnodes ; row++ )
{
child = index.child( row, 0 );
if ( child.isValid() && getArtUrl( child ).isEmpty() )
THEMIM->getIM()->requestArtUpdate( getItem( child )->inputItem() );
}
}
}
void PLModel::createNode( QModelIndex index, QString name ) void PLModel::createNode( QModelIndex index, QString name )
{ {
if( name.isEmpty() || !index.isValid() ) return; if( name.isEmpty() || !index.isValid() ) return;
...@@ -1063,40 +1026,29 @@ void PLModel::createNode( QModelIndex index, QString name ) ...@@ -1063,40 +1026,29 @@ void PLModel::createNode( QModelIndex index, QString name )
PL_LOCK; PL_LOCK;
index = index.parent(); index = index.parent();
if ( !index.isValid() ) index = rootIndex(); if ( !index.isValid() ) index = rootIndex();
playlist_item_t *p_item = playlist_ItemGetById( p_playlist, itemId( index ) ); playlist_item_t *p_item = playlist_ItemGetById( p_playlist, itemId( index, PLAYLIST_ID ) );
if( p_item ) if( p_item )
playlist_NodeCreate( p_playlist, qtu( name ), p_item, PLAYLIST_END, 0, NULL ); playlist_NodeCreate( p_playlist, qtu( name ), p_item, PLAYLIST_END, 0, NULL );
PL_UNLOCK; PL_UNLOCK;
} }
void PLModel::actionSlot( QAction *action ) void PLModel::action( QAction *action, const QModelIndexList &indexes )
{ {
QString name;
QStringList mrls;
QModelIndex index; QModelIndex index;
actionsContainerType a = action->data().value<actionsContainerType>(); actionsContainerType a = action->data().value<actionsContainerType>();
switch ( a.action ) switch ( a.action )
{ {
case actionsContainerType::ACTION_PLAY: case actionsContainerType::ACTION_PLAY:
PL_LOCK; if ( !indexes.empty() && indexes.first().isValid() )
{ activateItem( indexes.first() );
if ( a.indexes.first().isValid() )
{
playlist_item_t *p_item = playlist_ItemGetById( p_playlist,
itemId( a.indexes.first() ) );
activateItem( p_item );
}
}
PL_UNLOCK;
break; break;
case actionsContainerType::ACTION_ADDTOPLAYLIST: case actionsContainerType::ACTION_ADDTOPLAYLIST:
PL_LOCK; PL_LOCK;
foreach( QModelIndex currentIndex, a.indexes ) foreach( const QModelIndex &currentIndex, indexes )
{ {
playlist_item_t *p_item = playlist_ItemGetById( THEPL, itemId( currentIndex ) ); playlist_item_t *p_item = playlist_ItemGetById( THEPL, itemId( currentIndex, PLAYLIST_ID ) );
if( !p_item ) continue; if( !p_item ) continue;
playlist_NodeAddCopy( THEPL, p_item, playlist_NodeAddCopy( THEPL, p_item,
...@@ -1107,13 +1059,14 @@ void PLModel::actionSlot( QAction *action ) ...@@ -1107,13 +1059,14 @@ void PLModel::actionSlot( QAction *action )
break; break;
case actionsContainerType::ACTION_REMOVE: case actionsContainerType::ACTION_REMOVE:
doDelete( a.indexes ); doDelete( indexes );
break; break;
case actionsContainerType::ACTION_SORT: case actionsContainerType::ACTION_SORT:
index = a.indexes.first().parent(); if ( indexes.empty() ) break;
index = indexes.first().parent();
if( !index.isValid() ) index = rootIndex(); if( !index.isValid() ) index = rootIndex();
sort( a.indexes.first(), index, sort( indexes.first(), index,
a.column > 0 ? a.column - 1 : -a.column - 1, a.column > 0 ? a.column - 1 : -a.column - 1,
a.column > 0 ? Qt::AscendingOrder : Qt::DescendingOrder ); a.column > 0 ? Qt::AscendingOrder : Qt::DescendingOrder );
break; break;
......
...@@ -39,15 +39,93 @@ ...@@ -39,15 +39,93 @@
#include <QSignalMapper> #include <QSignalMapper>
#include <QMimeData> #include <QMimeData>
#include <QAbstractItemModel> #include <QAbstractItemModel>
#include <QSortFilterProxyModel>
#include <QVariant> #include <QVariant>
#include <QModelIndex> #include <QModelIndex>
#include <QTimer> #include <QTimer>
#include <QMutex> #include <QMutex>
#include <QAction>
class PLItem; class PLItem;
class PLSelector; class PLSelector;
class PlMimeData; class PlMimeData;
class VLCProxyModel : public QSortFilterProxyModel, public VLCModelSubInterface
{
Q_OBJECT
public:
VLCProxyModel( QObject *parent = 0 );
inline VLCModel *model() const
{
return qobject_cast<VLCModel *>( sourceModel() );
}
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 );
/* Different Models Handling */
/* 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 ); }
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 void sort( const int column, Qt::SortOrder order = Qt::AscendingOrder )
{
/* use native */
QSortFilterProxyModel::sort( column, order );
}
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 bool isCurrentItem( const QModelIndex &index, playLocation where ) const { return model()->isCurrentItem( mapToSource( index ), where ); }
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 ) ); }
virtual void action( QAction *action, const QModelIndexList &indexes )
{
model()->action( action, mapListToSource( indexes ) );
}
/* Indirect slots handlers */
virtual void activateItem( const QModelIndex &index ) { model()->activateItem( mapToSource( index ) ); }
virtual void ensureArtRequested( const QModelIndex &index ) { model()->ensureArtRequested( mapToSource( index ) ); }
virtual void clearPlaylist() { model()->clearPlaylist(); }
/* 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];
};
class PLModel : public VLCModel class PLModel : public VLCModel
{ {
Q_OBJECT Q_OBJECT
...@@ -75,8 +153,6 @@ public: ...@@ -75,8 +153,6 @@ public:
/* Data structure */ /* Data structure */
virtual QVariant data( const QModelIndex &index, const int role ) const; virtual QVariant data( const QModelIndex &index, const int role ) const;
virtual QVariant headerData( int section, Qt::Orientation orientation,
int role = Qt::DisplayRole ) const;
virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const; virtual int rowCount( const QModelIndex &parent = QModelIndex() ) const;
virtual Qt::ItemFlags flags( const QModelIndex &index ) const; virtual Qt::ItemFlags flags( const QModelIndex &index ) const;
virtual QModelIndex index( const int r, const int c, const QModelIndex &parent ) const; virtual QModelIndex index( const int r, const int c, const QModelIndex &parent ) const;
...@@ -92,36 +168,31 @@ public: ...@@ -92,36 +168,31 @@ public:
/* Sort */ /* Sort */
virtual void sort( const int column, Qt::SortOrder order = Qt::AscendingOrder ); virtual void sort( const int column, Qt::SortOrder order = Qt::AscendingOrder );
/**** Custom ****/ /*** VLCModelSubInterface subclassing ***/
virtual void rebuild( playlist_item_t * p = NULL );
virtual void doDelete( QModelIndexList selected );
virtual void createNode( QModelIndex index, QString name );
/* Lookups */ /* Lookups */
QModelIndex index( const int i_id, const int c );
virtual QModelIndex rootIndex() const; virtual QModelIndex rootIndex() const;
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;
virtual bool isTree() const; virtual bool isTree() const;
virtual bool canEdit() const; virtual bool canEdit() const;
virtual QModelIndex currentIndex() const;
int itemId( const QModelIndex &index ) const;
virtual input_item_t *getInputItem( const QModelIndex & ) const;
virtual QString getURI( const QModelIndex &index ) const;
QString getTitle( const QModelIndex &index ) const;
virtual bool isCurrentItem( const QModelIndex &index, playLocation where ) const; virtual bool isCurrentItem( const QModelIndex &index, playLocation where ) const;
virtual void action( QAction *action, const QModelIndexList &indexes );
/* */ /* VLCModelSubInterface indirect slots */
void search( const QString& search_text, const QModelIndex & root, bool b_recursive );
void rebuild( playlist_item_t * p = NULL );
virtual void doDelete( QModelIndexList selected );
virtual void createNode( QModelIndex index, QString name );
signals:
void currentIndexChanged( const QModelIndex& );
void rootIndexChanged();
public slots:
virtual void activateItem( const QModelIndex &index ); virtual void activateItem( const QModelIndex &index );
void clearPlaylist(); virtual void clearPlaylist();
void ensureArtRequested( const QModelIndex &index );
virtual void actionSlot( QAction *action ); protected:
/* VLCModel subclassing */
bool isParent( const QModelIndex &index, const QModelIndex &current) const;
bool isLeaf( const QModelIndex &index ) const;
PLItem *getItem( const QModelIndex & index ) const;
private: private:
/* General */ /* General */
...@@ -129,8 +200,6 @@ private: ...@@ -129,8 +200,6 @@ private:
playlist_t *p_playlist; playlist_t *p_playlist;
static QIcon icons[ITEM_TYPE_NUMBER];
/* single row linear inserts agregation */ /* single row linear inserts agregation */
void bufferedRowInsert( PLItem *item, PLItem *parent, int pos ); void bufferedRowInsert( PLItem *item, PLItem *parent, int pos );
bool isBufferedForInsert( PLItem *parent, int i_item ); bool isBufferedForInsert( PLItem *parent, int i_item );
...@@ -143,20 +212,11 @@ private: ...@@ -143,20 +212,11 @@ private:
/* Custom model private methods */ /* Custom model private methods */
/* Lookups */ /* Lookups */
PLItem *getItem( const QModelIndex & index ) const
{
if( index.isValid() )
return static_cast<PLItem*>( index.internalPointer() );
else return rootItem;
}
QModelIndex index( PLItem *, const int c ) const; QModelIndex index( PLItem *, const int c ) const;
bool isCurrent( const QModelIndex &index ) const;
bool isParent( const QModelIndex &index, const QModelIndex &current) const;
/* Shallow actions (do not affect core playlist) */ /* Shallow actions (do not affect core playlist) */
void updateTreeItem( PLItem * ); void updateTreeItem( PLItem * );
void removeItem ( PLItem * ); void removeItem ( PLItem * );
void removeItem( int );
void recurseDelete( QList<AbstractPLItem*> children, QModelIndexList *fullList ); void recurseDelete( QList<AbstractPLItem*> children, QModelIndexList *fullList );
void takeItem( PLItem * ); //will not delete item void takeItem( PLItem * ); //will not delete item
void insertChildren( PLItem *node, QList<PLItem*>& items, int i_pos ); void insertChildren( PLItem *node, QList<PLItem*>& items, int i_pos );
...@@ -172,14 +232,9 @@ private: ...@@ -172,14 +232,9 @@ private:
void sort( QModelIndex caller, QModelIndex rootIndex, const int column, Qt::SortOrder order ); void sort( QModelIndex caller, QModelIndex rootIndex, const int column, Qt::SortOrder order );
/* Lookups */ /* Lookups */
PLItem *findById( PLItem *, int ) const; PLItem *findByPLId( PLItem *, int i_plitemid ) const;
PLItem *findByInput( PLItem *, int ) const; PLItem *findByInputId( PLItem *, int i_input_itemid ) const;
PLItem *findInner(PLItem *, int , bool ) const; PLItem *findInner(PLItem *, int i_id, bool b_isinputid ) const;
PLItem *p_cached_item;
PLItem *p_cached_item_bi;
int i_cached_id;
int i_cached_input_id;
/* */ /* */
QString latestSearch; QString latestSearch;
...@@ -187,8 +242,8 @@ private: ...@@ -187,8 +242,8 @@ private:
private slots: private slots:
void processInputItemUpdate( input_item_t *); void processInputItemUpdate( input_item_t *);
void processInputItemUpdate( input_thread_t* p_input ); void processInputItemUpdate( input_thread_t* p_input );
void processItemRemoval( int i_id ); void processItemRemoval( int i_pl_itemid );
void processItemAppend( int item, int parent ); void processItemAppend( int i_pl_itemid, int i_pl_itemidparent );
void commitBufferedRowInserts(); void commitBufferedRowInserts();
void activateItem( playlist_item_t *p_item ); void activateItem( playlist_item_t *p_item );
}; };
......
...@@ -64,15 +64,16 @@ ...@@ -64,15 +64,16 @@
#include <assert.h> #include <assert.h>
/* local helper */
inline QModelIndex popupIndex( QAbstractItemView *view );
StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent, StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent,
intf_thread_t *_p_intf, intf_thread_t *_p_intf,
playlist_item_t *p_root, playlist_item_t *p_root,
PLSelector *_p_selector, PLSelector *_p_selector,
PLModel *_p_model, VLCProxyModel *_p_model )
MLModel *_p_plmodel)
: QWidget( _parent ), : QWidget( _parent ),
model( _p_model ), model( _p_model ),
mlmodel( _p_plmodel),
p_intf( _p_intf ), p_intf( _p_intf ),
p_selector( _p_selector ) p_selector( _p_selector )
{ {
...@@ -85,8 +86,8 @@ StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent, ...@@ -85,8 +86,8 @@ StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent,
listView = NULL; listView = NULL;
picFlowView = NULL; picFlowView = NULL;
currentRootIndexId = -1; currentRootIndexPLId = -1;
lastActivatedId = -1; lastActivatedPLItemId = -1;
QList<QString> frames; QList<QString> frames;
frames << ":/util/wait1"; frames << ":/util/wait1";
...@@ -105,9 +106,9 @@ StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent, ...@@ -105,9 +106,9 @@ StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent,
DCONNECT( THEMIM, leafBecameParent( int ), DCONNECT( THEMIM, leafBecameParent( int ),
this, browseInto( int ) ); this, browseInto( int ) );
CONNECT( model, currentIndexChanged( const QModelIndex& ), CONNECT( model->sigs, currentIndexChanged( const QModelIndex& ),
this, handleExpansion( const QModelIndex& ) ); this, handleExpansion( const QModelIndex& ) );
CONNECT( model, rootIndexChanged(), this, browseInto() ); CONNECT( model->sigs, rootIndexChanged(), this, browseInto() );
setRootItem( p_root, false ); setRootItem( p_root, false );
} }
...@@ -131,46 +132,36 @@ void StandardPLPanel::gotoPlayingItem() ...@@ -131,46 +132,36 @@ void StandardPLPanel::gotoPlayingItem()
void StandardPLPanel::handleExpansion( const QModelIndex& index ) void StandardPLPanel::handleExpansion( const QModelIndex& index )
{ {
assert( currentView ); assert( currentView );
if( currentRootIndexId != -1 && currentRootIndexId != model->itemId( index.parent() ) ) if( currentRootIndexPLId != -1 && currentRootIndexPLId != model->itemId( index.parent(), PLAYLIST_ID ) )
browseInto( index.parent() ); browseInto( index.parent() );
currentView->scrollTo( index ); currentView->scrollTo( index );
} }
void StandardPLPanel::popupPlView( const QPoint &point ) void StandardPLPanel::popupPlView( const QPoint &point )
{ {
QModelIndex index = currentView->indexAt( point );
QPoint globalPoint = currentView->viewport()->mapToGlobal( point ); QPoint globalPoint = currentView->viewport()->mapToGlobal( point );
QItemSelectionModel *selection = currentView->selectionModel(); if( !popup( globalPoint ) ) VLCMenuBar::PopupMenu( p_intf, true );
QModelIndexList list = selection->selectedRows();
if( !popup( index, globalPoint, list ) )
VLCMenuBar::PopupMenu( p_intf, true );
} }
/*********** Popup *********/ /*********** Popup *********/
bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, const QModelIndexList &selectionlist ) bool StandardPLPanel::popup( const QPoint &point )
{ {
VLCModel *model = qobject_cast<VLCModel*>(currentView->model()); QModelIndex index = popupIndex( currentView ); /* index for menu logic only. Do not store.*/
QModelIndexList callerAsList; #define ADD_MENU_ENTRY( icon, title, act ) \
callerAsList << ( index.isValid() ? index : QModelIndex() );
popupIndex = index; /* suitable for modal only */
#define ADD_MENU_ENTRY( icon, title, act, data ) \
action = menu.addAction( icon, title ); \ action = menu.addAction( icon, title ); \
container.action = act; \ container.action = act; \
container.indexes = data; \
action->setData( QVariant::fromValue( container ) ) action->setData( QVariant::fromValue( container ) )
/* */ /* */
QMenu menu; QMenu menu;
QAction *action; QAction *action;
PLModel::actionsContainerType container; VLCModelSubInterface::actionsContainerType container;
/* Play/Stream/Info static actions */ /* Play/Stream/Info static actions */
if( index.isValid() ) if( index.isValid() )
{ {
ADD_MENU_ENTRY( QIcon( ":/menu/play" ), qtr(I_POP_PLAY), ADD_MENU_ENTRY( QIcon( ":/menu/play" ), qtr(I_POP_PLAY),
container.ACTION_PLAY, callerAsList ); container.ACTION_PLAY );
menu.addAction( QIcon( ":/menu/stream" ), qtr(I_POP_STREAM), menu.addAction( QIcon( ":/menu/stream" ), qtr(I_POP_STREAM),
this, SLOT( popupStream() ) ); this, SLOT( popupStream() ) );
...@@ -198,13 +189,13 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con ...@@ -198,13 +189,13 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
this, SLOT( popupPromptAndCreateNode() ) ); this, SLOT( popupPromptAndCreateNode() ) );
menu.addSeparator(); menu.addSeparator();
if( model->isCurrentItem( model->rootIndex(), PLModel::IN_PLAYLIST ) ) if( model->isCurrentItem( model->rootIndex(), VLCModelSubInterface::IN_PLAYLIST ) )
{ {
menu.addAction( addIcon, qtr(I_PL_ADDF), THEDP, SLOT( simplePLAppendDialog()) ); menu.addAction( addIcon, qtr(I_PL_ADDF), THEDP, SLOT( simplePLAppendDialog()) );
menu.addAction( addIcon, qtr(I_PL_ADDDIR), THEDP, SLOT( PLAppendDir()) ); menu.addAction( addIcon, qtr(I_PL_ADDDIR), THEDP, SLOT( PLAppendDir()) );
menu.addAction( addIcon, qtr(I_OP_ADVOP), THEDP, SLOT( PLAppendDialog()) ); menu.addAction( addIcon, qtr(I_OP_ADVOP), THEDP, SLOT( PLAppendDialog()) );
} }
else if( model->isCurrentItem( model->rootIndex(), PLModel::IN_MEDIALIBRARY ) ) else if( model->isCurrentItem( model->rootIndex(), VLCModelSubInterface::IN_MEDIALIBRARY ) )
{ {
menu.addAction( addIcon, qtr(I_PL_ADDF), THEDP, SLOT( simpleMLAppendDialog()) ); menu.addAction( addIcon, qtr(I_PL_ADDF), THEDP, SLOT( simpleMLAppendDialog()) );
menu.addAction( addIcon, qtr(I_PL_ADDDIR), THEDP, SLOT( MLAppendDir() ) ); menu.addAction( addIcon, qtr(I_PL_ADDDIR), THEDP, SLOT( MLAppendDir() ) );
...@@ -214,10 +205,10 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con ...@@ -214,10 +205,10 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
if( index.isValid() ) if( index.isValid() )
{ {
if( !model->isCurrentItem( model->rootIndex(), PLModel::IN_PLAYLIST ) ) if( !model->isCurrentItem( model->rootIndex(), VLCModelSubInterface::IN_PLAYLIST ) )
{ {
ADD_MENU_ENTRY( QIcon(), qtr(I_PL_ADDPL), ADD_MENU_ENTRY( QIcon(), qtr(I_PL_ADDPL),
container.ACTION_ADDTOPLAYLIST, selectionlist ); container.ACTION_ADDTOPLAYLIST );
} }
} }
...@@ -227,12 +218,12 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con ...@@ -227,12 +218,12 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
if( index.isValid() ) if( index.isValid() )
{ {
ADD_MENU_ENTRY( QIcon( ":/buttons/playlist/playlist_remove" ), qtr(I_POP_DEL), ADD_MENU_ENTRY( QIcon( ":/buttons/playlist/playlist_remove" ), qtr(I_POP_DEL),
container.ACTION_REMOVE, selectionlist ); container.ACTION_REMOVE );
} }
if( model->canEdit() ) { if( model->canEdit() ) {
menu.addAction( QIcon( ":/toolbar/clear" ), qtr("Clear the playlist"), menu.addAction( QIcon( ":/toolbar/clear" ), qtr("Clear the playlist"),
model, SLOT( clearPlaylist() ) ); model->sigs, SLOT( clearPlaylistSlot() ) );
} }
menu.addSeparator(); menu.addSeparator();
...@@ -243,7 +234,6 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con ...@@ -243,7 +234,6 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
QList<int> sortingColumns; QList<int> sortingColumns;
sortingColumns << COLUMN_TITLE << COLUMN_ARTIST << COLUMN_ALBUM << COLUMN_TRACK_NUMBER << COLUMN_URI; sortingColumns << COLUMN_TITLE << COLUMN_ARTIST << COLUMN_ALBUM << COLUMN_TRACK_NUMBER << COLUMN_URI;
container.action = container.ACTION_SORT; container.action = container.ACTION_SORT;
container.indexes = callerAsList;
foreach( int Column, sortingColumns ) foreach( int Column, sortingColumns )
{ {
action = sortingMenu->addAction( qfu( psz_column_title( Column ) ) + " " + qtr("Ascending") ); action = sortingMenu->addAction( qfu( psz_column_title( Column ) ) + " " + qtr("Ascending") );
...@@ -262,7 +252,7 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con ...@@ -262,7 +252,7 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
zoomMenu->addAction( qtr( "Decrease" ), this, SLOT( decreaseZoom() ) ); zoomMenu->addAction( qtr( "Decrease" ), this, SLOT( decreaseZoom() ) );
menu.addMenu( zoomMenu ); menu.addMenu( zoomMenu );
CONNECT( &menu, triggered( QAction * ), model, actionSlot( QAction * ) ); CONNECT( &menu, triggered( QAction * ), this, popupAction( QAction * ) );
menu.addMenu( StandardPLPanel::viewSelectionMenu( this ) ); menu.addMenu( StandardPLPanel::viewSelectionMenu( this ) );
...@@ -276,6 +266,12 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con ...@@ -276,6 +266,12 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
#undef ADD_MENU_ENTRY #undef ADD_MENU_ENTRY
} }
void StandardPLPanel::popupAction( QAction *action )
{
QModelIndexList list = currentView->selectionModel()->selectedRows();
model->action( action, list );
}
QMenu* StandardPLPanel::viewSelectionMenu( StandardPLPanel *panel ) QMenu* StandardPLPanel::viewSelectionMenu( StandardPLPanel *panel )
{ {
QMenu *viewMenu = new QMenu( qtr( "Playlist View Mode" ) ); QMenu *viewMenu = new QMenu( qtr( "Playlist View Mode" ) );
...@@ -297,6 +293,15 @@ QMenu* StandardPLPanel::viewSelectionMenu( StandardPLPanel *panel ) ...@@ -297,6 +293,15 @@ QMenu* StandardPLPanel::viewSelectionMenu( StandardPLPanel *panel )
return viewMenu; return viewMenu;
} }
inline QModelIndex popupIndex( QAbstractItemView *view )
{
QModelIndexList list = view->selectionModel()->selectedIndexes();
if ( list.isEmpty() )
return QModelIndex();
else
return list.first();
}
void StandardPLPanel::popupSelectColumn( QPoint ) void StandardPLPanel::popupSelectColumn( QPoint )
{ {
QMenu menu; QMenu menu;
...@@ -322,15 +327,16 @@ void StandardPLPanel::popupPromptAndCreateNode() ...@@ -322,15 +327,16 @@ void StandardPLPanel::popupPromptAndCreateNode()
qtr( I_NEW_DIR ), qtr( I_NEW_DIR_NAME ), qtr( I_NEW_DIR ), qtr( I_NEW_DIR_NAME ),
QLineEdit::Normal, QString(), &ok); QLineEdit::Normal, QString(), &ok);
if ( !ok ) return; if ( !ok ) return;
qobject_cast<VLCModel *>(currentView->model())->createNode( popupIndex, name ); qobject_cast<VLCProxyModel *>(currentView->model())->createNode( popupIndex( currentView ), name );
} }
void StandardPLPanel::popupInfoDialog() void StandardPLPanel::popupInfoDialog()
{ {
if( popupIndex.isValid() ) QModelIndex index = popupIndex( currentView );
if( index.isValid() )
{ {
VLCModel *model = qobject_cast<VLCModel *>(currentView->model()); VLCProxyModel *model = qobject_cast<VLCProxyModel *>(currentView->model());
input_item_t* p_input = model->getInputItem( popupIndex ); input_item_t* p_input = model->getInputItem( index );
MediaInfoDialog *mid = new MediaInfoDialog( p_intf, p_input ); MediaInfoDialog *mid = new MediaInfoDialog( p_intf, p_input );
mid->setParent( PlaylistDialog::getInstance( p_intf ), mid->setParent( PlaylistDialog::getInstance( p_intf ),
Qt::Dialog ); Qt::Dialog );
...@@ -340,8 +346,8 @@ void StandardPLPanel::popupInfoDialog() ...@@ -340,8 +346,8 @@ void StandardPLPanel::popupInfoDialog()
void StandardPLPanel::popupExplore() void StandardPLPanel::popupExplore()
{ {
VLCModel *model = qobject_cast<VLCModel *>(currentView->model()); VLCProxyModel *model = qobject_cast<VLCProxyModel *>(currentView->model());
QString uri = model->getURI( popupIndex ); QString uri = model->getURI( popupIndex( currentView ) );
char *path = NULL; char *path = NULL;
if( ! uri.isEmpty() ) if( ! uri.isEmpty() )
...@@ -358,16 +364,16 @@ void StandardPLPanel::popupExplore() ...@@ -358,16 +364,16 @@ void StandardPLPanel::popupExplore()
void StandardPLPanel::popupStream() void StandardPLPanel::popupStream()
{ {
VLCModel *model = qobject_cast<VLCModel *>(currentView->model()); VLCProxyModel *model = qobject_cast<VLCProxyModel *>(currentView->model());
QString uri = model->getURI( popupIndex ); QString uri = model->getURI( popupIndex( currentView ) );
if ( ! uri.isEmpty() ) if ( ! uri.isEmpty() )
THEDP->streamingDialog( NULL, uri, false ); THEDP->streamingDialog( NULL, uri, false );
} }
void StandardPLPanel::popupSave() void StandardPLPanel::popupSave()
{ {
VLCModel *model = qobject_cast<VLCModel *>(currentView->model()); VLCProxyModel *model = qobject_cast<VLCProxyModel *>(currentView->model());
QString uri = model->getURI( popupIndex ); QString uri = model->getURI( popupIndex( currentView ) );
if ( ! uri.isEmpty() ) if ( ! uri.isEmpty() )
THEDP->streamingDialog( NULL, uri ); THEDP->streamingDialog( NULL, uri );
} }
...@@ -390,7 +396,7 @@ void StandardPLPanel::search( const QString& searchText ) ...@@ -390,7 +396,7 @@ void StandardPLPanel::search( const QString& searchText )
bool flat = ( currentView == iconView || bool flat = ( currentView == iconView ||
currentView == listView || currentView == listView ||
currentView == picFlowView ); currentView == picFlowView );
model->search( searchText, model->filter( searchText,
flat ? currentView->rootIndex() : QModelIndex(), flat ? currentView->rootIndex() : QModelIndex(),
!flat ); !flat );
} }
...@@ -419,16 +425,16 @@ void StandardPLPanel::setRootItem( playlist_item_t *p_item, bool b ) ...@@ -419,16 +425,16 @@ void StandardPLPanel::setRootItem( playlist_item_t *p_item, bool b )
if( b ) if( b )
{ {
msg_Dbg( p_intf, "Setting the SQL ML" ); msg_Dbg( p_intf, "Setting the SQL ML" );
currentView->setModel( mlmodel ); if ( model->switchToModel( VLCProxyModel::SQLML_MODEL ) )
currentView->setModel( model );
} }
else else
#else #else
Q_UNUSED( b ); Q_UNUSED( b );
#endif #endif
{ {
if( currentView->model() != model ) if ( model->switchToModel( VLCProxyModel::PL_MODEL ) )
currentView->setModel( model ); model->rebuild( p_item );
model->rebuild( p_item );
} }
} }
...@@ -441,14 +447,15 @@ void StandardPLPanel::browseInto( const QModelIndex &index ) ...@@ -441,14 +447,15 @@ void StandardPLPanel::browseInto( const QModelIndex &index )
/* When going toward root in LocationBar, scroll to the item /* When going toward root in LocationBar, scroll to the item
that was previously as root */ that was previously as root */
QModelIndex newIndex = model->index(currentRootIndexId,0); QModelIndex newIndex = model->indexByPLID(currentRootIndexPLId,0);
while( newIndex.isValid() && (newIndex.parent() != index) ) while( newIndex.isValid() && (newIndex.parent() != index) )
newIndex = newIndex.parent(); newIndex = newIndex.parent();
if( newIndex.isValid() ) if( newIndex.isValid() )
currentView->scrollTo( newIndex ); currentView->scrollTo( newIndex );
/* Store new rootindexid*/ /* Store new rootindexid*/
currentRootIndexId = model->itemId( index ); currentRootIndexPLId = model->itemId( index, PLAYLIST_ID );
model->ensureArtRequested( index ); model->ensureArtRequested( index );
} }
...@@ -457,8 +464,8 @@ void StandardPLPanel::browseInto( const QModelIndex &index ) ...@@ -457,8 +464,8 @@ void StandardPLPanel::browseInto( const QModelIndex &index )
void StandardPLPanel::browseInto() void StandardPLPanel::browseInto()
{ {
browseInto( (currentRootIndexId != -1 && currentView != treeView) ? browseInto( (currentRootIndexPLId != -1 && currentView != treeView) ?
model->index( currentRootIndexId, 0 ) : model->indexByPLID( currentRootIndexPLId, 0 ) :
QModelIndex() ); QModelIndex() );
} }
...@@ -532,8 +539,7 @@ bool StandardPLPanel::eventFilter ( QObject *obj, QEvent * event ) ...@@ -532,8 +539,7 @@ bool StandardPLPanel::eventFilter ( QObject *obj, QEvent * event )
void StandardPLPanel::deleteSelection() void StandardPLPanel::deleteSelection()
{ {
QItemSelectionModel *selection = currentView->selectionModel(); QModelIndexList list = currentView->selectionModel()->selectedIndexes();
QModelIndexList list = selection->selectedIndexes();
model->doDelete( list ); model->doDelete( list );
} }
...@@ -614,23 +620,6 @@ void StandardPLPanel::updateZoom( int i ) ...@@ -614,23 +620,6 @@ void StandardPLPanel::updateZoom( int i )
#undef A_ZOOM #undef A_ZOOM
} }
void StandardPLPanel::changeModel( bool b_ml )
{
#ifdef MEDIA_LIBRARY
VLCModel *mod;
if( b_ml )
mod = mlmodel;
else
mod = model;
if( currentView->model() != mod )
currentView->setModel( mod );
#else
Q_UNUSED( b_ml );
if( currentView->model() != model )
currentView->setModel( model );
#endif
}
void StandardPLPanel::showView( int i_view ) void StandardPLPanel::showView( int i_view )
{ {
bool b_treeViewCreated = false; bool b_treeViewCreated = false;
...@@ -671,7 +660,7 @@ void StandardPLPanel::showView( int i_view ) ...@@ -671,7 +660,7 @@ void StandardPLPanel::showView( int i_view )
} }
} }
changeModel( false ); currentView->setModel( model );
/* Restoring the header Columns must come after changeModel */ /* Restoring the header Columns must come after changeModel */
if( b_treeViewCreated ) if( b_treeViewCreated )
...@@ -755,7 +744,7 @@ void StandardPLPanel::activate( const QModelIndex &index ) ...@@ -755,7 +744,7 @@ void StandardPLPanel::activate( const QModelIndex &index )
if( currentView->model() == model ) if( currentView->model() == model )
{ {
/* If we are not a leaf node */ /* If we are not a leaf node */
if( !index.data( PLModel::IsLeafNodeRole ).toBool() ) if( !index.data( VLCModelSubInterface::IsLeafNodeRole ).toBool() )
{ {
if( currentView != treeView ) if( currentView != treeView )
browseInto( index ); browseInto( index );
...@@ -763,25 +752,26 @@ void StandardPLPanel::activate( const QModelIndex &index ) ...@@ -763,25 +752,26 @@ void StandardPLPanel::activate( const QModelIndex &index )
else else
{ {
playlist_Lock( THEPL ); playlist_Lock( THEPL );
playlist_item_t *p_item = playlist_ItemGetById( THEPL, model->itemId( index ) ); playlist_item_t *p_item = playlist_ItemGetById( THEPL, model->itemId( index, PLAYLIST_ID ) );
p_item->i_flags |= PLAYLIST_SUBITEM_STOP_FLAG; p_item->i_flags |= PLAYLIST_SUBITEM_STOP_FLAG;
lastActivatedId = p_item->i_id; lastActivatedPLItemId = p_item->i_id;
playlist_Unlock( THEPL ); playlist_Unlock( THEPL );
model->activateItem( index ); if ( index.isValid() )
model->activateItem( index );
} }
} }
} }
void StandardPLPanel::browseInto( int i_id ) void StandardPLPanel::browseInto( int i_pl_item_id )
{ {
if( i_id != lastActivatedId ) return; if( i_pl_item_id != lastActivatedPLItemId ) return;
QModelIndex index = model->index( i_id, 0 ); QModelIndex index = model->indexByPLID( i_pl_item_id, 0 );
if( currentView == treeView ) if( currentView == treeView )
treeView->setExpanded( index, true ); treeView->setExpanded( index, true );
else else
browseInto( index ); browseInto( index );
lastActivatedId = -1; lastActivatedPLItemId = -1;
} }
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "qt4.hpp" #include "qt4.hpp"
#include "components/playlist/playlist.hpp" #include "components/playlist/playlist.hpp"
#include "components/playlist/vlc_model.hpp"
#include <QWidget> #include <QWidget>
#include <QModelIndexList> #include <QModelIndexList>
...@@ -37,8 +38,7 @@ ...@@ -37,8 +38,7 @@
#include <vlc_playlist.h> /* playlist_item_t */ #include <vlc_playlist.h> /* playlist_item_t */
class QSignalMapper; class QSignalMapper;
class PLModel; class VLCProxyModel;
class MLModel;
class QKeyEvent; class QKeyEvent;
class QWheelEvent; class QWheelEvent;
class QStackedLayout; class QStackedLayout;
...@@ -50,7 +50,6 @@ class PlIconView; ...@@ -50,7 +50,6 @@ class PlIconView;
class PlListView; class PlListView;
class PicFlowView; class PicFlowView;
class LocationBar;
class PLSelector; class PLSelector;
class PlaylistWidget; class PlaylistWidget;
class PixmapAnimator; class PixmapAnimator;
...@@ -61,7 +60,7 @@ class StandardPLPanel: public QWidget ...@@ -61,7 +60,7 @@ class StandardPLPanel: public QWidget
public: public:
StandardPLPanel( PlaylistWidget *, intf_thread_t *, StandardPLPanel( PlaylistWidget *, intf_thread_t *,
playlist_item_t *, PLSelector *, PLModel *, MLModel * ); playlist_item_t *, PLSelector *, VLCProxyModel * );
virtual ~StandardPLPanel(); virtual ~StandardPLPanel();
enum { ICON_VIEW = 0, enum { ICON_VIEW = 0,
...@@ -75,10 +74,9 @@ public: ...@@ -75,10 +74,9 @@ public:
static QMenu *viewSelectionMenu(StandardPLPanel *obj); static QMenu *viewSelectionMenu(StandardPLPanel *obj);
protected: protected:
PLModel *model; VLCProxyModel *model;
MLModel *mlmodel;
virtual void wheelEvent( QWheelEvent *e ); virtual void wheelEvent( QWheelEvent *e );
bool popup( const QModelIndex & index, const QPoint &point, const QModelIndexList &selectionlist ); bool popup( const QPoint &point );
private: private:
intf_thread_t *p_intf; intf_thread_t *p_intf;
...@@ -97,20 +95,16 @@ private: ...@@ -97,20 +95,16 @@ private:
QSignalMapper *selectColumnsSigMapper; QSignalMapper *selectColumnsSigMapper;
int lastActivatedId; int lastActivatedPLItemId;
int currentRootIndexId; int currentRootIndexPLId;
void createTreeView(); void createTreeView();
void createIconView(); void createIconView();
void createListView(); void createListView();
void createCoverView(); void createCoverView();
void updateZoom( int i_zoom ); void updateZoom( int i_zoom );
void changeModel ( bool b_ml );
bool eventFilter ( QObject * watched, QEvent * event ); bool eventFilter ( QObject * watched, QEvent * event );
/* for popup */
QModelIndex popupIndex; /* FIXME: don't store here, pass as Action param */
/* Wait spinner */ /* Wait spinner */
PixmapAnimator *spinnerAnimation; PixmapAnimator *spinnerAnimation;
...@@ -140,6 +134,7 @@ private slots: ...@@ -140,6 +134,7 @@ private slots:
void popupExplore(); void popupExplore();
void popupStream(); void popupStream();
void popupSave(); void popupSave();
void popupAction( QAction * );
void increaseZoom() { updateZoom( i_zoom + 1 ); }; void increaseZoom() { updateZoom( i_zoom + 1 ); };
void decreaseZoom() { updateZoom( i_zoom - 1 ); }; void decreaseZoom() { updateZoom( i_zoom - 1 ); };
void toggleColumnShown( int ); void toggleColumnShown( int );
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
*****************************************************************************/ *****************************************************************************/
#include "components/playlist/views.hpp" #include "components/playlist/views.hpp"
#include "components/playlist/playlist_model.hpp" /* PLModel */ #include "components/playlist/vlc_model.hpp" /* VLCModel */
#include "components/playlist/sorting.h" /* Columns List */ #include "components/playlist/sorting.h" /* Columns List */
#include "input_manager.hpp" /* THEMIM */ #include "input_manager.hpp" /* THEMIM */
...@@ -58,7 +58,7 @@ void AbstractPlViewItemDelegate::paintBackground( ...@@ -58,7 +58,7 @@ void AbstractPlViewItemDelegate::paintBackground(
painter->setPen( option.palette.color( QPalette::Highlight ).darker( 150 ) ); painter->setPen( option.palette.color( QPalette::Highlight ).darker( 150 ) );
painter->drawRect( r ); painter->drawRect( r );
} }
else if( index.data( PLModel::IsCurrentRole ).toBool() ) else if( index.data( VLCModel::IsCurrentRole ).toBool() )
{ {
painter->setBrush( QBrush( Qt::lightGray ) ); painter->setBrush( QBrush( Qt::lightGray ) );
painter->setPen( QColor( Qt::darkGray ) ); painter->setPen( QColor( Qt::darkGray ) );
...@@ -81,7 +81,7 @@ void PlIconViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt ...@@ -81,7 +81,7 @@ void PlIconViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt
QFont font( index.data( Qt::FontRole ).value<QFont>() ); QFont font( index.data( Qt::FontRole ).value<QFont>() );
font.setPointSize( __MAX( font.pointSize() + i_zoom, 4 ) ); font.setPointSize( __MAX( font.pointSize() + i_zoom, 4 ) );
font.setBold( index.data( PLModel::IsCurrentRole ).toBool() ); font.setBold( index.data( VLCModel::IsCurrentRole ).toBool() );
painter->setFont( font ); painter->setFont( font );
QFontMetrics fm = painter->fontMetrics(); QFontMetrics fm = painter->fontMetrics();
...@@ -120,12 +120,12 @@ void PlIconViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt ...@@ -120,12 +120,12 @@ void PlIconViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt
//Draw children indicator //Draw children indicator
if( !index.data( PLModel::IsLeafNodeRole ).toBool() ) if( !index.data( VLCModel::IsLeafNodeRole ).toBool() )
{ {
QRect r( option.rect ); QRect r( option.rect );
r.setSize( QSize( 25, 25 ) ); r.setSize( QSize( 25, 25 ) );
r.translate( 5, 5 ); r.translate( 5, 5 );
if( index.data( PLModel::IsCurrentsParentNodeRole ).toBool() ) if( index.data( VLCModel::IsCurrentsParentNodeRole ).toBool() )
{ {
painter->setOpacity( 0.75 ); painter->setOpacity( 0.75 );
QPainterPath nodeRectPath; QPainterPath nodeRectPath;
...@@ -222,7 +222,7 @@ void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt ...@@ -222,7 +222,7 @@ void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt
//Draw title info //Draw title info
f.setItalic( true ); f.setItalic( true );
f.setPointSize( __MAX( f.pointSize() + i_zoom, 4 ) ); f.setPointSize( __MAX( f.pointSize() + i_zoom, 4 ) );
f.setBold( index.data( PLModel::IsCurrentRole ).toBool() ); f.setBold( index.data( VLCModel::IsCurrentRole ).toBool() );
painter->setFont( f ); painter->setFont( f );
QFontMetrics fm( painter->fontMetrics() ); QFontMetrics fm( painter->fontMetrics() );
...@@ -234,7 +234,7 @@ void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt ...@@ -234,7 +234,7 @@ void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt
} }
//Draw children indicator //Draw children indicator
if( !index.data( PLModel::IsLeafNodeRole ).toBool() ) if( !index.data( VLCModel::IsLeafNodeRole ).toBool() )
{ {
QPixmap dirPix = QPixmap( ":/type/node" ); QPixmap dirPix = QPixmap( ":/type/node" );
painter->drawPixmap( QPoint( textRect.x(), textRect.center().y() - dirPix.height() / 2 ), painter->drawPixmap( QPoint( textRect.x(), textRect.center().y() - dirPix.height() / 2 ),
...@@ -276,7 +276,7 @@ QSize PlListViewItemDelegate::sizeHint ( const QStyleOptionViewItem &, const QMo ...@@ -276,7 +276,7 @@ QSize PlListViewItemDelegate::sizeHint ( const QStyleOptionViewItem &, const QMo
void PlTreeViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const void PlTreeViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const
{ {
if ( index.data( PLModel::IsCurrentRole ).toBool() ) if ( index.data( VLCModel::IsCurrentRole ).toBool() )
{ {
QStyleOptionViewItem myoptions = option; QStyleOptionViewItem myoptions = option;
myoptions.font.setBold( true ); myoptions.font.setBold( true );
...@@ -305,7 +305,7 @@ static void plViewDragMoveEvent( QAbstractItemView *, QDragMoveEvent * event ) ...@@ -305,7 +305,7 @@ static void plViewDragMoveEvent( QAbstractItemView *, QDragMoveEvent * event )
else event->acceptProposedAction(); else event->acceptProposedAction();
} }
PlIconView::PlIconView( PLModel *, QWidget *parent ) : QListView( parent ) PlIconView::PlIconView( QAbstractItemModel *, QWidget *parent ) : QListView( parent )
{ {
PlIconViewItemDelegate *delegate = new PlIconViewItemDelegate( this ); PlIconViewItemDelegate *delegate = new PlIconViewItemDelegate( this );
...@@ -355,7 +355,7 @@ bool PlIconView::viewportEvent ( QEvent * event ) ...@@ -355,7 +355,7 @@ bool PlIconView::viewportEvent ( QEvent * event )
return QAbstractItemView::viewportEvent( event ); return QAbstractItemView::viewportEvent( event );
} }
PlListView::PlListView( PLModel *, QWidget *parent ) : QListView( parent ) PlListView::PlListView( QAbstractItemModel *, QWidget *parent ) : QListView( parent )
{ {
setViewMode( QListView::ListMode ); setViewMode( QListView::ListMode );
setUniformItemSizes( true ); setUniformItemSizes( true );
...@@ -412,7 +412,7 @@ bool PlListView::viewportEvent ( QEvent * event ) ...@@ -412,7 +412,7 @@ bool PlListView::viewportEvent ( QEvent * event )
return QAbstractItemView::viewportEvent( event ); return QAbstractItemView::viewportEvent( event );
} }
PlTreeView::PlTreeView( PLModel *, QWidget *parent ) : QTreeView( parent ) PlTreeView::PlTreeView( QAbstractItemModel *, QWidget *parent ) : QTreeView( parent )
{ {
setItemDelegate( new PlTreeViewItemDelegate( this ) ); setItemDelegate( new PlTreeViewItemDelegate( this ) );
...@@ -443,8 +443,9 @@ PlTreeView::PlTreeView( PLModel *, QWidget *parent ) : QTreeView( parent ) ...@@ -443,8 +443,9 @@ PlTreeView::PlTreeView( PLModel *, QWidget *parent ) : QTreeView( parent )
void PlTreeView::setModel( QAbstractItemModel * model ) void PlTreeView::setModel( QAbstractItemModel * model )
{ {
QTreeView::setModel( model ); QTreeView::setModel( model );
VLCModel *m = static_cast<VLCModel*>(model);
CONNECT( this, expanded( const QModelIndex & ), CONNECT( this, expanded( const QModelIndex & ),
model, ensureArtRequested( const QModelIndex & ) ); m->sigs, ensureArtRequestedSlot( const QModelIndex & ) );
} }
void PlTreeView::startDrag ( Qt::DropActions supportedActions ) void PlTreeView::startDrag ( Qt::DropActions supportedActions )
...@@ -470,7 +471,7 @@ void PlTreeView::keyPressEvent( QKeyEvent *event ) ...@@ -470,7 +471,7 @@ void PlTreeView::keyPressEvent( QKeyEvent *event )
} }
#include <QHBoxLayout> #include <QHBoxLayout>
PicFlowView::PicFlowView( PLModel *p_model, QWidget *parent ) : QAbstractItemView( parent ) PicFlowView::PicFlowView( QAbstractItemModel *p_model, QWidget *parent ) : QAbstractItemView( parent )
{ {
QHBoxLayout *layout = new QHBoxLayout( this ); QHBoxLayout *layout = new QHBoxLayout( this );
layout->setMargin( 0 ); layout->setMargin( 0 );
......
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
#include "util/pictureflow.hpp" #include "util/pictureflow.hpp"
class QPainter; class QPainter;
class PLModel;
class QFont; class QFont;
class AbstractPlViewItemDelegate : public QStyledItemDelegate class AbstractPlViewItemDelegate : public QStyledItemDelegate
...@@ -84,7 +83,7 @@ class PlIconView : public QListView ...@@ -84,7 +83,7 @@ class PlIconView : public QListView
Q_OBJECT Q_OBJECT
public: public:
PlIconView( PLModel *model, QWidget *parent = 0 ); PlIconView( QAbstractItemModel *model, QWidget *parent = 0 );
protected: protected:
virtual void startDrag ( Qt::DropActions supportedActions ); virtual void startDrag ( Qt::DropActions supportedActions );
virtual void dragMoveEvent ( QDragMoveEvent * event ); virtual void dragMoveEvent ( QDragMoveEvent * event );
...@@ -96,7 +95,7 @@ class PlListView : public QListView ...@@ -96,7 +95,7 @@ class PlListView : public QListView
Q_OBJECT Q_OBJECT
public: public:
PlListView( PLModel *model, QWidget *parent = 0 ); PlListView( QAbstractItemModel *model, QWidget *parent = 0 );
protected: protected:
virtual void startDrag ( Qt::DropActions supportedActions ); virtual void startDrag ( Qt::DropActions supportedActions );
virtual void dragMoveEvent ( QDragMoveEvent * event ); virtual void dragMoveEvent ( QDragMoveEvent * event );
...@@ -109,7 +108,7 @@ class PlTreeView : public QTreeView ...@@ -109,7 +108,7 @@ class PlTreeView : public QTreeView
Q_OBJECT Q_OBJECT
public: public:
PlTreeView( PLModel *, QWidget *parent = 0 ); PlTreeView( QAbstractItemModel *, QWidget *parent = 0 );
protected: protected:
virtual void startDrag ( Qt::DropActions supportedActions ); virtual void startDrag ( Qt::DropActions supportedActions );
virtual void dragMoveEvent ( QDragMoveEvent * event ); virtual void dragMoveEvent ( QDragMoveEvent * event );
...@@ -121,7 +120,7 @@ class PicFlowView : public QAbstractItemView ...@@ -121,7 +120,7 @@ class PicFlowView : public QAbstractItemView
{ {
Q_OBJECT Q_OBJECT
public: public:
PicFlowView( PLModel *model, QWidget *parent = 0 ); PicFlowView( QAbstractItemModel *model, QWidget *parent = 0 );
virtual QRect visualRect(const QModelIndex&) const; virtual QRect visualRect(const QModelIndex&) const;
virtual void scrollTo(const QModelIndex&, QAbstractItemView::ScrollHint); virtual void scrollTo(const QModelIndex&, QAbstractItemView::ScrollHint);
......
...@@ -22,14 +22,52 @@ ...@@ -22,14 +22,52 @@
*****************************************************************************/ *****************************************************************************/
#include "vlc_model.hpp" #include "vlc_model.hpp"
#include "input_manager.hpp" /* THEMIM */
#include "pixmaps/types/type_unknown.xpm"
VLCModelSubInterface::VLCModelSubInterface()
{
sigs = new VLCModelSignalsHandler( this );
}
VLCModelSubInterface::~VLCModelSubInterface()
{
delete sigs;
}
int VLCModelSubInterface::columnFromMeta( int meta_col )
{
int meta = 1, column = 0;
while( meta != meta_col && meta != COLUMN_END )
{
meta <<= 1;
column++;
}
return column;
}
VLCModel::VLCModel( intf_thread_t *_p_intf, QObject *parent ) VLCModel::VLCModel( intf_thread_t *_p_intf, QObject *parent )
: QAbstractItemModel( parent ), p_intf(_p_intf) : QAbstractItemModel( parent ), VLCModelSubInterface(), p_intf(_p_intf)
{ {
/* Icons initialization */
#define ADD_ICON(type, x) icons[ITEM_TYPE_##type] = QIcon( x )
ADD_ICON( UNKNOWN , type_unknown_xpm );
ADD_ICON( FILE, ":/type/file" );
ADD_ICON( DIRECTORY, ":/type/directory" );
ADD_ICON( DISC, ":/type/disc" );
ADD_ICON( CDDA, ":/type/cdda" );
ADD_ICON( CARD, ":/type/capture-card" );
ADD_ICON( NET, ":/type/net" );
ADD_ICON( PLAYLIST, ":/type/playlist" );
ADD_ICON( NODE, ":/type/node" );
#undef ADD_ICON
} }
VLCModel::~VLCModel() VLCModel::~VLCModel()
{ {
} }
QString VLCModel::getMeta( const QModelIndex & index, int meta ) QString VLCModel::getMeta( const QModelIndex & index, int meta )
...@@ -77,8 +115,93 @@ QPixmap VLCModel::getArtPixmap( const QModelIndex & index, const QSize & size ) ...@@ -77,8 +115,93 @@ QPixmap VLCModel::getArtPixmap( const QModelIndex & index, const QSize & size )
return artPix; return artPix;
} }
QVariant VLCModel::headerData( int section, Qt::Orientation orientation,
int role ) const
{
if (orientation != Qt::Horizontal || role != Qt::DisplayRole)
return QVariant();
int meta_col = columnToMeta( section );
if( meta_col == COLUMN_END ) return QVariant();
return QVariant( qfu( psz_column_title( meta_col ) ) );
}
int VLCModel::columnToMeta( int _column )
{
int meta = 1, column = 0;
while( column != _column && meta != COLUMN_END )
{
meta <<= 1;
column++;
}
return meta;
}
int VLCModel::itemId( const QModelIndex &index, int type ) const
{
AbstractPLItem *item = getItem( index );
if ( !item ) return -1;
return item->id( type );
}
AbstractPLItem *VLCModel::getItem( const QModelIndex &index ) const
{
if( index.isValid() )
return static_cast<AbstractPLItem*>( index.internalPointer() );
else return NULL;
}
QString VLCModel::getURI( const QModelIndex &index ) const
{
AbstractPLItem *item = getItem( index );
if ( !item ) return QString();
return item->getURI().toString();
}
input_item_t * VLCModel::getInputItem( const QModelIndex &index ) const
{
AbstractPLItem *item = getItem( index );
if ( !item ) return NULL;
return item->inputItem();
}
QString VLCModel::getTitle( const QModelIndex &index ) const
{
AbstractPLItem *item = getItem( index );
if ( !item ) return QString();
return item->getTitle();
}
bool VLCModel::isCurrent( const QModelIndex &index ) const
{
AbstractPLItem *item = getItem( index );
if ( !item ) return false;
return item->inputItem() == THEMIM->currentInputItem();
}
int VLCModel::columnCount( const QModelIndex & ) const int VLCModel::columnCount( const QModelIndex & ) const
{ {
return columnFromMeta( COLUMN_END ); return columnFromMeta( COLUMN_END );
} }
void VLCModel::ensureArtRequested( const QModelIndex &index )
{
if ( index.isValid() && hasChildren( index ) )
{
int i_art_policy = var_GetInteger( THEPL, "album-art" );
if ( i_art_policy != ALBUM_ART_ALL ) return;
int nbnodes = rowCount( index );
QModelIndex child;
for( int row = 0 ; row < nbnodes ; row++ )
{
child = index.child( row, 0 );
if ( child.isValid() && getArtUrl( child ).isEmpty() )
THEMIM->getIM()->requestArtUpdate( getInputItem( child ) );
}
}
}
...@@ -31,47 +31,61 @@ ...@@ -31,47 +31,61 @@
#include "qt4.hpp" #include "qt4.hpp"
#include "sorting.h" #include "sorting.h"
#include "playlist_item.hpp"
#include <vlc_input.h> #include <vlc_input.h>
#include <QModelIndex> #include <QModelIndex>
#include <QPixmapCache> #include <QPixmapCache>
#include <QSize> #include <QSize>
#include <QObject>
#include <QAbstractItemModel> #include <QAbstractItemModel>
class QAction; #include <QIcon>
class VLCModel : public QAbstractItemModel class QAction;
class VLCModelSignalsHandler;
/* Provides non Q_Object interface for Models.
This allows multiple inheritance on already QAbstractModel based
Qobjects like Q*ProxyModel.
Signals being a Q_Object property, they need to be redirected
using a QObject based class member.
*/
class VLCModelSubInterface
{ {
Q_OBJECT
public: public:
enum { VLCModelSubInterface();
IsCurrentRole = Qt::UserRole, virtual ~VLCModelSubInterface();
IsLeafNodeRole, virtual void rebuild( playlist_item_t * p = NULL ) = 0;
IsCurrentsParentNodeRole
};
VLCModel( intf_thread_t *_p_intf, QObject *parent = 0 );
/*** QAbstractItemModel subclassing ***/
virtual int columnCount( const QModelIndex &parent = QModelIndex() ) const;
virtual int itemId( const QModelIndex & ) const = 0;
virtual input_item_t *getInputItem( const QModelIndex & ) const = 0;
virtual QModelIndex currentIndex() const = 0;
virtual void doDelete( QModelIndexList ) = 0; virtual void doDelete( QModelIndexList ) = 0;
virtual ~VLCModel(); virtual void createNode( QModelIndex, QString ) = 0;
static QString getMeta( const QModelIndex & index, int meta );
static QPixmap getArtPixmap( const QModelIndex & index, const QSize & size );
static QString getArtUrl( const QModelIndex & index );
virtual QString getURI( const QModelIndex &index ) const = 0;
virtual QModelIndex rootIndex() const = 0; virtual QModelIndex rootIndex() const = 0;
virtual void filter( const QString& search_text, const QModelIndex & root, bool b_recursive ) = 0;
virtual void sort( const int column, Qt::SortOrder order = Qt::AscendingOrder ) = 0;
virtual QModelIndex currentIndex() const = 0;
virtual QModelIndex indexByPLID( const int i_plid, const int c ) const = 0;
virtual QModelIndex indexByInputItemID( const int i_inputitem_id, const int c ) const = 0;
virtual int itemId( const QModelIndex &, int type ) const = 0;
virtual bool isTree() const = 0; virtual bool isTree() const = 0;
virtual bool canEdit() const = 0; virtual bool canEdit() const = 0;
enum playLocation enum playLocation
{ {
IN_PLAYLIST, IN_PLAYLIST,
IN_MEDIALIBRARY IN_MEDIALIBRARY,
IN_SQLMEDIALIB
}; };
virtual bool isCurrentItem( const QModelIndex &index, playLocation where ) const = 0; virtual bool isCurrentItem( const QModelIndex &index, playLocation where ) const = 0;
virtual QString getURI( const QModelIndex &index ) const = 0;
virtual input_item_t *getInputItem( const QModelIndex & ) const = 0;
virtual QString getTitle( const QModelIndex &index ) const = 0;
virtual void action( QAction *, const QModelIndexList & ) = 0;
enum nodeRole {
IsCurrentRole = Qt::UserRole,
IsLeafNodeRole,
IsCurrentsParentNodeRole
};
struct actionsContainerType struct actionsContainerType
{ {
enum enum
...@@ -81,46 +95,83 @@ public: ...@@ -81,46 +95,83 @@ public:
ACTION_REMOVE, ACTION_REMOVE,
ACTION_SORT ACTION_SORT
} action; } action;
QModelIndexList indexes; /* for passing selection or caller index(es) */
int column; /* for sorting */ int column; /* for sorting */
}; };
static int columnFromMeta( int meta_col );
static int columnToMeta( int _column ) VLCModelSignalsHandler *sigs;
{ /* Indirect slots handlers */
int meta = 1, column = 0; virtual void activateItem( const QModelIndex &index ) = 0;
virtual void ensureArtRequested( const QModelIndex &index ) = 0;
virtual void clearPlaylist() = 0;
};
while( column != _column && meta != COLUMN_END ) class VLCModelSignalsHandler : public QObject
{ {
meta <<= 1; Q_OBJECT
column++;
}
return meta; public:
} VLCModelSignalsHandler( VLCModelSubInterface *_parent ) { parent = _parent; }
static int columnFromMeta( int meta_col ) void emit_currentIndexChanged( const QModelIndex &index ) { emit currentIndexChanged( index ); }
{ void emit_rootIndexChanged() { emit rootIndexChanged(); }
int meta = 1, column = 0;
while( meta != meta_col && meta != COLUMN_END ) public slots:
{ void activateItemSlot( const QModelIndex &index ) { parent->activateItem( index ); }
meta <<= 1; void ensureArtRequestedSlot( const QModelIndex &index ) { parent->ensureArtRequested( index ); }
column++; void clearPlaylistSlot() { parent->clearPlaylist(); }
}
return column; signals:
} void currentIndexChanged( const QModelIndex& );
void rootIndexChanged();
virtual void createNode( QModelIndex, QString ) {}; private:
VLCModelSubInterface *parent;
};
public slots: /* Abstract VLC Model ; Base for custom models.
virtual void activateItem( const QModelIndex &index ) = 0; Only implements methods sharing the same code that would be
virtual void actionSlot( QAction *action ) = 0; implemented in subclasses.
Any custom method here must be only used in implemented methods.
*/
class VLCModel : public QAbstractItemModel, public VLCModelSubInterface
{
Q_OBJECT
public:
VLCModel( intf_thread_t *_p_intf, QObject *parent = 0 );
virtual ~VLCModel();
/*** QAbstractItemModel subclassing ***/
virtual int columnCount( const QModelIndex &parent = QModelIndex() ) const;
QVariant headerData( int, Qt::Orientation, int ) const;
/*** VLCModelSubInterface subclassing ***/
virtual int itemId( const QModelIndex &, int type ) const;
virtual QString getURI( const QModelIndex &index ) const;
virtual input_item_t *getInputItem( const QModelIndex & ) const;
virtual QString getTitle( const QModelIndex &index ) const;
/* VLCModelSubInterface Indirect slots handlers */
virtual void ensureArtRequested( const QModelIndex &index );
/* Custom */
static int columnToMeta( int _column );
static QString getMeta( const QModelIndex & index, int meta );
static QPixmap getArtPixmap( const QModelIndex & index, const QSize & size );
static QString getArtUrl( const QModelIndex & index );
protected: protected:
/* Custom methods / helpers */
virtual bool isCurrent( const QModelIndex &index ) const;
virtual bool isParent( const QModelIndex &index, const QModelIndex &current ) const = 0;
virtual bool isLeaf( const QModelIndex &index ) const = 0;
virtual AbstractPLItem *getItem( const QModelIndex & index ) const;
QIcon icons[ITEM_TYPE_NUMBER];
intf_thread_t *p_intf; intf_thread_t *p_intf;
}; };
Q_DECLARE_METATYPE(VLCModel::actionsContainerType) Q_DECLARE_METATYPE(VLCModelSubInterface::actionsContainerType)
#endif #endif
...@@ -494,26 +494,16 @@ QRect PictureFlowSoftwareRenderer::renderSlide(const SlideInfo &slide, int col1, ...@@ -494,26 +494,16 @@ QRect PictureFlowSoftwareRenderer::renderSlide(const SlideInfo &slide, int col1,
QString artURL; QString artURL;
PLModel* plm = qobject_cast<PLModel*>( state->model ); VLCModel *m = static_cast<VLCModel*>( state->model );
#ifdef MEDIA_LIBRARY
MLModel* mlm = qobject_cast<MLModel*>( state->model ); if( m )
#endif
if( plm != 0 )
{
index = ((PLModel*)state->model)->index( slide.slideIndex, 0, state->model->currentIndex().parent() );
if( !index.isValid() )
return QRect();
artURL = plm->data( index, COLUMN_COVER ).toString();
}
#ifdef MEDIA_LIBRARY
else if( mlm != 0 )
{ {
index = ((MLModel*)state->model)->index( slide.slideIndex, 0, QModelIndex() ); index = m->index( slide.slideIndex, 0, m->currentIndex().parent() );
if( !index.isValid() ) if( !index.isValid() )
return QRect(); return QRect();
artURL = mlm->data( index, COLUMN_COVER ).toString(); artURL = m->data( index, COLUMN_COVER ).toString();
} }
#endif
QString key = QString("%1%2%3%4").arg(VLCModel::getMeta( index, COLUMN_TITLE )).arg( VLCModel::getMeta( index, COLUMN_ARTIST ) ).arg(index.data( VLCModel::IsCurrentRole ).toBool() ).arg( artURL ); QString key = QString("%1%2%3%4").arg(VLCModel::getMeta( index, COLUMN_TITLE )).arg( VLCModel::getMeta( index, COLUMN_ARTIST ) ).arg(index.data( VLCModel::IsCurrentRole ).toBool() ).arg( artURL );
QImage* src; QImage* src;
...@@ -643,7 +633,7 @@ void PictureFlowSoftwareRenderer::render() ...@@ -643,7 +633,7 @@ void PictureFlowSoftwareRenderer::render()
// ----------------------------------------- // -----------------------------------------
PictureFlow::PictureFlow(QWidget* parent, VLCModel* _p_model): QWidget(parent) PictureFlow::PictureFlow(QWidget* parent, QAbstractItemModel* _p_model): QWidget(parent)
{ {
d = new PictureFlowPrivate; d = new PictureFlowPrivate;
d->picrole = Qt::DecorationRole; d->picrole = Qt::DecorationRole;
......
...@@ -81,7 +81,7 @@ public: ...@@ -81,7 +81,7 @@ public:
/*! /*!
Creates a new PictureFlow widget. Creates a new PictureFlow widget.
*/ */
PictureFlow(QWidget* parent = 0, VLCModel *model = 0); PictureFlow(QWidget* parent = 0, QAbstractItemModel *model = 0);
/*! /*!
Destroys the widget. Destroys the widget.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment