1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-31 01:30:02 +02:00

Merge remote branch 'origin' into phonon

This commit is contained in:
Christian Muehlhaeuser
2011-02-23 17:12:46 +01:00
54 changed files with 946 additions and 362 deletions

View File

@@ -53,6 +53,7 @@ ENDIF(LIBLASTFM_FOUND)
SET( tomahawkSourcesGui ${tomahawkSourcesGui}
sourcetree/sourcesmodel.cpp
sourcetree/sourcesproxymodel.cpp
sourcetree/sourcetreeitem.cpp
sourcetree/sourcetreeitemwidget.cpp
sourcetree/sourcetreeview.cpp
@@ -97,6 +98,7 @@ ENDIF(LIBLASTFM_FOUND)
SET( tomahawkHeadersGui ${tomahawkHeadersGui}
sourcetree/sourcesmodel.h
sourcetree/sourcesproxymodel.h
sourcetree/sourcetreeitem.h
sourcetree/sourcetreeitemwidget.h
sourcetree/sourcetreeview.h
@@ -155,7 +157,8 @@ ENDIF( UNIX )
IF(GLOOX_FOUND)
ADD_SUBDIRECTORY( xmppbot )
SET( tomahawkHeaders ${tomahawkHeaders} xmppbot/xmppbot.h )
SET( tomahawkSources ${tomahawkSources} xmppbot/xmppbot.cpp )
ENDIF(GLOOX_FOUND)
ADD_SUBDIRECTORY( sip )
@@ -191,12 +194,11 @@ MESSAGE( STATUS "OS_SPECIFIC_LINK_LIBRARIES: ${OS_SPECIFIC_LINK_LIBRARIES}" )
SET(LINK_LIBRARIES "")
IF(LIBLASTFM_FOUND)
SET(LINK_LIBRARIES
${LINK_LIBRARIES}
${LIBLASTFM_LIBRARY}
)
SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${LIBLASTFM_LIBRARY} )
ENDIF(LIBLASTFM_FOUND)
IF(GLOOX_FOUND)
SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${GLOOX_LIBRARIES} )
ENDIF(GLOOX_FOUND)
TARGET_LINK_LIBRARIES( tomahawk
${LINK_LIBRARIES}

View File

@@ -7,4 +7,7 @@
#cmakedefine LEOPARD
#cmakedefine HAVE_SPARKLE
#cmakedefine LIBLASTFM_FOUND
#cmakedefine GLOOX_FOUND
#endif // CONFIG_H_IN

View File

@@ -57,6 +57,7 @@ set( libSources
database/databasecommand_playbackhistory.cpp
database/databasecommand_setplaylistrevision.cpp
database/databasecommand_loadallplaylists.cpp
database/databasecommand_loadallsources.cpp
database/databasecommand_createplaylist.cpp
database/databasecommand_deleteplaylist.cpp
database/databasecommand_renameplaylist.cpp
@@ -195,6 +196,7 @@ set( libHeaders
database/databasecommand_playbackhistory.h
database/databasecommand_setplaylistrevision.h
database/databasecommand_loadallplaylists.h
database/databasecommand_loadallsources.h
database/databasecommand_createplaylist.h
database/databasecommand_deleteplaylist.h
database/databasecommand_renameplaylist.h
@@ -296,7 +298,7 @@ set( libUI ${libUI}
playlist/infobar/infobar.ui
)
include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ..
include_directories( . ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/.. ..
${QT_INCLUDE_DIR}
${LIBECHONEST_INCLUDE_DIR}
${LIBECHONEST_INCLUDE_DIR}/..

View File

@@ -46,6 +46,7 @@ Database::enqueue( QSharedPointer<DatabaseCommand> lc )
if( lc->doesMutates() )
{
//qDebug() << Q_FUNC_INFO << "RW" << lc->commandname();
qDebug() << "Enqueueing command to rw thread:" << lc->commandname();
m_workerRW->enqueue( lc );
}
else

View File

@@ -17,7 +17,8 @@ DatabaseCommand_CollectionStats::exec( DatabaseImpl* dbi )
Q_ASSERT( source()->isLocal() || source()->id() >= 1 );
TomahawkSqlQuery query = dbi->newquery();
if( source()->isLocal() )
QVariantMap m;
if ( source()->isLocal() )
{
query.exec( "SELECT count(*), max(mtime), (SELECT guid FROM oplog WHERE source IS NULL ORDER BY id DESC LIMIT 1) "
"FROM file "
@@ -30,16 +31,18 @@ DatabaseCommand_CollectionStats::exec( DatabaseImpl* dbi )
"WHERE source = ?" );
query.addBindValue( source()->id() );
query.addBindValue( source()->id() );
query.exec();
}
query.exec();
QVariantMap m;
if( query.next() )
if ( query.next() )
{
m.insert( "numfiles", query.value( 0 ).toInt() );
m.insert( "lastmodified", query.value( 1 ).toInt() );
m.insert( "lastop", query.value( 2 ).toString() );
if ( !source()->isLocal() && !source()->lastOpGuid().isEmpty() )
m.insert( "lastop", source()->lastOpGuid() );
else
m.insert( "lastop", query.value( 2 ).toString() );
}
emit done( m );

View File

@@ -1,5 +1,5 @@
#ifndef DATABASECOMMAND_IMPORTALLPLAYLIST_H
#define DATABASECOMMAND_IMPORTALLPLAYLIST_H
#ifndef DATABASECOMMAND_LOADALLPLAYLIST_H
#define DATABASECOMMAND_LOADALLPLAYLIST_H
#include <QObject>
#include <QVariantMap>
@@ -26,4 +26,4 @@ signals:
void done( const QList<Tomahawk::playlist_ptr>& playlists );
};
#endif // DATABASECOMMAND_ADDFILES_H
#endif // DATABASECOMMAND_LOADALLPLAYLIST_H

View File

@@ -0,0 +1,29 @@
#include "databasecommand_loadallsources.h"
#include <QSqlQuery>
#include "network/servent.h"
#include "source.h"
#include "databaseimpl.h"
using namespace Tomahawk;
void DatabaseCommand_LoadAllSources::exec( DatabaseImpl* dbi )
{
TomahawkSqlQuery query = dbi->newquery();
query.exec( QString( "SELECT id, name, friendlyname "
"FROM source" ) );
QList<source_ptr> sources;
while ( query.next() )
{
source_ptr src( new Source( query.value( 0 ).toUInt(), query.value( 1 ).toString() ) );
src->setFriendlyName( query.value( 2 ).toString() );
sources << src;
}
emit done( sources );
}

View File

@@ -0,0 +1,29 @@
#ifndef DATABASECOMMAND_LOADALLSOURCES_H
#define DATABASECOMMAND_LOADALLSOURCES_H
#include <QObject>
#include <QVariantMap>
#include "databasecommand.h"
#include "typedefs.h"
#include "dllmacro.h"
class DLLEXPORT DatabaseCommand_LoadAllSources : public DatabaseCommand
{
Q_OBJECT
public:
explicit DatabaseCommand_LoadAllSources( QObject* parent = 0 )
: DatabaseCommand( parent )
{}
virtual void exec( DatabaseImpl* );
virtual bool doesMutates() const { return false; }
virtual QString commandname() const { return "loadallsources"; }
signals:
void done( const QList<Tomahawk::source_ptr>& sources );
};
#endif // DATABASECOMMAND_LOADALLSOURCES_H

View File

@@ -16,10 +16,7 @@ DatabaseCommand_loadOps::exec( DatabaseImpl* dbi )
).arg( source()->isLocal() ? "IS NULL" : QString( "= %1" ).arg( source()->id() ) )
);
query.addBindValue( m_since );
if( !query.exec() )
{
Q_ASSERT(0);
}
query.exec();
QString lastguid = m_since;
while( query.next() )

View File

@@ -22,9 +22,9 @@ DatabaseCommand_LogPlayback::postCommitHook()
}
connect( this, SIGNAL( trackPlaying( Tomahawk::query_ptr ) ),
source().data(), SIGNAL( playbackStarted( Tomahawk::query_ptr ) ), Qt::QueuedConnection );
source().data(), SLOT( onPlaybackStarted( Tomahawk::query_ptr ) ), Qt::QueuedConnection );
connect( this, SIGNAL( trackPlayed( Tomahawk::query_ptr ) ),
source().data(), SIGNAL( playbackFinished( Tomahawk::query_ptr ) ), Qt::QueuedConnection );
source().data(), SLOT( onPlaybackFinished( Tomahawk::query_ptr ) ), Qt::QueuedConnection );
QVariantMap m;
m.insert( "track", m_track );

View File

@@ -139,7 +139,7 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib )
s = SourceList::instance()->get( files_query.value( 13 ).toUInt() );
if( s.isNull() )
{
//qDebug() << "Skipping result for offline sourceid:" << files_query.value( 13 ).toUInt();
qDebug() << "Skipping result for offline sourceid:" << files_query.value( 13 ).toUInt();
// will happen for valid sources which are offline (and thus not in the sourcelist)
continue;
}

View File

@@ -16,7 +16,8 @@
*/
#include "schema.sql.h"
#define CURRENT_SCHEMA_VERSION 19
#define CURRENT_SCHEMA_VERSION 20
DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
: QObject( (QObject*) parent )
@@ -36,6 +37,7 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
QSqlQuery qry = QSqlQuery( db );
bool schemaUpdated = false;
qry.exec( "SELECT v FROM settings WHERE k='schema_version'" );
if ( qry.next() )
{
@@ -60,18 +62,24 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
{
db = QSqlDatabase::addDatabase( "QSQLITE", "tomahawk" );
db.setDatabaseName( dbname );
if( !db.open() ) throw "db moving failed";
updateSchema( v );
if( !db.open() )
throw "db moving failed";
TomahawkSqlQuery query = newquery();
query.exec( "PRAGMA auto_vacuum = FULL" );
schemaUpdated = updateSchema( v );
}
else
{
Q_ASSERT(0);
Q_ASSERT( false );
QTimer::singleShot( 0, qApp, SLOT( quit() ) );
return;
}
}
} else {
updateSchema( 0 );
}
else
{
schemaUpdated = updateSchema( 0 );
}
TomahawkSqlQuery query = newquery();
@@ -95,15 +103,12 @@ DatabaseImpl::DatabaseImpl( const QString& dbname, Database* parent )
// in case of unclean shutdown last time:
query.exec( "UPDATE source SET isonline = 'false'" );
m_fuzzyIndex = new FuzzyIndex( *this );
m_fuzzyIndex = new FuzzyIndex( *this, schemaUpdated );
}
DatabaseImpl::~DatabaseImpl()
{
m_indexThread.quit();
m_indexThread.wait( 5000 );
delete m_fuzzyIndex;
}
@@ -111,11 +116,8 @@ DatabaseImpl::~DatabaseImpl()
void
DatabaseImpl::loadIndex()
{
// load ngram index in the background
m_fuzzyIndex->moveToThread( &m_indexThread );
connect( &m_indexThread, SIGNAL( started() ), m_fuzzyIndex, SLOT( loadLuceneIndex() ) );
connect( m_fuzzyIndex, SIGNAL( indexReady() ), this, SIGNAL( indexReady() ) );
m_indexThread.start();
connect( m_fuzzyIndex, SIGNAL( indexReady() ), SIGNAL( indexReady() ) );
m_fuzzyIndex->loadLuceneIndex();
}
@@ -346,6 +348,7 @@ DatabaseImpl::searchTable( const QString& table, const QString& name, uint limit
results << resultslist.at( k ).first;
}
// qDebug() << "Returning" << results.count() << "results";
return results;
}

