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 )
}
MLItem::MLItem( const MLModel *p_model,
intf_thread_t* _p_intf,
MLItem::MLItem( intf_thread_t* _p_intf,
ml_media_t *p_media,
MLItem *p_parent )
: p_intf( _p_intf ), model( p_model )
{
parentItem = p_parent;
if( p_media )
......@@ -119,18 +117,9 @@ AbstractPLItem* MLItem::child( int row ) const
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()
{
return ml_CreateInputItem( p_ml, id() );
return ml_CreateInputItem( p_ml, id( MLMEDIA_ID ) );
}
/**
......@@ -139,13 +128,12 @@ input_item_t* MLItem::inputItem()
* @return The QVariant may be formed of a int, QString
* 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;
QString qsz_return;
#define sreturn(a) if(media->a) return qfu(media->a); break
switch( type )
switch( columntype )
{
case ML_ALBUM: sreturn( psz_album );
case ML_ALBUM_ID: return media->i_album_id;
......@@ -166,7 +154,10 @@ QVariant MLItem::data( int column ) const
break;
case ML_COVER: sreturn( psz_cover );
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_GENRE: sreturn( psz_genre );
case ML_ID: return media->i_id;
......@@ -194,9 +185,11 @@ QVariant MLItem::data( int column ) const
return qsz_return;
else
{
vlc_mutex_lock( &media->lock );
QFileInfo p_file = QFileInfo( qfu( media->psz_uri ) );
vlc_mutex_unlock( &media->lock );
QUrl uri = getURI();
if ( uri.scheme() != "file" )
return QUrl::fromPercentEncoding( getURI().toString().toUtf8() );
QFileInfo p_file( uri.toLocalFile() );
return p_file.fileName().isEmpty() ? p_file.absoluteFilePath()
: p_file.fileName();
}
......@@ -249,20 +242,21 @@ bool MLItem::setData( ml_select_e meta, const QVariant &data )
case ML_ARTIST: ml_DeletePersonTypeFromMedia( media, ML_PERSON_ARTIST );
ml_CreateAppendPersonAdv( &media->p_people,
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;
case ML_EXTRA: setmeta( psz_extra );
case ML_GENRE: setmeta( psz_genre );
case ML_ORIGINAL_TITLE: setmeta( psz_orig_title );
case ML_TITLE: setmeta( psz_title );
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;
/* Modifiable integers */
case ML_TRACK_NUMBER:
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;
// TODO case ML_VOTE:
......@@ -274,9 +268,19 @@ update:
# 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
......@@ -284,19 +288,28 @@ ml_media_t* MLItem::getMedia() const
return media;
}
QUrl MLItem::getUri() const
QUrl MLItem::getURI() const
{
QString uri;
vlc_mutex_lock( &media->lock );
uri = QString( media->psz_uri );
uri = qfu( media->psz_uri );
vlc_mutex_unlock( &media->lock );
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" );
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 )
{
int ret = compareMeta( getMedia(), item->getMedia(), ML_ALBUM );
......
......@@ -49,28 +49,26 @@ class MLItem : public AbstractPLItem
friend class MLModel;
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 );
virtual ~MLItem();
bool operator<( MLItem* item );
private:
/* AbstractPLItem */
int id() const;
int id( int type );
input_item_t *inputItem();
AbstractPLItem* child( int row ) const;
virtual QUrl getURI() const;
virtual QString getTitle() const;
/* Local */
void delChild( int row );
QVariant data( int column ) const;
QVariant data( ml_select_e meta ) const;
bool setData( ml_select_e meta, const QVariant &data );
// Media structure connections
ml_media_t* getMedia() const;
QUrl getUri() const;
ml_media_t* media;
intf_thread_t* p_intf;
const MLModel *model;
media_library_t* p_ml;
};
......
......@@ -34,6 +34,7 @@
#include <QUrl>
#include <QMenu>
#include <QMimeData>
#include <QApplication>
#include "ml_item.hpp"
#include "ml_model.hpp"
#include "dialogs/playlist.hpp"
......@@ -54,6 +55,14 @@ static int mediaUpdated( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval,
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
* @param parent the parent Qt object
......@@ -65,6 +74,7 @@ MLModel::MLModel( intf_thread_t* _p_intf, QObject *parent )
if ( !p_ml ) return;
vlc_array_t *p_result_array = vlc_array_new();
if ( p_result_array )
{
ml_Find( p_ml, p_result_array, ML_MEDIA );
......@@ -89,16 +99,35 @@ MLModel::~MLModel()
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();
if( rows > 0 )
{
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();
endRemoveRows();
emit layoutChanged();
}
vlc_array_destroy( p_where );
reset();
}
QModelIndex MLModel::index( int row, int column,
......@@ -118,6 +147,17 @@ QModelIndex MLModel::parent(const QModelIndex & ) const
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
*/
......@@ -126,16 +166,33 @@ QModelIndex MLModel::currentIndex() const
input_thread_t *p_input_thread = THEMIM->getInput();
if( !p_input_thread ) return QModelIndex();
/*TODO: O(n) not good */
input_item_t* p_iitem = input_GetItem( p_input_thread );
int i = 0;
foreach( MLItem* item, items )
{
if( !QString::compare( item->getUri().toString(),
QString::fromAscii( p_iitem->psz_uri ) ) )
return index( items.indexOf( item ), 0 );
if ( item->inputItem() == p_iitem )
return index( i, 0 );
i++;
}
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
* @param column must be valid
......@@ -147,15 +204,6 @@ ml_select_e MLModel::columnType( int logicalindex ) const
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
{
if( !index.isValid() )
......@@ -214,8 +262,8 @@ QMimeData* MLModel::mimeData( const QModelIndexList &indexes ) const
if( rows.contains( idx.row() ) )
continue;
rows.append( idx.row() );
MLItem* item = static_cast<MLItem*>( idx.internalPointer() );
urls.append( item->getUri() );
AbstractPLItem* item = static_cast<AbstractPLItem*>( idx.internalPointer() );
urls.append( item->getURI() );
}
QMimeData *data = new QMimeData;
data->setUrls( urls );
......@@ -229,41 +277,34 @@ int MLModel::rowCount( const QModelIndex & parent ) const
return 0;
}
void MLModel::remove( MLItem *item )
void MLModel::rebuild( playlist_item_t *p )
{
int row = items.indexOf( item );
remove( createIndex( row, 0 ) );
Q_UNUSED( p );
emit layoutChanged();
}
void MLModel::doDelete( QModelIndexList list )
{
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 );
/* 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() )
return;
else
{
beginRemoveRows( createIndex( 0, 0 ), idx.row(), idx.row() );
items.removeAt( idx.row() );
endRemoveRows();
}
}
int MLModel::itemId( const QModelIndex &index ) const
{
return getItem( index )->id();
}
input_item_t * MLModel::getInputItem( const QModelIndex &index ) const
{
return getItem( index )->inputItem();
/* !warn probably not a good idea to expose this as public method */
if ( row < 0 || count < 0 ) return false;
beginRemoveRows( parent, row, row );
MLItem *item = items.takeAt( row );
assert( item );
if ( likely( item ) ) delete item;
endRemoveRows();
return true;
}
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() );
if( !it ) return QVariant();
QVariant tmp = it->data( index.column() );
QVariant tmp = it->data( columnType( index.column() ) );
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 )
return QVariant( true );
return isLeaf( index );
else if( role == IsCurrentsParentNodeRole )
return QVariant( false );
return isParent( index, currentIndex() );
else if( role == IsCurrentRole )
{
return QVariant( isCurrent( index ) );
}
}
return QVariant();
}
......@@ -299,12 +352,9 @@ bool MLModel::setData( const QModelIndex &idx, const QVariant &value,
* @brief Insert a media to the model in a given row
* @param p_media the media to append
* @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
*/
int MLModel::insertMedia( ml_media_t *p_media, int row,
bool bSignal )
int MLModel::insertMedia( ml_media_t *p_media, int row )
{
// Some checks
if( !p_media || row < -1 || row > rowCount() )
......@@ -313,105 +363,19 @@ int MLModel::insertMedia( ml_media_t *p_media, int row,
if( row == -1 )
row = rowCount();
if( bSignal )
beginInsertRows( createIndex( -1, -1 ), row, row );
// 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 );
if( bSignal )
endInsertRows();
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
* @param p_result_array the medias to append
* @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 row, bool bSignal )
int MLModel::insertResultArray( vlc_array_t *p_result_array, int row )
{
int i_ok = VLC_SUCCESS;
int count = vlc_array_count( p_result_array );
......@@ -419,12 +383,12 @@ int MLModel::insertResultArray( vlc_array_t *p_result_array,
if( !count )
return i_ok;
emit layoutAboutToBeChanged();
if( row == -1 )
row = rowCount();
// 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
for( int i = 0; i < count; ++i )
......@@ -433,17 +397,50 @@ int MLModel::insertResultArray( vlc_array_t *p_result_array,
vlc_array_item_at_index( p_result_array, i );
if( !p_result || p_result->type != ML_TYPE_MEDIA )
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 )
break;
}
// Signal we're done
if( bSignal )
endInsertRows();
endInsertRows();
emit layoutChanged();
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
*
......@@ -496,46 +493,33 @@ static void AddItemToPlaylist( int i_media_id, bool bPlay, media_library_t* p_ml
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>();
switch ( a.action )
{
case actionsContainerType::ACTION_PLAY:
play( a.indexes.first() );
if ( ! indexes.empty() && indexes.first().isValid() )
activateItem( indexes.first() );
break;
case actionsContainerType::ACTION_ADDTOPLAYLIST:
foreach( const QModelIndex &index, indexes )
{
if( !index.isValid() ) break;
AddItemToPlaylist( itemId( index, MLMEDIA_ID ), false, p_ml, true );
}
break;
case actionsContainerType::ACTION_REMOVE:
doDelete( a.indexes );
doDelete( indexes );
break;
case actionsContainerType::ACTION_SORT:
......@@ -563,9 +547,8 @@ bool MLModel::canEdit() const
bool MLModel::isCurrentItem( const QModelIndex &index, playLocation where ) const
{
Q_UNUSED( index );
if ( where == IN_MEDIALIBRARY )
return true;
if ( where == IN_SQLMEDIALIB )
return index.isValid();
return false;
}
......@@ -575,31 +558,39 @@ QModelIndex MLModel::getIndexByMLID( int id ) const
{
QModelIndex idx = index( i, 0 );
MLItem *item = static_cast< MLItem* >( idx.internalPointer() );
if( item->id() == id )
return idx;
if( item->id( MLMEDIA_ID ) == id ) return idx;
}
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,
vlc_value_t oldval, vlc_value_t newval,
void *data )
{
VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
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 );
postMLEvent( p_this, MLEvent::MediaAdded_Type, data, newval.i_int );
return VLC_SUCCESS;
}
......@@ -607,12 +598,8 @@ static int mediaDeleted( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval,
void *data )
{
VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
MLModel* p_model = ( MLModel* )data;
QModelIndex remove_idx = p_model->getIndexByMLID( newval.i_int );
if( remove_idx.isValid() )
p_model->remove( remove_idx );
VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
postMLEvent( p_this, MLEvent::MediaRemoved_Type, data, newval.i_int );
return VLC_SUCCESS;
}
......@@ -620,9 +607,8 @@ static int mediaUpdated( vlc_object_t *p_this, char const *psz_var,
vlc_value_t oldval, vlc_value_t newval,
void *data )
{
VLC_UNUSED( p_this ); VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
VLC_UNUSED( newval ); VLC_UNUSED( data );
VLC_UNUSED( psz_var ); VLC_UNUSED( oldval );
postMLEvent( p_this, MLEvent::MediaUpdated_Type, data, newval.i_int );
return VLC_SUCCESS;
}
......
......@@ -41,8 +41,25 @@
#include "ml_item.hpp"
#include "qt4.hpp"
#include <QMutex>
#include <QEvent>
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
****************************************************************************/
......@@ -55,69 +72,57 @@ public:
MLModel( intf_thread_t *_p_intf, QObject *parent = NULL );
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;
bool setData( const QModelIndex &idx, const QVariant &value,
int role = Qt::EditRole );
ml_select_e columnType( int column ) const;
QModelIndex index( int row, int column,
const QModelIndex & parent = QModelIndex() ) const;
virtual QModelIndex currentIndex() const;
int rowCount( const QModelIndex & parent = QModelIndex() ) const;
QModelIndex parent( const QModelIndex& ) const;
QVariant headerData( int, Qt::Orientation, int ) const;
Qt::ItemFlags flags( const QModelIndex& ) const;
bool isEditable( const QModelIndex& ) const;
// Drag and drop: MIME data
QMimeData* mimeData( const QModelIndexList & indexes ) const;
virtual bool removeRows( int row, int count, const QModelIndex & parent = QModelIndex() );
// Custom functions
int insertMedia( ml_media_t *p_media, int row = -1,
bool bSignal = true );
int appendMedia( ml_media_t *p_media );
int insertMediaArray( vlc_array_t *p_media_array, int row = -1,
bool bSignal = true );
int insertResult( const ml_result_t *p_result, int row = -1,
bool bSignal = true );
inline int appendResult( const ml_result_t *p_result );
int insertResultArray( vlc_array_t *p_result_array, int row = -1,
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;
bool isEditable( const QModelIndex& ) const;
ml_select_e columnType( int column ) const;
virtual bool event( QEvent * e );
QModelIndex getIndexByMLID( int id ) const;
/* VLCModelSubInterface */
virtual void rebuild( playlist_item_t * p = NULL );
virtual void doDelete( QModelIndexList selected );
virtual void createNode( QModelIndex, QString ) {};
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 canEdit() 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:
void activateItem( const QModelIndex &index );
virtual void actionSlot( QAction *action );
/* VLCModelSubInterface virtual slots */
virtual void activateItem( const QModelIndex &index );
virtual void clearPlaylist();
protected:
void remove( MLItem *item );
inline MLItem *getItem( QModelIndex index ) const
{
if( index.isValid() )
return static_cast<MLItem*>( index.internalPointer() );
else return NULL;
}
/* VLCModel subclassing */
bool isParent( const QModelIndex &index, const QModelIndex &current) const;
bool isLeaf( const QModelIndex &index ) const;
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;
media_library_t* p_ml;
};
#endif
......
......@@ -94,14 +94,19 @@ PlaylistWidget::PlaylistWidget( intf_thread_t *_p_i, QWidget *_par )
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
MLModel *mlmodel = new MLModel( p_intf, this );
mainView = new StandardPLPanel( this, p_intf, p_root, selector, model, mlmodel );
#else
mainView = new StandardPLPanel( this, p_intf, p_root, selector, model, NULL );
MLModel *mlmodel = new MLModel( p_intf, model );
model->setModel( VLCProxyModel::SQLML_MODEL, mlmodel );
#endif
mainView = new StandardPLPanel( this, p_intf, p_root, selector, model );
/* Location Bar */
locationBar = new LocationBar( model );
locationBar->setSizePolicy( QSizePolicy::Ignored, QSizePolicy::Preferred );
......@@ -228,20 +233,15 @@ void PlaylistWidget::forceShow()
void PlaylistWidget::changeView( const QModelIndex& index )
{
searchEdit->clear();
locationBar->setIndex( index );
}
void PlaylistWidget::clearPlaylist()
{
PLModel::getPLModel( p_intf )->clearPlaylist();
}
#include <QSignalMapper>
#include <QMenu>
#include <QPainter>
LocationBar::LocationBar( PLModel *m )
LocationBar::LocationBar( VLCProxyModel *m )
{
model = m;
setModel( m );
mapper = new QSignalMapper( this );
CONNECT( mapper, mapped( int ), this, invoke( int ) );
......@@ -272,7 +272,7 @@ void LocationBar::setIndex( const QModelIndex &index )
actions.append( action );
CONNECT( btn, clicked(), action, trigger() );
mapper->setMapping( action, model->itemId( i ) );
mapper->setMapping( action, model->itemId( i, PLAYLIST_ID ) );
CONNECT( action, triggered(), mapper, map() );
first = false;
......@@ -298,7 +298,7 @@ void LocationBar::setRootIndex()
void LocationBar::invoke( int i_id )
{
QModelIndex index = model->index( i_id, 0 );
QModelIndex index = model->indexByPLID( i_id, 0 );
emit invoked ( index );
}
......
......@@ -77,7 +77,6 @@ protected:
virtual void closeEvent( QCloseEvent * );
private slots:
void changeView( const QModelIndex& index );
void clearPlaylist();
friend class PlaylistDialog;
};
......@@ -119,14 +118,16 @@ private:
bool b_arrow;
};
class PLModel;
class VLCProxyModel;
class QHBoxLayout;
class LocationBar : public QWidget
{
Q_OBJECT
public:
LocationBar( PLModel * );
LocationBar( VLCProxyModel * );
void setIndex( const QModelIndex & );
void setModel( VLCProxyModel * _model ) { model = _model; };
virtual QSize sizeHint() const;
protected:
virtual void resizeEvent ( QResizeEvent * event );
......@@ -134,7 +135,7 @@ protected:
private:
void layOut( const QSize& size );
PLModel *model;
VLCProxyModel *model;
QSignalMapper *mapper;
QWidgetList buttons;
QList<QAction*> actions;
......
......@@ -41,6 +41,12 @@ void AbstractPLItem::clearChildren()
children.clear();
}
void AbstractPLItem::removeChild( AbstractPLItem *item )
{
children.removeOne( item );
delete item;
}
/*
Playlist item is just a wrapper, an abstraction of the playlist_item
in order to be managed by PLModel
......@@ -51,8 +57,8 @@ void AbstractPLItem::clearChildren()
void PLItem::init( playlist_item_t *_playlist_item, PLItem *parent )
{
parentItem = parent; /* Can be NULL, but only for the rootItem */
i_id = _playlist_item->i_id; /* Playlist item specific id */
p_input = _playlist_item->p_input;
i_playlist_id = _playlist_item->i_id; /* Playlist item specific id */
p_input = _playlist_item->p_input;
vlc_gc_incref( p_input );
}
......@@ -77,10 +83,19 @@ PLItem::~PLItem()
children.clear();
}
void PLItem::removeChild( PLItem *item )
int PLItem::id( int type )
{
children.removeOne( item );
delete item;
switch( type )
{
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 )
......@@ -98,7 +113,7 @@ int PLItem::row()
return 0;
}
bool PLItem::operator< ( PLItem& other )
bool PLItem::operator< ( AbstractPLItem& other )
{
AbstractPLItem *item1 = this;
while( item1->parentItem )
......@@ -117,3 +132,26 @@ bool PLItem::operator< ( PLItem& other )
}
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 @@
#endif
#include <QList>
#include <QString>
#include <QUrl>
enum
{
INPUTITEM_ID = 1,
PLAYLIST_ID,
MLMEDIA_ID
};
class AbstractPLItem
{
friend class PLItem; /* super ugly glue stuff */
friend class MLItem;
friend class VLCModel;
friend class PLModel;
friend class MLModel;
......@@ -41,7 +51,7 @@ public:
virtual ~AbstractPLItem() {}
protected:
virtual int id() const = 0;
virtual int id( int type ) = 0;
int childCount() const { return children.count(); }
int indexOf( AbstractPLItem *item ) const { return children.indexOf( item ); };
int lastIndexOf( AbstractPLItem *item ) const { return children.lastIndexOf( item ); };
......@@ -50,7 +60,10 @@ protected:
void insertChild( AbstractPLItem *item, int pos = -1 ) { children.insert( pos, item ); }
void appendChild( AbstractPLItem *item ) { insertChild( item, children.count() ); } ;
virtual AbstractPLItem *child( int id ) const = 0;
void removeChild( AbstractPLItem *item );
void clearChildren();
virtual QUrl getURI() const = 0;
virtual QString getTitle() const = 0;
QList<AbstractPLItem *> children;
AbstractPLItem *parentItem;
......@@ -63,23 +76,24 @@ class PLItem : public AbstractPLItem
public:
virtual ~PLItem();
bool hasSameParent( PLItem *other ) { return parent() == other->parent(); }
bool operator< ( PLItem& );
bool operator< ( AbstractPLItem& );
private:
/* AbstractPLItem */
int id() const { return i_id; };
int id( int type );
input_item_t *inputItem() { return p_input; }
AbstractPLItem *child( int id ) const { return children.value( id ); };
virtual QUrl getURI() const;
virtual QString getTitle() const;
/* Local */
PLItem( playlist_item_t *, PLItem *parent );
int row();
void removeChild( PLItem * );
void takeChildAt( int );
PLItem( playlist_item_t * );
void init( playlist_item_t *, PLItem * );
int i_id;
int i_playlist_id;
input_item_t *p_input;
};
......
......@@ -33,17 +33,62 @@
#include <vlc_intf_strings.h> /* I_DIR */
#include "pixmaps/types/type_unknown.xpm"
#include "sorting.h"
#include <assert.h>
#include <QIcon>
#include <QFont>
#include <QTimer>
#include <QAction>
#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
......@@ -56,25 +101,10 @@ PLModel::PLModel( playlist_t *_p_playlist, /* THEPL */
: VLCModel( _p_intf, parent )
{
p_playlist = _p_playlist;
i_cached_id = -1;
i_cached_input_id = -1;
rootItem = NULL; /* PLItem rootItem, will be set in rebuild( ) */
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 );
DCONNECT( THEMIM->getIM(), metaChanged( input_item_t *),
this, processInputItemUpdate( input_item_t *) );
......@@ -107,7 +137,7 @@ Qt::ItemFlags PLModel::flags( const QModelIndex &index ) const
{
PL_LOCK;
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 ) )
flags |= Qt::ItemIsDropEnabled;
......@@ -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 );
if( !p_item ) continue;
PLItem *item = findByInput( rootItem, p_input->i_id );
PLItem *item = findByInputId( rootItem, p_input->i_id );
if( !item ) continue;
/* Better not try to move a node into itself.
......@@ -287,20 +317,13 @@ void PLModel::dropMove( const PlMimeData * plMimeData, PLItem *target, int row )
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 )
{
assert( index.isValid() );
const PLItem *item = getItem( index );
assert( item );
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 );
PL_UNLOCK;
}
......@@ -313,7 +336,7 @@ void PLModel::activateItem( playlist_item_t *p_item )
playlist_item_t *p_parent = p_item;
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;
}
if( p_parent )
......@@ -360,7 +383,7 @@ QVariant PLModel::data( const QModelIndex &index, const int role ) const
else if( role == Qt::DecorationRole && index.column() == 0 )
{
/* 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 )
{
......@@ -412,16 +435,7 @@ QVariant PLModel::data( const QModelIndex &index, const int role ) const
}
else if( role == IsLeafNodeRole )
{
QVariant isLeaf;
PL_LOCK;
playlist_item_t *plItem =
playlist_ItemGetById( p_playlist, item->i_id );
if( plItem )
isLeaf = plItem->i_children == -1;
PL_UNLOCK;
return isLeaf;
return QVariant( isLeaf( index ) );
}
else if( role == IsCurrentsParentNodeRole )
{
......@@ -445,74 +459,40 @@ bool PLModel::isParent( const QModelIndex &index, const QModelIndex &current ) c
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();
}
int PLModel::itemId( const QModelIndex &index ) const
{
return getItem( index )->id();
}
input_item_t * PLModel::getInputItem( const QModelIndex &index ) const
{
return getItem( index )->inputItem();
}
bool b_isLeaf = false;
PL_LOCK;
playlist_item_t *plItem =
playlist_ItemGetById( p_playlist, itemId( index, PLAYLIST_ID ) );
QString PLModel::getURI( const QModelIndex &index ) const
{
QString uri;
input_item_t *p_item = getItem( index )->inputItem();
/* 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;
if( plItem )
b_isLeaf = plItem->i_children == -1;
PL_UNLOCK;
return b_isLeaf;
}
QString PLModel::getTitle( const QModelIndex &index ) const
PLItem* PLModel::getItem( const QModelIndex & index ) const
{
QString title;
input_item_t *p_item = getItem( index )->inputItem();
char *fb_name = input_item_GetTitle( p_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;
PLItem *item = static_cast<PLItem *>( VLCModel::getItem( index ) );
if ( item == NULL ) item = rootItem;
return item;
}
bool PLModel::isCurrentItem( const QModelIndex &index, playLocation where ) const
{
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 )
{
return THEPL->p_media_library &&
itemId( index ) == THEPL->p_media_library->i_id;
return ( p_playlist->p_media_library &&
rootItem->inputItem() == p_playlist->p_media_library->p_input );
}
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 )
const
{
......@@ -525,19 +505,24 @@ QModelIndex PLModel::index( const int row, const int column, const 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
{
return index( findById( rootItem, rootItem->id() ), 0 );
return index( findByPLId( rootItem, rootItem->id( PLAYLIST_ID ) ), 0 );
}
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" ) );
}
......@@ -556,7 +541,7 @@ QModelIndex PLModel::currentIndex() const
{
input_thread_t *p_input_thread = THEMIM->getInput();
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 );
}
......@@ -588,40 +573,40 @@ int PLModel::rowCount( const QModelIndex &parent ) const
}
/************************* 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;
}
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( !b_input && root->id() == i_id )
if( !b_isinputid && root->id( PLAYLIST_ID ) == i_id )
return root;
else if( b_input && root->inputItem()->i_id == i_id )
else if( b_isinputid && root->id( INPUTITEM_ID ) == i_id )
return root;
QList<AbstractPLItem *>::iterator it = root->children.begin();
while ( it != root->children.end() )
{
PLItem *item = static_cast<PLItem *>(*it);
if( !b_input && item->id() == i_id )
if( !b_isinputid && item->id( PLAYLIST_ID ) == i_id )
return item;
else if( b_input && item->inputItem()->i_id == i_id )
else if( b_isinputid && item->id( INPUTITEM_ID ) == i_id )
return item;
if( item->childCount() )
{
PLItem *childFound = findInner( item, i_id, b_input );
PLItem *childFound = findInner( item, i_id, b_isinputid );
if( childFound )
return childFound;
}
......@@ -649,23 +634,27 @@ void PLModel::processInputItemUpdate( input_thread_t *p_input )
{
if( !p_input ) return;
PLItem *item = findByInput( rootItem, input_GetItem( p_input )->i_id );
if( item ) emit currentIndexChanged( index( item, 0 ) );
if( p_input && !( p_input->b_dead || !vlc_object_alive( p_input ) ) )
{
PLItem *item = findByInputId( rootItem, input_GetItem( p_input )->i_id );
if( item ) sigs->emit_currentIndexChanged( index( item, 0 ) );
}
processInputItemUpdate( input_GetItem( p_input ) );
}
void PLModel::processInputItemUpdate( input_item_t *p_item )
{
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 )
updateTreeItem( item );
}
void PLModel::processItemRemoval( int i_id )
void PLModel::processItemRemoval( int i_pl_itemid )
{
if( i_id <= 0 ) return;
removeItem( i_id );
if( i_pl_itemid <= 0 ) return;
removeItem( findByPLId( rootItem, i_pl_itemid ) );
}
void PLModel::commitBufferedRowInserts()
......@@ -687,7 +676,7 @@ void PLModel::commitBufferedRowInserts()
}
insertBufferMutex.unlock();
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 )
if ( parent == insertBufferRoot )
{
foreach (PLItem *item, insertBuffer)
if ( item->i_id == i_item )
if ( item->i_playlist_id == i_item )
{
b_return = true;
break;
......@@ -747,29 +736,29 @@ bool PLModel::isBufferedForInsert( PLItem *parent, int i_item )
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;
PLItem *newItem = NULL;
int pos;
/* Find the Parent */
PLItem *nodeParentItem = findById( rootItem, i_parent );
PLItem *nodeParentItem = findByPLId( rootItem, i_pl_itemidparent );
if( !nodeParentItem )
{ /* retry as it might have been in buffer */
commitBufferedRowInserts();
nodeParentItem = findById( rootItem, i_parent );
nodeParentItem = findByPLId( rootItem, i_pl_itemidparent );
}
if( !nodeParentItem ) return;
/* Search for an already matching children */
if ( isBufferedForInsert( nodeParentItem, i_item ) ) return;
foreach( const AbstractPLItem *existing, nodeParentItem->children )
if( existing->id() == i_item ) return;
if ( isBufferedForInsert( nodeParentItem, i_pl_itemid ) ) return;
foreach( AbstractPLItem *existing, nodeParentItem->children )
if( existing->id( PLAYLIST_ID ) == i_pl_itemid ) return;
/* Find the child */
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 )
{
PL_UNLOCK; return;
......@@ -785,23 +774,20 @@ void PLModel::processItemAppend( int i_item, int i_parent )
bufferedRowInsert( newItem, nodeParentItem, pos );
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 )
{
commitBufferedRowInserts();
/* Invalidate cache */
i_cached_id = i_cached_input_id = -1;
beginResetModel();
if( rootItem ) rootItem->clearChildren();
PL_LOCK;
if( rootItem ) rootItem->clearChildren();
if( p_root ) // Can be NULL
{
delete rootItem;
if ( rootItem ) delete rootItem;
rootItem = new PLItem( p_root );
}
assert( rootItem );
......@@ -811,7 +797,7 @@ void PLModel::rebuild( playlist_item_t *p_root )
/* And signal the view */
endResetModel();
if( p_root ) emit rootIndexChanged();
if( p_root ) sigs->emit_rootIndexChanged();
}
void PLModel::takeItem( PLItem *item )
......@@ -847,9 +833,6 @@ void PLModel::removeItem( PLItem *item )
if( !item ) return;
commitBufferedRowInserts();
i_cached_id = -1;
i_cached_input_id = -1;
if( item->parent() ) {
int i = item->parent()->indexOf( item );
beginRemoveRows( index( static_cast<PLItem*>(item->parent()), 0), i, i );
......@@ -869,7 +852,7 @@ void PLModel::removeItem( PLItem *item )
/* This function must be entered WITH the playlist lock */
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 );
}
......@@ -936,7 +919,7 @@ void PLModel::recurseDelete( QList<AbstractPLItem*> children, QModelIndexList *f
/******* Volume III: Sorting and searching ********/
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 )
......@@ -950,7 +933,7 @@ void PLModel::sort( QModelIndex caller, QModelIndex rootIndex, const int column,
: rootItem;
if( !item ) return;
int i_root_id = item->id();
int i_root_id = item->id( PLAYLIST_ID );
commitBufferedRowInserts();
......@@ -976,8 +959,6 @@ void PLModel::sort( QModelIndex caller, QModelIndex rootIndex, const int column,
}
}
i_cached_id = i_cached_input_id = -1;
if( count )
{
beginInsertRows( qIndex, 0, count - 1 );
......@@ -986,12 +967,12 @@ void PLModel::sort( QModelIndex caller, QModelIndex rootIndex, const int column,
}
PL_UNLOCK;
/* 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;
......@@ -1001,7 +982,7 @@ void PLModel::search( const QString& search_text, const QModelIndex & idx, bool
PL_LOCK;
{
playlist_item_t *p_root = playlist_ItemGetById( p_playlist,
itemId( idx ) );
itemId( idx, PLAYLIST_ID ) );
assert( p_root );
playlist_LiveSearchUpdate( p_playlist, p_root, qtu( search_text ),
b_recursive );
......@@ -1038,24 +1019,6 @@ void PLModel::clearPlaylist()
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 )
{
if( name.isEmpty() || !index.isValid() ) return;
......@@ -1063,40 +1026,29 @@ void PLModel::createNode( QModelIndex index, QString name )
PL_LOCK;
index = index.parent();
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 )
playlist_NodeCreate( p_playlist, qtu( name ), p_item, PLAYLIST_END, 0, NULL );
PL_UNLOCK;
}
void PLModel::actionSlot( QAction *action )
void PLModel::action( QAction *action, const QModelIndexList &indexes )
{
QString name;
QStringList mrls;
QModelIndex index;
actionsContainerType a = action->data().value<actionsContainerType>();
switch ( a.action )
{
case actionsContainerType::ACTION_PLAY:
PL_LOCK;
{
if ( a.indexes.first().isValid() )
{
playlist_item_t *p_item = playlist_ItemGetById( p_playlist,
itemId( a.indexes.first() ) );
activateItem( p_item );
}
}
PL_UNLOCK;
if ( !indexes.empty() && indexes.first().isValid() )
activateItem( indexes.first() );
break;
case actionsContainerType::ACTION_ADDTOPLAYLIST:
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;
playlist_NodeAddCopy( THEPL, p_item,
......@@ -1107,13 +1059,14 @@ void PLModel::actionSlot( QAction *action )
break;
case actionsContainerType::ACTION_REMOVE:
doDelete( a.indexes );
doDelete( indexes );
break;
case actionsContainerType::ACTION_SORT:
index = a.indexes.first().parent();
if ( indexes.empty() ) break;
index = indexes.first().parent();
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 ? Qt::AscendingOrder : Qt::DescendingOrder );
break;
......
......@@ -39,15 +39,93 @@
#include <QSignalMapper>
#include <QMimeData>
#include <QAbstractItemModel>
#include <QSortFilterProxyModel>
#include <QVariant>
#include <QModelIndex>
#include <QTimer>
#include <QMutex>
#include <QAction>
class PLItem;
class PLSelector;
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
{
Q_OBJECT
......@@ -75,8 +153,6 @@ public:
/* Data structure */
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 Qt::ItemFlags flags( const QModelIndex &index ) const;
virtual QModelIndex index( const int r, const int c, const QModelIndex &parent ) const;
......@@ -92,36 +168,31 @@ public:
/* Sort */
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 */
QModelIndex index( const int i_id, const int c );
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 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 void action( QAction *action, const QModelIndexList &indexes );
/* */
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:
/* VLCModelSubInterface indirect slots */
virtual void activateItem( const QModelIndex &index );
void clearPlaylist();
void ensureArtRequested( const QModelIndex &index );
virtual void actionSlot( QAction *action );
virtual void clearPlaylist();
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:
/* General */
......@@ -129,8 +200,6 @@ private:
playlist_t *p_playlist;
static QIcon icons[ITEM_TYPE_NUMBER];
/* single row linear inserts agregation */
void bufferedRowInsert( PLItem *item, PLItem *parent, int pos );
bool isBufferedForInsert( PLItem *parent, int i_item );
......@@ -143,20 +212,11 @@ private:
/* Custom model private methods */
/* 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;
bool isCurrent( const QModelIndex &index ) const;
bool isParent( const QModelIndex &index, const QModelIndex &current) const;
/* Shallow actions (do not affect core playlist) */
void updateTreeItem( PLItem * );
void removeItem ( PLItem * );
void removeItem( int );
void recurseDelete( QList<AbstractPLItem*> children, QModelIndexList *fullList );
void takeItem( PLItem * ); //will not delete item
void insertChildren( PLItem *node, QList<PLItem*>& items, int i_pos );
......@@ -172,14 +232,9 @@ private:
void sort( QModelIndex caller, QModelIndex rootIndex, const int column, Qt::SortOrder order );
/* Lookups */
PLItem *findById( PLItem *, int ) const;
PLItem *findByInput( PLItem *, int ) const;
PLItem *findInner(PLItem *, int , bool ) const;
PLItem *p_cached_item;
PLItem *p_cached_item_bi;
int i_cached_id;
int i_cached_input_id;
PLItem *findByPLId( PLItem *, int i_plitemid ) const;
PLItem *findByInputId( PLItem *, int i_input_itemid ) const;
PLItem *findInner(PLItem *, int i_id, bool b_isinputid ) const;
/* */
QString latestSearch;
......@@ -187,8 +242,8 @@ private:
private slots:
void processInputItemUpdate( input_item_t *);
void processInputItemUpdate( input_thread_t* p_input );
void processItemRemoval( int i_id );
void processItemAppend( int item, int parent );
void processItemRemoval( int i_pl_itemid );
void processItemAppend( int i_pl_itemid, int i_pl_itemidparent );
void commitBufferedRowInserts();
void activateItem( playlist_item_t *p_item );
};
......
......@@ -64,15 +64,16 @@
#include <assert.h>
/* local helper */
inline QModelIndex popupIndex( QAbstractItemView *view );
StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent,
intf_thread_t *_p_intf,
playlist_item_t *p_root,
PLSelector *_p_selector,
PLModel *_p_model,
MLModel *_p_plmodel)
VLCProxyModel *_p_model )
: QWidget( _parent ),
model( _p_model ),
mlmodel( _p_plmodel),
p_intf( _p_intf ),
p_selector( _p_selector )
{
......@@ -85,8 +86,8 @@ StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent,
listView = NULL;
picFlowView = NULL;
currentRootIndexId = -1;
lastActivatedId = -1;
currentRootIndexPLId = -1;
lastActivatedPLItemId = -1;
QList<QString> frames;
frames << ":/util/wait1";
......@@ -105,9 +106,9 @@ StandardPLPanel::StandardPLPanel( PlaylistWidget *_parent,
DCONNECT( THEMIM, leafBecameParent( int ),
this, browseInto( int ) );
CONNECT( model, currentIndexChanged( const QModelIndex& ),
CONNECT( model->sigs, currentIndexChanged( const QModelIndex& ),
this, handleExpansion( const QModelIndex& ) );
CONNECT( model, rootIndexChanged(), this, browseInto() );
CONNECT( model->sigs, rootIndexChanged(), this, browseInto() );
setRootItem( p_root, false );
}
......@@ -131,46 +132,36 @@ void StandardPLPanel::gotoPlayingItem()
void StandardPLPanel::handleExpansion( const QModelIndex& index )
{
assert( currentView );
if( currentRootIndexId != -1 && currentRootIndexId != model->itemId( index.parent() ) )
if( currentRootIndexPLId != -1 && currentRootIndexPLId != model->itemId( index.parent(), PLAYLIST_ID ) )
browseInto( index.parent() );
currentView->scrollTo( index );
}
void StandardPLPanel::popupPlView( const QPoint &point )
{
QModelIndex index = currentView->indexAt( point );
QPoint globalPoint = currentView->viewport()->mapToGlobal( point );
QItemSelectionModel *selection = currentView->selectionModel();
QModelIndexList list = selection->selectedRows();
if( !popup( index, globalPoint, list ) )
VLCMenuBar::PopupMenu( p_intf, true );
if( !popup( globalPoint ) ) VLCMenuBar::PopupMenu( p_intf, true );
}
/*********** 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());
QModelIndexList callerAsList;
callerAsList << ( index.isValid() ? index : QModelIndex() );
popupIndex = index; /* suitable for modal only */
#define ADD_MENU_ENTRY( icon, title, act, data ) \
QModelIndex index = popupIndex( currentView ); /* index for menu logic only. Do not store.*/
#define ADD_MENU_ENTRY( icon, title, act ) \
action = menu.addAction( icon, title ); \
container.action = act; \
container.indexes = data; \
action->setData( QVariant::fromValue( container ) )
/* */
QMenu menu;
QAction *action;
PLModel::actionsContainerType container;
VLCModelSubInterface::actionsContainerType container;
/* Play/Stream/Info static actions */
if( index.isValid() )
{
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),
this, SLOT( popupStream() ) );
......@@ -198,13 +189,13 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
this, SLOT( popupPromptAndCreateNode() ) );
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_ADDDIR), THEDP, SLOT( PLAppendDir()) );
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_ADDDIR), THEDP, SLOT( MLAppendDir() ) );
......@@ -214,10 +205,10 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
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),
container.ACTION_ADDTOPLAYLIST, selectionlist );
container.ACTION_ADDTOPLAYLIST );
}
}
......@@ -227,12 +218,12 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
if( index.isValid() )
{
ADD_MENU_ENTRY( QIcon( ":/buttons/playlist/playlist_remove" ), qtr(I_POP_DEL),
container.ACTION_REMOVE, selectionlist );
container.ACTION_REMOVE );
}
if( model->canEdit() ) {
menu.addAction( QIcon( ":/toolbar/clear" ), qtr("Clear the playlist"),
model, SLOT( clearPlaylist() ) );
model->sigs, SLOT( clearPlaylistSlot() ) );
}
menu.addSeparator();
......@@ -243,7 +234,6 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
QList<int> sortingColumns;
sortingColumns << COLUMN_TITLE << COLUMN_ARTIST << COLUMN_ALBUM << COLUMN_TRACK_NUMBER << COLUMN_URI;
container.action = container.ACTION_SORT;
container.indexes = callerAsList;
foreach( int Column, sortingColumns )
{
action = sortingMenu->addAction( qfu( psz_column_title( Column ) ) + " " + qtr("Ascending") );
......@@ -262,7 +252,7 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
zoomMenu->addAction( qtr( "Decrease" ), this, SLOT( decreaseZoom() ) );
menu.addMenu( zoomMenu );
CONNECT( &menu, triggered( QAction * ), model, actionSlot( QAction * ) );
CONNECT( &menu, triggered( QAction * ), this, popupAction( QAction * ) );
menu.addMenu( StandardPLPanel::viewSelectionMenu( this ) );
......@@ -276,6 +266,12 @@ bool StandardPLPanel::popup( const QModelIndex & index, const QPoint &point, con
#undef ADD_MENU_ENTRY
}
void StandardPLPanel::popupAction( QAction *action )
{
QModelIndexList list = currentView->selectionModel()->selectedRows();
model->action( action, list );
}
QMenu* StandardPLPanel::viewSelectionMenu( StandardPLPanel *panel )
{
QMenu *viewMenu = new QMenu( qtr( "Playlist View Mode" ) );
......@@ -297,6 +293,15 @@ QMenu* StandardPLPanel::viewSelectionMenu( StandardPLPanel *panel )
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 )
{
QMenu menu;
......@@ -322,15 +327,16 @@ void StandardPLPanel::popupPromptAndCreateNode()
qtr( I_NEW_DIR ), qtr( I_NEW_DIR_NAME ),
QLineEdit::Normal, QString(), &ok);
if ( !ok ) return;
qobject_cast<VLCModel *>(currentView->model())->createNode( popupIndex, name );
qobject_cast<VLCProxyModel *>(currentView->model())->createNode( popupIndex( currentView ), name );
}
void StandardPLPanel::popupInfoDialog()
{
if( popupIndex.isValid() )
QModelIndex index = popupIndex( currentView );
if( index.isValid() )
{
VLCModel *model = qobject_cast<VLCModel *>(currentView->model());
input_item_t* p_input = model->getInputItem( popupIndex );
VLCProxyModel *model = qobject_cast<VLCProxyModel *>(currentView->model());
input_item_t* p_input = model->getInputItem( index );
MediaInfoDialog *mid = new MediaInfoDialog( p_intf, p_input );
mid->setParent( PlaylistDialog::getInstance( p_intf ),
Qt::Dialog );
......@@ -340,8 +346,8 @@ void StandardPLPanel::popupInfoDialog()
void StandardPLPanel::popupExplore()
{
VLCModel *model = qobject_cast<VLCModel *>(currentView->model());
QString uri = model->getURI( popupIndex );
VLCProxyModel *model = qobject_cast<VLCProxyModel *>(currentView->model());
QString uri = model->getURI( popupIndex( currentView ) );
char *path = NULL;
if( ! uri.isEmpty() )
......@@ -358,16 +364,16 @@ void StandardPLPanel::popupExplore()
void StandardPLPanel::popupStream()
{
VLCModel *model = qobject_cast<VLCModel *>(currentView->model());
QString uri = model->getURI( popupIndex );
VLCProxyModel *model = qobject_cast<VLCProxyModel *>(currentView->model());
QString uri = model->getURI( popupIndex( currentView ) );
if ( ! uri.isEmpty() )
THEDP->streamingDialog( NULL, uri, false );
}
void StandardPLPanel::popupSave()
{
VLCModel *model = qobject_cast<VLCModel *>(currentView->model());
QString uri = model->getURI( popupIndex );
VLCProxyModel *model = qobject_cast<VLCProxyModel *>(currentView->model());
QString uri = model->getURI( popupIndex( currentView ) );
if ( ! uri.isEmpty() )
THEDP->streamingDialog( NULL, uri );
}
......@@ -390,7 +396,7 @@ void StandardPLPanel::search( const QString& searchText )
bool flat = ( currentView == iconView ||
currentView == listView ||
currentView == picFlowView );
model->search( searchText,
model->filter( searchText,
flat ? currentView->rootIndex() : QModelIndex(),
!flat );
}
......@@ -419,16 +425,16 @@ void StandardPLPanel::setRootItem( playlist_item_t *p_item, bool b )
if( b )
{
msg_Dbg( p_intf, "Setting the SQL ML" );
currentView->setModel( mlmodel );
if ( model->switchToModel( VLCProxyModel::SQLML_MODEL ) )
currentView->setModel( model );
}
else
#else
Q_UNUSED( b );
#endif
{
if( currentView->model() != model )
currentView->setModel( model );
model->rebuild( p_item );
if ( model->switchToModel( VLCProxyModel::PL_MODEL ) )
model->rebuild( p_item );
}
}
......@@ -441,14 +447,15 @@ void StandardPLPanel::browseInto( const QModelIndex &index )
/* When going toward root in LocationBar, scroll to the item
that was previously as root */
QModelIndex newIndex = model->index(currentRootIndexId,0);
QModelIndex newIndex = model->indexByPLID(currentRootIndexPLId,0);
while( newIndex.isValid() && (newIndex.parent() != index) )
newIndex = newIndex.parent();
if( newIndex.isValid() )
currentView->scrollTo( newIndex );
/* Store new rootindexid*/
currentRootIndexId = model->itemId( index );
currentRootIndexPLId = model->itemId( index, PLAYLIST_ID );
model->ensureArtRequested( index );
}
......@@ -457,8 +464,8 @@ void StandardPLPanel::browseInto( const QModelIndex &index )
void StandardPLPanel::browseInto()
{
browseInto( (currentRootIndexId != -1 && currentView != treeView) ?
model->index( currentRootIndexId, 0 ) :
browseInto( (currentRootIndexPLId != -1 && currentView != treeView) ?
model->indexByPLID( currentRootIndexPLId, 0 ) :
QModelIndex() );
}
......@@ -532,8 +539,7 @@ bool StandardPLPanel::eventFilter ( QObject *obj, QEvent * event )
void StandardPLPanel::deleteSelection()
{
QItemSelectionModel *selection = currentView->selectionModel();
QModelIndexList list = selection->selectedIndexes();
QModelIndexList list = currentView->selectionModel()->selectedIndexes();
model->doDelete( list );
}
......@@ -614,23 +620,6 @@ void StandardPLPanel::updateZoom( int i )
#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 )
{
bool b_treeViewCreated = false;
......@@ -671,7 +660,7 @@ void StandardPLPanel::showView( int i_view )
}
}
changeModel( false );
currentView->setModel( model );
/* Restoring the header Columns must come after changeModel */
if( b_treeViewCreated )
......@@ -755,7 +744,7 @@ void StandardPLPanel::activate( const QModelIndex &index )
if( currentView->model() == model )
{
/* If we are not a leaf node */
if( !index.data( PLModel::IsLeafNodeRole ).toBool() )
if( !index.data( VLCModelSubInterface::IsLeafNodeRole ).toBool() )
{
if( currentView != treeView )
browseInto( index );
......@@ -763,25 +752,26 @@ void StandardPLPanel::activate( const QModelIndex &index )
else
{
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;
lastActivatedId = p_item->i_id;
lastActivatedPLItemId = p_item->i_id;
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 )
treeView->setExpanded( index, true );
else
browseInto( index );
lastActivatedId = -1;
lastActivatedPLItemId = -1;
}
......@@ -30,6 +30,7 @@
#include "qt4.hpp"
#include "components/playlist/playlist.hpp"
#include "components/playlist/vlc_model.hpp"
#include <QWidget>
#include <QModelIndexList>
......@@ -37,8 +38,7 @@
#include <vlc_playlist.h> /* playlist_item_t */
class QSignalMapper;
class PLModel;
class MLModel;
class VLCProxyModel;
class QKeyEvent;
class QWheelEvent;
class QStackedLayout;
......@@ -50,7 +50,6 @@ class PlIconView;
class PlListView;
class PicFlowView;
class LocationBar;
class PLSelector;
class PlaylistWidget;
class PixmapAnimator;
......@@ -61,7 +60,7 @@ class StandardPLPanel: public QWidget
public:
StandardPLPanel( PlaylistWidget *, intf_thread_t *,
playlist_item_t *, PLSelector *, PLModel *, MLModel * );
playlist_item_t *, PLSelector *, VLCProxyModel * );
virtual ~StandardPLPanel();
enum { ICON_VIEW = 0,
......@@ -75,10 +74,9 @@ public:
static QMenu *viewSelectionMenu(StandardPLPanel *obj);
protected:
PLModel *model;
MLModel *mlmodel;
VLCProxyModel *model;
virtual void wheelEvent( QWheelEvent *e );
bool popup( const QModelIndex & index, const QPoint &point, const QModelIndexList &selectionlist );
bool popup( const QPoint &point );
private:
intf_thread_t *p_intf;
......@@ -97,20 +95,16 @@ private:
QSignalMapper *selectColumnsSigMapper;
int lastActivatedId;
int currentRootIndexId;
int lastActivatedPLItemId;
int currentRootIndexPLId;
void createTreeView();
void createIconView();
void createListView();
void createCoverView();
void updateZoom( int i_zoom );
void changeModel ( bool b_ml );
bool eventFilter ( QObject * watched, QEvent * event );
/* for popup */
QModelIndex popupIndex; /* FIXME: don't store here, pass as Action param */
/* Wait spinner */
PixmapAnimator *spinnerAnimation;
......@@ -140,6 +134,7 @@ private slots:
void popupExplore();
void popupStream();
void popupSave();
void popupAction( QAction * );
void increaseZoom() { updateZoom( i_zoom + 1 ); };
void decreaseZoom() { updateZoom( i_zoom - 1 ); };
void toggleColumnShown( int );
......
......@@ -22,7 +22,7 @@
*****************************************************************************/
#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 "input_manager.hpp" /* THEMIM */
......@@ -58,7 +58,7 @@ void AbstractPlViewItemDelegate::paintBackground(
painter->setPen( option.palette.color( QPalette::Highlight ).darker( 150 ) );
painter->drawRect( r );
}
else if( index.data( PLModel::IsCurrentRole ).toBool() )
else if( index.data( VLCModel::IsCurrentRole ).toBool() )
{
painter->setBrush( QBrush( Qt::lightGray ) );
painter->setPen( QColor( Qt::darkGray ) );
......@@ -81,7 +81,7 @@ void PlIconViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt
QFont font( index.data( Qt::FontRole ).value<QFont>() );
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 );
QFontMetrics fm = painter->fontMetrics();
......@@ -120,12 +120,12 @@ void PlIconViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt
//Draw children indicator
if( !index.data( PLModel::IsLeafNodeRole ).toBool() )
if( !index.data( VLCModel::IsLeafNodeRole ).toBool() )
{
QRect r( option.rect );
r.setSize( QSize( 25, 25 ) );
r.translate( 5, 5 );
if( index.data( PLModel::IsCurrentsParentNodeRole ).toBool() )
if( index.data( VLCModel::IsCurrentsParentNodeRole ).toBool() )
{
painter->setOpacity( 0.75 );
QPainterPath nodeRectPath;
......@@ -222,7 +222,7 @@ void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt
//Draw title info
f.setItalic( true );
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 );
QFontMetrics fm( painter->fontMetrics() );
......@@ -234,7 +234,7 @@ void PlListViewItemDelegate::paint( QPainter * painter, const QStyleOptionViewIt
}
//Draw children indicator
if( !index.data( PLModel::IsLeafNodeRole ).toBool() )
if( !index.data( VLCModel::IsLeafNodeRole ).toBool() )
{
QPixmap dirPix = QPixmap( ":/type/node" );
painter->drawPixmap( QPoint( textRect.x(), textRect.center().y() - dirPix.height() / 2 ),
......@@ -276,7 +276,7 @@ QSize PlListViewItemDelegate::sizeHint ( const QStyleOptionViewItem &, const QMo
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;
myoptions.font.setBold( true );
......@@ -305,7 +305,7 @@ static void plViewDragMoveEvent( QAbstractItemView *, QDragMoveEvent * event )
else event->acceptProposedAction();
}
PlIconView::PlIconView( PLModel *, QWidget *parent ) : QListView( parent )
PlIconView::PlIconView( QAbstractItemModel *, QWidget *parent ) : QListView( parent )
{
PlIconViewItemDelegate *delegate = new PlIconViewItemDelegate( this );
......@@ -355,7 +355,7 @@ bool PlIconView::viewportEvent ( QEvent * event )
return QAbstractItemView::viewportEvent( event );
}
PlListView::PlListView( PLModel *, QWidget *parent ) : QListView( parent )
PlListView::PlListView( QAbstractItemModel *, QWidget *parent ) : QListView( parent )
{
setViewMode( QListView::ListMode );
setUniformItemSizes( true );
......@@ -412,7 +412,7 @@ bool PlListView::viewportEvent ( QEvent * event )
return QAbstractItemView::viewportEvent( event );
}
PlTreeView::PlTreeView( PLModel *, QWidget *parent ) : QTreeView( parent )
PlTreeView::PlTreeView( QAbstractItemModel *, QWidget *parent ) : QTreeView( parent )
{
setItemDelegate( new PlTreeViewItemDelegate( this ) );
......@@ -443,8 +443,9 @@ PlTreeView::PlTreeView( PLModel *, QWidget *parent ) : QTreeView( parent )
void PlTreeView::setModel( QAbstractItemModel * model )
{
QTreeView::setModel( model );
VLCModel *m = static_cast<VLCModel*>(model);
CONNECT( this, expanded( const QModelIndex & ),
model, ensureArtRequested( const QModelIndex & ) );
m->sigs, ensureArtRequestedSlot( const QModelIndex & ) );
}
void PlTreeView::startDrag ( Qt::DropActions supportedActions )
......@@ -470,7 +471,7 @@ void PlTreeView::keyPressEvent( QKeyEvent *event )
}
#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 );
layout->setMargin( 0 );
......
......@@ -31,7 +31,6 @@
#include "util/pictureflow.hpp"
class QPainter;
class PLModel;
class QFont;
class AbstractPlViewItemDelegate : public QStyledItemDelegate
......@@ -84,7 +83,7 @@ class PlIconView : public QListView
Q_OBJECT
public:
PlIconView( PLModel *model, QWidget *parent = 0 );
PlIconView( QAbstractItemModel *model, QWidget *parent = 0 );
protected:
virtual void startDrag ( Qt::DropActions supportedActions );
virtual void dragMoveEvent ( QDragMoveEvent * event );
......@@ -96,7 +95,7 @@ class PlListView : public QListView
Q_OBJECT
public:
PlListView( PLModel *model, QWidget *parent = 0 );
PlListView( QAbstractItemModel *model, QWidget *parent = 0 );
protected:
virtual void startDrag ( Qt::DropActions supportedActions );
virtual void dragMoveEvent ( QDragMoveEvent * event );
......@@ -109,7 +108,7 @@ class PlTreeView : public QTreeView
Q_OBJECT
public:
PlTreeView( PLModel *, QWidget *parent = 0 );
PlTreeView( QAbstractItemModel *, QWidget *parent = 0 );
protected:
virtual void startDrag ( Qt::DropActions supportedActions );
virtual void dragMoveEvent ( QDragMoveEvent * event );
......@@ -121,7 +120,7 @@ class PicFlowView : public QAbstractItemView
{
Q_OBJECT
public:
PicFlowView( PLModel *model, QWidget *parent = 0 );
PicFlowView( QAbstractItemModel *model, QWidget *parent = 0 );
virtual QRect visualRect(const QModelIndex&) const;
virtual void scrollTo(const QModelIndex&, QAbstractItemView::ScrollHint);
......
......@@ -22,14 +22,52 @@
*****************************************************************************/
#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 )
: 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()
{
}
QString VLCModel::getMeta( const QModelIndex & index, int meta )
......@@ -77,8 +115,93 @@ QPixmap VLCModel::getArtPixmap( const QModelIndex & index, const QSize & size )
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
{
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 @@
#include "qt4.hpp"
#include "sorting.h"
#include "playlist_item.hpp"
#include <vlc_input.h>
#include <QModelIndex>
#include <QPixmapCache>
#include <QSize>
#include <QObject>
#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:
enum {
IsCurrentRole = Qt::UserRole,
IsLeafNodeRole,
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;
VLCModelSubInterface();
virtual ~VLCModelSubInterface();
virtual void rebuild( playlist_item_t * p = NULL ) = 0;
virtual void doDelete( QModelIndexList ) = 0;
virtual ~VLCModel();
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 void createNode( QModelIndex, QString ) = 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 canEdit() const = 0;
enum playLocation
{
IN_PLAYLIST,
IN_MEDIALIBRARY
IN_MEDIALIBRARY,
IN_SQLMEDIALIB
};
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
{
enum
......@@ -81,46 +95,83 @@ public:
ACTION_REMOVE,
ACTION_SORT
} action;
QModelIndexList indexes; /* for passing selection or caller index(es) */
int column; /* for sorting */
};
static int columnFromMeta( int meta_col );
static int columnToMeta( int _column )
{
int meta = 1, column = 0;
VLCModelSignalsHandler *sigs;
/* Indirect slots handlers */
virtual void activateItem( const QModelIndex &index ) = 0;
virtual void ensureArtRequested( const QModelIndex &index ) = 0;
virtual void clearPlaylist() = 0;
};
while( column != _column && meta != COLUMN_END )
{
meta <<= 1;
column++;
}
class VLCModelSignalsHandler : public QObject
{
Q_OBJECT
return meta;
}
public:
VLCModelSignalsHandler( VLCModelSubInterface *_parent ) { parent = _parent; }
static int columnFromMeta( int meta_col )
{
int meta = 1, column = 0;
void emit_currentIndexChanged( const QModelIndex &index ) { emit currentIndexChanged( index ); }
void emit_rootIndexChanged() { emit rootIndexChanged(); }
while( meta != meta_col && meta != COLUMN_END )
{
meta <<= 1;
column++;
}
public slots:
void activateItemSlot( const QModelIndex &index ) { parent->activateItem( index ); }
void ensureArtRequestedSlot( const QModelIndex &index ) { parent->ensureArtRequested( index ); }
void clearPlaylistSlot() { parent->clearPlaylist(); }
return column;
}
signals:
void currentIndexChanged( const QModelIndex& );
void rootIndexChanged();
virtual void createNode( QModelIndex, QString ) {};
private:
VLCModelSubInterface *parent;
};
public slots:
virtual void activateItem( const QModelIndex &index ) = 0;
virtual void actionSlot( QAction *action ) = 0;
/* Abstract VLC Model ; Base for custom models.
Only implements methods sharing the same code that would be
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:
/* 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;
};
Q_DECLARE_METATYPE(VLCModel::actionsContainerType)
Q_DECLARE_METATYPE(VLCModelSubInterface::actionsContainerType)
#endif
......@@ -494,26 +494,16 @@ QRect PictureFlowSoftwareRenderer::renderSlide(const SlideInfo &slide, int col1,
QString artURL;
PLModel* plm = qobject_cast<PLModel*>( state->model );
#ifdef MEDIA_LIBRARY
MLModel* mlm = qobject_cast<MLModel*>( state->model );
#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 )
VLCModel *m = static_cast<VLCModel*>( state->model );
if( m )
{
index = ((MLModel*)state->model)->index( slide.slideIndex, 0, QModelIndex() );
index = m->index( slide.slideIndex, 0, m->currentIndex().parent() );
if( !index.isValid() )
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 );
QImage* src;
......@@ -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->picrole = Qt::DecorationRole;
......
......@@ -81,7 +81,7 @@ public:
/*!
Creates a new PictureFlow widget.
*/
PictureFlow(QWidget* parent = 0, VLCModel *model = 0);
PictureFlow(QWidget* parent = 0, QAbstractItemModel *model = 0);
/*!
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