diff --git a/src/libtomahawk/database/databasecommand_allalbums.cpp b/src/libtomahawk/database/databasecommand_allalbums.cpp index cd6784864..ee31bf22c 100644 --- a/src/libtomahawk/database/databasecommand_allalbums.cpp +++ b/src/libtomahawk/database/databasecommand_allalbums.cpp @@ -21,6 +21,7 @@ #include #include "databaseimpl.h" +#include "utils/tomahawkutils.h" #include "utils/logger.h" @@ -29,7 +30,7 @@ DatabaseCommand_AllAlbums::execForArtist( DatabaseImpl* dbi ) { TomahawkSqlQuery query = dbi->newquery(); QList al; - QString orderToken, sourceToken; + QString orderToken, sourceToken, filterToken, tables; switch ( m_sortOrder ) { @@ -43,17 +44,33 @@ DatabaseCommand_AllAlbums::execForArtist( DatabaseImpl* dbi ) if ( !m_collection.isNull() ) sourceToken = QString( "AND file.source %1 " ).arg( m_collection->source()->isLocal() ? "IS NULL" : QString( "= %1" ).arg( m_collection->source()->id() ) ); + if ( !m_filter.isEmpty() ) + { + QString filtersql; + QStringList sl = m_filter.split( " ", QString::SkipEmptyParts ); + foreach( QString s, sl ) + { + filtersql += QString( " AND ( artist.name LIKE '%%1%' OR album.name LIKE '%%1%' OR track.name LIKE '%%1%' )" ).arg( TomahawkUtils::sqlEscape( s ) ); + } + + filterToken = QString( "AND artist.id = file_join.artist AND file_join.track = track.id %1" ).arg( filtersql ); + tables = "artist, track, file, file_join"; + } + else + tables = "file, file_join"; + QString sql = QString( "SELECT DISTINCT album.id, album.name " - "FROM file, file_join " + "FROM %1 " "LEFT OUTER JOIN album " "ON file_join.album = album.id " "WHERE file.id = file_join.file " - "AND file_join.artist = %1 " - "%2 " - "%3 %4 %5" - ).arg( m_artist->id() ) + "AND file_join.artist = %2 " + "%3 %4 %5 %6 %7" + ).arg( tables ) + .arg( m_artist->id() ) .arg( sourceToken ) + .arg( filterToken ) .arg( m_sortOrder > 0 ? QString( "ORDER BY %1" ).arg( orderToken ) : QString() ) .arg( m_sortDescending ? "DESC" : QString() ) .arg( m_amount > 0 ? QString( "LIMIT 0, %1" ).arg( m_amount ) : QString() ); diff --git a/src/libtomahawk/database/databasecommand_allalbums.h b/src/libtomahawk/database/databasecommand_allalbums.h index 8a13ea576..0f077628c 100644 --- a/src/libtomahawk/database/databasecommand_allalbums.h +++ b/src/libtomahawk/database/databasecommand_allalbums.h @@ -59,6 +59,7 @@ public: void setLimit( unsigned int amount ) { m_amount = amount; } void setSortOrder( DatabaseCommand_AllAlbums::SortOrder order ) { m_sortOrder = order; } void setSortDescending( bool descending ) { m_sortDescending = descending; } + void setFilter( const QString& filter ) { m_filter = filter; } signals: void albums( const QList&, const QVariant& data ); @@ -71,6 +72,7 @@ private: unsigned int m_amount; DatabaseCommand_AllAlbums::SortOrder m_sortOrder; bool m_sortDescending; + QString m_filter; }; #endif // DATABASECOMMAND_ALLALBUMS_H diff --git a/src/libtomahawk/playlist/artistview.cpp b/src/libtomahawk/playlist/artistview.cpp index 584902930..c0903b2d7 100644 --- a/src/libtomahawk/playlist/artistview.cpp +++ b/src/libtomahawk/playlist/artistview.cpp @@ -25,6 +25,7 @@ #include "audio/audioengine.h" #include "dynamic/widgets/LoadingSpinner.h" +#include "widgets/overlaywidget.h" #include "tomahawksettings.h" #include "treeheader.h" @@ -40,6 +41,7 @@ using namespace Tomahawk; ArtistView::ArtistView( QWidget* parent ) : QTreeView( parent ) , m_header( new TreeHeader( this ) ) + , m_overlay( new OverlayWidget( this ) ) , m_model( 0 ) , m_proxyModel( 0 ) // , m_delegate( 0 ) @@ -124,6 +126,8 @@ ArtistView::setTreeModel( TreeModel* model ) connect( m_model, SIGNAL( loadingStarted() ), m_loadingSpinner, SLOT( fadeIn() ) ); connect( m_model, SIGNAL( loadingFinished() ), m_loadingSpinner, SLOT( fadeOut() ) ); + connect( m_proxyModel, SIGNAL( filteringStarted() ), SLOT( onFilteringStarted() ) ); + connect( m_proxyModel, SIGNAL( filteringFinished() ), m_loadingSpinner, SLOT( fadeOut() ) ); connect( m_proxyModel, SIGNAL( filterChanged( QString ) ), SLOT( onFilterChanged( QString ) ) ); connect( m_proxyModel, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onViewChanged() ) ); @@ -206,12 +210,20 @@ ArtistView::onFilterChanged( const QString& ) if ( !proxyModel()->filter().isEmpty() && !proxyModel()->trackCount() && model()->trackCount() ) { -/* m_overlay->setText( tr( "Sorry, your filter '%1' did not match any results." ).arg( proxyModel()->filter() ) ); - m_overlay->show();*/ + m_overlay->setText( tr( "Sorry, your filter '%1' did not match any results." ).arg( proxyModel()->filter() ) ); + m_overlay->show(); } -/* else + else if ( model()->trackCount() ) - m_overlay->hide();*/ + m_overlay->hide(); +} + + +void +ArtistView::onFilteringStarted() +{ + m_overlay->hide(); + m_loadingSpinner->fadeIn(); } diff --git a/src/libtomahawk/playlist/artistview.h b/src/libtomahawk/playlist/artistview.h index 3f7a522d3..4ab9201fc 100644 --- a/src/libtomahawk/playlist/artistview.h +++ b/src/libtomahawk/playlist/artistview.h @@ -31,6 +31,7 @@ class TreeHeader; class LoadingSpinner; +class OverlayWidget; class DLLEXPORT ArtistView : public QTreeView, public Tomahawk::ViewPage { @@ -47,7 +48,8 @@ public: TreeModel* model() const { return m_model; } TreeProxyModel* proxyModel() const { return m_proxyModel; } -// PlaylistItemDelegate* delegate() { return m_delegate; } + OverlayWidget* overlay() const { return m_overlay; } + // PlaylistItemDelegate* delegate() { return m_delegate; } void setModel( QAbstractItemModel* model ); void setTreeModel( TreeModel* model ); @@ -79,6 +81,7 @@ protected: private slots: void onFilterChanged( const QString& filter ); + void onFilteringStarted(); void onViewChanged(); void onScrollTimeout(); @@ -87,11 +90,12 @@ private slots: private: TreeHeader* m_header; + OverlayWidget* m_overlay; TreeModel* m_model; TreeProxyModel* m_proxyModel; // PlaylistItemDelegate* m_delegate; - LoadingSpinner* m_loadingSpinner; + QModelIndex m_contextMenuIndex; Tomahawk::ContextMenu* m_contextMenu; diff --git a/src/libtomahawk/playlist/trackproxymodel.cpp b/src/libtomahawk/playlist/trackproxymodel.cpp index b3d871a81..cbdd14a04 100644 --- a/src/libtomahawk/playlist/trackproxymodel.cpp +++ b/src/libtomahawk/playlist/trackproxymodel.cpp @@ -181,6 +181,7 @@ TrackProxyModel::currentItem() const return Tomahawk::result_ptr(); } + bool TrackProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const { diff --git a/src/libtomahawk/playlist/treemodel.cpp b/src/libtomahawk/playlist/treemodel.cpp index 357df0edc..47520ae6c 100644 --- a/src/libtomahawk/playlist/treemodel.cpp +++ b/src/libtomahawk/playlist/treemodel.cpp @@ -190,6 +190,20 @@ TreeModel::fetchMore( const QModelIndex& parent ) } +bool +TreeModel::hasChildren( const QModelIndex& parent ) const +{ + TreeModelItem* parentItem = itemFromIndex( parent ); + if ( !parentItem ) + return false; + + if ( parentItem == m_rootItem ) + return true; + + return ( !parentItem->artist().isNull() || !parentItem->album().isNull() ); +} + + int TreeModel::rowCount( const QModelIndex& parent ) const { @@ -200,12 +214,6 @@ TreeModel::rowCount( const QModelIndex& parent ) const if ( !parentItem ) return 0; - if ( !parentItem->artist().isNull() || !parentItem->album().isNull() ) - { - if ( !parentItem->children.count() ) - return 1; - } - return parentItem->children.count(); } @@ -667,8 +675,6 @@ TreeModel::onArtistsAdded( const QList& artists ) void TreeModel::onAlbumsAdded( const QList& albums, const QVariant& data ) { - qDebug() << Q_FUNC_INFO << albums.count() << data.toInt(); - emit loadingFinished(); if ( !albums.count() ) return; @@ -681,11 +687,7 @@ TreeModel::onAlbumsAdded( const QList& albums, const QVaria crows.first = c; crows.second = c + albums.count() - 1; - if ( parent.isValid() ) - crows.second -= 1; - - if ( !parent.isValid() || crows.second > 0 ) - emit beginInsertRows( parent, crows.first, crows.second ); + emit beginInsertRows( parent, crows.first, crows.second ); TreeModelItem* albumitem = 0; foreach( const album_ptr& album, albums ) @@ -697,18 +699,13 @@ TreeModel::onAlbumsAdded( const QList& albums, const QVaria getCover( albumitem->index ); } - if ( !parent.isValid() || crows.second > 0 ) - emit endInsertRows(); - else - emit dataChanged( albumitem->index, albumitem->index.sibling( albumitem->index.row(), columnCount( QModelIndex() ) - 1 ) ); + emit endInsertRows(); } void TreeModel::onTracksAdded( const QList& tracks, const QVariant& data ) { - qDebug() << Q_FUNC_INFO << tracks.count(); - emit loadingFinished(); if ( !tracks.count() ) return; @@ -723,11 +720,7 @@ TreeModel::onTracksAdded( const QList& tracks, const QVaria crows.first = c; crows.second = c + tracks.count() - 1; - if ( parent.isValid() ) - crows.second -= 1; - - if ( !parent.isValid() || crows.second > 0 ) - emit beginInsertRows( parent, crows.first, crows.second ); + emit beginInsertRows( parent, crows.first, crows.second ); TreeModelItem* item = 0; foreach( const query_ptr& query, tracks ) @@ -739,10 +732,7 @@ TreeModel::onTracksAdded( const QList& tracks, const QVaria connect( item, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); } - if ( !parent.isValid() || crows.second > 0 ) - emit endInsertRows(); - - emit dataChanged( item->index.sibling( 0, 0 ), item->index.sibling( item->index.row(), columnCount( QModelIndex() ) - 1 ) ); + emit endInsertRows(); } @@ -826,3 +816,27 @@ TreeModel::setColumnStyle( TreeModel::ColumnStyle style ) { m_columnStyle = style; } + + +QModelIndex +TreeModel::indexFromArtist( const Tomahawk::artist_ptr& artist ) const +{ + for ( int i = 0; i < rowCount(); i++ ) + { + QModelIndex idx = index( i, 0, QModelIndex() ); + TreeModelItem* item = itemFromIndex( idx ); + if ( item && item->artist() == artist ) + { + return idx; + } + } + + return QModelIndex(); +} + + +QModelIndex +TreeModel::indexFromAlbum( const Tomahawk::album_ptr& album ) const +{ + return QModelIndex(); +} diff --git a/src/libtomahawk/playlist/treemodel.h b/src/libtomahawk/playlist/treemodel.h index 53205e858..1bc075fe3 100644 --- a/src/libtomahawk/playlist/treemodel.h +++ b/src/libtomahawk/playlist/treemodel.h @@ -64,8 +64,10 @@ public: virtual int trackCount() const { return rowCount( QModelIndex() ); } virtual int albumCount() const { return rowCount( QModelIndex() ); } - virtual int rowCount( const QModelIndex& parent ) const; - virtual int columnCount( const QModelIndex& parent ) const; + virtual bool hasChildren( const QModelIndex& parent = QModelIndex() ) const; + + virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const; + virtual int columnCount( const QModelIndex& parent = QModelIndex() ) const; virtual void clear(); @@ -101,6 +103,9 @@ public: virtual void setTitle( const QString& title ) { m_title = title; } virtual void setDescription( const QString& description ) { m_description = description; } + QModelIndex indexFromArtist( const Tomahawk::artist_ptr& artist ) const; + QModelIndex indexFromAlbum( const Tomahawk::album_ptr& album ) const; + TreeModelItem* itemFromIndex( const QModelIndex& index ) const { if ( index.isValid() ) diff --git a/src/libtomahawk/playlist/treeproxymodel.cpp b/src/libtomahawk/playlist/treeproxymodel.cpp index 5f3b739be..1637469bc 100644 --- a/src/libtomahawk/playlist/treeproxymodel.cpp +++ b/src/libtomahawk/playlist/treeproxymodel.cpp @@ -22,12 +22,14 @@ #include "query.h" #include "database/database.h" +#include "database/databasecommand_allalbums.h" #include "utils/logger.h" TreeProxyModel::TreeProxyModel( QObject* parent ) : QSortFilterProxyModel( parent ) , PlaylistInterface( this ) + , m_artistsFilterCmd( 0 ) , m_model( 0 ) , m_repeatMode( PlaylistInterface::NoRepeat ) , m_shuffled( false ) @@ -54,38 +56,120 @@ TreeProxyModel::setSourceTreeModel( TreeModel* sourceModel ) { m_model = sourceModel; - if ( m_model && m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) - connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); + if ( m_model ) + { + if ( m_model->metaObject()->indexOfSignal( "trackCountChanged(uint)" ) > -1 ) + connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SIGNAL( sourceTrackCountChanged( unsigned int ) ) ); + + connect( m_model, SIGNAL( rowsInserted( QModelIndex, int, int ) ), SLOT( onRowsInserted( QModelIndex, int, int ) ) ); + } QSortFilterProxyModel::setSourceModel( sourceModel ); } void -TreeProxyModel::setFilter( const QString& pattern ) +TreeProxyModel::onRowsInserted( const QModelIndex& parent, int /* start */, int /* end */ ) { - m_filter = pattern; + if ( m_filter.isEmpty() ) + return; + if ( sender() != m_model ) + return; - DatabaseCommand_AllArtists* cmd = new DatabaseCommand_AllArtists( m_model->collection() ); - cmd->setFilter( pattern ); + TreeModelItem* pi = m_model->itemFromIndex( m_model->index( parent.row(), 0, parent.parent() ) ); + if ( pi->artist().isNull() ) + return; - connect( cmd, SIGNAL( artists( QList ) ), - SLOT( onFilterArtists( QList ) ) ); + DatabaseCommand_AllAlbums* cmd = new DatabaseCommand_AllAlbums( m_model->collection() ); + cmd->setArtist( pi->artist() ); + cmd->setFilter( m_filter ); + + connect( cmd, SIGNAL( albums( QList, QVariant ) ), + SLOT( onFilterAlbums( QList ) ) ); Database::instance()->enqueue( QSharedPointer( cmd ) ); } +void +TreeProxyModel::setFilter( const QString& pattern ) +{ + emit filteringStarted(); + + m_filter = pattern; + m_albumsFilter.clear(); + + if ( m_artistsFilterCmd ) + { + disconnect( m_artistsFilterCmd, SIGNAL( artists( QList ) ), + this, SLOT( onFilterArtists( QList ) ) ); + } + + if ( m_filter.isEmpty() ) + { + filterFinished(); + } + else + { + DatabaseCommand_AllArtists* cmd = new DatabaseCommand_AllArtists( m_model->collection() ); + cmd->setFilter( pattern ); + m_artistsFilterCmd = cmd; + + connect( cmd, SIGNAL( artists( QList ) ), + SLOT( onFilterArtists( QList ) ) ); + + Database::instance()->enqueue( QSharedPointer( cmd ) ); + } +} + + void TreeProxyModel::onFilterArtists( const QList& artists ) { + bool finished = true; m_artistsFilter = artists; + foreach ( const Tomahawk::artist_ptr& artist, artists ) + { + QModelIndex idx = m_model->indexFromArtist( artist ); + if ( m_model->rowCount( idx ) ) + { + finished = false; + + DatabaseCommand_AllAlbums* cmd = new DatabaseCommand_AllAlbums( m_model->collection() ); + cmd->setArtist( artist ); + cmd->setFilter( m_filter ); + + connect( cmd, SIGNAL( albums( QList, QVariant ) ), + SLOT( onFilterAlbums( QList ) ) ); + + Database::instance()->enqueue( QSharedPointer( cmd ) ); + } + } + + if ( finished ) + filterFinished(); +} + + +void +TreeProxyModel::onFilterAlbums( const QList& albums ) +{ + m_albumsFilter << albums; + filterFinished(); +} + + +void +TreeProxyModel::filterFinished() +{ + m_artistsFilterCmd = 0; PlaylistInterface::setFilter( m_filter ); setFilterRegExp( m_filter ); emit filterChanged( m_filter ); emit trackCountChanged( trackCount() ); + emit filteringFinished(); } @@ -103,7 +187,8 @@ TreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent if ( result->track() == pi->result()->track() && ( result->albumpos() == pi->result()->albumpos() || result->albumpos() == 0 ) ) { - return ( result.data() == pi->result().data() ); + if ( result.data() != pi->result().data() ) + return false; } } @@ -125,27 +210,34 @@ TreeProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent } } - tDebug() << "Accepting:" << pi->result()->toString() << pi->result()->collection()->source()->id(); +// tDebug() << "Accepting:" << pi->result()->toString() << pi->result()->collection()->source()->id(); m_cache.insertMulti( sourceParent, pi->result() ); } - if ( !filterRegExp().isEmpty() && !pi->artist().isNull() ) - { - return m_artistsFilter.contains( pi->artist() ); - } - return true; + if ( m_filter.isEmpty() ) + return true; - QStringList sl = filterRegExp().pattern().split( " ", QString::SkipEmptyParts ); - bool found = true; + if ( !pi->artist().isNull() ) + return m_artistsFilter.contains( pi->artist() ); + if ( !pi->album().isNull() ) + return m_albumsFilter.contains( pi->album() ); + + QStringList sl = m_filter.split( " ", QString::SkipEmptyParts ); foreach( const QString& s, sl ) { - if ( !textForItem( pi ).contains( s, Qt::CaseInsensitive ) ) + QString album; + if ( !pi->result()->album().isNull() ) + album = pi->result()->album()->name(); + + if ( !pi->result()->track().contains( s, Qt::CaseInsensitive ) && + !album.contains( s, Qt::CaseInsensitive ) && + !pi->result()->album()->artist()->name().contains( s, Qt::CaseInsensitive ) ) { - found = false; + return false; } } - return found; + return true; } diff --git a/src/libtomahawk/playlist/treeproxymodel.h b/src/libtomahawk/playlist/treeproxymodel.h index eba5ae200..4613540a6 100644 --- a/src/libtomahawk/playlist/treeproxymodel.h +++ b/src/libtomahawk/playlist/treeproxymodel.h @@ -26,6 +26,8 @@ #include "dllmacro.h" +class DatabaseCommand_AllArtists; + class DLLEXPORT TreeProxyModel : public QSortFilterProxyModel, public Tomahawk::PlaylistInterface { Q_OBJECT @@ -71,6 +73,8 @@ signals: void sourceTrackCountChanged( unsigned int tracks ); void filterChanged( const QString& filter ); + void filteringStarted(); + void filteringFinished(); void nextTrackReady(); @@ -83,14 +87,21 @@ protected: bool lessThan( const QModelIndex& left, const QModelIndex& right ) const; private slots: + void onRowsInserted( const QModelIndex& parent, int start, int end ); + void onFilterArtists( const QList& artists ); + void onFilterAlbums( const QList& albums ); private: + void filterFinished(); QString textForItem( TreeModelItem* item ) const; mutable QMap< QPersistentModelIndex, Tomahawk::result_ptr > m_cache; QList m_artistsFilter; + QList m_albumsFilter; + DatabaseCommand_AllArtists* m_artistsFilterCmd; + QString m_filter; TreeModel* m_model; diff --git a/src/libtomahawk/widgets/whatshotwidget.cpp b/src/libtomahawk/widgets/whatshotwidget.cpp index 60b72039a..22faeddcd 100644 --- a/src/libtomahawk/widgets/whatshotwidget.cpp +++ b/src/libtomahawk/widgets/whatshotwidget.cpp @@ -157,7 +157,6 @@ WhatsHotWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDat { if ( requestData.caller != s_whatsHotIdentifier ) { - tDebug() << "WhatsHot::" << "Info of wrong type or not with our identifier"; return; }