View File

@@ -74,7 +74,6 @@ private:
QString m_dbid;
QThread m_indexThread;
FuzzyIndex* m_fuzzyIndex;
};

View File

@@ -29,7 +29,7 @@ DatabaseResolver::resolve( const QVariant& v )
void
DatabaseResolver::gotResults( const Tomahawk::QID qid, QList< Tomahawk::result_ptr> results )
{
// qDebug() << Q_FUNC_INFO << qid << results.length();
qDebug() << Q_FUNC_INFO << qid << results.length();
Tomahawk::Pipeline::instance()->reportResults( qid, results );
}

View File

@@ -24,10 +24,11 @@ DatabaseWorker::~DatabaseWorker()
{
qDebug() << Q_FUNC_INFO << m_outstanding;
qDebug () << m_commands;
if ( m_commands.count() )
qDebug() << m_commands;
quit();
wait( 5000 );
wait( 60000 );
}

View File

@@ -16,17 +16,21 @@ using namespace lucene::queryParser;
using namespace lucene::search;
FuzzyIndex::FuzzyIndex( DatabaseImpl& db )
FuzzyIndex::FuzzyIndex( DatabaseImpl& db, bool wipeIndex )
: QObject()
, m_db( db )
, m_luceneReader( 0 )
, m_luceneSearcher( 0 )
{
QString lucenePath = TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" );
bool create = !IndexReader::indexExists( lucenePath.toStdString().c_str() );
m_luceneDir = FSDirectory::getDirectory( lucenePath.toStdString().c_str(), create );
QString m_lucenePath = TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" );
m_luceneDir = FSDirectory::getDirectory( m_lucenePath.toStdString().c_str() );
m_analyzer = _CLNEW SimpleAnalyzer();
if ( wipeIndex )
{
beginIndexing();
endIndexing();
}
}
@@ -52,7 +56,6 @@ FuzzyIndex::beginIndexing()
qDebug() << "Deleting old lucene stuff.";
m_luceneSearcher->close();
m_luceneReader->close();
m_luceneReader->unlock( m_luceneDir );
delete m_luceneSearcher;
delete m_luceneReader;
m_luceneSearcher = 0;
@@ -83,6 +86,7 @@ FuzzyIndex::appendFields( const QString& table, const QMap< unsigned int, QStrin
{
try
{
qDebug() << "Appending to index:" << fields.count();
bool create = !IndexReader::indexExists( TomahawkUtils::appDataDir().absoluteFilePath( "tomahawk.lucene" ).toStdString().c_str() );
IndexWriter luceneWriter = IndexWriter( m_luceneDir, m_analyzer, create );
Document doc;
@@ -173,9 +177,12 @@ FuzzyIndex::search( const QString& table, const QString& name )
if ( score > 0.05 )
{
resultsmap.insert( id, score );
// qDebug() << "Hitres:" << result << id << score << table << name;
// qDebug() << "Hitres:" << result << id << score << table << name;
}
}
delete hits;
delete qry;
}
catch( CLuceneError& error )
{

View File

@@ -35,7 +35,7 @@ class FuzzyIndex : public QObject
Q_OBJECT
public:
explicit FuzzyIndex( DatabaseImpl& db );
explicit FuzzyIndex( DatabaseImpl& db, bool wipeIndex = false );
~FuzzyIndex();
void beginIndexing();
@@ -53,6 +53,7 @@ public slots:
private:
DatabaseImpl& m_db;
QMutex m_mutex;
QString m_lucenePath;
lucene::analysis::SimpleAnalyzer* m_analyzer;
lucene::store::Directory* m_luceneDir;

View File

@@ -250,4 +250,4 @@ CREATE TABLE IF NOT EXISTS settings (
v TEXT NOT NULL DEFAULT ''
);
INSERT INTO settings(k,v) VALUES('schema_version', '19');
INSERT INTO settings(k,v) VALUES('schema_version', '20');

View File

@@ -1,5 +1,5 @@
/*
This file was automatically generated from schema.sql on Thu Feb 3 08:21:21 EST 2011.
This file was automatically generated from ./schema.sql on Wed Feb 23 12:39:07 CET 2011.
*/
static const char * tomahawk_schema_sql =
@@ -165,7 +165,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', '19');"
"INSERT INTO settings(k,v) VALUES('schema_version', '20');"
;
const char * get_tomahawk_sql()

View File

@@ -8,7 +8,7 @@
#define BLOCKSIZE 4096
BufferIODevice::BufferIODevice( unsigned int size, QObject *parent )
BufferIODevice::BufferIODevice( unsigned int size, QObject* parent )
: QIODevice( parent )
, m_size( size )
, m_received( 0 )
@@ -125,7 +125,8 @@ BufferIODevice::readData( char* data, qint64 maxSize )
}
qint64 BufferIODevice::writeData( const char* data, qint64 maxSize )
qint64
BufferIODevice::writeData( const char* data, qint64 maxSize )
{
// call addData instead
Q_ASSERT( false );
@@ -133,14 +134,16 @@ qint64 BufferIODevice::writeData( const char* data, qint64 maxSize )
}
qint64 BufferIODevice::size() const
qint64
BufferIODevice::size() const
{
qDebug() << Q_FUNC_INFO << m_size;
return m_size;
}
bool BufferIODevice::atEnd() const
bool
BufferIODevice::atEnd() const
{
// qDebug() << Q_FUNC_INFO << ( m_size <= m_pos );
return ( m_size <= m_pos );

View File

@@ -11,7 +11,7 @@ class BufferIODevice : public QIODevice
Q_OBJECT
public:
explicit BufferIODevice( unsigned int size = 0, QObject *parent = 0 );
explicit BufferIODevice( unsigned int size = 0, QObject* parent = 0 );
virtual bool open( OpenMode mode );
virtual void close();

View File

@@ -1,6 +1,5 @@
#include "controlconnection.h"
#include "remotecollection.h"
#include "filetransferconnection.h"
#include "database/database.h"
#include "database/databasecommand_collectionstats.h"
@@ -33,6 +32,9 @@ ControlConnection::~ControlConnection()
{
qDebug() << "DTOR controlconnection";
if ( !m_source.isNull() )
m_source->setOffline();
delete m_pingtimer;
m_servent->unregisterControlConnection(this);
if( m_dbsyncconn ) m_dbsyncconn->deleteLater();
@@ -53,29 +55,28 @@ void
ControlConnection::setup()
{
qDebug() << Q_FUNC_INFO << id() << name();
// setup source and remote collection for this peer
m_source = source_ptr( new Source( id(), this ) );
if( Servent::isIPWhitelisted( m_sock->peerAddress() ) )
QString friendlyName;
if ( Servent::isIPWhitelisted( m_sock->peerAddress() ) )
{
// FIXME TODO blocking DNS lookup if LAN, slow/fails on windows?
QHostInfo i = QHostInfo::fromName( m_sock->peerAddress().toString() );
if( i.hostName().length() )
{
m_source->setFriendlyName( i.hostName() );
}
friendlyName = i.hostName();
}
else
{
m_source->setFriendlyName( QString( "%1" ).arg( name() ) );
}
friendlyName = name();
// setup source and remote collection for this peer
m_source = SourceList::instance()->get( id(), friendlyName );
m_source->setControlConnection( this );
// delay setting up collection/etc until source is synced.
// we need it DB synced so it has an ID + exists in DB.
connect( m_source.data(), SIGNAL( syncedWithDatabase() ),
SLOT( registerSource() ), Qt::QueuedConnection );
m_source->doDBSync();
m_source->setOnline();
m_pingtimer = new QTimer;
m_pingtimer->setInterval( 5000 );
@@ -94,10 +95,6 @@ ControlConnection::registerSource()
Q_ASSERT( source == m_source.data() );
// .. but we'll use the shared pointer we've already made:
collection_ptr coll( new RemoteCollection( m_source ) );
m_source->addCollection( coll );
SourceList::instance()->add( m_source );
m_registered = true;
setupDbSyncConnection();
m_servent->registerControlConnection( this );
@@ -234,7 +231,7 @@ ControlConnection::onPingTimer()
if ( m_pingtimer_mark.elapsed() >= TCP_TIMEOUT * 1000 )
{
qDebug() << "Timeout reached! Shutting down connection to" << m_source->friendlyName();
shutdown( false );
shutdown( true );
}
sendMsg( Msg::factory( QByteArray(), Msg::PING ) );

View File

@@ -34,10 +34,9 @@ DBSyncConnection::DBSyncConnection( Servent* s, source_ptr src )
, m_source( src )
, m_state( UNKNOWN )
{
qDebug() << Q_FUNC_INFO << thread();
connect( this, SIGNAL( stateChanged( DBSyncConnection::State, DBSyncConnection::State, QString ) ),
m_source.data(), SIGNAL( loadingStateChanged(DBSyncConnection::State, DBSyncConnection::State, QString ) )
);
qDebug() << Q_FUNC_INFO << src->id() << thread();
connect( this, SIGNAL( stateChanged( DBSyncConnection::State, DBSyncConnection::State, QString ) ),
m_source.data(), SLOT( onStateChanged( DBSyncConnection::State, DBSyncConnection::State, QString ) ) );
m_timer.setInterval( IDLE_TIMEOUT );
connect( &m_timer, SIGNAL( timeout() ), SLOT( idleTimeout() ) );
@@ -71,7 +70,7 @@ DBSyncConnection::changeState( State newstate )
qDebug() << "DBSYNC State changed from" << s << "to" << newstate;
emit stateChanged( newstate, s, "" );
if( newstate == SYNCED )
if ( newstate == SYNCED )
{
qDebug() << "Synced :)";
}
@@ -82,7 +81,7 @@ void
DBSyncConnection::setup()
{
qDebug() << Q_FUNC_INFO;
setId( QString("DBSyncConnection/%1").arg(socket()->peerAddress().toString()) );
setId( QString( "DBSyncConnection/%1" ).arg( socket()->peerAddress().toString() ) );
check();
}
@@ -93,7 +92,8 @@ DBSyncConnection::trigger()
qDebug() << Q_FUNC_INFO;
// if we're still setting up the connection, do nothing - we sync on first connect anyway:
if( !this->isRunning() ) return;
if ( !this->isRunning() )
return;
QMetaObject::invokeMethod( this, "sendMsg", Qt::QueuedConnection,
Q_ARG( msg_ptr,
@@ -105,8 +105,8 @@ DBSyncConnection::trigger()
void
DBSyncConnection::check()
{
qDebug() << Q_FUNC_INFO;
if( m_state != UNKNOWN && m_state != SYNCED )
qDebug() << Q_FUNC_INFO << m_source->id();
if ( m_state != UNKNOWN && m_state != SYNCED )
{
qDebug() << "Syncing in progress already.";
return;
@@ -115,20 +115,20 @@ DBSyncConnection::check()
m_themcache.clear();
m_us.clear();
changeState(CHECKING);
changeState( CHECKING );
// load last-modified etc data for our collection and theirs from our DB:
DatabaseCommand_CollectionStats * cmd_us =
DatabaseCommand_CollectionStats* cmd_us =
new DatabaseCommand_CollectionStats( SourceList::instance()->getLocal() );
DatabaseCommand_CollectionStats * cmd_them =
DatabaseCommand_CollectionStats* cmd_them =
new DatabaseCommand_CollectionStats( m_source );
connect( cmd_us, SIGNAL( done(const QVariantMap&) ),
this, SLOT( gotUs(const QVariantMap&) ) );
connect( cmd_us, SIGNAL( done( QVariantMap ) ),
SLOT( gotUs( QVariantMap ) ) );
connect( cmd_them, SIGNAL( done(const QVariantMap&) ),
this, SLOT( gotThemCache(const QVariantMap&) ) );
connect( cmd_them, SIGNAL( done( QVariantMap ) ),
SLOT( gotThemCache( QVariantMap ) ) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd_us) );
@@ -145,7 +145,8 @@ void
DBSyncConnection::gotUs( const QVariantMap& m )
{
m_us = m;
if( !m_uscache.empty() ) sendOps();
if ( !m_uscache.empty() )
sendOps();
}
@@ -154,7 +155,7 @@ void
DBSyncConnection::gotThemCache( const QVariantMap& m )
{
m_themcache = m;
changeState(FETCHING);
changeState( FETCHING );
qDebug() << "Sending a FETCHOPS cmd since:" << m_themcache.value( "lastop" ).toString();
@@ -170,20 +171,21 @@ DBSyncConnection::handleMsg( msg_ptr msg )
{
Q_ASSERT( !msg->is( Msg::COMPRESSED ) );
if( m_state == FETCHING ) changeState(PARSING);
if ( m_state == FETCHING )
changeState( PARSING );
// "everything is synced" indicated by non-json msg containing "ok":
if( !msg->is( Msg::JSON ) &&
msg->is( Msg::DBOP ) &&
msg->payload() == "ok" )
if ( !msg->is( Msg::JSON ) &&
msg->is( Msg::DBOP ) &&
msg->payload() == "ok" )
{
qDebug() << "No ops to apply, we are synced.";
changeState( SYNCED );
// calc the collection stats, to updates the "X tracks" in the sidebar etc
// this is done automatically if you run a dbcmd to add files.
DatabaseCommand_CollectionStats* cmd = new DatabaseCommand_CollectionStats( m_source );
connect( cmd, SIGNAL( done( const QVariantMap & ) ),
m_source.data(), SLOT( setStats( const QVariantMap& ) ), Qt::QueuedConnection );
connect( cmd, SIGNAL( done( const QVariantMap & ) ),
m_source.data(), SLOT( setStats( const QVariantMap& ) ), Qt::QueuedConnection );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
return;
}
@@ -191,7 +193,7 @@ DBSyncConnection::handleMsg( msg_ptr msg )
Q_ASSERT( msg->is( Msg::JSON ) );
QVariantMap m = msg->json().toMap();
if( m.empty() )
if ( m.empty() )
{
qDebug() << "Failed to parse msg in dbsync";
Q_ASSERT( false );
@@ -199,45 +201,49 @@ DBSyncConnection::handleMsg( msg_ptr msg )
}
// a db sync op msg
if( msg->is( Msg::DBOP ) )
if ( msg->is( Msg::DBOP ) )
{
DatabaseCommand *cmd = DatabaseCommand::factory( m, m_source );
DatabaseCommand* cmd = DatabaseCommand::factory( m, m_source );
if ( !cmd )
{
qDebug() << "UNKNOWN DBOP CMD";
if( !msg->is( Msg::FRAGMENT ) ) // last msg in this batch
if ( !msg->is( Msg::FRAGMENT ) ) // last msg in this batch
lastOpApplied();
return;
}
qDebug() << "APPLYING CMD" << cmd->commandname() << cmd->guid();
if( !msg->is( Msg::FRAGMENT ) ) // last msg in this batch
if ( !msg->is( Msg::FRAGMENT ) ) // last msg in this batch
{
changeState( SAVING ); // just DB work left to complete
connect( cmd, SIGNAL( finished() ), this, SLOT( lastOpApplied() ) );
connect( cmd, SIGNAL( finished() ), SLOT( lastOpApplied() ) );
}
if ( !cmd->singletonCmd() )
m_source->setLastOpGuid( cmd->guid() );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
return;
}
if( m.value( "method" ).toString() == "fetchops" )
if ( m.value( "method" ).toString() == "fetchops" )
{
m_uscache = m;
if( !m_us.empty() ) sendOps();
if ( !m_us.empty() )
sendOps();
return;
}
if( m.value( "method" ).toString() == "trigger" )
if ( m.value( "method" ).toString() == "trigger" )
{
qDebug() << "Got trigger msg on dbsyncconnection, checking for new stuff.";
check();
return;
}
qDebug() << Q_FUNC_INFO << "Unhandled msg: " << msg->payload();
qDebug() << Q_FUNC_INFO << "Unhandled msg:" << msg->payload();
Q_ASSERT( false );
}
@@ -246,8 +252,8 @@ void
DBSyncConnection::lastOpApplied()
{
qDebug() << Q_FUNC_INFO;
changeState(SYNCED);
// check again, until peer reponds we have no new ops to process
changeState( SYNCED );
// check again, until peer responds we have no new ops to process
check();
}
@@ -263,7 +269,7 @@ DBSyncConnection::sendOps()
DatabaseCommand_loadOps* cmd = new DatabaseCommand_loadOps( src, m_uscache.value( "lastop" ).toString() );
connect( cmd, SIGNAL( done( QString, QString, QList< dbop_ptr > ) ),
this, SLOT( sendOpsData( QString, QString, QList< dbop_ptr > ) ) );
SLOT( sendOpsData( QString, QString, QList< dbop_ptr > ) ) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
@@ -272,13 +278,12 @@ DBSyncConnection::sendOps()
void
DBSyncConnection::sendOpsData( QString sinceguid, QString lastguid, QList< dbop_ptr > ops )
{
qDebug() << Q_FUNC_INFO << sinceguid << lastguid << "Num ops to send:" << ops.length();
if ( m_lastSentOp == lastguid )
ops.clear();
qDebug() << Q_FUNC_INFO << sinceguid << lastguid << "Num ops to send:" << ops.length();
m_lastSentOp = lastguid;
if( ops.length() == 0 )
if ( ops.length() == 0 )
{
sendMsg( Msg::factory( "ok", Msg::DBOP ) );
return;
@@ -289,12 +294,12 @@ DBSyncConnection::sendOpsData( QString sinceguid, QString lastguid, QList< dbop_
{
quint8 flags = Msg::JSON | Msg::DBOP;
if( ops.at(i)->compressed )
if ( ops.at( i )->compressed )
flags |= Msg::COMPRESSED;
if( i != ops.length()-1 )
if ( i != ops.length() - 1 )
flags |= Msg::FRAGMENT;
sendMsg( Msg::factory( ops.at(i)->payload, flags ) );
sendMsg( Msg::factory( ops.at( i )->payload, flags ) );
}
}

View File

@@ -711,7 +711,8 @@ Servent::triggerDBSync()
if( src.isNull() || src->isLocal() )
continue;
src->controlConnection()->dbSyncConnection()->trigger();
if ( src->controlConnection() ) // source online?
src->controlConnection()->dbSyncConnection()->trigger();
}
}

View File

@@ -139,14 +139,14 @@ Pipeline::reportResults( QID qid, const QList< result_ptr >& results )
if ( !m_qids.contains( qid ) )
{
qDebug() << "reportResults called for unknown QID";
qDebug() << "reportResults called for unknown QID" << qid;
Q_ASSERT( false );
return;
}
if ( !m_qidsState.contains( qid ) )
{
qDebug() << "reportResults called for unknown QID-state";
qDebug() << "reportResults called for unknown QID-state" << qid;
Q_ASSERT( false );
return;
}

View File

@@ -57,6 +57,9 @@ PlaylistItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& opti
if ( item->query()->results().count() )
painter->setOpacity( item->query()->results().at( 0 )->score() );
else
painter->setOpacity( 0.0 );
if ( painter->opacity() < 0.3 )
painter->setOpacity( 0.3 );
if ( item->isPlaying() )

View File

@@ -104,28 +104,18 @@ PlItem::setupItem( const Tomahawk::query_ptr& query, PlItem* parent, int row )
toberemoved = false;
m_query = query;
if ( query->numResults() )
onResultsAdded( query->results() );
{
emit dataChanged();
}
else
{
connect( query.data(), SIGNAL( resultsAdded( QList<Tomahawk::result_ptr> ) ),
SLOT( onResultsAdded( QList<Tomahawk::result_ptr> ) ), Qt::DirectConnection );
SIGNAL( dataChanged() ) );
connect( query.data(), SIGNAL( resultsRemoved( Tomahawk::result_ptr ) ),
SLOT( onResultsRemoved( Tomahawk::result_ptr ) ), Qt::DirectConnection );
SIGNAL( dataChanged() ) );
connect( query.data(), SIGNAL( resultsChanged() ),
SIGNAL( dataChanged() ) );
}
}
void
PlItem::onResultsAdded( const QList<Tomahawk::result_ptr>& results )
{
// qDebug() << "Found results for playlist item:" << this;
emit dataChanged();
}
void
PlItem::onResultsRemoved( const Tomahawk::result_ptr& result )
{
emit dataChanged();
}

View File

@@ -41,10 +41,6 @@ public:
signals:
void dataChanged();
private slots:
void onResultsAdded( const QList<Tomahawk::result_ptr>& result );
void onResultsRemoved( const Tomahawk::result_ptr& result );
private:
void setupItem( const Tomahawk::query_ptr& query, PlItem* parent, int row = -1 );

View File

@@ -28,14 +28,14 @@ PluginAPI::reportResults( const QString& qid, const QList<QVariantMap>& vresults
void
PluginAPI::addSource( source_ptr s )
{
SourceList::instance()->add( s );
// SourceList::instance()->add( s );
}
void
PluginAPI::removeSource( source_ptr s )
{
SourceList::instance()->remove( s );
// SourceList::instance()->remove( s );
}

View File

@@ -13,7 +13,7 @@ using namespace Tomahawk;
query_ptr
Query::get( const QVariant& v, bool autoResolve )
{
query_ptr q = query_ptr( new Query( v ) );
query_ptr q = query_ptr( new Query( v, autoResolve ) );
if ( autoResolve )
Pipeline::instance()->resolve( q );
@@ -21,7 +21,7 @@ Query::get( const QVariant& v, bool autoResolve )
}
Query::Query( const QVariant& v )
Query::Query( const QVariant& v, bool autoResolve )
: m_v( v )
, m_solved( false )
{
@@ -33,8 +33,8 @@ Query::Query( const QVariant& v )
m_qid = m.value( "qid" ).toString();
connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( refreshResults() ), Qt::QueuedConnection );
connect( Database::instance(), SIGNAL( indexReady() ), SLOT( refreshResults() ), Qt::QueuedConnection );
if ( autoResolve )
connect( Database::instance(), SIGNAL( indexReady() ), SLOT( refreshResults() ), Qt::QueuedConnection );
}
@@ -50,17 +50,12 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults )
// hook up signals, and check solved status
foreach( const result_ptr& rp, newresults )
{
connect( rp.data(), SIGNAL( becomingUnavailable() ), SLOT( resultUnavailable() ) );
if( !m_solved && rp->score() > 0.99 )
{
m_solved = true;
becameSolved = true;
}
connect( rp.data(), SIGNAL( statusChanged() ), SLOT( onResultStatusChanged() ) );
}
}
emit resultsAdded( newresults );
if( becameSolved )
emit solvedStateChanged( true );
checkResults();
}
@@ -72,28 +67,12 @@ Query::refreshResults()
void
Query::resultUnavailable()
Query::onResultStatusChanged()
{
Result* result = (Result*) sender();
Q_ASSERT( result );
qStableSort( m_results.begin(), m_results.end(), Query::resultSorter );
checkResults();
for ( int i = 0; i < m_results.length(); ++i )
{
if ( m_results.value( i ).data() == result )
{
result_ptr r = m_results.value( i );
m_results.removeAt( i );
emit resultsRemoved( r );
break;
}
}
if ( m_results.isEmpty() ) // FIXME proper score checking
{
m_solved = false;
emit solvedStateChanged( false );
}
emit resultsChanged();
}
@@ -104,10 +83,9 @@ Query::removeResult( const Tomahawk::result_ptr& result )
QMutexLocker lock( &m_mut );
m_results.removeAll( result );
}
emit resultsRemoved( result );
if ( m_results.isEmpty() ) // FIXME proper score checking
emit solvedStateChanged( false );
emit resultsRemoved( result );
checkResults();
}
@@ -157,3 +135,43 @@ Query::resultSorter( const result_ptr& left, const result_ptr& right )
return left->score() > right->score();
}
void
Query::clearResults()
{
foreach( const result_ptr& rp, m_results )
{
removeResult( rp );
}
}
void
Query::checkResults()
{
bool becameSolved = false;
bool becameUnsolved = true;
// hook up signals, and check solved status
foreach( const result_ptr& rp, m_results )
{
if ( !m_solved && rp->score() > 0.99 )
{
m_solved = true;
becameSolved = true;
}
if ( rp->score() > 0.99 )
{
becameUnsolved = false;
}
}
if ( m_solved && becameUnsolved )
{
m_solved = false;
emit solvedStateChanged( true );
}
if( becameSolved )
emit solvedStateChanged( true );
}

