1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-07-31 03:10:12 +02:00

* WIP: Fulltext resolving, score bars and score column.

* Added social_attributes table to the database.
* Added db migration script.
* Fixed database migration.
This commit is contained in:
Christian Muehlhaeuser
2011-06-12 05:57:57 +02:00
parent 35590c381c
commit 8c10bdfb07
24 changed files with 384 additions and 273 deletions

View File

@@ -0,0 +1,22 @@
-- Script to migate from db version 23 to 24.
-- Added the social_attributes table.
--
-- Separate each command with %%
CREATE TABLE IF NOT EXISTS social_attributes (
id INTEGER REFERENCES track(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED, -- track id
source INTEGER REFERENCES source(id) ON DELETE CASCADE ON UPDATE CASCADE, -- DEFERRABLE INITIALLY DEFERRED,
k TEXT NOT NULL,
v TEXT NOT NULL,
timestamp INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX social_attrib_id ON social_attributes(id);
CREATE INDEX social_attrib_source ON social_attributes(source);
CREATE INDEX social_attrib_k ON social_attributes(k);
CREATE INDEX social_attrib_timestamp ON social_attributes(timestamp);
UPDATE settings SET v = '24' WHERE k == 'schema_version';

View File

@@ -102,5 +102,6 @@
<file>./data/www/auth.na.html</file>
<file>./data/www/tomahawk_banner_small.png</file>
<file>./data/sql/dbmigrate-22_to_23.sql</file>
<file>./data/sql/dbmigrate-23_to_24.sql</file>
</qresource>
</RCC>

View File

@@ -36,6 +36,13 @@ DatabaseCommand_Resolve::DatabaseCommand_Resolve( const query_ptr& query )
void
DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
{
/*
* Resolving is a 2 stage process.
* 1) find list of trk/art/alb IDs that are reasonable matches to the metadata given
* 2) find files in database by permitted sources and calculate score, ignoring
* results that are less than MINSCORE
*/
if ( !m_query->resultHint().isEmpty() )
{
qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint();
@@ -64,20 +71,12 @@ void
DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
{
QList<Tomahawk::result_ptr> res;
/*
Resolving is a 2 stage process.
1) find list of trk/art/alb IDs that are reasonable matches to the metadata given
2) find files in database by permitted sources and calculate score, ignoring
results that are less than MINSCORE
*/
typedef QPair<int, float> scorepair_t;
// STEP 1
QList< int > artists = lib->searchTable( "artist", m_query->artist(), 10 );
QList< int > tracks = lib->searchTable( "track", m_query->track(), 10 );
QList< int > albums = lib->searchTable( "album", m_query->album(), 10 );
QList< QPair<int, float> > artists = lib->searchTable( "artist", m_query->artist(), 10 );
QList< QPair<int, float> > tracks = lib->searchTable( "track", m_query->track(), 10 );
QList< QPair<int, float> > albums = lib->searchTable( "album", m_query->album(), 10 );
if ( artists.length() == 0 || tracks.length() == 0 )
{
@@ -90,10 +89,10 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
TomahawkSqlQuery files_query = lib->newquery();
QStringList artsl, trksl;
foreach( int i, artists )
artsl.append( QString::number( i ) );
foreach( int i, tracks )
trksl.append( QString::number( i ) );
for ( int k = 0; k < artists.count(); k++ )
artsl.append( QString::number( artists.at( k ).first ) );
for ( int k = 0; k < tracks.count(); k++ )
trksl.append( QString::number( tracks.at( k ).first ) );
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
@@ -189,20 +188,12 @@ void
DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
{
QList<Tomahawk::result_ptr> res;
/*
* Resolving is a 2 stage process.
* 1) find list of trk/art/alb IDs that are reasonable matches to the metadata given
* 2) find files in database by permitted sources and calculate score, ignoring
* results that are less than MINSCORE
*/
typedef QPair<int, float> scorepair_t;
// STEP 1
QList< int > artists = lib->searchTable( "artist", m_query->fullTextQuery(), 10 );
QList< int > tracks = lib->searchTable( "track", m_query->fullTextQuery(), 10 );
QList< int > albums = lib->searchTable( "album", m_query->fullTextQuery(), 10 );
QList< QPair<int, float> > artists = lib->searchTable( "artist", m_query->fullTextQuery(), 10 );
QList< QPair<int, float> > tracks = lib->searchTable( "track", m_query->fullTextQuery(), 10 );
QList< QPair<int, float> > albums = lib->searchTable( "album", m_query->fullTextQuery(), 10 );
if ( artists.length() == 0 && tracks.length() == 0 && albums.length() == 0 )
{
@@ -215,12 +206,12 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
TomahawkSqlQuery files_query = lib->newquery();
QStringList artsl, trksl, albsl;
foreach( int i, artists )
artsl.append( QString::number( i ) );
foreach( int i, tracks )
trksl.append( QString::number( i ) );
foreach( int i, albums )
albsl.append( QString::number( i ) );
for ( int k = 0; k < artists.count(); k++ )
artsl.append( QString::number( artists.at( k ).first ) );
for ( int k = 0; k < tracks.count(); k++ )
trksl.append( QString::number( tracks.at( k ).first ) );
for ( int k = 0; k < albums.count(); k++ )
albsl.append( QString::number( albums.at( k ).first ) );
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
@@ -241,10 +232,8 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
"artist.id = file_join.artist AND "
"track.id = file_join.track AND "
"file.id = file_join.file AND "
"(%1 OR %2 OR %3)" )
.arg( artists.length() > 0 ? artsToken : QString( "0" ) )
.arg( tracks.length() > 0 ? trksToken : QString( "0" ) )
.arg( albums.length() > 0 ? albsToken : QString( "0" ) );
"%1" )
.arg( tracks.length() > 0 ? trksToken : QString( "0" ) );
files_query.prepare( sql );
files_query.exec();
@@ -288,6 +277,15 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
result->setId( files_query.value( 9 ).toUInt() );
result->setYear( files_query.value( 17 ).toUInt() );
for ( int k = 0; k < tracks.count(); k++ )
{
if ( tracks.at( k ).first == (int)result->dbid() )
{
result->setScore( tracks.at( k ).second );
break;
}
}
TomahawkSqlQuery attrQuery = lib->newquery();
QVariantMap attr;
@@ -301,11 +299,6 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
result->setAttributes( attr );
float score = how_similar( m_query, result );
result->setScore( score );
if ( m_query->fullTextQuery().isEmpty() && score < MINSCORE )
continue;
result->setCollection( s->collection() );
res << result;
}

View File

@@ -38,7 +38,7 @@
*/
#include "schema.sql.h"
#define CURRENT_SCHEMA_VERSION 23
#define CURRENT_SCHEMA_VERSION 24
DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
@@ -47,66 +47,46 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
, m_lastalbid( 0 )
, m_lasttrkid( 0 )
{
db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" );
db.setDatabaseName( dbname );
if ( !db.open() )
{
qDebug() << "FAILED TO OPEN DB";
throw "failed to open db"; // TODO
}
QSqlQuery qry = QSqlQuery( db );
bool schemaUpdated = false;
qry.exec( "SELECT v FROM settings WHERE k='schema_version'" );
if ( qry.next() )
int version = getDatabaseVersion( dbname );
if ( version != CURRENT_SCHEMA_VERSION )
{
int v = qry.value( 0 ).toInt();
qDebug() << "Current schema is" << v << this->thread();
if ( v != CURRENT_SCHEMA_VERSION )
QString newname = QString( "%1.v%2" ).arg( dbname ).arg( version );
qDebug() << endl << "****************************" << endl;
qDebug() << "Schema version too old: " << version << ". Current version is:" << CURRENT_SCHEMA_VERSION;
qDebug() << "Moving" << dbname << newname;
qDebug() << "If the migration fails, you can recover your DB by copying" << newname << "back to" << dbname;
qDebug() << endl << "****************************" << endl;
QFile::copy( dbname, newname );
{
db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" );
db.setDatabaseName( dbname );
if( !db.open() )
throw "db moving failed";
QString newname = QString("%1.v%2").arg(dbname).arg(v);
qDebug() << endl << "****************************" << endl;
qDebug() << "Schema version too old: " << v << ". Current version is:" << CURRENT_SCHEMA_VERSION;
qDebug() << "Moving" << dbname << newname;
qDebug() << "If the migration fails, you can recover your DB by copying" << newname << "back to" << dbname;
qDebug() << endl << "****************************" << endl;
TomahawkSqlQuery query = newquery();
query.exec( "PRAGMA auto_vacuum = FULL" );
qry.clear();
qry.finish();
db.close();
db.removeDatabase( "tomahawk" );
if( QFile::copy( dbname, newname ) )
{
db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" );
db.setDatabaseName( dbname );
if( !db.open() )
throw "db moving failed";
TomahawkSqlQuery query = newquery();
query.exec( "PRAGMA auto_vacuum = FULL" );
schemaUpdated = updateSchema( v );
if( !schemaUpdated )
{
Q_ASSERT( false );
QTimer::singleShot( 0, qApp, SLOT( quit() ) );
}
}
else
schemaUpdated = updateSchema( version );
if ( !schemaUpdated )
{
Q_ASSERT( false );
QTimer::singleShot( 0, qApp, SLOT( quit() ) );
return;
}
}
}
else
{
db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" );
db.setDatabaseName( dbname );
if ( !db.open() )
{
qDebug() << "Failed to open database" << dbname;
throw "failed to open db"; // TODO
}
schemaUpdated = updateSchema( 0 );
}
@@ -422,30 +402,23 @@ DatabaseImpl::albumId( int artistid, const QString& name_orig, bool& isnew )
}
QList< int >
QList< QPair<int, float> >
DatabaseImpl::searchTable( const QString& table, const QString& name, uint limit )
{
Q_UNUSED( limit );
QList< int > results;
if( table != "artist" && table != "track" && table != "album" )
return results;
QMap< int, float > resultsmap = m_fuzzyIndex->search( table, name );
QList< QPair<int, float> > resultslist;
if( table != "artist" && table != "track" && table != "album" )
return resultslist;
QMap< int, float > resultsmap = m_fuzzyIndex->search( table, name );
foreach( int i, resultsmap.keys() )
{
resultslist << QPair<int, float>( i, (float)resultsmap.value( i ) );
}
qSort( resultslist.begin(), resultslist.end(), DatabaseImpl::scorepairSorter );
for( int k = 0; k < resultslist.count(); k++ )
{
results << resultslist.at( k ).first;
}
// qDebug() << "Returning" << results.count() << "results";
return results;
return resultslist;
}
@@ -639,3 +612,31 @@ DatabaseImpl::resultFromHint( const Tomahawk::query_ptr& origquery )
return res;
}
int
DatabaseImpl::getDatabaseVersion( const QString& dbname )
{
int version = -1;
{
QSqlDatabase db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" );
db.setDatabaseName( dbname );
if ( !db.open() )
{
qDebug() << "Failed to open database" << dbname;
throw "failed to open db"; // TODO
}
QSqlQuery qry = QSqlQuery( db );
qry.exec( "SELECT v FROM settings WHERE k='schema_version'" );
if ( qry.next() )
{
version = qry.value( 0 ).toInt();
qDebug() << "Database schema of" << dbname << "is" << version;
}
}
QSqlDatabase::removeDatabase( "tomahawk" );
return version;
}

View File

@@ -55,7 +55,7 @@ public:
int trackId( int artistid, const QString& name_orig, bool& isnew );
int albumId( int artistid, const QString& name_orig, bool& isnew );
QList< int > searchTable( const QString& table, const QString& name, uint limit = 10 );
QList< QPair<int, float> > searchTable( const QString& table, const QString& name, uint limit = 10 );
QList< int > getTrackFids( int tid );
static QString sortname( const QString& str );
@@ -84,19 +84,18 @@ signals:
public slots:
private:
static int getDatabaseVersion( const QString& dbname );
QString cleanSql( const QString& sql );
bool m_ready;
bool updateSchema( int oldVersion );
bool m_ready;
QSqlDatabase db;
QString m_lastart, m_lastalb, m_lasttrk;
int m_lastartid, m_lastalbid, m_lasttrkid;
QString m_dbid;
FuzzyIndex* m_fuzzyIndex;
};

View File

@@ -227,6 +227,24 @@ CREATE TABLE IF NOT EXISTS track_attributes (
CREATE INDEX track_attrib_id ON track_attributes(id);
CREATE INDEX track_attrib_k ON track_attributes(k);
-- social attributes connected to the track.
-- like love, hate, comments, recommendations
-- love=[comment], hate=[comment], comment=Some text
-- NB: since all values are text, numeric values should be zero-padded to a set amount
-- so that we can always do range queries.
CREATE TABLE IF NOT EXISTS social_attributes (
id INTEGER REFERENCES track(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED, -- track id
source INTEGER REFERENCES source(id) ON DELETE CASCADE ON UPDATE CASCADE, -- DEFERRABLE INITIALLY DEFERRED,
k TEXT NOT NULL,
v TEXT NOT NULL,
timestamp INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX social_attrib_id ON social_attributes(id);
CREATE INDEX social_attrib_source ON social_attributes(source);
CREATE INDEX social_attrib_k ON social_attributes(k);
CREATE INDEX social_attrib_timestamp ON social_attributes(timestamp);
-- playback history
@@ -264,4 +282,4 @@ CREATE TABLE IF NOT EXISTS settings (
v TEXT NOT NULL DEFAULT ''
);
INSERT INTO settings(k,v) VALUES('schema_version', '23');
INSERT INTO settings(k,v) VALUES('schema_version', '24');

View File

@@ -1,5 +1,5 @@
/*
This file was automatically generated from schema.sql on Fri Apr 15 15:55:52 EDT 2011.
This file was automatically generated from ./schema.sql on Sun Jun 12 05:17:25 CEST 2011.
*/
static const char * tomahawk_schema_sql =
@@ -151,6 +151,17 @@ static const char * tomahawk_schema_sql =
");"
"CREATE INDEX track_attrib_id ON track_attributes(id);"
"CREATE INDEX track_attrib_k ON track_attributes(k);"
"CREATE TABLE IF NOT EXISTS social_attributes ("
" id INTEGER REFERENCES track(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED, "
" source INTEGER REFERENCES source(id) ON DELETE CASCADE ON UPDATE CASCADE, "
" k TEXT NOT NULL,"
" v TEXT NOT NULL,"
" timestamp INTEGER NOT NULL DEFAULT 0"
");"
"CREATE INDEX social_attrib_id ON social_attributes(id);"
"CREATE INDEX social_attrib_source ON social_attributes(source);"
"CREATE INDEX social_attrib_k ON social_attributes(k);"
"CREATE INDEX social_attrib_timestamp ON social_attributes(timestamp);"
"CREATE TABLE IF NOT EXISTS playback_log ("
" id INTEGER PRIMARY KEY AUTOINCREMENT,"
" source INTEGER REFERENCES source(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,"
@@ -172,7 +183,7 @@ static const char * tomahawk_schema_sql =
" k TEXT NOT NULL PRIMARY KEY,"
" v TEXT NOT NULL DEFAULT ''"
");"
"INSERT INTO settings(k,v) VALUES('schema_version', '23');"
"INSERT INTO settings(k,v) VALUES('schema_version', '24');"
;
const char * get_tomahawk_sql()

View File

@@ -29,109 +29,3 @@ CollectionProxyModel::CollectionProxyModel( QObject* parent )
: TrackProxyModel( parent )
{
}
bool
CollectionProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
{
TrackModelItem* p1 = itemFromIndex( left );
TrackModelItem* p2 = itemFromIndex( right );
if ( !p1 )
return true;
if ( !p2 )
return false;
const Tomahawk::query_ptr& q1 = p1->query();
const Tomahawk::query_ptr& q2 = p2->query();
QString artist1 = q1->artist();
QString artist2 = q2->artist();
QString album1 = q1->album();
QString album2 = q2->album();
QString track1 = q1->track();
QString track2 = q2->track();
unsigned int albumpos1 = 0, albumpos2 = 0;
unsigned int bitrate1 = 0, bitrate2 = 0;
unsigned int mtime1 = 0, mtime2 = 0;
unsigned int id1 = 0, id2 = 0;
unsigned int size1 = 0, size2 = 0;
if ( q1->numResults() )
{
const Tomahawk::result_ptr& r = q1->results().at( 0 );
artist1 = r->artist()->name();
album1 = r->album()->name();
track1 = r->track();
albumpos1 = r->albumpos();
bitrate1 = r->bitrate();
mtime1 = r->modificationTime();
id1 = r->dbid();
size1 = r->size();
}
if ( q2->numResults() )
{
const Tomahawk::result_ptr& r = q2->results().at( 0 );
artist2 = r->artist()->name();
album2 = r->album()->name();
track2 = r->track();
albumpos2 = r->albumpos();
bitrate2 = r->bitrate();
mtime2 = r->modificationTime();
id2 = r->dbid();
size2 = r->size();
}
if ( left.column() == TrackModel::Artist ) // sort by artist
{
if ( artist1 == artist2 )
{
if ( album1 == album2 )
{
if ( albumpos1 == albumpos2 )
return id1 < id2;
return albumpos1 < albumpos2;
}
return QString::localeAwareCompare( album1, album2 ) < 0;
}
return QString::localeAwareCompare( artist1, artist2 ) < 0;
}
else if ( left.column() == TrackModel::Album ) // sort by album
{
if ( album1 == album2 )
{
if ( albumpos1 == albumpos2 )
return id1 < id2;
return albumpos1 < albumpos2;
}
return QString::localeAwareCompare( album1, album2 ) < 0;
}
else if ( left.column() == TrackModel::Bitrate ) // sort by bitrate
{
if ( bitrate1 == bitrate2 )
return id1 < id2;
return bitrate1 < bitrate2;
}
else if ( left.column() == TrackModel::Age ) // sort by mtime
{
if ( mtime1 == mtime2 )
return id1 < id2;
return mtime1 < mtime2;
}
else if ( left.column() == TrackModel::Filesize ) // sort by file size
{
if ( size1 == size2 )
return id1 < id2;
return size1 < size2;
}
return QString::localeAwareCompare( sourceModel()->data( left ).toString(),
sourceModel()->data( right ).toString() ) < 0;
}

View File

@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -31,9 +31,6 @@ public:
explicit CollectionProxyModel( QObject* parent = 0 );
virtual PlaylistInterface::ViewMode viewMode() const { return PlaylistInterface::Flat; }
protected:
bool lessThan( const QModelIndex& left, const QModelIndex& right ) const;
};
#endif // COLLECTIONPROXYMODEL_H

View File

@@ -63,8 +63,12 @@ void
CollectionView::setTrackModel( TrackModel* model )
{
TrackView::setTrackModel( model );
setColumnHidden( TrackModel::Score, true ); // Hide age column per default
setGuid( "collectionview" );
setSortingEnabled( true );
sortByColumn( 0, Qt::AscendingOrder );
connect( model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) );
}
@@ -83,14 +87,14 @@ CollectionView::setupMenus()
m_playItemAction = m_itemMenu.addAction( tr( "&Play" ) );
m_addItemsToQueueAction = m_itemMenu.addAction( tr( "Add to &Queue" ) );
m_itemMenu.addSeparator();
m_itemMenu.addSeparator();
foreach( QAction* a, actions() )
m_itemMenu.addAction( a );
foreach( QAction* a, actions() )
m_itemMenu.addAction( a );
// m_addItemsToPlaylistAction = m_itemMenu.addAction( tr( "&Add to Playlist" ) );
connect( m_playItemAction, SIGNAL( triggered() ), SLOT( playItem() ) );
connect( m_addItemsToQueueAction, SIGNAL( triggered() ), SLOT( addItemsToQueue() ) );
connect( m_playItemAction, SIGNAL( triggered() ), SLOT( playItem() ) );
connect( m_addItemsToQueueAction, SIGNAL( triggered() ), SLOT( addItemsToQueue() ) );
// connect( m_addItemsToPlaylistAction, SIGNAL( triggered() ), SLOT( addItemsToPlaylist() ) );
}

View File

@@ -18,6 +18,7 @@
#include "playlistitemdelegate.h"
#include <QApplication>
#include <QDebug>
#include <QPainter>
@@ -36,6 +37,7 @@
PlaylistItemDelegate::PlaylistItemDelegate( TrackView* parent, TrackProxyModel* proxy )
: QStyledItemDelegate( (QObject*)parent )
, m_style( Detailed )
, m_view( parent )
, m_model( proxy )
{
@@ -43,6 +45,13 @@ PlaylistItemDelegate::PlaylistItemDelegate( TrackView* parent, TrackProxyModel*
}
void
PlaylistItemDelegate::setStyle( PlaylistItemDelegate::PlaylistItemStyle style )
{
m_style = style;
}
void
PlaylistItemDelegate::updateRowSize( const QModelIndex& index )
{
@@ -70,6 +79,29 @@ PlaylistItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem&
void
PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
switch ( m_style )
{
case Detailed:
paintDetailed( painter, option, index );
break;
case Short:
paintShort( painter, option, index );
break;
}
}
void
PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
}
void
PlaylistItemDelegate::paintDetailed( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
TrackModelItem* item = m_model->itemFromIndex( m_model->mapToSource( index ) );
if ( !item || item->query().isNull() )
@@ -82,13 +114,46 @@ PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& opti
opacity = qMax( (float)0.3, opacity );
QColor textColor = TomahawkUtils::alphaBlend( option.palette.color( QPalette::Foreground ), option.palette.color( QPalette::Background ), opacity );
if ( item->isPlaying() )
{
// painter->setRenderHint( QPainter::Antialiasing );
painter->save();
QStyleOptionViewItemV4 opt = option;
initStyleOption( &opt, index );
if ( item->isPlaying() )
opt.state |= QStyle::State_Selected;
if ( item->isPlaying() || index.column() == TrackModel::Score )
opt.text.clear();
if ( opt.state & QStyle::State_Selected )
opt.palette.setColor( QPalette::Text, opt.palette.color( QPalette::HighlightedText ) );
qApp->style()->drawControl( QStyle::CE_ItemViewItem, &opt, painter );
painter->save();
if ( index.column() == TrackModel::Score )
{
if ( opt.state & QStyle::State_Selected )
painter->setPen( opt.palette.brightText().color() );
else
painter->setPen( opt.palette.highlight().color() );
QRect r = opt.rect.adjusted( 3, 3, -6, -5 );
painter->drawRect( r );
QRect fillR = r;
int fillerWidth = (int)( index.data().toFloat() * (float)fillR.width() );
fillR.adjust( 0, 0, -( fillR.width() - fillerWidth ), 0 );
if ( opt.state & QStyle::State_Selected )
painter->setBrush( opt.palette.brightText().color() );
else
painter->setBrush( opt.palette.highlight().color() );
painter->drawRect( fillR );
}
else if ( item->isPlaying() )
{
{
QRect r = option.rect.adjusted( 3, 0, 0, 0 );
QRect r = opt.rect.adjusted( 3, 0, 0, 0 );
// Paint Now Playing Speaker Icon
if ( m_view->header()->visualIndex( index.column() ) == 0 )
{
r.adjust( 0, 0, 0, -3 );
@@ -96,34 +161,23 @@ PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& opti
r.adjust( 22, 0, 0, 3 );
}
painter->setPen( option.palette.text().color() );
painter->setPen( opt.palette.text().color() );
QTextOption to( Qt::AlignVCenter );
QString text = painter->fontMetrics().elidedText( index.data().toString(), Qt::ElideRight, r.width() - 3 );
painter->drawText( r.adjusted( 0, 1, 0, 0 ), text, to );
}
// if ( m_view->header()->visualIndex( index.column() ) == m_view->header()->visibleSectionCount() - 1 )
// Paint Now Playing Frame
return; //FIXME
{
QRect r = QRect( 3, option.rect.y() + 1, m_view->viewport()->width() - 6, option.rect.height() - 2 );
painter->setPen( option.palette.highlight().color() );
QRect r = QRect( 3, opt.rect.y() + 1, m_view->viewport()->width() - 6, opt.rect.height() - 2 );
painter->setPen( opt.palette.highlight().color() );
QPen pen = painter->pen();
pen.setWidth( 1.0 );
painter->setPen( pen );
painter->drawRoundedRect( r, 3.0, 3.0 );
}
painter->restore();
}
else
{
if ( const QStyleOptionViewItem *vioption = qstyleoption_cast<const QStyleOptionViewItem *>(&option))
{
QStyleOptionViewItemV4 o( *vioption );
o.palette.setColor( QPalette::Text, textColor );
QStyledItemDelegate::paint( painter, o, index );
}
else
QStyledItemDelegate::paint( painter, option, index );
}
painter->restore();
}

View File

@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -31,8 +31,12 @@ class DLLEXPORT PlaylistItemDelegate : public QStyledItemDelegate
Q_OBJECT
public:
enum PlaylistItemStyle
{ Detailed = 0, Short = 1 };
PlaylistItemDelegate( TrackView* parent = 0, TrackProxyModel* proxy = 0 );
void setStyle( PlaylistItemDelegate::PlaylistItemStyle style );
void updateRowSize( const QModelIndex& index );
public slots:
@@ -41,13 +45,16 @@ public slots:
protected:
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
private:
void paintDetailed( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
void paintShort( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
unsigned int m_removalProgress;
QPixmap m_nowPlayingIcon;
PlaylistItemStyle m_style;
TrackView* m_view;
TrackProxyModel* m_model;
};

View File

@@ -509,6 +509,7 @@ PlaylistModel::removeIndex( const QModelIndex& index, bool moreToCome )
}
}
bool
PlaylistModel::isTemporary() const
{

View File

@@ -73,10 +73,8 @@ PlaylistView::setPlaylistModel( PlaylistModel* model )
else
{
setGuid( "playlistview" );
m_model->title();
m_model->description();
}
connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) );
connect( m_model, SIGNAL( playlistDeleted() ), SLOT( onDeleted() ) );
connect( m_model, SIGNAL( playlistChanged() ), SLOT( onChanged() ) );
@@ -148,12 +146,6 @@ PlaylistView::keyPressEvent( QKeyEvent* event )
}
void
PlaylistView::addItemsToPlaylist()
{
}
void
PlaylistView::deleteItems()
{
@@ -189,6 +181,7 @@ PlaylistView::onDeleted()
deleteLater();
}
void
PlaylistView::onChanged()
{
@@ -197,12 +190,9 @@ PlaylistView::onChanged()
emit nameChanged( m_model->playlist()->title() );
}
bool
PlaylistView::isTemporaryPage() const
{
if ( m_model ) {
return m_model->isTemporary();
} else {
return false;
}
return ( m_model && m_model->isTemporary() );
}

View File

@@ -65,7 +65,6 @@ private slots:
void onCustomContextMenu( const QPoint& pos );
void onTrackCountChanged( unsigned int tracks );
void addItemsToPlaylist();
void deleteItems();
void onDeleted();

View File

@@ -1,5 +1,5 @@
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
*
*
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
*
* Tomahawk is free software: you can redistribute it and/or modify
@@ -79,11 +79,15 @@ TrackHeader::checkState()
QByteArray state = TomahawkSettings::instance()->playlistColumnSizes( m_parent->guid() );
if ( !state.isEmpty() )
{
restoreState( state );
setSortIndicatorShown( true );
setSortIndicator( -1, Qt::AscendingOrder );
}
else
{
QList< double > m_columnWeights;
m_columnWeights << 0.21 << 0.22 << 0.20 << 0.05 << 0.05 << 0.05 << 0.05 << 0.05; // << 0.12;
m_columnWeights << 0.20 << 0.20 << 0.18 << 0.05 << 0.05 << 0.05 << 0.05 << 0.05 << 0.12; // << 0.05;
for ( int i = 0; i < count() - 1; i++ )
{

View File

@@ -82,7 +82,7 @@ int
TrackModel::columnCount( const QModelIndex& parent ) const
{
Q_UNUSED( parent );
return 9;
return 10;
}
@@ -183,6 +183,10 @@ TrackModel::data( const QModelIndex& index, int role ) const
case Origin:
return query->results().first()->friendlySource();
break;
case Score:
return query->results().first()->score();
break;
}
}
@@ -195,7 +199,7 @@ TrackModel::headerData( int section, Qt::Orientation orientation, int role ) con
{
Q_UNUSED( orientation );
QStringList headers;
headers << tr( "Artist" ) << tr( "Track" ) << tr( "Album" ) << tr( "Duration" ) << tr( "Bitrate" ) << tr( "Age" ) << tr( "Year" ) << tr( "Size" ) << tr( "Origin" );
headers << tr( "Artist" ) << tr( "Track" ) << tr( "Album" ) << tr( "Duration" ) << tr( "Bitrate" ) << tr( "Age" ) << tr( "Year" ) << tr( "Size" ) << tr( "Origin" ) << tr( "Score" );
if ( role == Qt::DisplayRole && section >= 0 )
{
return headers.at( section );

View File

@@ -42,7 +42,8 @@ public:
Age = 5,
Year = 6,
Filesize = 7,
Origin = 8
Origin = 8,
Score = 9
};
explicit TrackModel( QObject* parent = 0 );

View File

@@ -270,3 +270,111 @@ TrackProxyModel::removeIndexes( const QList<QPersistentModelIndex>& indexes )
sourceModel()->removeIndex( idx, b );
}
}
bool
TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) const
{
qDebug() << Q_FUNC_INFO;
TrackModelItem* p1 = itemFromIndex( left );
TrackModelItem* p2 = itemFromIndex( right );
if ( !p1 )
return true;
if ( !p2 )
return false;
const Tomahawk::query_ptr& q1 = p1->query();
const Tomahawk::query_ptr& q2 = p2->query();
QString artist1 = q1->artist();
QString artist2 = q2->artist();
QString album1 = q1->album();
QString album2 = q2->album();
QString track1 = q1->track();
QString track2 = q2->track();
unsigned int albumpos1 = 0, albumpos2 = 0;
unsigned int bitrate1 = 0, bitrate2 = 0;
unsigned int mtime1 = 0, mtime2 = 0;
unsigned int id1 = 0, id2 = 0;
unsigned int size1 = 0, size2 = 0;
if ( q1->numResults() )
{
const Tomahawk::result_ptr& r = q1->results().at( 0 );
artist1 = r->artist()->name();
album1 = r->album()->name();
track1 = r->track();
albumpos1 = r->albumpos();
bitrate1 = r->bitrate();
mtime1 = r->modificationTime();
id1 = r->dbid();
size1 = r->size();
}
if ( q2->numResults() )
{
const Tomahawk::result_ptr& r = q2->results().at( 0 );
artist2 = r->artist()->name();
album2 = r->album()->name();
track2 = r->track();
albumpos2 = r->albumpos();
bitrate2 = r->bitrate();
mtime2 = r->modificationTime();
id2 = r->dbid();
size2 = r->size();
}
if ( left.column() == TrackModel::Artist ) // sort by artist
{
if ( artist1 == artist2 )
{
if ( album1 == album2 )
{
if ( albumpos1 == albumpos2 )
return id1 < id2;
return albumpos1 < albumpos2;
}
return QString::localeAwareCompare( album1, album2 ) < 0;
}
return QString::localeAwareCompare( artist1, artist2 ) < 0;
}
else if ( left.column() == TrackModel::Album ) // sort by album
{
if ( album1 == album2 )
{
if ( albumpos1 == albumpos2 )
return id1 < id2;
return albumpos1 < albumpos2;
}
return QString::localeAwareCompare( album1, album2 ) < 0;
}
else if ( left.column() == TrackModel::Bitrate ) // sort by bitrate
{
if ( bitrate1 == bitrate2 )
return id1 < id2;
return bitrate1 < bitrate2;
}
else if ( left.column() == TrackModel::Age ) // sort by mtime
{
if ( mtime1 == mtime2 )
return id1 < id2;
return mtime1 < mtime2;
}
else if ( left.column() == TrackModel::Filesize ) // sort by file size
{
if ( size1 == size2 )
return id1 < id2;
return size1 < size2;
}
return QString::localeAwareCompare( sourceModel()->data( left ).toString(),
sourceModel()->data( right ).toString() ) < 0;
}

