PageRenderTime 538ms CodeModel.GetById 81ms app.highlight 373ms RepoModel.GetById 80ms app.codeStats 1ms

/src/libtomahawk/infosystem/InfoSystem.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 408 lines | 294 code | 92 blank | 22 comment | 30 complexity | c2a3601842e28131aae54ba332a449c5 MD5 | raw file
  1/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2 *
  3 *   Copyright 2010-2011, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4 *   Copyright 2012       Leo Franchi            <lfranchi@kde.org>
  5 *   Copyright 2010-2011, Jeff Mitchell <jeff@tomahawk-player.org>
  6 *
  7 *   Tomahawk is free software: you can redistribute it and/or modify
  8 *   it under the terms of the GNU General Public License as published by
  9 *   the Free Software Foundation, either version 3 of the License, or
 10 *   (at your option) any later version.
 11 *
 12 *   Tomahawk is distributed in the hope that it will be useful,
 13 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 14 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15 *   GNU General Public License for more details.
 16 *
 17 *   You should have received a copy of the GNU General Public License
 18 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 19 */
 20
 21#include <QCoreApplication>
 22
 23#include "InfoSystem.h"
 24#include "TomahawkSettings.h"
 25#include "InfoSystemCache.h"
 26#include "InfoSystemWorker.h"
 27#include "utils/TomahawkUtils.h"
 28#include "utils/Logger.h"
 29#include "Source.h"
 30
 31namespace Tomahawk
 32{
 33
 34namespace InfoSystem
 35{
 36
 37static const int DEFAULT_TIMEOUT_MILLIS = 10000;
 38
 39InfoRequestData::InfoRequestData()
 40    : requestId( TomahawkUtils::infosystemRequestId() )
 41{
 42    init( QString() , Tomahawk::InfoSystem::InfoNoInfo, QVariant(), QVariantMap() );
 43}
 44
 45
 46InfoRequestData::InfoRequestData( const quint64 rId, const QString& callr, const InfoType typ, const QVariant& inputvar, const QVariantMap& custom )
 47    : requestId( rId )
 48{
 49    init( callr, typ, inputvar, custom );
 50}
 51
 52
 53void
 54InfoRequestData::init( const QString& callr, const InfoType typ, const QVariant& inputvar, const QVariantMap& custom )
 55{
 56    internalId = TomahawkUtils::infosystemRequestId();
 57    caller = callr;
 58    type = typ;
 59    input = inputvar;
 60    customData = custom;
 61    timeoutMillis = DEFAULT_TIMEOUT_MILLIS;
 62    allSources = false;
 63}
 64
 65
 66InfoPlugin::InfoPlugin()
 67    : QObject()
 68{
 69}
 70
 71
 72InfoPlugin::~InfoPlugin()
 73{
 74}
 75
 76
 77void
 78InfoPlugin::setFriendlyName( const QString& friendlyName )
 79{
 80    m_friendlyName = friendlyName;
 81}
 82
 83
 84const QString
 85InfoPlugin::friendlyName() const
 86{
 87    return m_friendlyName;
 88}
 89
 90
 91InfoSystem* InfoSystem::s_instance = 0;
 92
 93InfoSystem*
 94InfoSystem::instance()
 95{
 96    if ( !s_instance )
 97        s_instance = new InfoSystem( 0 );
 98
 99    return s_instance;
100}
101
102
103InfoSystem::InfoSystem( QObject* parent )
104    : QObject( parent )
105    , m_inited( false )
106    , m_infoSystemCacheThreadController( 0 )
107    , m_infoSystemWorkerThreadController( 0 )
108{
109    s_instance = this;
110
111    m_infoSystemCacheThreadController = new InfoSystemCacheThread( this );
112    m_infoSystemCacheThreadController->start( QThread::IdlePriority );
113
114    m_infoSystemWorkerThreadController = new InfoSystemWorkerThread( this );
115    m_infoSystemWorkerThreadController->start();
116
117    QTimer::singleShot( 0, this, SLOT( init() ) );
118}
119
120
121InfoSystem::~InfoSystem()
122{
123    tDebug() << Q_FUNC_INFO << "beginning";
124
125    if ( m_infoSystemWorkerThreadController )
126    {
127        m_infoSystemWorkerThreadController->quit();
128        m_infoSystemWorkerThreadController->wait( 60000 );
129
130        delete m_infoSystemWorkerThreadController;
131        m_infoSystemWorkerThreadController = 0;
132    }
133    tDebug() << Q_FUNC_INFO << "done deleting worker";
134
135    if ( m_infoSystemCacheThreadController )
136    {
137        m_infoSystemCacheThreadController->quit();
138        m_infoSystemCacheThreadController->wait( 60000 );
139
140        delete m_infoSystemCacheThreadController;
141        m_infoSystemCacheThreadController = 0;
142    }
143
144    tDebug() << Q_FUNC_INFO << "done deleting cache";
145}
146
147
148void
149InfoSystem::init()
150{
151    if ( m_inited )
152        return;
153
154    if ( !m_infoSystemCacheThreadController->cache() || !m_infoSystemWorkerThreadController->worker() )
155    {
156        // tLog() << "Worker not found";
157        QTimer::singleShot( 0, this, SLOT( init() ) );
158        return;
159    }
160
161    Tomahawk::InfoSystem::InfoSystemCache* cache = m_infoSystemCacheThreadController->cache();
162    Tomahawk::InfoSystem::InfoSystemWorker* worker = m_infoSystemWorkerThreadController->worker();
163
164    connect( cache, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
165             worker, SLOT( infoSlot( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
166
167    connect( worker, SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ),
168             this,       SIGNAL( info( Tomahawk::InfoSystem::InfoRequestData, QVariant ) ), Qt::UniqueConnection );
169
170    connect( worker, SIGNAL( finished( QString ) ), this, SIGNAL( finished( QString ) ), Qt::UniqueConnection );
171
172    connect( worker, SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ),
173             this, SIGNAL( finished( QString, Tomahawk::InfoSystem::InfoType ) ), Qt::UniqueConnection );
174
175    qRegisterMetaType< Tomahawk::InfoSystem::InfoTypeSet >();
176    connect( worker, SIGNAL( updatedSupportedGetTypes( Tomahawk::InfoSystem::InfoTypeSet ) ),
177             this,   SLOT(   receiveUpdatedSupportedGetTypes( Tomahawk::InfoSystem::InfoTypeSet ) ) );
178    connect( worker, SIGNAL( updatedSupportedPushTypes( Tomahawk::InfoSystem::InfoTypeSet ) ),
179             this,   SLOT(   receiveUpdatedSupportedPushTypes( Tomahawk::InfoSystem::InfoTypeSet ) ) );
180
181    QMetaObject::invokeMethod( worker, "init", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoSystemCache*, cache ) );
182
183    m_inited = true;
184    emit ready();
185}
186
187
188bool
189InfoSystem::getInfo( const InfoRequestData& requestData )
190{
191    if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
192    {
193        init();
194        return false;
195    }
196    QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
197    return true;
198}
199
200
201bool
202InfoSystem::getInfo( const QString& caller, const QVariantMap& customData, const InfoTypeMap& inputMap, const InfoTimeoutMap& timeoutMap, bool allSources )
203{
204    if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
205    {
206        init();
207        return false;
208    }
209    InfoRequestData requestData;
210    requestData.caller = caller;
211    requestData.customData = customData;
212    requestData.allSources = allSources;
213    foreach ( InfoType type, inputMap.keys() )
214    {
215        requestData.type = type;
216        requestData.input = inputMap[ type ];
217        requestData.timeoutMillis = timeoutMap.contains( type ) ? timeoutMap[ type ] : DEFAULT_TIMEOUT_MILLIS;
218        QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "getInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoRequestData, requestData ) );
219    }
220    return false;
221}
222
223
224bool
225InfoSystem::pushInfo( InfoPushData pushData )
226{
227    tDebug( LOGVERBOSE ) << Q_FUNC_INFO << "type is" << pushData.type;
228    if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
229    {
230        init();
231        return false;
232    }
233
234    PushInfoPair pushInfoPair( QVariantMap(), pushData.input );
235    pushData.infoPair = pushInfoPair;
236    QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "pushInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPushData, pushData ) );
237
238    return true;
239}
240
241
242bool
243InfoSystem::pushInfo( const QString& caller, const InfoTypeMap& input, const PushInfoFlags pushFlags )
244{
245    if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
246    {
247        init();
248        return false;
249    }
250
251    foreach ( InfoType type, input.keys() )
252    {
253        InfoPushData pushData( caller, type, input[ type ], pushFlags );
254        pushData.infoPair = PushInfoPair( QVariantMap(), pushData.input );
255        QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "pushInfo", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPushData, pushData ) );
256    }
257
258    return true;
259}
260
261
262void
263InfoSystem::addInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin )
264{
265    // Init is not complete (waiting for worker thread to start and create worker object) so keep trying till then
266    if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
267    {
268        QMetaObject::invokeMethod( this, "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) );
269        return;
270    }
271
272    if ( plugin.isNull() )
273    {
274        tDebug() << Q_FUNC_INFO << "Given plugin is null!";
275        return;
276    }
277
278    if ( plugin.data()->thread() != m_infoSystemWorkerThreadController->worker()->thread() )
279    {
280        tLog() << Q_FUNC_INFO << "The object must be moved to the worker thread first, see InfoSystem::workerThread(): " << plugin->friendlyName();
281        Q_ASSERT( false );
282        return;
283    }
284
285    tDebug( LOGVERBOSE ) << Q_FUNC_INFO << plugin.data();
286    QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "addInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) );
287}
288
289
290void
291InfoSystem::removeInfoPlugin( Tomahawk::InfoSystem::InfoPluginPtr plugin )
292{
293    // Init is not complete (waiting for worker th read to start and create worker object) so keep trying till then
294    if ( !m_inited || !m_infoSystemWorkerThreadController->worker() )
295    {
296        QMetaObject::invokeMethod( this, "removeInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) );
297        return;
298    }
299
300    if ( plugin.isNull() )
301    {
302        tDebug() << Q_FUNC_INFO << "Given plugin is null!";
303        return;
304    }
305
306    if ( plugin.data()->thread() != m_infoSystemWorkerThreadController->worker()->thread() )
307    {
308        tDebug() << Q_FUNC_INFO << "The object must be moved to the worker thread first, see InfoSystem::workerThread()";
309        return;
310    }
311
312    tDebug( LOGVERBOSE ) << Q_FUNC_INFO << plugin.data();
313    QMetaObject::invokeMethod( m_infoSystemWorkerThreadController->worker(), "removeInfoPlugin", Qt::QueuedConnection, Q_ARG( Tomahawk::InfoSystem::InfoPluginPtr, plugin ) );
314}
315
316
317void
318InfoSystem::receiveUpdatedSupportedGetTypes( InfoTypeSet supportedTypes )
319{
320    m_supportedGetTypes = supportedTypes;
321    emit updatedSupportedGetTypes( m_supportedGetTypes );
322}
323
324
325void
326InfoSystem::receiveUpdatedSupportedPushTypes( InfoTypeSet supportedTypes )
327{
328    m_supportedPushTypes = supportedTypes;
329    emit updatedSupportedPushTypes( m_supportedPushTypes );
330}
331
332
333QPointer< QThread >
334InfoSystem::workerThread() const
335{
336    if ( m_infoSystemWorkerThreadController->isRunning() && m_infoSystemWorkerThreadController->worker() )
337        return QPointer< QThread >( m_infoSystemWorkerThreadController->worker()->thread() );
338
339    return QPointer< QThread >();
340}
341
342
343InfoSystemCacheThread::InfoSystemCacheThread( QObject* parent )
344    : QThread( parent )
345{
346    tDebug() << Q_FUNC_INFO;
347}
348
349
350InfoSystemCacheThread::~InfoSystemCacheThread()
351{
352    tDebug() << Q_FUNC_INFO;
353}
354
355
356void
357InfoSystemCacheThread::InfoSystemCacheThread::run()
358{
359    m_cache = QPointer< InfoSystemCache >( new InfoSystemCache() );
360    exec();
361    if ( !m_cache.isNull() )
362        delete m_cache.data();
363}
364
365
366InfoSystemCache*
367InfoSystemCacheThread::cache() const
368{
369    if ( m_cache.isNull() )
370        return 0;
371    return m_cache.data();
372}
373
374
375InfoSystemWorkerThread::InfoSystemWorkerThread( QObject* parent )
376    : QThread( parent )
377{
378    tDebug() << Q_FUNC_INFO;
379}
380
381
382InfoSystemWorkerThread::~InfoSystemWorkerThread()
383{
384    tDebug() << Q_FUNC_INFO;
385}
386
387
388void
389InfoSystemWorkerThread::InfoSystemWorkerThread::run()
390{
391    m_worker = QPointer< InfoSystemWorker >( new InfoSystemWorker() );
392    exec();
393    if ( !m_worker.isNull() )
394        delete m_worker.data();
395}
396
397
398InfoSystemWorker*
399InfoSystemWorkerThread::worker() const
400{
401    if ( m_worker.isNull() )
402        return 0;
403    return m_worker.data();
404}
405
406} //namespace InfoSystem
407
408} //namespace Tomahawk