View File

@@ -20,7 +20,7 @@ Q_OBJECT
public:
static query_ptr get( const QVariant& v, bool autoResolve = true );
explicit Query( const QVariant& v );
explicit Query( const QVariant& v, bool autoResolve );
QVariant toVariant() const { return m_v; }
@@ -55,6 +55,7 @@ signals:
void resultsAdded( const QList<Tomahawk::result_ptr>& );
void resultsRemoved( const Tomahawk::result_ptr& );
void resultsChanged();
void solvedStateChanged( bool state );
void resolvingFinished( bool hasResults );
@@ -66,10 +67,13 @@ public slots:
void onResolvingFinished();
private slots:
void resultUnavailable();
void onResultStatusChanged();
void refreshResults();
private:
void clearResults();
void checkResults();
mutable QMutex m_mut;
mutable QVariant m_v;
QList< Tomahawk::result_ptr > m_results;

View File

@@ -25,15 +25,23 @@ Result::Result( const QVariant& v, const collection_ptr& collection )
m_size = m.value( "size" ).toUInt();
m_albumpos = m.value( "albumpos" ).toUInt();
m_modtime = m.value( "mtime" ).toUInt();
m_score = m.value( "score" ).toFloat();
m_year = 0;
m_id = m.value( "id" ).toUInt();
if ( !m_collection.isNull() )
connect( m_collection->source().data(), SIGNAL( offline() ), SIGNAL( becomingUnavailable() ), Qt::QueuedConnection );
{
connect( m_collection->source().data(), SIGNAL( online() ), SLOT( onOnline() ), Qt::QueuedConnection );
connect( m_collection->source().data(), SIGNAL( offline() ), SLOT( onOffline() ), Qt::QueuedConnection );
}
}
Result::~Result()
{
}
Result::~Result() {}
artist_ptr
Result::artist() const
@@ -41,22 +49,30 @@ Result::artist() const
return m_artist;
}
album_ptr
Result::album() const
{
return m_album;
}
collection_ptr
Result::collection() const
{
return m_collection;
}
float
Result::score() const
{
return m_v.toMap().value( "score", 0.0 ).toFloat();
if ( collection()->source()->isOnline() )
{
return m_score;
}
else
return 0.0;
}
@@ -68,7 +84,7 @@ Result::id() const
m_rid = m_v.toMap().value( "sid" ).toString();
}
return m_rid;
};
}
QString
@@ -94,3 +110,19 @@ Result::updateAttributes()
m_year = m_attributes.value( "releaseyear" ).toInt();
}
}
void
Result::onOnline()
{
// qDebug() << Q_FUNC_INFO << toString();
emit statusChanged();
}
void
Result::onOffline()
{
// qDebug() << Q_FUNC_INFO << toString();
emit statusChanged();
}

