mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-08-05 21:57:41 +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:
22
data/sql/dbmigrate-23_to_24.sql
Normal file
22
data/sql/dbmigrate-23_to_24.sql
Normal 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';
|
@@ -102,5 +102,6 @@
|
|||||||
<file>./data/www/auth.na.html</file>
|
<file>./data/www/auth.na.html</file>
|
||||||
<file>./data/www/tomahawk_banner_small.png</file>
|
<file>./data/www/tomahawk_banner_small.png</file>
|
||||||
<file>./data/sql/dbmigrate-22_to_23.sql</file>
|
<file>./data/sql/dbmigrate-22_to_23.sql</file>
|
||||||
|
<file>./data/sql/dbmigrate-23_to_24.sql</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
@@ -36,6 +36,13 @@ DatabaseCommand_Resolve::DatabaseCommand_Resolve( const query_ptr& query )
|
|||||||
void
|
void
|
||||||
DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
|
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() )
|
if ( !m_query->resultHint().isEmpty() )
|
||||||
{
|
{
|
||||||
qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint();
|
qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint();
|
||||||
@@ -64,20 +71,12 @@ void
|
|||||||
DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
|
DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
|
||||||
{
|
{
|
||||||
QList<Tomahawk::result_ptr> res;
|
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;
|
typedef QPair<int, float> scorepair_t;
|
||||||
|
|
||||||
// STEP 1
|
// STEP 1
|
||||||
QList< int > artists = lib->searchTable( "artist", m_query->artist(), 10 );
|
QList< QPair<int, float> > artists = lib->searchTable( "artist", m_query->artist(), 10 );
|
||||||
QList< int > tracks = lib->searchTable( "track", m_query->track(), 10 );
|
QList< QPair<int, float> > tracks = lib->searchTable( "track", m_query->track(), 10 );
|
||||||
QList< int > albums = lib->searchTable( "album", m_query->album(), 10 );
|
QList< QPair<int, float> > albums = lib->searchTable( "album", m_query->album(), 10 );
|
||||||
|
|
||||||
if ( artists.length() == 0 || tracks.length() == 0 )
|
if ( artists.length() == 0 || tracks.length() == 0 )
|
||||||
{
|
{
|
||||||
@@ -90,10 +89,10 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib )
|
|||||||
TomahawkSqlQuery files_query = lib->newquery();
|
TomahawkSqlQuery files_query = lib->newquery();
|
||||||
|
|
||||||
QStringList artsl, trksl;
|
QStringList artsl, trksl;
|
||||||
foreach( int i, artists )
|
for ( int k = 0; k < artists.count(); k++ )
|
||||||
artsl.append( QString::number( i ) );
|
artsl.append( QString::number( artists.at( k ).first ) );
|
||||||
foreach( int i, tracks )
|
for ( int k = 0; k < tracks.count(); k++ )
|
||||||
trksl.append( QString::number( i ) );
|
trksl.append( QString::number( tracks.at( k ).first ) );
|
||||||
|
|
||||||
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
|
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
|
||||||
QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
|
QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.join( "," ) );
|
||||||
@@ -189,20 +188,12 @@ void
|
|||||||
DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
||||||
{
|
{
|
||||||
QList<Tomahawk::result_ptr> res;
|
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;
|
typedef QPair<int, float> scorepair_t;
|
||||||
|
|
||||||
// STEP 1
|
// STEP 1
|
||||||
QList< int > artists = lib->searchTable( "artist", m_query->fullTextQuery(), 10 );
|
QList< QPair<int, float> > artists = lib->searchTable( "artist", m_query->fullTextQuery(), 10 );
|
||||||
QList< int > tracks = lib->searchTable( "track", m_query->fullTextQuery(), 10 );
|
QList< QPair<int, float> > tracks = lib->searchTable( "track", m_query->fullTextQuery(), 10 );
|
||||||
QList< int > albums = lib->searchTable( "album", 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 )
|
if ( artists.length() == 0 && tracks.length() == 0 && albums.length() == 0 )
|
||||||
{
|
{
|
||||||
@@ -215,12 +206,12 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
|||||||
TomahawkSqlQuery files_query = lib->newquery();
|
TomahawkSqlQuery files_query = lib->newquery();
|
||||||
|
|
||||||
QStringList artsl, trksl, albsl;
|
QStringList artsl, trksl, albsl;
|
||||||
foreach( int i, artists )
|
for ( int k = 0; k < artists.count(); k++ )
|
||||||
artsl.append( QString::number( i ) );
|
artsl.append( QString::number( artists.at( k ).first ) );
|
||||||
foreach( int i, tracks )
|
for ( int k = 0; k < tracks.count(); k++ )
|
||||||
trksl.append( QString::number( i ) );
|
trksl.append( QString::number( tracks.at( k ).first ) );
|
||||||
foreach( int i, albums )
|
for ( int k = 0; k < albums.count(); k++ )
|
||||||
albsl.append( QString::number( i ) );
|
albsl.append( QString::number( albums.at( k ).first ) );
|
||||||
|
|
||||||
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
|
QString artsToken = QString( "file_join.artist IN (%1)" ).arg( artsl.join( "," ) );
|
||||||
QString trksToken = QString( "file_join.track IN (%1)" ).arg( trksl.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 "
|
"artist.id = file_join.artist AND "
|
||||||
"track.id = file_join.track AND "
|
"track.id = file_join.track AND "
|
||||||
"file.id = file_join.file AND "
|
"file.id = file_join.file AND "
|
||||||
"(%1 OR %2 OR %3)" )
|
"%1" )
|
||||||
.arg( artists.length() > 0 ? artsToken : QString( "0" ) )
|
.arg( tracks.length() > 0 ? trksToken : QString( "0" ) );
|
||||||
.arg( tracks.length() > 0 ? trksToken : QString( "0" ) )
|
|
||||||
.arg( albums.length() > 0 ? albsToken : QString( "0" ) );
|
|
||||||
|
|
||||||
files_query.prepare( sql );
|
files_query.prepare( sql );
|
||||||
files_query.exec();
|
files_query.exec();
|
||||||
@@ -288,6 +277,15 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
|||||||
result->setId( files_query.value( 9 ).toUInt() );
|
result->setId( files_query.value( 9 ).toUInt() );
|
||||||
result->setYear( files_query.value( 17 ).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();
|
TomahawkSqlQuery attrQuery = lib->newquery();
|
||||||
QVariantMap attr;
|
QVariantMap attr;
|
||||||
|
|
||||||
@@ -301,11 +299,6 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib )
|
|||||||
|
|
||||||
result->setAttributes( attr );
|
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() );
|
result->setCollection( s->collection() );
|
||||||
res << result;
|
res << result;
|
||||||
}
|
}
|
||||||
|
@@ -38,7 +38,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "schema.sql.h"
|
#include "schema.sql.h"
|
||||||
|
|
||||||
#define CURRENT_SCHEMA_VERSION 23
|
#define CURRENT_SCHEMA_VERSION 24
|
||||||
|
|
||||||
|
|
||||||
DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
|
DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
|
||||||
@@ -47,66 +47,46 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
|
|||||||
, m_lastalbid( 0 )
|
, m_lastalbid( 0 )
|
||||||
, m_lasttrkid( 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;
|
bool schemaUpdated = false;
|
||||||
qry.exec( "SELECT v FROM settings WHERE k='schema_version'" );
|
int version = getDatabaseVersion( dbname );
|
||||||
if ( qry.next() )
|
|
||||||
|
if ( version != CURRENT_SCHEMA_VERSION )
|
||||||
{
|
{
|
||||||
int v = qry.value( 0 ).toInt();
|
QString newname = QString( "%1.v%2" ).arg( dbname ).arg( version );
|
||||||
qDebug() << "Current schema is" << v << this->thread();
|
qDebug() << endl << "****************************" << endl;
|
||||||
if ( v != CURRENT_SCHEMA_VERSION )
|
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);
|
TomahawkSqlQuery query = newquery();
|
||||||
qDebug() << endl << "****************************" << endl;
|
query.exec( "PRAGMA auto_vacuum = FULL" );
|
||||||
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;
|
|
||||||
|
|
||||||
qry.clear();
|
schemaUpdated = updateSchema( version );
|
||||||
qry.finish();
|
if ( !schemaUpdated )
|
||||||
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
Q_ASSERT( false );
|
Q_ASSERT( false );
|
||||||
QTimer::singleShot( 0, qApp, SLOT( quit() ) );
|
QTimer::singleShot( 0, qApp, SLOT( quit() ) );
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
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 );
|
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 )
|
DatabaseImpl::searchTable( const QString& table, const QString& name, uint limit )
|
||||||
{
|
{
|
||||||
Q_UNUSED( 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;
|
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() )
|
foreach( int i, resultsmap.keys() )
|
||||||
{
|
{
|
||||||
resultslist << QPair<int, float>( i, (float)resultsmap.value( i ) );
|
resultslist << QPair<int, float>( i, (float)resultsmap.value( i ) );
|
||||||
}
|
}
|
||||||
qSort( resultslist.begin(), resultslist.end(), DatabaseImpl::scorepairSorter );
|
qSort( resultslist.begin(), resultslist.end(), DatabaseImpl::scorepairSorter );
|
||||||
|
|
||||||
for( int k = 0; k < resultslist.count(); k++ )
|
return resultslist;
|
||||||
{
|
|
||||||
results << resultslist.at( k ).first;
|
|
||||||
}
|
|
||||||
|
|
||||||
// qDebug() << "Returning" << results.count() << "results";
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -639,3 +612,31 @@ DatabaseImpl::resultFromHint( const Tomahawk::query_ptr& origquery )
|
|||||||
|
|
||||||
return res;
|
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;
|
||||||
|
}
|
||||||
|
@@ -55,7 +55,7 @@ public:
|
|||||||
int trackId( int artistid, const QString& name_orig, bool& isnew );
|
int trackId( int artistid, const QString& name_orig, bool& isnew );
|
||||||
int albumId( 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 );
|
QList< int > getTrackFids( int tid );
|
||||||
|
|
||||||
static QString sortname( const QString& str );
|
static QString sortname( const QString& str );
|
||||||
@@ -84,19 +84,18 @@ signals:
|
|||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static int getDatabaseVersion( const QString& dbname );
|
||||||
|
|
||||||
QString cleanSql( const QString& sql );
|
QString cleanSql( const QString& sql );
|
||||||
|
|
||||||
bool m_ready;
|
|
||||||
|
|
||||||
bool updateSchema( int oldVersion );
|
bool updateSchema( int oldVersion );
|
||||||
|
|
||||||
|
bool m_ready;
|
||||||
QSqlDatabase db;
|
QSqlDatabase db;
|
||||||
|
|
||||||
QString m_lastart, m_lastalb, m_lasttrk;
|
QString m_lastart, m_lastalb, m_lasttrk;
|
||||||
int m_lastartid, m_lastalbid, m_lasttrkid;
|
int m_lastartid, m_lastalbid, m_lasttrkid;
|
||||||
|
|
||||||
QString m_dbid;
|
QString m_dbid;
|
||||||
|
|
||||||
FuzzyIndex* m_fuzzyIndex;
|
FuzzyIndex* m_fuzzyIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -227,6 +227,24 @@ CREATE TABLE IF NOT EXISTS track_attributes (
|
|||||||
CREATE INDEX track_attrib_id ON track_attributes(id);
|
CREATE INDEX track_attrib_id ON track_attributes(id);
|
||||||
CREATE INDEX track_attrib_k ON track_attributes(k);
|
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
|
-- playback history
|
||||||
@@ -264,4 +282,4 @@ CREATE TABLE IF NOT EXISTS settings (
|
|||||||
v TEXT NOT NULL DEFAULT ''
|
v TEXT NOT NULL DEFAULT ''
|
||||||
);
|
);
|
||||||
|
|
||||||
INSERT INTO settings(k,v) VALUES('schema_version', '23');
|
INSERT INTO settings(k,v) VALUES('schema_version', '24');
|
||||||
|
@@ -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 =
|
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_id ON track_attributes(id);"
|
||||||
"CREATE INDEX track_attrib_k ON track_attributes(k);"
|
"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 ("
|
"CREATE TABLE IF NOT EXISTS playback_log ("
|
||||||
" id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
" id INTEGER PRIMARY KEY AUTOINCREMENT,"
|
||||||
" source INTEGER REFERENCES source(id) ON DELETE CASCADE ON UPDATE CASCADE DEFERRABLE INITIALLY DEFERRED,"
|
" 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,"
|
" k TEXT NOT NULL PRIMARY KEY,"
|
||||||
" v TEXT NOT NULL DEFAULT ''"
|
" 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()
|
const char * get_tomahawk_sql()
|
||||||
|
@@ -29,109 +29,3 @@ CollectionProxyModel::CollectionProxyModel( QObject* parent )
|
|||||||
: TrackProxyModel( 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;
|
|
||||||
}
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
*
|
*
|
||||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
*
|
*
|
||||||
* Tomahawk is free software: you can redistribute it and/or modify
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
@@ -31,9 +31,6 @@ public:
|
|||||||
explicit CollectionProxyModel( QObject* parent = 0 );
|
explicit CollectionProxyModel( QObject* parent = 0 );
|
||||||
|
|
||||||
virtual PlaylistInterface::ViewMode viewMode() const { return PlaylistInterface::Flat; }
|
virtual PlaylistInterface::ViewMode viewMode() const { return PlaylistInterface::Flat; }
|
||||||
|
|
||||||
protected:
|
|
||||||
bool lessThan( const QModelIndex& left, const QModelIndex& right ) const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // COLLECTIONPROXYMODEL_H
|
#endif // COLLECTIONPROXYMODEL_H
|
||||||
|
@@ -63,8 +63,12 @@ void
|
|||||||
CollectionView::setTrackModel( TrackModel* model )
|
CollectionView::setTrackModel( TrackModel* model )
|
||||||
{
|
{
|
||||||
TrackView::setTrackModel( model );
|
TrackView::setTrackModel( model );
|
||||||
|
setColumnHidden( TrackModel::Score, true ); // Hide age column per default
|
||||||
setGuid( "collectionview" );
|
setGuid( "collectionview" );
|
||||||
|
|
||||||
|
setSortingEnabled( true );
|
||||||
|
sortByColumn( 0, Qt::AscendingOrder );
|
||||||
|
|
||||||
connect( model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) );
|
connect( model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,14 +87,14 @@ CollectionView::setupMenus()
|
|||||||
|
|
||||||
m_playItemAction = m_itemMenu.addAction( tr( "&Play" ) );
|
m_playItemAction = m_itemMenu.addAction( tr( "&Play" ) );
|
||||||
m_addItemsToQueueAction = m_itemMenu.addAction( tr( "Add to &Queue" ) );
|
m_addItemsToQueueAction = m_itemMenu.addAction( tr( "Add to &Queue" ) );
|
||||||
m_itemMenu.addSeparator();
|
m_itemMenu.addSeparator();
|
||||||
|
|
||||||
foreach( QAction* a, actions() )
|
foreach( QAction* a, actions() )
|
||||||
m_itemMenu.addAction( a );
|
m_itemMenu.addAction( a );
|
||||||
// m_addItemsToPlaylistAction = m_itemMenu.addAction( tr( "&Add to Playlist" ) );
|
// m_addItemsToPlaylistAction = m_itemMenu.addAction( tr( "&Add to Playlist" ) );
|
||||||
|
|
||||||
connect( m_playItemAction, SIGNAL( triggered() ), SLOT( playItem() ) );
|
connect( m_playItemAction, SIGNAL( triggered() ), SLOT( playItem() ) );
|
||||||
connect( m_addItemsToQueueAction, SIGNAL( triggered() ), SLOT( addItemsToQueue() ) );
|
connect( m_addItemsToQueueAction, SIGNAL( triggered() ), SLOT( addItemsToQueue() ) );
|
||||||
// connect( m_addItemsToPlaylistAction, SIGNAL( triggered() ), SLOT( addItemsToPlaylist() ) );
|
// connect( m_addItemsToPlaylistAction, SIGNAL( triggered() ), SLOT( addItemsToPlaylist() ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "playlistitemdelegate.h"
|
#include "playlistitemdelegate.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
|
|
||||||
PlaylistItemDelegate::PlaylistItemDelegate( TrackView* parent, TrackProxyModel* proxy )
|
PlaylistItemDelegate::PlaylistItemDelegate( TrackView* parent, TrackProxyModel* proxy )
|
||||||
: QStyledItemDelegate( (QObject*)parent )
|
: QStyledItemDelegate( (QObject*)parent )
|
||||||
|
, m_style( Detailed )
|
||||||
, m_view( parent )
|
, m_view( parent )
|
||||||
, m_model( proxy )
|
, m_model( proxy )
|
||||||
{
|
{
|
||||||
@@ -43,6 +45,13 @@ PlaylistItemDelegate::PlaylistItemDelegate( TrackView* parent, TrackProxyModel*
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
PlaylistItemDelegate::setStyle( PlaylistItemDelegate::PlaylistItemStyle style )
|
||||||
|
{
|
||||||
|
m_style = style;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
PlaylistItemDelegate::updateRowSize( const QModelIndex& index )
|
PlaylistItemDelegate::updateRowSize( const QModelIndex& index )
|
||||||
{
|
{
|
||||||
@@ -70,6 +79,29 @@ PlaylistItemDelegate::createEditor( QWidget* parent, const QStyleOptionViewItem&
|
|||||||
|
|
||||||
void
|
void
|
||||||
PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
|
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 ) );
|
TrackModelItem* item = m_model->itemFromIndex( m_model->mapToSource( index ) );
|
||||||
if ( !item || item->query().isNull() )
|
if ( !item || item->query().isNull() )
|
||||||
@@ -82,13 +114,46 @@ PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& opti
|
|||||||
opacity = qMax( (float)0.3, opacity );
|
opacity = qMax( (float)0.3, opacity );
|
||||||
QColor textColor = TomahawkUtils::alphaBlend( option.palette.color( QPalette::Foreground ), option.palette.color( QPalette::Background ), opacity );
|
QColor textColor = TomahawkUtils::alphaBlend( option.palette.color( QPalette::Foreground ), option.palette.color( QPalette::Background ), opacity );
|
||||||
|
|
||||||
if ( item->isPlaying() )
|
QStyleOptionViewItemV4 opt = option;
|
||||||
{
|
initStyleOption( &opt, index );
|
||||||
// painter->setRenderHint( QPainter::Antialiasing );
|
|
||||||
painter->save();
|
|
||||||
|
|
||||||
|
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 )
|
if ( m_view->header()->visualIndex( index.column() ) == 0 )
|
||||||
{
|
{
|
||||||
r.adjust( 0, 0, 0, -3 );
|
r.adjust( 0, 0, 0, -3 );
|
||||||
@@ -96,34 +161,23 @@ PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& opti
|
|||||||
r.adjust( 22, 0, 0, 3 );
|
r.adjust( 22, 0, 0, 3 );
|
||||||
}
|
}
|
||||||
|
|
||||||
painter->setPen( option.palette.text().color() );
|
painter->setPen( opt.palette.text().color() );
|
||||||
|
|
||||||
QTextOption to( Qt::AlignVCenter );
|
QTextOption to( Qt::AlignVCenter );
|
||||||
QString text = painter->fontMetrics().elidedText( index.data().toString(), Qt::ElideRight, r.width() - 3 );
|
QString text = painter->fontMetrics().elidedText( index.data().toString(), Qt::ElideRight, r.width() - 3 );
|
||||||
painter->drawText( r.adjusted( 0, 1, 0, 0 ), text, to );
|
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 );
|
QRect r = QRect( 3, opt.rect.y() + 1, m_view->viewport()->width() - 6, opt.rect.height() - 2 );
|
||||||
painter->setPen( option.palette.highlight().color() );
|
painter->setPen( opt.palette.highlight().color() );
|
||||||
QPen pen = painter->pen();
|
QPen pen = painter->pen();
|
||||||
pen.setWidth( 1.0 );
|
pen.setWidth( 1.0 );
|
||||||
painter->setPen( pen );
|
painter->setPen( pen );
|
||||||
painter->drawRoundedRect( r, 3.0, 3.0 );
|
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();
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
*
|
*
|
||||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
*
|
*
|
||||||
* Tomahawk is free software: you can redistribute it and/or modify
|
* Tomahawk is free software: you can redistribute it and/or modify
|
||||||
@@ -31,8 +31,12 @@ class DLLEXPORT PlaylistItemDelegate : public QStyledItemDelegate
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum PlaylistItemStyle
|
||||||
|
{ Detailed = 0, Short = 1 };
|
||||||
|
|
||||||
PlaylistItemDelegate( TrackView* parent = 0, TrackProxyModel* proxy = 0 );
|
PlaylistItemDelegate( TrackView* parent = 0, TrackProxyModel* proxy = 0 );
|
||||||
|
|
||||||
|
void setStyle( PlaylistItemDelegate::PlaylistItemStyle style );
|
||||||
void updateRowSize( const QModelIndex& index );
|
void updateRowSize( const QModelIndex& index );
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
@@ -41,13 +45,16 @@ public slots:
|
|||||||
protected:
|
protected:
|
||||||
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||||
QSize sizeHint( 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;
|
QWidget* createEditor( QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
|
||||||
|
|
||||||
private:
|
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;
|
unsigned int m_removalProgress;
|
||||||
QPixmap m_nowPlayingIcon;
|
QPixmap m_nowPlayingIcon;
|
||||||
|
|
||||||
|
PlaylistItemStyle m_style;
|
||||||
TrackView* m_view;
|
TrackView* m_view;
|
||||||
TrackProxyModel* m_model;
|
TrackProxyModel* m_model;
|
||||||
};
|
};
|
||||||
|
@@ -509,6 +509,7 @@ PlaylistModel::removeIndex( const QModelIndex& index, bool moreToCome )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PlaylistModel::isTemporary() const
|
PlaylistModel::isTemporary() const
|
||||||
{
|
{
|
||||||
|
@@ -73,10 +73,8 @@ PlaylistView::setPlaylistModel( PlaylistModel* model )
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
setGuid( "playlistview" );
|
setGuid( "playlistview" );
|
||||||
|
|
||||||
m_model->title();
|
|
||||||
m_model->description();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) );
|
connect( m_model, SIGNAL( trackCountChanged( unsigned int ) ), SLOT( onTrackCountChanged( unsigned int ) ) );
|
||||||
connect( m_model, SIGNAL( playlistDeleted() ), SLOT( onDeleted() ) );
|
connect( m_model, SIGNAL( playlistDeleted() ), SLOT( onDeleted() ) );
|
||||||
connect( m_model, SIGNAL( playlistChanged() ), SLOT( onChanged() ) );
|
connect( m_model, SIGNAL( playlistChanged() ), SLOT( onChanged() ) );
|
||||||
@@ -148,12 +146,6 @@ PlaylistView::keyPressEvent( QKeyEvent* event )
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PlaylistView::addItemsToPlaylist()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
PlaylistView::deleteItems()
|
PlaylistView::deleteItems()
|
||||||
{
|
{
|
||||||
@@ -189,6 +181,7 @@ PlaylistView::onDeleted()
|
|||||||
deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
PlaylistView::onChanged()
|
PlaylistView::onChanged()
|
||||||
{
|
{
|
||||||
@@ -197,12 +190,9 @@ PlaylistView::onChanged()
|
|||||||
emit nameChanged( m_model->playlist()->title() );
|
emit nameChanged( m_model->playlist()->title() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PlaylistView::isTemporaryPage() const
|
PlaylistView::isTemporaryPage() const
|
||||||
{
|
{
|
||||||
if ( m_model ) {
|
return ( m_model && m_model->isTemporary() );
|
||||||
return m_model->isTemporary();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -65,7 +65,6 @@ private slots:
|
|||||||
void onCustomContextMenu( const QPoint& pos );
|
void onCustomContextMenu( const QPoint& pos );
|
||||||
void onTrackCountChanged( unsigned int tracks );
|
void onTrackCountChanged( unsigned int tracks );
|
||||||
|
|
||||||
void addItemsToPlaylist();
|
|
||||||
void deleteItems();
|
void deleteItems();
|
||||||
|
|
||||||
void onDeleted();
|
void onDeleted();
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
|
||||||
*
|
*
|
||||||
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
* Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
|
||||||
*
|
*
|
||||||
* Tomahawk is free software: you can redistribute it and/or modify
|
* 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() );
|
QByteArray state = TomahawkSettings::instance()->playlistColumnSizes( m_parent->guid() );
|
||||||
if ( !state.isEmpty() )
|
if ( !state.isEmpty() )
|
||||||
|
{
|
||||||
restoreState( state );
|
restoreState( state );
|
||||||
|
setSortIndicatorShown( true );
|
||||||
|
setSortIndicator( -1, Qt::AscendingOrder );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QList< double > m_columnWeights;
|
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++ )
|
for ( int i = 0; i < count() - 1; i++ )
|
||||||
{
|
{
|
||||||
|
@@ -82,7 +82,7 @@ int
|
|||||||
TrackModel::columnCount( const QModelIndex& parent ) const
|
TrackModel::columnCount( const QModelIndex& parent ) const
|
||||||
{
|
{
|
||||||
Q_UNUSED( parent );
|
Q_UNUSED( parent );
|
||||||
return 9;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -183,6 +183,10 @@ TrackModel::data( const QModelIndex& index, int role ) const
|
|||||||
case Origin:
|
case Origin:
|
||||||
return query->results().first()->friendlySource();
|
return query->results().first()->friendlySource();
|
||||||
break;
|
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 );
|
Q_UNUSED( orientation );
|
||||||
QStringList headers;
|
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 )
|
if ( role == Qt::DisplayRole && section >= 0 )
|
||||||
{
|
{
|
||||||
return headers.at( section );
|
return headers.at( section );
|
||||||
|
@@ -42,7 +42,8 @@ public:
|
|||||||
Age = 5,
|
Age = 5,
|
||||||
Year = 6,
|
Year = 6,
|
||||||
Filesize = 7,
|
Filesize = 7,
|
||||||
Origin = 8
|
Origin = 8,
|
||||||
|
Score = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit TrackModel( QObject* parent = 0 );
|
explicit TrackModel( QObject* parent = 0 );
|
||||||
|
@@ -270,3 +270,111 @@ TrackProxyModel::removeIndexes( const QList<QPersistentModelIndex>& indexes )
|
|||||||
sourceModel()->removeIndex( idx, b );
|
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;
|
||||||
|
}
|
||||||
|
@@ -77,6 +77,7 @@ public slots:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const;
|
bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const;
|
||||||
|
bool lessThan( const QModelIndex& left, const QModelIndex& right ) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TrackModel* m_model;
|
TrackModel* m_model;
|
||||||
|
@@ -50,7 +50,6 @@ TrackView::TrackView( QWidget* parent )
|
|||||||
, m_resizing( false )
|
, m_resizing( false )
|
||||||
, m_dragging( false )
|
, m_dragging( false )
|
||||||
{
|
{
|
||||||
setSortingEnabled( false );
|
|
||||||
setAlternatingRowColors( true );
|
setAlternatingRowColors( true );
|
||||||
setSelectionMode( QAbstractItemView::ExtendedSelection );
|
setSelectionMode( QAbstractItemView::ExtendedSelection );
|
||||||
setSelectionBehavior( QAbstractItemView::SelectRows );
|
setSelectionBehavior( QAbstractItemView::SelectRows );
|
||||||
@@ -63,9 +62,11 @@ TrackView::TrackView( QWidget* parent )
|
|||||||
setRootIsDecorated( false );
|
setRootIsDecorated( false );
|
||||||
setUniformRowHeights( true );
|
setUniformRowHeights( true );
|
||||||
setMinimumWidth( 300 );
|
setMinimumWidth( 300 );
|
||||||
// setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
|
// setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
|
||||||
|
|
||||||
setHeader( m_header );
|
setHeader( m_header );
|
||||||
|
setSortingEnabled( true );
|
||||||
|
sortByColumn( -1 );
|
||||||
|
|
||||||
#ifndef Q_WS_WIN
|
#ifndef Q_WS_WIN
|
||||||
QFont f = font();
|
QFont f = font();
|
||||||
|
@@ -42,6 +42,7 @@ SearchWidget::SearchWidget( const QString& search, QWidget* parent )
|
|||||||
m_resultsModel = new PlaylistModel( ui->resultsView );
|
m_resultsModel = new PlaylistModel( ui->resultsView );
|
||||||
ui->resultsView->setPlaylistModel( m_resultsModel );
|
ui->resultsView->setPlaylistModel( m_resultsModel );
|
||||||
ui->resultsView->overlay()->setEnabled( false );
|
ui->resultsView->overlay()->setEnabled( false );
|
||||||
|
ui->resultsView->sortByColumn( PlaylistModel::Score, Qt::DescendingOrder );
|
||||||
|
|
||||||
m_queries << Tomahawk::Query::get( search, uuid() );
|
m_queries << Tomahawk::Query::get( search, uuid() );
|
||||||
|
|
||||||
|
@@ -685,7 +685,7 @@ void JabberPlugin::onPresenceReceived( const Jreen::RosterItem::Ptr &item, const
|
|||||||
|
|
||||||
Jreen::IQ featuresIq( Jreen::IQ::Get, jid );
|
Jreen::IQ featuresIq( Jreen::IQ::Get, jid );
|
||||||
featuresIq.addExtension( new Jreen::Disco::Info( node ) );
|
featuresIq.addExtension( new Jreen::Disco::Info( node ) );
|
||||||
|
|
||||||
Jreen::IQReply *reply = m_client->send(featuresIq);
|
Jreen::IQReply *reply = m_client->send(featuresIq);
|
||||||
reply->setData(RequestDisco);
|
reply->setData(RequestDisco);
|
||||||
connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
|
connect(reply, SIGNAL(received(Jreen::IQ)), SLOT(onNewIq(Jreen::IQ)));
|
||||||
|
2
thirdparty/jreen
vendored
2
thirdparty/jreen
vendored
Submodule thirdparty/jreen updated: 8f995f2466...2957d0ff03
Reference in New Issue
Block a user