summaryrefslogtreecommitdiffstats
path: root/src/library
diff options
context:
space:
mode:
authorxerus2000 <27jf@pm.me>2020-06-11 19:42:13 +0200
committerxerus2000 <27jf@pm.me>2020-06-11 19:42:13 +0200
commit87575715297e806fc7af33daf7e9572fbf51a607 (patch)
tree3e5384a9f98aa45161c878343129bff6696bb560 /src/library
parenteb756ee61a4007f3ad91195c57f85e3786f8e1cc (diff)
parent091253696f83a6b3c8a6e5976f5138e1caaa71f0 (diff)
Merge branch 'master' into refactor-basetrackset
Diffstat (limited to 'src/library')
-rw-r--r--src/library/banshee/bansheeplaylistmodel.h2
-rw-r--r--src/library/coverart.cpp110
-rw-r--r--src/library/coverart.h55
-rw-r--r--src/library/coverartcache.cpp107
-rw-r--r--src/library/coverartcache.h4
-rw-r--r--src/library/coverartdelegate.h2
-rw-r--r--src/library/dao/playlistdao.cpp2
-rw-r--r--src/library/dlgcoverartfullsize.cpp5
-rw-r--r--src/library/hiddentablemodel.h2
-rw-r--r--src/library/missingtablemodel.h2
-rw-r--r--src/library/playlisttablemodel.h2
-rw-r--r--src/library/songdownloader.cpp9
-rw-r--r--src/library/trackcollection.cpp51
-rw-r--r--src/library/trackcollection.h8
-rw-r--r--src/library/trackcollectionmanager.cpp27
-rw-r--r--src/library/trackcollectionmanager.h4
-rw-r--r--src/library/trackset/crate/cratetablemodel.h2
17 files changed, 287 insertions, 107 deletions
diff --git a/src/library/banshee/bansheeplaylistmodel.h b/src/library/banshee/bansheeplaylistmodel.h
index d6cad06cf5..f632c04e67 100644
--- a/src/library/banshee/bansheeplaylistmodel.h
+++ b/src/library/banshee/bansheeplaylistmodel.h
@@ -11,7 +11,7 @@
#include "library/stardelegate.h"
#include "library/basesqltablemodel.h"
-class BansheePlaylistModel : public BaseSqlTableModel {
+class BansheePlaylistModel final : public BaseSqlTableModel {
Q_OBJECT
public:
BansheePlaylistModel(QObject* pParent, TrackCollectionManager* pTrackCollectionManager, BansheeDbConnection* pConnection);
diff --git a/src/library/coverart.cpp b/src/library/coverart.cpp
index 491dbbe139..85620cdd87 100644
--- a/src/library/coverart.cpp
+++ b/src/library/coverart.cpp
@@ -1,5 +1,7 @@
#include "library/coverart.h"
+#include <QDebugStateSaver>
+
#include "library/coverartutils.h"
#include "util/debug.h"
#include "util/logger.h"
@@ -83,19 +85,27 @@ QDebug operator<<(QDebug dbg, const CoverInfoRelative& infoRelative) {
.arg(coverInfoRelativeToString(infoRelative));
}
-QImage CoverInfo::loadImage(
+CoverInfo::LoadedImage CoverInfo::loadImage(
const SecurityTokenPointer& pTrackLocationToken) const {
+ LoadedImage loadedImage(LoadedImage::Result::ErrorUnknown);
if (type == CoverInfo::METADATA) {
VERIFY_OR_DEBUG_ASSERT(!trackLocation.isEmpty()) {
- kLogger.warning()
- << "loadImage"
- << type
- << "cover with empty trackLocation";
- return QImage();
+ loadedImage.result = LoadedImage::Result::ErrorMetadataWithEmptyTrackLocation;
+ return loadedImage;
}
- return CoverArtUtils::extractEmbeddedCover(
+ loadedImage.filePath = trackLocation;
+ loadedImage.image = CoverArtUtils::extractEmbeddedCover(
TrackFile(trackLocation),
pTrackLocationToken);
+ if (loadedImage.image.isNull()) {
+ // TODO: extractEmbeddedCover() should indicate if no image
+ // is available or if loading the embedded image failed.
+ // Until then we assume optimistically that no image is
+ // available instead of presuming that an error occurred.
+ loadedImage.result = LoadedImage::Result::NoImage;
+ } else {
+ loadedImage.result = LoadedImage::Result::Ok;
+ }
} else if (type == CoverInfo::FILE) {
auto coverFile = QFileInfo(coverLocation);
if (coverFile.isRelative()) {
@@ -104,13 +114,9 @@ QImage CoverInfo::loadImage(
// must have a valid location, i.e. a file path. Most
// likely a programming error, but might also be caused
// by yet unknown circumstances.
- kLogger.warning()
- << "loadImage"
- << type
- << "cover with empty track location"
- << "and relative file path:"
- << coverFile.filePath();
- return QImage();
+ loadedImage.result = LoadedImage::Result::
+ ErrorRelativeFilePathWithEmptyTrackLocation;
+ return loadedImage;
}
// Compose track directory with relative path
const auto trackFile = TrackFile(trackLocation);
@@ -120,28 +126,28 @@ QImage CoverInfo::loadImage(
coverLocation);
}
DEBUG_ASSERT(coverFile.isAbsolute());
+ loadedImage.filePath = coverFile.filePath();
if (!coverFile.exists()) {
- // Disabled because this code can cause high CPU and thus possibly
- // xruns as it might print the warning repeatedly.
- // ToDo: Print warning about missing cover image only once.
- // kLogger.warning()
- // << "loadImage"
- // << type
- // << "cover does not exist:"
- // << coverFile.filePath();
- return QImage();
+ loadedImage.result = LoadedImage::Result::ErrorFilePathDoesNotExist;
+ return loadedImage;
}
SecurityTokenPointer pToken =
Sandbox::openSecurityToken(
coverFile,
true);
- return QImage(coverFile.filePath());
+ if (loadedImage.image.load(loadedImage.filePath)) {
+ DEBUG_ASSERT(!loadedImage.image.isNull());
+ loadedImage.result = LoadedImage::Result::Ok;
+ } else {
+ DEBUG_ASSERT(loadedImage.image.isNull());
+ loadedImage.result = LoadedImage::Result::ErrorLoadingFailed;
+ }
} else if (type == CoverInfo::NONE) {
- return QImage();
+ loadedImage.result = LoadedImage::Result::NoImage;
} else {
DEBUG_ASSERT(!"unhandled CoverInfo::Type");
- return QImage();
}
+ return loadedImage;
}
bool CoverInfo::refreshImageHash(
@@ -154,8 +160,8 @@ bool CoverInfo::refreshImageHash(
return false;
}
QImage image = loadedImage;
- if (loadedImage.isNull()) {
- image = loadImage(pTrackLocationToken);
+ if (image.isNull()) {
+ image = loadImage(pTrackLocationToken).image;
}
if (image.isNull() && type != CoverInfo::NONE) {
kLogger.warning()
@@ -185,9 +191,49 @@ QDebug operator<<(QDebug dbg, const CoverInfo& info) {
.arg(coverInfoToString(info));
}
+QDebug operator<<(QDebug dbg, const CoverInfo::LoadedImage::Result& result) {
+ switch (result) {
+ case CoverInfo::LoadedImage::Result::Ok:
+ return dbg << "Ok";
+ case CoverInfo::LoadedImage::Result::NoImage:
+ return dbg << "NoImage";
+ case CoverInfo::LoadedImage::Result::ErrorMetadataWithEmptyTrackLocation:
+ return dbg << "ErrorMetadataWithEmptyTrackLocation";
+ case CoverInfo::LoadedImage::Result::ErrorRelativeFilePathWithEmptyTrackLocation:
+ return dbg << "ErrorRelativeFilePathWithEmptyTrackLocation";
+ case CoverInfo::LoadedImage::Result::ErrorFilePathDoesNotExist:
+ return dbg << "ErrorFilePathDoesNotExist";
+ case CoverInfo::LoadedImage::Result::ErrorLoadingFailed:
+ return dbg << "ErrorLoadingFailed";
+ case CoverInfo::LoadedImage::Result::ErrorUnknown:
+ return dbg << "ErrorUnknown";
+ }
+ DEBUG_ASSERT(!"unreachable");
+ return dbg;
+}
+
+QDebug operator<<(QDebug dbg, const CoverInfo::LoadedImage& loadedImage) {
+ const QDebugStateSaver saver(dbg);
+ dbg = dbg.maybeSpace() << "CoverInfo::LoadedImage";
+ return dbg.nospace()
+ << '{'
+ << loadedImage.filePath
+ << ','
+ << loadedImage.image.size()
+ << ','
+ << loadedImage.result
+ << '}';
+}
+
QDebug operator<<(QDebug dbg, const CoverArt& art) {
- return dbg.maybeSpace() << QString("CoverArt(%1,%2,%3)")
- .arg(coverInfoToString(art),
- toDebugString(art.image.size()),
- QString::number(art.resizedToWidth));
+ const QDebugStateSaver saver(dbg);
+ dbg = dbg.maybeSpace() << "CoverArt";
+ return dbg.nospace()
+ << '{'
+ << static_cast<const CoverInfo&>(art)
+ << ','
+ << art.loadedImage
+ << ','
+ << art.resizedToWidth
+ << '}';
}
diff --git a/src/library/coverart.h b/src/library/coverart.h
index d9179c3d08..74fa85722a 100644
--- a/src/library/coverart.h
+++ b/src/library/coverart.h
@@ -85,7 +85,40 @@ class CoverInfo : public CoverInfoRelative {
CoverInfo(CoverInfo&&) = default;
CoverInfo& operator=(CoverInfo&&) = default;
- QImage loadImage(
+ struct LoadedImage final {
+ enum class Result {
+ Ok,
+ NoImage,
+ ErrorMetadataWithEmptyTrackLocation,
+ ErrorRelativeFilePathWithEmptyTrackLocation,
+ ErrorFilePathDoesNotExist,
+ ErrorLoadingFailed, // if the image file is not readable or the format is not supported
+ ErrorUnknown, // should never happen
+ };
+
+ LoadedImage(const LoadedImage&) = default;
+ LoadedImage(LoadedImage&&) = default;
+ LoadedImage& operator=(const LoadedImage&) = default;
+ LoadedImage& operator=(LoadedImage&&) = default;
+
+ /// The loaded image if available.
+ QImage image;
+
+ /// Either the track location if the image was embedded in
+ /// the metadata or the (absolute) path of the image file.
+ QString filePath;
+
+ /// The result of the operation.
+ Result result;
+
+ private:
+ friend class CoverArt;
+ friend class CoverInfo;
+ LoadedImage(Result result)
+ : result(result) {
+ }
+ };
+ LoadedImage loadImage(
const SecurityTokenPointer& pTrackLocationToken = SecurityTokenPointer()) const;
// Verify the image hash and update it if necessary.
@@ -103,16 +136,22 @@ bool operator==(const CoverInfo& a, const CoverInfo& b);
bool operator!=(const CoverInfo& a, const CoverInfo& b);
QDebug operator<<(QDebug dbg, const CoverInfo& info);
+QDebug operator<<(QDebug dbg, const CoverInfo::LoadedImage::Result& result);
+QDebug operator<<(QDebug dbg, const CoverInfo::LoadedImage& loadedImage);
+
class CoverArt : public CoverInfo {
public:
CoverArt()
- : resizedToWidth(0) {
+ : loadedImage(LoadedImage::Result::NoImage), // not loaded = no image
+ resizedToWidth(0) {
}
-
- CoverArt(const CoverInfo& base, const QImage& img, int rtw)
- : CoverInfo(base),
- image(img),
- resizedToWidth(rtw) {
+ CoverArt(
+ const CoverInfo&& base,
+ CoverInfo::LoadedImage&& loadedImage,
+ int resizedToWidth)
+ : CoverInfo(std::move(base)),
+ loadedImage(std::move(loadedImage)),
+ resizedToWidth(resizedToWidth) {
}
// all-default memory management
@@ -123,7 +162,7 @@ class CoverArt : public CoverInfo {
// it is not a QPixmap, because it is not safe to use pixmaps
// outside the GUI thread
- QImage image;
+ CoverInfo::LoadedImage loadedImage;
int resizedToWidth;
};
diff --git a/src/library/coverartcache.cpp b/src/library/coverartcache.cpp
index 019afdb0dd..bcf0093d3b 100644
--- a/src/library/coverartcache.cpp
+++ b/src/library/coverartcache.cpp
@@ -1,13 +1,14 @@
+#include "library/coverartcache.h"
+
#include <QFutureWatcher>
#include <QPixmapCache>
#include <QtConcurrentRun>
#include <QtDebug>
-#include "library/coverartcache.h"
#include "library/coverartutils.h"
#include "util/compatibility.h"
#include "util/logger.h"
-
+#include "util/thread_affinity.h"
namespace {
@@ -176,26 +177,30 @@ CoverArtCache::FutureResult CoverArtCache::loadCover(
res.signalWhenDone = signalWhenDone;
DEBUG_ASSERT(!res.coverInfoUpdated);
- QImage image = coverInfo.loadImage(
+ auto loadedImage = coverInfo.loadImage(
pTrack ? pTrack->getSecurityToken() : SecurityTokenPointer());
+ if (!loadedImage.image.isNull()) {
+ // Refresh hash before resizing the original image!
+ res.coverInfoUpdated = coverInfo.refreshImageHash(loadedImage.image);
+ if (pTrack && res.coverInfoUpdated) {
+ kLogger.info()
+ << "Updating cover info of track"
+ << coverInfo.trackLocation;
+ pTrack->setCoverInfo(coverInfo);
+ }
- // Refresh hash before resizing the original image!
- res.coverInfoUpdated = coverInfo.refreshImageHash(image);
- if (pTrack && res.coverInfoUpdated) {
- kLogger.info()
- << "Updating cover info of track"
- << coverInfo.trackLocation;
- pTrack->setCoverInfo(coverInfo);
- }
-
- // Resize image to requested size
- if (!image.isNull() && desiredWidth > 0) {
- // Adjust the cover size according to the request
- // or downsize the image for efficiency.
- image = resizeImageWidth(image, desiredWidth);
+ // Resize image to requested size
+ if (desiredWidth > 0) {
+ // Adjust the cover size according to the request
+ // or downsize the image for efficiency.
+ loadedImage.image = resizeImageWidth(loadedImage.image, desiredWidth);
+ }
}
- res.cover = CoverArt(coverInfo, image, desiredWidth);
+ res.coverArt = CoverArt(
+ std::move(coverInfo),
+ std::move(loadedImage),
+ desiredWidth);
return res;
}
@@ -213,30 +218,60 @@ void CoverArtCache::coverLoaded() {
}
if (kLogger.traceEnabled()) {
- kLogger.trace() << "coverLoaded" << res.cover;
+ kLogger.trace() << "coverLoaded" << res.coverArt;
}
- // 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);
+ QPixmap pixmap;
+ if (res.coverArt.loadedImage.result != CoverInfo::LoadedImage::Result::NoImage) {
+ if (res.coverArt.loadedImage.result == CoverInfo::LoadedImage::Result::Ok) {
+ DEBUG_ASSERT(!res.coverArt.loadedImage.filePath.isEmpty());
+ } else {
+ DEBUG_ASSERT(res.coverArt.loadedImage.image.isNull());
+ kLogger.warning()
+ << "Failed to load cover art image"
+ << res.coverArt.loadedImage
+ << "for track"
+ << res.coverArt.trackLocation;
+ // Substitute missing cover art with a placeholder image to avoid high CPU load
+ // See also: https://bugs.launchpad.net/mixxx/+bug/1879160
+ const int imageSize = math_max(1, res.coverArt.resizedToWidth);
+ QImage placeholderImage(imageSize, imageSize, QImage::Format_RGB32);
+ // TODO(uklotzde): Use optional cover art background color (if available)
+ // instead of Qt::darkGray
+ placeholderImage.fill(
+ mixxx::RgbColor::toQColor(std::nullopt /*res.coverArt.color*/, Qt::darkGray));
+ res.coverArt.loadedImage.image = placeholderImage;
+ }
+ // Create pixmap, GUI thread only!
+ DEBUG_ASSERT_MAIN_THREAD_AFFINITY();
+ DEBUG_ASSERT(!res.coverArt.loadedImage.image.isNull());
+ pixmap = QPixmap::fromImage(res.coverArt.loadedImage.image);
+ // 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.
+ if (res.coverArt.resizedToWidth > 0) {
+ DEBUG_ASSERT(!pixmap.isNull());
+ // It is very unlikely that res.coverArt.hash generates the
+ // same hash for different images. Otherwise the wrong image would
+ // be displayed when loaded from the cache.
+ QString cacheKey = pixmapCacheKey(
+ res.coverArt.hash, res.coverArt.resizedToWidth);
+ QPixmapCache::insert(cacheKey, pixmap);
+ }
}
m_runningRequests.remove(qMakePair(res.pRequestor, res.requestedHash));
if (res.signalWhenDone) {
- emit coverFound(res.pRequestor, res.cover, pixmap, res.requestedHash, res.coverInfoUpdated);
+ emit coverFound(
+ res.pRequestor,
+ std::move(res.coverArt),
+ pixmap,
+ res.requestedHash,
+ res.coverInfoUpdated);
}
}
diff --git a/src/library/coverartcache.h b/src/library/coverartcache.h
index 170c8b82a3..22ab59a005 100644
--- a/src/library/coverartcache.h
+++ b/src/library/coverartcache.h
@@ -65,7 +65,7 @@ class CoverArtCache : public QObject, public Singleton<CoverArtCache> {
quint16 requestedHash;
bool signalWhenDone;
- CoverArt cover;
+ CoverArt coverArt;
bool coverInfoUpdated;
};
// Load cover from path indicated in coverInfo. WARNING: This is run in a
@@ -107,7 +107,7 @@ class CoverArtCache : public QObject, public Singleton<CoverArtCache> {
int desiredWidth,
Loading loading);
- QSet<QPair<const QObject*, quint16> > m_runningRequests;
+ QSet<QPair<const QObject*, quint16>> m_runningRequests;
};
inline
diff --git a/src/library/coverartdelegate.h b/src/library/coverartdelegate.h
index dd4e31ed0e..c2cecd72d0 100644
--- a/src/library/coverartdelegate.h
+++ b/src/library/coverartdelegate.h
@@ -2,7 +2,7 @@
#include "library/basecoverartdelegate.h"
-class CoverArtDelegate : public BaseCoverArtDelegate {
+class CoverArtDelegate final : public BaseCoverArtDelegate {
Q_OBJECT
public:
diff --git a/src/library/dao/playlistdao.cpp b/src/library/dao/playlistdao.cpp
index 12b2545775..30736c99a8 100644
--- a/src/library/dao/playlistdao.cpp
+++ b/src/library/dao/playlistdao.cpp
@@ -885,7 +885,7 @@ void PlaylistDAO::shuffleTracks(const int playlistId,
ScopedTransaction transaction(m_database);
QSqlQuery query(m_database);
-#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
+#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
// Seed the randomness generator
qsrand(QDateTime::currentDateTimeUtc().toTime_t());
#endif
diff --git a/src/library/dlgcoverartfullsize.cpp b/src/library/dlgcoverartfullsize.cpp
index fa1baee113..7ee2e82fd1 100644
--- a/src/library/dlgcoverartfullsize.cpp
+++ b/src/library/dlgcoverartfullsize.cpp
@@ -247,7 +247,12 @@ void DlgCoverArtFullSize::wheelEvent(QWheelEvent* event) {
// To keep the same part of the image under the cursor, shift the
// origin (top left point) by the distance the point moves under the cursor.
QPoint oldOrigin = geometry().topLeft();
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ QPoint oldPointUnderCursor = event->position().toPoint();
+#else
QPoint oldPointUnderCursor = event->pos();
+#endif
+
int newPointX = (double) oldPointUnderCursor.x() / oldWidth * newSize.width();
int newPointY = (double) oldPointUnderCursor.y() / oldHeight * newSize.height();
QPoint newOrigin = QPoint(
diff --git a/src/library/hiddentablemodel.h b/src/library/hiddentablemodel.h
index be559c5f19..d8d1b8028f 100644
--- a/src/library/hiddentablemodel.h
+++ b/src/library/hiddentablemodel.h
@@ -3,7 +3,7 @@
#include "library/basesqltablemodel.h"
-class HiddenTableModel : public BaseSqlTableModel {
+class HiddenTableModel final : public BaseSqlTableModel {
Q_OBJECT
public:
HiddenTableModel(QObject* parent, TrackCollectionManager* pTrackCollectionManager);
diff --git a/src/library/missingtablemodel.h b/src/library/missingtablemodel.h
index dbe4c347e1..716e64d54c 100644
--- a/src/library/missingtablemodel.h
+++ b/src/library/missingtablemodel.h
@@ -8,7 +8,7 @@
#include "library/basesqltablemodel.h"
#include "library/trackmodel.h"
-class MissingTableModel : public BaseSqlTableModel {
+class MissingTableModel final : public BaseSqlTableModel {
Q_OBJECT
public:
MissingTableModel(QObject* parent, TrackCollectionManager* pTrackCollectionManager);
diff --git a/src/library/playlisttablemodel.h b/src/library/playlisttablemodel.h
index 591b147d70..aa8ab57336 100644
--- a/src/library/playlisttablemodel.h
+++ b/src/library/playlisttablemodel.h
@@ -3,7 +3,7 @@
#include "library/basesqltablemodel.h"
#include "library/trackset/tracksettablemodel.h"
-class PlaylistTableModel : public TrackSetTableModel {
+class PlaylistTableModel final : public TrackSetTableModel {
Q_OBJECT
public:
diff --git a/src/library/songdownloader.cpp b/src/library/songdownloader.cpp
index 5e97dd4903..1eb211dd76 100644
--- a/src/library/songdownloader.cpp
+++ b/src/library/songdownloader.cpp
@@ -69,7 +69,14 @@ bool SongDownloader::downloadFromQueue() {
&QNetworkReply::readyRead,
this,
&SongDownloader::slotReadyRead);
- connect(m_pReply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error), this, &SongDownloader::slotError);
+ connect(m_pReply,
+#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
+ &QNetworkReply::errorOccurred,
+#else
+ QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),
+#endif
+ this,
+ &SongDownloader::slotError);
connect(m_pReply,
&QNetworkReply::downloadProgress,
this,
diff --git a/src/library/trackcollection.cpp b/src/library/trackcollection.cpp
index d3457d4af7..82d2a25f95 100644
--- a/src/library/trackcollection.cpp
+++ b/src/library/trackcollection.cpp
@@ -1,5 +1,4 @@
#include <QApplication>
-#include <QThread>
#include "library/trackcollection.h"
@@ -65,14 +64,14 @@ TrackCollection::~TrackCollection() {
}
void TrackCollection::repairDatabase(QSqlDatabase database) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
kLogger.info() << "Repairing database";
m_crates.repairDatabase(database);
}
void TrackCollection::connectDatabase(QSqlDatabase database) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
kLogger.info() << "Connecting database";
m_database = database;
@@ -86,7 +85,7 @@ void TrackCollection::connectDatabase(QSqlDatabase database) {
}
void TrackCollection::disconnectDatabase() {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
kLogger.info() << "Disconnecting database";
m_database = QSqlDatabase();
@@ -95,7 +94,7 @@ void TrackCollection::disconnectDatabase() {
}
void TrackCollection::connectTrackSource(QSharedPointer<BaseTrackCache> pTrackSource) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
VERIFY_OR_DEBUG_ASSERT(m_pTrackSource.isNull()) {
kLogger.warning() << "Track source has already been connected";
@@ -130,7 +129,7 @@ void TrackCollection::connectTrackSource(QSharedPointer<BaseTrackCache> pTrackSo
}
QWeakPointer<BaseTrackCache> TrackCollection::disconnectTrackSource() {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
auto pWeakPtr = m_pTrackSource.toWeakRef();
if (m_pTrackSource) {
@@ -142,6 +141,8 @@ QWeakPointer<BaseTrackCache> TrackCollection::disconnectTrackSource() {
}
bool TrackCollection::addDirectory(const QString& dir) {
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
+
SqlTransaction transaction(m_database);
switch (m_directoryDao.addDirectory(dir)) {
case SQL_ERROR:
@@ -158,6 +159,8 @@ bool TrackCollection::addDirectory(const QString& dir) {
}
bool TrackCollection::removeDirectory(const QString& dir) {
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
+
SqlTransaction transaction(m_database);
switch (m_directoryDao.removeDirectory(dir)) {
case SQL_ERROR:
@@ -172,7 +175,7 @@ bool TrackCollection::removeDirectory(const QString& dir) {
}
void TrackCollection::relocateDirectory(QString oldDir, QString newDir) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
// We only call this method if the user has picked a relocated directory via
// a file dialog. This means the system sandboxer (if we are sandboxed) has
@@ -236,7 +239,7 @@ QList<TrackId> TrackCollection::resolveTrackIdsFromLocations(
}
bool TrackCollection::hideTracks(const QList<TrackId>& trackIds) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
// Warn if tracks have a playlist membership
QSet<int> allPlaylistIds;
@@ -302,11 +305,13 @@ bool TrackCollection::hideTracks(const QList<TrackId>& trackIds) {
}
void TrackCollection::hideAllTracks(const QDir& rootDir) {
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
+
m_trackDao.hideAllTracks(rootDir);
}
bool TrackCollection::unhideTracks(const QList<TrackId>& trackIds) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
VERIFY_OR_DEBUG_ASSERT(m_trackDao.unhideTracks(trackIds)) {
return false;
@@ -330,7 +335,7 @@ bool TrackCollection::unhideTracks(const QList<TrackId>& trackIds) {
bool TrackCollection::purgeTracks(
const QList<TrackId>& trackIds) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
// Transactional
SqlTransaction transaction(m_database);
@@ -369,10 +374,12 @@ bool TrackCollection::purgeTracks(
bool TrackCollection::purgeAllTracks(
const QDir& rootDir) {
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
+
QList<TrackRef> trackRefs = m_trackDao.getAllTrackRefs(rootDir);
QList<TrackId> trackIds;
trackIds.reserve(trackRefs.size());
- for (const auto trackRef : trackRefs) {
+ for (const auto& trackRef : trackRefs) {
DEBUG_ASSERT(trackRef.hasId());
trackIds.append(trackRef.getId());
}
@@ -382,7 +389,7 @@ bool TrackCollection::purgeAllTracks(
bool TrackCollection::insertCrate(
const Crate& crate,
CrateId* pCrateId) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
// Transactional
SqlTransaction transaction(m_database);
@@ -409,7 +416,7 @@ bool TrackCollection::insertCrate(
bool TrackCollection::updateCrate(
const Crate& crate) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
// Transactional
SqlTransaction transaction(m_database);
@@ -431,7 +438,7 @@ bool TrackCollection::updateCrate(
bool TrackCollection::deleteCrate(
CrateId crateId) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
// Transactional
SqlTransaction transaction(m_database);
@@ -454,7 +461,7 @@ bool TrackCollection::deleteCrate(
bool TrackCollection::addCrateTracks(
CrateId crateId,
const QList<TrackId>& trackIds) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
// Transactional
SqlTransaction transaction(m_database);
@@ -477,7 +484,7 @@ bool TrackCollection::addCrateTracks(
bool TrackCollection::removeCrateTracks(
CrateId crateId,
const QList<TrackId>& trackIds) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
// Transactional
SqlTransaction transaction(m_database);
@@ -500,7 +507,7 @@ bool TrackCollection::removeCrateTracks(
bool TrackCollection::updateAutoDjCrate(
CrateId crateId,
bool isAutoDjSource) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
Crate crate;
VERIFY_OR_DEBUG_ASSERT(crates().readCrateById(crateId, &crate)) {
@@ -514,18 +521,22 @@ bool TrackCollection::updateAutoDjCrate(
}
void TrackCollection::saveTrack(Track* pTrack) {
- DEBUG_ASSERT(QApplication::instance()->thread() == QThread::currentThread());
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
m_trackDao.saveTrack(pTrack);
}
TrackPointer TrackCollection::getTrackById(
TrackId trackId) const {
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
+
return m_trackDao.getTrackById(trackId);
}
TrackPointer TrackCollection::getTrackByRef(
const TrackRef& trackRef) const {
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
+
return m_trackDao.getTrackByRef(trackRef);
}
@@ -537,12 +548,16 @@ TrackId TrackCollection::getTrackIdByRef(
TrackPointer TrackCollection::getOrAddTrack(
const TrackRef& trackRef,
bool* pAlreadyInLibrary) {
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
+
return m_trackDao.getOrAddTrack(trackRef, pAlreadyInLibrary);
}
TrackId TrackCollection::addTrack(
const TrackPointer& pTrack,
bool unremove) {
+ DEBUG_ASSERT_QOBJECT_THREAD_AFFINITY(this);
+
m_trackDao.addTracksPrepare();
const auto trackId = m_trackDao.addTracksAddTrack(pTrack, unremove);
m_trackDao.addTracksFinish(!trackId.isValid());
diff --git a/src/library/trackcollection.h b/src/library/trackcollection.h
index db99eb8e35..01de194a2d 100644
--- a/src/library/trackcollection.h
+++ b/src/library/trackcollection.h
@@ -13,6 +13,7 @@
#include "library/dao/trackdao.h"
#include "library/trackset/crate/cratestorage.h"
#include "preferences/usersettings.h"
+#include "util/thread_affinity.h"
// forward declaration(s)
class BaseTrackCache;
@@ -36,23 +37,29 @@ class TrackCollection : public QO