View File

@@ -30,7 +30,7 @@ public:
RID id() const;
collection_ptr collection() const;
Tomahawk::artist_ptr artist() const;
Tomahawk::album_ptr album() const;
Tomahawk::album_ptr album() const;
QString track() const { return m_track; }
QString url() const { return m_url; }
QString mimetype() const { return m_mimetype; }
@@ -48,8 +48,12 @@ public:
unsigned int dbid() const { return m_id; }
signals:
// emitted when the collection this result comes from is going offline:
void becomingUnavailable();
// emitted when the collection this result comes from is going offline/online:
void statusChanged();
private slots:
void onOffline();
void onOnline();
private:
void updateAttributes();
@@ -70,6 +74,7 @@ private:
unsigned int m_albumpos;
unsigned int m_modtime;
int m_year;
float m_score;
QVariantMap m_attributes;

View File

@@ -6,43 +6,42 @@
#include "network/controlconnection.h"
#include "database/databasecommand_addsource.h"
#include "database/databasecommand_sourceoffline.h"
#include "database/databasecommand_logplayback.h"
#include "database/database.h"
using namespace Tomahawk;
Source::Source( const QString &username, ControlConnection* cc )
Source::Source( int id, const QString &username )
: QObject()
, m_isLocal( false )
, m_online( false )
, m_username( username )
, m_id( 0 )
, m_cc( cc )
, m_ftc( 0 )
{
// source for local machine doesn't have a controlconnection. this is normal.
if ( cc )
connect( cc, SIGNAL( finished() ), SLOT( remove() ), Qt::QueuedConnection );
}
Source::Source( const QString &username )
: QObject()
, m_isLocal( true )
, m_online( false )
, m_username( username )
, m_id( 0 )
, m_id( id )
, m_cc( 0 )
{
qDebug() << Q_FUNC_INFO;
if ( id == 0 )
{
m_isLocal = true;
m_online = true;
}
}
Source::~Source()
{
qDebug() << Q_FUNC_INFO << friendlyName();
}
/* DatabaseCommand_SourceOffline* cmd = new DatabaseCommand_SourceOffline( id() );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );*/
void
Source::setControlConnection( ControlConnection* cc )
{
m_cc = cc;
if ( cc )
connect( cc, SIGNAL( finished() ), SLOT( remove() ), Qt::QueuedConnection );
}
@@ -57,17 +56,6 @@ Source::collection() const
}
void
Source::doDBSync()
{
// ensure username is in the database
DatabaseCommand_addSource* cmd = new DatabaseCommand_addSource( m_username, m_friendlyname );
connect( cmd, SIGNAL( done( unsigned int, QString ) ),
SLOT( dbLoaded( unsigned int, const QString& ) ) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
}
void
Source::setStats( const QVariantMap& m )
{
@@ -81,10 +69,7 @@ Source::remove()
{
qDebug() << Q_FUNC_INFO;
m_cc = 0;
emit offline();
m_collections.clear();
SourceList::instance()->remove( this );
setOffline();
}
@@ -102,7 +87,7 @@ Source::friendlyName() const
void
Source::addCollection( collection_ptr c )
Source::addCollection( const collection_ptr& c )
{
Q_ASSERT( m_collections.length() == 0 ); // only 1 source supported atm
m_collections.append( c );
@@ -111,7 +96,7 @@ Source::addCollection( collection_ptr c )
void
Source::removeCollection( collection_ptr c )
Source::removeCollection( const collection_ptr& c )
{
Q_ASSERT( m_collections.length() == 1 && m_collections.first() == c ); // only 1 source supported atm
m_collections.removeAll( c );
@@ -127,6 +112,10 @@ Source::setOffline()
m_online = false;
emit offline();
m_cc = 0;
DatabaseCommand_SourceOffline* cmd = new DatabaseCommand_SourceOffline( id() );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
}
@@ -136,6 +125,12 @@ Source::setOnline()
if ( m_online )
return;
// ensure username is in the database
DatabaseCommand_addSource* cmd = new DatabaseCommand_addSource( m_username, m_friendlyname );
connect( cmd, SIGNAL( done( unsigned int, QString ) ),
SLOT( dbLoaded( unsigned int, const QString& ) ) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>(cmd) );
m_online = true;
emit online();
}
@@ -145,7 +140,76 @@ void
Source::dbLoaded( unsigned int id, const QString& fname )
{
qDebug() << Q_FUNC_INFO << id << fname;
m_id = id;
m_friendlyname = fname;
emit syncedWithDatabase();
}
void
Source::scanningProgress( unsigned int files )
{
m_textStatus = tr( "Scanning (%L1 tracks)" ).arg( files );
emit stateChanged();
}
void
Source::scanningFinished( unsigned int files )
{
m_textStatus = tr( "Online" );
emit stateChanged();
}
void
Source::onStateChanged( DBSyncConnection::State newstate, DBSyncConnection::State oldstate, const QString& info )
{
QString msg;
switch( newstate )
{
case DBSyncConnection::CHECKING:
msg = tr( "Checking" );
break;
case DBSyncConnection::FETCHING:
msg = tr( "Fetching" );
break;
case DBSyncConnection::PARSING:
msg = tr( "Parsing" );
break;
case DBSyncConnection::SAVING:
msg = tr( "Saving" );
break;
case DBSyncConnection::SYNCED:
msg = tr( "Online" );
break;
case DBSyncConnection::SCANNING:
msg = tr( "Scanning (%L1 tracks)" ).arg( info );
break;
default:
msg = "???";
}
m_textStatus = msg;
emit stateChanged();
}
void
Source::onPlaybackStarted( const Tomahawk::query_ptr& query )
{
qDebug() << Q_FUNC_INFO << query->toString();
m_currentTrack = query;
emit playbackStarted( query );
}
void
Source::onPlaybackFinished( const Tomahawk::query_ptr& query )
{
qDebug() << Q_FUNC_INFO << query->toString();
emit playbackFinished( query );
}

View File

@@ -11,6 +11,7 @@
#include "dllmacro.h"
class DatabaseCommand_LogPlayback;
class ControlConnection;
class FileTransferConnection;
@@ -21,26 +22,40 @@ class DLLEXPORT Source : public QObject
{
Q_OBJECT
friend class ::DatabaseCommand_LogPlayback;
friend class ::DBSyncConnection;
public:
explicit Source( const QString& username, ControlConnection* cc );
explicit Source( const QString& username = QString() );
explicit Source( int id, const QString& username = QString() );
virtual ~Source();
bool isLocal() const { return m_isLocal; }
bool isOnline() const { return m_online; }
QString lastOpGuid() const { return m_lastOpGuid; }
QString userName() const { return m_username; }
QString friendlyName() const;
void setFriendlyName( const QString& fname ) { m_friendlyname = fname; }
collection_ptr collection() const;
void addCollection( QSharedPointer<Collection> c );
void removeCollection( QSharedPointer<Collection> c );
void addCollection( const Tomahawk::collection_ptr& c );
void removeCollection( const Tomahawk::collection_ptr& c );
unsigned int id() const { return m_id; }
ControlConnection* controlConnection() const { return m_cc; }
void setControlConnection( ControlConnection* cc );
void scanningProgress( unsigned int files ) { emit loadingStateChanged( DBSyncConnection::SCANNING, DBSyncConnection::UNKNOWN, QString::number( files ) ); }
void scanningProgress( unsigned int files );
void scanningFinished( unsigned int files );
void setOffline();
void setOnline();
unsigned int trackCount() const { return m_stats.value( "numfiles" ).toUInt(); }
Tomahawk::query_ptr currentTrack() const { return m_currentTrack; }
QString textStatus() const { return m_textStatus; }
signals:
void syncedWithDatabase();
@@ -56,21 +71,21 @@ signals:
void playbackStarted( const Tomahawk::query_ptr& query );
void playbackFinished( const Tomahawk::query_ptr& query );
// this signal is emitted from DBSyncConnection:
void loadingStateChanged( DBSyncConnection::State newstate, DBSyncConnection::State oldstate, const QString& info );
void stateChanged();
public slots:
void doDBSync();
void setStats( const QVariantMap& m );
protected:
void setOffline();
void setOnline();
private slots:
void setLastOpGuid( const QString& guid ) { m_lastOpGuid = guid; }
void dbLoaded( unsigned int id, const QString& fname );
void remove();
void onStateChanged( DBSyncConnection::State newstate, DBSyncConnection::State oldstate, const QString& info );
void onPlaybackStarted( const Tomahawk::query_ptr& query );
void onPlaybackFinished( const Tomahawk::query_ptr& query );
private:
bool m_isLocal;
bool m_online;
@@ -78,6 +93,10 @@ private:
unsigned int m_id;
QList< QSharedPointer<Collection> > m_collections;
QVariantMap m_stats;
QString m_lastOpGuid;
Tomahawk::query_ptr m_currentTrack;
QString m_textStatus;
ControlConnection* m_cc;
FileTransferConnection* m_ftc;

View File

@@ -2,6 +2,9 @@
#include <QDebug>
#include "database/database.h"
#include "database/databasecommand_loadallsources.h"
#include "network/remotecollection.h"
#include "network/controlconnection.h"
using namespace Tomahawk;
@@ -20,9 +23,11 @@ SourceList::instance()
return s_instance;
}
SourceList::SourceList( QObject* parent )
: QObject( parent )
{
loadSources();
}
@@ -34,81 +39,95 @@ SourceList::getLocal()
void
SourceList::add( const Tomahawk::source_ptr& s )
{
{
QMutexLocker lock( &m_mut );
if ( m_sources.contains( s->userName() ) )
return;
m_sources.insert( s->userName(), s );
if( !s->isLocal() )
{
Q_ASSERT( s->id() );
m_sources_id2name.insert( s->id(), s->userName() );
}
if( s->isLocal() )
{
Q_ASSERT( m_local.isNull() );
m_local = s;
}
qDebug() << "SourceList::add(" << s->userName() << "), total sources now:" << m_sources.size();
}
emit sourceAdded( s );
}
void
SourceList::remove( Tomahawk::source_ptr& s )
{
if ( s.isNull() )
return;
remove( s.data() );
}
void
SourceList::remove( Tomahawk::Source* s )
SourceList::loadSources()
{
qDebug() << Q_FUNC_INFO;
source_ptr src;
DatabaseCommand_LoadAllSources* cmd = new DatabaseCommand_LoadAllSources();
connect( cmd, SIGNAL( done( const QList<Tomahawk::source_ptr>& ) ),
SLOT( setSources( const QList<Tomahawk::source_ptr>& ) ) );
Database::instance()->enqueue( QSharedPointer<DatabaseCommand>( cmd ) );
}
void
SourceList::setSources( const QList<Tomahawk::source_ptr>& sources )
{
QMutexLocker lock( &m_mut );
foreach( const source_ptr& src, sources )
{
QMutexLocker lock( &m_mut );
if ( !m_sources.contains( s->userName() ) )
return;
src = m_sources.value( s->userName() );
m_sources_id2name.remove( src->id() );
m_sources.remove( s->userName() );
qDebug() << "SourceList::remove(" << s->userName() << "), total sources now:" << m_sources.size();
if ( src->controlConnection() )
src->controlConnection()->shutdown( true );
add( src );
}
emit sourceRemoved( src );
src.clear();
qDebug() << Q_FUNC_INFO << "- Total sources now:" << m_sources.size();
}
void
SourceList::setLocal( const Tomahawk::source_ptr& localSrc )
{
Q_ASSERT( localSrc->isLocal() );
Q_ASSERT( m_local.isNull() );
{
QMutexLocker lock( &m_mut );
m_sources.insert( localSrc->userName(), localSrc );
m_local = localSrc;
qDebug() << Q_FUNC_INFO << localSrc->userName();
}
emit sourceAdded( localSrc );
}
void
SourceList::add( const source_ptr& source )
{
Q_ASSERT( source->id() );
m_sources.insert( source->userName(), source );
m_sources_id2name.insert( source->id(), source->userName() );
connect( source.data(), SIGNAL( syncedWithDatabase() ), SLOT( sourceSynced() ) );
collection_ptr coll( new RemoteCollection( source ) );
source->addCollection( coll );
emit sourceAdded( source );
}
void
SourceList::removeAllRemote()
{
foreach( source_ptr s, m_sources )
{
if( s != m_local )
remove( s );
{
if ( s->controlConnection() )
{
s->controlConnection()->shutdown( true );
}
}
}
}
QList<source_ptr>
SourceList::sources() const
SourceList::sources( bool onlyOnline ) const
{
QMutexLocker lock( &m_mut );
return m_sources.values();
QList< source_ptr > sources;
foreach( const source_ptr& src, m_sources )
{
if ( !onlyOnline || src->controlConnection() )
sources << src;
}
return sources;
}
@@ -121,10 +140,32 @@ SourceList::get( unsigned int id ) const
source_ptr
SourceList::get( const QString& username ) const
SourceList::get( const QString& username, const QString& friendlyName )
{
QMutexLocker lock( &m_mut );
return m_sources.value( username );
source_ptr source;
if ( !m_sources.contains( username ) )
{
source = source_ptr( new Source( -1, username ) );
source->setFriendlyName( friendlyName );
add( source );
}
else
source = m_sources.value( username );
return source;
}
void
SourceList::sourceSynced()
{
Source* src = qobject_cast< Source* >( sender() );
Q_ASSERT( m_sources_id2name.values().contains( src->userName() ) );
m_sources_id2name.remove( m_sources_id2name.key( src->userName() ) );
m_sources_id2name.insert( src->id(), src->userName() );
}

View File

@@ -20,24 +20,32 @@ public:
explicit SourceList( QObject* parent = 0 );
const Tomahawk::source_ptr& getLocal();
void add( const Tomahawk::source_ptr& s );
void remove( Tomahawk::source_ptr& s );
void remove( Tomahawk::Source* s );
void setLocal( const Tomahawk::source_ptr& localSrc );
void removeAllRemote();
QList<Tomahawk::source_ptr> sources() const;
QList<Tomahawk::source_ptr> sources( bool onlyOnline = false ) const;
unsigned int count() const;
Tomahawk::source_ptr get( const QString& username ) const;
Tomahawk::source_ptr get( const QString& username, const QString& friendlyName = QString() );
Tomahawk::source_ptr get( unsigned int id ) const;
signals:
void ready();
void sourceAdded( const Tomahawk::source_ptr& );
void sourceRemoved( const Tomahawk::source_ptr& );
private slots:
void setSources( const QList<Tomahawk::source_ptr>& sources );
void sourceSynced();
private:
QMap<QString, Tomahawk::source_ptr > m_sources;
QMap<unsigned int, QString> m_sources_id2name;
void loadSources();
void add( const Tomahawk::source_ptr& source );
QMap< QString, Tomahawk::source_ptr > m_sources;
QMap< unsigned int, QString > m_sources_id2name;
Tomahawk::source_ptr m_local;
mutable QMutex m_mut; // mutable so const methods can use a lock

View File

@@ -6,10 +6,45 @@
#include <QStyleOption>
#include <QWidget>
#define ARROW_WIDTH 8
#define ARROW_HEIGHT 8
void
ProxyStyle::drawPrimitive( PrimitiveElement pe, const QStyleOption* opt, QPainter* p, const QWidget* w ) const
{
if ( pe == PE_IndicatorBranch )
{
if ( opt->state & QStyle::State_Children )
{
QRect r = opt->rect;
int hd = ( opt->rect.height() - ARROW_HEIGHT ) / 2;
int wd = ( opt->rect.width() - ARROW_WIDTH ) / 2;
r.adjust( wd, hd, 0, 0 );
QPointF pointsOpened[3] = { QPointF( r.x(), r.y() ), QPointF( r.x() + ARROW_WIDTH, r.y() ), QPointF( r.x() + ARROW_WIDTH / 2, r.y() + ARROW_HEIGHT ) };
QPointF pointsClosed[3] = { QPointF( r.x(), r.y() ), QPointF( r.x() + ARROW_WIDTH, r.y() + ARROW_HEIGHT / 2 ), QPointF( r.x(), r.y() + ARROW_HEIGHT ) };
p->save();
p->setRenderHint( QPainter::Antialiasing );
p->setPen( opt->palette.dark().color() );
p->setBrush( opt->palette.dark().color() );
if ( !( opt->state & QStyle::State_Open ) )
{
p->drawPolygon( pointsClosed, 3 );
}
else
{
p->drawPolygon( pointsOpened, 3 );
}
p->restore();
}
return;
}
if ( pe != PE_FrameStatusBar )
QProxyStyle::drawPrimitive( pe, opt, p, w );
}

View File

@@ -111,7 +111,7 @@ MusicScanner::listerFinished( const QMap<QString, unsigned int>& newmtimes )
// any remaining stuff that wasnt emitted as a batch:
if( m_scannedfiles.length() )
{
SourceList::instance()->getLocal()->scanningProgress( m_scanned );
SourceList::instance()->getLocal()->scanningFinished( m_scanned );
commitBatch( m_scannedfiles );
}

View File

@@ -1,3 +1,5 @@
#include "config.h"
#include <QCryptographicHash>
#include <QDebug>
#include <QDesktopServices>

View File

@@ -9,16 +9,19 @@
#include "query.h"
#include "sourcelist.h"
#include "sourcetreeitem.h"
#include "sourcetreeview.h"
#include "utils/imagebutton.h"
using namespace Tomahawk;
SourcesModel::SourcesModel( QObject* parent )
SourcesModel::SourcesModel( SourceTreeView* parent )
: QStandardItemModel( parent )
, m_parent( parent )
{
setColumnCount( 1 );
onSourceAdded( SourceList::instance()->sources() );
connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) );
connect( SourceList::instance(), SIGNAL( sourceRemoved( Tomahawk::source_ptr ) ), SLOT( onSourceRemoved( Tomahawk::source_ptr ) ) );
@@ -91,6 +94,14 @@ SourcesModel::loadSources()
}
void
SourcesModel::onSourceAdded( const QList<source_ptr>& sources )
{
foreach( const source_ptr& source, sources )
appendItem( source );
}
void
SourcesModel::onSourceAdded( const source_ptr& source )
{
@@ -113,8 +124,14 @@ SourcesModel::appendItem( const source_ptr& source )
// qDebug() << "Appending source item:" << item->source()->username();
invisibleRootItem()->appendRow( item->columns() );
// m_parent->setIndexWidget( m_parent->model()->index( rowCount() - 1, 0 ), item->widget() );
((QTreeView*)parent())->setIndexWidget( index( rowCount() - 1, 0 ), item->widget() );
connect( source.data(), SIGNAL( offline() ), SLOT( onSourceChanged() ) );
connect( source.data(), SIGNAL( online() ), SLOT( onSourceChanged() ) );
connect( source.data(), SIGNAL( stats( QVariantMap ) ), SLOT( onSourceChanged() ) );
connect( source.data(), SIGNAL( playbackStarted( Tomahawk::query_ptr ) ), SLOT( onSourceChanged() ) );
connect( source.data(), SIGNAL( stateChanged() ), SLOT( onSourceChanged() ) );
return true; // FIXME
}
@@ -201,7 +218,9 @@ SourcesModel::indexToPlaylist( const QModelIndex& index )
return res;
}
dynplaylist_ptr SourcesModel::indexToDynamicPlaylist(const QModelIndex& index)
dynplaylist_ptr
SourcesModel::indexToDynamicPlaylist( const QModelIndex& index )
{
dynplaylist_ptr res;
if ( !index.isValid() )
@@ -252,7 +271,9 @@ SourcesModel::setData( const QModelIndex& index, const QVariant& value, int role
if ( indexType( index ) == PlaylistSource )
{
playlist = indexToPlaylist( index );
} else if ( indexType( index ) == DynamicPlaylistSource ) {
}
else if ( indexType( index ) == DynamicPlaylistSource )
{
playlist = indexToDynamicPlaylist( index ).staticCast< Playlist >();
}
@@ -265,3 +286,27 @@ SourcesModel::setData( const QModelIndex& index, const QVariant& value, int role
return false;
}
void
SourcesModel::onSourceChanged()
{
Source* src = qobject_cast< Source* >( sender() );
for ( int i = 0; i < rowCount(); i++ )
{
QModelIndex idx = index( i, 0 );
if ( indexType( idx ) == CollectionSource )
{
SourceTreeItem* sti = indexToTreeItem( idx );
if ( sti )
{
if ( sti->source().data() == src )
{
emit dataChanged( idx, idx );
}
}
}
}
}

View File

@@ -7,6 +7,7 @@
#include "typedefs.h"
class SourceTreeItem;
class SourceTreeView;
class SourcesModel : public QStandardItemModel
{
@@ -21,7 +22,7 @@ public:
DynamicPlaylistSource = 2
};
explicit SourcesModel( QObject* parent = 0 );
explicit SourcesModel( SourceTreeView* parent = 0 );
virtual QStringList mimeTypes() const;
virtual Qt::DropActions supportedDropActions() const;
@@ -43,14 +44,20 @@ protected:
bool setData( const QModelIndex& index, const QVariant& value, int role = Qt::EditRole );
private slots:
void onSourceAdded( const QList<Tomahawk::source_ptr>& sources );
void onSourceAdded( const Tomahawk::source_ptr& source );
void onSourceRemoved( const Tomahawk::source_ptr& source );
void onSourceChanged();
void onItemOnline( const QModelIndex& idx );
void onItemOffline( const QModelIndex& idx );
public slots:
void loadSources();
private:
SourceTreeView* m_parent;
};
#endif // SOURCESMODEL_H

View File

@@ -0,0 +1,57 @@
#include "sourcesproxymodel.h"
#include <QDebug>
#include <QTreeView>
#include "sourcesmodel.h"
#include "sourcetreeitem.h"
SourcesProxyModel::SourcesProxyModel( SourcesModel* model, QObject* parent )
: QSortFilterProxyModel( parent )
, m_model( model )
, m_filtered( false )
{
setDynamicSortFilter( true );
setSourceModel( model );
}
void
SourcesProxyModel::showOfflineSources()
{
m_filtered = false;
invalidateFilter();
// Q_ASSERT( qobject_cast<QTreeView*>( parent() ) );
// qobject_cast<QTreeView*>( parent() )->expandAll();
}
void
SourcesProxyModel::hideOfflineSources()
{
m_filtered = true;
invalidateFilter();
// Q_ASSERT( qobject_cast<QTreeView*>( parent() ) );
// qobject_cast<QTreeView*>( parent() )->expandAll();
}
bool
SourcesProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const
{
if ( !m_filtered )
return true;
SourceTreeItem* sti = m_model->indexToTreeItem( sourceModel()->index( sourceRow, 0, sourceParent ) );
if ( sti )
{
if ( sti->source().isNull() || sti->source()->isOnline() )
return true;
}
return false;
}

View File

@@ -0,0 +1,28 @@
#ifndef SOURCESPROXYMODEL_H
#define SOURCESPROXYMODEL_H
#include <QSortFilterProxyModel>
class SourcesModel;
class SourcesProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
explicit SourcesProxyModel( SourcesModel* model, QObject* parent = 0 );
public slots:
void showOfflineSources();
void hideOfflineSources();
protected:
bool filterAcceptsRow( int sourceRow, const QModelIndex& sourceParent ) const;
private:
SourcesModel* m_model;
bool m_filtered;
};
#endif // SOURCESPROXYMODEL_H