View File

@@ -77,6 +77,7 @@ public slots:
protected:
bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const;
bool lessThan( const QModelIndex& left, const QModelIndex& right ) const;
private:
TrackModel* m_model;

View File

@@ -50,7 +50,6 @@ TrackView::TrackView( QWidget* parent )
, m_resizing( false )
, m_dragging( false )
{
setSortingEnabled( false );
setAlternatingRowColors( true );
setSelectionMode( QAbstractItemView::ExtendedSelection );
setSelectionBehavior( QAbstractItemView::SelectRows );
@@ -63,9 +62,11 @@ TrackView::TrackView( QWidget* parent )
setRootIsDecorated( false );
setUniformRowHeights( true );
setMinimumWidth( 300 );
// setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
// setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
setHeader( m_header );
setSortingEnabled( true );
sortByColumn( -1 );
#ifndef Q_WS_WIN
QFont f = font();

View File

@@ -42,6 +42,7 @@ SearchWidget::SearchWidget( const QString& search, QWidget* parent )
m_resultsModel = new PlaylistModel( ui->resultsView );
ui->resultsView->setPlaylistModel( m_resultsModel );
ui->resultsView->overlay()->setEnabled( false );
ui->resultsView->sortByColumn( PlaylistModel::Score, Qt::DescendingOrder );
m_queries << Tomahawk::Query::get( search, uuid() );

View File

@@ -685,7 +685,7 @@ void JabberPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const
Jreen::IQ featuresIq( Jreen::IQ::Get, jid );
featuresIq.addExtension( new Jreen::Disco::Info( node ) );
Jreen::IQReply *reply = m_client->send(featuresIq);
reply->setData(RequestDisco);
connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));