// watcher void CoverArtCache::coverLoaded() { QFutureWatcher<FutureResult>* watcher; watcher = reinterpret_cast<QFutureWatcher<FutureResult>*>(sender()); FutureResult res = watcher->result(); if (sDebug) { kLogger.debug() << "coverLoaded" << res.cover; } // Don't cache full size covers (resizedToWidth = 0) // Large cover art wastes space in our cache and will likely // uncache a lot of the small covers we need in the library // table. // Full size covers are used in the Skin Widgets, which are // loaded with an artificial delay anyway and an additional // re-load delay can be accepted. // Create pixmap, GUI thread only QPixmap pixmap = QPixmap::fromImage(res.cover.image); if (!pixmap.isNull() && res.cover.resizedToWidth != 0) { // we have to be sure that res.cover.hash is unique // because insert replaces the images with the same key QString cacheKey = pixmapCacheKey( res.cover.hash, res.cover.resizedToWidth); QPixmapCache::insert(cacheKey, pixmap); } m_runningRequests.remove(qMakePair(res.pRequestor, res.cover.hash)); if (res.signalWhenDone) { emit(coverFound(res.pRequestor, res.cover, pixmap, false)); } }
QPixmap CoverArtCache::requestCover(const CoverInfo& requestInfo, const QObject* pRequestor, int requestReference, const int desiredWidth, const bool onlyCached, const bool signalWhenDone) { if (sDebug) { qDebug() << "CoverArtCache::requestCover" << requestInfo << pRequestor << requestReference << desiredWidth << onlyCached << signalWhenDone; } if (requestInfo.type == CoverInfo::NONE) { if (signalWhenDone) { emit(coverFound(pRequestor, requestReference, requestInfo, QPixmap(), true)); } return QPixmap(); } // keep a list of trackIds for which a future is currently running // to avoid loading the same picture again while we are loading it QPair<const QObject*, int> requestId = qMakePair(pRequestor, requestReference); if (m_runningRequests.contains(requestId)) { return QPixmap(); } // If this request comes from CoverDelegate (table view), it'll want to get // a cropped cover which is ready to be drawn in the table view (cover art // column). It's very important to keep the cropped covers in cache because // it avoids having to rescale+crop it ALWAYS (which brings a lot of // performance issues). QString cacheKey = CoverArtUtils::pixmapCacheKey(requestInfo.hash, desiredWidth); QPixmap pixmap; if (QPixmapCache::find(cacheKey, &pixmap)) { if (signalWhenDone) { emit(coverFound(pRequestor, requestReference, requestInfo, pixmap, true)); } return pixmap; } if (onlyCached) { if (sDebug) { qDebug() << "CoverArtCache::requestCover cache miss"; } return QPixmap(); } m_runningRequests.insert(requestId); QFutureWatcher<FutureResult>* watcher = new QFutureWatcher<FutureResult>(this); QFuture<FutureResult> future = QtConcurrent::run( this, &CoverArtCache::loadCover, requestInfo, pRequestor, requestReference, desiredWidth, signalWhenDone); connect(watcher, SIGNAL(finished()), this, SLOT(coverLoaded())); watcher->setFuture(future); return QPixmap(); }
// watcher void CoverArtCache::coverLoaded() { QFutureWatcher<FutureResult>* watcher; watcher = reinterpret_cast<QFutureWatcher<FutureResult>*>(sender()); FutureResult res = watcher->result(); if (sDebug) { qDebug() << "CoverArtCache::coverLoaded" << res.cover; } QString cacheKey = CoverArtUtils::pixmapCacheKey(res.cover.info.hash, res.desiredWidth); QPixmap pixmap; if (!QPixmapCache::find(cacheKey, &pixmap) && !res.cover.image.isNull()) { pixmap.convertFromImage(res.cover.image); QPixmapCache::insert(cacheKey, pixmap); } m_runningRequests.remove(qMakePair(res.pRequestor, res.requestReference)); if (res.signalWhenDone) { emit(coverFound(res.pRequestor, res.requestReference, res.cover.info, pixmap, false)); } }