From 6b247f8bca2eed873b32437b46fca30f3c024273 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Tue, 26 Oct 2010 02:34:10 +0200 Subject: [PATCH] * Added context menu to PlaylistView. * You can now remove tracks from a playlist via the context-menu or by pressing DELETE. --- .../databasecommand_loadplaylistentries.cpp | 1 + src/playlist.cpp | 2 - src/playlist/playlistmodel.cpp | 122 +++++++++++++++++- src/playlist/playlistmodel.h | 8 ++ src/playlist/playlistview.cpp | 73 +++++++++++ src/playlist/playlistview.h | 22 ++++ src/playlist/plitem.cpp | 60 ++++----- src/playlist/plitem.h | 12 +- src/playlist/trackmodel.cpp | 28 ++++ src/playlist/trackmodel.h | 3 + src/playlist/trackproxymodel.cpp | 27 ++++ src/playlist/trackproxymodel.h | 3 + src/playlist/trackview.cpp | 66 +++------- src/playlist/trackview.h | 5 +- src/query.cpp | 2 - 15 files changed, 338 insertions(+), 96 deletions(-) diff --git a/src/database/databasecommand_loadplaylistentries.cpp b/src/database/databasecommand_loadplaylistentries.cpp index 44787fb85..507cabffb 100644 --- a/src/database/databasecommand_loadplaylistentries.cpp +++ b/src/database/databasecommand_loadplaylistentries.cpp @@ -91,6 +91,7 @@ DatabaseCommand_LoadPlaylistEntries::exec( DatabaseImpl* dbi ) if( !query_entries_old.next() ) { + return; Q_ASSERT( false ); } diff --git a/src/playlist.cpp b/src/playlist.cpp index 57c7c8eb2..892e3191e 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -299,8 +299,6 @@ Playlist::setRevision( const QString& rev, m_currentrevision = rev; pr.applied = applied; - - emit revisionLoaded( pr ); } diff --git a/src/playlist/playlistmodel.cpp b/src/playlist/playlistmodel.cpp index eef6de35f..204542f27 100644 --- a/src/playlist/playlistmodel.cpp +++ b/src/playlist/playlistmodel.cpp @@ -9,6 +9,7 @@ using namespace Tomahawk; PlaylistModel::PlaylistModel( QObject* parent ) : TrackModel( parent ) + , m_waitForUpdate( false ) { qDebug() << Q_FUNC_INFO; m_rootItem = new PlItem( 0, this ); @@ -51,8 +52,8 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist ) { emit beginRemoveRows( QModelIndex(), 0, rowCount( QModelIndex() ) - 1 ); delete m_rootItem; - m_rootItem = new PlItem( 0, this ); emit endRemoveRows(); + m_rootItem = new PlItem( 0, this ); } m_playlist = playlist; @@ -68,6 +69,7 @@ PlaylistModel::loadPlaylist( const Tomahawk::playlist_ptr& playlist ) foreach( const plentry_ptr& entry, entries ) { + qDebug() << entry->query()->toString(); plitem = new PlItem( entry, m_rootItem ); plitem->index = createIndex( m_rootItem->children.count() - 1, 0, plitem ); @@ -95,5 +97,121 @@ PlaylistModel::onRevisionLoaded( Tomahawk::PlaylistRevision revision ) { qDebug() << Q_FUNC_INFO; - loadPlaylist( m_playlist ); + if ( m_waitForUpdate ) + { + qDebug() << m_playlist->currentrevision() << revision.revisionguid; + m_waitForUpdate = false; + } + else + loadPlaylist( m_playlist ); +} + + +bool +PlaylistModel::dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent ) +{ + if ( action == Qt::IgnoreAction ) + return true; + + if ( !data->hasFormat( "application/tomahawk.query.list" ) && !data->hasFormat( "application/tomahawk.plentry.list" ) ) + return false; + + int beginRow; + if ( row != -1 ) + beginRow = row; + else if ( parent.isValid() ) + beginRow = parent.row(); + else + beginRow = rowCount( QModelIndex() ); + + qDebug() << data->formats(); + + if ( data->hasFormat( "application/tomahawk.query.list" ) ) + { + QByteArray itemData = data->data( "application/tomahawk.query.list" ); + QDataStream stream( &itemData, QIODevice::ReadOnly ); + QList queries; + + while ( !stream.atEnd() ) + { + qlonglong qptr; + stream >> qptr; + + Tomahawk::query_ptr* query = reinterpret_cast(qptr); + if ( query && !query->isNull() ) + { + qDebug() << "Dropped query item:" << query->data()->artist() << "-" << query->data()->track(); + queries << *query; + } + } + + emit beginInsertRows( QModelIndex(), beginRow, beginRow + queries.count() - 1 ); + foreach( const Tomahawk::query_ptr& query, queries ) + { + plentry_ptr e( new PlaylistEntry() ); + e->setGuid( uuid() ); + + if ( query->results().count() ) + e->setDuration( query->results().at( 0 )->duration() ); + else + e->setDuration( 0 ); + + e->setLastmodified( 0 ); + e->setAnnotation( "" ); // FIXME + e->setQuery( query ); + + PlItem* plitem = new PlItem( e, m_rootItem, beginRow ); + plitem->index = createIndex( beginRow++, 0, plitem ); + + connect( plitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); + } + emit endInsertRows(); + } + + return true; +} + + +void +PlaylistModel::onPlaylistChanged() +{ + qDebug() << Q_FUNC_INFO; + + QList l = playlistEntries(); + foreach( const plentry_ptr& ple, l ) + { + qDebug() << "updateinternal:" << ple->query()->toString(); + } + + QString newrev = uuid(); + m_playlist->createNewRevision( newrev, m_playlist->currentrevision(), l ); +} + + +QList +PlaylistModel::playlistEntries() const +{ + QList l; + for ( int i = 0; i < rowCount( QModelIndex() ); i++ ) + { + QModelIndex idx = index( i, 0, QModelIndex() ); + if ( !idx.isValid() ) + continue; + + PlItem* item = itemFromIndex( idx ); + if ( item ) + l << item->entry(); + } + + return l; +} + + +void +PlaylistModel::removeIndex( const QModelIndex& index ) +{ + TrackModel::removeIndex( index ); + + m_waitForUpdate = true; + onPlaylistChanged(); } diff --git a/src/playlist/playlistmodel.h b/src/playlist/playlistmodel.h index 10c133267..cc93a6d6a 100644 --- a/src/playlist/playlistmodel.h +++ b/src/playlist/playlistmodel.h @@ -28,8 +28,12 @@ public: QVariant data( const QModelIndex& index, int role ) const; QVariant headerData( int section, Qt::Orientation orientation, int role ) const; + virtual bool dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent ); + void loadPlaylist( const Tomahawk::playlist_ptr& playlist ); + virtual void removeIndex( const QModelIndex& index ); + signals: void repeatModeChanged( PlaylistInterface::RepeatMode mode ); void shuffleModeChanged( bool enabled ); @@ -43,9 +47,13 @@ private slots: void onDataChanged(); void onRevisionLoaded( Tomahawk::PlaylistRevision revision ); + void onPlaylistChanged(); private: + QList playlistEntries() const; + Tomahawk::playlist_ptr m_playlist; + bool m_waitForUpdate; }; #endif // PLAYLISTMODEL_H diff --git a/src/playlist/playlistview.cpp b/src/playlist/playlistview.cpp index 388bef5f5..12523cc71 100644 --- a/src/playlist/playlistview.cpp +++ b/src/playlist/playlistview.cpp @@ -1,6 +1,7 @@ #include "playlistview.h" #include +#include #include "playlist/playlistproxymodel.h" @@ -11,6 +12,7 @@ PlaylistView::PlaylistView( QWidget* parent ) : TrackView( parent ) { setProxyModel( new PlaylistProxyModel( this ) ); + setupMenus(); } @@ -18,3 +20,74 @@ PlaylistView::~PlaylistView() { qDebug() << Q_FUNC_INFO; } + + +void +PlaylistView::setupMenus() +{ + m_playItemAction = m_itemMenu.addAction( tr( "&Play" ) ); + m_itemMenu.addSeparator(); + m_addItemsToPlaylistAction = m_itemMenu.addAction( tr( "&Add to Playlist" ) ); + m_itemMenu.addSeparator(); + m_deleteItemAction = m_itemMenu.addAction( tr( "&Delete Item" ) ); + + connect( m_playItemAction, SIGNAL( triggered() ), SLOT( playItem() ) ); + connect( m_addItemsToPlaylistAction, SIGNAL( triggered() ), SLOT( addItemsToPlaylist() ) ); + connect( m_deleteItemAction, SIGNAL( triggered() ), SLOT( deleteItem() ) ); + + setContextMenuPolicy( Qt::CustomContextMenu ); + connect( this, SIGNAL( customContextMenuRequested( const QPoint& ) ), SLOT( onCustomContextMenu( const QPoint& ) ) ); +} + + +void +PlaylistView::onCustomContextMenu( const QPoint& pos ) +{ + qDebug() << Q_FUNC_INFO; + + QModelIndex idx = indexAt( pos ); + idx = idx.sibling( idx.row(), 0 ); + m_contextMenuIndex = idx; + + if ( !idx.isValid() ) + return; + + m_itemMenu.exec( mapToGlobal( pos ) ); +} + + +void +PlaylistView::keyPressEvent( QKeyEvent* event ) +{ + qDebug() << Q_FUNC_INFO; + QTreeView::keyPressEvent( event ); + + if ( !model() ) + return; + + if ( event->key() == Qt::Key_Delete ) + { + qDebug() << "Removing selected items"; + proxyModel()->removeIndexes( selectedIndexes() ); + } +} + + +void +PlaylistView::playItem() +{ + onItemActivated( m_contextMenuIndex ); +} + + +void +PlaylistView::addItemToPlaylist() +{ +} + + +void +PlaylistView::deleteItem() +{ + proxyModel()->removeIndex( m_contextMenuIndex ); +} diff --git a/src/playlist/playlistview.h b/src/playlist/playlistview.h index 9ed1138d2..12d68a5d7 100644 --- a/src/playlist/playlistview.h +++ b/src/playlist/playlistview.h @@ -1,6 +1,8 @@ #ifndef PLAYLISTVIEW_H #define PLAYLISTVIEW_H +#include + #include "tomahawk/tomahawkapp.h" #include "trackview.h" @@ -11,6 +13,26 @@ Q_OBJECT public: explicit PlaylistView( QWidget* parent = 0 ); ~PlaylistView(); + +protected: + virtual void keyPressEvent( QKeyEvent* event ); + +private slots: + void onCustomContextMenu( const QPoint& pos ); + + void playItem(); + void addItemToPlaylist(); + void deleteItem(); + +private: + void setupMenus(); + + QModelIndex m_contextMenuIndex; + + QMenu m_itemMenu; + QAction* m_playItemAction; + QAction* m_addItemsToPlaylistAction; + QAction* m_deleteItemAction; }; #endif // PLAYLISTVIEW_H diff --git a/src/playlist/plitem.cpp b/src/playlist/plitem.cpp index dd341fc9c..efaa0eb70 100644 --- a/src/playlist/plitem.cpp +++ b/src/playlist/plitem.cpp @@ -9,12 +9,16 @@ using namespace Tomahawk; PlItem::~PlItem() { - qDeleteAll( children ); + // Don't use qDeleteAll here! The children will remove themselves + // from the list when they get deleted and the qDeleteAll iterator + // will fail badly! + for ( int i = children.count() - 1; i >= 0; i-- ) + delete children.at( i ); -// Q_ASSERT( parent->children.at( m_parentPos ) == this ); - - if ( parent ) - parent->children.removeAt( m_parentPos ); + if ( parent && index.isValid() ) + { + parent->children.removeAt( index.row() ); + } } @@ -28,7 +32,6 @@ PlItem::PlItem( PlItem* parent, QAbstractItemModel* model ) if ( parent ) { parent->children.append( this ); - m_parentPos = parent->children.count() - 1; } } @@ -45,38 +48,42 @@ PlItem::PlItem( const QString& caption, PlItem* parent ) if ( parent ) { parent->children.append( this ); - m_parentPos = parent->children.count() - 1; } } -PlItem::PlItem( const Tomahawk::query_ptr& query, PlItem* parent ) +PlItem::PlItem( const Tomahawk::query_ptr& query, PlItem* parent, int row ) : QObject( parent ) { - setupItem( query, parent ); + setupItem( query, parent, row ); } -PlItem::PlItem( const Tomahawk::plentry_ptr& entry, PlItem* parent ) +PlItem::PlItem( const Tomahawk::plentry_ptr& entry, PlItem* parent, int row ) : QObject( parent ) , m_entry( entry ) { - setupItem( entry->query(), parent ); + setupItem( entry->query(), parent, row ); } void -PlItem::setupItem( const Tomahawk::query_ptr& query, PlItem* parent ) +PlItem::setupItem( const Tomahawk::query_ptr& query, PlItem* parent, int row ) { this->parent = parent; if ( parent ) { - parent->children.append( this ); - m_parentPos = parent->children.count() - 1; - this->model = parent->model; + if ( row < 0 ) + { + parent->children.append( this ); + row = parent->children.count() - 1; + } + else + { + parent->children.insert( row, this ); + } - connect( model, SIGNAL( rowsRemoved( QModelIndex, int, int ) ), - SLOT( onModelRowsRemoved( QModelIndex, int, int ) ) ); + this->model = parent->model; } m_isPlaying = false; @@ -104,24 +111,5 @@ PlItem::onResultsAdded( const QList& results ) void PlItem::onResultsRemoved( const Tomahawk::result_ptr& result ) { - qDebug() << Q_FUNC_INFO; emit dataChanged(); } - - -void -PlItem::onModelRowsRemoved( const QModelIndex& index, int start, int end ) -{ - if ( !toberemoved && this->parent->index == index ) - { - if ( ( start <= m_parentPos ) && ( m_parentPos <= end ) ) - toberemoved = true; - else - { - if ( start < m_parentPos ) - { - m_parentPos -= ( end - start ) + 1; - } - } - } -} diff --git a/src/playlist/plitem.h b/src/playlist/plitem.h index 95afdd69e..9c06999ac 100644 --- a/src/playlist/plitem.h +++ b/src/playlist/plitem.h @@ -2,7 +2,7 @@ #define PLITEM_H #include -#include +#include #include #include "tomahawk/query.h" @@ -17,8 +17,8 @@ public: explicit PlItem( PlItem* parent = 0, QAbstractItemModel* model = 0 ); explicit PlItem( const QString& caption, PlItem* parent = 0 ); - explicit PlItem( const Tomahawk::query_ptr& query, PlItem* parent = 0 ); - explicit PlItem( const Tomahawk::plentry_ptr& entry, PlItem* parent = 0 ); + explicit PlItem( const Tomahawk::query_ptr& query, PlItem* parent = 0, int row = -1 ); + explicit PlItem( const Tomahawk::plentry_ptr& entry, PlItem* parent = 0, int row = -1 ); const Tomahawk::plentry_ptr& entry() const { return m_entry; }; const Tomahawk::query_ptr& query() const { return m_query; }; @@ -31,7 +31,7 @@ public: QHash hash; QString caption; int childCount; - QModelIndex index; + QPersistentModelIndex index; QAbstractItemModel* model; bool toberemoved; @@ -41,15 +41,13 @@ signals: private slots: void onResultsAdded( const QList& result ); void onResultsRemoved( const Tomahawk::result_ptr& result ); - void onModelRowsRemoved( const QModelIndex& index, int start, int end ); private: - void setupItem( const Tomahawk::query_ptr& query, PlItem* parent ); + void setupItem( const Tomahawk::query_ptr& query, PlItem* parent, int row = -1 ); Tomahawk::plentry_ptr m_entry; Tomahawk::query_ptr m_query; bool m_isPlaying; - int m_parentPos; }; #endif // PLITEM_H diff --git a/src/playlist/trackmodel.cpp b/src/playlist/trackmodel.cpp index 617bd30c8..6a4445b7e 100644 --- a/src/playlist/trackmodel.cpp +++ b/src/playlist/trackmodel.cpp @@ -260,3 +260,31 @@ TrackModel::mimeData( const QModelIndexList &indexes ) const return mimeData; } + + +void +TrackModel::removeIndex( const QModelIndex& index ) +{ + qDebug() << Q_FUNC_INFO; + + if ( index.column() > 0 ) + return; + + PlItem* item = itemFromIndex( index ); + if ( item ) + { + emit beginRemoveRows( index.parent(), index.row(), index.row() ); + delete item; + emit endRemoveRows(); + } +} + + +void +TrackModel::removeIndexes( const QList& indexes ) +{ + foreach( const QModelIndex& idx, indexes ) + { + removeIndex( idx ); + } +} diff --git a/src/playlist/trackmodel.h b/src/playlist/trackmodel.h index d090735bb..f8893b07a 100644 --- a/src/playlist/trackmodel.h +++ b/src/playlist/trackmodel.h @@ -26,6 +26,9 @@ public: virtual QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const; virtual QVariant headerData( int section, Qt::Orientation orientation, int role ) const; + virtual void removeIndex( const QModelIndex& index ); + virtual void removeIndexes( const QList& indexes ); + virtual PlItem* previousItem() { return 0; } virtual PlItem* nextItem() { return 0; } virtual PlItem* siblingItem( int direction ) { return 0; } diff --git a/src/playlist/trackproxymodel.cpp b/src/playlist/trackproxymodel.cpp index 2ece99d0f..9edd1b99f 100644 --- a/src/playlist/trackproxymodel.cpp +++ b/src/playlist/trackproxymodel.cpp @@ -168,3 +168,30 @@ TrackProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParen return found; } + + +void +TrackProxyModel::removeIndex( const QModelIndex& index ) +{ + qDebug() << Q_FUNC_INFO; + + if ( !sourceModel() ) + return; + if ( index.column() > 0 ) + return; + + sourceModel()->removeIndex( mapToSource( index ) ); +} + + +void +TrackProxyModel::removeIndexes( const QList& indexes ) +{ + if ( !sourceModel() ) + return; + + foreach( const QModelIndex& idx, indexes ) + { + removeIndex( idx ); + } +} diff --git a/src/playlist/trackproxymodel.h b/src/playlist/trackproxymodel.h index dc307b28a..70143c016 100644 --- a/src/playlist/trackproxymodel.h +++ b/src/playlist/trackproxymodel.h @@ -21,6 +21,9 @@ public: virtual int trackCount() const { return rowCount( QModelIndex() ); } + virtual void removeIndex( const QModelIndex& index ); + virtual void removeIndexes( const QList& indexes ); + virtual PlItem* previousItem(); virtual PlItem* nextItem(); virtual PlItem* siblingItem( int itemsAway ); diff --git a/src/playlist/trackview.cpp b/src/playlist/trackview.cpp index 755366477..955449704 100644 --- a/src/playlist/trackview.cpp +++ b/src/playlist/trackview.cpp @@ -29,7 +29,7 @@ TrackView::TrackView( QWidget* parent ) setDragEnabled( true ); setDropIndicatorShown( false ); setDragDropMode( QAbstractItemView::InternalMove ); - setDragDropOverwriteMode ( false ); + setDragDropOverwriteMode( false ); setAllColumnsShowFocus( true ); header()->setMinimumSectionSize( 60 ); @@ -186,39 +186,6 @@ TrackView::resizeColumns() } -void -TrackView::keyPressEvent( QKeyEvent* event ) -{ -// qDebug() << Q_FUNC_INFO; - QTreeView::keyPressEvent( event ); - - if ( !m_model ) - return; - - if ( event->key() == Qt::Key_Delete ) - { -/* if ( m_model->isPlaylistBacked() && selectedIndexes().count() ) - { - qDebug() << "Removing selected items"; - QList items; - - QModelIndexList sidxs = selectedIndexes(); - foreach( const QModelIndex& idx, sidxs ) - { - if ( idx.column() > 0 ) - continue; - - PlaylistItem* item = PlaylistModel::indexToPlaylistItem( idx ); - if ( item ) - items << item; - } - - m_model->removeItems( items ); - }*/ - } -} - - void TrackView::dragEnterEvent( QDragEnterEvent* event ) { @@ -329,24 +296,25 @@ TrackView::onFilterChanged( const QString& ) void TrackView::startDrag( Qt::DropActions supportedActions ) { + QList pindexes; QModelIndexList indexes = selectedIndexes(); - qDebug() << "Dragging" << indexes.count() << "indexes"; for( int i = indexes.count() - 1 ; i >= 0; --i ) { - if( !( m_proxyModel->flags( indexes.at( i ) ) & Qt::ItemIsDragEnabled ) ) + if ( !( m_proxyModel->flags( indexes.at( i ) ) & Qt::ItemIsDragEnabled ) ) indexes.removeAt( i ); + else + pindexes << indexes.at( i ); } - if( indexes.count() == 0 ) + if ( indexes.count() == 0 ) return; qDebug() << "Dragging" << indexes.count() << "indexes"; - - QMimeData *data = m_proxyModel->mimeData( indexes ); + QMimeData* data = m_proxyModel->mimeData( indexes ); if ( !data ) return; - QDrag *drag = new QDrag( this ); + QDrag* drag = new QDrag( this ); drag->setMimeData( data ); const QPixmap p = createDragPixmap( indexes.count() ); drag->setPixmap( p ); @@ -355,7 +323,15 @@ TrackView::startDrag( Qt::DropActions supportedActions ) // NOTE: if we support moving items in the model // in the future, if exec() returns Qt::MoveAction // we need to clean up ourselves. - drag->exec( supportedActions, Qt::CopyAction ); + Qt::DropAction action = drag->exec( supportedActions, Qt::CopyAction ); + + if ( action == Qt::MoveAction ) + { + foreach ( const QPersistentModelIndex& idx, pindexes ) + { + m_proxyModel->removeIndex( idx ); + } + } } @@ -396,22 +372,22 @@ TrackView::createDragPixmap( int itemCount ) const QPixmap dragPixmap( xCount * size + xCount - 1, yCount * size + yCount - 1 ); dragPixmap.fill( Qt::transparent ); - QPainter painter(&dragPixmap); + QPainter painter( &dragPixmap ); painter.setRenderHint( QPainter::Antialiasing ); int x = 0; int y = 0; for( int i = 0; i < itemCount; ++i ) { const QPixmap pixmap = QPixmap( QString( ":/data/icons/audio-x-generic-%2.png" ).arg( size ) ); - painter.drawPixmap(x, y, pixmap); + painter.drawPixmap( x, y, pixmap ); x += size + 1; - if (x >= dragPixmap.width()) + if ( x >= dragPixmap.width() ) { x = 0; y += size + 1; } - if (y >= dragPixmap.height()) + if ( y >= dragPixmap.height() ) { break; } diff --git a/src/playlist/trackview.h b/src/playlist/trackview.h index 010f011dd..e376ff6f6 100644 --- a/src/playlist/trackview.h +++ b/src/playlist/trackview.h @@ -26,9 +26,11 @@ public: void setModel( TrackModel* model ); +public slots: + void onItemActivated( const QModelIndex& index ); + protected: virtual void resizeEvent( QResizeEvent* event ); - virtual void keyPressEvent( QKeyEvent* event ); virtual void startDrag( Qt::DropActions supportedActions ); virtual void dragEnterEvent( QDragEnterEvent* event ); @@ -39,7 +41,6 @@ protected: void paintEvent( QPaintEvent* event ); private slots: - void onItemActivated( const QModelIndex& index ); void onItemResized( const QModelIndex& index ); void resizeColumns(); diff --git a/src/query.cpp b/src/query.cpp index ff5cbddfa..b5de0088e 100644 --- a/src/query.cpp +++ b/src/query.cpp @@ -47,8 +47,6 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults ) void Query::resultUnavailable() { - qDebug() << Q_FUNC_INFO; - Result* result = (Result*) sender(); Q_ASSERT( result );