PageRenderTime 226ms CodeModel.GetById 60ms app.highlight 113ms RepoModel.GetById 48ms app.codeStats 0ms

/src/libtomahawk/Result.cpp

http://github.com/tomahawk-player/tomahawk
C++ | 714 lines | 518 code | 175 blank | 21 comment | 32 complexity | 81013e87e1541ffe2678bdb0d9552ed8 MD5 | raw file
  1/* === This file is part of Tomahawk Player - <http://tomahawk-player.org> ===
  2 *
  3 *   Copyright 2010-2015, Christian Muehlhaeuser <muesli@tomahawk-player.org>
  4 *   Copyright 2015,      Dominik Schmidt <domme@tomahawk-player.org>
  5 *
  6 *   Tomahawk is free software: you can redistribute it and/or modify
  7 *   it under the terms of the GNU General Public License as published by
  8 *   the Free Software Foundation, either version 3 of the License, or
  9 *   (at your option) any later version.
 10 *
 11 *   Tomahawk is distributed in the hope that it will be useful,
 12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 14 *   GNU General Public License for more details.
 15 *
 16 *   You should have received a copy of the GNU General Public License
 17 *   along with Tomahawk. If not, see <http://www.gnu.org/licenses/>.
 18 */
 19
 20#include "Result.h"
 21
 22#include "collection/Collection.h"
 23#include "database/Database.h"
 24#include "filemetadata/MetadataEditor.h"
 25#include "resolvers/ExternalResolverGui.h"
 26#include "resolvers/Resolver.h"
 27#include "utils/TomahawkUtilsGui.h"
 28#include "utils/Logger.h"
 29
 30#include "Album.h"
 31#include "Pipeline.h"
 32#include "PlaylistInterface.h"
 33#include "Source.h"
 34#include "TomahawkSettings.h"
 35#include "Track.h"
 36#include "Typedefs.h"
 37
 38#include <QCoreApplication>
 39
 40using namespace Tomahawk;
 41
 42static QHash< QString, result_wptr > s_results;
 43static QMutex s_mutex;
 44
 45typedef QMap< QString, QPixmap > SourceIconCache;
 46Q_GLOBAL_STATIC( SourceIconCache, sourceIconCache );
 47static QMutex s_sourceIconMutex;
 48
 49inline QString
 50sourceCacheKey( Resolver* resolver, const QSize& size, TomahawkUtils::ImageMode style )
 51{
 52    QString str;
 53    QTextStream stream( &str );
 54    stream << resolver << size.width() << size.height() << "_" << style;
 55    return str;
 56}
 57
 58
 59Tomahawk::result_ptr
 60Result::get( const QString& url, const track_ptr& track )
 61{
 62    if ( url.trimmed().isEmpty() || track.isNull() )
 63    {
 64        return result_ptr();
 65    }
 66
 67    QMutexLocker lock( &s_mutex );
 68    if ( s_results.contains( url ) )
 69    {
 70        return s_results.value( url );
 71    }
 72
 73    result_ptr r = result_ptr( new Result( url, track ), &Result::deleteLater );
 74    r->moveToThread( QCoreApplication::instance()->thread() );
 75    r->setWeakRef( r.toWeakRef() );
 76    s_results.insert( url, r );
 77
 78    return r;
 79}
 80
 81
 82result_ptr
 83Result::getCached( const QString& url )
 84{
 85    if ( url.trimmed().isEmpty() )
 86    {
 87        return result_ptr();
 88    }
 89
 90    QMutexLocker lock( &s_mutex );
 91    if ( s_results.contains( url ) )
 92    {
 93        return s_results.value( url );
 94    }
 95
 96    return result_ptr();
 97}
 98
 99
