diff --git a/include/tomahawk/tomahawkapp.h b/include/tomahawk/tomahawkapp.h index a3162855b..8409d033b 100644 --- a/include/tomahawk/tomahawkapp.h +++ b/include/tomahawk/tomahawkapp.h @@ -4,6 +4,8 @@ #define APP TomahawkApp::instance() #include "headlesscheck.h" +#include "config.h" + #include "mac/tomahawkapp_mac.h" // for PlatforInterface #include diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 15923b836..de14fb95d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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} diff --git a/src/config.h.in b/src/config.h.in index a06d239a5..8a8d1807d 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -7,4 +7,7 @@ #cmakedefine LEOPARD #cmakedefine HAVE_SPARKLE +#cmakedefine LIBLASTFM_FOUND +#cmakedefine GLOOX_FOUND + #endif // CONFIG_H_IN diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 6f0782dfc..527a6adfb 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -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}/.. diff --git a/src/libtomahawk/database/database.cpp b/src/libtomahawk/database/database.cpp index 03c23f85b..23ae975b4 100644 --- a/src/libtomahawk/database/database.cpp +++ b/src/libtomahawk/database/database.cpp @@ -46,6 +46,7 @@ Database::enqueue( QSharedPointer lc ) if( lc->doesMutates() ) { //qDebug() << Q_FUNC_INFO << "RW" << lc->commandname(); + qDebug() << "Enqueueing command to rw thread:" << lc->commandname(); m_workerRW->enqueue( lc ); } else diff --git a/src/libtomahawk/database/databasecommand_collectionstats.cpp b/src/libtomahawk/database/databasecommand_collectionstats.cpp index 587c7d1b3..7236981ff 100644 --- a/src/libtomahawk/database/databasecommand_collectionstats.cpp +++ b/src/libtomahawk/database/databasecommand_collectionstats.cpp @@ -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 ); diff --git a/src/libtomahawk/database/databasecommand_loadallplaylists.h b/src/libtomahawk/database/databasecommand_loadallplaylists.h index 2738f26df..53ee5e3c0 100644 --- a/src/libtomahawk/database/databasecommand_loadallplaylists.h +++ b/src/libtomahawk/database/databasecommand_loadallplaylists.h @@ -1,5 +1,5 @@ -#ifndef DATABASECOMMAND_IMPORTALLPLAYLIST_H -#define DATABASECOMMAND_IMPORTALLPLAYLIST_H +#ifndef DATABASECOMMAND_LOADALLPLAYLIST_H +#define DATABASECOMMAND_LOADALLPLAYLIST_H #include #include @@ -26,4 +26,4 @@ signals: void done( const QList& playlists ); }; -#endif // DATABASECOMMAND_ADDFILES_H +#endif // DATABASECOMMAND_LOADALLPLAYLIST_H diff --git a/src/libtomahawk/database/databasecommand_loadallsources.cpp b/src/libtomahawk/database/databasecommand_loadallsources.cpp new file mode 100644 index 000000000..58e6744d2 --- /dev/null +++ b/src/libtomahawk/database/databasecommand_loadallsources.cpp @@ -0,0 +1,29 @@ +#include "databasecommand_loadallsources.h" + +#include + +#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 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 ); +} + diff --git a/src/libtomahawk/database/databasecommand_loadallsources.h b/src/libtomahawk/database/databasecommand_loadallsources.h new file mode 100644 index 000000000..fbd99597d --- /dev/null +++ b/src/libtomahawk/database/databasecommand_loadallsources.h @@ -0,0 +1,29 @@ +#ifndef DATABASECOMMAND_LOADALLSOURCES_H +#define DATABASECOMMAND_LOADALLSOURCES_H + +#include +#include + +#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& sources ); +}; + +#endif // DATABASECOMMAND_LOADALLSOURCES_H diff --git a/src/libtomahawk/database/databasecommand_loadops.cpp b/src/libtomahawk/database/databasecommand_loadops.cpp index 1c2a3880f..11a9516e0 100644 --- a/src/libtomahawk/database/databasecommand_loadops.cpp +++ b/src/libtomahawk/database/databasecommand_loadops.cpp @@ -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() ) diff --git a/src/libtomahawk/database/databasecommand_logplayback.cpp b/src/libtomahawk/database/databasecommand_logplayback.cpp index d93e50ce5..283291d23 100644 --- a/src/libtomahawk/database/databasecommand_logplayback.cpp +++ b/src/libtomahawk/database/databasecommand_logplayback.cpp @@ -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 ); diff --git a/src/libtomahawk/database/databasecommand_resolve.cpp b/src/libtomahawk/database/databasecommand_resolve.cpp index 7cf8ac5cd..2cc5d6cb4 100644 --- a/src/libtomahawk/database/databasecommand_resolve.cpp +++ b/src/libtomahawk/database/databasecommand_resolve.cpp @@ -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; } diff --git a/src/libtomahawk/database/databaseimpl.cpp b/src/libtomahawk/database/databaseimpl.cpp index fe38d63f0..7746f8a0f 100644 --- a/src/libtomahawk/database/databaseimpl.cpp +++ b/src/libtomahawk/database/databaseimpl.cpp @@ -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; } diff --git a/src/libtomahawk/database/databaseimpl.h b/src/libtomahawk/database/databaseimpl.h index f3aaaa410..ab3cc319e 100644 --- a/src/libtomahawk/database/databaseimpl.h +++ b/src/libtomahawk/database/databaseimpl.h @@ -74,7 +74,6 @@ private: QString m_dbid; - QThread m_indexThread; FuzzyIndex* m_fuzzyIndex; }; diff --git a/src/libtomahawk/database/databaseresolver.cpp b/src/libtomahawk/database/databaseresolver.cpp index 639a3fede..a58204a2a 100644 --- a/src/libtomahawk/database/databaseresolver.cpp +++ b/src/libtomahawk/database/databaseresolver.cpp @@ -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 ); } diff --git a/src/libtomahawk/database/databaseworker.cpp b/src/libtomahawk/database/databaseworker.cpp index 57ae9ba5a..f24fe99a6 100644 --- a/src/libtomahawk/database/databaseworker.cpp +++ b/src/libtomahawk/database/databaseworker.cpp @@ -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 ); } diff --git a/src/libtomahawk/database/fuzzyindex.cpp b/src/libtomahawk/database/fuzzyindex.cpp index 1aae63130..f6da39b68 100644 --- a/src/libtomahawk/database/fuzzyindex.cpp +++ b/src/libtomahawk/database/fuzzyindex.cpp @@ -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 ) { diff --git a/src/libtomahawk/database/fuzzyindex.h b/src/libtomahawk/database/fuzzyindex.h index e3274149b..bc294705c 100644 --- a/src/libtomahawk/database/fuzzyindex.h +++ b/src/libtomahawk/database/fuzzyindex.h @@ -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; diff --git a/src/libtomahawk/database/schema.sql b/src/libtomahawk/database/schema.sql index 174634d6f..ad8b000d1 100644 --- a/src/libtomahawk/database/schema.sql +++ b/src/libtomahawk/database/schema.sql @@ -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'); diff --git a/src/libtomahawk/database/schema.sql.h b/src/libtomahawk/database/schema.sql.h index d8052e10d..a580c1851 100644 --- a/src/libtomahawk/database/schema.sql.h +++ b/src/libtomahawk/database/schema.sql.h @@ -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() diff --git a/src/libtomahawk/network/bufferiodevice.cpp b/src/libtomahawk/network/bufferiodevice.cpp index c3be04748..836f4f6fc 100644 --- a/src/libtomahawk/network/bufferiodevice.cpp +++ b/src/libtomahawk/network/bufferiodevice.cpp @@ -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 ); diff --git a/src/libtomahawk/network/bufferiodevice.h b/src/libtomahawk/network/bufferiodevice.h index 0fca19b94..1474deb74 100644 --- a/src/libtomahawk/network/bufferiodevice.h +++ b/src/libtomahawk/network/bufferiodevice.h @@ -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(); diff --git a/src/libtomahawk/network/controlconnection.cpp b/src/libtomahawk/network/controlconnection.cpp index a9aec0ba7..d2cf61004 100644 --- a/src/libtomahawk/network/controlconnection.cpp +++ b/src/libtomahawk/network/controlconnection.cpp @@ -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 ) ); diff --git a/src/libtomahawk/network/dbsyncconnection.cpp b/src/libtomahawk/network/dbsyncconnection.cpp index 2d2eb8842..3172a5252 100644 --- a/src/libtomahawk/network/dbsyncconnection.cpp +++ b/src/libtomahawk/network/dbsyncconnection.cpp @@ -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(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(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( 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( 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 ) ); } } diff --git a/src/libtomahawk/network/servent.cpp b/src/libtomahawk/network/servent.cpp index 0ae3e3853..49385adf3 100644 --- a/src/libtomahawk/network/servent.cpp +++ b/src/libtomahawk/network/servent.cpp @@ -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(); } } diff --git a/src/libtomahawk/pipeline.cpp b/src/libtomahawk/pipeline.cpp index 22a1bd374..1e3e83d9a 100644 --- a/src/libtomahawk/pipeline.cpp +++ b/src/libtomahawk/pipeline.cpp @@ -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; } diff --git a/src/libtomahawk/playlist/playlistitemdelegate.cpp b/src/libtomahawk/playlist/playlistitemdelegate.cpp index 74ae72f17..c408dbb9f 100644 --- a/src/libtomahawk/playlist/playlistitemdelegate.cpp +++ b/src/libtomahawk/playlist/playlistitemdelegate.cpp @@ -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() ) diff --git a/src/libtomahawk/playlist/plitem.cpp b/src/libtomahawk/playlist/plitem.cpp index 163855d56..b9fcdf916 100644 --- a/src/libtomahawk/playlist/plitem.cpp +++ b/src/libtomahawk/playlist/plitem.cpp @@ -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 ) ), - SLOT( onResultsAdded( QList ) ), 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& results ) -{ -// qDebug() << "Found results for playlist item:" << this; - emit dataChanged(); -} - - -void -PlItem::onResultsRemoved( const Tomahawk::result_ptr& result ) -{ - emit dataChanged(); -} diff --git a/src/libtomahawk/playlist/plitem.h b/src/libtomahawk/playlist/plitem.h index ae09cdd0c..4796e54c1 100644 --- a/src/libtomahawk/playlist/plitem.h +++ b/src/libtomahawk/playlist/plitem.h @@ -41,10 +41,6 @@ public: signals: void dataChanged(); -private slots: - void onResultsAdded( const QList& result ); - void onResultsRemoved( const Tomahawk::result_ptr& result ); - private: void setupItem( const Tomahawk::query_ptr& query, PlItem* parent, int row = -1 ); diff --git a/src/libtomahawk/pluginapi.cpp b/src/libtomahawk/pluginapi.cpp index 850d693df..4bf86d317 100644 --- a/src/libtomahawk/pluginapi.cpp +++ b/src/libtomahawk/pluginapi.cpp @@ -28,14 +28,14 @@ PluginAPI::reportResults( const QString& qid, const QList& 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 ); } diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index 09c60df19..7e53c9f9d 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -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 ); +} diff --git a/src/libtomahawk/query.h b/src/libtomahawk/query.h index 83a4a74e6..bfd712ba0 100644 --- a/src/libtomahawk/query.h +++ b/src/libtomahawk/query.h @@ -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& ); 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; diff --git a/src/libtomahawk/result.cpp b/src/libtomahawk/result.cpp index 65adb656f..658d7681f 100644 --- a/src/libtomahawk/result.cpp +++ b/src/libtomahawk/result.cpp @@ -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(); +} diff --git a/src/libtomahawk/result.h b/src/libtomahawk/result.h index 1c15ab165..3bc9d02f4 100644 --- a/src/libtomahawk/result.h +++ b/src/libtomahawk/result.h @@ -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; diff --git a/src/libtomahawk/source.cpp b/src/libtomahawk/source.cpp index d6a6a090f..e6400344f 100644 --- a/src/libtomahawk/source.cpp +++ b/src/libtomahawk/source.cpp @@ -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(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(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(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(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 ); +} diff --git a/src/libtomahawk/source.h b/src/libtomahawk/source.h index 3e40b1db0..3e598c4aa 100644 --- a/src/libtomahawk/source.h +++ b/src/libtomahawk/source.h @@ -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 c ); - void removeCollection( QSharedPointer 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 > m_collections; QVariantMap m_stats; + QString m_lastOpGuid; + + Tomahawk::query_ptr m_currentTrack; + QString m_textStatus; ControlConnection* m_cc; FileTransferConnection* m_ftc; diff --git a/src/libtomahawk/sourcelist.cpp b/src/libtomahawk/sourcelist.cpp index f6e46c1b0..20be81298 100644 --- a/src/libtomahawk/sourcelist.cpp +++ b/src/libtomahawk/sourcelist.cpp @@ -2,6 +2,9 @@ #include +#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& ) ), + SLOT( setSources( const QList& ) ) ); + + Database::instance()->enqueue( QSharedPointer( cmd ) ); +} + + +void +SourceList::setSources( const QList& 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 -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() ); } diff --git a/src/libtomahawk/sourcelist.h b/src/libtomahawk/sourcelist.h index 7a776535d..aeabad234 100644 --- a/src/libtomahawk/sourcelist.h +++ b/src/libtomahawk/sourcelist.h @@ -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 sources() const; + QList 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& sources ); + void sourceSynced(); + private: - QMap m_sources; - QMap 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 diff --git a/src/libtomahawk/utils/proxystyle.cpp b/src/libtomahawk/utils/proxystyle.cpp index 34feb8f93..617cd348f 100644 --- a/src/libtomahawk/utils/proxystyle.cpp +++ b/src/libtomahawk/utils/proxystyle.cpp @@ -6,10 +6,45 @@ #include #include +#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 ); } diff --git a/src/musicscanner.cpp b/src/musicscanner.cpp index ef9bde29f..68a47e562 100644 --- a/src/musicscanner.cpp +++ b/src/musicscanner.cpp @@ -111,7 +111,7 @@ MusicScanner::listerFinished( const QMap& 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 ); } diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 92e335f0e..4b290e24a 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -1,3 +1,5 @@ +#include "config.h" + #include #include #include diff --git a/src/sourcetree/sourcesmodel.cpp b/src/sourcetree/sourcesmodel.cpp index 94d038096..3a8cf60ce 100644 --- a/src/sourcetree/sourcesmodel.cpp +++ b/src/sourcetree/sourcesmodel.cpp @@ -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& 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 ); + } + } + } + } +} diff --git a/src/sourcetree/sourcesmodel.h b/src/sourcetree/sourcesmodel.h index aa33e10ac..2b761637b 100644 --- a/src/sourcetree/sourcesmodel.h +++ b/src/sourcetree/sourcesmodel.h @@ -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& 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 diff --git a/src/sourcetree/sourcesproxymodel.cpp b/src/sourcetree/sourcesproxymodel.cpp new file mode 100644 index 000000000..e4bcea7c3 --- /dev/null +++ b/src/sourcetree/sourcesproxymodel.cpp @@ -0,0 +1,57 @@ +#include "sourcesproxymodel.h" + +#include +#include + +#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( parent() ) ); +// qobject_cast( parent() )->expandAll(); +} + + +void +SourcesProxyModel::hideOfflineSources() +{ + m_filtered = true; + invalidateFilter(); + +// Q_ASSERT( qobject_cast( parent() ) ); +// qobject_cast( 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; +} diff --git a/src/sourcetree/sourcesproxymodel.h b/src/sourcetree/sourcesproxymodel.h new file mode 100644 index 000000000..5961b4a37 --- /dev/null +++ b/src/sourcetree/sourcesproxymodel.h @@ -0,0 +1,28 @@ +#ifndef SOURCESPROXYMODEL_H +#define SOURCESPROXYMODEL_H + +#include + +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 diff --git a/src/sourcetree/sourcetreeitem.cpp b/src/sourcetree/sourcetreeitem.cpp index bd340cf1d..0e4ec8748 100644 --- a/src/sourcetree/sourcetreeitem.cpp +++ b/src/sourcetree/sourcetreeitem.cpp @@ -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 ) ), SLOT( onPlaylistsAdded( QList ) ) ); - connect( source->collection().data(), SIGNAL( playlistsDeleted( QList ) ), SLOT( onPlaylistsDeleted( QList ) ) ); @@ -46,8 +48,8 @@ SourceTreeItem::SourceTreeItem( const source_ptr& source, QObject* parent ) SLOT( onDynamicPlaylistsDeleted( QList ) ) ); } - 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& playlists ) } } + void SourceTreeItem::onPlaylistsDeleted( const QList& playlists ) { @@ -125,6 +128,7 @@ SourceTreeItem::onPlaylistsDeleted( const QList& 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( sender() ); diff --git a/src/sourcetree/sourcetreeitem.h b/src/sourcetree/sourcetreeitem.h index cc384981d..fbbaa8349 100644 --- a/src/sourcetree/sourcetreeitem.h +++ b/src/sourcetree/sourcetreeitem.h @@ -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(); diff --git a/src/sourcetree/sourcetreeitemwidget.cpp b/src/sourcetree/sourcetreeitemwidget.cpp index a93c59d29..fe37abbf8 100644 --- a/src/sourcetree/sourcetreeitemwidget.cpp +++ b/src/sourcetree/sourcetreeitemwidget.cpp @@ -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" ); } diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp index b079e606a..dbee09d92 100644 --- a/src/sourcetree/sourcetreeview.cpp +++ b/src/sourcetree/sourcetreeview.cpp @@ -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 #include #include +#include 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 ); + } } diff --git a/src/sourcetree/sourcetreeview.h b/src/sourcetree/sourcetreeview.h index 67243b77a..10df5d54d 100644 --- a/src/sourcetree/sourcetreeview.h +++ b/src/sourcetree/sourcetreeview.h @@ -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; diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 4dc5a86ec..13f63ec27 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -1,5 +1,7 @@ #include "tomahawk/tomahawkapp.h" +#include "config.h" + #include #include #include @@ -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"); // 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 >("QList"); qRegisterMetaType< QList >("QList"); qRegisterMetaType< QList >("QList"); + qRegisterMetaType< QList >("QList"); 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 } diff --git a/src/tomahawkwindow.cpp b/src/tomahawkwindow.cpp index caaf32ae5..4f03fd1a6 100644 --- a/src/tomahawkwindow.cpp +++ b/src/tomahawkwindow.cpp @@ -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() ); } } diff --git a/src/tomahawkwindow.ui b/src/tomahawkwindow.ui index cd4692ae0..94a6cecd1 100644 --- a/src/tomahawkwindow.ui +++ b/src/tomahawkwindow.ui @@ -50,6 +50,9 @@ + + + @@ -150,6 +153,16 @@ Create New &Station + + + Show Offline Sources + + + + + Hide Offline Sources + + diff --git a/src/xmppbot/CMakeLists.txt b/src/xmppbot/CMakeLists.txt deleted file mode 100644 index e593e2e4b..000000000 --- a/src/xmppbot/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -SET( tomahawkHeaders ${tomahawkHeaders} - xmppbot.h -) - -SET( tomahawkSources ${tomahawkSources} - xmppbot.cpp -) \ No newline at end of file