View File

@@ -10,6 +10,7 @@
using namespace Tomahawk;
static inline QList< playlist_ptr > dynListToPlaylists( const QList< Tomahawk::dynplaylist_ptr >& list )
{
QList< playlist_ptr > newptrs;
@@ -19,11 +20,13 @@ static inline QList< playlist_ptr > dynListToPlaylists( const QList< Tomahawk::d
return newptrs;
}
SourceTreeItem::SourceTreeItem( const source_ptr& source, QObject* parent )
: QObject( parent )
, m_source( source )
{
QStandardItem* item = new QStandardItem( "" );
QStandardItem* item = new QStandardItem( source.isNull() ? "Super Collection" : source->friendlyName() );
item->setIcon( QIcon( RESPATH "images/user-avatar.png" ) );
item->setEditable( false );
item->setData( SourcesModel::CollectionSource, Type );
item->setData( (qlonglong)this, SourceItemPointer );
@@ -36,7 +39,6 @@ SourceTreeItem::SourceTreeItem( const source_ptr& source, QObject* parent )
connect( source->collection().data(), SIGNAL( playlistsAdded( QList<Tomahawk::playlist_ptr> ) ),
SLOT( onPlaylistsAdded( QList<Tomahawk::playlist_ptr> ) ) );
connect( source->collection().data(), SIGNAL( playlistsDeleted( QList<Tomahawk::playlist_ptr> ) ),
SLOT( onPlaylistsDeleted( QList<Tomahawk::playlist_ptr> ) ) );
@@ -46,8 +48,8 @@ SourceTreeItem::SourceTreeItem( const source_ptr& source, QObject* parent )
SLOT( onDynamicPlaylistsDeleted( QList<Tomahawk::dynplaylist_ptr> ) ) );
}
m_widget = new SourceTreeItemWidget( source );
connect( m_widget, SIGNAL( clicked() ), SLOT( onClicked() ) );
/* m_widget = new SourceTreeItemWidget( source );
connect( m_widget, SIGNAL( clicked() ), SLOT( onClicked() ) );*/
}
@@ -98,6 +100,7 @@ SourceTreeItem::onPlaylistsAdded( const QList<playlist_ptr>& playlists )
}
}
void
SourceTreeItem::onPlaylistsDeleted( const QList<playlist_ptr>& playlists )
{
@@ -125,6 +128,7 @@ SourceTreeItem::onPlaylistsDeleted( const QList<playlist_ptr>& playlists )
}
}
void
SourceTreeItem::onPlaylistLoaded( Tomahawk::PlaylistRevision revision )
{
@@ -149,7 +153,9 @@ SourceTreeItem::onPlaylistLoaded( Tomahawk::PlaylistRevision revision )
}
}
void SourceTreeItem::onDynamicPlaylistsAdded( const QList< dynplaylist_ptr >& playlists )
void
SourceTreeItem::onDynamicPlaylistsAdded( const QList< dynplaylist_ptr >& playlists )
{
// const-ness is important for getting the right pointer!
foreach( const dynplaylist_ptr& p, playlists )
@@ -167,7 +173,9 @@ void SourceTreeItem::onDynamicPlaylistsAdded( const QList< dynplaylist_ptr >& pl
}
}
void SourceTreeItem::onDynamicPlaylistsDeleted( const QList< dynplaylist_ptr >& playlists )
void
SourceTreeItem::onDynamicPlaylistsDeleted( const QList< dynplaylist_ptr >& playlists )
{
// const-ness is important for getting the right pointer!
foreach( const dynplaylist_ptr& p, playlists )
@@ -193,7 +201,9 @@ void SourceTreeItem::onDynamicPlaylistsDeleted( const QList< dynplaylist_ptr >&
}
}
void SourceTreeItem::onDynamicPlaylistLoaded( DynamicPlaylistRevision revision )
void
SourceTreeItem::onDynamicPlaylistLoaded( DynamicPlaylistRevision revision )
{
qlonglong ptr = reinterpret_cast<qlonglong>( sender() );

View File

@@ -19,8 +19,7 @@ public:
PlaylistPointer = Qt::UserRole + 3, /// Value is the playlist_ptr.data()
DynamicPlaylistPointer = Qt::UserRole + 4 /// Value is the dynplaylist_ptr.data()
};
explicit SourceTreeItem( const Tomahawk::source_ptr& source, QObject* parent );
virtual ~SourceTreeItem();

