X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fqt4%2Fplaylist_model.cpp;h=3a43c766f1745af16980af4f2405494afad2deee;hb=116f3a23ac8209172ad78363ebd7aeff0c83a231;hp=6e601353dd5d5a52421a5e58488589d414022e98;hpb=159fa24a6c6af16f20a4d5bf0210b8326623a628;p=vlc diff --git a/modules/gui/qt4/playlist_model.cpp b/modules/gui/qt4/playlist_model.cpp index 6e601353dd..3a43c766f1 100644 --- a/modules/gui/qt4/playlist_model.cpp +++ b/modules/gui/qt4/playlist_model.cpp @@ -20,14 +20,17 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ +#define PLI_NAME( p ) p ? p->p_input->psz_name : "null" +#include #include #include -#include "qt4.hpp" +#include #include + +#include "qt4.hpp" #include "playlist_model.hpp" -#include -#include +#include "dialogs/mediainfo.hpp" #include #include "pixmaps/type_unknown.xpm" @@ -97,7 +100,7 @@ void PLItem::insertChild( PLItem *item, int i_pos, bool signal ) assert( model ); if( signal ) model->beginInsertRows( model->index( this , 0 ), i_pos, i_pos ); - children.append( item ); + children.insert( i_pos, item ); if( signal ) model->endInsertRows(); } @@ -131,18 +134,26 @@ void PLItem::update( playlist_item_t *p_item, bool iscurrent ) strings[2] = QString( psz_duration ); type = p_item->p_input->i_type; current = iscurrent; + + if( current && p_item->p_input->p_meta && + p_item->p_input->p_meta->psz_arturl && + !strncmp( p_item->p_input->p_meta->psz_arturl, "file://", 7 ) ) + model->sendArt( qfu( p_item->p_input->p_meta->psz_arturl ) ); + else if( current ) + model->removeArt(); } /************************************************************************* * Playlist model implementation *************************************************************************/ -PLModel::PLModel( playlist_t *_p_playlist, +PLModel::PLModel( playlist_t *_p_playlist, intf_thread_t *_p_intf, playlist_item_t * p_root, int _i_depth, QObject *parent) : QAbstractItemModel(parent) { i_depth = _i_depth; assert( i_depth == 1 || i_depth == -1 ); + p_intf = _p_intf; p_playlist= _p_playlist; i_items_to_append = 0; b_need_update = false; @@ -163,8 +174,8 @@ PLModel::PLModel( playlist_t *_p_playlist, ADD_ICON( NODE, node ); rootItem = NULL; - rebuild( p_root ); addCallbacks(); + rebuild( p_root ); } @@ -174,6 +185,130 @@ PLModel::~PLModel() delete rootItem; } +Qt::DropActions PLModel::supportedDropActions() const +{ + return Qt::CopyAction; +} + +Qt::ItemFlags PLModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags defaultFlags = QAbstractItemModel::flags(index); + if( index.isValid() ) + return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags; + else + return Qt::ItemIsDropEnabled | defaultFlags; +} + +QStringList PLModel::mimeTypes() const +{ + QStringList types; + types << "vlc/playlist-item-id"; + return types; +} + +QMimeData *PLModel::mimeData(const QModelIndexList &indexes) const +{ + QMimeData *mimeData = new QMimeData(); + QByteArray encodedData; + QDataStream stream(&encodedData, QIODevice::WriteOnly); + + foreach (QModelIndex index, indexes) { + if (index.isValid() && index.column() == 0 ) + stream << itemId(index); + } + mimeData->setData("vlc/playlist-item-id", encodedData); + return mimeData; +} + +bool PLModel::dropMimeData(const QMimeData *data, Qt::DropAction action, + int row, int column, const QModelIndex &target) +{ + if ( data->hasFormat("vlc/playlist-item-id") ) + { + if (action == Qt::IgnoreAction) + return true; + + PLItem *targetItem; + if( target.isValid() ) + targetItem = static_cast( target.internalPointer() ); + else + targetItem = rootItem; + + QByteArray encodedData = data->data("vlc/playlist-item-id"); + QDataStream stream(&encodedData, QIODevice::ReadOnly); + + PLItem *newParentItem; + while (!stream.atEnd()) + { + int i; + int srcId; + stream >> srcId; + + PL_LOCK; + playlist_item_t *p_target = + playlist_ItemGetById( p_playlist, targetItem->i_id, + VLC_TRUE ); + playlist_item_t *p_src = playlist_ItemGetById( p_playlist, srcId, + VLC_TRUE ); + + if( !p_target || !p_src ) + { + PL_UNLOCK; + return false; + } + if( p_target->i_children == -1 ) /* A leaf */ + { + PLItem *parentItem = targetItem->parent(); + assert( parentItem ); + playlist_item_t *p_parent = + playlist_ItemGetById( p_playlist, parentItem->i_id, + VLC_TRUE ); + if( !p_parent ) + { + PL_UNLOCK; + return false; + } + for( i = 0 ; i< p_parent->i_children ; i++ ) + if( p_parent->pp_children[i] == p_target ) break; + playlist_TreeMove( p_playlist, p_src, p_parent, i ); + newParentItem = parentItem; + } + else + { + /* \todo: if we drop on a top-level node, use copy instead ? */ + playlist_TreeMove( p_playlist, p_src, p_target, 0 ); + i = 0; + newParentItem = targetItem; + } + /* Remove from source */ + PLItem *srcItem = FindById( rootItem, p_src->i_id ); + // We dropped on the source selector. Ask the dialog to forward + // to the main view + if( !srcItem ) + { + emit shouldRemove( p_src->i_id ); + } + else + srcItem->remove( srcItem ); + + /* Display at new destination */ + PLItem *newItem = new PLItem( p_src, newParentItem, this ); + newParentItem->insertChild( newItem, i, true ); + UpdateTreeItem( p_src, newItem, true ); + if( p_src->i_children != -1 ) + UpdateNodeChildren( newItem ); + PL_UNLOCK; + } + } + return true; +} + +void PLModel::removeItem( int i_id ) +{ + PLItem *item = FindById( rootItem,i_id ); + if( item ) item->remove( item ); +} + void PLModel::addCallbacks() { /* Some global changes happened -> Rebuild all */ @@ -201,7 +336,8 @@ void PLModel::activateItem( const QModelIndex &index ) PLItem *item = static_cast(index.internalPointer()); 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_id, + VLC_TRUE); activateItem( p_item ); PL_UNLOCK; } @@ -216,13 +352,13 @@ void PLModel::activateItem( playlist_item_t *p_item ) p_parent = p_parent->p_parent; } if( p_parent ) - playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, p_parent, p_item ); + playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, VLC_TRUE, p_parent, p_item ); } /****************** Base model mandatory implementations *****************/ QVariant PLModel::data(const QModelIndex &index, int role) const { - assert( index.isValid() ); + if(!index.isValid() ) return QVariant(); PLItem *item = static_cast(index.internalPointer()); if( role == Qt::DisplayRole ) { @@ -255,12 +391,6 @@ int PLModel::itemId( const QModelIndex &index ) const return static_cast(index.internalPointer())->i_id; } -Qt::ItemFlags PLModel::flags(const QModelIndex &index) const -{ - if( !index.isValid() ) return Qt::ItemIsEnabled; - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - QVariant PLModel::headerData( int section, Qt::Orientation orientation, int role) const { @@ -357,14 +487,17 @@ bool PLModel::hasLoop() void PLModel::setLoop( bool on ) { var_SetBool( p_playlist, "loop", on ? VLC_TRUE:VLC_FALSE ); + config_PutInt( p_playlist, "loop", on ? 1: 0 ); } void PLModel::setRepeat( bool on ) { var_SetBool( p_playlist, "repeat", on ? VLC_TRUE:VLC_FALSE ); + config_PutInt( p_playlist, "repeat", on ? 1: 0 ); } void PLModel::setRandom( bool on ) { var_SetBool( p_playlist, "random", on ? VLC_TRUE:VLC_FALSE ); + config_PutInt( p_playlist, "random", on ? 1: 0 ); } /************************* Lookups *****************************/ @@ -439,7 +572,7 @@ void PLModel::customEvent( QEvent *event ) { int type = event->type(); if( type != ItemUpdate_Type && type != ItemAppend_Type && - type != ItemDelete_Type ) + type != ItemDelete_Type && type != PLUpdate_Type ) return; PLEvent *ple = static_cast(event); @@ -448,8 +581,10 @@ void PLModel::customEvent( QEvent *event ) ProcessInputItemUpdate( ple->i_id ); else if( type == ItemAppend_Type ) ProcessItemAppend( ple->p_add ); - else + else if( type == ItemDelete_Type ) ProcessItemRemoval( ple->i_id ); + else + rebuild(); } /**** Events processing ****/ @@ -466,7 +601,6 @@ void PLModel::ProcessItemRemoval( int i_id ) if( i_id <= 0 ) return; if( i_id == i_cached_id ) i_cached_id = -1; i_cached_input_id = -1; - PLItem *item = FindById( rootItem, i_id ); if( item ) item->remove( item ); @@ -480,10 +614,10 @@ void PLModel::ProcessItemAppend( playlist_add_t *p_add ) if( b_need_update ) return; PLItem *nodeItem = FindById( rootItem, p_add->i_node ); + PL_LOCK; if( !nodeItem ) goto end; - PL_LOCK; - p_item = playlist_ItemGetById( p_playlist, p_add->i_item ); + p_item = playlist_ItemGetById( p_playlist, p_add->i_item, VLC_TRUE ); if( !p_item || p_item->i_flags & PLAYLIST_DBL_FLAG ) goto end; if( i_depth == 1 && p_item->p_parent && p_item->p_parent->i_id != rootItem->i_id ) @@ -526,6 +660,7 @@ void PLModel::rebuild( playlist_item_t *p_root ) rootItem = new PLItem( p_root, NULL, this ); rootItem->strings[0] = qtr("Name"); rootItem->strings[1] = qtr("Artist"); + rootItem->strings[2] = qtr("Duration"); } assert( rootItem ); /* Recreate from root */ @@ -550,7 +685,8 @@ void PLModel::rebuild( playlist_item_t *p_root ) /* This function must be entered WITH the playlist lock */ void PLModel::UpdateNodeChildren( PLItem *root ) { - playlist_item_t *p_node = playlist_ItemGetById( p_playlist, root->i_id ); + playlist_item_t *p_node = playlist_ItemGetById( p_playlist, root->i_id, + VLC_TRUE ); UpdateNodeChildren( p_node, root ); } @@ -559,6 +695,7 @@ void PLModel::UpdateNodeChildren( playlist_item_t *p_node, PLItem *root ) { for( int i = 0; i < p_node->i_children ; i++ ) { + if( p_node->pp_children[i]->i_flags & PLAYLIST_DBL_FLAG ) continue; PLItem *newItem = new PLItem( p_node->pp_children[i], root, this ); root->appendChild( newItem, false ); UpdateTreeItem( newItem, false, true ); @@ -570,7 +707,8 @@ void PLModel::UpdateNodeChildren( playlist_item_t *p_node, PLItem *root ) /* This function must be entered WITH the playlist lock */ void PLModel::UpdateTreeItem( PLItem *item, bool signal, bool force ) { - playlist_item_t *p_item = playlist_ItemGetById( p_playlist, item->i_id ); + playlist_item_t *p_item = playlist_ItemGetById( p_playlist, item->i_id, + VLC_TRUE ); UpdateTreeItem( p_item, item, signal, force ); } @@ -588,6 +726,17 @@ void PLModel::UpdateTreeItem( playlist_item_t *p_item, PLItem *item, /************************* Actions ******************************/ +void PLModel::sendArt( QString url ) +{ + QString arturl = url.replace( "file://",QString("" ) ); + emit artSet( arturl ); +} + +void PLModel::removeArt() +{ + emit artSet( QString() ); +} + /** * Deletion, here we have to do a ugly slow hack as we retrieve the full * list of indexes to delete at once: when we delete a node and all of @@ -627,13 +776,14 @@ void PLModel::doDeleteItem( PLItem *item, QModelIndexList *fullList ) fullList->removeAll( deleteIndex ); 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_id, + VLC_TRUE ); if( !p_item ) { PL_UNLOCK; return; } if( p_item->i_children == -1 ) - playlist_DeleteAllFromInput( p_playlist, item->i_input_id ); + playlist_DeleteFromInput( p_playlist, item->i_input_id, VLC_TRUE ); else playlist_NodeDelete( p_playlist, p_item, VLC_TRUE, VLC_FALSE ); /* And finally, remove it from the tree */ @@ -645,29 +795,50 @@ void PLModel::doDeleteItem( PLItem *item, QModelIndexList *fullList ) void PLModel::sort( int column, Qt::SortOrder order ) { PL_LOCK; - playlist_item_t *p_root = playlist_ItemGetById( p_playlist, rootItem->i_id ); - int i_mode; - switch( column ) { - case 0: i_mode = SORT_TITLE_NODES_FIRST;break; - case 1: i_mode = SORT_ARTIST;break; - case 2: i_mode = SORT_DURATION; break; + playlist_item_t *p_root = playlist_ItemGetById( p_playlist, + rootItem->i_id, + VLC_TRUE ); + int i_mode; + switch( column ) + { + case 0: i_mode = SORT_TITLE_NODES_FIRST;break; + case 1: i_mode = SORT_ARTIST;break; + case 2: i_mode = SORT_DURATION; break; + default: i_mode = SORT_TITLE_NODES_FIRST; break; + } + if( p_root ) + playlist_RecursiveNodeSort( p_playlist, p_root, i_mode, + order == Qt::AscendingOrder ? + ORDER_NORMAL : ORDER_REVERSE ); } - if( p_root ) - playlist_RecursiveNodeSort( p_playlist, p_root, i_mode, - order == Qt::AscendingOrder ? ORDER_NORMAL : - ORDER_REVERSE ); PL_UNLOCK rebuild(); } +void PLModel::search( QString search_text ) +{ + /** \todo Fire the search with a small delay ? */ + PL_LOCK; + { + playlist_item_t *p_root = playlist_ItemGetById( p_playlist, + rootItem->i_id, + VLC_TRUE ); + assert( p_root ); + char *psz_name = search_text.toUtf8().data(); + playlist_LiveSearchUpdate( p_playlist , p_root, psz_name ); + } + PL_UNLOCK; + rebuild(); +} + /*********** Popup *********/ void PLModel::popup( QModelIndex & index, QPoint &point, QModelIndexList list ) { assert( index.isValid() ); PL_LOCK; playlist_item_t *p_item = playlist_ItemGetById( p_playlist, - itemId( index ) ); + itemId( index ), VLC_TRUE ); if( p_item ) { i_popup_item = p_item->i_id; @@ -676,8 +847,11 @@ void PLModel::popup( QModelIndex & index, QPoint &point, QModelIndexList list ) current_selection = list; QMenu *menu = new QMenu; menu->addAction( qfu(I_POP_PLAY), this, SLOT( popupPlay() ) ); - menu->addAction( qfu(I_POP_PREPARSE), this, SLOT( popupPreparse() ) ); menu->addAction( qfu(I_POP_DEL), this, SLOT( popupDel() ) ); + menu->addSeparator(); + menu->addAction( qfu(I_POP_STREAM), this, SLOT( popupStream() ) ); + menu->addAction( qfu(I_POP_SAVE), this, SLOT( popupSave() ) ); + menu->addSeparator(); menu->addAction( qfu(I_POP_INFO), this, SLOT( popupInfo() ) ); if( p_item->i_children > -1 ) { @@ -698,11 +872,35 @@ void PLModel::popupDel() void PLModel::popupPlay() { PL_LOCK; - playlist_item_t *p_item = playlist_ItemGetById( p_playlist, i_popup_item ); - activateItem( p_item ); + { + playlist_item_t *p_item = playlist_ItemGetById( p_playlist, + i_popup_item,VLC_TRUE ); + activateItem( p_item ); + } PL_UNLOCK; } +void PLModel::popupInfo() +{ + playlist_item_t *p_item = playlist_ItemGetById( p_playlist, + i_popup_item,VLC_TRUE ); + if( p_item ) + { + MediaInfoDialog *mid = new MediaInfoDialog( p_intf ); + mid->setInput( p_item->p_input ); + mid->show(); + } +} + +void PLModel::popupStream() +{ + fprintf( stderr, "Stream not implemented\n" ); +} +void PLModel::popupSave() +{ + fprintf( stderr, "Save not implemented\n" ); +} + /********************************************************************** * Playlist callbacks **********************************************************************/ @@ -710,7 +908,8 @@ static int PlaylistChanged( vlc_object_t *p_this, const char *psz_variable, vlc_value_t oval, vlc_value_t nval, void *param ) { PLModel *p_model = (PLModel *) param; - p_model->b_need_update = VLC_TRUE; + PLEvent *event = new PLEvent( PLUpdate_Type, 0 ); + QApplication::postEvent( p_model, static_cast(event) ); return VLC_SUCCESS; } @@ -752,8 +951,8 @@ static int ItemAppended( vlc_object_t *p_this, const char *psz_variable, if( ++p_model->i_items_to_append >= 50 ) { - p_model->b_need_update = VLC_TRUE; - return VLC_SUCCESS; +// p_model->b_need_update = VLC_TRUE; +// return VLC_SUCCESS; } PLEvent *event = new PLEvent( p_add ); QApplication::postEvent( p_model, static_cast(event) );