100Result::Result( const QString& url, const track_ptr& track )
101    : QObject()
102    , m_url( url )
103    , m_isPreview( false )
104    , m_checked( false )
105    , m_bitrate( 0 )
106    , m_size( 0 )
107    , m_modtime( 0 )
108    , m_fileId( 0 )
109    , m_track( track )
110{
111    connect( Pipeline::instance(), SIGNAL( resolverRemoved( Tomahawk::Resolver* ) ), SLOT( onResolverRemoved( Tomahawk::Resolver* ) ), Qt::QueuedConnection );
112}
113
114
115Result::~Result()
116{
117    tDebug( LOGVERBOSE ) << Q_FUNC_INFO << toString();
118}
119
120
121void
122Result::deleteLater()
123{
124    QMutexLocker lock( &s_mutex );
125
126    if ( s_results.contains( m_url ) )
127    {
128        s_results.remove( m_url );
129    }
130
131    QObject::deleteLater();
132}
133
134
135void
136Result::onResolverRemoved( Tomahawk::Resolver* resolver )
137{
138    m_mutex.lock();
139
140    if ( m_resolver.data() == resolver )
141    {
142        m_resolver = 0;
143        m_mutex.unlock();
144
145        emit statusChanged();
146    }
147    else
148    {
149        m_mutex.unlock();
150    }
151}
152
153
154collection_ptr
155Result::resolvedByCollection() const
156{
157    return m_collection;
158}
159
160
161QString
162Result::url() const
163{
164    QMutexLocker lock( &m_mutex );
165
166    return m_url;
167}
168
169
170bool
171Result::checked() const
172{
173    QMutexLocker lock( &m_mutex );
174
175    return m_checked;
176}
177
178
179bool
180Result::isPreview() const
181{
182    QMutexLocker lock( &m_mutex );
183
184    return m_isPreview;
185}
186
187
188QString
189Result::mimetype() const
190{
191    QMutexLocker lock( &m_mutex );
192
193    return m_mimetype;
194}
195
196
197RID
198Result::id() const
199{
200    QMutexLocker lock( &m_mutex );
201
202    if ( m_rid.isEmpty() )
203        m_rid = uuid();
204
205    return m_rid;
206}
207
208
209bool
210Result::isOnline() const
211{
212    if ( !resolvedByCollection().isNull() )
213    {
214        return resolvedByCollection()->isOnline();
215    }
216    else
217    {
218        QMutexLocker lock( &m_mutex );
219
220        return !m_resolver.isNull();
221    }
222}
223
224
225bool
226Result::playable() const
227{
228    if ( resolvedByCollection() )
229    {
230        return resolvedByCollection()->isOnline();
231    }
232
233    return true;
234}
235
236
237bool
238Result::isLocal() const
239{
240    return resolvedByCollection().isNull() ? false : resolvedByCollection()->isLocal();
241}
242
243
244QVariant
245Result::toVariant() const
246{
247    track_ptr t = track();
248
249    QVariantMap m;
250    m.insert( "artist", t->artist() );
251    m.insert( "album", t->album() );
252    m.insert( "track", t->track() );
253    m.insert( "source", friendlySource() );
254    m.insert( "mimetype", mimetype() );
255    m.insert( "size", size() );
256    m.insert( "bitrate", bitrate() );
257    m.insert( "duration", t->duration() );
258//    m.insert( "score", score() );
259    m.insert( "sid", id() );
260    m.insert( "discnumber", t->discnumber() );
261    m.insert( "albumpos", t->albumpos() );
262    m.insert( "preview", isPreview() );
263    m.insert( "purchaseUrl", purchaseUrl() );
264
265    if ( !t->composer().isEmpty() )
266        m.insert( "composer", t->composer() );
267
268    return m;
269}
270
271
272QString
273Result::toString() const
274{
275    m_mutex.lock();
276    track_ptr track = m_track;
277    QString url = m_url;
278    m_mutex.unlock();
279
280    if ( track )
281    {
282        return QString( "Result(%1) %2 - %3%4 (%5)" )
283                  .arg( id() )
284                  .arg( track->artist() )
285                  .arg( track->track() )
286                  .arg( track->album().isEmpty() ? QString() : QString( " on %1" ).arg( track->album() ) )
287                  .arg( url );
288    }
289    else
290    {
291        return QString( "Result(%1) (%2)" )
292                  .arg( id() )
293                  .arg( url );
294    }
295}
296
297
298Tomahawk::query_ptr
299Result::toQuery()
300{
301    QMutexLocker l( &m_mutex );
302
303    if ( m_query.isNull() )
304    {
305        query_ptr query = Tomahawk::Query::get( m_track );
306        if ( !query )
307            return query_ptr();
308
309        m_query = query->weakRef();
310
311        QList<Tomahawk::result_ptr> rl;
312        rl << m_ownRef.toStrongRef();
313        m_mutex.unlock();
314        query->addResults( rl );
315        m_mutex.lock();
316        query->setResolveFinished( true );
317        return query;
318    }
319
320
321    return m_query.toStrongRef();
322}
323
324
325void
326Result::onOnline()
327{
328    emit statusChanged();
329}
330
331
332void
333Result::onOffline()
334{
335    emit statusChanged();
336}
337
338
339void
340Result::setResolvedByCollection( const Tomahawk::collection_ptr& collection, bool emitOnlineEvents )
341{
342    m_collection = collection;
343
344    if ( emitOnlineEvents )
345    {
346        Q_ASSERT( !collection.isNull() );
347        connect( collection.data(), SIGNAL( destroyed( QObject * ) ), SLOT( onOffline() ), Qt::QueuedConnection );
348        connect( collection.data(), SIGNAL( online() ), SLOT( onOnline() ), Qt::QueuedConnection );
349        connect( collection.data(), SIGNAL( offline() ), SLOT( onOffline() ), Qt::QueuedConnection );
350    }
351}
352
353
354void
355Result::setFriendlySource( const QString& s )
356{
357    QMutexLocker lock( &m_mutex );
358
359    m_friendlySource = s;
360}
361
362
363void
364Result::setPreview( bool isPreview )
365{
366    QMutexLocker lock( &m_mutex );
367
368    m_isPreview = isPreview;
369}
370
371
372void
373Result::setPurchaseUrl( const QString& u )
374{
375    QMutexLocker lock( &m_mutex );
376
377    m_purchaseUrl = u;
378}
379
380
381void
382Result::setLinkUrl( const QString& u )
383{
384    QMutexLocker lock( &m_mutex );
385
386    m_linkUrl = u;
387}
388
389
390void
391Result::setChecked( bool checked )
392{
393    QMutexLocker lock( &m_mutex );
394
395    m_checked = checked;
396}
397
398
399void
400Result::setMimetype( const QString& mimetype )
401{
402    QMutexLocker lock( &m_mutex );
403
404    m_mimetype = mimetype;
405}
406
407
408void
409Result::setBitrate( unsigned int bitrate )
410{
411    QMutexLocker lock( &m_mutex );
412
413    m_bitrate = bitrate;
414}
415
416
417void
418Result::setSize( unsigned int size )
419{
420    QMutexLocker lock( &m_mutex );
421
422    m_size = size;
423}
424
425
426void
427Result::setModificationTime( unsigned int modtime )
428{
429    QMutexLocker lock( &m_mutex );
430
431    m_modtime = modtime;
432}
433
434
435void
436Result::setTrack( const track_ptr& track )
437{
438    QMutexLocker lock( &m_mutex );
439
440    m_track = track;
441}
442
443
444unsigned int
445Result::fileId() const
446{
447    QMutexLocker lock( &m_mutex );
448
449    return m_fileId;
450}
451
452
453QString
454Result::friendlySource() const
455{
456    if ( resolvedByCollection().isNull() )
457    {
458        QMutexLocker lock( &m_mutex );
459
460        return m_friendlySource;
461    }
462    else
463        return resolvedByCollection()->prettyName();
464}
465
466
467QString
468Result::purchaseUrl() const
469{
470    QMutexLocker lock( &m_mutex );
471
472    return m_purchaseUrl;
473}
474
475
476QString
477Result::linkUrl() const
478{
479    QMutexLocker lock( &m_mutex );
480
481    return m_linkUrl;
482}
483
484
485QPixmap
486Result::sourceIcon( TomahawkUtils::ImageMode style, const QSize& desiredSize ) const
487{
488    if ( resolvedByCollection().isNull() )
489    {
490        //QMutexLocker lock( &m_mutex );
491
492        const ExternalResolver* resolver = qobject_cast< ExternalResolver* >( m_resolver.data() );
493        if ( !resolver )
494        {
495            return QPixmap();
496        }
497        else
498        {
499            QMutexLocker l( &s_sourceIconMutex );
500
501            const QString key = sourceCacheKey( m_resolver.data(), desiredSize, style );
502            if ( !sourceIconCache()->contains( key ) )
503            {
504                QPixmap pixmap = resolver->icon( desiredSize );
505                if ( pixmap.isNull() )
506                    return pixmap;
507
508                switch ( style )
509                {
510                    case TomahawkUtils::DropShadow:
511                        pixmap = TomahawkUtils::addDropShadow( pixmap, QSize() );
512                        break;
513
514                    case TomahawkUtils::RoundedCorners:
515                        pixmap = TomahawkUtils::createRoundedImage( pixmap, QSize() );
516                        break;
517
518                    default:
519                        break;
520                }
521
522                sourceIconCache()->insert( key, pixmap );
523                return pixmap;
524            }
525            else
526            {
527                return sourceIconCache()->value( key );
528            }
529        }
530    }
531    else
532    {
533        QPixmap avatar = resolvedByCollection()->icon( desiredSize );
534        return avatar;
535    }
536}
537
538
539unsigned int
540Result::bitrate() const
541{
542    QMutexLocker lock( &m_mutex );
543
544    return m_bitrate;
545}
546
547
548unsigned int
549Result::size() const
550{
551    QMutexLocker lock( &m_mutex );
552
553    return m_size;
554}
555
556
557unsigned int
558Result::modificationTime() const
559{
560    QMutexLocker lock( &m_mutex );
561
562    return m_modtime;
563}
564
565
566void
567Result::setFileId( unsigned int id )
568{
569    QMutexLocker lock( &m_mutex );
570
571    m_fileId = id;
572}
573
574
575Tomahawk::Resolver*
576Result::resolvedBy() const
577{
578    QMutexLocker lock( &m_mutex );
579
580    if ( !m_collection.isNull() )
581        return m_collection.data();
582
583    return m_resolver.data();
584}
585
586
587void
588Result::setResolvedByResolver( Tomahawk::Resolver* resolver )
589{
590    QMutexLocker lock( &m_mutex );
591
592    m_resolver = QPointer< Tomahawk::Resolver >( resolver );
593}
594
595
596QPointer< Resolver > Result::resolvedByResolver() const
597{
598    QMutexLocker lock( &m_mutex );
599
600    return m_resolver;
601}
602
603
604void
605Result::doneEditing()
606{
607//    m_query.clear();
608    emit updated();
609}
610
611
612track_ptr
613Result::track() const
614{
615    QMutexLocker lock( &m_mutex );
616
617    return m_track;
618}
619
620
621QList< DownloadFormat >
622Result::downloadFormats() const
623{
624    QMutexLocker lock( &m_mutex );
625
626    return m_formats;
627}
628
629
630void
631Result::setDownloadFormats( const QList<DownloadFormat>& formats )
632{
633    if ( formats.isEmpty() )
634        return;
635
636    QMutexLocker lock( &m_mutex );
637
638    m_formats.clear();
639    foreach ( const DownloadFormat& format, formats )
640    {
641        if ( format.extension.toLower() == TomahawkSettings::instance()->downloadsPreferredFormat().toLower() )
642        {
643            m_formats.insert( 0, format );
644        }
645        else
646        {
647            m_formats << format;
648        }
649    }
650
651    if ( !m_formats.isEmpty() )
652    {
653        connect( TomahawkSettings::instance(), SIGNAL( changed() ), this, SLOT( onSettingsChanged() ), Qt::UniqueConnection );
654    }
655    else
656    {
657        disconnect( TomahawkSettings::instance(), SIGNAL( changed() ), this, SLOT( onSettingsChanged() ) );
658    }
659}
660
661
662void
663Result::onSettingsChanged()
664{
665    if ( TomahawkSettings::instance()->downloadsPreferredFormat().toLower() != downloadFormats().first().extension.toLower() )
666    {
667        setDownloadFormats( downloadFormats() );
668        emit updated();
669    }
670}
671
672
673downloadjob_ptr
674Result::toDownloadJob( const DownloadFormat& format )
675{
676    if ( !m_downloadJob )
677    {
678        m_downloadJob = downloadjob_ptr( new DownloadJob( weakRef().toStrongRef(), format ) );
679        connect( m_downloadJob.data(), SIGNAL( progress( int ) ), SIGNAL( updated() ) );
680        connect( m_downloadJob.data(), SIGNAL( stateChanged( DownloadJob::TrackState, DownloadJob::TrackState ) ),
681                                         SLOT( onDownloadJobStateChanged( DownloadJob::TrackState, DownloadJob::TrackState ) ) );
682    }
683
684    return m_downloadJob;
685}
686
687
688void
689Result::onDownloadJobStateChanged( DownloadJob::TrackState newState, DownloadJob::TrackState oldState )
690{
691    if ( newState == DownloadJob::Aborted )
692    {
693        m_downloadJob.clear();
694        emit updated();
695    }
696}
697
698
699QWeakPointer<Result>
700Result::weakRef()
701{
702    QMutexLocker lock( &m_mutex );
703
704    return m_ownRef;
705}
706
707
708void
709Result::setWeakRef( QWeakPointer<Result> weakRef )
710{
711    QMutexLocker lock( &m_mutex );
712
713    m_ownRef = weakRef;
714}