View File

@@ -49,7 +49,8 @@ SourceTreeItemWidget::SourceTreeItemWidget( const source_ptr& source, QWidget* p
connect( source.data(), SIGNAL( stats( QVariantMap ) ), SLOT( gotStats( QVariantMap ) ) );
connect( source.data(), SIGNAL( playbackStarted( Tomahawk::query_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::query_ptr ) ) );
connect( source.data(), SIGNAL( offline() ), SLOT( onOffline() ) );
ui->avatarImage->setPixmap( QPixmap( RESPATH "images/user-avatar.png" ) );
displayname = source->friendlyName();
@@ -62,8 +63,12 @@ SourceTreeItemWidget::SourceTreeItemWidget( const source_ptr& source, QWidget* p
ui->infoButton->setPixmap( QPixmap( RESPATH "images/source-info.png" ) .scaledToHeight( 32, Qt::SmoothTransformation ) );
}
if ( source.isNull() || source->isLocal() )
ui->activityLabel->setText( tr( "Idle" ) );
else
onOffline();
ui->nameLabel->setText( displayname );
ui->activityLabel->setText( tr( "Idle" ) );
ui->infoLabel->setForegroundRole( QPalette::Dark );
ui->activityLabel->setForegroundRole( QPalette::Dark );
@@ -73,8 +78,6 @@ SourceTreeItemWidget::SourceTreeItemWidget( const source_ptr& source, QWidget* p
connect( ui->onOffButton, SIGNAL( clicked() ), SIGNAL( clicked() ) );
connect( ui->infoButton, SIGNAL( clicked() ), SLOT( onInfoButtonClicked() ) );
onOffline();
}
@@ -145,7 +148,6 @@ void
SourceTreeItemWidget::onPlaybackStarted( const Tomahawk::query_ptr& query )
{
qDebug() << Q_FUNC_INFO << query->toString();
// ui->activityLabel->setText( tr( "Playing: %1 by %2" ).arg( query->track() ).arg( query->artist() ) );
ui->activityLabel->setQuery( query );
}
@@ -154,19 +156,14 @@ void
SourceTreeItemWidget::onOnline()
{
return;
if ( !m_source.isNull() )
ui->onOffButton->setPixmap( RESPATH "images/source-on-rest.png" );
}
void
SourceTreeItemWidget::onOffline()
{
ui->activityLabel->setText( tr( "Offline" ) );
return;
if ( !m_source.isNull() )
ui->onOffButton->setPixmap( RESPATH "images/source-off-rest.png" );
}

View File

@@ -5,6 +5,7 @@
#include "playlist/playlistmanager.h"
#include "sourcetreeitem.h"
#include "sourcesmodel.h"
#include "sourcesproxymodel.h"
#include "sourcelist.h"
#include "tomahawk/tomahawkapp.h"
@@ -14,6 +15,7 @@
#include <QHeaderView>
#include <QPainter>
#include <QStyledItemDelegate>
#include <QSize>
using namespace Tomahawk;
@@ -24,11 +26,12 @@ public:
SourceDelegate( QAbstractItemView* parent = 0 ) : QStyledItemDelegate( parent ), m_parent( parent ) {}
protected:
void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
void updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const
virtual QSize sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual void updateEditorGeometry( QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
if ( SourcesModel::indexType( index ) == SourcesModel::PlaylistSource || SourcesModel::indexType( index ) == SourcesModel::DynamicPlaylistSource )
editor->setGeometry( option.rect.adjusted( 32, 0, 0, 0 ) );
editor->setGeometry( option.rect.adjusted( 20, 0, 0, 0 ) );
else
QStyledItemDelegate::updateEditorGeometry( editor, option, index );
}
@@ -49,7 +52,7 @@ SourceTreeView::SourceTreeView( QWidget* parent )
setMinimumWidth( 220 );
setHeaderHidden( true );
setRootIsDecorated( false );
setRootIsDecorated( true );
setExpandsOnDoubleClick( false );
setSelectionBehavior( QAbstractItemView::SelectRows );
@@ -58,8 +61,8 @@ SourceTreeView::SourceTreeView( QWidget* parent )
setDropIndicatorShown( false );
setAllColumnsShowFocus( true );
setUniformRowHeights( false );
setIndentation( 0 );
setAnimated( false );
setIndentation( 16 );
setAnimated( true );
setItemDelegate( new SourceDelegate( this ) );
@@ -67,7 +70,8 @@ SourceTreeView::SourceTreeView( QWidget* parent )
connect( this, SIGNAL( customContextMenuRequested( const QPoint& ) ), SLOT( onCustomContextMenu( const QPoint& ) ) );
m_model = new SourcesModel( this );
setModel( m_model );
m_proxyModel = new SourcesProxyModel( m_model, this );
setModel( m_proxyModel );
header()->setStretchLastSection( false );
header()->setResizeMode( 0, QHeaderView::Stretch );
@@ -79,6 +83,8 @@ SourceTreeView::SourceTreeView( QWidget* parent )
connect( SourceList::instance(), SIGNAL( sourceRemoved( Tomahawk::source_ptr ) ), SLOT( onSourceOffline( Tomahawk::source_ptr ) ) );
m_model->appendItem( source_ptr() );
hideOfflineSources();
}
@@ -107,11 +113,8 @@ SourceTreeView::setupMenus()
}
}
if ( readonly )
{
m_deletePlaylistAction->setEnabled( !readonly );
m_renamePlaylistAction->setEnabled( !readonly );
}
m_deletePlaylistAction->setEnabled( !readonly );
m_renamePlaylistAction->setEnabled( !readonly );
connect( m_loadPlaylistAction, SIGNAL( triggered() ), SLOT( loadPlaylist() ) );
connect( m_renamePlaylistAction, SIGNAL( triggered() ), SLOT( renamePlaylist() ) );
@@ -119,6 +122,20 @@ SourceTreeView::setupMenus()
}
void
SourceTreeView::showOfflineSources()
{
m_proxyModel->showOfflineSources();
}
void
SourceTreeView::hideOfflineSources()
{
m_proxyModel->hideOfflineSources();
}
void
SourceTreeView::onSourceOffline( Tomahawk::source_ptr src )
{
@@ -160,7 +177,7 @@ SourceTreeView::onItemActivated( const QModelIndex& index )
PlaylistManager::instance()->show( playlist );
}
}
else if ( type == SourcesModel::DynamicPlaylistSource )
else if ( type == SourcesModel::DynamicPlaylistSource )
{
dynplaylist_ptr playlist = SourcesModel::indexToDynamicPlaylist( index );
if ( !playlist.isNull() )
@@ -211,7 +228,9 @@ SourceTreeView::deletePlaylist()
}
}
void SourceTreeView::renamePlaylist()
void
SourceTreeView::renamePlaylist()
{
edit( m_contextMenuIndex );
}
@@ -384,23 +403,122 @@ SourceTreeView::drawRow( QPainter* painter, const QStyleOptionViewItem& option,
}
QSize
SourceDelegate::sizeHint( const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
if ( index.data( SourceTreeItem::Type ) == SourcesModel::CollectionSource )
return QSize( option.rect.width(), 44 );
else
return QStyledItemDelegate::sizeHint( option, index );
}
void
SourceDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
{
QStyleOptionViewItem o = option;
o.rect.adjust( 12, 0, 0, 0 );
QStyleOptionViewItem o2 = option;
o2.rect.setX( 0 );
o2.state = option.state;
if ( ( option.state & QStyle::State_Enabled ) == QStyle::State_Enabled )
{
o.state = QStyle::State_Enabled;
if ( ( SourcesModel::indexType( index ) == SourcesModel::PlaylistSource || SourcesModel::indexType( index ) == SourcesModel::DynamicPlaylistSource ) &&
( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
{
o.palette.setColor( QPalette::Text, o.palette.color( QPalette::HighlightedText ) );
}
}
QStyledItemDelegate::paint( painter, option, index.model()->index( 0, 0 ) );
QStyledItemDelegate::paint( painter, o, index );
QStyledItemDelegate::paint( painter, o2, QModelIndex() );
if ( index.data( SourceTreeItem::Type ) == SourcesModel::CollectionSource )
{
painter->save();
QFont normal = painter->font();
QFont bold = painter->font();
bold.setBold( true );
SourceTreeItem* sti = SourcesModel::indexToTreeItem( index );
bool status = !( !sti || sti->source().isNull() || !sti->source()->isOnline() );
QString tracks;
int figWidth = 0;
if ( status )
{
tracks = QString::number( sti->source()->trackCount() );
figWidth = painter->fontMetrics().width( tracks );
}
QRect iconRect = option.rect.adjusted( 4, 6, -option.rect.width() + option.rect.height() - 12 + 4, -6 );
painter->drawPixmap( iconRect, QPixmap( RESPATH "images/user-avatar.png" ) );
if ( ( option.state & QStyle::State_Selected ) == QStyle::State_Selected )
{
painter->setPen( o.palette.color( QPalette::HighlightedText ) );
}
QRect textRect = option.rect.adjusted( iconRect.width() + 8, 6, -figWidth - 24, 0 );
if ( status || sti->source().isNull() )
painter->setFont( bold );
QString text = painter->fontMetrics().elidedText( index.data().toString(), Qt::ElideRight, textRect.width() );
painter->drawText( textRect, text );
QString desc = status ? sti->source()->textStatus() : tr( "Offline" );
if ( sti->source().isNull() )
desc = tr( "All available tracks" );
if ( status && !sti->source()->currentTrack().isNull() )
desc = sti->source()->currentTrack()->artist() + " - " + sti->source()->currentTrack()->track();
if ( desc.isEmpty() )
desc = tr( "Online" );
textRect = option.rect.adjusted( iconRect.width() + 8, painter->fontMetrics().height() + 10, -figWidth - 24, 0 );
painter->setFont( normal );
text = painter->fontMetrics().elidedText( desc, Qt::ElideRight, textRect.width() );
painter->drawText( textRect, text );
if ( !status )
{
painter->restore();
return;
}
painter->setRenderHint( QPainter::Antialiasing );
QRect figRect = o.rect.adjusted( o.rect.width() - figWidth - 18, 0, -10, -o.rect.height() + 16 );
int hd = ( option.rect.height() - figRect.height() ) / 2;
figRect.adjust( 0, hd, 0, hd );
QColor figColor( 167, 183, 211 );
painter->setPen( figColor );
painter->setBrush( figColor );
QPen origpen = painter->pen();
QPen pen = origpen;
pen.setWidth( 1.0 );
painter->setPen( pen );
painter->drawRect( figRect );
QPainterPath ppath;
ppath.moveTo( QPoint( figRect.x(), figRect.y() ) );
ppath.quadTo( QPoint( figRect.x() - 8, figRect.y() + figRect.height() / 2 ), QPoint( figRect.x(), figRect.y() + figRect.height() ) );
painter->drawPath( ppath );
ppath.moveTo( QPoint( figRect.x() + figRect.width(), figRect.y() ) );
ppath.quadTo( QPoint( figRect.x() + figRect.width() + 8, figRect.y() + figRect.height() / 2 ), QPoint( figRect.x() + figRect.width(), figRect.y() + figRect.height() ) );
painter->drawPath( ppath );
painter->setPen( origpen );
QTextOption to( Qt::AlignCenter );
painter->setFont( bold );
painter->setPen( Qt::white );
painter->drawText( figRect, tracks, to );
painter->restore();
}
else
{
QStyledItemDelegate::paint( painter, o, index );
}
}

View File

@@ -9,6 +9,7 @@
class CollectionModel;
class PlaylistModel;
class SourcesModel;
class SourcesProxyModel;
class SourceTreeView : public QTreeView
{
@@ -17,6 +18,10 @@ Q_OBJECT
public:
explicit SourceTreeView( QWidget* parent = 0 );
public slots:
void showOfflineSources();
void hideOfflineSources();
signals:
void onOnline( const QModelIndex& index );
void onOffline( const QModelIndex& index );
@@ -33,7 +38,7 @@ private slots:
void onSourceOffline( Tomahawk::source_ptr );
protected:
void drawBranches( QPainter* painter, const QRect& rect, const QModelIndex& index ) const {}
// void drawBranches( QPainter* painter, const QRect& rect, const QModelIndex& index ) const {}
void drawRow( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const;
virtual void paintEvent( QPaintEvent* event );
@@ -48,6 +53,7 @@ private:
CollectionModel* m_collectionModel;
SourcesModel* m_model;
SourcesProxyModel* m_proxyModel;
QModelIndex m_contextMenuIndex;
QMenu m_playlistMenu;

View File

@@ -1,5 +1,7 @@
#include "tomahawk/tomahawkapp.h"
#include "config.h"
#include <QPluginLoader>
#include <QDir>
#include <QMetaType>
@@ -151,20 +153,21 @@ TomahawkApp::TomahawkApp( int& argc, char *argv[] )
registerMetaTypes();
setupLogfile();
Echonest::Config::instance()->setAPIKey("JRIHWEP6GPOER2QQ6");
Echonest::Config::instance()->setAPIKey( "JRIHWEP6GPOER2QQ6" );
new TomahawkSettings( this );
m_audioEngine = new AudioEngine;
new ScanManager( this );
new Pipeline( this );
new SourceList( this );
m_servent = new Servent( this );
connect( m_servent, SIGNAL( ready() ), SLOT( setupSIP() ) );
qDebug() << "Init Database.";
setupDatabase();
new SourceList( this );
qDebug() << "Init Echonest Factory.";
GeneratorFactory::registerFactory( "echonest", new EchonestFactory );
@@ -319,6 +322,7 @@ TomahawkApp::registerMetaTypes()
qRegisterMetaType< GeneratorMode>("GeneratorMode");
qRegisterMetaType<Tomahawk::GeneratorMode>("Tomahawk::GeneratorMode");
// Extra definition for namespaced-versions of signals/slots required
qRegisterMetaType< Tomahawk::source_ptr >("Tomahawk::source_ptr");
qRegisterMetaType< Tomahawk::collection_ptr >("Tomahawk::collection_ptr");
qRegisterMetaType< Tomahawk::result_ptr >("Tomahawk::result_ptr");
qRegisterMetaType< Tomahawk::query_ptr >("Tomahawk::query_ptr");
@@ -334,6 +338,7 @@ TomahawkApp::registerMetaTypes()
qRegisterMetaType< QList<Tomahawk::result_ptr> >("QList<Tomahawk::result_ptr>");
qRegisterMetaType< QList<Tomahawk::artist_ptr> >("QList<Tomahawk::artist_ptr>");
qRegisterMetaType< QList<Tomahawk::album_ptr> >("QList<Tomahawk::album_ptr>");
qRegisterMetaType< QList<Tomahawk::source_ptr> >("QList<Tomahawk::source_ptr>");
qRegisterMetaType< QMap< QString, Tomahawk::plentry_ptr > >("QMap< QString, Tomahawk::plentry_ptr >");
qRegisterMetaType< Tomahawk::PlaylistRevision >("Tomahawk::PlaylistRevision");
qRegisterMetaType< Tomahawk::DynamicPlaylistRevision >("Tomahawk::DynamicPlaylistRevision");
@@ -411,11 +416,11 @@ TomahawkApp::removeScriptResolver( const QString& path )
void
TomahawkApp::initLocalCollection()
{
source_ptr src( new Source( "My Collection" ) );
source_ptr src( new Source( 0, "My Collection" ) );
collection_ptr coll( new DatabaseCollection( src ) );
src->addCollection( coll );
SourceList::instance()->add( src );
SourceList::instance()->setLocal( src );
// to make the stats signal be emitted by our local source
// this will update the sidebar, etc.
@@ -480,16 +485,17 @@ TomahawkApp::setupSIP()
{
qDebug() << Q_FUNC_INFO;
#ifdef GLOOX_FOUND
//FIXME: jabber autoconnect is really more, now that there is sip -- should be renamed and/or split out of jabber-specific settings
if( !arguments().contains( "--nosip" ) && TomahawkSettings::instance()->jabberAutoConnect() )
{
#ifdef GLOOX_FOUND
m_xmppBot = new XMPPBot( this );
#endif
qDebug() << "Connecting SIP classes";
m_sipHandler->connectPlugins( true );
// m_sipHandler->setProxy( *TomahawkUtils::proxy() );
}
#endif
}

View File

@@ -83,6 +83,9 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
SourceTreeView* stv = new SourceTreeView();
TransferView* transferView = new TransferView();
connect( ui->actionHideOfflineSources, SIGNAL( triggered() ), stv, SLOT( hideOfflineSources() ) );
connect( ui->actionShowOfflineSources, SIGNAL( triggered() ), stv, SLOT( showOfflineSources() ) );
sidebar->addWidget( stv );
sidebar->addWidget( transferView );
sidebar->hide( 1, false );
@@ -122,11 +125,11 @@ TomahawkWindow::TomahawkWindow( QWidget* parent )
statusBar()->addPermanentWidget( m_audioControls, 1 );
// propagate sip menu
foreach(SipPlugin *plugin, APP->sipHandler()->plugins())
foreach( SipPlugin *plugin, APP->sipHandler()->plugins() )
{
if(plugin->menu())
if ( plugin->menu() )
{
ui->menuNetwork->addMenu(plugin->menu());
ui->menuNetwork->addMenu( plugin->menu() );
}
}

View File

@@ -50,6 +50,9 @@
</property>
<addaction name="actionRescanCollection"/>
<addaction name="separator"/>
<addaction name="actionShowOfflineSources"/>
<addaction name="actionHideOfflineSources"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
<widget class="QMenu" name="menuPlaylist">
@@ -150,6 +153,16 @@
<string>Create New &amp;Station</string>
</property>
</action>
<action name="actionShowOfflineSources">
<property name="text">
<string>Show Offline Sources</string>
</property>
</action>
<action name="actionHideOfflineSources">
<property name="text">
<string>Hide Offline Sources</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>

View File

@@ -1,7 +0,0 @@
SET( tomahawkHeaders ${tomahawkHeaders}
xmppbot.h
)
SET( tomahawkSources ${tomahawkSources}
xmppbot.cpp
)