Commit 40c45b77 authored by Matěj Laitl's avatar Matěj Laitl
Browse files

MetaProxy, LastFmMeta: finally fix Last.fm track recreation

QObjects and threads don't go well together, hopefully I'll win.

BUG: 305576
FIXED-IN: 2.7
parent 143c96f6
......@@ -14,21 +14,22 @@
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#include "core-impl/meta/proxy/MetaProxy.h"
#include "core-impl/meta/proxy/MetaProxy_p.h"
#include "core-impl/meta/proxy/MetaProxy_p.moc"
#include "core-impl/meta/proxy/MetaProxyWorker.h"
#include "MetaProxy.h"
#include "core/meta/Statistics.h"
#include "core/capabilities/EditCapability.h"
#include "core-impl/collections/support/CollectionManager.h"
#include <QObject>
#include <QWeakPointer>
#include <QTimer>
#include "core-impl/meta/proxy/MetaProxy_p.h"
#include "core-impl/meta/proxy/MetaProxy_p.moc"
#include "core-impl/meta/proxy/MetaProxyWorker.h"
#include <KSharedPtr>
#include <threadweaver/ThreadWeaver.h>
#include <ThreadWeaver/Weaver>
#include <QCoreApplication>
#include <QThread>
#include <QTimer>
#include <QWeakPointer>
using namespace MetaProxy;
......@@ -78,9 +79,17 @@ MetaProxy::Track::Track( const KUrl &url, LookupType lookupType )
d->composerPtr = Meta::ComposerPtr( new ProxyComposer( d ) );
d->yearPtr = Meta::YearPtr( new ProxyYear( d ) );
QThread *mainThread = QCoreApplication::instance()->thread();
bool foreignThread = QThread::currentThread() != mainThread;
if( foreignThread )
d->moveToThread( mainThread );
if( lookupType == AutomaticLookup )
{
Worker *worker = new Worker( d->url );
if( foreignThread )
worker->moveToThread( mainThread );
QObject::connect( worker, SIGNAL(finishedLookup(Meta::TrackPtr)),
d, SLOT(slotUpdateTrack(Meta::TrackPtr)) );
ThreadWeaver::Weaver::instance()->enqueue( worker );
......@@ -96,6 +105,10 @@ void
MetaProxy::Track::lookupTrack( Collections::TrackProvider *provider )
{
Worker *worker = new Worker( d->url, provider );
QThread *mainThread = QCoreApplication::instance()->thread();
if( QThread::currentThread() != mainThread )
worker->moveToThread( mainThread );
QObject::connect( worker, SIGNAL(finishedLookup(Meta::TrackPtr)),
d, SLOT(slotUpdateTrack(Meta::TrackPtr)) );
ThreadWeaver::Weaver::instance()->enqueue( worker );
......
......@@ -21,9 +21,12 @@
using namespace MetaProxy;
Worker::Worker( const KUrl &url, Collections::TrackProvider *provider )
: Amarok::TrackForUrlWorker( url )
: m_url( url )
, m_provider( provider )
, m_stepsDoneReceived( 0 )
{
connect( this, SIGNAL(done(ThreadWeaver::Job*)), SLOT(slotStepDone()) );
connect( this, SIGNAL(finishedLookup(Meta::TrackPtr)), SLOT(slotStepDone()) );
}
void
......@@ -39,36 +42,33 @@ Worker::run()
}
track = CollectionManager::instance()->trackForUrl( m_url );
if( track )
{
emit finishedLookup( track );
return;
}
//no TrackProvider has a track for us yet, query new ones that are added.
if( track.isNull() )
// no TrackProvider has a track for us yet, query new ones that are added.
if( !track )
{
//TODO: should only have to connecto to TrackProvider signals.
//Each Collection contains a TrackProvider
connect( CollectionManager::instance(),
SIGNAL(trackProviderAdded( Collections::TrackProvider * )),
SLOT(slotNewTrackProvider( Collections::TrackProvider * )) );
SIGNAL(trackProviderAdded(Collections::TrackProvider*)),
SLOT(slotNewTrackProvider( Collections::TrackProvider*)),
Qt::DirectConnection ); // we may live in a thread w/out event loop
connect( CollectionManager::instance(),
SIGNAL(collectionAdded( Collections::Collection * )),
SLOT(slotNewCollection( Collections::Collection * )) );
/* FIXME: slotNewTrackProvider/slotNewCollection are IMO never called,
* because when run() returns, ThreadWeaver::Job emits done(), which is
* connected to Amarok::TrackForUrlWorker::completeJob(), which emits
* finishedLookup() and calls deleteLater() on this object. -- strohel */
SIGNAL(collectionAdded(Collections::Collection*)),
SLOT(slotNewTrackProvider(Collections::TrackProvider*)),
Qt::DirectConnection ); // we may live in a thread w/out event loop
return;
}
emit finishedLookup( track );
}
void
Worker::slotNewTrackProvider( Collections::TrackProvider *newTrackProvider )
{
if( !newTrackProvider )
{
return;
}
if( newTrackProvider->possiblyContainsTrack( m_url ) )
{
......@@ -78,16 +78,9 @@ Worker::slotNewTrackProvider( Collections::TrackProvider *newTrackProvider )
}
void
Worker::slotNewCollection( Collections::Collection *newCollection )
Worker::slotStepDone()
{
if( !newCollection )
{
return;
}
if( newCollection->possiblyContainsTrack( m_url ) )
{
Meta::TrackPtr track = newCollection->trackForUrl( m_url );
emit finishedLookup( track );
}
m_stepsDoneReceived++;
if( m_stepsDoneReceived >= 2 )
deleteLater();
}
......@@ -17,33 +17,43 @@
#ifndef METAPROXY_METAPROXYWORKER_H
#define METAPROXY_METAPROXYWORKER_H
#include <core/collections/support/TrackForUrlWorker.h>
#include <core/collections/Collection.h>
#include "core/collections/Collection.h"
namespace MetaProxy {
#include <ThreadWeaver/Job>
class Worker : public Amarok::TrackForUrlWorker
namespace MetaProxy
{
Q_OBJECT
public:
/**
* If @param provider is null (the default), all providers registered to
* CollectionManager are used and a watch for new providers is used.
* Otherwise the lookup happes just in @param provider and is one-shot.
*/
explicit Worker( const KUrl &url, Collections::TrackProvider *provider = 0 );
//TrackForUrlWorker virtual methods
virtual void run();
private slots:
void slotNewTrackProvider( Collections::TrackProvider *newTrackProvider );
void slotNewCollection( Collections::Collection *newCollection );
private:
Collections::TrackProvider *m_provider;
};
/**
* Worker to get real track for MetaProxy::Track. Worker deletes itself somewhere
* after emitting finishedLookup().
*/
class Worker : public ThreadWeaver::Job
{
Q_OBJECT
public:
/**
* If @param provider is null (the default), all providers registered to
* CollectionManager are used and a watch for new providers is used.
* Otherwise the lookup happes just in @param provider and is one-shot.
*/
explicit Worker( const KUrl &url, Collections::TrackProvider *provider = 0 );
//TrackForUrlWorker virtual methods
virtual void run();
signals:
void finishedLookup( Meta::TrackPtr track );
private slots:
void slotNewTrackProvider( Collections::TrackProvider *newTrackProvider );
void slotStepDone();
private:
KUrl m_url;
Collections::TrackProvider *m_provider;
int m_stepsDoneReceived;
};
} // namespace MetaProxy
#endif // METAPROXY_METAPROXYWORKER_H
......@@ -26,6 +26,9 @@
#include <KIcon>
#include <Solid/Networking>
#include <QCoreApplication>
#include <QThread>
using namespace LastFm;
Track::Track( const QString &lastFmUri )
......@@ -75,17 +78,25 @@ void Track::init( int id /* = -1*/ )
d->composerPtr = Meta::ComposerPtr( new LastFmComposer( d ) );
d->yearPtr = Meta::YearPtr( new LastFmYear( d ) );
QAction * banAction = new QAction( KIcon( "remove-amarok" ), i18n( "Last.fm: &Ban" ), this );
QAction *banAction = new QAction( KIcon( "remove-amarok" ), i18n( "Last.fm: &Ban" ), this );
banAction->setShortcut( i18n( "Ctrl+B" ) );
banAction->setStatusTip( i18n( "Ban this track" ) );
connect( banAction, SIGNAL( triggered() ), this, SLOT( ban() ) );
m_trackActions.append( banAction );
QAction * skipAction = new QAction( KIcon( "media-seek-forward-amarok" ), QString( "Last.fm: &Skip" ), this ); // i18n after string freeze
QAction *skipAction = new QAction( KIcon( "media-seek-forward-amarok" ), QString( "Last.fm: &Skip" ), this ); // i18n after string freeze
skipAction->setShortcut( QString( "Ctrl+S" ) ); // i18n after string freeze
skipAction->setStatusTip( QString( "Skip this track" ) ); // i18n after string freeze
connect( skipAction, SIGNAL(triggered()), this, SIGNAL(skipTrack()) );
m_trackActions.append( skipAction );
QThread *mainThread = QCoreApplication::instance()->thread();
bool foreignThread = QThread::currentThread() != mainThread;
if( foreignThread )
{
moveToThread( mainThread ); // the actions are children and are moved together with parent
d->moveToThread( mainThread );
}
}
QString
......@@ -155,10 +166,17 @@ Track::uidUrl() const
bool
Track::isPlayable() const
{
if( Solid::Networking::status() != Solid::Networking::Connected )
return false;
return !d->trackPath.isEmpty();
switch( Solid::Networking::status() )
{
case Solid::Networking::Unknown:
case Solid::Networking::Connected:
return true;
case Solid::Networking::Unconnected:
case Solid::Networking::Disconnecting:
case Solid::Networking::Connecting:
return false;
}
return true;
}
Meta::AlbumPtr
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment