From fab36b2262e75e6952069491012232e3cc877d76 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Mar 2012 18:23:48 -0500 Subject: [PATCH 01/59] Use new QTweetLib 0.5 API for PIN values so leading zeros are respected Conflicts: src/accounts/twitter/tomahawkoauthtwitter.h --- src/sip/twitter/tomahawkoauthtwitter.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sip/twitter/tomahawkoauthtwitter.cpp b/src/sip/twitter/tomahawkoauthtwitter.cpp index 35cd98a9e..c70f66986 100644 --- a/src/sip/twitter/tomahawkoauthtwitter.cpp +++ b/src/sip/twitter/tomahawkoauthtwitter.cpp @@ -12,15 +12,15 @@ TomahawkOAuthTwitter::TomahawkOAuthTwitter( QNetworkAccessManager *nam, QObject* } -int +const QString TomahawkOAuthTwitter::authorizationWidget() { bool ok; - int i = QInputDialog::getInt(0, tr( "Twitter PIN" ), tr( "After authenticating on Twitter's web site,\nenter the displayed PIN number here:" ), 0, 0, 2147483647, 1, &ok); - if (ok) - return i; + const QString str = QInputDialog::getText(0, tr( "Twitter PIN" ), tr( "After authenticating on Twitter's web site,\nenter the displayed PIN number here:" ), QLineEdit::Normal, QString(), &ok); + if ( ok && !str.isEmpty() ) + return str; - return 0; + return QString(); } void From 240517b0cd95ffe658983f8c53b47182bd8afe6b Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Sun, 11 Mar 2012 18:46:00 +0100 Subject: [PATCH 02/59] Bump the required QTweetLib version --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index 8ada27b9c..e554d3555 100644 --- a/README +++ b/README @@ -41,7 +41,7 @@ Dependencies Attica 0.2.0 - ftp://ftp.kde.org/pub/kde/stable/attica/ QuaZip 0.4.3 - http://quazip.sourceforge.net/ Jreen 1.0.1 - https://github.com/euroelessar/jreen - QTweetLib 0.3.0 - https://github.com/minimoog/QTweetLib + QTweetLib 0.5.0 - https://github.com/minimoog/QTweetLib Third party libraries that we ship with our source: From 18e366991199f50c22c4c910e2e621cb0979dce6 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Fri, 9 Mar 2012 17:41:38 -0500 Subject: [PATCH 03/59] Fix XMPP proxy. Make no proxy hosts static so changing it works across all threads; make a duplication method so jreen doesn't scopepointer us to death on shutdown; pass in proxyfactory to jreen. Conflicts: src/settingsdialog.cpp src/sip/jabber/jabber.cpp --- src/libtomahawk/utils/tomahawkutils.cpp | 46 +++++++++++++++++-------- src/libtomahawk/utils/tomahawkutils.h | 2 +- src/proxydialog.ui | 3 +- src/settingsdialog.cpp | 21 +++++------ src/settingsdialog.h | 4 +-- src/sip/jabber/jabber.cpp | 1 + src/tomahawkapp.cpp | 1 - 7 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/libtomahawk/utils/tomahawkutils.cpp b/src/libtomahawk/utils/tomahawkutils.cpp index d706c3232..be219786f 100644 --- a/src/libtomahawk/utils/tomahawkutils.cpp +++ b/src/libtomahawk/utils/tomahawkutils.cpp @@ -301,10 +301,11 @@ extensionToMimetype( const QString& extension ) return s_ext2mime.value( extension, "unknown" ); } +static QMutex s_noProxyHostsMutex; +static QStringList s_noProxyHosts; NetworkProxyFactory::NetworkProxyFactory( const NetworkProxyFactory& other ) { - m_noProxyHosts = QStringList( other.m_noProxyHosts ); m_proxy = QNetworkProxy( other.m_proxy ); } @@ -312,13 +313,17 @@ NetworkProxyFactory::NetworkProxyFactory( const NetworkProxyFactory& other ) QList< QNetworkProxy > NetworkProxyFactory::queryProxy( const QNetworkProxyQuery& query ) { + tDebug() << Q_FUNC_INFO << "query hostname is " << query.peerHostName(); QList< QNetworkProxy > proxies; QString hostname = query.peerHostName(); - if ( m_proxy.hostName().isEmpty() || hostname.isEmpty() || m_noProxyHosts.contains( hostname ) || TomahawkSettings::instance()->proxyType() == QNetworkProxy::NoProxy ) + s_noProxyHostsMutex.lock(); + if ( s_noProxyHosts.contains( hostname ) ) + proxies << QNetworkProxy::NoProxy << systemProxyForQuery( query ); + else if ( m_proxy.hostName().isEmpty() || hostname.isEmpty() || TomahawkSettings::instance()->proxyType() == QNetworkProxy::NoProxy ) proxies << systemProxyForQuery( query ); else proxies << m_proxy << systemProxyForQuery( query ); - + s_noProxyHostsMutex.unlock(); return proxies; } @@ -335,7 +340,9 @@ NetworkProxyFactory::setNoProxyHosts( const QStringList& hosts ) //TODO: wildcard support } tDebug() << Q_FUNC_INFO << "New no-proxy hosts:" << newList; - m_noProxyHosts = newList; + s_noProxyHostsMutex.lock(); + s_noProxyHosts = newList; + s_noProxyHostsMutex.unlock(); } @@ -357,7 +364,6 @@ NetworkProxyFactory::operator=( const NetworkProxyFactory& rhs ) if ( this != &rhs ) { m_proxy = QNetworkProxy( rhs.m_proxy ); - m_noProxyHosts = QStringList( rhs.m_noProxyHosts ); } return *this; @@ -367,7 +373,7 @@ NetworkProxyFactory::operator=( const NetworkProxyFactory& rhs ) bool NetworkProxyFactory::operator==( const NetworkProxyFactory& other ) const { tDebug() << Q_FUNC_INFO; - if ( m_noProxyHosts != other.m_noProxyHosts || m_proxy != other.m_proxy ) + if ( m_proxy != other.m_proxy ) return false; return true; @@ -378,25 +384,29 @@ static QMap< QThread*, NetworkProxyFactory* > s_threadProxyFactoryHash; static QMutex s_namAccessMutex; NetworkProxyFactory* -proxyFactory( bool noMutexLocker ) +proxyFactory( bool makeClone, bool noMutexLocker ) { // Don't lock if being called from nam() tDebug() << Q_FUNC_INFO; QMutex otherMutex; QMutexLocker locker( noMutexLocker ? &otherMutex : &s_namAccessMutex ); - if ( s_threadProxyFactoryHash.contains( QThread::currentThread() ) ) - return s_threadProxyFactoryHash[ QThread::currentThread() ]; + if ( !makeClone ) + { + if ( s_threadProxyFactoryHash.contains( QThread::currentThread() ) ) + return s_threadProxyFactoryHash[ QThread::currentThread() ]; - if ( !s_threadProxyFactoryHash.contains( TOMAHAWK_APPLICATION::instance()->thread() ) ) - return 0; + if ( !s_threadProxyFactoryHash.contains( TOMAHAWK_APPLICATION::instance()->thread() ) ) + return 0; + } // create a new proxy factory for this thread TomahawkUtils::NetworkProxyFactory *mainProxyFactory = s_threadProxyFactoryHash[ TOMAHAWK_APPLICATION::instance()->thread() ]; TomahawkUtils::NetworkProxyFactory *newProxyFactory = new TomahawkUtils::NetworkProxyFactory(); *newProxyFactory = *mainProxyFactory; - s_threadProxyFactoryHash[ QThread::currentThread() ] = newProxyFactory; + if ( !makeClone ) + s_threadProxyFactoryHash[ QThread::currentThread() ] = newProxyFactory; return newProxyFactory; } @@ -455,7 +465,7 @@ nam() newNam->setConfiguration( QNetworkConfiguration( mainNam->configuration() ) ); newNam->setNetworkAccessible( mainNam->networkAccessible() ); - newNam->setProxyFactory( proxyFactory( true ) ); + newNam->setProxyFactory( proxyFactory( false, true ) ); s_threadNamHash[ QThread::currentThread() ] = newNam; @@ -485,9 +495,15 @@ setNam( QNetworkAccessManager* nam, bool noMutexLocker ) QNetworkProxy proxy( s->proxyType(), s->proxyHost(), s->proxyPort(), s->proxyUsername(), s->proxyPassword() ); proxyFactory->setProxy( proxy ); //FIXME: Jreen is broke without this - QNetworkProxy::setApplicationProxy( proxy ); - if ( !s->proxyNoProxyHosts().isEmpty() ) + //QNetworkProxy::setApplicationProxy( proxy ); + s_noProxyHostsMutex.lock(); + if ( !s->proxyNoProxyHosts().isEmpty() && s_noProxyHosts.isEmpty() ) + { + s_noProxyHostsMutex.unlock(); proxyFactory->setNoProxyHosts( s->proxyNoProxyHosts().split( ',', QString::SkipEmptyParts ) ); + } + else + s_noProxyHostsMutex.unlock(); } nam->setProxyFactory( proxyFactory ); diff --git a/src/libtomahawk/utils/tomahawkutils.h b/src/libtomahawk/utils/tomahawkutils.h index f3133e112..c244bff63 100644 --- a/src/libtomahawk/utils/tomahawkutils.h +++ b/src/libtomahawk/utils/tomahawkutils.h @@ -92,7 +92,7 @@ namespace TomahawkUtils DLLEXPORT QString extensionToMimetype( const QString& extension ); DLLEXPORT bool newerVersion( const QString& oldVersion, const QString& newVersion ); - DLLEXPORT NetworkProxyFactory* proxyFactory( bool noMutexLocker = false ); + DLLEXPORT NetworkProxyFactory* proxyFactory( bool makeClone = false, bool noMutexLocker = false ); DLLEXPORT void setProxyFactory( TomahawkUtils::NetworkProxyFactory* factory, bool noMutexLocker = false ); DLLEXPORT QNetworkAccessManager* nam(); DLLEXPORT void setNam( QNetworkAccessManager* nam, bool noMutexLocker = false ); diff --git a/src/proxydialog.ui b/src/proxydialog.ui index 4b30ca1ca..321fcb09c 100644 --- a/src/proxydialog.ui +++ b/src/proxydialog.ui @@ -139,7 +139,8 @@ - No Proxy Hosts: + No Proxy Hosts: +(Overrides system proxy) diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 850701b86..57f3a735e 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -22,13 +22,13 @@ #include "utils/tomahawkutilsgui.h" -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include #ifdef LIBLASTFM_FOUND #include @@ -859,7 +859,6 @@ ProxyDialog::ProxyDialog( QWidget *parent ) ui->userLineEdit->setEnabled( false ); ui->passwordLineEdit->setEnabled( false ); ui->checkBoxUseProxyForDns->setEnabled( false ); - ui->noHostLineEdit->setEnabled( false ); } connect( ui->typeBox, SIGNAL( currentIndexChanged( int ) ), SLOT( proxyTypeChangedSlot( int ) ) ); @@ -876,7 +875,6 @@ ProxyDialog::proxyTypeChangedSlot( int index ) ui->userLineEdit->setEnabled( false ); ui->passwordLineEdit->setEnabled( false ); ui->checkBoxUseProxyForDns->setEnabled( false ); - ui->noHostLineEdit->setEnabled( false ); } else { @@ -885,7 +883,6 @@ ProxyDialog::proxyTypeChangedSlot( int index ) ui->userLineEdit->setEnabled( true ); ui->passwordLineEdit->setEnabled( true ); ui->checkBoxUseProxyForDns->setEnabled( true ); - ui->noHostLineEdit->setEnabled( true ); } } @@ -923,8 +920,8 @@ ProxyDialog::saveSettings() proxyFactory->setProxy( QNetworkProxy( type, s->proxyHost(), s->proxyPort(), s->proxyUsername(), s->proxyPassword() ) ); if ( !ui->noHostLineEdit->text().isEmpty() ) { - tDebug() << Q_FUNC_INFO << "hosts line edit is " << ui->noHostLineEdit->text(); - tDebug() << Q_FUNC_INFO << "split hosts line edit is " << ui->noHostLineEdit->text().split( ' ', QString::SkipEmptyParts ); + tDebug() << Q_FUNC_INFO << "noproxy line edit is " << ui->noHostLineEdit->text(); + tDebug() << Q_FUNC_INFO << "split noproxy line edit is " << ui->noHostLineEdit->text().split( ' ', QString::SkipEmptyParts ); proxyFactory->setNoProxyHosts( ui->noHostLineEdit->text().split( ' ', QString::SkipEmptyParts ) ); } } diff --git a/src/settingsdialog.h b/src/settingsdialog.h index ef2bdb90e..4c80b127b 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -19,8 +19,8 @@ #ifndef SETTINGSDIALOG_H #define SETTINGSDIALOG_H -#include -#include +#include +#include #include "config.h" diff --git a/src/sip/jabber/jabber.cpp b/src/sip/jabber/jabber.cpp index fa3295a4f..0473c9c17 100644 --- a/src/sip/jabber/jabber.cpp +++ b/src/sip/jabber/jabber.cpp @@ -102,6 +102,7 @@ JabberPlugin::JabberPlugin( const QString& pluginId ) // general client setup m_client = new Jreen::Client( jid, m_currentPassword ); + m_client->setProxyFactory( TomahawkUtils::proxyFactory( true ) ); setupClientHelper(); m_client->registerPayload(new TomahawkSipMessageFactory); diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 145a55f8a..d15440343 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include "artist.h" #include "album.h" From 6c6411561b6b1ec8adbf8dbd2e8655b389224620 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 14 Mar 2012 16:20:24 -0400 Subject: [PATCH 04/59] Bump dependencies --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index e554d3555..5cd733079 100644 --- a/README +++ b/README @@ -40,7 +40,7 @@ Dependencies Attica 0.2.0 - ftp://ftp.kde.org/pub/kde/stable/attica/ QuaZip 0.4.3 - http://quazip.sourceforge.net/ - Jreen 1.0.1 - https://github.com/euroelessar/jreen + Jreen 1.0.3 - https://github.com/euroelessar/jreen QTweetLib 0.5.0 - https://github.com/minimoog/QTweetLib Third party libraries that we ship with our source: From 042ccbe73088b88eb1d0e692cc3851a589919c4d Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 14 Mar 2012 16:31:20 -0400 Subject: [PATCH 05/59] Fix merge issue --- src/sip/twitter/tomahawkoauthtwitter.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sip/twitter/tomahawkoauthtwitter.h b/src/sip/twitter/tomahawkoauthtwitter.h index 6b1a75465..a1cd53304 100644 --- a/src/sip/twitter/tomahawkoauthtwitter.h +++ b/src/sip/twitter/tomahawkoauthtwitter.h @@ -16,7 +16,7 @@ public: ~TomahawkOAuthTwitter() {} protected: - virtual int authorizationWidget(); + virtual const QString authorizationWidget(); private slots: void error(); From 6342e6a9f8c09ce2012d7d11f241c69b6d116f08 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 15 Mar 2012 08:42:05 +0100 Subject: [PATCH 06/59] * Fixed TWK-758: Sorting playlist by album position. --- src/libtomahawk/playlist/trackproxymodel.cpp | 22 +++++++++--- src/libtomahawk/playlist/treeproxymodel.cpp | 35 ++++++++++++-------- 2 files changed, 38 insertions(+), 19 deletions(-) diff --git a/src/libtomahawk/playlist/trackproxymodel.cpp b/src/libtomahawk/playlist/trackproxymodel.cpp index 6b42a6051..b9e8b4629 100644 --- a/src/libtomahawk/playlist/trackproxymodel.cpp +++ b/src/libtomahawk/playlist/trackproxymodel.cpp @@ -69,7 +69,7 @@ TrackProxyModel::filterAcceptsRow( int sourceRow, const QModelIndex& sourceParen return false; const Tomahawk::query_ptr& q = pi->query(); - if( q.isNull() ) // uh oh? filter out invalid queries i guess + if ( q.isNull() ) // uh oh? filter out invalid queries i guess return false; Tomahawk::result_ptr r; @@ -190,7 +190,7 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c album1 = r->album()->name(); track1 = r->track(); albumpos1 = r->albumpos(); - discnumber1 = r->discnumber(); + discnumber1 = qMax( 1, (int)r->discnumber() ); bitrate1 = r->bitrate(); mtime1 = r->modificationTime(); id1 = r->trackId(); @@ -203,7 +203,7 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c album2 = r->album()->name(); track2 = r->track(); albumpos2 = r->albumpos(); - discnumber2 = r->discnumber(); + discnumber2 = qMax( 1, (int)r->discnumber() ); bitrate2 = r->bitrate(); mtime2 = r->modificationTime(); id2 = r->trackId(); @@ -223,7 +223,7 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c { if ( album1 == album2 ) { - if( discnumber1 == discnumber2 ) + if ( discnumber1 == discnumber2 ) { if ( albumpos1 == albumpos2 ) return id1 < id2; @@ -243,7 +243,7 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c { if ( album1 == album2 ) { - if( discnumber1 == discnumber2 ) + if ( discnumber1 == discnumber2 ) { if ( albumpos1 == albumpos2 ) return id1 < id2; @@ -277,6 +277,18 @@ TrackProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) c return size1 < size2; } + else if ( left.column() == TrackModel::AlbumPos ) // sort by album pos + { + if ( discnumber1 != discnumber2 ) + { + return discnumber1 < discnumber2; + } + else + { + if ( albumpos1 != albumpos2 ) + return albumpos1 < albumpos2; + } + } const QString& lefts = sourceModel()->data( left ).toString(); const QString& rights = sourceModel()->data( right ).toString(); diff --git a/src/libtomahawk/playlist/treeproxymodel.cpp b/src/libtomahawk/playlist/treeproxymodel.cpp index e9494f32e..ff2e3e9c9 100644 --- a/src/libtomahawk/playlist/treeproxymodel.cpp +++ b/src/libtomahawk/playlist/treeproxymodel.cpp @@ -301,28 +301,35 @@ TreeProxyModel::lessThan( const QModelIndex& left, const QModelIndex& right ) co albumpos2 = p2->query()->albumpos(); discnumber2 = p2->query()->discnumber(); } + if ( !p1->result().isNull() ) + { + if ( albumpos1 == 0 ) + albumpos1 = p1->result()->albumpos(); + if ( discnumber1 == 0 ) + discnumber1 = p1->result()->discnumber(); + } + if ( !p2->result().isNull() ) + { + if ( albumpos2 == 0 ) + albumpos2 = p2->result()->albumpos(); + if ( discnumber2 == 0 ) + discnumber2 = p2->result()->discnumber(); + } + discnumber1 = qMax( 1, (int)discnumber1 ); + discnumber2 = qMax( 1, (int)discnumber2 ); - if ( albumpos1 == 0 && !p1->result().isNull() ) - albumpos1 = p1->result()->albumpos(); - if ( discnumber1 == 0 && !p1->result().isNull() ) - discnumber1 = p1->result()->discnumber(); - - if ( albumpos2 == 0 && !p2->result().isNull() ) - albumpos2 = p2->result()->albumpos(); - if ( discnumber2 == 0 && !p2->result().isNull() ) - discnumber2 = p2->result()->discnumber(); - - const QString& lefts = textForItem( p1 ); - const QString& rights = textForItem( p2 ); - - if( discnumber1 != discnumber2 ) + if ( discnumber1 != discnumber2 ) + { return discnumber1 < discnumber2; + } else { if ( albumpos1 != albumpos2 ) return albumpos1 < albumpos2; } + const QString& lefts = textForItem( p1 ); + const QString& rights = textForItem( p2 ); if ( lefts == rights ) return (qint64)&p1 < (qint64)&p2; From 66836ae0bd2bcdfbf04a4110ced4e064e71bb8cb Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 15 Mar 2012 09:04:16 +0100 Subject: [PATCH 07/59] * Something is wonky about CLucene scoring. Rely on our internal scoring. --- src/libtomahawk/database/fuzzyindex.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/database/fuzzyindex.cpp b/src/libtomahawk/database/fuzzyindex.cpp index f9cf8802c..b7597c9c7 100644 --- a/src/libtomahawk/database/fuzzyindex.cpp +++ b/src/libtomahawk/database/fuzzyindex.cpp @@ -227,7 +227,7 @@ FuzzyIndex::search( const Tomahawk::query_ptr& query ) fqry = _CLNEW FuzzyQuery( term ); qry->add( fqry, true, BooleanClause::MUST ); - minScore = 0.05; + minScore = 0.00; } Hits* hits = m_luceneSearcher->search( qry ); From 27147a0140d004001df08293e76d3e4d5342c18f Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Mon, 19 Mar 2012 21:25:38 -0400 Subject: [PATCH 08/59] Guard against null sharedptr that shouldn't be null anyway -.- --- src/libtomahawk/result.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/result.cpp b/src/libtomahawk/result.cpp index fb03c7aaf..33ca4e86d 100644 --- a/src/libtomahawk/result.cpp +++ b/src/libtomahawk/result.cpp @@ -170,7 +170,7 @@ Result::toVariant() const QString Result::toString() const { - return QString( "Result(%1 %2\t%3 - %4 %5" ).arg( id() ).arg( score() ).arg( artist()->name() ).arg( track() ).arg( url() ); + return QString( "Result(%1 %2\t%3 - %4 %5" ).arg( id() ).arg( score() ).arg( artist().isNull() ? QString() : artist()->name() ).arg( track() ).arg( url() ); } From e1b086e3a45c0bdd36e55882d70a1d28b1270b15 Mon Sep 17 00:00:00 2001 From: mack-t Date: Sun, 18 Mar 2012 16:12:19 -0400 Subject: [PATCH 09/59] Add albumpos, discnumber and score information from tomahawk resolver (cherry picked from commit 21eeab61d8e871f9d1b1dbb7540c274e6e8781d8) --- src/libtomahawk/resolvers/qtscriptresolver.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libtomahawk/resolvers/qtscriptresolver.cpp b/src/libtomahawk/resolvers/qtscriptresolver.cpp index d518c15f2..92d9e4506 100644 --- a/src/libtomahawk/resolvers/qtscriptresolver.cpp +++ b/src/libtomahawk/resolvers/qtscriptresolver.cpp @@ -392,10 +392,13 @@ QtScriptResolver::parseResultVariantList( const QVariantList& reslist ) rp->setArtist( ap ); rp->setAlbum( Tomahawk::Album::get( ap, m.value( "album" ).toString(), false ) ); rp->setTrack( m.value( "track" ).toString() ); + rp->setAlbumPos( m.value( "albumpos" ).toUInt() ); rp->setBitrate( m.value( "bitrate" ).toUInt() ); rp->setSize( m.value( "size" ).toUInt() ); rp->setRID( uuid() ); rp->setFriendlySource( name() ); + rp->setScore( m.value( "score" ).toFloat() ); + rp->setDiscNumber( m.value( "discnumber" ).toUInt() ); if ( m.contains( "year" ) ) { From 6e929986cb2ea218e7e7f785bc69b68b3f5801db Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 9 Mar 2012 14:13:43 -0500 Subject: [PATCH 10/59] A bit of extra safety (cherry picked from commit 2a58d53145e066d307029757866d34c3cde2543a) --- src/libtomahawk/query.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index 1393a3260..113ad7b8c 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -106,6 +106,7 @@ Query::~Query() { QMutexLocker lock( &m_mutex ); m_ownRef.clear(); + m_results.clear(); } From e828dadec82a9f798d53c644e5140c9054574e5d Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Thu, 15 Mar 2012 19:00:14 -0400 Subject: [PATCH 11/59] All QSharedPointers used in different threads need deleteLater as custom deleter. This is some of them. (cherry picked from commit e3f5605c4e04bd3e5dc55ccafeb2e6fb150cb1e5) --- src/libtomahawk/album.cpp | 2 +- src/libtomahawk/artist.cpp | 2 +- src/libtomahawk/database/databasecollection.cpp | 4 ++-- src/libtomahawk/database/databasecommand_loadallplaylists.cpp | 2 +- src/libtomahawk/playlist.cpp | 2 +- src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp | 2 +- src/libtomahawk/query.cpp | 4 ++-- src/libtomahawk/result.cpp | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libtomahawk/album.cpp b/src/libtomahawk/album.cpp index fbf362427..00fe82aa0 100644 --- a/src/libtomahawk/album.cpp +++ b/src/libtomahawk/album.cpp @@ -61,7 +61,7 @@ Album::get( unsigned int id, const QString& name, const Tomahawk::artist_ptr& ar return s_albums.value( id ); } - album_ptr a = album_ptr( new Album( id, name, artist ) ); + album_ptr a = album_ptr( new Album( id, name, artist ), &QObject::deleteLater ); if ( id > 0 ) s_albums.insert( id, a ); diff --git a/src/libtomahawk/artist.cpp b/src/libtomahawk/artist.cpp index cdefc2505..9eea97d13 100644 --- a/src/libtomahawk/artist.cpp +++ b/src/libtomahawk/artist.cpp @@ -61,7 +61,7 @@ Artist::get( unsigned int id, const QString& name ) return s_artists.value( id ); } - artist_ptr a = artist_ptr( new Artist( id, name ) ); + artist_ptr a = artist_ptr( new Artist( id, name ), &QObject::deleteLater ); if ( id > 0 ) s_artists.insert( id, a ); diff --git a/src/libtomahawk/database/databasecollection.cpp b/src/libtomahawk/database/databasecollection.cpp index 9baed7f31..801897a69 100644 --- a/src/libtomahawk/database/databasecollection.cpp +++ b/src/libtomahawk/database/databasecollection.cpp @@ -142,7 +142,7 @@ DatabaseCollection::autoPlaylistCreated( const source_ptr& source, const QVarian static_cast(data[6].toInt()), // dynamic mode data[7].toBool(), //shared data[8].toInt(), //lastmod - data[9].toString() ) ); //GUID + data[9].toString() ), &QObject::deleteLater ); //GUID addAutoPlaylist( p ); } @@ -160,7 +160,7 @@ DatabaseCollection::stationCreated( const source_ptr& source, const QVariantList static_cast(data[6].toInt()), // dynamic mode data[7].toBool(), //shared data[8].toInt(), //lastmod - data[9].toString() ) ); //GUID + data[9].toString() ), &QObject::deleteLater ); //GUID addStation( p ); } diff --git a/src/libtomahawk/database/databasecommand_loadallplaylists.cpp b/src/libtomahawk/database/databasecommand_loadallplaylists.cpp index 90f8cac7c..c40ac4872 100644 --- a/src/libtomahawk/database/databasecommand_loadallplaylists.cpp +++ b/src/libtomahawk/database/databasecommand_loadallplaylists.cpp @@ -71,7 +71,7 @@ DatabaseCommand_LoadAllPlaylists::exec( DatabaseImpl* dbi ) query.value(5).toBool(), //shared query.value(4).toInt(), //lastmod query.value(0).toString() //GUID - ) ); + ), &QObject::deleteLater ); plists.append( p ); } diff --git a/src/libtomahawk/playlist.cpp b/src/libtomahawk/playlist.cpp index f093c24f1..04cc0d6f6 100644 --- a/src/libtomahawk/playlist.cpp +++ b/src/libtomahawk/playlist.cpp @@ -185,7 +185,7 @@ Playlist::create( const source_ptr& author, entries << p; } - playlist_ptr playlist( new Playlist( author, guid, title, info, creator, shared, entries ) ); + playlist_ptr playlist( new Playlist( author, guid, title, info, creator, shared, entries ), &QObject::deleteLater ); // save to DB in the background // Watch for the created() signal if you need to be sure it's written. diff --git a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp index 02c70eccf..602b7b7dd 100644 --- a/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp +++ b/src/libtomahawk/playlist/dynamic/DynamicPlaylist.cpp @@ -152,7 +152,7 @@ DynamicPlaylist::create( const Tomahawk::source_ptr& author, bool autoLoad ) { - dynplaylist_ptr dynplaylist = Tomahawk::dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared, autoLoad ) ); + dynplaylist_ptr dynplaylist = Tomahawk::dynplaylist_ptr( new DynamicPlaylist( author, guid, title, info, creator, type, mode, shared, autoLoad ), &QObject::deleteLater ); DatabaseCommand_CreateDynamicPlaylist* cmd = new DatabaseCommand_CreateDynamicPlaylist( author, dynplaylist, autoLoad ); connect( cmd, SIGNAL(finished()), dynplaylist.data(), SIGNAL(created()) ); diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index 113ad7b8c..a914098b5 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -44,7 +44,7 @@ Query::get( const QString& artist, const QString& track, const QString& album, c if ( qid.isEmpty() ) autoResolve = false; - query_ptr q = query_ptr( new Query( artist, track, album, qid, autoResolve ) ); + query_ptr q = query_ptr( new Query( artist, track, album, qid, autoResolve ), &QObject::deleteLater ); q->setWeakRef( q.toWeakRef() ); if ( autoResolve ) @@ -58,7 +58,7 @@ query_ptr Query::get( const QString& query, const QID& qid ) { - query_ptr q = query_ptr( new Query( query, qid ) ); + query_ptr q = query_ptr( new Query( query, qid ), &QObject::deleteLater ); q->setWeakRef( q.toWeakRef() ); if ( !qid.isEmpty() ) diff --git a/src/libtomahawk/result.cpp b/src/libtomahawk/result.cpp index 33ca4e86d..06dd7a472 100644 --- a/src/libtomahawk/result.cpp +++ b/src/libtomahawk/result.cpp @@ -43,7 +43,7 @@ Result::get( const QString& url ) return s_results.value( url ); } - result_ptr r = result_ptr( new Result( url ) ); + result_ptr r = result_ptr( new Result( url ), &QObject::deleteLater ); s_results.insert( url, r ); return r; From 753e1b3c903d199d390c8f14bf9aa11c810b5d5e Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 20 Mar 2012 11:28:45 -0400 Subject: [PATCH 12/59] aFix crash in dragging artist, don't assume AlbumModel only contains albums as it's hacked to also contain artists. (cherry picked from commit 68d541d2e8dc847c40f6782c65beb4e15ff6aa72) --- src/libtomahawk/playlist/albummodel.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/playlist/albummodel.cpp b/src/libtomahawk/playlist/albummodel.cpp index 08cc3f653..c20ec6b8f 100644 --- a/src/libtomahawk/playlist/albummodel.cpp +++ b/src/libtomahawk/playlist/albummodel.cpp @@ -178,6 +178,7 @@ AlbumModel::mimeData( const QModelIndexList &indexes ) const QByteArray queryData; QDataStream queryStream( &queryData, QIODevice::WriteOnly ); + bool isAlbumData = true; foreach ( const QModelIndex& i, indexes ) { if ( i.column() > 0 ) @@ -185,16 +186,25 @@ AlbumModel::mimeData( const QModelIndexList &indexes ) const QModelIndex idx = index( i.row(), 0, i.parent() ); AlbumItem* item = itemFromIndex( idx ); - if ( item ) + if ( item && !item->album().isNull() ) { const album_ptr& album = item->album(); queryStream << album->artist()->name(); queryStream << album->name(); + + isAlbumData = true; + } + else if ( item && !item->artist().isNull() ) + { + const artist_ptr& artist = item->artist(); + queryStream << artist->name(); + + isAlbumData = false; } } - QMimeData* mimeData = new QMimeData(); - mimeData->setData( "application/tomahawk.metadata.album", queryData ); + QMimeData* mimeData = new QMimeData; + mimeData->setData( isAlbumData ? "application/tomahawk.metadata.album" : "application/tomahawk.metadata.artist", queryData ); return mimeData; } @@ -431,7 +441,7 @@ AlbumModel::findItem( const artist_ptr& artist ) const return item; } } - + return 0; } @@ -447,6 +457,6 @@ AlbumModel::findItem( const album_ptr& album ) const return item; } } - + return 0; } From 68f03dbd136eedb2bed44dbbec4583955e0aaefa Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 27 Mar 2012 10:30:37 -0400 Subject: [PATCH 13/59] autoupdate fixes: init on creation, and every 10 not 100 mins (cherry picked from commit ff04ab3b922fdf44d18751546b371ffa7ed1c941) --- src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp | 2 ++ src/libtomahawk/utils/xspfloader.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp b/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp index c057ceb59..da7e2f75d 100644 --- a/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp +++ b/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp @@ -64,6 +64,8 @@ PlaylistUpdaterInterface::PlaylistUpdaterInterface( const playlist_ptr& pl ) connect( m_timer, SIGNAL( timeout() ), this, SLOT( updateNow() ) ); QTimer::singleShot( 0, this, SLOT( doSave() ) ); + + setAutoUpdate( m_autoUpdate ); } PlaylistUpdaterInterface::PlaylistUpdaterInterface( const playlist_ptr& pl, int interval, bool autoUpdate ) diff --git a/src/libtomahawk/utils/xspfloader.cpp b/src/libtomahawk/utils/xspfloader.cpp index 29fdbfe67..c5118875d 100644 --- a/src/libtomahawk/utils/xspfloader.cpp +++ b/src/libtomahawk/utils/xspfloader.cpp @@ -262,7 +262,7 @@ XSPFLoader::gotBody() // 10 minute default---for now, no way to change it connect( m_playlist.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistCreated() ) ); - new Tomahawk::XspfUpdater( m_playlist, 6000000, m_autoUpdate, m_url.toString() ); + new Tomahawk::XspfUpdater( m_playlist, 600000, m_autoUpdate, m_url.toString() ); emit ok( m_playlist ); } else{ From eec8b76de092eba093088a5779396f542fa04d19 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Tue, 27 Mar 2012 11:26:33 -0400 Subject: [PATCH 14/59] fix xspf auto-updating (cherry picked from commit c54ca787693cd3a3e0340dfcb08032a09d6059cf) --- src/libtomahawk/playlist/XspfUpdater.cpp | 10 +++------- src/libtomahawk/playlist/XspfUpdater.h | 3 ++- src/libtomahawk/utils/xspfloader.cpp | 7 +++++-- src/libtomahawk/utils/xspfloader.h | 3 ++- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/libtomahawk/playlist/XspfUpdater.cpp b/src/libtomahawk/playlist/XspfUpdater.cpp index a9d794334..2eb1d7a1e 100644 --- a/src/libtomahawk/playlist/XspfUpdater.cpp +++ b/src/libtomahawk/playlist/XspfUpdater.cpp @@ -58,28 +58,24 @@ XspfUpdater::updateNow() XSPFLoader* l = new XSPFLoader( false, false ); l->setAutoResolveTracks( false ); l->load( m_url ); - connect( l, SIGNAL( ok ( Tomahawk::playlist_ptr ) ), this, SLOT( playlistLoaded() ) ); + connect( l, SIGNAL( tracks( QList ) ), this, SLOT( playlistLoaded( QList ) ) ); } void -XspfUpdater::playlistLoaded() +XspfUpdater::playlistLoaded( const QList& newEntries ) { - XSPFLoader* loader = qobject_cast( sender() ); - Q_ASSERT( loader ); - QList< query_ptr > tracks; foreach ( const plentry_ptr ple, playlist()->entries() ) tracks << ple->query(); bool changed = false; - QList< query_ptr > mergedTracks = TomahawkUtils::mergePlaylistChanges( tracks, loader->entries(), changed ); + QList< query_ptr > mergedTracks = TomahawkUtils::mergePlaylistChanges( tracks, newEntries, changed ); if ( !changed ) return; QList el = playlist()->entriesFromQueries( mergedTracks, true ); playlist()->createNewRevision( uuid(), playlist()->currentrevision(), el ); - } void diff --git a/src/libtomahawk/playlist/XspfUpdater.h b/src/libtomahawk/playlist/XspfUpdater.h index c5254d79a..227c9ab4a 100644 --- a/src/libtomahawk/playlist/XspfUpdater.h +++ b/src/libtomahawk/playlist/XspfUpdater.h @@ -37,6 +37,7 @@ public: virtual ~XspfUpdater(); virtual QString type() const { return "xspf"; } + public slots: void updateNow(); @@ -46,7 +47,7 @@ protected: virtual void removeFromSettings(const QString& group) const; private slots: - void playlistLoaded(); + void playlistLoaded( const QList & ); private: QString m_url; diff --git a/src/libtomahawk/utils/xspfloader.cpp b/src/libtomahawk/utils/xspfloader.cpp index c5118875d..9fd0c7369 100644 --- a/src/libtomahawk/utils/xspfloader.cpp +++ b/src/libtomahawk/utils/xspfloader.cpp @@ -60,6 +60,7 @@ XSPFLoader::XSPFLoader( bool autoCreate, bool autoUpdate, QObject *parent ) , m_autoCreate( autoCreate ) , m_autoUpdate( autoUpdate ) , m_autoResolve( true ) + , m_autoDelete( true ) , m_NS("http://xspf.org/ns/0/") { qRegisterMetaType< XSPFErrorCode >("XSPFErrorCode"); @@ -265,12 +266,14 @@ XSPFLoader::gotBody() new Tomahawk::XspfUpdater( m_playlist, 600000, m_autoUpdate, m_url.toString() ); emit ok( m_playlist ); } - else{ + else + { if( !m_entries.isEmpty() ) emit tracks( m_entries ); } - deleteLater(); + if ( m_autoDelete ) + deleteLater(); } diff --git a/src/libtomahawk/utils/xspfloader.h b/src/libtomahawk/utils/xspfloader.h index eee77de96..e4e912618 100644 --- a/src/libtomahawk/utils/xspfloader.h +++ b/src/libtomahawk/utils/xspfloader.h @@ -48,6 +48,7 @@ public: void setOverrideTitle( const QString& newTitle ); void setAutoResolveTracks( bool autoResolve ) { m_autoResolve = autoResolve; } + void setAutoDelete( bool autoDelete ) { m_autoDelete = autoDelete; } static QString errorToString( XSPFErrorCode error ); @@ -69,7 +70,7 @@ private: void reportError(); void gotBody(); - bool m_autoCreate, m_autoUpdate, m_autoResolve; + bool m_autoCreate, m_autoUpdate, m_autoResolve, m_autoDelete; QString m_NS,m_overrideTitle; QList< Tomahawk::query_ptr > m_entries; QString m_title, m_info, m_creator; From 5593c134cdac3a9590ae61854801b04a24a903e7 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Wed, 28 Mar 2012 07:06:02 +0200 Subject: [PATCH 15/59] * Reorder toma.hk parameters to match website order. --- src/libtomahawk/globalactionmanager.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/globalactionmanager.cpp b/src/libtomahawk/globalactionmanager.cpp index 5cc66d6f0..069887438 100644 --- a/src/libtomahawk/globalactionmanager.cpp +++ b/src/libtomahawk/globalactionmanager.cpp @@ -89,12 +89,13 @@ GlobalActionManager::openLinkFromQuery( const query_ptr& query ) const { QString title, artist, album; - if( !query->results().isEmpty() && !query->results().first().isNull() ) + if ( !query->results().isEmpty() && !query->results().first().isNull() ) { title = query->results().first()->track(); artist = query->results().first()->artist().isNull() ? QString() : query->results().first()->artist()->name(); album = query->results().first()->album().isNull() ? QString() : query->results().first()->album()->name(); - } else + } + else { title = query->track(); artist = query->artist(); @@ -110,11 +111,11 @@ GlobalActionManager::openLink( const QString& title, const QString& artist, cons { QUrl link( QString( "%1/open/track/" ).arg( hostname() ) ); - if( !title.isEmpty() ) - link.addQueryItem( "title", title ); - if( !artist.isEmpty() ) + if ( !artist.isEmpty() ) link.addQueryItem( "artist", artist ); - if( !album.isEmpty() ) + if ( !title.isEmpty() ) + link.addQueryItem( "title", title ); + if ( !album.isEmpty() ) link.addQueryItem( "album", album ); return link; From 8e0f44a3746fec57bb84697ecfb51ee837a6e259 Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Wed, 28 Mar 2012 14:38:59 +0200 Subject: [PATCH 16/59] Add XmppInfoPlugin for updating the user tune --- src/accounts/xmpp/CMakeLists.txt | 2 + src/accounts/xmpp/XmppInfoPlugin.cpp | 137 ++++++++++++++++++ src/accounts/xmpp/XmppInfoPlugin.h | 68 +++++++++ .../xmpp/googlewrapper/CMakeLists.txt | 2 + src/accounts/xmpp/sip/xmppsip.cpp | 17 +++ src/accounts/xmpp/sip/xmppsip.h | 11 +- src/accounts/xmpp/xmppaccount.cpp | 11 ++ src/accounts/xmpp/xmppaccount.h | 4 +- src/libtomahawk/audio/audioengine.cpp | 28 ++-- 9 files changed, 268 insertions(+), 12 deletions(-) create mode 100644 src/accounts/xmpp/XmppInfoPlugin.cpp create mode 100644 src/accounts/xmpp/XmppInfoPlugin.h diff --git a/src/accounts/xmpp/CMakeLists.txt b/src/accounts/xmpp/CMakeLists.txt index aaa6ce0ce..03313b8df 100644 --- a/src/accounts/xmpp/CMakeLists.txt +++ b/src/accounts/xmpp/CMakeLists.txt @@ -14,6 +14,7 @@ set( xmppAccountSources sip/tomahawkxmppmessagefactory.cpp sip/avatarmanager.cpp sip/xmlconsole.cpp + XmppInfoPlugin.cpp ) set( xmppAccountHeaders @@ -22,6 +23,7 @@ set( xmppAccountHeaders sip/xmppsip.h sip/avatarmanager.h sip/xmlconsole.h + XmppInfoPlugin.h ) set( xmppAccountUI diff --git a/src/accounts/xmpp/XmppInfoPlugin.cpp b/src/accounts/xmpp/XmppInfoPlugin.cpp new file mode 100644 index 000000000..6cfd7cc0f --- /dev/null +++ b/src/accounts/xmpp/XmppInfoPlugin.cpp @@ -0,0 +1,137 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012, Dominik Schmidt + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + + +#include "XmppInfoPlugin.h" + +#include "globalactionmanager.h" +#include "sip/xmppsip.h" +#include "utils/logger.h" + +#include +#include +#include + +#include + +// remove now playing status after PAUSE_TIMEOUT seconds +static const int PAUSE_TIMEOUT = 60; + +Tomahawk::InfoSystem::XmppInfoPlugin::XmppInfoPlugin(XmppSipPlugin* sipPlugin) + : m_sipPlugin( sipPlugin ) + , m_pubSubManager( 0 ) + , m_pauseTimer( this ) +{ + Q_ASSERT( sipPlugin->m_client ); + + m_supportedPushTypes << InfoNowPlaying << InfoNowPaused << InfoNowResumed << InfoNowStopped; + + m_pubSubManager = new Jreen::PubSub::Manager( sipPlugin->m_client ); + m_pubSubManager->addEntityType< Jreen::Tune >(); + + m_pauseTimer.setSingleShot( true ); + connect( &m_pauseTimer, SIGNAL( timeout() ), + this, SLOT( audioStopped() ) ); +} + + +Tomahawk::InfoSystem::XmppInfoPlugin::~XmppInfoPlugin() +{ + delete m_pubSubManager; +} + + +void +Tomahawk::InfoSystem::XmppInfoPlugin::pushInfo(QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input) +{ + tDebug() << Q_FUNC_INFO; + + switch ( type ) + { + case InfoNowPlaying: + case InfoNowResumed: + m_pauseTimer.stop(); + if ( input.canConvert< Tomahawk::InfoSystem::InfoStringHash >() ) + audioStarted( input.value< Tomahawk::InfoSystem::InfoStringHash >() ); + break; + case InfoNowPaused: + m_pauseTimer.start( PAUSE_TIMEOUT * 1000 ); + audioPaused(); + break; + case InfoNowStopped: + m_pauseTimer.stop(); + audioStopped(); + break; + + default: + return; + } +} + + +void +Tomahawk::InfoSystem::XmppInfoPlugin::audioStarted(const Tomahawk::InfoSystem::InfoStringHash& info) +{ + tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full() << info; + + Jreen::Tune::Ptr tune( new Jreen::Tune() ); + + tune->setTitle( info.value( "title" ) ); + tune->setArtist( info.value( "artist" ) ); + tune->setLength( info.value("duration").toInt() ); + tune->setTrack( info.value("albumpos") ); + tune->setUri( GlobalActionManager::instance()->openLink( info.value( "title" ), info.value( "artist" ), info.value( "album" ) ) ); + + //TODO: provide a rating once available in Tomahawk + tune->setRating( 10 ); + + //TODO: it would be nice to set Spotify, Dilandau etc here, but not the jabber ids of friends + tune->setSource( "Tomahawk" ); + + m_pubSubManager->publishItems( QList() << tune, Jreen::JID() ); +} + +void +Tomahawk::InfoSystem::XmppInfoPlugin::audioPaused() +{ + tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full(); +} + +void +Tomahawk::InfoSystem::XmppInfoPlugin::audioStopped() +{ + tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full(); + + Jreen::Tune::Ptr tune( new Jreen::Tune() ); + m_pubSubManager->publishItems(QList() << tune, Jreen::JID()); +} + + +void +Tomahawk::InfoSystem::XmppInfoPlugin::getInfo(Tomahawk::InfoSystem::InfoRequestData requestData) +{ + Q_UNUSED( requestData ); +} + + +void +Tomahawk::InfoSystem::XmppInfoPlugin::notInCacheSlot(const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData) +{ + Q_UNUSED( criteria ); + Q_UNUSED( requestData ); +} diff --git a/src/accounts/xmpp/XmppInfoPlugin.h b/src/accounts/xmpp/XmppInfoPlugin.h new file mode 100644 index 000000000..f7d298de4 --- /dev/null +++ b/src/accounts/xmpp/XmppInfoPlugin.h @@ -0,0 +1,68 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2012, Dominik Schmidt + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#ifndef XMPPINFOPLUGIN_H +#define XMPPINFOPLUGIN_H + +#include "infosystem/infosystem.h" + +#include + +namespace Jreen { + namespace PubSub { + class Manager; + } +} + +class XmppSipPlugin; + +namespace Tomahawk { + + namespace InfoSystem { + + class XmppInfoPlugin : public InfoPlugin + { + Q_OBJECT + + public: + XmppInfoPlugin(XmppSipPlugin* parent); + virtual ~XmppInfoPlugin(); + + public slots: + void notInCacheSlot( const Tomahawk::InfoSystem::InfoStringHash criteria, Tomahawk::InfoSystem::InfoRequestData requestData ); + + protected slots: + void pushInfo( QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input ); + void getInfo( Tomahawk::InfoSystem::InfoRequestData requestData ); + + private slots: + void audioStarted( const Tomahawk::InfoSystem::InfoStringHash& info ); + void audioStopped(); + void audioPaused(); + + private: + XmppSipPlugin* m_sipPlugin; + Jreen::PubSub::Manager* m_pubSubManager; + QTimer m_pauseTimer; + }; + + } + +} + +#endif // XMPPINFOPLUGIN_H diff --git a/src/accounts/xmpp/googlewrapper/CMakeLists.txt b/src/accounts/xmpp/googlewrapper/CMakeLists.txt index b7631e19b..a6c1a7ce3 100644 --- a/src/accounts/xmpp/googlewrapper/CMakeLists.txt +++ b/src/accounts/xmpp/googlewrapper/CMakeLists.txt @@ -7,6 +7,7 @@ set( googleHeaders ../sip/xmppsip.h ../sip/avatarmanager.h ../sip/xmlconsole.h + ../XmppInfoPlugin.h googlewrapper.h ) set( googleSources @@ -17,6 +18,7 @@ set( googleSources ../sip/tomahawkxmppmessagefactory.cpp ../sip/avatarmanager.cpp ../sip/xmlconsole.cpp + ../XmppInfoPlugin.cpp googlewrapper.cpp ) diff --git a/src/accounts/xmpp/sip/xmppsip.cpp b/src/accounts/xmpp/sip/xmppsip.cpp index 1e877c40e..6ff55b7c7 100644 --- a/src/accounts/xmpp/sip/xmppsip.cpp +++ b/src/accounts/xmpp/sip/xmppsip.cpp @@ -56,6 +56,7 @@ #include #include "utils/logger.h" +#include "XmppInfoPlugin.h" using namespace Tomahawk; using namespace Accounts; @@ -85,6 +86,7 @@ JreenMessageHandler(QtMsgType type, const char *msg) XmppSipPlugin::XmppSipPlugin( Account *account ) : SipPlugin( account ) + , m_infoPlugin( 0 ) , m_state( Account::Disconnected ) #ifndef ENABLE_HEADLESS , m_menu( 0 ) @@ -163,6 +165,7 @@ XmppSipPlugin::XmppSipPlugin( Account *account ) XmppSipPlugin::~XmppSipPlugin() { + delete m_infoPlugin; delete m_avatarManager; delete m_roster; #ifndef ENABLE_HEADLESS @@ -172,6 +175,13 @@ XmppSipPlugin::~XmppSipPlugin() } +InfoSystem::InfoPlugin* +XmppSipPlugin::infoPlugin() +{ + return m_infoPlugin; +} + + #ifndef ENABLE_HEADLESS QMenu* XmppSipPlugin::menu() @@ -255,6 +265,13 @@ XmppSipPlugin::onConnect() // load roster m_roster->load(); + // load XmppInfoPlugin + if( !m_infoPlugin ) + { + m_infoPlugin = new Tomahawk::InfoSystem::XmppInfoPlugin( this ); + InfoSystem::InfoSystem::instance()->addInfoPlugin( m_infoPlugin ); + } + //FIXME: this implementation is totally broken atm, so it's disabled to avoid harm :P // join MUC with bare jid as nickname //TODO: make the room a list of rooms and make that configurable diff --git a/src/accounts/xmpp/sip/xmppsip.h b/src/accounts/xmpp/sip/xmppsip.h index 722d04f53..33b7b61dd 100644 --- a/src/accounts/xmpp/sip/xmppsip.h +++ b/src/accounts/xmpp/sip/xmppsip.h @@ -52,10 +52,14 @@ #include "accounts/accountdllmacro.h" +#include "XmppInfoPlugin.h" + class ACCOUNTDLLEXPORT XmppSipPlugin : public SipPlugin { Q_OBJECT +friend class Tomahawk::InfoSystem::XmppInfoPlugin; + public: XmppSipPlugin( Tomahawk::Accounts::Account* account ); virtual ~XmppSipPlugin(); @@ -63,6 +67,8 @@ public: //FIXME: Make this more correct virtual bool isValid() const { return true; } + Tomahawk::InfoSystem::InfoPlugin* infoPlugin(); + #ifndef ENABLE_HEADLESS virtual QMenu* menu(); #endif @@ -123,10 +129,11 @@ private: QString m_currentPassword; QString m_currentServer; int m_currentPort; - Tomahawk::Accounts::Account::ConnectionState m_state; - QString m_currentResource; + Tomahawk::InfoSystem::InfoPlugin* m_infoPlugin; + Tomahawk::Accounts::Account::ConnectionState m_state; + // sort out Jreen::Client *m_client; diff --git a/src/accounts/xmpp/xmppaccount.cpp b/src/accounts/xmpp/xmppaccount.cpp index bb3cbcf2c..3ea09aeab 100644 --- a/src/accounts/xmpp/xmppaccount.cpp +++ b/src/accounts/xmpp/xmppaccount.cpp @@ -22,6 +22,7 @@ #include "xmppconfigwidget.h" #include "sip/SipPlugin.h" #include "ui_xmppconfigwidget.h" +#include "XmppInfoPlugin.h" #include @@ -90,6 +91,16 @@ XmppAccount::saveConfig() } +InfoSystem::InfoPlugin* +XmppAccount::infoPlugin() +{ + if( !m_xmppSipPlugin.isNull() ) + m_xmppSipPlugin.data()->infoPlugin(); + + return 0; +} + + SipPlugin* XmppAccount::sipPlugin() { diff --git a/src/accounts/xmpp/xmppaccount.h b/src/accounts/xmpp/xmppaccount.h index ad45d3414..8529d9e11 100644 --- a/src/accounts/xmpp/xmppaccount.h +++ b/src/accounts/xmpp/xmppaccount.h @@ -69,7 +69,8 @@ public: void deauthenticate(); bool isAuthenticated() const; - Tomahawk::InfoSystem::InfoPlugin* infoPlugin() { return 0; } + Tomahawk::InfoSystem::InfoPlugin* infoPlugin(); + SipPlugin* sipPlugin(); QWidget* configurationWidget() { return m_configWidget.data(); } @@ -81,6 +82,7 @@ public: protected: QWeakPointer< QWidget > m_configWidget; // so the google wrapper can change the config dialog a bit QWeakPointer< XmppSipPlugin > m_xmppSipPlugin; + QWeakPointer< Tomahawk::InfoSystem::XmppInfoPlugin > m_xmppInfoPlugin; }; }; diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 97ef2902b..6ea43c6e8 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -78,7 +78,7 @@ AudioEngine::AudioEngine() connect( m_audioOutput, SIGNAL( volumeChanged( qreal ) ), SLOT( onVolumeChanged( qreal ) ) ); connect( this, SIGNAL( sendWaitingNotification() ), SLOT( sendWaitingNotificationSlot() ), Qt::QueuedConnection ); - + onVolumeChanged( m_audioOutput->volume() ); #ifndef Q_WS_X11 @@ -134,14 +134,22 @@ AudioEngine::play() { m_mediaObject->play(); emit resumed(); - Tomahawk::InfoSystem::InfoStringHash trackInfo; - trackInfo["title"] = m_currentTrack->track(); - trackInfo["artist"] = m_currentTrack->artist()->name(); - trackInfo["album"] = m_currentTrack->album()->name(); - Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( - s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowResumed, - QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ) ); + if ( TomahawkSettings::instance()->privateListeningMode() != TomahawkSettings::FullyPrivate ) + { + Tomahawk::InfoSystem::InfoStringHash trackInfo; + + trackInfo["title"] = m_currentTrack->track(); + trackInfo["artist"] = m_currentTrack->artist()->name(); + trackInfo["album"] = m_currentTrack->album()->name(); + trackInfo["albumpos"] = QString::number( m_currentTrack->albumpos() ); + trackInfo["duration"] = QString::number( m_currentTrack->duration() ); + + + Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( + s_aeInfoIdentifier, Tomahawk::InfoSystem::InfoNowResumed, + QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ) ); + } } else next(); @@ -319,7 +327,7 @@ AudioEngine::sendWaitingNotificationSlot() const //since it's async, after this is triggered our result could come in, so don't show the popup in that case if ( !m_playlist.isNull() && m_playlist->hasNextItem() ) return; - + QVariantMap retryInfo; retryInfo["message"] = QString( "The current track could not be resolved. Tomahawk will pick back up with the next resolvable track from this source." ); Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( @@ -460,6 +468,8 @@ AudioEngine::loadTrack( const Tomahawk::result_ptr& result ) trackInfo["title"] = m_currentTrack->track(); trackInfo["artist"] = m_currentTrack->artist()->name(); trackInfo["album"] = m_currentTrack->album()->name(); + trackInfo["duration"] = QString::number( m_currentTrack->duration() ); + trackInfo["albumpos"] = QString::number( m_currentTrack->albumpos() ); Tomahawk::InfoSystem::InfoSystem::instance()->pushInfo( s_aeInfoIdentifier, From bac82c0abfa937a606d97b716b213c653dcb70a6 Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Wed, 28 Mar 2012 15:03:40 +0200 Subject: [PATCH 17/59] Add missing return --- src/accounts/xmpp/xmppaccount.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/accounts/xmpp/xmppaccount.cpp b/src/accounts/xmpp/xmppaccount.cpp index 3ea09aeab..4d79fb7fa 100644 --- a/src/accounts/xmpp/xmppaccount.cpp +++ b/src/accounts/xmpp/xmppaccount.cpp @@ -95,7 +95,7 @@ InfoSystem::InfoPlugin* XmppAccount::infoPlugin() { if( !m_xmppSipPlugin.isNull() ) - m_xmppSipPlugin.data()->infoPlugin(); + return m_xmppSipPlugin.data()->infoPlugin(); return 0; } From 301c1d21fea4fc06ac70fd4727a5cadb9a8751da Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Wed, 28 Mar 2012 15:34:51 +0200 Subject: [PATCH 18/59] Make publishing the user tune optional --- src/accounts/xmpp/XmppInfoPlugin.cpp | 8 +++++++- src/accounts/xmpp/xmppconfigwidget.cpp | 2 ++ src/accounts/xmpp/xmppconfigwidget.ui | 12 +++++++++++- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/accounts/xmpp/XmppInfoPlugin.cpp b/src/accounts/xmpp/XmppInfoPlugin.cpp index 6cfd7cc0f..27166c829 100644 --- a/src/accounts/xmpp/XmppInfoPlugin.cpp +++ b/src/accounts/xmpp/XmppInfoPlugin.cpp @@ -59,7 +59,13 @@ Tomahawk::InfoSystem::XmppInfoPlugin::~XmppInfoPlugin() void Tomahawk::InfoSystem::XmppInfoPlugin::pushInfo(QString caller, Tomahawk::InfoSystem::InfoType type, QVariant input) { - tDebug() << Q_FUNC_INFO; + tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full(); + + if( m_sipPlugin->m_account->configuration().value("publishtracks").toBool() == false ) + { + tDebug() << Q_FUNC_INFO << m_sipPlugin->m_client->jid().full() << "Not publishing now playing info (disabled in account config)"; + return; + } switch ( type ) { diff --git a/src/accounts/xmpp/xmppconfigwidget.cpp b/src/accounts/xmpp/xmppconfigwidget.cpp index 70e58d01d..b93559d61 100644 --- a/src/accounts/xmpp/xmppconfigwidget.cpp +++ b/src/accounts/xmpp/xmppconfigwidget.cpp @@ -43,6 +43,7 @@ XmppConfigWidget::XmppConfigWidget( XmppAccount* account, QWidget *parent ) : m_ui->xmppPassword->setText( account->credentials().contains( "password" ) ? account->credentials()[ "password" ].toString() : QString() ); m_ui->xmppServer->setText( account->configuration().contains( "server" ) ? account->configuration()[ "server" ].toString() : QString() ); m_ui->xmppPort->setValue( account->configuration().contains( "port" ) ? account->configuration()[ "port" ].toInt() : 5222 ); + m_ui->xmppPublishTracksCheckbox->setChecked( account->configuration().contains( "publishtracks" ) ? account->configuration()[ "publishtracks" ].toBool() : true); m_ui->jidExistsLabel->hide(); connect( m_ui->xmppUsername, SIGNAL( textChanged( QString ) ), SLOT( onCheckJidExists( QString ) ) ); @@ -64,6 +65,7 @@ XmppConfigWidget::saveConfig() QVariantHash configuration = m_account->configuration(); configuration[ "server" ] = m_ui->xmppServer->text().trimmed(); configuration[ "port" ] = m_ui->xmppPort->text().trimmed(); + configuration[ "publishtracks"] = m_ui->xmppPublishTracksCheckbox->checkState() == Qt::Checked ? true : false; m_account->setAccountFriendlyName( m_ui->xmppUsername->text() ); m_account->setCredentials( credentials ); diff --git a/src/accounts/xmpp/xmppconfigwidget.ui b/src/accounts/xmpp/xmppconfigwidget.ui index 99876aa6a..07a585604 100644 --- a/src/accounts/xmpp/xmppconfigwidget.ui +++ b/src/accounts/xmpp/xmppconfigwidget.ui @@ -209,7 +209,7 @@ Advanced Xmpp Settings - + @@ -293,6 +293,16 @@ + + + + Lots of servers don't support this (e.g. GTalk, jabber.org) + + + Publish currently playing track + + + From 00dade54605ba7056bf66de5c59cdc093a8e6b45 Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Wed, 28 Mar 2012 15:44:03 +0200 Subject: [PATCH 19/59] YES, I GOT IT. I'M SURE. --- src/accounts/xmpp/xmppconfigwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/accounts/xmpp/xmppconfigwidget.cpp b/src/accounts/xmpp/xmppconfigwidget.cpp index b93559d61..bc7c138da 100644 --- a/src/accounts/xmpp/xmppconfigwidget.cpp +++ b/src/accounts/xmpp/xmppconfigwidget.cpp @@ -65,7 +65,7 @@ XmppConfigWidget::saveConfig() QVariantHash configuration = m_account->configuration(); configuration[ "server" ] = m_ui->xmppServer->text().trimmed(); configuration[ "port" ] = m_ui->xmppPort->text().trimmed(); - configuration[ "publishtracks"] = m_ui->xmppPublishTracksCheckbox->checkState() == Qt::Checked ? true : false; + configuration[ "publishtracks"] = m_ui->xmppPublishTracksCheckbox->checkState() == Qt::Checked; m_account->setAccountFriendlyName( m_ui->xmppUsername->text() ); m_account->setCredentials( credentials ); From fff8fbfe802fec6af32de251a615b95e9c4b9ef2 Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Wed, 28 Mar 2012 17:23:27 +0200 Subject: [PATCH 20/59] win: fix qca2 usage/grooveshark --- src/libtomahawk/playlist.h | 2 +- src/libtomahawk/viewmanager.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libtomahawk/playlist.h b/src/libtomahawk/playlist.h index 5cc6c70cf..4ba6faa71 100644 --- a/src/libtomahawk/playlist.h +++ b/src/libtomahawk/playlist.h @@ -182,7 +182,7 @@ public: QList entriesFromQueries( const QList& queries, bool clearFirst = false ); - void setUpdater( PlaylistUpdaterInterface* interface ) { m_updater = interface; } + void setUpdater( PlaylistUpdaterInterface* pluinterface ) { m_updater = pluinterface; } PlaylistUpdaterInterface* updater() const { return m_updater; } Tomahawk::playlistinterface_ptr playlistInterface(); diff --git a/src/libtomahawk/viewmanager.h b/src/libtomahawk/viewmanager.h index 4dc2148b8..1320fd1bb 100644 --- a/src/libtomahawk/viewmanager.h +++ b/src/libtomahawk/viewmanager.h @@ -84,7 +84,7 @@ public: Tomahawk::playlistinterface_ptr currentPlaylistInterface() const; Tomahawk::ViewPage* currentPage() const; - Tomahawk::ViewPage* pageForInterface( Tomahawk::playlistinterface_ptr interface ) const; + Tomahawk::ViewPage* pageForInterface( Tomahawk::playlistinterface_ptr plInterface ) const; Tomahawk::ViewPage* show( Tomahawk::ViewPage* page ); @@ -185,9 +185,9 @@ private: void saveCurrentPlaylistSettings(); void loadCurrentPlaylistSettings(); - Tomahawk::playlist_ptr playlistForInterface( Tomahawk::playlistinterface_ptr interface ) const; - Tomahawk::dynplaylist_ptr dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr interface ) const; - Tomahawk::collection_ptr collectionForInterface( Tomahawk::playlistinterface_ptr interface ) const; + Tomahawk::playlist_ptr playlistForInterface( Tomahawk::playlistinterface_ptr plInterface ) const; + Tomahawk::dynplaylist_ptr dynamicPlaylistForInterface( Tomahawk::playlistinterface_ptr plInterface ) const; + Tomahawk::collection_ptr collectionForInterface( Tomahawk::playlistinterface_ptr plInterface ) const; QWidget* m_widget; InfoBar* m_infobar; From eebf5dfe0703f92e1da896634d5a350cb1555b90 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 28 Mar 2012 14:17:20 -0400 Subject: [PATCH 21/59] Dynamically enable/disable the web API, and change the wording for the option to make it more enticing --- src/stackedsettingsdialog.ui | 2 +- src/tomahawkapp.cpp | 48 ++++++++++++++++++++++++++++++------ src/tomahawkapp.h | 7 +++--- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/stackedsettingsdialog.ui b/src/stackedsettingsdialog.ui index 6d08a1a2b..7b241b440 100644 --- a/src/stackedsettingsdialog.ui +++ b/src/stackedsettingsdialog.ui @@ -393,7 +393,7 @@ Qt::RightToLeft - Playdar HTTP API + Allow web browsers to detect Tomahawk true diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index 09576f369..e7f3869b1 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -268,6 +268,7 @@ TomahawkApp::init() { initHTTP(); } + connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( initHTTP() ) ); #ifndef ENABLE_HEADLESS if ( !s->hasScannerPaths() ) @@ -309,6 +310,11 @@ TomahawkApp::~TomahawkApp() { tLog() << "Shutting down Tomahawk..."; + if ( !m_session.isNull() ) + delete m_session.data(); + if ( !m_connector.isNull() ) + delete m_connector.data(); + Pipeline::instance()->stop(); if ( !m_servent.isNull() ) @@ -470,15 +476,43 @@ TomahawkApp::initDatabase() void TomahawkApp::initHTTP() { - m_session.setPort( 60210 ); //TODO config - m_session.setListenInterface( QHostAddress::LocalHost ); - m_session.setConnector( &m_connector ); + if ( !TomahawkSettings::instance()->httpEnabled() ) + { + tLog() << "Stopping HTTPd, not enabled"; + if ( !m_session.isNull() ) + delete m_session.data(); + if ( !m_connector.isNull() ) + delete m_connector.data(); + return; + } - Api_v1* api = new Api_v1( &m_session ); - m_session.setStaticContentService( api ); + if ( m_session ) + { + tLog() << "HTTPd session already exists, returning"; + return; + } + + m_session = QWeakPointer< QxtHttpSessionManager >( new QxtHttpSessionManager() ); + m_connector = QWeakPointer< QxtHttpServerConnector >( new QxtHttpServerConnector ); + if ( m_session.isNull() || m_connector.isNull() ) + { + if ( !m_session.isNull() ) + delete m_session.data(); + if ( !m_connector.isNull() ) + delete m_connector.data(); + tLog() << "Failed to start HTTPd, could not create object"; + return; + } + + m_session.data()->setPort( 60210 ); //TODO config + m_session.data()->setListenInterface( QHostAddress::LocalHost ); + m_session.data()->setConnector( m_connector.data() ); - tLog() << "Starting HTTPd on" << m_session.listenInterface().toString() << m_session.port(); - m_session.start(); + Api_v1* api = new Api_v1( m_session.data() ); + m_session.data()->setStaticContentService( api ); + + tLog() << "Starting HTTPd on" << m_session.data()->listenInterface().toString() << m_session.data()->port(); + m_session.data()->start(); } diff --git a/src/tomahawkapp.h b/src/tomahawkapp.h index a8d2a0c45..ade0e72d8 100644 --- a/src/tomahawkapp.h +++ b/src/tomahawkapp.h @@ -108,6 +108,7 @@ public slots: private slots: void initServent(); void initSIP(); + void initHTTP(); void spotifyApiCheckFinished(); @@ -121,8 +122,6 @@ private: void initLocalCollection(); void initPipeline(); - void initHTTP(); - QWeakPointer m_database; QWeakPointer m_scanManager; QWeakPointer m_audioEngine; @@ -143,8 +142,8 @@ private: bool m_headless, m_loaded; - QxtHttpServerConnector m_connector; - QxtHttpSessionManager m_session; + QWeakPointer< QxtHttpServerConnector > m_connector; + QWeakPointer< QxtHttpSessionManager > m_session; }; Q_DECLARE_METATYPE( QPersistentModelIndex ) From 38ea9653a059d3c54816f2378b76a63e8412c470 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 28 Mar 2012 14:20:29 -0400 Subject: [PATCH 22/59] Change wording --- src/stackedsettingsdialog.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stackedsettingsdialog.ui b/src/stackedsettingsdialog.ui index 7b241b440..63e3674a1 100644 --- a/src/stackedsettingsdialog.ui +++ b/src/stackedsettingsdialog.ui @@ -393,7 +393,7 @@ Qt::RightToLeft - Allow web browsers to detect Tomahawk + Allow web browsers to interact with Tomahawk true From 0d8a8038b72403d205dd74de6c217bf7a46cdb31 Mon Sep 17 00:00:00 2001 From: Kevin Funk Date: Wed, 28 Mar 2012 23:16:44 +0200 Subject: [PATCH 23/59] Compile fix for ARM Not sure why this is needed, but without this the tomahawk binary fails to link. Error: `.LTHUNK9' referenced in section `.text._ZN21AccountFactoryWrapperD1Ev[AccountFactoryWrapper::~AccountFactoryWrapper()]' of CMakeFiles/tomahawk.dir/tomahawk_automoc.cpp.o: defined in discarded section `.text._ZN21AccountFactoryWrapperD2Ev[_ZN21AccountFactoryWrapperD5Ev]' of CMakeFiles/tomahawk.dir/tomahawk_automoc.cpp.o collect2: ld returned 1 exit status make[2]: *** [tomahawk] Error 1 --- src/AccountFactoryWrapper.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/AccountFactoryWrapper.h b/src/AccountFactoryWrapper.h index d96d89486..00e31e672 100644 --- a/src/AccountFactoryWrapper.h +++ b/src/AccountFactoryWrapper.h @@ -42,6 +42,7 @@ public: }; explicit AccountFactoryWrapper( Tomahawk::Accounts::AccountFactory* factory, QWidget* parent = 0 ); + virtual ~AccountFactoryWrapper() {} public slots: void openAccountConfig( Tomahawk::Accounts::Account* ); From fc95cee6ced0ee7cf7fb1b57f1e912baecd0f2b3 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 28 Mar 2012 14:17:20 -0400 Subject: [PATCH 24/59] Dynamically enable/disable the web API, and change the wording for the option to make it more enticing --- src/stackedsettingsdialog.ui | 2 +- src/tomahawkapp.cpp | 48 ++++++++++++++++++++++++++++++------ src/tomahawkapp.h | 7 +++--- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/stackedsettingsdialog.ui b/src/stackedsettingsdialog.ui index 704c60c40..3ee15c7fe 100644 --- a/src/stackedsettingsdialog.ui +++ b/src/stackedsettingsdialog.ui @@ -644,7 +644,7 @@ Qt::RightToLeft - Playdar HTTP API + Allow web browsers to detect Tomahawk true diff --git a/src/tomahawkapp.cpp b/src/tomahawkapp.cpp index d15440343..22bcad592 100644 --- a/src/tomahawkapp.cpp +++ b/src/tomahawkapp.cpp @@ -255,6 +255,7 @@ TomahawkApp::init() { initHTTP(); } + connect( TomahawkSettings::instance(), SIGNAL( changed() ), SLOT( initHTTP() ) ); #ifndef ENABLE_HEADLESS if ( !s->hasScannerPaths() ) @@ -296,6 +297,11 @@ TomahawkApp::~TomahawkApp() { tLog() << "Shutting down Tomahawk..."; + if ( !m_session.isNull() ) + delete m_session.data(); + if ( !m_connector.isNull() ) + delete m_connector.data(); + Pipeline::instance()->stop(); if ( !m_servent.isNull() ) @@ -458,15 +464,43 @@ TomahawkApp::initDatabase() void TomahawkApp::initHTTP() { - m_session.setPort( 60210 ); //TODO config - m_session.setListenInterface( QHostAddress::LocalHost ); - m_session.setConnector( &m_connector ); + if ( !TomahawkSettings::instance()->httpEnabled() ) + { + tLog() << "Stopping HTTPd, not enabled"; + if ( !m_session.isNull() ) + delete m_session.data(); + if ( !m_connector.isNull() ) + delete m_connector.data(); + return; + } - Api_v1* api = new Api_v1( &m_session ); - m_session.setStaticContentService( api ); + if ( m_session ) + { + tLog() << "HTTPd session already exists, returning"; + return; + } + + m_session = QWeakPointer< QxtHttpSessionManager >( new QxtHttpSessionManager() ); + m_connector = QWeakPointer< QxtHttpServerConnector >( new QxtHttpServerConnector ); + if ( m_session.isNull() || m_connector.isNull() ) + { + if ( !m_session.isNull() ) + delete m_session.data(); + if ( !m_connector.isNull() ) + delete m_connector.data(); + tLog() << "Failed to start HTTPd, could not create object"; + return; + } + + m_session.data()->setPort( 60210 ); //TODO config + m_session.data()->setListenInterface( QHostAddress::LocalHost ); + m_session.data()->setConnector( m_connector.data() ); - tLog() << "Starting HTTPd on" << m_session.listenInterface().toString() << m_session.port(); - m_session.start(); + Api_v1* api = new Api_v1( m_session.data() ); + m_session.data()->setStaticContentService( api ); + + tLog() << "Starting HTTPd on" << m_session.data()->listenInterface().toString() << m_session.data()->port(); + m_session.data()->start(); } diff --git a/src/tomahawkapp.h b/src/tomahawkapp.h index e97e359b8..f78a05b30 100644 --- a/src/tomahawkapp.h +++ b/src/tomahawkapp.h @@ -101,6 +101,7 @@ public slots: private slots: void initServent(); void initSIP(); + void initHTTP(); void spotifyApiCheckFinished(); @@ -114,8 +115,6 @@ private: void initLocalCollection(); void initPipeline(); - void initHTTP(); - QWeakPointer m_database; QWeakPointer m_scanManager; QWeakPointer m_audioEngine; @@ -135,8 +134,8 @@ private: bool m_headless, m_loaded; - QxtHttpServerConnector m_connector; - QxtHttpSessionManager m_session; + QWeakPointer< QxtHttpServerConnector > m_connector; + QWeakPointer< QxtHttpSessionManager > m_session; }; Q_DECLARE_METATYPE( QPersistentModelIndex ) From 43c4daa4e367e0c015380a86247678548a348766 Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 28 Mar 2012 14:20:29 -0400 Subject: [PATCH 25/59] Change wording --- src/stackedsettingsdialog.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stackedsettingsdialog.ui b/src/stackedsettingsdialog.ui index 3ee15c7fe..355a6b4a3 100644 --- a/src/stackedsettingsdialog.ui +++ b/src/stackedsettingsdialog.ui @@ -644,7 +644,7 @@ Qt::RightToLeft - Allow web browsers to detect Tomahawk + Allow web browsers to interact with Tomahawk true From 47774c38947689b1b487884ee5db2b8cfd5aa208 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 29 Mar 2012 18:04:57 +0200 Subject: [PATCH 26/59] * Add polish to our released languages. All translations could do with an update now. --- lang/tomahawk_i18n.qrc | 1 + 1 file changed, 1 insertion(+) diff --git a/lang/tomahawk_i18n.qrc b/lang/tomahawk_i18n.qrc index 7dbc698e6..5bb43cef2 100644 --- a/lang/tomahawk_i18n.qrc +++ b/lang/tomahawk_i18n.qrc @@ -4,6 +4,7 @@ tomahawk_de.qm tomahawk_sv.qm tomahawk_es.qm +tomahawk_pl.qm tomahawk_pt_BR.qm From a4421df9e9fa9b0d0d4d48f3af61c310f1f27769 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Thu, 29 Mar 2012 19:02:06 +0200 Subject: [PATCH 27/59] * Potential fix for rotzbouw's weird crash. --- src/libtomahawk/playlist/playlistitemdelegate.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/playlistitemdelegate.cpp b/src/libtomahawk/playlist/playlistitemdelegate.cpp index 80e4220c7..fe18db54d 100644 --- a/src/libtomahawk/playlist/playlistitemdelegate.cpp +++ b/src/libtomahawk/playlist/playlistitemdelegate.cpp @@ -203,7 +203,10 @@ PlaylistItemDelegate::paintShort( QPainter* painter, const QStyleOptionViewItem& QRect ir = r.adjusted( 4, 0, -option.rect.width() + option.rect.height() - 8 + r.left(), 0 ); if ( useAvatars ) - pixmap = source->avatar( Source::FancyStyle, ir.size() ); + { + if ( !source.isNull() ) + pixmap = source->avatar( Source::FancyStyle, ir.size() ); + } else pixmap = item->query()->cover( ir.size(), false ); From 04864c7d796f4197f49308676f95d8d47c63da8e Mon Sep 17 00:00:00 2001 From: Jeff Mitchell Date: Wed, 14 Mar 2012 16:14:25 -0400 Subject: [PATCH 28/59] Set scanning threads idle priority (cherry picked from commit 5a57e285ec2a25fe71877a7828b87bb65a31cf3e) --- src/musicscanner.cpp | 1 + src/scanmanager.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/musicscanner.cpp b/src/musicscanner.cpp index 14f619aeb..9f064b4ed 100644 --- a/src/musicscanner.cpp +++ b/src/musicscanner.cpp @@ -173,6 +173,7 @@ MusicScanner::scan() SLOT( commitBatch( QVariantList, QVariantList ) ), Qt::DirectConnection ); m_dirListerThreadController = new QThread( this ); + m_dirListerThreadController->setPriority( QThread::IdlePriority ); m_dirLister = QWeakPointer< DirLister >( new DirLister( m_dirs ) ); m_dirLister.data()->moveToThread( m_dirListerThreadController ); diff --git a/src/scanmanager.cpp b/src/scanmanager.cpp index 1209f58ce..adad60807 100644 --- a/src/scanmanager.cpp +++ b/src/scanmanager.cpp @@ -195,6 +195,7 @@ ScanManager::runDirScan() { m_scanTimer->stop(); m_musicScannerThreadController = new QThread( this ); + m_musicScannerThreadController->setPriority( QThread::IdlePriority ); m_scanner = QWeakPointer< MusicScanner >( new MusicScanner( paths ) ); m_scanner.data()->moveToThread( m_musicScannerThreadController ); connect( m_scanner.data(), SIGNAL( finished() ), SLOT( scannerFinished() ) ); From deb0eb819c828b538a998e972629d3467ab7b28f Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 17 Mar 2012 01:33:03 +0100 Subject: [PATCH 29/59] * Fetch square covers from Last.fm. (cherry picked from commit d5aed7b6df11634ea6d86691feea94e8a3462a36) --- .../infosystem/infoplugins/generic/lastfmplugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/infosystem/infoplugins/generic/lastfmplugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/lastfmplugin.cpp index df14af143..bf2d0134c 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/lastfmplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/generic/lastfmplugin.cpp @@ -456,7 +456,7 @@ LastFmPlugin::notInCacheSlot( QHash criteria, Tomahawk::InfoSy imgurl.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artistName, "", "+" ) ); imgurl.addEncodedQueryItem( "album", QUrl::toPercentEncoding( albumName, "", "+" ) ); imgurl.addQueryItem( "autocorrect", QString::number( 1 ) ); - imgurl.addQueryItem( "size", "large" ); + imgurl.addQueryItem( "size", "largesquare" ); imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" ); QNetworkRequest req( imgurl ); @@ -475,7 +475,7 @@ LastFmPlugin::notInCacheSlot( QHash criteria, Tomahawk::InfoSy imgurl.addQueryItem( "method", "artist.imageredirect" ); imgurl.addEncodedQueryItem( "artist", QUrl::toPercentEncoding( artistName, "", "+" ) ); imgurl.addQueryItem( "autocorrect", QString::number( 1 ) ); - imgurl.addQueryItem( "size", "large" ); + imgurl.addQueryItem( "size", "largesquare" ); imgurl.addQueryItem( "api_key", "7a90f6672a04b809ee309af169f34b8b" ); QNetworkRequest req( imgurl ); From e5bdd2242fa670cac9646600d0db1cdc4d5dd3ad Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 17 Mar 2012 05:42:25 +0100 Subject: [PATCH 30/59] * Fixed race condition during resolving. (cherry picked from commit b70114a22557be39d998b017fd82c4553a40bdfb) --- .../database/databasecommand_resolve.cpp | 40 ++++++++++--------- src/libtomahawk/result.cpp | 18 ++++++++- src/libtomahawk/result.h | 6 ++- 3 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/libtomahawk/database/databasecommand_resolve.cpp b/src/libtomahawk/database/databasecommand_resolve.cpp index 38149e83d..4f13539a5 100644 --- a/src/libtomahawk/database/databasecommand_resolve.cpp +++ b/src/libtomahawk/database/databasecommand_resolve.cpp @@ -55,9 +55,6 @@ DatabaseCommand_Resolve::exec( DatabaseImpl* lib ) qDebug() << "Using result-hint to speed up resolving:" << m_query->resultHint(); Tomahawk::result_ptr result = lib->resultFromHint( m_query ); - /* qDebug() << "Result null:" << result.isNull(); - * qDebug() << "Collection null:" << result->collection().isNull(); - * qDebug() << "Source null:" << result->collection()->source().isNull();*/ if ( !result.isNull() && !result->collection().isNull() && result->collection()->source()->isOnline() ) { QList res; @@ -137,7 +134,7 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib ) else { s = SourceList::instance()->get( files_query.value( 16 ).toUInt() ); - if( s.isNull() ) + if ( s.isNull() ) { qDebug() << "Could not find source" << files_query.value( 16 ).toUInt(); continue; @@ -147,12 +144,15 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib ) } Tomahawk::result_ptr result = Tomahawk::Result::get( url ); - Tomahawk::artist_ptr artist = - Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() ); - Tomahawk::album_ptr album = - Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist ); - Tomahawk::artist_ptr composer = - Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() ); + if ( result->isValid() ) + { + qDebug() << "Result already cached:" << result->toString(); + continue; + } + + Tomahawk::artist_ptr artist = Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() ); + Tomahawk::album_ptr album = Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist ); + Tomahawk::artist_ptr composer = Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() ); result->setModificationTime( files_query.value( 1 ).toUInt() ); result->setSize( files_query.value( 2 ).toUInt() ); @@ -181,6 +181,7 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib ) result->setAttributes( attr ); result->setCollection( s->collection() ); + res << result; } @@ -270,7 +271,7 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib ) else { s = SourceList::instance()->get( files_query.value( 16 ).toUInt() ); - if( s.isNull() ) + if ( s.isNull() ) { qDebug() << "Could not find source" << files_query.value( 16 ).toUInt(); continue; @@ -280,12 +281,15 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib ) } Tomahawk::result_ptr result = Tomahawk::Result::get( url ); - Tomahawk::artist_ptr artist = - Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() ); - Tomahawk::album_ptr album = - Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist ); - Tomahawk::artist_ptr composer = - Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() ); + if ( result->isValid() ) + { + qDebug() << "Result already cached:" << result->toString(); + continue; + } + + Tomahawk::artist_ptr artist = Tomahawk::Artist::get( files_query.value( 18 ).toUInt(), files_query.value( 12 ).toString() ); + Tomahawk::album_ptr album = Tomahawk::Album::get( files_query.value( 19 ).toUInt(), files_query.value( 13 ).toString(), artist ); + Tomahawk::artist_ptr composer = Tomahawk::Artist::get( files_query.value( 20 ).toUInt(), files_query.value( 15 ).toString() ); result->setModificationTime( files_query.value( 1 ).toUInt() ); result->setSize( files_query.value( 2 ).toUInt() ); @@ -322,8 +326,8 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib ) } result->setAttributes( attr ); - result->setCollection( s->collection() ); + res << result; } diff --git a/src/libtomahawk/result.cpp b/src/libtomahawk/result.cpp index 06dd7a472..2e00e8953 100644 --- a/src/libtomahawk/result.cpp +++ b/src/libtomahawk/result.cpp @@ -43,7 +43,7 @@ Result::get( const QString& url ) return s_results.value( url ); } - result_ptr r = result_ptr( new Result( url ), &QObject::deleteLater ); + result_ptr r = result_ptr( new Result( url ), &Result::deleteLater ); s_results.insert( url, r ); return r; @@ -68,12 +68,28 @@ Result::Result( const QString& url ) Result::~Result() +{ +} + + +void +Result::deleteLater() { QMutexLocker lock( &s_mutex ); + if ( s_results.contains( m_url ) ) { s_results.remove( m_url ); } + + QObject::deleteLater(); +} + + +bool +Result::isValid() const +{ + return !m_rid.isEmpty(); } diff --git a/src/libtomahawk/result.h b/src/libtomahawk/result.h index 2d743e4dd..95bafcd74 100644 --- a/src/libtomahawk/result.h +++ b/src/libtomahawk/result.h @@ -58,6 +58,7 @@ public: static Tomahawk::result_ptr get( const QString& url ); virtual ~Result(); + bool isValid() const; QVariant toVariant() const; QString toString() const; Tomahawk::query_ptr toQuery(); @@ -108,6 +109,9 @@ public: unsigned int trackId() const { return m_trackId; } unsigned int fileId() const { return m_fileId; } +public slots: + void deleteLater(); + signals: // emitted when the collection this result comes from is going offline/online: void statusChanged(); @@ -115,7 +119,7 @@ signals: private slots: void onOffline(); void onOnline(); - + private: // private constructor explicit Result( const QString& url ); From 95f1162b6e3d481365c9e6c52310acd488edf661 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 17 Mar 2012 05:49:43 +0100 Subject: [PATCH 31/59] * Fixed cached resolving. (cherry picked from commit bd098e3ff267dbe636192464683314679e1f225d) --- src/libtomahawk/database/databasecommand_resolve.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/database/databasecommand_resolve.cpp b/src/libtomahawk/database/databasecommand_resolve.cpp index 4f13539a5..354208105 100644 --- a/src/libtomahawk/database/databasecommand_resolve.cpp +++ b/src/libtomahawk/database/databasecommand_resolve.cpp @@ -147,6 +147,7 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib ) if ( result->isValid() ) { qDebug() << "Result already cached:" << result->toString(); + res << result; continue; } @@ -284,6 +285,7 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib ) if ( result->isValid() ) { qDebug() << "Result already cached:" << result->toString(); + res << result; continue; } From ace18dfa1fc04f15a4f93f861f9f21effc5f988e Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 17 Mar 2012 12:10:09 +0100 Subject: [PATCH 32/59] * Prevent race condition. (cherry picked from commit ebbedb2b991f1f02b862b91af14ad6eaa9574c70) --- .../database/databasecommand_resolve.cpp | 6 ++++-- src/libtomahawk/result.cpp | 15 ++++++++------- src/libtomahawk/result.h | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/libtomahawk/database/databasecommand_resolve.cpp b/src/libtomahawk/database/databasecommand_resolve.cpp index 354208105..9d0e4199c 100644 --- a/src/libtomahawk/database/databasecommand_resolve.cpp +++ b/src/libtomahawk/database/databasecommand_resolve.cpp @@ -143,8 +143,9 @@ DatabaseCommand_Resolve::resolve( DatabaseImpl* lib ) url = QString( "servent://%1\t%2" ).arg( s->userName() ).arg( url ); } + bool cached = Tomahawk::Result::isCached( url ); Tomahawk::result_ptr result = Tomahawk::Result::get( url ); - if ( result->isValid() ) + if ( cached ) { qDebug() << "Result already cached:" << result->toString(); res << result; @@ -281,8 +282,9 @@ DatabaseCommand_Resolve::fullTextResolve( DatabaseImpl* lib ) url = QString( "servent://%1\t%2" ).arg( s->userName() ).arg( url ); } + bool cached = Tomahawk::Result::isCached( url ); Tomahawk::result_ptr result = Tomahawk::Result::get( url ); - if ( result->isValid() ) + if ( cached ) { qDebug() << "Result already cached:" << result->toString(); res << result; diff --git a/src/libtomahawk/result.cpp b/src/libtomahawk/result.cpp index 2e00e8953..8c53a45c4 100644 --- a/src/libtomahawk/result.cpp +++ b/src/libtomahawk/result.cpp @@ -50,6 +50,14 @@ Result::get( const QString& url ) } +bool +Result::isCached( const QString& url ) +{ + QMutexLocker lock( &s_mutex ); + return ( s_results.contains( url ) ); +} + + Result::Result( const QString& url ) : QObject() , m_url( url ) @@ -86,13 +94,6 @@ Result::deleteLater() } -bool -Result::isValid() const -{ - return !m_rid.isEmpty(); -} - - artist_ptr Result::artist() const { diff --git a/src/libtomahawk/result.h b/src/libtomahawk/result.h index 95bafcd74..72f3f3825 100644 --- a/src/libtomahawk/result.h +++ b/src/libtomahawk/result.h @@ -56,9 +56,9 @@ friend class ::DatabaseCommand_LoadFile; public: static Tomahawk::result_ptr get( const QString& url ); + static bool isCached( const QString& url ); virtual ~Result(); - bool isValid() const; QVariant toVariant() const; QString toString() const; Tomahawk::query_ptr toQuery(); From bee6485475dcc2c5fc0b37e3a34b3bbcca5b8edf Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 17 Mar 2012 17:09:57 +0100 Subject: [PATCH 33/59] * Fixed crash situation in AudioControls. (cherry picked from commit a2bfd73d555ac1a8e8b6107bba4cee89a0ca701f) Conflicts: src/audiocontrols.cpp --- src/audiocontrols.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audiocontrols.cpp b/src/audiocontrols.cpp index f6211ca06..85e4e2411 100644 --- a/src/audiocontrols.cpp +++ b/src/audiocontrols.cpp @@ -277,7 +277,7 @@ void AudioControls::onSocialActionsLoaded() { Query* query = qobject_cast< Query* >( sender() ); - if ( !query ) + if ( !query || !m_currentTrack || query != m_currentTrack->toQuery().data() ) return; query_ptr currentQuery = m_currentTrack->toQuery(); From 565217a53a6f42235bb972c8634a7bce5d36825e Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 30 Mar 2012 10:42:11 -0400 Subject: [PATCH 34/59] TWK-725: Some extra pointer safety --- .../qxtweb-standalone/qxtweb/qxthttpsessionmanager.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/thirdparty/qxt/qxtweb-standalone/qxtweb/qxthttpsessionmanager.cpp b/thirdparty/qxt/qxtweb-standalone/qxtweb/qxthttpsessionmanager.cpp index c444018e3..e02ba562a 100644 --- a/thirdparty/qxt/qxtweb-standalone/qxtweb/qxthttpsessionmanager.cpp +++ b/thirdparty/qxt/qxtweb-standalone/qxtweb/qxthttpsessionmanager.cpp @@ -575,9 +575,14 @@ void QxtHttpSessionManager::processEvents() */ void QxtHttpSessionManager::chunkReadyRead(int requestID) { + if (!connector()) return; + const QSharedPointer& dataSource = connector()->getRequestDataSource( requestID ); if (!dataSource->bytesAvailable()) return; + QIODevice* device = connector()->getRequestConnection(requestID); + if (!device) return; + if (!device->bytesToWrite() || qxt_d().connectionState[device].readyRead == false) { qxt_d().connectionState[device].readyRead = true; @@ -590,6 +595,9 @@ void QxtHttpSessionManager::chunkReadyRead(int requestID) */ void QxtHttpSessionManager::sendNextChunk(int requestID) { + if ( !connector() ) + return; + const QSharedPointer& dataSource = connector()->getRequestDataSource( requestID ); QIODevice* device = connector()->getRequestConnection(requestID); QxtHttpSessionManagerPrivate::ConnectionState& state = qxt_d().connectionState[device]; From cdb70b05d26a3f772d757b1100ffd4bc76b58476 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 30 Mar 2012 11:25:51 -0400 Subject: [PATCH 35/59] Cleanups --- src/accounts/lastfm/LastFmAccount.cpp | 1 + src/accounts/lastfm/lastfmplugin.h | 1 - src/tomahawkapp.h | 4 ---- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/accounts/lastfm/LastFmAccount.cpp b/src/accounts/lastfm/LastFmAccount.cpp index 9ceffdce1..7e4ac519f 100644 --- a/src/accounts/lastfm/LastFmAccount.cpp +++ b/src/accounts/lastfm/LastFmAccount.cpp @@ -270,6 +270,7 @@ LastFmAccount::hookupResolver() const Attica::Content res = AtticaManager::instance()->resolverForId( "lastfm" ); const AtticaManager::ResolverState state = AtticaManager::instance()->resolverState( res ); Q_ASSERT( state == AtticaManager::Installed ); + Q_UNUSED( state ); const AtticaManager::Resolver data = AtticaManager::instance()->resolverData( res.id() ); diff --git a/src/accounts/lastfm/lastfmplugin.h b/src/accounts/lastfm/lastfmplugin.h index 00b133a58..164b0d51d 100644 --- a/src/accounts/lastfm/lastfmplugin.h +++ b/src/accounts/lastfm/lastfmplugin.h @@ -95,4 +95,3 @@ private: #endif // LASTFMPLUGIN_H -class A; diff --git a/src/tomahawkapp.h b/src/tomahawkapp.h index ade0e72d8..24f2acba8 100644 --- a/src/tomahawkapp.h +++ b/src/tomahawkapp.h @@ -151,7 +151,3 @@ Q_DECLARE_METATYPE( PairList ) #endif // TOMAHAWKAPP_H - -struct A; - -struct A; From 907dad95e1febb564ffb7d522b089e1c1d016c9f Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 30 Mar 2012 12:09:59 -0400 Subject: [PATCH 36/59] TWK-721: Don't flicker from officialtracks to supercollection tracks. If the second infosystem albumtracks request comes back empty but the first one came back with tracks, this is not a failure and so keep the official tracks --- src/libtomahawk/playlist/treemodel.cpp | 19 +++++++++++++------ .../widgets/infowidgets/AlbumInfoWidget.cpp | 5 +++-- .../widgets/infowidgets/AlbumInfoWidget.h | 1 + 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/libtomahawk/playlist/treemodel.cpp b/src/libtomahawk/playlist/treemodel.cpp index 98100d65d..b933f9231 100644 --- a/src/libtomahawk/playlist/treemodel.cpp +++ b/src/libtomahawk/playlist/treemodel.cpp @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2012, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -622,7 +623,7 @@ TreeModel::addAlbums( const artist_ptr& artist, const QModelIndex& parent, bool requestData.caller = m_infoId; requestData.customData["row"] = parent.row(); requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); - requestData.customData["refetch"] = QVariant( autoRefetch ); + requestData.customData["refetch"] = autoRefetch; requestData.type = Tomahawk::InfoSystem::InfoArtistReleases; Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); } @@ -660,8 +661,8 @@ TreeModel::addTracks( const album_ptr& album, const QModelIndex& parent, bool au m_receivedInfoData.removeAll( artistInfo ); Tomahawk::InfoSystem::InfoRequestData requestData; requestData.caller = m_infoId; - requestData.customData["rows"] = QVariant( rows ); - requestData.customData["refetch"] = QVariant( autoRefetch ); + requestData.customData["rows"] = rows; + requestData.customData["refetch"] = autoRefetch; requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); requestData.type = Tomahawk::InfoSystem::InfoAlbumSongs; requestData.timeoutMillis = 0; @@ -796,7 +797,7 @@ TreeModel::onAlbumsAdded( const QList& albums, const QModel albumitem = new TreeModelItem( album, parentItem ); albumitem->index = createIndex( parentItem->children.count() - 1, 0, albumitem ); connect( albumitem, SIGNAL( dataChanged() ), SLOT( onDataChanged() ) ); - + getCover( albumitem->index ); } @@ -886,7 +887,7 @@ TreeModel::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QV QModelIndex idx = index( requestData.customData[ "row" ].toInt(), 0, QModelIndex() ); - if ( requestData.customData[ "refetch" ].toInt() > 0 && !al.count() ) + if ( requestData.customData[ "refetch" ].toBool() && !al.count() ) { setMode( DatabaseMode ); @@ -940,7 +941,13 @@ TreeModel::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestData, QV } else if ( m_receivedInfoData.count() == 2 /* FIXME */ ) { - if ( requestData.customData[ "refetch" ].toInt() > 0 ) + // If the second load got no data, but the first load did, don't do anything + QList< QVariant > rows = requestData.customData[ "rows" ].toList(); + QModelIndex idx = index( rows.first().toUInt(), 0, index( rows.at( 1 ).toUInt(), 0, QModelIndex() ) ); + if ( rowCount( idx ) ) + return; + + if ( requestData.customData[ "refetch" ].toBool() ) { setMode( DatabaseMode ); diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp index af76743c7..ca0c8bf00 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.cpp @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -231,7 +232,7 @@ AlbumInfoWidget::loadAlbums( bool autoRefetch ) artistInfo["artist"] = m_album->artist()->name(); Tomahawk::InfoSystem::InfoRequestData requestData; - requestData.customData["refetch"] = QVariant( autoRefetch ); + requestData.customData["refetch"] = autoRefetch; requestData.caller = m_infoId; requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( artistInfo ); requestData.type = Tomahawk::InfoSystem::InfoArtistReleases; @@ -308,7 +309,7 @@ AlbumInfoWidget::infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData requestDa tDebug() << "Adding" << al.count() << "albums"; gotAlbums( al ); } - else if ( requestData.customData[ "refetch" ].toInt() > 0 ) + else if ( requestData.customData[ "refetch" ].toBool() ) { tDebug() << "Auto refetching"; m_buttonAlbums->setChecked( false ); diff --git a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h index 23aafb046..fe92e760f 100644 --- a/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h +++ b/src/libtomahawk/widgets/infowidgets/AlbumInfoWidget.h @@ -1,6 +1,7 @@ /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Christian Muehlhaeuser + * Copyright 2010-2011, Leo Franchi * * Tomahawk is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by From d623bbefc20918f7048f652ad80a897f782d97a2 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 30 Mar 2012 13:27:36 -0400 Subject: [PATCH 37/59] Fix crash on exit --- src/libtomahawk/resolvers/scriptresolver.cpp | 8 +++++++- src/libtomahawk/resolvers/scriptresolver.h | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/resolvers/scriptresolver.cpp b/src/libtomahawk/resolvers/scriptresolver.cpp index 0cdd371a6..aea82067c 100644 --- a/src/libtomahawk/resolvers/scriptresolver.cpp +++ b/src/libtomahawk/resolvers/scriptresolver.cpp @@ -41,6 +41,7 @@ ScriptResolver::ScriptResolver( const QString& exe ) , m_ready( false ) , m_stopped( true ) , m_configSent( false ) + , m_deleting( false ) , m_error( Tomahawk::ExternalResolver::NoError ) { tLog() << Q_FUNC_INFO << "Created script resolver:" << exe; @@ -61,9 +62,10 @@ ScriptResolver::ScriptResolver( const QString& exe ) ScriptResolver::~ScriptResolver() { disconnect( &m_proc, SIGNAL( finished( int, QProcess::ExitStatus ) ), this, SLOT( cmdExited( int, QProcess::ExitStatus ) ) ); + m_deleting = true; m_proc.kill(); - m_proc.waitForFinished(); + m_proc.waitForFinished(); // might call handleMsg Tomahawk::Pipeline::instance()->removeResolver( this ); @@ -207,6 +209,10 @@ ScriptResolver::handleMsg( const QByteArray& msg ) { // qDebug() << Q_FUNC_INFO << msg.size() << QString::fromAscii( msg ); + // Might be called from waitForFinished() in ~ScriptResolver, no database in that case, abort. + if ( m_deleting ) + return; + bool ok; QVariant v = m_parser.parse( msg, &ok ); if ( !ok || v.type() != QVariant::Map ) diff --git a/src/libtomahawk/resolvers/scriptresolver.h b/src/libtomahawk/resolvers/scriptresolver.h index f8e94b0ff..f894ece7e 100644 --- a/src/libtomahawk/resolvers/scriptresolver.h +++ b/src/libtomahawk/resolvers/scriptresolver.h @@ -85,7 +85,7 @@ private: quint32 m_msgsize; QByteArray m_msg; - bool m_ready, m_stopped, m_configSent; + bool m_ready, m_stopped, m_configSent, m_deleting; ExternalResolver::ErrorState m_error; QJson::Parser m_parser; From 73d7ba03f500ea04717bb6640b67b9badd32f6b9 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 30 Mar 2012 13:34:48 -0400 Subject: [PATCH 38/59] TWK-815: Try using foreground text color when drawing grey bg, white on grey is hard to read --- src/libtomahawk/playlist/playlistitemdelegate.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libtomahawk/playlist/playlistitemdelegate.cpp b/src/libtomahawk/playlist/playlistitemdelegate.cpp index ba932a8c1..684e1e249 100644 --- a/src/libtomahawk/playlist/playlistitemdelegate.cpp +++ b/src/libtomahawk/playlist/playlistitemdelegate.cpp @@ -104,10 +104,13 @@ PlaylistItemDelegate::prepareStyleOption( QStyleOptionViewItemV4* option, const if ( item->isPlaying() ) { option->palette.setColor( QPalette::Highlight, option->palette.color( QPalette::Mid ) ); - option->state |= QStyle::State_Selected; + + option->backgroundBrush = option->palette.color( QPalette::Mid ); + option->palette.setColor( QPalette::Text, option->palette.color( QPalette::Text ) ); + } - if ( option->state & QStyle::State_Selected ) + if ( option->state & QStyle::State_Selected && !item->isPlaying() ) { option->palette.setColor( QPalette::Text, option->palette.color( QPalette::HighlightedText ) ); } From 9f5215302cc0df28ba77066f0da1031f56534826 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 30 Mar 2012 14:32:01 -0400 Subject: [PATCH 39/59] various updater fixes --- src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp | 2 -- src/libtomahawk/playlist/XspfUpdater.cpp | 7 +++++++ src/libtomahawk/utils/xspfloader.cpp | 6 +++++- src/libtomahawk/utils/xspfloader.h | 3 ++- 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp b/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp index da7e2f75d..c057ceb59 100644 --- a/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp +++ b/src/libtomahawk/playlist/PlaylistUpdaterInterface.cpp @@ -64,8 +64,6 @@ PlaylistUpdaterInterface::PlaylistUpdaterInterface( const playlist_ptr& pl ) connect( m_timer, SIGNAL( timeout() ), this, SLOT( updateNow() ) ); QTimer::singleShot( 0, this, SLOT( doSave() ) ); - - setAutoUpdate( m_autoUpdate ); } PlaylistUpdaterInterface::PlaylistUpdaterInterface( const playlist_ptr& pl, int interval, bool autoUpdate ) diff --git a/src/libtomahawk/playlist/XspfUpdater.cpp b/src/libtomahawk/playlist/XspfUpdater.cpp index 2eb1d7a1e..d00991d20 100644 --- a/src/libtomahawk/playlist/XspfUpdater.cpp +++ b/src/libtomahawk/playlist/XspfUpdater.cpp @@ -55,8 +55,15 @@ XspfUpdater::~XspfUpdater() void XspfUpdater::updateNow() { + if ( m_url.isEmpty() ) + { + qWarning() << "XspfUpdater not updating because we have an empty url..."; + return; + } + XSPFLoader* l = new XSPFLoader( false, false ); l->setAutoResolveTracks( false ); + l->setErrorTitle( playlist()->title() ); l->load( m_url ); connect( l, SIGNAL( tracks( QList ) ), this, SLOT( playlistLoaded( QList ) ) ); } diff --git a/src/libtomahawk/utils/xspfloader.cpp b/src/libtomahawk/utils/xspfloader.cpp index 9fd0c7369..f9a70851b 100644 --- a/src/libtomahawk/utils/xspfloader.cpp +++ b/src/libtomahawk/utils/xspfloader.cpp @@ -122,7 +122,11 @@ XSPFLoader::reportError() { emit error( FetchError ); #ifndef ENABLE_HEADLESS - JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( errorToString( FetchError) ) ); + const QString errorMsg = errorToString( FetchError); + if ( !m_errorTitle.isEmpty() ) + JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( QString( "%1: %2" ).arg( m_errorTitle ).arg( errorMsg ) ) ); + else + JobStatusView::instance()->model()->addJob( new ErrorStatusMessage( errorMsg ) ); #endif deleteLater(); } diff --git a/src/libtomahawk/utils/xspfloader.h b/src/libtomahawk/utils/xspfloader.h index e4e912618..7369a51b8 100644 --- a/src/libtomahawk/utils/xspfloader.h +++ b/src/libtomahawk/utils/xspfloader.h @@ -49,6 +49,7 @@ public: void setOverrideTitle( const QString& newTitle ); void setAutoResolveTracks( bool autoResolve ) { m_autoResolve = autoResolve; } void setAutoDelete( bool autoDelete ) { m_autoDelete = autoDelete; } + void setErrorTitle( const QString& error ) { m_errorTitle = error; } static QString errorToString( XSPFErrorCode error ); @@ -73,7 +74,7 @@ private: bool m_autoCreate, m_autoUpdate, m_autoResolve, m_autoDelete; QString m_NS,m_overrideTitle; QList< Tomahawk::query_ptr > m_entries; - QString m_title, m_info, m_creator; + QString m_title, m_info, m_creator, m_errorTitle; QUrl m_url; QByteArray m_body; From 948a438ff275d157706ccbce4049016c06026747 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 30 Mar 2012 15:00:53 -0400 Subject: [PATCH 40/59] Remove autoconnect hidden toggle --- src/libtomahawk/accounts/Account.cpp | 4 ---- src/libtomahawk/accounts/Account.h | 3 --- src/libtomahawk/accounts/AccountManager.cpp | 2 +- src/utils/guihelpers.cpp | 1 - 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/libtomahawk/accounts/Account.cpp b/src/libtomahawk/accounts/Account.cpp index 7450a96a4..e8a293c2e 100644 --- a/src/libtomahawk/accounts/Account.cpp +++ b/src/libtomahawk/accounts/Account.cpp @@ -46,7 +46,6 @@ accountTypeToString( AccountType type ) Account::Account( const QString& accountId ) : QObject() , m_enabled( false ) - , m_autoConnect( false ) , m_accountId( accountId ) { connect( this, SIGNAL( error( int, QString ) ), this, SLOT( onError( int,QString ) ) ); @@ -126,7 +125,6 @@ Account::syncConfig() s->beginGroup( "accounts/" + m_accountId ); s->setValue( "accountfriendlyname", m_accountFriendlyName ); s->setValue( "enabled", m_enabled ); - s->setValue( "autoconnect", m_autoConnect ); s->setValue( "credentials", m_credentials ); s->setValue( "configuration", m_configuration ); s->setValue( "acl", m_acl ); @@ -144,7 +142,6 @@ Account::loadFromConfig( const QString& accountId ) s->beginGroup( "accounts/" + m_accountId ); m_accountFriendlyName = s->value( "accountfriendlyname", QString() ).toString(); m_enabled = s->value( "enabled", false ).toBool(); - m_autoConnect = s->value( "autoconnect", false ).toBool(); m_credentials = s->value( "credentials", QVariantHash() ).toHash(); m_configuration = s->value( "configuration", QVariantHash() ).toHash(); m_acl = s->value( "acl", QVariantMap() ).toMap(); @@ -160,7 +157,6 @@ Account::removeFromConfig() s->beginGroup( "accounts/" + m_accountId ); s->remove( "accountfriendlyname" ); s->remove( "enabled" ); - s->remove( "autoconnect" ); s->remove( "credentials" ); s->remove( "configuration" ); s->remove( "acl" ); diff --git a/src/libtomahawk/accounts/Account.h b/src/libtomahawk/accounts/Account.h index f2e297241..43e98ff67 100644 --- a/src/libtomahawk/accounts/Account.h +++ b/src/libtomahawk/accounts/Account.h @@ -78,7 +78,6 @@ public: QString accountServiceName() const { QMutexLocker locker( &m_mutex ); return m_accountServiceName; } // e.g. "Twitter", "Last.fm" QString accountFriendlyName() const { QMutexLocker locker( &m_mutex ); return m_accountFriendlyName; } // e.g. screen name on the service, JID, etc. bool enabled() const { QMutexLocker locker( &m_mutex ); return m_enabled; } - bool autoConnect() const { QMutexLocker locker( &m_mutex ); return m_autoConnect; } QString accountId() const { QMutexLocker locker( &m_mutex ); return m_accountId; } QVariantHash configuration() const { QMutexLocker locker( &m_mutex ); return m_configuration; } @@ -109,7 +108,6 @@ public: void setAccountServiceName( const QString &serviceName ) { QMutexLocker locker( &m_mutex ); m_accountServiceName = serviceName; } void setAccountFriendlyName( const QString &friendlyName ) { QMutexLocker locker( &m_mutex ); m_accountFriendlyName = friendlyName; } void setEnabled( bool enabled ) { QMutexLocker locker( &m_mutex ); m_enabled = enabled; } - void setAutoConnect( bool autoConnect ) { QMutexLocker locker( &m_mutex ); m_autoConnect = autoConnect; } void setAccountId( const QString &accountId ) { QMutexLocker locker( &m_mutex ); m_accountId = accountId; } void setCredentials( const QVariantHash &credentialHash ) { QMutexLocker locker( &m_mutex ); m_credentials = credentialHash; } void setConfiguration( const QVariantHash &configuration ) { QMutexLocker locker( &m_mutex ); m_configuration = configuration; } @@ -148,7 +146,6 @@ private: QString m_accountFriendlyName; QString m_cachedError; bool m_enabled; - bool m_autoConnect; QString m_accountId; QVariantHash m_credentials; QVariantHash m_configuration; diff --git a/src/libtomahawk/accounts/AccountManager.cpp b/src/libtomahawk/accounts/AccountManager.cpp index 1683485e7..eb1f7b43d 100644 --- a/src/libtomahawk/accounts/AccountManager.cpp +++ b/src/libtomahawk/accounts/AccountManager.cpp @@ -374,7 +374,7 @@ AccountManager::hookupAndEnable( Account* account, bool startup ) if ( p ) SipHandler::instance()->hookUpPlugin( p ); - if ( account->enabled() && ( !startup || account->autoConnect() ) ) + if ( account->enabled() ) { account->authenticate(); m_enabledAccounts << account; diff --git a/src/utils/guihelpers.cpp b/src/utils/guihelpers.cpp index e7345e4f2..fd1bfe8a1 100644 --- a/src/utils/guihelpers.cpp +++ b/src/utils/guihelpers.cpp @@ -33,7 +33,6 @@ handleAccountAdded( Tomahawk::Accounts::Account* account, bool added ) if ( added ) { account->setEnabled( true ); - account->setAutoConnect( true ); account->saveConfig(); TomahawkSettings::instance()->addAccount( account->accountId() ); From d8be1fa224f9d108c75794f462716115aa8eeac0 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Fri, 30 Mar 2012 23:00:29 +0200 Subject: [PATCH 41/59] * Merged neycho's bg translation. --- lang/tomahawk_bg.ts | 3501 ++++++++++++++++++++++++++++++++++++++++ lang/tomahawk_i18n.qrc | 1 + 2 files changed, 3502 insertions(+) create mode 100644 lang/tomahawk_bg.ts diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts new file mode 100644 index 000000000..2451fa9f1 --- /dev/null +++ b/lang/tomahawk_bg.ts @@ -0,0 +1,3501 @@ + + + + + ACLRegistry + + + Connect to Peer? + Свързване към друг потребител? + + + + Another Tomahawk instance that claims to be owned by %1 is attempting to connect to you. Select whether to allow or deny this connection. + +Remember: Only allow peers to connect if you trust who they are and if you have the legal right for them to stream music from you. + Tomahawk, стартиран от %1 се опитва да се свърже с теб. Избери дали да приемеш или откажеш свързването. +Внимание! Позволявайте връзки само от потребители, които познавате и на които имате доверие и ако имате право да разпространявате музиката, която съхранявате. + + + + Deny + Откажи + + + + Allow + Позволи + + + + AccountFactoryWrapper + + + Dialog + + + + + Description goes here + + + + + Add Account + Добави регистрация + + + + AccountFactoryWrapperDelegate + + + Online + На линия + + + + Connecting... + Свързване... + + + + Offline + Извън линия + + + + ActionCollection + + + &Listen Along + &Слушай заедно + + + + Stop &Listening Along + Спри & да слушаш заедно + + + + &Follow in real-time + &Последвай + + + + + &Listen Privately + &Слушай самостоятелно + + + + + &Listen Publicly + &Слушай публично + + + + &Load Playlist + &Зареди списък + + + + &Rename Playlist + &Преименувай списък + + + + &Copy Playlist Link + &Копирай връзка към списък + + + + &Play + &Изпълни + + + + &Stop + &Спри + + + + &Previous Track + &Предходна песен + + + + &Next Track + &Следваща песен + + + + &Quit + &Изключи приложението + + + + AlbumInfoWidget + + + Form + + + + + Other Albums by Artist + Други албуми на този артист + + + + + Click to show SuperCollection Tracks + Покажи песните от супер колекцията + + + + + Click to show Official Tracks + Покажи само официалните песни + + + + + Click to show SuperCollection Albums + Покажи албумите от супер колекцията + + + + Click to show Official Albums + Покажи само официалните албуми + + + + Other Albums by %1 + Други албуми от %1 + + + + AlbumModel + + + Album + Албум + + + + + All albums from %1 + Всички албуми на %1 + + + + All albums + Всички албуми + + + + AlbumView + + + After you have scanned your music collection you will find your latest album additions right here. + След като сканирате музикалната ви колекция, ще откриете най-скоро добавените албуми тук. + + + + This collection doesn't have any recent albums. + + + + + ArtistInfoWidget + + + Form + + + + + Top Hits + Най-големи хитове + + + + Related Artists + Свързани артисти + + + + Albums + Албуми + + + + + Click to show SuperCollection Albums + Покажи албумите от супер колекцията + + + + Click to show Official Albums + Покажи само официалните албуми + + + + ArtistView + + + After you have scanned your music collection you will find your tracks right here. + + + + + This collection is currently empty. + + + + + Sorry, your filter '%1' did not match any results. + + + + + AudioControls + + + Prev + Предходна + + + + Play + Изпълни + + + + Pause + Пауза + + + + Next + Следваща + + + + Artist + Артист + + + + Album + Албум + + + + Owner + Притежател + + + + love + Харесай + + + + Time + Продължителност + + + + Time Left + Оставащо време + + + + Shuffle + Разбъркано + + + + Repeat + Повтори + + + + Low + 0 + + + + High + 100% + + + + AudioEngine + + + Tomahawk is stopped. + Tomahawk е спрян + + + + Tomahawk is playing "%1" by %2%3. + Tomahawk изпълнява "%1" от %2%3. + + + + on album %1 + от албум %1 + + + + CategoryAddItem + + + + New Playlist + Нов списък + + + + + + + New Station + Нова станция + + + + + + %1 Station + %1 Станция + + + + CategoryItem + + + Playlists + Списъци + + + + Stations + Станции + + + + ClearButton + + + Clear + Изчисти + + + + CollectionFlatModel + + + My Collection + Моята колекция + + + + Collection of %1 + Колекцията на %1 + + + + CollectionView + + + This collection is empty. + Тази колекция е празна. + + + + ContextWidget + + + InfoBar + + + + + + Show Footnotes + Покажи подробности + + + + Hide Footnotes + Скрий подробности + + + + CrashReporter + + + Tomahawk Crash Reporter + Автоматично докладване на грешки на Tomahawk + + + + <p><b>Sorry!</b>&nbsp;Tomahawk crashed. Information about the crash is now being sent to Tomahawk HQ so that we can fix the bug.</p> + <p><b>Извинявай</b>! + Tomahawk спря да работи. Информация относно проблемът се изпраща към нашата централа, за да можем да го отстраним. + + + + Abort + Откажи + + + + You can disable sending crash reports in the configuration dialog. + Можете да спрете изпращането на информация относно проблеми в панелът с настройки. + + + + Uploaded %L1 of %L2 KB. + Качени %L1 от %В2 КБ + + + + + Close + Затвори + + + + Sent! <b>Many thanks</b>. + Изпращането приключи. Благодарим ви за отзивчивостта! :) + + + + Failed to send crash info. + Изпращането на краш-данни е неуспешно. + + + + DatabaseCommand_AllAlbums + + + Unknown + Неизвестно + + + + DelegateConfigWrapper + + + Delete Account + Изтрий регистрация + + + + DiagnosticsDialog + + + Tomahawk Diagnostics + Диагностична информация относно Tomahawk + + + + Update + Обнови + + + + Copy to Clipboard + Копирай в буферът + + + + DropJob + + + No tracks found for given %1 + Няма открити изпълнения на %1 + + + + GlobalSearchWidget + + + Form + + + + + IndexingJobItem + + + Indexing database + Индексиране на БД + + + + InfoBar + + + InfoBar + Информационно поле + + + + Automatically update + Автоматично обновление + + + + Filter... + Филтър... + + + + JobStatusView + + + Searching For + Търсене за + + + + Pending + Изчакващо + + + + Idle + + + + + LastFmConfig + + + Form + + + + + Scrobble tracks to Last.fm + Изпращане на изпълнени песни към Last.fm + + + + Username: + Потребителско име: + + + + Password: + Парола: + + + + Test Login + Пробна връзка + + + + LastfmContext + + + Last.fm + + + + + LatchedStatusItem + + + %1 is listening along to you! + %1 слуша заедно с теб! + + + + LoadXSPF + + + Load XSPF + Зареди XSPF + + + + Playlist URL + Адрес на списък + + + + Enter URL... + Въведи адрес... + + + + ... + + + + + Automatically update + Автоматично обновяване + + + + LoadXSPFDialog + + + Load XSPF File + + + + + XSPF Files (*.xspf) + + + + + LocalCollection + + + Bookmarks + Отметки + + + + Saved tracks + Запаметени изпълнения + + + + NewPlaylistWidget + + + Enter a title for the new playlist: + Въведи име за новият списък + + + + Tomahawk offers a variety of ways to help you create playlists and find music you enjoy! + Tomahawk предлага множесто начини за създаване на списъци за изпълнение и откриване на любимата ти музика! + + + + Just enter a genre or tag name and Tomahawk will suggest a few songs to get you started with your new playlist: + Просто въведи стил или име и Tomahawk ще ти предложи няколко песни с които да стартира новият ти списък: + + + + &Create Playlist + + + + + Create a new playlist + + + + + PlaylistItemDelegate + + + played %1 by you + изпълнен %1 от теб + + + + played %1 by %2 + изпълнен %1 от %2 + + + + PlaylistLargeItemDelegate + + + played %1 by you + изпълнен %1 от теб + + + + played %1 by %2 + изпълнен %1 от %2 + + + + PlaylistModel + + + A playlist by %1, created %2 + Списък с изпълниния на %1, създаден %2 + + + + you + ти + + + + All tracks by %1 on album %2 + Всички изпълнения от %1 от албум %2 + + + + All tracks by %1 + Всички изпълнения от %1 + + + + PlaylistTypeSelectorDlg + + + New Playlist + Нов списък + + + + Just a regular old playlist... Give it a name, drag in some tracks, and go! + Обикновен стар списък... Наименовай го, довлачи няколко изпълнения и давай напред! + + + + Don't know exactly what you want? Give Tomahawk a few pointers and let it build a playlist for you! + Не знаеш точно какво искаш? Дай на Tomahawk няколко начални идеи и му позволи да създаде списък с песни за теб! + + + + Name: + Име: + + + + New Playlist... + Нов списък + + + + Create Manual Playlist + Създай ръчно създаден списък + + + + Create Automatic Playlist + Създай автоматично генериран списък + + + + PlaylistView + + + This playlist is currently empty. Add some tracks to it and enjoy the music! + Този списък в момента е празен. Добави няколко изпълнения и се наслади на музиката! + + + + ProxyDialog + + + Proxy Settings + Proxy настройки + + + + Hostname of proxy server + Адрес на proxy сървър + + + + Host + Адрес + + + + Port + Порт + + + + Proxy login + Настройка на влизане + + + + User + Потребител + + + + Password + Парола + + + + Proxy password + Парола за proxy + + + + Type + Тип + + + + No Proxy Hosts: +(Overrides system proxy) + Без адреси за Proxy (Отменя системните настройки) + + + + localhost *.example.com (space separated) + localhost *.example.com (отделени с интервал) + + + + Use proxy for DNS lookups? + Използване на Proxy за DNS заявки? + + + + QObject + + + Friend Finders + Търсене на приятели + + + + Music Finders + Търсене на музика + + + + Status Updaters + Обновяване на статус + + + + %n year(s) ago + + Преди %n години + + + + + + %n year(s) + + %n години + + + + + + %n month(s) ago + + Преди %n месеца + + + + + + %n month(s) + + %n месеца + + + + + + %n week(s) ago + + Преди %n седмици + + + + + + %n week(s) + + %n седмици + + + + + + %n day(s) ago + + Преди %n дена + + + + + + %n day(s) + + %n дни + + + + + + %n hour(s) ago + + Преди %n часа + + + + + + %n hour(s) + + %n часа + + + + + + %1 minutes ago + Преди %1 минути + + + + %1 minutes + %1 минути + + + + just now + Сега + + + + QuaZipFilePrivate + + + ZIP/UNZIP API error %1 + ZIP/UNZIP API грешка %1 + + + + QueueView + + + InfoBar + Информационно поле + + + + + Show Queue + Покажи опашката + + + + Hide Queue + Скрий опашката + + + + RelatedArtistsContext + + + Related Artists + Подобни артисти + + + + ResolverConfigDelegate + + + Not found: %1 + Не откривам : %1 + + + + Failed to load: %1 + Неуспех при зареждане на %1 + + + + SearchLineEdit + + + Search + Търси + + + + SearchWidget + + + Search: %1 + Търси %1 + + + + Results for '%1' + Резултати за '%1' + + + + SettingsDialog + + + All + Всички + + + + Services + Услуги + + + + Collection + Колекция + + + + Advanced + Разширени + + + + Install resolver from file + Инсталирай услиги за търсене от файл + + + + Information + Информация + + + + Changing this setting requires a restart of Tomahawk! + Промяната на тази настройка(и) изисква рестартиране на програмата! + + + + SocialPlaylistWidget + + + Popular New Albums From Your Friends + Популярни нови албуми от твоите приятели + + + + Most Played Playlists + Най-изпълнявани списъци + + + + Most Played Tracks You Don't Have + Най-изпълнявани песни, които нямаш в наличност + + + + SourceDelegate + + + Track + Песен + + + + Album + Албум + + + + Artist + Артист + + + + Local + Локално + + + + Top 10 + Първите 10 + + + + Offline + Извън линия + + + + All available tracks + Всички налични изпълнения + + + + Online + На линия + + + + + Show + Покажи + + + + + Hide + Скрий + + + + SourceInfoWidget + + + Recent Albums + Скорошни албуми + + + + Latest Additions + Последно добавени + + + + Recently Played Tracks + Наскоро изпълнени песни + + + + New Additions + Нови попълнения + + + + My recent activity + Скорошна активност + + + + Recent activity from %1 + Скорошна активност на %1 + + + + SourceItem + + + Collection + Колекция + + + + Latest Additions + Последно добавен + + + + Recently Played + Наскоро изпълнени песни + + + + Loved Tracks + Харесани песни + + + + SuperCollection + Супер колекция + + + + SourceTreeView + + + &Copy Link + &Копирай адресът + + + + &Delete %1 + &Изтрий %1 + + + + &Export Playlist + &Изнеси списък + + + + Save XSPF + Запази XSPF + + + + Playlists (*.xspf) + Списъци (*.xspf) + + + + SourcesModel + + + Group + Гпупирай + + + + Collection + Колекция + + + + Playlist + Списък за изпълнение + + + + Automatic Playlist + Автоматичен списък + + + + Station + Станция + + + + Browse + Разгледай + + + + Search History + Търси в историята + + + + My Music + Моята музика + + + + SuperCollection + Супер колекция + + + + Top Loved Tracks + Най-харесвани песни + + + + Dashboard + Табло + + + + Charts + Класации + + + + Friends + Приятели + + + + SpotifyConfig + + + Form + + + + + Configure your Spotify credentials + Настрой твоити Spotify настройки на регистрация + + + + Username: + Потребителско име + + + + placeholderUsername + потребителско име + + + + Password: + Парола: + + + + placeholderPw + парола + + + + High Quality Streaming + Висококачествен поток + + + + This product uses SPOTIFY(R) CORE but is not endorsed, certified or otherwise approved in any way by Spotify. Spotify is the registered trade mark of the Spotify Group. + Този продукт ползва ядрото на SPOTIFY(R), но не е поддържан, сертифицират или одобрен по какъвто и да е начин от Spotify. +Spotify e TM на Spotify Group. + + + + StackedSettingsDialog + + + Tomahawk Settings + Настройки на Tomahawk + + + + Internet Services + Интернет услуги + + + + Install from file... + Инсталирай от файл... + + + + Filter by capability: + Филтрирай по възможности: + + + + Local Music Information + Информация за локалната музика + + + + Path to scan for music files: + Път за сканиране за музика: + + + + The Echo Nest supports keeping track of your catalog metadata + and using it to craft personalized radios. Enabling this option + will allow you (and all your friends) to create automatic playlists + and stations based on your personal taste profile. + The Echo Nest поддържа постоянно актуална информация за съдържанието на твоят каталог и +и я използва за създаването на персонализирани станции. Активирането на тази опция +ще позволи ти (и твоите приятели) да създадавате персонализирани списъци за изпълнение, +базирани на вашият персонален вкус. + + + + Upload collection list to The Echo Nest to enable user radio + Качи списък на колекцията ти в The Echo Nest за да се създаде потребителско радио + + + + Watch for changes + Наблюдавай за промени + + + + Time between scans, in seconds: + Време между две сканирания, в секунди + + + + Advanced Network Settings + Разширени мрежови настройки + + + + If you're having difficulty connecting to peers, try setting this to your external IP address/host name and a port number (default 50210). Make sure to forward that port to this machine! + + + + + Static Host Name: + + + + + Static Port: + + + + + Always use static host name/port? (Overrides UPnP discovery/port forwarding) + + + + + Proxy Settings... + + + + + Send reports after Tomahawk crashed + + + + + Playdar HTTP API + + + + + Use UPnP to establish port forward + + + + + Tomahawk::Accounts::AccountDelegate + + + Add Account + Добави регистрация + + + + Remove Account + Премахни регистрация + + + + %1 downloads + %1 сваляния + + + + Online + На линия + + + + Connecting... + Свързване... + + + + Offline + Извън линия + + + + Tomahawk::Accounts::GoogleWrapper + + + Configure this Google Account + Настрой регистрацията в Google + + + + Google Address + Google адрес + + + + Enter your Google login to connect with your friends using Tomahawk! + Въведи твоята Google регистрация за да можеш да се свържеш с твоите приятели, ползващи Tomahawk + + + + username@gmail.com + потребителско_име@gmail.com + + + + Tomahawk::Accounts::GoogleWrapperFactory + + + Connect to Google Talk to find your friends + Свържи се с Google Talk да можеш да търсиш твоите приятели + + + + Tomahawk::Accounts::GoogleWrapperSip + + + Add Friend + + + + + Enter Google Address: + + + + + Tomahawk::Accounts::LastFmAccountFactory + + + Scrobble your tracks to last.fm, and find freely downloadable tracks to play + + + + + Tomahawk::Accounts::LastFmConfig + + + + Failed + Неуспешно + + + + Success + Успех! + + + + Could not contact server + Не мога да се свържа със сървъра + + + + Tomahawk::Accounts::SpotifyAccountFactory + + + Play music from and sync your playlists with Spotify Premium + Слушай музика и синхронизирай твоите списъци със Spotify Premium + + + + Tomahawk::Accounts::TwitterAccountFactory + + + Connect to your Twitter followers. + Свържи се с твоите приятели в Twitter + + + + Tomahawk::Accounts::TwitterConfigWidget + + + + + Tweet! + Чурулик! + + + + + Status: No saved credentials + Няма запазени данни за вход + + + + + + Authenticate + Удостовери + + + + + Status: Credentials saved for %1 + + + + + + De-authenticate + Премахни усостоверяване + + + + + + + + + + Tweetin' Error + + + + + The credentials could not be verified. +You may wish to try re-authenticating. + + + + + Status: Error validating credentials + + + + + Global Tweet + + + + + Direct Message + + + + + Send Message! + + + + + @Mention + + + + + Send Mention! + + + + + You must enter a user name for this type of tweet. + + + + + Your saved credentials could not be loaded. +You may wish to try re-authenticating. + + + + + Your saved credentials could not be verified. +You may wish to try re-authenticating. + + + + + + There was an error posting your status -- sorry! + + + + + + Tweeted! + + + + + Your tweet has been posted! + + + + + There was an error posting your direct message -- sorry! + + + + + Your message has been posted! + + + + + Tomahawk::Accounts::XmppAccountFactory + + + Log on to your Jabber/XMPP account to connect to your friends + Свържи се с твоята Jabber/XMPP регистрация, за да откриеш твоите приятели + + + + Tomahawk::Accounts::ZeroconfFactory + + + Automatically connect to Tomahawks on the local network + Автоматично свързва Tomahawk с останалите копия на програмата, + работещи в локалната мрежа. + + + + Tomahawk::ContextMenu + + + &Play + &Изпълни + + + + + + Add to &Queue + Добави към &опашката + + + + + &Love + &Харесай + + + + &Copy Track Link + &Копирай адресът на изпълнението + + + + &Delete Items + &Изтрий позициите + + + + &Delete Item + &Изтрий позицията + + + + Show &Album page + Покажи &страницата на албума + + + + Show &Artist page + Покажи страницата на &артиста + + + + Un-&Love + Не-&харесай + + + + Tomahawk::CustomPlaylistView + + + Top Loved Tracks + Най-харесвани изпълнения + + + + Your loved tracks + Изпълненията, които харесваш ти + + + + %1's loved tracks + Изпълненията, каресвани от %1 + + + + The most loved tracks from all your friends + Харесваните изпълнения от всички твои приятели + + + + All of your loved tracks + Всички изпълнения, които харесваш + + + + All of %1's loved tracks + Всички изпълнения , харесвани от %1 + + + + Tomahawk::DropJobNotifier + + + Fetching %1 from database + Извличане на %1 от БД + + + + Parsing %1 %2 + Обединяване на %1 %2 + + + + Tomahawk::DynamicControlList + + + Click to collapse + Свий + + + + Tomahawk::DynamicModel + + + + Could not find a playable track. + +Please change the filters or try again. + Не откривам песни годни за изпълняване. +Моля променете филтрите и опитайте отново. + + + + Failed to generate preview with the desired filters + Неуспех при генериране на предварителен преглед на избраните филтри. + + + + Tomahawk::DynamicSetupWidget + + + Type: + Тип: + + + + Generate + Генерирай + + + + Tomahawk::DynamicView + + + Add some filters above to seed this station! + Добави няколко критерия, за да разпространиш тази станция + + + + Press Generate to get started! + Натисни "Генерирай" за да почне просвирване. + + + + Add some filters above, and press Generate to get started! + Добави няколко критерия и натисни "Генерирай" за да почне просвирване. + + + + Tomahawk::DynamicWidget + + + Station ran out of tracks! + +Try tweaking the filters for a new set of songs to play. + Станцията изчерпа изпълненията по зададените критерии. +Опитай да добевиш/въведеш нови за да продължи изпълнението. + + + + Tomahawk::EchonestControl + + + + + + + + is + + + + + from user + + + + + + No users with Echo Nest Catalogs enabled. Try enabling option in Collection settings + + + + + similar to + + + + + + + + + + + Less + + + + + + + + + + + More + + + + + 0 BPM + + + + + 500 BPM + + + + + 0 secs + + + + + 3600 secs + + + + + -100 dB + + + + + 100 dB + + + + + Major + + + + + Minor + + + + + C + + + + + C Sharp + + + + + D + + + + + E Flat + + + + + E + + + + + F + + + + + F Sharp + + + + + G + + + + + A Flat + + + + + A + + + + + B Flat + + + + + B + + + + + Ascending + + + + + Descending + + + + + Tempo + + + + + Duration + + + + + Loudness + + + + + Artist Familiarity + + + + + Artist Hotttnesss + + + + + Song Hotttnesss + + + + + Latitude + + + + + Longitude + + + + + Mode + + + + + Key + + + + + Energy + + + + + Danceability + + + + + only by ~%1 + + + + + similar to ~%1 + + + + + with genre ~%1 + + + + + + from no one + + + + + My Collection + + + + + from %1 radio + + + + + with %1 %2 + + + + + about %1 BPM + + + + + about %n minute(s) long + + + + + + + about %1 dB + + + + + at around %1%2 %3 + + + + + in %1 + + + + + in a %1 key + + + + + sorted in %1 %2 order + + + + + with a %1 mood + + + + + in a %1 style + + + + + Tomahawk::EchonestSteerer + + + Steer this station: + Задръж тази станция: + + + + Much less + Много по-малко + + + + Less + По-малко + + + + A bit less + Малко по-малко + + + + Keep at current + Задръж + + + + A bit more + Малко повече + + + + More + Повече + + + + Much more + Много повече + + + + Tempo + Темпо + + + + Loudness + Сила + + + + Danceability + Танцувалност + + + + Energy + Енергия + + + + Song Hotttnesss + Популярност на изпълненията + + + + Artist Hotttnesss + Популярност на изпълнителя + + + + Artist Familiarity + Близост на изпълнителите + + + + By Description + По описание + + + + Enter a description + Въведи описание + + + + Apply steering command + Приложи избраната команда + + + + Reset all steering commands + Нулирай всички предишни настройки + + + + Tomahawk::GroovesharkParser + + + Error fetching Grooveshark information from the network! + Грешка при извличане на информацията от Grooveshark + + + + Tomahawk::InfoSystem::ChartsPlugin + + + Top Overall + + + + + Artists + + + + + Albums + + + + + Tracks + + + + + Tomahawk::InfoSystem::LastFmPlugin + + + Top Tracks + + + + + Loved Tracks + + + + + Hyped Tracks + + + + + Top Artists + + + + + Hyped Artists + + + + + Tomahawk::ItunesParser + + + Error fetching iTunes information from the network! + Грешка при извличане на информация от iTunes + + + + Tomahawk::JSPFLoader + + + New Playlist + + + + + Failed to save tracks + + + + + Some tracks in the playlist do not contain an artist and a title. They will be ignored. + + + + + XSPF Error + + + + + This is not a valid XSPF playlist. + + + + + Tomahawk::LatchManager + + + &Catch Up + &Последвай + + + + + &Listen Along + &Слушай заедно + + + + Tomahawk::Query + + + and + и + + + + You + Ти + + + + you + ти + + + + and + и + + + + %n other(s) + + % други + + + + + + %1 people + %1 хора + + + + loved this track + харесаха това изпълнение + + + + Tomahawk::RdioParser + + + Error fetching Rdio information from the network! + Грешка при извличане на информация от Rdio + + + + Tomahawk::ShortenedLinkParser + + + Network error parsing shortened link! + Мрежова грешка при извличане на съкратеният адрес. + + + + Tomahawk::Source + + + + Scanning (%L1 tracks) + Сканиране (%L1 изпълнения) + + + + Scanning + Сканиране + + + + Checking + Проверка + + + + Fetching + Удължаване + + + + Parsing + Сортиране + + + + Saving (%1%) + Запазване (%1%) + + + + Tomahawk::SpotifyParser + + + Error fetching Spotify information from the network! + Грешка при извличане на информация от Spotify + + + + TomahawkApp + + + My Collection + Моята колекция + + + + TomahawkOAuthTwitter + + + Twitter PIN + Twitter код + + + + After authenticating on Twitter's web site, +enter the displayed PIN number here: + След удостоверяване в Twitter, + въведете генерираният код тук: + + + + TomahawkTrayIcon + + + + Hide Tomahawk Window + Скрий прозорецът на Tomahawk + + + + Show Tomahawk Window + Покажи прозорецът на Tomahawk + + + + Currently not playing. + В момента не се изпълнява нищо. + + + + Play + Изпълни + + + + Pause + Пауза + + + + TomahawkWindow + + + Tomahawk + + + + + &Settings + &Настройки + + + + &Controls + &Контроли + + + + &Network + &Мрежа + + + + &Window + &Прозорец + + + + &Help + &Помощ + + + + &Quit + &Изход + + + + Ctrl+Q + Ctrl+Q + + + + Go &Online + &Свържи се + + + + Add &Friend... + Добави &приятел + + + + U&pdate Collection + О&бнови колекцията + + + + Update Collection + Обнови колекцията + + + + &Configure Tomahawk... + &Настройки на Tomahawk + + + + Load &XSPF... + Зареди &XSPF... + + + + Create &New Playlist... + Зареди &Нов списък + + + + About &Tomahawk... + За &Tomahawk + + + + Create New &Automatic Playlist + Създай нов &Автоматичен списък + + + + Create New &Station + Създай нова станция + + + + Show Offline Sources + Покажи източници извън интернет + + + + Hide Offline Sources + Скрий източници извън интернет + + + + Minimize + Смали + + + + Ctrl+M + + + + + Zoom + Увеличи + + + + Meta+Ctrl+Z + + + + + Diagnostics... + Диагностика... + + + + Fully &Rescan Collection + Пълно &сканиране на колекцията + + + + Fully Rescan Collection + Пълно сканиране на колекцията + + + + + Play + Изпълни + + + + Space + + + + + Previous + Предишна + + + + Next + Следваща + + + + Global Search... + Глобално търсене... + + + + + Check For Updates... + Провери за обновления... + + + + + + Connect To Peer + Свържи се с друг потребител + + + + Enter peer address: + Въведи адресът на отдалеченият потребител + + + + Enter peer port: + Въведи портът на отдалеченият потребител + + + + Enter peer key: + Въведи ключът на на отдалеченият потребител + + + + XSPF Error + XSPF Грешка + + + + This is not a valid XSPF playlist. + Това не е валиден XSPF списък + + + + Failed to save tracks + Неуспех при запазване на списък с изпълнения + + + + Some tracks in the playlist do not contain an artist and a title. They will be ignored. + Някои от изпълненията в списък, нямат артист и заглавие. Те ще бъдат игнорирани. + + + + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. Make sure you have a suitable Phonon backend and required plugins installed. + Съжалявам. Има проблем с достъпа до твоето аудио-устройство или до избраното изпълнение - то ще бъде прескочено. Моля, увери се, че са инсталирани подходящ Phonon и приставки. + + + + Sorry, there is a problem accessing your audio device or the desired track, current track will be skipped. + Съжалявам. Има проблем с достъпа до твоето аудио устройство или избрано изпълнение. Текущото изпъление ще бъде пропуснато. + + + + Create New Station + Създай нова станция + + + + Name: + Име: + + + + New Station + Нова станция + + + + New Playlist + Нов списък + + + + Pause + Пауза + + + + Go &offline + Излез &извън линия + + + + Go &online + Свържи &се + + + + Authentication Error + Грешка при удостоверяване + + + + %1 by %2 + track, artist name + %1 от %2 + + + + %1 - %2 + current track, some window title + %1 - %2 + + + + About Tomahawk + За Tomahawk + + + + <h2><b>Tomahawk %1<br/>(%2)</h2>Copyright 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Thanks to: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + <h2><b>Tomahawk %1<br/>(%2)</h2>Всички права запазени 2010 - 2012<br/>Christian Muehlhaeuser &lt;muesli@tomahawk-player.org&gt;<br/><br/>Благодарности на: Leo Franchi, Jeff Mitchell, Dominik Schmidt, Jason Herskowitz, Alejandro Wainzinger, Hugo Lindstr&ouml;m, Michael Zanetti, Harald Sitter and Steve Robertson + + + + TopBar + + + Form + + + + + 0 Sources + + + + + 0 Tracks + + + + + 0 Artists + + + + + 0 Shown + + + + + Tracks + Изпълнения + + + + Artists + Артиста + + + + Filter + Филтър + + + + Artist View + Преглед на артист + + + + Flat View + Плосък изглед + + + + Sources + Източници + + + + Shown + Показани + + + + TopTracksContext + + + Top Hits + Най-слушани + + + + TrackModel + + + Artist + Артист + + + + Title + Заглавие + + + + Composer + Композитор + + + + Album + Албум + + + + Track + Номер + + + + Duration + Продължителност + + + + Bitrate + Качество + + + + Age + Възраст + + + + Year + Година + + + + Size + Размер + + + + Origin + Произход + + + + Score + Популярност + + + + TrackView + + + Sorry, your filter '%1' did not match any results. + Съжалявам, твоят филтър %1 не върна никакъв резултат. + + + + TransferStatusItem + + + from + от + + + + to + до + + + + TreeItemDelegate + + + Unknown + + + + + TreeModel + + + Name + Име + + + + Composer + Композитор + + + + Duration + Продължителност + + + + Bitrate + Качество + + + + Age + Възраст + + + + Year + Година + + + + Size + Размер + + + + Origin + Произход + + + + All Artists + Всички артисти + + + + + My Collection + Моята колекция + + + + + Collection of %1 + Колекцията на %1 + + + + TwitterConfigWidget + + + Configure this Twitter account + Настрой Twitter профил + + + + The Twitter plugin allows you to discover and play music from your Twitter friends running Tomahawk and post messages to your account. + Тази приставка за Twitter ще ти позволи да откриваш и изпълняваш музика, от твоите приятели в Twitter ползващи Tomahawk и побликуващи съобщения в твоя профил. + + + + Status: No saved credentials + Статус: Няма запаметени данни за вход + + + + Authenticate with Twitter + Удостовери в Twitter + + + + Twitter Connections + Twitter връзки + + + + +If you only want to post tweets, you're done. + +If you want to connect Tomahawk to your friends using Twitter, select the type of tweet and press the button below to send a sync message. You must both be following each other as Direct Messages are used. Then be (very) patient -- it can take several minutes! + +You can re-send a sync message at any time simply by sending another tweet using the button. + +Ако само желаете да побликуваш съобщения, си готов. +Ако желаеш да се свържеш с твои приятели, ползващи Twitter, избери тип на съобщението и натисни бутонът от долу, за изпращане. Трябва взаимно да се следвате, за да можете да ползвате функцията DM. +След изпращане, бъди търпелив. Може да изминат няколко минути преди побликуване. + + + + Select the kind of tweet you would like, then press the button to post it: + Избери тип на съобщението и след това натисни бутонът, да го побликуваш. + + + + Global Tweet + Общо съобщение + + + + @Mention + @Споменаване + + + + Direct Message + Лично съобщение + + + + e.g. @tomahawk + т.е. @tomahawk + + + + Send Message + Изпрати съобщение + + + + ViewManager + + + SuperCollection + Супер колекция + + + + Combined libraries of all your online friends + Комбинирани библиотеки от всичките ти приятели на линия + + + + All available albums + Всички налични албуми + + + + WelcomeWidget + + + Recent Additions + Нови попълнения + + + + Newest Stations & Playlists + Най-нови станции и списъци + + + + Recently Played Tracks + Наскоро изпълнени + + + + No recently created playlists in your network. + Няма наскоро създавани списъзи в твоята мрежа + + + + Welcome to Tomahawk + Здравей! + + + + WhatsHotWidget + + + Charts + Класации + + + + WikipediaContext + + + Wikipedia + Уикипедиа + + + + XMPPBot + + + +Terms for %1: + + Условия за %1 + + + + No terms found, sorry. + Няма открити условия, съжалявам. + + + + +Hotttness for %1: %2 + + Популарност на %1:%2 + + + + +Familiarity for %1: %2 + + Еднаквост за %1: %2 + + + + +Lyrics for "%1" by %2: + +%3 + + Текст за "%1" by %2: + +%3 + + + + + XSPFLoader + + + Failed to parse contents of XSPF playlist + Неуспешно извличане на данни от XSPF списък + + + + Some playlist entries were found without artist and track name, they will be omitted + За някои от позициите не открих артист или име на на песента. Те ще бъдат пропуснати. + + + + Failed to fetch the desired playlist from the network, or the desired file does not exist + Неуспех при извличане на избраният списък през мрежата или избраният файл не съществува. + + + + New Playlist + Нов списък + + + + XmlConsole + + + Xml stream console + Конзола за Xml поток + + + + + Filter + Филтър + + + + Save log + Запази диагностичните съобщения + + + + Disabled + Деактивиран + + + + By JID + По JID + + + + By namespace uri + По namespace uri + + + + By all attributes + По всички атрибути + + + + Visible stanzas + + + + + Information query + Извличане на информация + + + + Message + Съобщение + + + + Presence + Наличие + + + + Custom + Специфично създаден + + + + Close + Затвори + + + + Save XMPP log to file + Запази XMPP диагностичните съобщения във файл. + + + + OpenDocument Format (*.odf);;HTML file (*.html);;Plain text (*.txt) + + + + + XmppConfigWidget + + + Xmpp Configuration + Настройка на Xmpp + + + + Configure this Xmpp account + Настрой тази Xmpp регистрация + + + + Enter your Xmpp login to connect with your friends using Tomahawk! + Въведи Xmpp потребителско име и парола за да се свържеш с приятелите ти, ползващи Tomahawk + + + + Login Information + Информация за влизане + + + + Xmpp ID: + Xmpp потребителско име: + + + + e.g. user@example.com + т.е. user@example.com + + + + Password: + Парола: + + + + An account with this name already exists! + Вече съществува регистрация с такова име! + + + + Advanced Xmpp Settings + Разширени настройки: + + + + Server: + Сървър: + + + + Port: + Порт: + + + + XmppSipPlugin + + + User Interaction + Действие от потребителя + + + + Host is unknown + Непознат адрес + + + + Item not found + Обектът не е открит + + + + Authorization Error + Грешка при даване на достъп + + + + Remote Stream Error + Грешка в стриймът от отдалечената машина + + + + Remote Connection failed + Отдалечената връзка е неуспешна + + + + Internal Server Error + Вътрешна грешка на сървъра + + + + System shutdown + Изключване на системата + + + + Conflict + + + + + Unknown + + + + + Add Friend + Добави приятел + + + + Enter Xmpp ID: + Въведи Xmpp ID: + + + + Add Friend... + Добави приятел... + + + + XML Console... + XML Конзола... + + + + I'm sorry -- I'm just an automatic presence used by Tomahawk Player (http://gettomahawk.com). If you are getting this message, the person you are trying to reach is probably not signed on, so please try again later! + Извинявай.. Аз съм режимът за автоматични отговори изпълзван от Tomahawk. (http://gettomahawk.com) Щом получаваш това съобщение, този с който се опитваш да се свържеш вероятно не е на линия. Моля, потай отново по-късно. + + + + Authorize User + Оправомощяване на потребител + + + + Do you want to grant <b>%1</b> access to your Collection? + Искате ли да позволите на <b>%1</b> достъп до вашата колекция? + + + + ZeroconfConfig + + + Form + + + + + Local Network configuration + Настройка на локалната мрежа + + + + This plugin will automatically find other users running Tomahawk on your local network + Тази приставка, автоматично ще открие другите потребители +ползващи Tomahawk в локалната мрежа + + + + Connect automatically when Tomahawk starts + Свържи се автоматично при стартиране + + + diff --git a/lang/tomahawk_i18n.qrc b/lang/tomahawk_i18n.qrc index 5bb43cef2..e38135fbc 100644 --- a/lang/tomahawk_i18n.qrc +++ b/lang/tomahawk_i18n.qrc @@ -4,6 +4,7 @@ tomahawk_de.qm tomahawk_sv.qm tomahawk_es.qm +tomahawk_bg.qm tomahawk_pl.qm tomahawk_pt_BR.qm From 79bfdec895f4b04af30d89660e6fa82f8fa42930 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 30 Mar 2012 17:14:08 -0400 Subject: [PATCH 42/59] TWK-798: Start playing first resolvable track when double-clicking on a playlist item --- src/libtomahawk/CMakeLists.txt | 2 + src/libtomahawk/playlist/trackview.cpp | 71 +++++++- src/libtomahawk/playlist/trackview.h | 10 ++ src/libtomahawk/utils/closure.cpp | 89 ++++++++++ src/libtomahawk/utils/closure.h | 225 +++++++++++++++++++++++++ src/sourcetree/items/playlistitems.cpp | 12 ++ src/sourcetree/items/playlistitems.h | 5 +- src/sourcetree/items/sourcetreeitem.h | 1 + src/sourcetree/sourcedelegate.cpp | 23 ++- src/sourcetree/sourcedelegate.h | 2 + src/sourcetree/sourcetreeview.cpp | 13 ++ src/sourcetree/sourcetreeview.h | 1 + 12 files changed, 451 insertions(+), 3 deletions(-) create mode 100644 src/libtomahawk/utils/closure.cpp create mode 100644 src/libtomahawk/utils/closure.h diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index 55fbc8da8..bde94eb52 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -116,6 +116,7 @@ set( libGuiSources utils/dropjobnotifier.cpp utils/proxystyle.cpp utils/tomahawkutilsgui.cpp + utils/closure.cpp widgets/checkdirtree.cpp widgets/querylabel.cpp @@ -240,6 +241,7 @@ set( libGuiHeaders utils/rdioparser.h utils/shortenedlinkparser.h utils/dropjobnotifier.h + utils/closure.h widgets/checkdirtree.h widgets/querylabel.h diff --git a/src/libtomahawk/playlist/trackview.cpp b/src/libtomahawk/playlist/trackview.cpp index 7111cd68c..603d38895 100644 --- a/src/libtomahawk/playlist/trackview.cpp +++ b/src/libtomahawk/playlist/trackview.cpp @@ -32,6 +32,7 @@ #include "dynamic/widgets/LoadingSpinner.h" #include "utils/tomahawkutils.h" #include "utils/logger.h" +#include "utils/closure.h" #include "dropjob.h" #include "artist.h" #include "album.h" @@ -152,6 +153,41 @@ TrackView::setTrackModel( TrackModel* model ) } +void +TrackView::startPlayingFromStart() +{ + if ( m_proxyModel->rowCount() == 0 ) + return; + + const QModelIndex index = m_proxyModel->index( 0, 0 ); + startAutoPlay( index ); +} + + +void +TrackView::autoPlayResolveFinished( const query_ptr& query, int row ) +{ + Q_ASSERT( !query.isNull() ); + Q_ASSERT( row >= 0 ); + + if ( query.isNull() || row < 0 || query != m_autoPlaying ) + return; + + const QModelIndex index = m_proxyModel->index( row, 0 ); + if ( query->playable() ) + { + onItemActivated( index ); + return; + } + + // Try the next one.. + const QModelIndex sib = index.sibling( index.row() + 1, index.column() ); + if ( sib.isValid() ) + startAutoPlay( sib ); + +} + + void TrackView::currentChanged( const QModelIndex& current, const QModelIndex& previous ) { @@ -174,15 +210,48 @@ TrackView::onItemActivated( const QModelIndex& index ) if ( !index.isValid() ) return; + tryToPlayItem( index ); + emit itemActivated( index ); +} + + +void +TrackView::startAutoPlay( const QModelIndex& index ) +{ + if ( tryToPlayItem( index ) ) + return; + + // item isn't playable but still resolving + TrackModelItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( index ) ); + if ( item && !item->query().isNull() && !item->query()->resolvingFinished() ) + { + m_autoPlaying = item->query(); // So we can kill it if user starts autoplaying this playlist again + NewClosure( item->query().data(), SIGNAL( resolvingFinished( bool ) ), this, SLOT( autoPlayResolveFinished( Tomahawk::query_ptr, int ) ), + item->query(), index.row() ); + return; + } + + // not playable at all, try next + const QModelIndex sib = index.sibling( index.row() + 1, index.column() ); + if ( sib.isValid() ) + startAutoPlay( sib ); +} + + +bool +TrackView::tryToPlayItem( const QModelIndex& index ) +{ TrackModelItem* item = m_model->itemFromIndex( m_proxyModel->mapToSource( index ) ); if ( item && !item->query().isNull() && item->query()->numResults() ) { tDebug() << "Result activated:" << item->query()->toString() << item->query()->results().first()->url(); m_proxyModel->setCurrentIndex( index ); AudioEngine::instance()->playItem( m_proxyModel->playlistInterface(), item->query()->results().first() ); + + return true; } - emit itemActivated( index ); + return false; } diff --git a/src/libtomahawk/playlist/trackview.h b/src/libtomahawk/playlist/trackview.h index 45bb1b23c..8e8724da1 100644 --- a/src/libtomahawk/playlist/trackview.h +++ b/src/libtomahawk/playlist/trackview.h @@ -64,6 +64,9 @@ public: bool updatesContextView() const { return m_updateContextView; } void setUpdatesContextView( bool b ) { m_updateContextView = b; } + // Starts playing from the beginning if resolved, or waits until a track is playable + void startPlayingFromStart(); + public slots: virtual void onItemActivated( const QModelIndex& index ); @@ -98,7 +101,11 @@ private slots: void onCustomContextMenu( const QPoint& pos ); + void autoPlayResolveFinished( const Tomahawk::query_ptr& query, int row ); + private: + void startAutoPlay( const QModelIndex& index ); + bool tryToPlayItem( const QModelIndex& index ); void updateHoverIndex( const QPoint& pos ); QString m_guid; @@ -117,6 +124,9 @@ private: QModelIndex m_hoveredIndex; QModelIndex m_contextMenuIndex; + + Tomahawk::query_ptr m_autoPlaying; + Tomahawk::ContextMenu* m_contextMenu; }; diff --git a/src/libtomahawk/utils/closure.cpp b/src/libtomahawk/utils/closure.cpp new file mode 100644 index 000000000..8a68b63e1 --- /dev/null +++ b/src/libtomahawk/utils/closure.cpp @@ -0,0 +1,89 @@ +/* This file is part of Clementine. + Copyright 2011, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#include "closure.h" + +namespace _detail { + +Closure::Closure(QObject* sender, + const char* signal, + QObject* receiver, + const char* slot, + const ClosureArgumentWrapper* val0, + const ClosureArgumentWrapper* val1, + const ClosureArgumentWrapper* val2, + const ClosureArgumentWrapper* val3) + : QObject(receiver), + callback_(NULL), + val0_(val0), + val1_(val1), + val2_(val2), + val3_(val3) { + const QMetaObject* meta_receiver = receiver->metaObject(); + + QByteArray normalised_slot = QMetaObject::normalizedSignature(slot + 1); + const int index = meta_receiver->indexOfSlot(normalised_slot.constData()); + Q_ASSERT(index != -1); + slot_ = meta_receiver->method(index); + + Connect(sender, signal); +} + +Closure::Closure(QObject* sender, + const char* signal, + std::tr1::function callback) + : callback_(callback) { + Connect(sender, signal); +} + +Closure::~Closure() { +} + +void Closure::Connect(QObject* sender, const char* signal) { + bool success = connect(sender, signal, SLOT(Invoked())); + Q_ASSERT(success); + success = connect(sender, SIGNAL(destroyed()), SLOT(Cleanup())); + Q_ASSERT(success); + Q_UNUSED(success); +} + +void Closure::Invoked() { + if (callback_) { + callback_(); + } else { + slot_.invoke( + parent(), + val0_ ? val0_->arg() : QGenericArgument(), + val1_ ? val1_->arg() : QGenericArgument(), + val2_ ? val2_->arg() : QGenericArgument(), + val3_ ? val3_->arg() : QGenericArgument()); + } + deleteLater(); +} + +void Closure::Cleanup() { + disconnect(); + deleteLater(); +} + +} // namespace _detail + +_detail::Closure* NewClosure( + QObject* sender, const char* signal, + QObject* receiver, const char* slot) { + return new _detail::Closure(sender, signal, receiver, slot); +} diff --git a/src/libtomahawk/utils/closure.h b/src/libtomahawk/utils/closure.h new file mode 100644 index 000000000..8458bbb36 --- /dev/null +++ b/src/libtomahawk/utils/closure.h @@ -0,0 +1,225 @@ +/* This file is part of Clementine. + Copyright 2011, David Sansome + + Clementine is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Clementine is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Clementine. If not, see . +*/ + +#ifndef CLOSURE_H +#define CLOSURE_H + +#include + +#include +#include +#include + +#include +#include + +namespace _detail { + +class ClosureArgumentWrapper { + public: + virtual ~ClosureArgumentWrapper() {} + + virtual QGenericArgument arg() const = 0; +}; + +template +class ClosureArgument : public ClosureArgumentWrapper { + public: + explicit ClosureArgument(const T& data) : data_(data) {} + + virtual QGenericArgument arg() const { + return Q_ARG(T, data_); + } + + private: + T data_; +}; + +class Closure : public QObject, boost::noncopyable { + Q_OBJECT + + public: + Closure(QObject* sender, const char* signal, + QObject* receiver, const char* slot, + const ClosureArgumentWrapper* val0 = 0, + const ClosureArgumentWrapper* val1 = 0, + const ClosureArgumentWrapper* val2 = 0, + const ClosureArgumentWrapper* val3 = 0); + + Closure(QObject* sender, const char* signal, + std::tr1::function callback); + + virtual ~Closure(); + + private slots: + void Invoked(); + void Cleanup(); + + private: + void Connect(QObject* sender, const char* signal); + + QMetaMethod slot_; + std::tr1::function callback_; + + boost::scoped_ptr val0_; + boost::scoped_ptr val1_; + boost::scoped_ptr val2_; + boost::scoped_ptr val3_; +}; + +class SharedPointerWrapper { + public: + virtual ~SharedPointerWrapper() {} + virtual QObject* data() const = 0; +}; + +template +class SharedPointer : public SharedPointerWrapper { + public: + explicit SharedPointer(QSharedPointer ptr) + : ptr_(ptr) { + } + + QObject* data() const { + return ptr_.data(); + } + + private: + QSharedPointer ptr_; +}; + +// For use with a QSharedPointer as a sender. +class SharedClosure : public Closure { + Q_OBJECT + + public: + SharedClosure(SharedPointerWrapper* sender, const char* signal, + QObject* receiver, const char* slot, + const ClosureArgumentWrapper* val0 = 0, + const ClosureArgumentWrapper* val1 = 0, + const ClosureArgumentWrapper* val2 = 0, + const ClosureArgumentWrapper* val3 = 0) + : Closure(sender->data(), signal, + receiver, slot, + val0, val1, val2, val3), + shared_sender_(sender) { + } + + private: + boost::scoped_ptr shared_sender_; +}; + +} // namespace _detail + +#define C_ARG(type, data) new _detail::ClosureArgument(data) + +_detail::Closure* NewClosure( + QObject* sender, + const char* signal, + QObject* receiver, + const char* slot); + +template +_detail::Closure* NewClosure( + QObject* sender, + const char* signal, + QObject* receiver, + const char* slot, + const T& val0) { + return new _detail::Closure( + sender, signal, receiver, slot, + C_ARG(T, val0)); +} + +template +_detail::Closure* NewClosure( + QObject* sender, + const char* signal, + QObject* receiver, + const char* slot, + const T0& val0, + const T1& val1) { + return new _detail::Closure( + sender, signal, receiver, slot, + C_ARG(T0, val0), C_ARG(T1, val1)); +} + +template +_detail::Closure* NewClosure( + QObject* sender, + const char* signal, + QObject* receiver, + const char* slot, + const T0& val0, + const T1& val1, + const T2& val2) { + return new _detail::Closure( + sender, signal, receiver, slot, + C_ARG(T0, val0), C_ARG(T1, val1), C_ARG(T2, val2)); +} + +template +_detail::Closure* NewClosure( + QObject* sender, + const char* signal, + QObject* receiver, + const char* slot, + const T0& val0, + const T1& val1, + const T2& val2, + const T3& val3) { + return new _detail::Closure( + sender, signal, receiver, slot, + C_ARG(T0, val0), C_ARG(T1, val1), C_ARG(T2, val2), C_ARG(T3, val3)); +} + +template +_detail::Closure* NewClosure( + QSharedPointer sender, + const char* signal, + QObject* receiver, + const char* slot) { + return new _detail::SharedClosure( + new _detail::SharedPointer(sender), signal, receiver, slot); +} + +template +_detail::Closure* NewClosure( + QSharedPointer sender, + const char* signal, + QObject* receiver, + const char* slot, + const T0& val0) { + return new _detail::SharedClosure( + new _detail::SharedPointer(sender), signal, receiver, slot, + C_ARG(T0, val0)); +} + +template +_detail::Closure* NewClosure( + QSharedPointer sender, + const char* signal, + QObject* receiver, + const char* slot, + const T0& val0, + const T1& val1) { + return new _detail::SharedClosure( + new _detail::SharedPointer(sender), signal, receiver, slot, + C_ARG(T0, val0), C_ARG(T1, val1)); +} + +#endif // CLOSURE_H diff --git a/src/sourcetree/items/playlistitems.cpp b/src/sourcetree/items/playlistitems.cpp index 1df14c381..3f0cb4b2e 100644 --- a/src/sourcetree/items/playlistitems.cpp +++ b/src/sourcetree/items/playlistitems.cpp @@ -24,6 +24,7 @@ #include "query.h" #include "viewmanager.h" #include "playlist/dynamic/GeneratorInterface.h" +#include "playlist/playlistview.h" #include "categoryitems.h" #include "sourceitem.h" #include "utils/tomahawkutils.h" @@ -136,6 +137,17 @@ PlaylistItem::activate() } +void +PlaylistItem::doubleClicked() +{ + ViewPage* p = ViewManager::instance()->currentPage(); + if ( PlaylistView* view = dynamic_cast< PlaylistView* >( p ) ) + { + view->startPlayingFromStart(); + } +} + + void PlaylistItem::setLoaded( bool loaded ) { diff --git a/src/sourcetree/items/playlistitems.h b/src/sourcetree/items/playlistitems.h index dad5da151..860eeffe7 100644 --- a/src/sourcetree/items/playlistitems.h +++ b/src/sourcetree/items/playlistitems.h @@ -31,7 +31,6 @@ public: virtual QString text() const; virtual Tomahawk::playlist_ptr playlist() const; virtual Qt::ItemFlags flags() const; - virtual void activate(); virtual bool willAcceptDrag( const QMimeData* data ) const; virtual DropTypes supportedDropTypes( const QMimeData* data ) const; virtual bool dropMimeData( const QMimeData* data, Qt::DropAction action ); @@ -43,6 +42,10 @@ public: virtual SourceTreeItem* activateCurrent(); +public slots: + virtual void activate(); + virtual void doubleClicked(); + protected: void setLoaded( bool loaded ); diff --git a/src/sourcetree/items/sourcetreeitem.h b/src/sourcetree/items/sourcetreeitem.h index adde55609..9fb0299cf 100644 --- a/src/sourcetree/items/sourcetreeitem.h +++ b/src/sourcetree/items/sourcetreeitem.h @@ -78,6 +78,7 @@ public: public slots: virtual void activate() {} + virtual void doubleClicked() {} signals: void updated(); diff --git a/src/sourcetree/sourcedelegate.cpp b/src/sourcetree/sourcedelegate.cpp index 6cd00ce65..ccd27c673 100644 --- a/src/sourcetree/sourcedelegate.cpp +++ b/src/sourcetree/sourcedelegate.cpp @@ -43,6 +43,7 @@ SourceDelegate::SourceDelegate( QAbstractItemView* parent ) : QStyledItemDelegate( parent ) , m_parent( parent ) + , m_lastClicked( -1 ) { m_dropTypeMap.insert( 0, SourceTreeItem::DropTypeThisTrack ); m_dropTypeMap.insert( 1, SourceTreeItem::DropTypeThisAlbum ); @@ -631,7 +632,27 @@ SourceDelegate::editorEvent( QEvent* event, QAbstractItemModel* model, const QSt // a mouse press event. Since we want to swallow click events when they are on headphones other action items, here wemake sure we only // emit if we really want to if ( event->type() == QEvent::MouseButtonRelease ) - emit clicked( index ); + { + if ( m_lastClicked == -1 ) + { + m_lastClicked = QDateTime::currentMSecsSinceEpoch(); + emit clicked( index ); + } + else + { + qint64 elapsed = QDateTime::currentMSecsSinceEpoch() - m_lastClicked; + if ( elapsed < QApplication::doubleClickInterval() ) + { + m_lastClicked = -1; + emit doubleClicked( index ); + } else + { + m_lastClicked = QDateTime::currentMSecsSinceEpoch(); + emit clicked( index ); + } + } + + } return QStyledItemDelegate::editorEvent ( event, model, option, index ); } diff --git a/src/sourcetree/sourcedelegate.h b/src/sourcetree/sourcedelegate.h index d7a1d3ef6..051c0c0db 100644 --- a/src/sourcetree/sourcedelegate.h +++ b/src/sourcetree/sourcedelegate.h @@ -43,6 +43,7 @@ public: signals: void clicked( const QModelIndex& idx ); + void doubleClicked( const QModelIndex& idx ); void latchOn( const Tomahawk::source_ptr& idx ); void latchOff( const Tomahawk::source_ptr& idx ); void toggleRealtimeLatch( const Tomahawk::source_ptr& idx, bool realtime ); @@ -72,6 +73,7 @@ private: mutable SourceTreeItem::DropType m_hoveredDropType; // Hack to keep easily track of the current highlighted DropType in paint() QMap< QModelIndex, AnimationHelper* > m_expandedMap; QPixmap m_headphonesOn, m_headphonesOff, m_realtimeLocked, m_realtimeUnlocked, m_nowPlayingSpeaker, m_nowPlayingSpeakerDark; + qint64 m_lastClicked; QMap< int, SourceTreeItem::DropType > m_dropTypeMap; QMap< int, QString > m_dropTypeTextMap; diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp index ced9bda00..6e1d08ddc 100644 --- a/src/sourcetree/sourcetreeview.cpp +++ b/src/sourcetree/sourcetreeview.cpp @@ -78,6 +78,7 @@ SourceTreeView::SourceTreeView( QWidget* parent ) sortByColumn( 0, Qt::AscendingOrder ); setVerticalScrollMode( QTreeView::ScrollPerPixel ); setMouseTracking( true ); + setEditTriggers( NoEditTriggers ); // TODO animation conflicts with the expanding-playlists-when-collection-is-null // so investigate @@ -88,6 +89,7 @@ SourceTreeView::SourceTreeView( QWidget* parent ) connect( m_delegate, SIGNAL( latchOff( Tomahawk::source_ptr ) ), SLOT( latchOff( Tomahawk::source_ptr ) ) ); connect( m_delegate, SIGNAL( toggleRealtimeLatch( Tomahawk::source_ptr, bool ) ), m_latchManager, SLOT( latchModeChangeRequest( Tomahawk::source_ptr,bool ) ) ); connect( m_delegate, SIGNAL( clicked( QModelIndex ) ), SLOT( onItemActivated( QModelIndex ) ) ); + connect( m_delegate, SIGNAL( doubleClicked( QModelIndex ) ), SLOT( onItemDoubleClicked( QModelIndex ) ) ); setItemDelegate( m_delegate ); @@ -230,6 +232,17 @@ SourceTreeView::onItemActivated( const QModelIndex& index ) } +void +SourceTreeView::onItemDoubleClicked( const QModelIndex& idx ) +{ + if ( !selectionModel()->selectedIndexes().contains( idx ) ) + onItemActivated( idx ); + + SourceTreeItem* item = itemFromIndex< SourceTreeItem >( idx ); + item->doubleClicked(); +} + + void SourceTreeView::onItemExpanded( const QModelIndex& idx ) { diff --git a/src/sourcetree/sourcetreeview.h b/src/sourcetree/sourcetreeview.h index 0d6a9b7b1..4a33f7c21 100644 --- a/src/sourcetree/sourcetreeview.h +++ b/src/sourcetree/sourcetreeview.h @@ -66,6 +66,7 @@ private slots: void selectRequest( const QPersistentModelIndex& idx ); void expandRequest( const QPersistentModelIndex& idx ); void toggleExpandRequest( const QPersistentModelIndex& idx ); + void onItemDoubleClicked( const QModelIndex& idx ); void loadPlaylist(); void deletePlaylist( const QModelIndex& = QModelIndex() ); From 9c5966000c97430a0e667fd9b5b08e0dc1703fbb Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Fri, 30 Mar 2012 17:47:28 -0400 Subject: [PATCH 43/59] TWK-799: Don't set autoupdate when loading playlist view --- src/libtomahawk/infobar/infobar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libtomahawk/infobar/infobar.cpp b/src/libtomahawk/infobar/infobar.cpp index 4296b75ae..bdfe8bd74 100644 --- a/src/libtomahawk/infobar/infobar.cpp +++ b/src/libtomahawk/infobar/infobar.cpp @@ -85,7 +85,7 @@ InfoBar::InfoBar( QWidget* parent ) m_autoUpdate->setText( tr( "Automatically update" ) ); m_autoUpdate->setLayoutDirection( Qt::RightToLeft ); m_autoUpdate->setPalette( whitePal ); - connect( m_autoUpdate, SIGNAL( stateChanged( int ) ), this, SIGNAL( autoUpdateChanged( int ) ) ); + connect( m_autoUpdate, SIGNAL( toggled(bool) ), this, SIGNAL( autoUpdateChanged( int ) ) ); ui->horizontalLayout->addWidget( m_autoUpdate ); From 87086e527880f48d0687c90b4185d1fca4b83640 Mon Sep 17 00:00:00 2001 From: Kevin Funk Date: Wed, 28 Mar 2012 23:16:21 +0200 Subject: [PATCH 44/59] Make compile on ARM (related to breakpad) Make breakpad optional, add options Same for CrashReporter - both don't work on ARM. --- CMakeLists.txt | 19 +++++++++++++------ src/CMakeLists.txt | 14 +++++++++++--- src/config.h.in | 3 +++ src/main.cpp | 4 ++++ thirdparty/CMakeLists.txt | 4 +++- 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f21fd37f5..a9cb28650 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,8 +26,21 @@ add_definitions( "-fvisibility=hidden" ) # build options option(BUILD_GUI "Build Tomahawk with GUI" ON) option(BUILD_RELEASE "Generate TOMAHAWK_VERSION without GIT info" OFF) +option(WITH_BREAKPAD "Build with breakpad integration" ON) +option(WITH_CRASHREPORTER "Build with CrashReporter" ON) option(LEGACY_KDE_INTEGRATION "Install tomahawk.protocol file, deprecated since 4.6.0" OFF) +IF( CMAKE_SYSTEM_PROCESSOR MATCHES "arm" ) + message(STATUS "Build of breakpad library disabled on this platform.") + SET(WITH_BREAKPAD OFF) + SET(WITH_CRASHREPORTER OFF) +ENDIF() + +# add definitions based on build options +IF(WITH_BREAKPAD) + message(STATUS "Build with support for breakpad.") +ENDIF() + # generate version string # base string used in release and unstable builds @@ -200,9 +213,3 @@ ADD_SUBDIRECTORY( src/libtomahawk ) SET( TOMAHAWK_LIBRARIES tomahawklib ) ADD_SUBDIRECTORY( src ) ADD_SUBDIRECTORY( admin ) - -IF( BUILD_GUI ) - IF( NOT DISABLE_CRASHREPORTER ) - ADD_SUBDIRECTORY( src/breakpad/CrashReporter ) - ENDIF() -ENDIF() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 669440e86..bc677d1e4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -68,8 +68,6 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} sourcetree/items/groupitem.cpp sourcetree/items/historyitem.cpp - breakpad/BreakPad.cpp - utils/guihelpers.cpp accounts/lastfm/LastFmAccount.cpp @@ -91,6 +89,10 @@ SET( tomahawkSourcesGui ${tomahawkSourcesGui} AccountFactoryWrapperDelegate.cpp ) +IF( WITH_BREAKPAD ) + LIST(APPEND tomahawkSourcesGui breakpad/BreakPad.cpp) +ENDIF() + SET( tomahawkUI ${tomahawkUI} tomahawkwindow.ui diagnosticsdialog.ui @@ -171,6 +173,10 @@ SET( final_src ${final_src} ${tomahawkMoc} ${tomahawkSources} ${trans_outfile}) IF( BUILD_GUI ) LIST(APPEND tomahawkSources ${tomahawkSourcesGui}) qt4_wrap_ui( tomahawkUI_H ${tomahawkUI} ) + + IF( WITH_CRASHREPORTER ) + ADD_SUBDIRECTORY( breakpad/CrashReporter ) + ENDIF() ENDIF() kde4_add_app_icon( tomahawkSources "${CMAKE_SOURCE_DIR}/data/icons/tomahawk-icon-*.png" ) @@ -203,9 +209,11 @@ ENDIF(GLOOX_FOUND) IF(QCA2_FOUND) SET(LINK_LIBRARIES ${LINK_LIBRARIES} ${QCA2_LIBRARIES} ) ENDIF(QCA2_FOUND) +IF(WITH_BREAKPAD) + SET(LINK_LIBRARIES ${LINK_LIBRARIES} tomahawk_breakpad) +ENDIF() TARGET_LINK_LIBRARIES( tomahawk - tomahawk_breakpad ${LINK_LIBRARIES} ${TOMAHAWK_LIBRARIES} ${PHONON_LIBS} diff --git a/src/config.h.in b/src/config.h.in index 0cdbb948e..87ec9b48d 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -17,6 +17,9 @@ #cmakedefine LEOPARD #cmakedefine HAVE_SPARKLE +#cmakedefine WITH_BREAKPAD +#cmakedefine WITH_CRASHREPORTER + #cmakedefine LIBLASTFM_FOUND #cmakedefine GLOOX_FOUND #cmakedefine QCA2_FOUND diff --git a/src/main.cpp b/src/main.cpp index f25a34a58..a8c74a8d4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -22,6 +22,7 @@ #include "thirdparty/kdsingleapplicationguard/kdsingleapplicationguard.h" #include "ubuntuunityhack.h" #include "tomahawksettings.h" +#include "config.h" #include @@ -123,8 +124,11 @@ main( int argc, char *argv[] ) new TomahawkSettingsGui( &a ); #endif + #ifndef ENABLE_HEADLESS +#ifdef WITH_BREAKPAD new BreakPad( QDir::tempPath(), TomahawkSettings::instance()->crashReporterEnabled() ); +#endif #endif KDSingleApplicationGuard guard( &a, KDSingleApplicationGuard::AutoKillOtherInstances ); diff --git a/thirdparty/CMakeLists.txt b/thirdparty/CMakeLists.txt index c1ddb6515..9612d4e16 100644 --- a/thirdparty/CMakeLists.txt +++ b/thirdparty/CMakeLists.txt @@ -1,6 +1,8 @@ ADD_SUBDIRECTORY( qxt ) ADD_SUBDIRECTORY( liblastfm2 ) -ADD_SUBDIRECTORY( breakpad ) +IF( WITH_BREAKPAD ) + ADD_SUBDIRECTORY( breakpad ) +ENDIF() IF( APPLE ) ADD_SUBDIRECTORY( SPMediaKeyTap ) ENDIF() From c3e39444217e27ca42cf65012c91b265a9e9f4f4 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 31 Mar 2012 05:17:07 +0200 Subject: [PATCH 45/59] * Added stop-after-track context menu entry. --- src/libtomahawk/audio/audioengine.cpp | 26 +++++++++++++++++---- src/libtomahawk/audio/audioengine.h | 6 ++++- src/libtomahawk/contextmenu.cpp | 18 ++++++++++++-- src/libtomahawk/contextmenu.h | 3 ++- src/libtomahawk/playlist/trackmodelitem.cpp | 5 +--- src/libtomahawk/playlist/trackview.cpp | 7 +++++- src/libtomahawk/query.cpp | 9 ++++--- src/libtomahawk/result.h | 1 + src/libtomahawk/widgets/querylabel.cpp | 2 +- 9 files changed, 59 insertions(+), 18 deletions(-) diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 6ea43c6e8..385891a0c 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -516,6 +516,16 @@ AudioEngine::loadNextTrack() Tomahawk::result_ptr result; + if ( !m_stopAfterTrack.isNull() && !m_currentTrack.isNull() ) + { + if ( m_stopAfterTrack.data() == m_currentTrack->toQuery().data() ) + { + m_stopAfterTrack.clear(); + stop(); + return; + } + } + if ( m_queue && m_queue->trackCount() ) { result = m_queue->nextItem(); @@ -555,7 +565,9 @@ AudioEngine::playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk: m_currentTrackPlaylist = playlist; if ( !result.isNull() ) + { loadTrack( result ); + } else if ( !m_playlist.isNull() && m_playlist.data()->retryMode() == PlaylistInterface::Retry ) { m_waitingOnNewTrack = true; @@ -678,6 +690,9 @@ AudioEngine::timerTriggered( qint64 time ) void AudioEngine::setPlaylist( Tomahawk::playlistinterface_ptr playlist ) { + if ( m_playlist == playlist ) + return; + if ( !m_playlist.isNull() ) { if ( m_playlist.data() && m_playlist.data()->retryMode() == PlaylistInterface::Retry ) @@ -691,8 +706,9 @@ AudioEngine::setPlaylist( Tomahawk::playlistinterface_ptr playlist ) emit playlistChanged( playlist ); return; } - + m_playlist = playlist; + m_stopAfterTrack.clear(); if ( !m_playlist.isNull() && m_playlist.data() && m_playlist.data()->retryMode() == PlaylistInterface::Retry ) connect( m_playlist.data(), SIGNAL( nextTrackReady() ), SLOT( onPlaylistNextTrackReady() ) ); @@ -704,16 +720,16 @@ AudioEngine::setPlaylist( Tomahawk::playlistinterface_ptr playlist ) void AudioEngine::setCurrentTrack( const Tomahawk::result_ptr& result ) { - m_lastTrack = m_currentTrack; - if ( !m_lastTrack.isNull() ) + Tomahawk::result_ptr lastTrack = m_currentTrack; + if ( !lastTrack.isNull() ) { if ( TomahawkSettings::instance()->privateListeningMode() == TomahawkSettings::PublicListening ) { - DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( m_lastTrack, DatabaseCommand_LogPlayback::Finished, m_timeElapsed ); + DatabaseCommand_LogPlayback* cmd = new DatabaseCommand_LogPlayback( lastTrack, DatabaseCommand_LogPlayback::Finished, m_timeElapsed ); Database::instance()->enqueue( QSharedPointer(cmd) ); } - emit finished( m_lastTrack ); + emit finished( lastTrack ); } m_currentTrack = result; diff --git a/src/libtomahawk/audio/audioengine.h b/src/libtomahawk/audio/audioengine.h index 3c6400229..4928fd6c4 100644 --- a/src/libtomahawk/audio/audioengine.h +++ b/src/libtomahawk/audio/audioengine.h @@ -64,6 +64,8 @@ public: Tomahawk::playlistinterface_ptr playlist() const { return m_playlist; } Tomahawk::result_ptr currentTrack() const { return m_currentTrack; } + + Tomahawk::query_ptr stopAfterTrack() const { return m_stopAfterTrack; } qint64 currentTime() const { return m_mediaObject->currentTime(); } qint64 currentTrackTotalTime() const { return m_mediaObject->totalTime(); } @@ -91,6 +93,8 @@ public slots: void playItem( Tomahawk::playlistinterface_ptr playlist, const Tomahawk::result_ptr& result ); void setPlaylist( Tomahawk::playlistinterface_ptr playlist ); void setQueue( Tomahawk::playlistinterface_ptr queue ) { m_queue = queue; } + + void setStopAfterTrack( const Tomahawk::query_ptr& query ) { m_stopAfterTrack = query; } signals: void loading( const Tomahawk::result_ptr& track ); @@ -141,8 +145,8 @@ private: QSharedPointer m_input; + Tomahawk::query_ptr m_stopAfterTrack; Tomahawk::result_ptr m_currentTrack; - Tomahawk::result_ptr m_lastTrack; Tomahawk::playlistinterface_ptr m_playlist; Tomahawk::playlistinterface_ptr m_currentTrackPlaylist; Tomahawk::playlistinterface_ptr m_queue; diff --git a/src/libtomahawk/contextmenu.cpp b/src/libtomahawk/contextmenu.cpp index de5122a05..b64dca517 100644 --- a/src/libtomahawk/contextmenu.cpp +++ b/src/libtomahawk/contextmenu.cpp @@ -37,7 +37,7 @@ ContextMenu::ContextMenu( QWidget* parent ) m_sigmap = new QSignalMapper( this ); connect( m_sigmap, SIGNAL( mapped( int ) ), SLOT( onTriggered( int ) ) ); - m_supportedActions = ActionPlay | ActionQueue | ActionCopyLink | ActionLove; + m_supportedActions = ActionPlay | ActionQueue | ActionCopyLink | ActionLove | ActionStopAfter; } @@ -80,6 +80,14 @@ ContextMenu::setQueries( const QList& queries ) if ( m_supportedActions & ActionQueue ) m_sigmap->setMapping( addAction( tr( "Add to &Queue" ) ), ActionQueue ); + if ( m_supportedActions & ActionStopAfter && itemCount() == 1 ) + { + if ( AudioEngine::instance()->stopAfterTrack() == queries.first() ) + m_sigmap->setMapping( addAction( tr( "&Continue playback after this track" ) ), ActionStopAfter ); + else + m_sigmap->setMapping( addAction( tr( "&Stop playback after this track" ) ), ActionStopAfter ); + } + addSeparator(); if ( m_supportedActions & ActionLove && itemCount() == 1 ) @@ -110,7 +118,6 @@ ContextMenu::setQueries( const QList& queries ) void ContextMenu::setQuery( const Tomahawk::query_ptr& query ) { - QList queries; queries << query; setQueries( queries ); @@ -212,6 +219,13 @@ ContextMenu::onTriggered( int action ) m_queries.first()->setLoved( !m_queries.first()->loved() ); break; + case ActionStopAfter: + if ( AudioEngine::instance()->stopAfterTrack() == m_queries.first() ) + AudioEngine::instance()->setStopAfterTrack( query_ptr() ); + else + AudioEngine::instance()->setStopAfterTrack( m_queries.first() ); + break; + default: emit triggered( action ); } diff --git a/src/libtomahawk/contextmenu.h b/src/libtomahawk/contextmenu.h index 467faeeb2..f077a4f04 100644 --- a/src/libtomahawk/contextmenu.h +++ b/src/libtomahawk/contextmenu.h @@ -40,7 +40,8 @@ public: ActionQueue = 2, ActionDelete = 4, ActionCopyLink = 8, - ActionLove = 16 + ActionLove = 16, + ActionStopAfter = 32 }; explicit ContextMenu( QWidget* parent = 0 ); diff --git a/src/libtomahawk/playlist/trackmodelitem.cpp b/src/libtomahawk/playlist/trackmodelitem.cpp index 18f0c5126..4a02431cf 100644 --- a/src/libtomahawk/playlist/trackmodelitem.cpp +++ b/src/libtomahawk/playlist/trackmodelitem.cpp @@ -82,10 +82,7 @@ TrackModelItem::entry() const const Tomahawk::query_ptr& TrackModelItem::query() const { - if ( !m_entry.isNull() ) - return m_entry->query(); - else - return m_query; + return m_query; } diff --git a/src/libtomahawk/playlist/trackview.cpp b/src/libtomahawk/playlist/trackview.cpp index af79f853d..35ed48376 100644 --- a/src/libtomahawk/playlist/trackview.cpp +++ b/src/libtomahawk/playlist/trackview.cpp @@ -558,7 +558,12 @@ TrackView::onCustomContextMenu( const QPoint& pos ) TrackModelItem* item = proxyModel()->itemFromIndex( proxyModel()->mapToSource( index ) ); if ( item && !item->query().isNull() ) - queries << item->query(); + { + if ( item->query()->numResults() > 0 ) + queries << item->query()->results().first()->toQuery(); + else + queries << item->query(); + } } m_contextMenu->setQueries( queries ); diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index 7d7f41846..a381fc343 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -58,7 +58,6 @@ Query::get( const QString& artist, const QString& track, const QString& album, c query_ptr Query::get( const QString& query, const QID& qid ) { - query_ptr q = query_ptr( new Query( query, qid ), &QObject::deleteLater ); q->setWeakRef( q.toWeakRef() ); @@ -164,10 +163,12 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults ) m_results << newresults; qStableSort( m_results.begin(), m_results.end(), Query::resultSorter ); + query_ptr q = m_ownRef.toStrongRef(); // hook up signals, and check solved status foreach( const result_ptr& rp, newresults ) { + rp->setQuery( q ); connect( rp.data(), SIGNAL( statusChanged() ), SLOT( onResultStatusChanged() ) ); } } @@ -538,7 +539,7 @@ Query::parseSocialActions() { Tomahawk::SocialAction socialAction; socialAction = it.next(); - if ( socialAction.timestamp.toUInt() > highestTimestamp && socialAction.source->id() == SourceList::instance()->getLocal()->id() ) + if ( socialAction.timestamp.toUInt() > highestTimestamp && socialAction.source->isLocal() ) { m_currentSocialActions[ socialAction.action.toString() ] = socialAction.value.toBool(); } @@ -568,7 +569,7 @@ Query::setLoved( bool loved ) query_ptr q = m_ownRef.toStrongRef(); if ( q ) { - m_currentSocialActions[ "Loved" ] = loved; + m_currentSocialActions[ "Love" ] = loved; Tomahawk::InfoSystem::InfoStringHash trackInfo; trackInfo["title"] = track(); @@ -581,6 +582,8 @@ Query::setLoved( bool loved ) DatabaseCommand_SocialAction* cmd = new DatabaseCommand_SocialAction( q, QString( "Love" ), loved ? QString( "true" ) : QString( "false" ) ); Database::instance()->enqueue( QSharedPointer(cmd) ); + + emit socialActionsLoaded(); } } diff --git a/src/libtomahawk/result.h b/src/libtomahawk/result.h index b15245342..7c8d3925a 100644 --- a/src/libtomahawk/result.h +++ b/src/libtomahawk/result.h @@ -85,6 +85,7 @@ public: int year() const { return m_year; } unsigned int discnumber() const { return m_discnumber; } + void setQuery( const Tomahawk::query_ptr& query ) { m_query = query; } void setScore( float score ) { m_score = score; } void setTrackId( unsigned int id ) { m_trackId = id; } void setFileId( unsigned int id ) { m_fileId = id; } diff --git a/src/libtomahawk/widgets/querylabel.cpp b/src/libtomahawk/widgets/querylabel.cpp index 131204e95..5271d0b89 100644 --- a/src/libtomahawk/widgets/querylabel.cpp +++ b/src/libtomahawk/widgets/querylabel.cpp @@ -80,7 +80,7 @@ void QueryLabel::init() { m_contextMenu = new ContextMenu( this ); - m_contextMenu->setSupportedActions( ContextMenu::ActionQueue | ContextMenu::ActionCopyLink ); + m_contextMenu->setSupportedActions( ContextMenu::ActionQueue | ContextMenu::ActionCopyLink | ContextMenu::ActionStopAfter | ContextMenu::ActionLove ); m_hoverType = None; setContentsMargins( 0, 0, 0, 0 ); From b9c61952a6c6e8e4122badbdc7c681ec3d6eac43 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 31 Mar 2012 05:48:15 +0200 Subject: [PATCH 46/59] * Fixed PlaylistLargeItemDelegate. --- .../playlist/PlaylistLargeItemDelegate.cpp | 24 ++++++++----------- .../playlist/PlaylistLargeItemDelegate.h | 6 ++++- src/libtomahawk/viewmanager.cpp | 2 +- src/sourcetree/items/sourceitem.cpp | 6 ++--- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp index 404fb1bf7..21824caec 100644 --- a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp +++ b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp @@ -40,10 +40,11 @@ using namespace Tomahawk; -PlaylistLargeItemDelegate::PlaylistLargeItemDelegate( TrackView* parent, TrackProxyModel* proxy ) +PlaylistLargeItemDelegate::PlaylistLargeItemDelegate( DisplayMode mode, TrackView* parent, TrackProxyModel* proxy ) : QStyledItemDelegate( (QObject*)parent ) , m_view( parent ) , m_model( proxy ) + , m_mode( mode ) { m_topOption = QTextOption( Qt::AlignTop ); m_topOption.setWrapMode( QTextOption::NoWrap ); @@ -149,8 +150,7 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& return; QPixmap pixmap, avatar; - QString artist, track, upperText, lowerText; - source_ptr source = item->query()->playedBy().first; + QString artist, track, lowerText; unsigned int duration = 0; if ( item->query()->results().count() ) @@ -165,14 +165,11 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& track = item->query()->track(); } - lowerText = item->query()->socialActionDescription( "Love", Query::Detailed ); - - if ( source.isNull() ) + QSize avatarSize( 32, 32 ); + source_ptr source = item->query()->playedBy().first; + if ( m_mode == RecentlyPlayed && !source.isNull() ) { - } - else - { - upperText = QString( "%1 - %2" ).arg( artist ).arg( track ); + avatar = source->avatar( Source::FancyStyle, avatarSize ); QString playtime = TomahawkUtils::ageToString( QDateTime::fromTime_t( item->query()->playedBy().second ), true ); if ( source == SourceList::instance()->getLocal() ) @@ -181,6 +178,9 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& lowerText = QString( tr( "played %1 by %2" ) ).arg( playtime ).arg( source->friendlyName() ); } + if ( m_mode == LovedTracks ) + lowerText = item->query()->socialActionDescription( "Love", Query::Detailed ); + painter->save(); { QRect r = opt.rect.adjusted( 3, 6, 0, -6 ); @@ -197,14 +197,10 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& painter->setPen( opt.palette.text().color() ); - QSize avatarSize( 32, 32 ); QRect pixmapRect = r.adjusted( 6, 0, -option.rect.width() + option.rect.height() - 6 + r.left(), 0 ); QRect avatarRect = r.adjusted( option.rect.width() - r.left() - 12 - avatarSize.width(), ( option.rect.height() - avatarSize.height() ) / 2 - 5, 0, 0 ); avatarRect.setSize( avatarSize ); - if ( source ) - avatar = source->avatar( Source::FancyStyle, avatarRect.size() ); - pixmap = item->query()->cover( pixmapRect.size(), false ); if ( !pixmap ) { diff --git a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h index 56ea64a57..ad2210a75 100644 --- a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h +++ b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.h @@ -35,7 +35,10 @@ class DLLEXPORT PlaylistLargeItemDelegate : public QStyledItemDelegate Q_OBJECT public: - PlaylistLargeItemDelegate( TrackView* parent = 0, TrackProxyModel* proxy = 0 ); + enum DisplayMode + { LovedTracks, RecentlyPlayed, LatestAdditions }; + + PlaylistLargeItemDelegate( DisplayMode mode, TrackView* parent = 0, TrackProxyModel* proxy = 0 ); protected: void paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const; @@ -52,6 +55,7 @@ private: TrackView* m_view; TrackProxyModel* m_model; + DisplayMode m_mode; }; #endif // PLAYLISTLARGEITEMDELEGATE_H diff --git a/src/libtomahawk/viewmanager.cpp b/src/libtomahawk/viewmanager.cpp index 2d06796d5..d0c8aa88c 100644 --- a/src/libtomahawk/viewmanager.cpp +++ b/src/libtomahawk/viewmanager.cpp @@ -441,7 +441,7 @@ ViewManager::showTopLovedPage() if ( !m_topLovedWidget ) { CustomPlaylistView* view = new CustomPlaylistView( CustomPlaylistView::TopLovedTracks, source_ptr(), m_widget ); - view->setItemDelegate( new PlaylistLargeItemDelegate( view, view->proxyModel() ) ); + view->setItemDelegate( new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::LovedTracks, view, view->proxyModel() ) ); m_topLovedWidget = view; } diff --git a/src/sourcetree/items/sourceitem.cpp b/src/sourcetree/items/sourceitem.cpp index 42327f565..c1767734f 100644 --- a/src/sourcetree/items/sourceitem.cpp +++ b/src/sourcetree/items/sourceitem.cpp @@ -504,7 +504,7 @@ SourceItem::lovedTracksClicked() if ( !m_lovedTracksPage ) { CustomPlaylistView* view = new CustomPlaylistView( m_source.isNull() ? CustomPlaylistView::TopLovedTracks : CustomPlaylistView::SourceLovedTracks, m_source, ViewManager::instance()->widget() ); - view->setItemDelegate( new PlaylistLargeItemDelegate( view, view->proxyModel() ) ); + view->setItemDelegate( new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::LovedTracks, view, view->proxyModel() ) ); m_lovedTracksPage = view; } @@ -533,7 +533,7 @@ SourceItem::latestAdditionsClicked() RecentlyAddedModel* raModel = new RecentlyAddedModel( m_source, cv ); raModel->setStyle( TrackModel::Large ); - cv->setItemDelegate( new PlaylistLargeItemDelegate( cv, cv->proxyModel() ) ); + cv->setItemDelegate( new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::LatestAdditions, cv, cv->proxyModel() ) ); cv->setTrackModel( raModel ); cv->sortByColumn( TrackModel::Age, Qt::DescendingOrder ); @@ -564,7 +564,7 @@ SourceItem::recentPlaysClicked() RecentlyPlayedModel* raModel = new RecentlyPlayedModel( m_source, pv ); raModel->setStyle( TrackModel::Large ); - pv->setItemDelegate( new PlaylistLargeItemDelegate( pv, pv->proxyModel() ) ); + pv->setItemDelegate( new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::RecentlyPlayed, pv, pv->proxyModel() ) ); pv->setPlaylistModel( raModel ); m_recentPlaysPage = pv; From f0f9e6847b936ffa516b2aa4b2d3ebc5e2e3881b Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 31 Mar 2012 06:38:38 +0200 Subject: [PATCH 47/59] * Make stop-after-track better. --- src/audiocontrols.cpp | 2 +- src/libtomahawk/audio/audioengine.cpp | 4 ++-- src/libtomahawk/contextmenu.cpp | 3 ++- src/libtomahawk/query.cpp | 13 ++++++++++++- src/libtomahawk/query.h | 2 ++ src/libtomahawk/result.h | 1 - 6 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/audiocontrols.cpp b/src/audiocontrols.cpp index ce907a11e..9b3807a0a 100644 --- a/src/audiocontrols.cpp +++ b/src/audiocontrols.cpp @@ -278,7 +278,7 @@ void AudioControls::onSocialActionsLoaded() { Query* query = qobject_cast< Query* >( sender() ); - if ( !query || !m_currentTrack || query != m_currentTrack->toQuery().data() ) + if ( !query || !m_currentTrack || !query->equals( m_currentTrack->toQuery() ) ) return; setSocialActions(); diff --git a/src/libtomahawk/audio/audioengine.cpp b/src/libtomahawk/audio/audioengine.cpp index 385891a0c..492c112bb 100644 --- a/src/libtomahawk/audio/audioengine.cpp +++ b/src/libtomahawk/audio/audioengine.cpp @@ -516,9 +516,9 @@ AudioEngine::loadNextTrack() Tomahawk::result_ptr result; - if ( !m_stopAfterTrack.isNull() && !m_currentTrack.isNull() ) + if ( !m_stopAfterTrack.isNull() ) { - if ( m_stopAfterTrack.data() == m_currentTrack->toQuery().data() ) + if ( m_stopAfterTrack->equals( m_currentTrack->toQuery() ) ) { m_stopAfterTrack.clear(); stop(); diff --git a/src/libtomahawk/contextmenu.cpp b/src/libtomahawk/contextmenu.cpp index b64dca517..fcba90360 100644 --- a/src/libtomahawk/contextmenu.cpp +++ b/src/libtomahawk/contextmenu.cpp @@ -1,3 +1,4 @@ + /* === This file is part of Tomahawk Player - === * * Copyright 2010-2011, Christian Muehlhaeuser @@ -220,7 +221,7 @@ ContextMenu::onTriggered( int action ) break; case ActionStopAfter: - if ( AudioEngine::instance()->stopAfterTrack() == m_queries.first() ) + if ( m_queries.first()->equals( AudioEngine::instance()->stopAfterTrack() ) ) AudioEngine::instance()->setStopAfterTrack( query_ptr() ); else AudioEngine::instance()->setStopAfterTrack( m_queries.first() ); diff --git a/src/libtomahawk/query.cpp b/src/libtomahawk/query.cpp index a381fc343..bd2310ee7 100644 --- a/src/libtomahawk/query.cpp +++ b/src/libtomahawk/query.cpp @@ -168,7 +168,6 @@ Query::addResults( const QList< Tomahawk::result_ptr >& newresults ) // hook up signals, and check solved status foreach( const result_ptr& rp, newresults ) { - rp->setQuery( q ); connect( rp.data(), SIGNAL( statusChanged() ), SLOT( onResultStatusChanged() ) ); } } @@ -413,6 +412,18 @@ Query::checkResults() } +bool +Query::equals( const Tomahawk::query_ptr& other ) const +{ + if ( other.isNull() ) + return false; + + return ( artist() == other->artist() && + album() == other->album() && + track() == other->track() ); +} + + QVariant Query::toVariant() const { diff --git a/src/libtomahawk/query.h b/src/libtomahawk/query.h index 0d8c6d1ce..724e53529 100644 --- a/src/libtomahawk/query.h +++ b/src/libtomahawk/query.h @@ -91,6 +91,8 @@ public: void setAlbumPos( unsigned int albumpos ) { m_albumpos = albumpos; } void setDiscNumber( unsigned int discnumber ) { m_discnumber = discnumber; } + bool equals( const Tomahawk::query_ptr& other ) const; + QVariant toVariant() const; QString toString() const; diff --git a/src/libtomahawk/result.h b/src/libtomahawk/result.h index 7c8d3925a..b15245342 100644 --- a/src/libtomahawk/result.h +++ b/src/libtomahawk/result.h @@ -85,7 +85,6 @@ public: int year() const { return m_year; } unsigned int discnumber() const { return m_discnumber; } - void setQuery( const Tomahawk::query_ptr& query ) { m_query = query; } void setScore( float score ) { m_score = score; } void setTrackId( unsigned int id ) { m_trackId = id; } void setFileId( unsigned int id ) { m_fileId = id; } From c054d07110b854af965e7597283cca95219d7bf5 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 31 Mar 2012 07:15:11 +0200 Subject: [PATCH 48/59] * Fading covers in AudioControls. --- src/audiocontrols.ui | 7 ++++++- src/libtomahawk/CMakeLists.txt | 4 +--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/audiocontrols.ui b/src/audiocontrols.ui index 584cca7d2..f07c1d784 100644 --- a/src/audiocontrols.ui +++ b/src/audiocontrols.ui @@ -142,7 +142,7 @@ 0 - + 0 @@ -561,6 +561,11 @@ QLabel
widgets/querylabel.h
+ + FadingPixmap + QLabel +
widgets/FadingPixmap.h
+
diff --git a/src/libtomahawk/CMakeLists.txt b/src/libtomahawk/CMakeLists.txt index e915bc8e4..78401e69c 100644 --- a/src/libtomahawk/CMakeLists.txt +++ b/src/libtomahawk/CMakeLists.txt @@ -142,6 +142,7 @@ set( libGuiSources widgets/HeaderWidget.cpp widgets/combobox.cpp widgets/ToggleButton.cpp + widgets/FadingPixmap.cpp widgets/SocialPlaylistWidget.cpp widgets/infowidgets/sourceinfowidget.cpp widgets/infowidgets/ArtistInfoWidget.cpp @@ -152,9 +153,6 @@ set( libGuiSources IF(QCA2_FOUND) set( libGuiSources ${libGuiSources} utils/groovesharkparser.cpp ) -ENDIF(QCA2_FOUND) - -IF(QCA2_FOUND) set( libGuiHeaders ${libGuiHeaders} utils/groovesharkparser.h ) ENDIF(QCA2_FOUND) From 48d66649b1b96ed59b751cef08c38399d9c33000 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 31 Mar 2012 07:18:01 +0200 Subject: [PATCH 49/59] * Forgot those files. --- src/libtomahawk/widgets/FadingPixmap.cpp | 114 +++++++++++++++++++++++ src/libtomahawk/widgets/FadingPixmap.h | 64 +++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 src/libtomahawk/widgets/FadingPixmap.cpp create mode 100644 src/libtomahawk/widgets/FadingPixmap.h diff --git a/src/libtomahawk/widgets/FadingPixmap.cpp b/src/libtomahawk/widgets/FadingPixmap.cpp new file mode 100644 index 000000000..29b7304c4 --- /dev/null +++ b/src/libtomahawk/widgets/FadingPixmap.cpp @@ -0,0 +1,114 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2011 - 2012, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#include "FadingPixmap.h" + +#include + +#define ANIMATION_TIME 1000 + +FadingPixmap::FadingPixmap( QWidget* parent ) + : QLabel( parent ) + , m_fadePct( 100 ) +{ +// setCursor( Qt::PointingHandCursor ); + + m_timeLine = new QTimeLine( ANIMATION_TIME, this ); + m_timeLine->setUpdateInterval( 20 ); + m_timeLine->setEasingCurve( QEasingCurve::Linear ); + + connect( m_timeLine, SIGNAL( frameChanged( int ) ), SLOT( onAnimationStep( int ) ) ); + connect( m_timeLine, SIGNAL( finished() ), SLOT( onAnimationFinished() ) ); +} + + +FadingPixmap::~FadingPixmap() +{ +} + + +void +FadingPixmap::onAnimationStep( int frame ) +{ + m_fadePct = (float)frame / 10.0; + repaint(); +} + + +void +FadingPixmap::onAnimationFinished() +{ + m_oldPixmap = QPixmap(); + repaint(); + + if ( m_pixmapQueue.count() ) + { + setPixmap( m_pixmapQueue.takeFirst() ); + } +} + + +void +FadingPixmap::setPixmap( const QPixmap& pixmap, bool clearQueue ) +{ + if ( m_timeLine->state() == QTimeLine::Running ) + { + if ( clearQueue ) + m_pixmapQueue.clear(); + + m_pixmapQueue << pixmap; + return; + } + + m_oldPixmap = m_pixmap; + m_pixmap = pixmap; + + m_timeLine->setFrameRange( 0, 1000 ); + m_timeLine->setDirection( QTimeLine::Forward ); + m_timeLine->start(); +} + + +void +FadingPixmap::mouseReleaseEvent( QMouseEvent* event ) +{ + QFrame::mouseReleaseEvent( event ); + + emit clicked(); +} + + +void +FadingPixmap::paintEvent( QPaintEvent* event ) +{ + Q_UNUSED( event ); + + QPainter p( this ); + QRect r = contentsRect(); + + p.save(); + p.setRenderHint( QPainter::Antialiasing ); + + p.setOpacity( float( 100.0 - m_fadePct ) / 100.0 ); + p.drawPixmap( r, m_oldPixmap ); + + p.setOpacity( float( m_fadePct ) / 100.0 ); + p.drawPixmap( r, m_pixmap ); + + p.restore(); +} diff --git a/src/libtomahawk/widgets/FadingPixmap.h b/src/libtomahawk/widgets/FadingPixmap.h new file mode 100644 index 000000000..e6bd7720f --- /dev/null +++ b/src/libtomahawk/widgets/FadingPixmap.h @@ -0,0 +1,64 @@ +/* === This file is part of Tomahawk Player - === + * + * Copyright 2011 - 2012, Christian Muehlhaeuser + * + * Tomahawk is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Tomahawk is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Tomahawk. If not, see . + */ + +#ifndef FADINGPIXMAP_H +#define FADINGPIXMAP_H + +#include +#include +#include + +#include "dllmacro.h" + +/** + * \class FadingPixmap + * \brief Fades to the new image when calling setPixmap. + */ +class DLLEXPORT FadingPixmap : public QLabel +{ +Q_OBJECT + +public: + FadingPixmap( QWidget* parent = 0 ); + virtual ~FadingPixmap(); + +public slots: + virtual void setPixmap( const QPixmap& pixmap, bool clearQueue = true ); + +signals: + void clicked(); + +protected: + virtual void paintEvent( QPaintEvent* ); + void mouseReleaseEvent( QMouseEvent* event ); + +private slots: + void onAnimationStep( int frame ); + void onAnimationFinished(); + +private: + QPixmap m_pixmap; + QPixmap m_oldPixmap; + + QList m_pixmapQueue; + + QTimeLine* m_timeLine; + int m_fadePct; +}; + +#endif From 1af928790e2cd8ea226201929b3f530a9b9d575c Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 31 Mar 2012 07:36:53 +0200 Subject: [PATCH 50/59] * Fixed delegate for latest additions. --- src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp index 21824caec..95ff66915 100644 --- a/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp +++ b/src/libtomahawk/playlist/PlaylistLargeItemDelegate.cpp @@ -178,6 +178,13 @@ PlaylistLargeItemDelegate::paint( QPainter* painter, const QStyleOptionViewItem& lowerText = QString( tr( "played %1 by %2" ) ).arg( playtime ).arg( source->friendlyName() ); } + if ( m_mode == LatestAdditions && item->query()->numResults() ) + { + QString playtime = TomahawkUtils::ageToString( QDateTime::fromTime_t( item->query()->results().first()->modificationTime() ), true ); + + lowerText = QString( tr( "added %1" ) ).arg( playtime ); + } + if ( m_mode == LovedTracks ) lowerText = item->query()->socialActionDescription( "Love", Query::Detailed ); From e049dcd6af4df74f05844dd3125cef13fbebbbc4 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 31 Mar 2012 07:53:47 +0200 Subject: [PATCH 51/59] * Added global Recently Played page. --- .../playlist/RecentlyPlayedModel.cpp | 2 ++ src/libtomahawk/viewmanager.cpp | 25 +++++++++++++++++++ src/libtomahawk/viewmanager.h | 3 +++ src/sourcetree/sourcesmodel.cpp | 17 ++++++++----- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/playlist/RecentlyPlayedModel.cpp b/src/libtomahawk/playlist/RecentlyPlayedModel.cpp index db41f2766..2a194295f 100644 --- a/src/libtomahawk/playlist/RecentlyPlayedModel.cpp +++ b/src/libtomahawk/playlist/RecentlyPlayedModel.cpp @@ -40,6 +40,8 @@ RecentlyPlayedModel::RecentlyPlayedModel( const source_ptr& source, QObject* par { if ( source.isNull() ) { + onSourcesReady(); + connect( SourceList::instance(), SIGNAL( ready() ), SLOT( onSourcesReady() ) ); connect( SourceList::instance(), SIGNAL( sourceAdded( Tomahawk::source_ptr ) ), SLOT( onSourceAdded( Tomahawk::source_ptr ) ) ); } diff --git a/src/libtomahawk/viewmanager.cpp b/src/libtomahawk/viewmanager.cpp index d0c8aa88c..e6d181053 100644 --- a/src/libtomahawk/viewmanager.cpp +++ b/src/libtomahawk/viewmanager.cpp @@ -43,6 +43,7 @@ #include "customplaylistview.h" #include "PlaylistLargeItemDelegate.h" +#include "RecentlyPlayedModel.h" #include "dynamic/widgets/DynamicWidget.h" #include "widgets/welcomewidget.h" @@ -75,6 +76,7 @@ ViewManager::ViewManager( QObject* parent ) , m_welcomeWidget( new WelcomeWidget() ) , m_whatsHotWidget( new WhatsHotWidget() ) , m_topLovedWidget( 0 ) + , m_recentPlaysWidget( 0 ) , m_currentMode( PlaylistInterface::Tree ) , m_loaded( false ) { @@ -131,6 +133,7 @@ ViewManager::~ViewManager() delete m_whatsHotWidget; delete m_welcomeWidget; delete m_topLovedWidget; + delete m_recentPlaysWidget; delete m_contextWidget; delete m_widget; } @@ -450,6 +453,28 @@ ViewManager::showTopLovedPage() } +Tomahawk::ViewPage* +ViewManager::showRecentPlaysPage() +{ + if ( !m_recentPlaysWidget ) + { + PlaylistView* pv = new PlaylistView( m_widget ); + pv->setFrameShape( QFrame::NoFrame ); + pv->setAttribute( Qt::WA_MacShowFocusRect, 0 ); + + RecentlyPlayedModel* raModel = new RecentlyPlayedModel( source_ptr(), pv ); + raModel->setStyle( TrackModel::Large ); + + pv->setItemDelegate( new PlaylistLargeItemDelegate( PlaylistLargeItemDelegate::RecentlyPlayed, pv, pv->proxyModel() ) ); + pv->setPlaylistModel( raModel ); + + m_recentPlaysWidget = pv; + } + + return show( m_recentPlaysWidget ); +} + + void ViewManager::setTableMode() { diff --git a/src/libtomahawk/viewmanager.h b/src/libtomahawk/viewmanager.h index ff284dd79..c2a7951aa 100644 --- a/src/libtomahawk/viewmanager.h +++ b/src/libtomahawk/viewmanager.h @@ -92,6 +92,7 @@ public: Tomahawk::ViewPage* welcomeWidget() const { return m_welcomeWidget; } Tomahawk::ViewPage* whatsHotWidget() const { return m_whatsHotWidget; } Tomahawk::ViewPage* topLovedWidget() const { return m_topLovedWidget; } + Tomahawk::ViewPage* recentPlaysWidget() const { return m_recentPlaysWidget; } ArtistView* superCollectionView() const { return m_superCollectionView; } /// Get the view page for the given item. Not pretty... @@ -140,6 +141,7 @@ public slots: Tomahawk::ViewPage* showWelcomePage(); Tomahawk::ViewPage* showWhatsHotPage(); Tomahawk::ViewPage* showTopLovedPage(); + Tomahawk::ViewPage* showRecentPlaysPage(); void showCurrentTrack(); // Returns the shown viewpage @@ -204,6 +206,7 @@ private: WelcomeWidget* m_welcomeWidget; WhatsHotWidget* m_whatsHotWidget; Tomahawk::ViewPage* m_topLovedWidget; + Tomahawk::ViewPage* m_recentPlaysWidget; QList< Tomahawk::collection_ptr > m_superCollections; diff --git a/src/sourcetree/sourcesmodel.cpp b/src/sourcetree/sourcesmodel.cpp index b8f55156c..7ee3b8b0c 100644 --- a/src/sourcetree/sourcesmodel.cpp +++ b/src/sourcetree/sourcesmodel.cpp @@ -263,13 +263,18 @@ SourcesModel::flags( const QModelIndex& index ) const void SourcesModel::appendGroups() { - beginInsertRows( QModelIndex(), rowCount(), rowCount() + 2 ); + beginInsertRows( QModelIndex(), rowCount(), rowCount() + 3 ); GroupItem* browse = new GroupItem( this, m_rootItem, tr( "Browse" ), 0 ); new HistoryItem( this, m_rootItem, tr( "Search History" ), 1 ); // new SourceTreeItem( this, m_rootItem, SourcesModel::Divider, 2 ); m_myMusicGroup = new GroupItem( this, m_rootItem, tr( "My Music" ), 3 ); + GenericPageItem* dashboard = new GenericPageItem( this, browse, tr( "Dashboard" ), QIcon( RESPATH "images/dashboard.png" ), + boost::bind( &ViewManager::showWelcomePage, ViewManager::instance() ), + boost::bind( &ViewManager::welcomeWidget, ViewManager::instance() ) ); + dashboard->setSortValue( 0 ); + // super collection GenericPageItem* sc = new GenericPageItem( this, browse, tr( "SuperCollection" ), QIcon( RESPATH "images/supercollection.png" ), boost::bind( &ViewManager::showSuperCollection, ViewManager::instance() ), @@ -282,15 +287,15 @@ SourcesModel::appendGroups() boost::bind( &ViewManager::topLovedWidget, ViewManager::instance() ) ); loved->setSortValue( 2 ); - GenericPageItem* recent = new GenericPageItem( this, browse, tr( "Dashboard" ), QIcon( RESPATH "images/dashboard.png" ), - boost::bind( &ViewManager::showWelcomePage, ViewManager::instance() ), - boost::bind( &ViewManager::welcomeWidget, ViewManager::instance() ) ); - recent->setSortValue( 0 ); + GenericPageItem* recent = new GenericPageItem( this, browse, tr( "Recently Played" ), QIcon( RESPATH "images/recently-played.png" ), + boost::bind( &ViewManager::showRecentPlaysPage, ViewManager::instance() ), + boost::bind( &ViewManager::recentPlaysWidget, ViewManager::instance() ) ); + recent->setSortValue( 3 ); GenericPageItem* hot = new GenericPageItem( this, browse, tr( "Charts" ), QIcon( RESPATH "images/charts.png" ), boost::bind( &ViewManager::showWhatsHotPage, ViewManager::instance() ), boost::bind( &ViewManager::whatsHotWidget, ViewManager::instance() ) ); - hot->setSortValue( 3 ); + hot->setSortValue( 4 ); m_collectionsGroup = new GroupItem( this, m_rootItem, tr( "Friends" ), 4 ); From 7403713d98afaccd4dc2ce7a27c22e284b4b4511 Mon Sep 17 00:00:00 2001 From: Christian Muehlhaeuser Date: Sat, 31 Mar 2012 08:44:07 +0200 Subject: [PATCH 52/59] * Only connect to InfoSystem on demand. --- src/libtomahawk/album.cpp | 21 ++++++++++++++------- src/libtomahawk/artist.cpp | 22 ++++++++++++++-------- 2 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/libtomahawk/album.cpp b/src/libtomahawk/album.cpp index a280f4905..3b52e7166 100644 --- a/src/libtomahawk/album.cpp +++ b/src/libtomahawk/album.cpp @@ -82,13 +82,6 @@ Album::Album( unsigned int id, const QString& name, const Tomahawk::artist_ptr& , m_cover( 0 ) #endif { - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( finished( QString ) ), - SLOT( infoSystemFinished( QString ) ) ); } @@ -131,6 +124,14 @@ Album::cover( const QSize& size, bool forceLoad ) const requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ); requestData.customData = QVariantMap(); + connect( Tomahawk::InfoSystem::InfoSystem::instance(), + SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), + SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); + + connect( Tomahawk::InfoSystem::InfoSystem::instance(), + SIGNAL( finished( QString ) ), + SLOT( infoSystemFinished( QString ) ) ); + Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); } @@ -190,6 +191,12 @@ Album::infoSystemFinished( QString target ) if ( target != m_uuid ) return; + disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), + this, SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); + + disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), + this, SLOT( infoSystemFinished( QString ) ) ); + m_infoLoaded = true; emit updated(); } diff --git a/src/libtomahawk/artist.cpp b/src/libtomahawk/artist.cpp index dc22a0861..d2b124240 100644 --- a/src/libtomahawk/artist.cpp +++ b/src/libtomahawk/artist.cpp @@ -82,14 +82,6 @@ Artist::Artist( unsigned int id, const QString& name ) #endif { m_sortname = DatabaseImpl::sortname( name, true ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), - SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); - - connect( Tomahawk::InfoSystem::InfoSystem::instance(), - SIGNAL( finished( QString ) ), - SLOT( infoSystemFinished( QString ) ) ); } @@ -122,6 +114,14 @@ Artist::cover( const QSize& size, bool forceLoad ) const requestData.input = QVariant::fromValue< Tomahawk::InfoSystem::InfoStringHash >( trackInfo ); requestData.customData = QVariantMap(); + connect( Tomahawk::InfoSystem::InfoSystem::instance(), + SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), + SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); + + connect( Tomahawk::InfoSystem::InfoSystem::instance(), + SIGNAL( finished( QString ) ), + SLOT( infoSystemFinished( QString ) ) ); + Tomahawk::InfoSystem::InfoSystem::instance()->getInfo( requestData ); } @@ -181,6 +181,12 @@ Artist::infoSystemFinished( QString target ) if ( target != m_uuid ) return; + disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), + this, SLOT( infoSystemInfo( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ) ); + + disconnect( Tomahawk::InfoSystem::InfoSystem::instance(), SIGNAL( finished( QString ) ), + this, SLOT( infoSystemFinished( QString ) ) ); + m_infoLoaded = true; emit updated(); } From f84d08e0110c5e531e9e518e4fca66b1bbdc7e79 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 31 Mar 2012 08:49:18 -0400 Subject: [PATCH 53/59] Don't sort related artists in footnotes --- src/libtomahawk/context/pages/RelatedArtistsContext.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp index 1c403e5e0..39f632bd6 100644 --- a/src/libtomahawk/context/pages/RelatedArtistsContext.cpp +++ b/src/libtomahawk/context/pages/RelatedArtistsContext.cpp @@ -37,6 +37,8 @@ RelatedArtistsContext::RelatedArtistsContext() m_relatedModel->setColumnStyle( TreeModel::TrackOnly ); m_relatedView->setTreeModel( m_relatedModel ); m_relatedView->setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOff ); + m_relatedView->setSortingEnabled( false ); + m_relatedView->proxyModel()->sort( -1 ); QPalette pal = m_relatedView->palette(); pal.setColor( QPalette::Window, QColor( 0, 0, 0, 0 ) ); From b3b70cea829de39668a65de9345c409c288417ba Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 31 Mar 2012 09:05:14 -0400 Subject: [PATCH 54/59] TWK-795: Filter dups from last.fm top artists --- src/libtomahawk/infosystem/infoplugins/generic/lastfmplugin.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libtomahawk/infosystem/infoplugins/generic/lastfmplugin.cpp b/src/libtomahawk/infosystem/infoplugins/generic/lastfmplugin.cpp index bf2d0134c..cff7abe19 100644 --- a/src/libtomahawk/infosystem/infoplugins/generic/lastfmplugin.cpp +++ b/src/libtomahawk/infosystem/infoplugins/generic/lastfmplugin.cpp @@ -585,6 +585,8 @@ LastFmPlugin::topTracksReturned() QNetworkReply* reply = qobject_cast( sender() ); QStringList topTracks = lastfm::Artist::getTopTracks( reply ); + topTracks.removeDuplicates(); + QVariantMap returnedData; returnedData["tracks"] = topTracks; From fb13ccd285e8cf9085ce56ddc283a0ce47cfbfdb Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 31 Mar 2012 09:26:07 -0400 Subject: [PATCH 55/59] Oops, fix signals/slot params --- src/libtomahawk/infobar/infobar.cpp | 2 +- src/libtomahawk/infobar/infobar.h | 2 +- src/libtomahawk/viewmanager.cpp | 6 +++--- src/libtomahawk/viewmanager.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libtomahawk/infobar/infobar.cpp b/src/libtomahawk/infobar/infobar.cpp index bdfe8bd74..0a5425f50 100644 --- a/src/libtomahawk/infobar/infobar.cpp +++ b/src/libtomahawk/infobar/infobar.cpp @@ -85,7 +85,7 @@ InfoBar::InfoBar( QWidget* parent ) m_autoUpdate->setText( tr( "Automatically update" ) ); m_autoUpdate->setLayoutDirection( Qt::RightToLeft ); m_autoUpdate->setPalette( whitePal ); - connect( m_autoUpdate, SIGNAL( toggled(bool) ), this, SIGNAL( autoUpdateChanged( int ) ) ); + connect( m_autoUpdate, SIGNAL( toggled( bool ) ), this, SIGNAL( autoUpdateChanged( bool ) ) ); ui->horizontalLayout->addWidget( m_autoUpdate ); diff --git a/src/libtomahawk/infobar/infobar.h b/src/libtomahawk/infobar/infobar.h index f16339d52..7f1f9d8ee 100644 --- a/src/libtomahawk/infobar/infobar.h +++ b/src/libtomahawk/infobar/infobar.h @@ -60,7 +60,7 @@ public slots: void setAutoUpdateAvailable( bool b ); signals: void filterTextChanged( const QString& filter ); - void autoUpdateChanged( int state ); + void autoUpdateChanged( bool checked ); protected: void changeEvent( QEvent* e ); diff --git a/src/libtomahawk/viewmanager.cpp b/src/libtomahawk/viewmanager.cpp index ef8008773..cf21a8a74 100644 --- a/src/libtomahawk/viewmanager.cpp +++ b/src/libtomahawk/viewmanager.cpp @@ -112,7 +112,7 @@ ViewManager::ViewManager( QObject* parent ) connect( &m_filterTimer, SIGNAL( timeout() ), SLOT( applyFilter() ) ); connect( m_infobar, SIGNAL( filterTextChanged( QString ) ), SLOT( setFilter( QString ) ) ); - connect( m_infobar, SIGNAL( autoUpdateChanged( int ) ), SLOT( autoUpdateChanged( int ) ) ); + connect( m_infobar, SIGNAL( autoUpdateChanged( bool ) ), SLOT( autoUpdateChanged( bool ) ) ); connect( this, SIGNAL( tomahawkLoaded() ), m_whatsHotWidget, SLOT( fetchData() ) ); connect( this, SIGNAL( tomahawkLoaded() ), m_welcomeWidget, SLOT( loadData() ) ); @@ -537,9 +537,9 @@ ViewManager::applyFilter() void -ViewManager::autoUpdateChanged( int state ) +ViewManager::autoUpdateChanged( bool toggled ) { - currentPage()->setAutoUpdate( state == Qt::Checked ); + currentPage()->setAutoUpdate( toggled ); } diff --git a/src/libtomahawk/viewmanager.h b/src/libtomahawk/viewmanager.h index 1320fd1bb..2762902ac 100644 --- a/src/libtomahawk/viewmanager.h +++ b/src/libtomahawk/viewmanager.h @@ -174,7 +174,7 @@ private slots: void setFilter( const QString& filter ); void applyFilter(); - void autoUpdateChanged( int ); + void autoUpdateChanged( bool ); void onWidgetDestroyed( QWidget* widget ); From fec670f27c2804777d16d853b51e9ab776018c86 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 31 Mar 2012 09:26:30 -0400 Subject: [PATCH 56/59] TWK-793: Let the sourcetreeview sort before we scroll otherwise we might scroll the wrong amount --- src/sourcetree/sourcetreeview.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sourcetree/sourcetreeview.cpp b/src/sourcetree/sourcetreeview.cpp index 6e1d08ddc..b6f94c0bc 100644 --- a/src/sourcetree/sourcetreeview.cpp +++ b/src/sourcetree/sourcetreeview.cpp @@ -98,7 +98,7 @@ SourceTreeView::SourceTreeView( QWidget* parent ) m_model = new SourcesModel( this ); m_proxyModel = new SourcesProxyModel( m_model, this ); - connect( m_proxyModel, SIGNAL( selectRequest( QPersistentModelIndex ) ), SLOT( selectRequest( QPersistentModelIndex ) ) ); + connect( m_proxyModel, SIGNAL( selectRequest( QPersistentModelIndex ) ), SLOT( selectRequest( QPersistentModelIndex ) ), Qt::QueuedConnection ); connect( m_proxyModel, SIGNAL( expandRequest( QPersistentModelIndex ) ), SLOT( expandRequest( QPersistentModelIndex ) ) ); connect( m_proxyModel, SIGNAL( toggleExpandRequest( QPersistentModelIndex ) ), SLOT( toggleExpandRequest( QPersistentModelIndex ) ) ); From 5b6c4560aebf9972d2a72a17eb54cc025052f047 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 31 Mar 2012 09:53:47 -0400 Subject: [PATCH 57/59] TWK-785: Rename playlist after revision is created so plitem is selectable --- src/sourcetree/items/categoryitems.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sourcetree/items/categoryitems.cpp b/src/sourcetree/items/categoryitems.cpp index 4be8e182f..a9c1a5131 100644 --- a/src/sourcetree/items/categoryitems.cpp +++ b/src/sourcetree/items/categoryitems.cpp @@ -295,6 +295,7 @@ CategoryAddItem::playlistToRenameLoaded() QTimer::singleShot( 400, APP->mainWindow()->sourceTreeView(), SLOT( renamePlaylist() ) ); disconnect( pl, SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( playlistToRenameLoaded() ) ); + disconnect( pl, SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistToRenameLoaded() ) ); } @@ -306,8 +307,7 @@ CategoryAddItem::parsedDroppedTracks( const QList< query_ptr >& tracks ) playlist_ptr newpl = Playlist::create( SourceList::instance()->getLocal(), uuid(), "New Playlist", "", SourceList::instance()->getLocal()->friendlyName(), false, tracks ); ViewManager::instance()->show( newpl ); - // Give a shot to try to rename it. The playlist has to be created first. ugly. - QTimer::singleShot( 300, APP->mainWindow()->sourceTreeView(), SLOT( renamePlaylist() ) ); + connect( newpl.data(), SIGNAL( revisionLoaded( Tomahawk::PlaylistRevision ) ), this, SLOT( playlistToRenameLoaded() ) ); } else if( m_categoryType == SourcesModel::StationsCategory ) { // seed the playlist with these song or artist filters QString name; From 5dcf426cdf13f04b2cf27167a67412cf6e787d5c Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 31 Mar 2012 10:03:53 -0400 Subject: [PATCH 58/59] TWK-770: Fix echonest sentence summary grammar --- .../playlist/dynamic/echonest/EchonestGenerator.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp index dcb34acef..dd55845e8 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp @@ -597,7 +597,9 @@ EchonestGenerator::sentenceSummary() suffix = ", "; else suffix = "."; - } else + } else if ( i < required.size() - 2 ) // An item in the list that is before the second to last one, don't use ", and", we only want that for the last item + suffix += ", "; + else suffix += ", and "; } sentence += center + suffix; From 5d09ff81fb1641c7f56a8e4f0a1ad497e4547647 Mon Sep 17 00:00:00 2001 From: Leo Franchi Date: Sat, 31 Mar 2012 10:35:50 -0400 Subject: [PATCH 59/59] Update bulgarian translation from neycho --- lang/tomahawk_bg.ts | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/lang/tomahawk_bg.ts b/lang/tomahawk_bg.ts index 2451fa9f1..1555549f8 100644 --- a/lang/tomahawk_bg.ts +++ b/lang/tomahawk_bg.ts @@ -1602,13 +1602,13 @@ Spotify e TM на Spotify Group. Status: Credentials saved for %1 - + Няма запазени данни за вход De-authenticate - Премахни усостоверяване + Премахни удостоверяване @@ -1619,87 +1619,91 @@ Spotify e TM на Spotify Group. Tweetin' Error - + Грешка при изпращане на съобщение The credentials could not be verified. You may wish to try re-authenticating. - + Данните за вход не могат да бъдат потвърдени. +Моля, опитай отново. Status: Error validating credentials - + Грешка при валидиране на данни за вход Global Tweet - + Общо съобщение Direct Message - + Лично съобщение Send Message! - + Чурулик! @Mention - + @Споменаване Send Mention! - + Чурулик! You must enter a user name for this type of tweet. - + Въведи име на потребител, за този вид съобщение. Your saved credentials could not be loaded. You may wish to try re-authenticating. - + Данните ти за вход не могат да бъдат заредени. +Моля, оторизирай програмата отново. Your saved credentials could not be verified. You may wish to try re-authenticating. - + Запаметените данни за вход не могат да бъдат потвърдени. +Моля, оторизирай програмата отново. There was an error posting your status -- sorry! - + Грешка при побликуване. Опитай отново. Tweeted! - + Изчуруликано! Your tweet has been posted! - + Съобщението ти беше побликувано. There was an error posting your direct message -- sorry! - + Грешка при изпращане на лично съобщение. +Опитай отново. Your message has been posted! - + Съобщението беще побликувано. @@ -3115,7 +3119,7 @@ You can re-send a sync message at any time simply by sending another tweet using e.g. @tomahawk - т.е. @tomahawk + напр. @tomahawk