1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-03-19 23:39:42 +01:00

* Fine-tuned filtering tree-models.

This commit is contained in:
Christian Muehlhaeuser 2011-09-05 09:26:45 +02:00
parent 9ef5894685
commit f3c19779cd
10 changed files with 220 additions and 63 deletions

View File

@ -21,6 +21,7 @@
#include <QSqlQuery>
#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<Tomahawk::album_ptr> 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() );

View File

@ -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<Tomahawk::album_ptr>&, 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

View File

@ -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();
}

View File

@ -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;

View File

@ -181,6 +181,7 @@ TrackProxyModel::currentItem() const
return Tomahawk::result_ptr();
}
bool
TrackProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
{

View File

@ -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<Tomahawk::artist_ptr>& artists )
void
TreeModel::onAlbumsAdded( const QList<Tomahawk::album_ptr>& 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<Tomahawk::album_ptr>& 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<Tomahawk::album_ptr>& 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<Tomahawk::query_ptr>& tracks, const QVariant& data )
{
qDebug() << Q_FUNC_INFO << tracks.count();
emit loadingFinished();
if ( !tracks.count() )
return;
@ -723,11 +720,7 @@ TreeModel::onTracksAdded( const QList<Tomahawk::query_ptr>& 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<Tomahawk::query_ptr>& 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();
}

View File

@ -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() )

View File

@ -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<Tomahawk::artist_ptr> ) ),
SLOT( onFilterArtists( QList<Tomahawk::artist_ptr> ) ) );
DatabaseCommand_AllAlbums* cmd = new DatabaseCommand_AllAlbums( m_model->collection() );
cmd->setArtist( pi->artist() );
cmd->setFilter( m_filter );
connect( cmd, SIGNAL( albums( QList<Tomahawk::album_ptr>, QVariant ) ),
SLOT( onFilterAlbums( QList<Tomahawk::album_ptr> ) ) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
void
TreeProxyModel::setFilter( const QString& pattern )
{
emit filteringStarted();
m_filter = pattern;
m_albumsFilter.clear();
if ( m_artistsFilterCmd )
{
disconnect( m_artistsFilterCmd, SIGNAL( artists( QList<Tomahawk::artist_ptr> ) ),
this, SLOT( onFilterArtists( QList<Tomahawk::artist_ptr> ) ) );
}
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<Tomahawk::artist_ptr> ) ),
SLOT( onFilterArtists( QList<Tomahawk::artist_ptr> ) ) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
}
void
TreeProxyModel::onFilterArtists( const QList<Tomahawk::artist_ptr>& 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<Tomahawk::album_ptr>, QVariant ) ),
SLOT( onFilterAlbums( QList<Tomahawk::album_ptr> ) ) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
}
if ( finished )
filterFinished();
}
void
TreeProxyModel::onFilterAlbums( const QList<Tomahawk::album_ptr>& 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;
}

View File

@ -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<Tomahawk::artist_ptr>& artists );
void onFilterAlbums( const QList<Tomahawk::album_ptr>& albums );
private:
void filterFinished();
QString textForItem( TreeModelItem* item ) const;
mutable QMap< QPersistentModelIndex, Tomahawk::result_ptr > m_cache;
QList<Tomahawk::artist_ptr> m_artistsFilter;
QList<Tomahawk::album_ptr> m_albumsFilter;
DatabaseCommand_AllArtists* m_artistsFilterCmd;
QString m_filter;
TreeModel* m_model;

View File

@ -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;
}