From 5d1413bc83b0e51a56525c098dc522ee06d5b494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 31 Oct 2018 10:59:56 +0100 Subject: Fix playlist import of the Banshee feature --- src/library/banshee/bansheefeature.cpp | 1 + src/library/banshee/bansheeplaylistmodel.cpp | 38 ++++++++++++++++++---------- src/library/banshee/bansheeplaylistmodel.h | 3 +++ src/library/baseexternallibraryfeature.cpp | 5 ++-- 4 files changed, 31 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/library/banshee/bansheefeature.cpp b/src/library/banshee/bansheefeature.cpp index 3973ad7d6d..80b5e46055 100644 --- a/src/library/banshee/bansheefeature.cpp +++ b/src/library/banshee/bansheefeature.cpp @@ -139,6 +139,7 @@ void BansheeFeature::appendTrackIdsFromRightClickIndex(QList* trackIds, if (playlistID > 0) { BansheePlaylistModel* pPlaylistModelToAdd = new BansheePlaylistModel(this, m_pTrackCollection, &m_connection); pPlaylistModelToAdd->setTableModel(playlistID); + pPlaylistModelToAdd->select(); // Copy Tracks int rows = pPlaylistModelToAdd->rowCount(); diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index c871095bd3..9e9a51f06d 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -31,38 +31,47 @@ #define CLM_COMPOSER "composer" #define CLM_PREVIEW "preview" +//static +QAtomicInt BansheePlaylistModel::m_tableNumber; + BansheePlaylistModel::BansheePlaylistModel(QObject* pParent, TrackCollection* pTrackCollection, BansheeDbConnection* pConnection) : BaseSqlTableModel(pParent, pTrackCollection, "mixxx.db.model.banshee_playlist"), m_pConnection(pConnection), m_playlistId(-1) { + m_tempTableName = BANSHEE_TABLE + QString::number(m_tableNumber.fetchAndAddAcquire(1)); } BansheePlaylistModel::~BansheePlaylistModel() { + deleteTempTable(); } -void BansheePlaylistModel::setTableModel(int playlistId) { - //qDebug() << "BansheePlaylistModel::setTableModel" << playlistId; - if (m_playlistId == playlistId) { - qDebug() << "Already focused on playlist " << playlistId; - return; - } - +void BansheePlaylistModel::deleteTempTable() { if (m_playlistId >= 0) { // Clear old playlist m_playlistId = -1; QSqlQuery query(m_pTrackCollection->database()); - QString strQuery("DELETE FROM " BANSHEE_TABLE); - if (!query.exec(strQuery)) { + QString strQuery("DELETE FROM %1"); + if (!query.exec(strQuery.arg(m_tempTableName))) { LOG_FAILED_QUERY(query); } } +} + +void BansheePlaylistModel::setTableModel(int playlistId) { + //qDebug() << "BansheePlaylistModel::setTableModel" << this << playlistId; + if (m_playlistId == playlistId) { + qDebug() << "Already focused on playlist " << playlistId; + return; + } + + deleteTempTable(); if (playlistId >= 0) { // setup new playlist m_playlistId = playlistId; QSqlQuery query(m_pTrackCollection->database()); - QString strQuery("CREATE TEMP TABLE IF NOT EXISTS " BANSHEE_TABLE + QString strQuery("CREATE TEMP TABLE IF NOT EXISTS %1" " (" CLM_VIEW_ORDER " INTEGER, " CLM_ARTIST " TEXT, " CLM_TITLE " TEXT, " @@ -82,11 +91,11 @@ void BansheePlaylistModel::setTableModel(int playlistId) { CLM_PLAYCOUNT" INTEGER, " CLM_COMPOSER " TEXT, " CLM_PREVIEW " TEXT)"); - if (!query.exec(strQuery)) { + if (!query.exec(strQuery.arg(m_tempTableName))) { LOG_FAILED_QUERY(query); } - query.prepare("INSERT INTO " BANSHEE_TABLE + QString strQuery2("INSERT INTO %1" " (" CLM_VIEW_ORDER ", " CLM_ARTIST ", " CLM_TITLE ", " @@ -125,6 +134,7 @@ void BansheePlaylistModel::setTableModel(int playlistId) { CLM_PLAYCOUNT ", :" CLM_COMPOSER ") "); + query.prepare(strQuery2.arg(m_tempTableName)); QList list = m_pConnection->getPlaylistEntries(playlistId); @@ -189,10 +199,10 @@ void BansheePlaylistModel::setTableModel(int playlistId) { << CLM_COMPOSER; QSharedPointer trackSource( - new BaseTrackCache(m_pTrackCollection, BANSHEE_TABLE, CLM_VIEW_ORDER, + new BaseTrackCache(m_pTrackCollection, m_tempTableName, CLM_VIEW_ORDER, trackSourceColumns, false)); - setTable(BANSHEE_TABLE, CLM_VIEW_ORDER, tableColumns, trackSource); + setTable(m_tempTableName, CLM_VIEW_ORDER, tableColumns, trackSource); setSearch(""); setDefaultSort(fieldIndex(PLAYLISTTRACKSTABLE_POSITION), Qt::AscendingOrder); setSort(defaultSortColumn(), defaultSortOrder()); diff --git a/src/library/banshee/bansheeplaylistmodel.h b/src/library/banshee/bansheeplaylistmodel.h index efda77a878..2b8e0fdfd5 100644 --- a/src/library/banshee/bansheeplaylistmodel.h +++ b/src/library/banshee/bansheeplaylistmodel.h @@ -41,9 +41,12 @@ class BansheePlaylistModel : public BaseSqlTableModel { private: QString getFieldString(const QModelIndex& index, const QString& fieldName) const; QVariant getFieldVariant(const QModelIndex& index, const QString& fieldName) const; + void deleteTempTable(); BansheeDbConnection* m_pConnection; int m_playlistId; + QString m_tempTableName; + static QAtomicInt m_tableNumber; }; #endif // BANSHEEPLAYLISTMODEL_H diff --git a/src/library/baseexternallibraryfeature.cpp b/src/library/baseexternallibraryfeature.cpp index 87807a62e7..5322a03bfd 100644 --- a/src/library/baseexternallibraryfeature.cpp +++ b/src/library/baseexternallibraryfeature.cpp @@ -56,7 +56,7 @@ void BaseExternalLibraryFeature::slotAddToAutoDJTop() { } void BaseExternalLibraryFeature::addToAutoDJ(bool bTop) { - // qDebug() << "slotAddToAutoDJ() row:" << m_lastRightClickedIndex.data(); + //qDebug() << "slotAddToAutoDJ() row:" << m_lastRightClickedIndex.data(); QList trackIds; QString playlist; @@ -96,7 +96,8 @@ void BaseExternalLibraryFeature::slotImportAsMixxxPlaylist() { } // This is a common function for all external Librarys copied to Mixxx DB -void BaseExternalLibraryFeature::appendTrackIdsFromRightClickIndex(QList* trackIds, QString* pPlaylist) { +void BaseExternalLibraryFeature::appendTrackIdsFromRightClickIndex( + QList* trackIds, QString* pPlaylist) { if (!m_lastRightClickedIndex.isValid()) { return; } -- cgit v1.2.3 From a04491acb5ed421a23454525d56a5fff0d8f268f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Wed, 31 Oct 2018 23:14:27 +0100 Subject: Fix Banshee playlist view for tracks that have never been sorted --- src/library/banshee/bansheeplaylistmodel.cpp | 30 ++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index 9e9a51f06d..0daaf399a9 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -11,6 +11,7 @@ #include "mixer/playermanager.h" #define BANSHEE_TABLE "banshee" +#define CLM_TRACK_ID "track_id" #define CLM_VIEW_ORDER "position" #define CLM_ARTIST "artist" #define CLM_TITLE "title" @@ -72,7 +73,8 @@ void BansheePlaylistModel::setTableModel(int playlistId) { QSqlQuery query(m_pTrackCollection->database()); QString strQuery("CREATE TEMP TABLE IF NOT EXISTS %1" - " (" CLM_VIEW_ORDER " INTEGER, " + " (" CLM_TRACK_ID " INTEGER, " + CLM_VIEW_ORDER " INTEGER, " CLM_ARTIST " TEXT, " CLM_TITLE " TEXT, " CLM_DURATION " INTEGER, " @@ -96,7 +98,8 @@ void BansheePlaylistModel::setTableModel(int playlistId) { } QString strQuery2("INSERT INTO %1" - " (" CLM_VIEW_ORDER ", " + " (" CLM_TRACK_ID ", " + CLM_VIEW_ORDER ", " CLM_ARTIST ", " CLM_TITLE ", " CLM_DURATION ", " @@ -115,6 +118,7 @@ void BansheePlaylistModel::setTableModel(int playlistId) { CLM_PLAYCOUNT ", " CLM_COMPOSER ") " "VALUES (:" + CLM_TRACK_ID ", :" CLM_VIEW_ORDER ", :" CLM_ARTIST ", :" CLM_TITLE ", :" @@ -143,6 +147,9 @@ void BansheePlaylistModel::setTableModel(int playlistId) { beginInsertRows(QModelIndex(), 0, list.size() - 1); foreach (struct BansheeDbConnection::PlaylistEntry entry, list) { + query.bindValue(":" CLM_TRACK_ID, entry.trackId); + // Note: entry.viewOrder is 0 for all tracks if they have + // never been sorted by the user query.bindValue(":" CLM_VIEW_ORDER, entry.viewOrder + 1); query.bindValue(":" CLM_ARTIST, entry.pArtist->name); query.bindValue(":" CLM_TITLE, entry.pTrack->title); @@ -175,11 +182,14 @@ void BansheePlaylistModel::setTableModel(int playlistId) { } QStringList tableColumns; - tableColumns << CLM_VIEW_ORDER // 0 - << CLM_PREVIEW; + tableColumns + << CLM_TRACK_ID // 0 + << CLM_VIEW_ORDER + << CLM_PREVIEW; // 3 QStringList trackSourceColumns; - trackSourceColumns << CLM_VIEW_ORDER // 0 + trackSourceColumns + << CLM_TRACK_ID // 0 << CLM_ARTIST << CLM_TITLE << CLM_DURATION @@ -199,10 +209,10 @@ void BansheePlaylistModel::setTableModel(int playlistId) { << CLM_COMPOSER; QSharedPointer trackSource( - new BaseTrackCache(m_pTrackCollection, m_tempTableName, CLM_VIEW_ORDER, + new BaseTrackCache(m_pTrackCollection, m_tempTableName, CLM_TRACK_ID, trackSourceColumns, false)); - setTable(m_tempTableName, CLM_VIEW_ORDER, tableColumns, trackSource); + setTable(m_tempTableName, CLM_TRACK_ID, tableColumns, trackSource); setSearch(""); setDefaultSort(fieldIndex(PLAYLISTTRACKSTABLE_POSITION), Qt::AscendingOrder); setSort(defaultSortColumn(), defaultSortOrder()); @@ -375,6 +385,10 @@ QString BansheePlaylistModel::getTrackLocation(const QModelIndex& index) const { } bool BansheePlaylistModel::isColumnInternal(int column) { - Q_UNUSED(column); + if (column == fieldIndex(ColumnCache::COLUMN_PLAYLISTTRACKSTABLE_TRACKID) || + (PlayerManager::numPreviewDecks() == 0 && + column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PREVIEW))) { + return true; + } return false; } -- cgit v1.2.3 From 8c2aec7e1e8eb7fca13fe19f3bbbf39405723398 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 1 Nov 2018 00:15:17 +0100 Subject: Fix playlist export for all external libraries --- src/library/baseexternallibraryfeature.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src') diff --git a/src/library/baseexternallibraryfeature.cpp b/src/library/baseexternallibraryfeature.cpp index 5322a03bfd..449fde79c2 100644 --- a/src/library/baseexternallibraryfeature.cpp +++ b/src/library/baseexternallibraryfeature.cpp @@ -102,10 +102,7 @@ void BaseExternalLibraryFeature::appendTrackIdsFromRightClickIndex( return; } - // Qt::UserRole asks TreeItemModel for the TreeItem's data. We need to - // use the data because models with nested playlists need to use the - // full path/name of the playlist. - *pPlaylist = m_lastRightClickedIndex.data(Qt::UserRole).toString(); + *pPlaylist = m_lastRightClickedIndex.data().toString(); QScopedPointer pPlaylistModelToAdd( getPlaylistModelForPlaylist(*pPlaylist)); -- cgit v1.2.3 From e0ecb77a5a2c40f9433109ab82f81112ffcb0c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 1 Nov 2018 20:16:58 +0100 Subject: move sTableNumber to anonymous namespace --- src/library/banshee/bansheeplaylistmodel.cpp | 7 ++++--- src/library/banshee/bansheeplaylistmodel.h | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index 0daaf399a9..d42944b38b 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -32,14 +32,15 @@ #define CLM_COMPOSER "composer" #define CLM_PREVIEW "preview" -//static -QAtomicInt BansheePlaylistModel::m_tableNumber; +namespace { +QAtomicInt sTableNumber; +} BansheePlaylistModel::BansheePlaylistModel(QObject* pParent, TrackCollection* pTrackCollection, BansheeDbConnection* pConnection) : BaseSqlTableModel(pParent, pTrackCollection, "mixxx.db.model.banshee_playlist"), m_pConnection(pConnection), m_playlistId(-1) { - m_tempTableName = BANSHEE_TABLE + QString::number(m_tableNumber.fetchAndAddAcquire(1)); + m_tempTableName = BANSHEE_TABLE + QString::number(sTableNumber.fetchAndAddAcquire(1)); } BansheePlaylistModel::~BansheePlaylistModel() { diff --git a/src/library/banshee/bansheeplaylistmodel.h b/src/library/banshee/bansheeplaylistmodel.h index 2b8e0fdfd5..209a5b4eaf 100644 --- a/src/library/banshee/bansheeplaylistmodel.h +++ b/src/library/banshee/bansheeplaylistmodel.h @@ -46,7 +46,6 @@ class BansheePlaylistModel : public BaseSqlTableModel { BansheeDbConnection* m_pConnection; int m_playlistId; QString m_tempTableName; - static QAtomicInt m_tableNumber; }; #endif // BANSHEEPLAYLISTMODEL_H -- cgit v1.2.3 From 9a2998227aa50e7781a1e8f45c35d486994e7d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 1 Nov 2018 21:20:09 +0100 Subject: Override getTrackId for external libraries --- src/library/banshee/bansheeplaylistmodel.cpp | 9 +++++++++ src/library/banshee/bansheeplaylistmodel.h | 2 ++ src/library/baseexternalplaylistmodel.cpp | 9 +++++++++ src/library/baseexternalplaylistmodel.h | 1 + 4 files changed, 21 insertions(+) (limited to 'src') diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index d42944b38b..8d70427f16 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -348,6 +348,15 @@ TrackPointer BansheePlaylistModel::getTrack(const QModelIndex& index) const { return pTrack; } +TrackId BansheePlaylistModel::getTrackId(const QModelIndex& index) const { + const auto track = getTrack(index); + if (track) { + return track->getId(); + } else { + return TrackId(); + } +} + // Gets the on-disk location of the track at the given location. QString BansheePlaylistModel::getTrackLocation(const QModelIndex& index) const { if (!index.isValid()) { diff --git a/src/library/banshee/bansheeplaylistmodel.h b/src/library/banshee/bansheeplaylistmodel.h index 209a5b4eaf..398e8b7c72 100644 --- a/src/library/banshee/bansheeplaylistmodel.h +++ b/src/library/banshee/bansheeplaylistmodel.h @@ -20,6 +20,8 @@ class BansheePlaylistModel : public BaseSqlTableModel { void setTableModel(int playlistId); TrackPointer getTrack(const QModelIndex& index) const final; + TrackId getTrackId(const QModelIndex& index) const final; + QString getTrackLocation(const QModelIndex& index) const final; bool isColumnInternal(int column) final; diff --git a/src/library/baseexternalplaylistmodel.cpp b/src/library/baseexternalplaylistmodel.cpp index 7529523896..2ba94fe30b 100644 --- a/src/library/baseexternalplaylistmodel.cpp +++ b/src/library/baseexternalplaylistmodel.cpp @@ -65,6 +65,15 @@ TrackPointer BaseExternalPlaylistModel::getTrack(const QModelIndex& index) const return pTrack; } +TrackId BaseExternalPlaylistModel::getTrackId(const QModelIndex& index) const { + const auto track = getTrack(index); + if (track) { + return track->getId(); + } else { + return TrackId(); + } +} + bool BaseExternalPlaylistModel::isColumnInternal(int column) { if (column == fieldIndex(ColumnCache::COLUMN_PLAYLISTTRACKSTABLE_TRACKID) || (PlayerManager::numPreviewDecks() == 0 && diff --git a/src/library/baseexternalplaylistmodel.h b/src/library/baseexternalplaylistmodel.h index 0b8cd3e7b4..51cbb9c94f 100644 --- a/src/library/baseexternalplaylistmodel.h +++ b/src/library/baseexternalplaylistmodel.h @@ -25,6 +25,7 @@ class BaseExternalPlaylistModel : public BaseSqlTableModel { void setPlaylist(QString path_name); TrackPointer getTrack(const QModelIndex& index) const override; + TrackId getTrackId(const QModelIndex& index) const override; bool isColumnInternal(int column) override; Qt::ItemFlags flags(const QModelIndex &index) const override; void trackLoaded(QString group, TrackPointer pTrack) override; -- cgit v1.2.3 From 1d056bf5aa4020ae33c1352f90071dc257a2a988 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 1 Nov 2018 22:23:50 +0100 Subject: disable metadata edit features in external libraries --- src/library/crate/cratetablemodel.cpp | 4 +- src/library/librarytablemodel.cpp | 4 +- src/library/playlisttablemodel.cpp | 4 +- src/library/trackmodel.h | 12 +++-- src/widget/wtracktableview.cpp | 85 ++++++++++++++++++----------------- 5 files changed, 51 insertions(+), 58 deletions(-) (limited to 'src') diff --git a/src/library/crate/cratetablemodel.cpp b/src/library/crate/cratetablemodel.cpp index f64850bb2d..300754172c 100644 --- a/src/library/crate/cratetablemodel.cpp +++ b/src/library/crate/cratetablemodel.cpp @@ -107,13 +107,11 @@ TrackModel::CapabilitiesFlags CrateTableModel::getCapabilities() const { | TRACKMODELCAPS_ADDTOPLAYLIST | TRACKMODELCAPS_ADDTOCRATE | TRACKMODELCAPS_ADDTOAUTODJ - | TRACKMODELCAPS_IMPORTMETADATA + | TRACKMODELCAPS_EDITMETADATA | TRACKMODELCAPS_LOADTODECK | TRACKMODELCAPS_LOADTOSAMPLER | TRACKMODELCAPS_LOADTOPREVIEWDECK | TRACKMODELCAPS_REMOVE - | TRACKMODELCAPS_MANIPULATEBEATS - | TRACKMODELCAPS_CLEAR_BEATS | TRACKMODELCAPS_RESETPLAYED; if (m_selectedCrate.isValid()) { Crate crate; diff --git a/src/library/librarytablemodel.cpp b/src/library/librarytablemodel.cpp index c50a99867b..3d79457bea 100644 --- a/src/library/librarytablemodel.cpp +++ b/src/library/librarytablemodel.cpp @@ -101,12 +101,10 @@ TrackModel::CapabilitiesFlags LibraryTableModel::getCapabilities() const { | TRACKMODELCAPS_ADDTOPLAYLIST | TRACKMODELCAPS_ADDTOCRATE | TRACKMODELCAPS_ADDTOAUTODJ - | TRACKMODELCAPS_IMPORTMETADATA + | TRACKMODELCAPS_EDITMETADATA | TRACKMODELCAPS_LOADTODECK | TRACKMODELCAPS_LOADTOSAMPLER | TRACKMODELCAPS_LOADTOPREVIEWDECK | TRACKMODELCAPS_HIDE - | TRACKMODELCAPS_MANIPULATEBEATS - | TRACKMODELCAPS_CLEAR_BEATS | TRACKMODELCAPS_RESETPLAYED; } diff --git a/src/library/playlisttablemodel.cpp b/src/library/playlisttablemodel.cpp index 218c79ce6c..5c683694c2 100644 --- a/src/library/playlisttablemodel.cpp +++ b/src/library/playlisttablemodel.cpp @@ -242,13 +242,11 @@ TrackModel::CapabilitiesFlags PlaylistTableModel::getCapabilities() const { | TRACKMODELCAPS_REORDER | TRACKMODELCAPS_ADDTOCRATE | TRACKMODELCAPS_ADDTOPLAYLIST - | TRACKMODELCAPS_IMPORTMETADATA + | TRACKMODELCAPS_EDITMETADATA | TRACKMODELCAPS_LOADTODECK | TRACKMODELCAPS_LOADTOSAMPLER | TRACKMODELCAPS_LOADTOPREVIEWDECK | TRACKMODELCAPS_REMOVE - | TRACKMODELCAPS_MANIPULATEBEATS - | TRACKMODELCAPS_CLEAR_BEATS | TRACKMODELCAPS_RESETPLAYED; // Only allow Add to AutoDJ if we aren't currently showing the AutoDJ queue. diff --git a/src/library/trackmodel.h b/src/library/trackmodel.h index 14cb625f7a..328bd5a42e 100644 --- a/src/library/trackmodel.h +++ b/src/library/trackmodel.h @@ -35,17 +35,15 @@ class TrackModel { TRACKMODELCAPS_ADDTOCRATE = 0x00008, TRACKMODELCAPS_ADDTOAUTODJ = 0x00010, TRACKMODELCAPS_LOCKED = 0x00020, - TRACKMODELCAPS_IMPORTMETADATA = 0x00040, + TRACKMODELCAPS_EDITMETADATA = 0x00040, TRACKMODELCAPS_LOADTODECK = 0x00080, TRACKMODELCAPS_LOADTOSAMPLER = 0x00100, TRACKMODELCAPS_LOADTOPREVIEWDECK = 0x00200, TRACKMODELCAPS_REMOVE = 0x00400, - TRACKMODELCAPS_MANIPULATEBEATS = 0x00800, - TRACKMODELCAPS_CLEAR_BEATS = 0x01000, - TRACKMODELCAPS_RESETPLAYED = 0x02000, - TRACKMODELCAPS_HIDE = 0x04000, - TRACKMODELCAPS_UNHIDE = 0x08000, - TRACKMODELCAPS_PURGE = 0x10000 + TRACKMODELCAPS_RESETPLAYED = 0x00800, + TRACKMODELCAPS_HIDE = 0x01000, + TRACKMODELCAPS_UNHIDE = 0x02000, + TRACKMODELCAPS_PURGE = 0x04000 }; typedef int CapabilitiesFlags; /** Enables us to do ORing */ diff --git a/src/widget/wtracktableview.cpp b/src/widget/wtracktableview.cpp index 8813d298eb..9419c668ff 100644 --- a/src/widget/wtracktableview.cpp +++ b/src/widget/wtracktableview.cpp @@ -895,16 +895,14 @@ void WTrackTableView::contextMenuEvent(QContextMenuEvent* event) { m_pMenu->addSeparator(); m_pMetadataMenu->clear(); - if (modelHasCapabilities(TrackModel::TRACKMODELCAPS_IMPORTMETADATA)) { + if (modelHasCapabilities(TrackModel::TRACKMODELCAPS_EDITMETADATA)) { m_pMetadataMenu->addAction(m_pImportMetadataFromFileAct); m_pImportMetadataFromMusicBrainzAct->setEnabled(oneSongSelected); m_pMetadataMenu->addAction(m_pImportMetadataFromMusicBrainzAct); m_pMetadataMenu->addAction(m_pExportMetadataAct); - } - m_pClearMetadataMenu->clear(); + m_pClearMetadataMenu->clear(); - if (modelHasCapabilities(TrackModel::TRACKMODELCAPS_CLEAR_BEATS)) { if (trackModel == nullptr) { return; } @@ -925,38 +923,38 @@ void WTrackTableView::contextMenuEvent(QContextMenuEvent* event) { m_pClearMetadataMenu->addAction(m_pClearPlayCountAction); } - //FIXME: Why are clearning the main cue and loop not working? -// m_pClearMetadataMenu->addAction(m_pClearMainCueAction); - m_pClearMetadataMenu->addAction(m_pClearHotCuesAction); -// m_pClearMetadataMenu->addAction(m_pClearLoopAction); - m_pClearMetadataMenu->addAction(m_pClearReplayGainAction); - m_pClearMetadataMenu->addAction(m_pClearWaveformAction); - m_pClearMetadataMenu->addSeparator(); - m_pClearMetadataMenu->addAction(m_pClearAllMetadataAction); - - // Cover art menu only applies if at least one track is selected. - if (indices.size()) { - // We load a single track to get the necessary context for the cover (we use - // last to be consistent with selectionChanged above). - QModelIndex last = indices.last(); - CoverInfo info; - info.source = static_cast( - last.sibling(last.row(), m_iCoverSourceColumn).data().toInt()); - info.type = static_cast( - last.sibling(last.row(), m_iCoverTypeColumn).data().toInt()); - info.hash = last.sibling(last.row(), m_iCoverHashColumn).data().toUInt(); - info.trackLocation = last.sibling( - last.row(), m_iTrackLocationColumn).data().toString(); - info.coverLocation = last.sibling( - last.row(), m_iCoverLocationColumn).data().toString(); - m_pCoverMenu->setCoverArt(info); - m_pMetadataMenu->addMenu(m_pCoverMenu); - } - - m_pMenu->addMenu(m_pMetadataMenu); - m_pMenu->addMenu(m_pClearMetadataMenu); - - if (modelHasCapabilities(TrackModel::TRACKMODELCAPS_MANIPULATEBEATS)) { + if (modelHasCapabilities(TrackModel::TRACKMODELCAPS_EDITMETADATA)) { + // FIXME: Why are clearning the main cue and loop not working? + //m_pClearMetadataMenu->addAction(m_pClearMainCueAction); + m_pClearMetadataMenu->addAction(m_pClearHotCuesAction); + //m_pClearMetadataMenu->addAction(m_pClearLoopAction); + m_pClearMetadataMenu->addAction(m_pClearReplayGainAction); + m_pClearMetadataMenu->addAction(m_pClearWaveformAction); + m_pClearMetadataMenu->addSeparator(); + m_pClearMetadataMenu->addAction(m_pClearAllMetadataAction); + + // Cover art menu only applies if at least one track is selected. + if (indices.size()) { + // We load a single track to get the necessary context for the cover (we use + // last to be consistent with selectionChanged above). + QModelIndex last = indices.last(); + CoverInfo info; + info.source = static_cast( + last.sibling(last.row(), m_iCoverSourceColumn).data().toInt()); + info.type = static_cast( + last.sibling(last.row(), m_iCoverTypeColumn).data().toInt()); + info.hash = last.sibling(last.row(), m_iCoverHashColumn).data().toUInt(); + info.trackLocation = last.sibling( + last.row(), m_iTrackLocationColumn).data().toString(); + info.coverLocation = last.sibling( + last.row(), m_iCoverLocationColumn).data().toString(); + m_pCoverMenu->setCoverArt(info); + m_pMetadataMenu->addMenu(m_pCoverMenu); + } + + m_pMenu->addMenu(m_pMetadataMenu); + m_pMenu->addMenu(m_pClearMetadataMenu); + m_pBPMMenu->addAction(m_pBpmDoubleAction); m_pBPMMenu->addAction(m_pBpmHalveAction); m_pBPMMenu->addAction(m_pBpmTwoThirdsAction); @@ -1022,8 +1020,8 @@ void WTrackTableView::contextMenuEvent(QContextMenuEvent* event) { m_pBpmThreeHalvesAction->setEnabled(true); } } + m_pMenu->addMenu(m_pBPMMenu); } - m_pMenu->addMenu(m_pBPMMenu); // REMOVE and HIDE should not be at the first menu position to avoid accidental clicks m_pMenu->addSeparator(); @@ -1045,9 +1043,12 @@ void WTrackTableView::contextMenuEvent(QContextMenuEvent* event) { m_pMenu->addAction(m_pPurgeAct); } m_pMenu->addAction(m_pFileBrowserAct); - m_pMenu->addSeparator(); - m_pPropertiesAct->setEnabled(oneSongSelected); - m_pMenu->addAction(m_pPropertiesAct); + + if (modelHasCapabilities(TrackModel::TRACKMODELCAPS_EDITMETADATA)) { + m_pMenu->addSeparator(); + m_pPropertiesAct->setEnabled(oneSongSelected); + m_pMenu->addAction(m_pPropertiesAct); + } //Create the right-click menu m_pMenu->popup(event->globalPos()); @@ -1457,7 +1458,7 @@ void WTrackTableView::sendToAutoDJ(PlaylistDAO::AutoDJSendLoc loc) { } void WTrackTableView::slotImportTrackMetadataFromFileTags() { - if (!modelHasCapabilities(TrackModel::TRACKMODELCAPS_IMPORTMETADATA)) { + if (!modelHasCapabilities(TrackModel::TRACKMODELCAPS_EDITMETADATA)) { return; } @@ -1482,7 +1483,7 @@ void WTrackTableView::slotImportTrackMetadataFromFileTags() { } void WTrackTableView::slotExportTrackMetadataIntoFileTags() { - if (!modelHasCapabilities(TrackModel::TRACKMODELCAPS_IMPORTMETADATA)) { + if (!modelHasCapabilities(TrackModel::TRACKMODELCAPS_EDITMETADATA)) { return; } -- cgit v1.2.3 From fa9229b5f1e644bd799b8b2703d27d01642b4ccf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 4 Nov 2018 01:46:08 +0100 Subject: Added DEBUG_ASSERT(pPlaylist); --- src/library/baseexternallibraryfeature.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/library/baseexternallibraryfeature.cpp b/src/library/baseexternallibraryfeature.cpp index 449fde79c2..b527c119d3 100644 --- a/src/library/baseexternallibraryfeature.cpp +++ b/src/library/baseexternallibraryfeature.cpp @@ -102,6 +102,7 @@ void BaseExternalLibraryFeature::appendTrackIdsFromRightClickIndex( return; } + DEBUG_ASSERT(pPlaylist); *pPlaylist = m_lastRightClickedIndex.data().toString(); QScopedPointer pPlaylistModelToAdd( getPlaylistModelForPlaylist(*pPlaylist)); -- cgit v1.2.3 From 22e2e9cf49411855fd896337210a890fb61a8670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 4 Nov 2018 01:49:28 +0100 Subject: user DROP instead of DELETE --- src/library/banshee/bansheeplaylistmodel.cpp | 8 ++++---- src/library/banshee/bansheeplaylistmodel.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index 8d70427f16..4f2b52caee 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -44,15 +44,15 @@ BansheePlaylistModel::BansheePlaylistModel(QObject* pParent, TrackCollection* pT } BansheePlaylistModel::~BansheePlaylistModel() { - deleteTempTable(); + dropTempTable(); } -void BansheePlaylistModel::deleteTempTable() { +void BansheePlaylistModel::dropTempTable() { if (m_playlistId >= 0) { // Clear old playlist m_playlistId = -1; QSqlQuery query(m_pTrackCollection->database()); - QString strQuery("DELETE FROM %1"); + QString strQuery("DROP TABLE IF EXISTS %1"); if (!query.exec(strQuery.arg(m_tempTableName))) { LOG_FAILED_QUERY(query); } @@ -66,7 +66,7 @@ void BansheePlaylistModel::setTableModel(int playlistId) { return; } - deleteTempTable(); + dropTempTable(); if (playlistId >= 0) { // setup new playlist diff --git a/src/library/banshee/bansheeplaylistmodel.h b/src/library/banshee/bansheeplaylistmodel.h index 398e8b7c72..d89fc20a8a 100644 --- a/src/library/banshee/bansheeplaylistmodel.h +++ b/src/library/banshee/bansheeplaylistmodel.h @@ -43,7 +43,7 @@ class BansheePlaylistModel : public BaseSqlTableModel { private: QString getFieldString(const QModelIndex& index, const QString& fieldName) const; QVariant getFieldVariant(const QModelIndex& index, const QString& fieldName) const; - void deleteTempTable(); + void dropTempTable(); BansheeDbConnection* m_pConnection; int m_playlistId; -- cgit v1.2.3 From 20aead0120b3c549627107d2cce56b90ccc6bb9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 4 Nov 2018 01:52:06 +0100 Subject: return condition directly --- src/library/banshee/bansheeplaylistmodel.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/library/banshee/bansheeplaylistmodel.cpp b/src/library/banshee/bansheeplaylistmodel.cpp index 4f2b52caee..d46661b965 100644 --- a/src/library/banshee/bansheeplaylistmodel.cpp +++ b/src/library/banshee/bansheeplaylistmodel.cpp @@ -395,10 +395,7 @@ QString BansheePlaylistModel::getTrackLocation(const QModelIndex& index) const { } bool BansheePlaylistModel::isColumnInternal(int column) { - if (column == fieldIndex(ColumnCache::COLUMN_PLAYLISTTRACKSTABLE_TRACKID) || + return (column == fieldIndex(ColumnCache::COLUMN_PLAYLISTTRACKSTABLE_TRACKID) || (PlayerManager::numPreviewDecks() == 0 && - column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PREVIEW))) { - return true; - } - return false; + column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PREVIEW))); } -- cgit v1.2.3 From 5ec1e9b3ff6ce03634f17ac0afa4880aab9318dd Mon Sep 17 00:00:00 2001 From: Swiftb0y Date: Mon, 5 Nov 2018 23:25:26 +0100 Subject: track_loaded now emits signals when an already loaded Deck loads a new Track --- src/engine/enginebuffer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/engine/enginebuffer.cpp b/src/engine/enginebuffer.cpp index 79d0aa95be..3df8c607c5 100644 --- a/src/engine/enginebuffer.cpp +++ b/src/engine/enginebuffer.cpp @@ -189,7 +189,7 @@ EngineBuffer::EngineBuffer(QString group, UserSettingsPointer pConfig, this, SLOT(slotEjectTrack(double)), Qt::DirectConnection); - m_pTrackLoaded = new ControlObject(ConfigKey(m_group, "track_loaded")); + m_pTrackLoaded = new ControlObject(ConfigKey(m_group, "track_loaded"), false); m_pTrackLoaded->setReadOnly(); // Quantization Controller for enabling and disabling the -- cgit v1.2.3 From 3866085d9c80ed42c40c9ea5c3452b98fe37c56f Mon Sep 17 00:00:00 2001 From: Matthew Nicholson Date: Tue, 6 Nov 2018 00:56:28 -0500 Subject: don't try and set bpm on invalid m_pBeats pointers If no track is loaded and the user presses the bpm_tap button, mixxx will crash. https://bugs.launchpad.net/mixxx/+bug/1801844 --- src/engine/bpmcontrol.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/engine/bpmcontrol.cpp b/src/engine/bpmcontrol.cpp index f1a92f2f24..123ab756fd 100644 --- a/src/engine/bpmcontrol.cpp +++ b/src/engine/bpmcontrol.cpp @@ -219,10 +219,14 @@ void BpmControl::slotTapFilter(double averageLength, int numSamples) { if (numSamples < 4) return; + auto pBeats = m_pBeats; + if (!pBeats) + return; + // (60 seconds per minute) * (1000 milliseconds per second) / (X millis per // beat) = Y beats/minute double averageBpm = 60.0 * 1000.0 / averageLength / calcRateRatio(); - m_pBeats->setBpm(averageBpm); + pBeats->setBpm(averageBpm); } void BpmControl::slotControlBeatSyncPhase(double v) { -- cgit v1.2.3 From faf1a67bf1c39510b3dfa2840e98280cf38572eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 6 Nov 2018 22:54:02 +0100 Subject: added Nikolaus Einhauser to the contributor list. Thank you very much. --- src/dialog/dlgabout.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/dialog/dlgabout.cpp b/src/dialog/dlgabout.cpp index 792922b6f6..52afeda9d6 100644 --- a/src/dialog/dlgabout.cpp +++ b/src/dialog/dlgabout.cpp @@ -99,7 +99,8 @@ DlgAbout::DlgAbout(QWidget* parent) : QDialog(parent), Ui::DlgAboutDlg() { << "Sebastian Reuße" << "Paweł Goliński" << "beenisss" - << "Bernd Binder"; + << "Bernd Binder" + << "Nikolaus Einhauser"; QStringList specialThanks; specialThanks -- cgit v1.2.3 From ec32bd0c209f42b6f88ecc136a45992ac9771487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 8 Nov 2018 23:58:18 +0100 Subject: Allow tosearch for whole words by adding a tailing space. lp1784141 --- src/library/searchquery.cpp | 10 ++++++++-- src/library/searchqueryparser.cpp | 9 +++++---- 2 files changed, 13 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index c7aad9931f..f6ca699663 100644 --- a/src/library/searchquery.cpp +++ b/src/library/searchquery.cpp @@ -157,8 +157,14 @@ bool TextFilterNode::match(const TrackPointer& pTrack) const { QString TextFilterNode::toSql() const { FieldEscaper escaper(m_database); - QString escapedArgument = escaper.escapeString(kSqlLikeMatchAll + m_argument + kSqlLikeMatchAll); - + QString argument = m_argument; + if (argument.right(1) == " ") { + // LIKE eats a tailing space. This can be avoided by adding "_" for any + // followng character + argument += "_"; + } + QString escapedArgument = escaper.escapeString( + kSqlLikeMatchAll + argument + kSqlLikeMatchAll); QStringList searchClauses; for (const auto& sqlColumn: m_sqlColumns) { searchClauses << QString("%1 LIKE %2").arg(sqlColumn, escapedArgument); diff --git a/src/library/searchqueryparser.cpp b/src/library/searchqueryparser.cpp index 081e8cb1b0..5b0b9b79ee 100644 --- a/src/library/searchqueryparser.cpp +++ b/src/library/searchqueryparser.cpp @@ -123,15 +123,16 @@ void SearchQueryParser::parseTokens(QStringList tokens, } else if (m_textFilterMatcher.indexIn(token) != -1) { QString field = m_textFilterMatcher.cap(1); QString argument = getTextArgument( - m_textFilterMatcher.cap(2), &tokens).trimmed(); + m_textFilterMatcher.cap(2), &tokens); if (!argument.isEmpty()) { if (field == "crate") { pNode = std::make_unique( - &m_pTrackCollection->crates(), argument); + &m_pTrackCollection->crates(), argument); } else { pNode = std::make_unique( - m_pTrackCollection->database(), m_fieldToSqlColumns[field], argument); + m_pTrackCollection->database(), + m_fieldToSqlColumns[field], argument); } } } else if (m_numericFilterMatcher.indexIn(token) != -1) { @@ -141,7 +142,7 @@ void SearchQueryParser::parseTokens(QStringList tokens, if (!argument.isEmpty()) { pNode = std::make_unique( - m_fieldToSqlColumns[field], argument); + m_fieldToSqlColumns[field], argument); } } else if (m_specialFilterMatcher.indexIn(token) != -1) { bool fuzzy = token.startsWith(kFuzzyPrefix); -- cgit v1.2.3 From 0b5d82a9b9e3db7a1ec84a09079308b436392542 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Fri, 9 Nov 2018 00:07:29 +0100 Subject: Handle quotes in search strings without a column identifier. lp1784141 --- src/library/searchqueryparser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/library/searchqueryparser.cpp b/src/library/searchqueryparser.cpp index 5b0b9b79ee..91676fa4e4 100644 --- a/src/library/searchqueryparser.cpp +++ b/src/library/searchqueryparser.cpp @@ -178,8 +178,9 @@ void SearchQueryParser::parseTokens(QStringList tokens, } // Don't trigger on a lone minus sign. if (!token.isEmpty()) { + QString argument = getTextArgument(token, &tokens); pNode = std::make_unique( - m_pTrackCollection->database(), searchColumns, token); + m_pTrackCollection->database(), searchColumns, argument); } } if (pNode) { -- cgit v1.2.3 From c2ee5331a04cb86de6504866132cfd308d291f02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 10 Nov 2018 20:09:49 +0100 Subject: check for all whitespace characters --- src/library/searchquery.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index f6ca699663..0ac3748598 100644 --- a/src/library/searchquery.cpp +++ b/src/library/searchquery.cpp @@ -158,10 +158,12 @@ bool TextFilterNode::match(const TrackPointer& pTrack) const { QString TextFilterNode::toSql() const { FieldEscaper escaper(m_database); QString argument = m_argument; - if (argument.right(1) == " ") { - // LIKE eats a tailing space. This can be avoided by adding "_" for any - // followng character - argument += "_"; + if (argument.size() > 0) { + if (argument[argument.size() - 1].isSpace()) { + // LIKE eats a tailing space. This can be avoided by adding a '_' + // that matches any following character. + argument.append('_'); + } } QString escapedArgument = escaper.escapeString( kSqlLikeMatchAll + argument + kSqlLikeMatchAll); -- cgit v1.2.3 From 6acd31a56caf1f302589110fd56cc9773b8f6deb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sat, 10 Nov 2018 21:05:38 +0100 Subject: Added a test for tailing spaces and quoted searches --- src/test/searchqueryparsertest.cpp | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'src') diff --git a/src/test/searchqueryparsertest.cpp b/src/test/searchqueryparsertest.cpp index cd8f4b830b..13a1f57323 100644 --- a/src/test/searchqueryparsertest.cpp +++ b/src/test/searchqueryparsertest.cpp @@ -260,6 +260,44 @@ TEST_F(SearchQueryParserTest, TextFilterAllowsSpace) { qPrintable(pQuery->toSql())); } +TEST_F(SearchQueryParserTest, TextFilterQuotes) { + QStringList searchColumns; + searchColumns << "artist" + << "album"; + + auto pQuery( + m_parser.parseQuery("comment:\"asdf ewe\"", searchColumns, "")); + + TrackPointer pTrack(Track::newTemporary()); + pTrack->setArtist("asdf"); + EXPECT_FALSE(pQuery->match(pTrack)); + pTrack->setComment("test ASDF ewetest"); + EXPECT_TRUE(pQuery->match(pTrack)); + + EXPECT_STREQ( + qPrintable(QString("comment LIKE '%asdf ewe%'")), + qPrintable(pQuery->toSql())); +} + +TEST_F(SearchQueryParserTest, TextFilterTailingSpace) { + QStringList searchColumns; + searchColumns << "artist" + << "album"; + + auto pQuery( + m_parser.parseQuery("comment:\"asdf \"", searchColumns, "")); + + TrackPointer pTrack(Track::newTemporary()); + pTrack->setArtist("asdf"); + EXPECT_FALSE(pQuery->match(pTrack)); + pTrack->setComment("test ASDF test"); + EXPECT_TRUE(pQuery->match(pTrack)); + + EXPECT_STREQ( + qPrintable(QString("comment LIKE '%asdf _%'")), + qPrintable(pQuery->toSql())); +} + TEST_F(SearchQueryParserTest, TextFilterNegation) { QStringList searchColumns; searchColumns << "artist" -- cgit v1.2.3 From cce34663c7c24558d2b01581d3ef523638bf2b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 11 Nov 2018 21:08:26 +0100 Subject: Dont decompose charactere when the base character is a space, fixing lp1802730 --- src/library/searchquery.cpp | 14 +++++++++++++- src/library/searchquery.h | 6 +----- src/test/searchqueryparsertest.cpp | 26 +++++++++++++++++++++++++- src/util/db/dbconnection.cpp | 24 ++++++++++++++++++------ src/util/db/dbconnection.h | 2 ++ 5 files changed, 59 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index 0ac3748598..23aa39ed0f 100644 --- a/src/library/searchquery.cpp +++ b/src/library/searchquery.cpp @@ -6,6 +6,7 @@ #include "track/keyutils.h" #include "library/dao/trackschema.h" #include "util/db/sqllikewildcards.h" +#include "util/db/dbconnection.h" QVariant getTrackValueForColumn(const TrackPointer& pTrack, const QString& column) { if (column == LIBRARYTABLE_ARTIST) { @@ -141,6 +142,15 @@ QString NotNode::toSql() const { } } +TextFilterNode::TextFilterNode(const QSqlDatabase& database, + const QStringList& sqlColumns, + const QString& argument) + : m_database(database), + m_sqlColumns(sqlColumns), + m_argument(argument) { + mixxx::DbConnection::makeStringLatinLow(&m_argument); +} + bool TextFilterNode::match(const TrackPointer& pTrack) const { for (const auto& sqlColumn: m_sqlColumns) { QVariant value = getTrackValueForColumn(pTrack, sqlColumn); @@ -148,7 +158,9 @@ bool TextFilterNode::match(const TrackPointer& pTrack) const { continue; } - if (value.toString().contains(m_argument, Qt::CaseInsensitive)) { + QString strValue = value.toString(); + mixxx::DbConnection::makeStringLatinLow(&strValue); + if (strValue.contains(m_argument)) { return true; } } diff --git a/src/library/searchquery.h b/src/library/searchquery.h index bf744ab24d..85a6d67803 100644 --- a/src/library/searchquery.h +++ b/src/library/searchquery.h @@ -76,11 +76,7 @@ class TextFilterNode : public QueryNode { public: TextFilterNode(const QSqlDatabase& database, const QStringList& sqlColumns, - const QString& argument) - : m_database(database), - m_sqlColumns(sqlColumns), - m_argument(argument) { - } + const QString& argument); bool match(const TrackPointer& pTrack) const override; QString toSql() const override; diff --git a/src/test/searchqueryparsertest.cpp b/src/test/searchqueryparsertest.cpp index 13a1f57323..5d7e84729d 100644 --- a/src/test/searchqueryparsertest.cpp +++ b/src/test/searchqueryparsertest.cpp @@ -279,6 +279,30 @@ TEST_F(SearchQueryParserTest, TextFilterQuotes) { qPrintable(pQuery->toSql())); } +TEST_F(SearchQueryParserTest, TextFilterDecoration) { + QStringList searchColumns; + searchColumns << "artist" + << "album"; + + auto pQuery( + m_parser.parseQuery(QString::fromUtf8("comment:\"asdf\xC2\xB0 ewe\""), searchColumns, "")); // with ˚ + + TrackPointer pTrack(Track::newTemporary()); + pTrack->setArtist("asdf"); + EXPECT_FALSE(pQuery->match(pTrack)); + pTrack->setComment("test ASDF ewetest"); + EXPECT_FALSE(pQuery->match(pTrack)); + + pTrack->setComment(QString::fromUtf8("comment:\"asdf\xC2\xB0 ewe\"")); + EXPECT_TRUE(pQuery->match(pTrack)); + + qDebug() << pQuery->toSql(); + + EXPECT_STREQ( + qPrintable(QString::fromUtf8("comment LIKE '%asdf\xC2\xB0 ewe%'")), + qPrintable(pQuery->toSql())); +} + TEST_F(SearchQueryParserTest, TextFilterTailingSpace) { QStringList searchColumns; searchColumns << "artist" @@ -485,7 +509,7 @@ TEST_F(SearchQueryParserTest, MultipleFilters) { EXPECT_STREQ( qPrintable(QString("((bpm >= 127.12) AND (bpm <= 129)) AND " "((artist LIKE '%com truise%') OR (album_artist LIKE '%com truise%')) AND " - "((artist LIKE '%Colorvision%') OR (title LIKE '%Colorvision%'))")), + "((artist LIKE '%colorvision%') OR (title LIKE '%colorvision%'))")), qPrintable(pQuery->toSql())); } diff --git a/src/util/db/dbconnection.cpp b/src/util/db/dbconnection.cpp index ee78dfec0f..fb3dd40dc1 100644 --- a/src/util/db/dbconnection.cpp +++ b/src/util/db/dbconnection.cpp @@ -73,7 +73,14 @@ inline int compareLocaleAwareCaseInsensitive( void makeLatinLow(QChar* c, int count) { for (int i = 0; i < count; ++i) { if (c[i].decompositionTag() != QChar::NoDecomposition) { - c[i] = c[i].decomposition()[0]; + QString decomposition = c[i].decomposition(); + if (!decomposition[0].isSpace()) { + // here we remove the decoration brom all characters. + // We want "o" matching "ó" and all other variants but we + // do not decompose decoration only characters like "˚" where + // the base character is a space + c[i] = c[i].decomposition()[0]; + } } if (c[i].isUpper()) { c[i] = c[i].toLower(); @@ -88,11 +95,11 @@ const QChar kSqlLikeEscapeDefault = '\0'; // false (0) if they are different. // This is the original sqlite3 icuLikeCompare rewritten for QChar int likeCompareInner( - const QChar* pattern, // LIKE pattern - int patternSize, - const QChar* string, // The string to compare against - int stringSize, - const QChar esc) { // The escape character + const QChar* pattern, // LIKE pattern + int patternSize, + const QChar* string, // The string to compare against + int stringSize, + const QChar esc) { // The escape character int iPattern = 0; // Current index in pattern int iString = 0; // Current index in string @@ -376,6 +383,11 @@ int DbConnection::likeCompareLatinLow( esc); } +//static +void DbConnection::makeStringLatinLow(QString* string) { + makeLatinLow(string->data(), string->length()); +} + QDebug operator<<(QDebug debug, const DbConnection& connection) { return debug << connection.name() diff --git a/src/util/db/dbconnection.h b/src/util/db/dbconnection.h index b0f080533c..1b344ac8ff 100644 --- a/src/util/db/dbconnection.h +++ b/src/util/db/dbconnection.h @@ -22,6 +22,8 @@ class DbConnection final { QString* string, QChar esc); + static void makeStringLatinLow(QString* string); + struct Params { QString type; QString hostName; -- cgit v1.2.3 From 75951f0671de0a6743bf7d5ba8a1c6ebc0391113 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 11 Nov 2018 21:14:03 +0100 Subject: improve comments --- src/library/searchquery.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index 23aa39ed0f..be35d22ae9 100644 --- a/src/library/searchquery.cpp +++ b/src/library/searchquery.cpp @@ -173,7 +173,7 @@ QString TextFilterNode::toSql() const { if (argument.size() > 0) { if (argument[argument.size() - 1].isSpace()) { // LIKE eats a tailing space. This can be avoided by adding a '_' - // that matches any following character. + // as a delimiter that matches any following character. argument.append('_'); } } -- cgit v1.2.3 From c345797f974819238440082ea6b1a3d3ddc543e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Sun, 11 Nov 2018 21:22:53 +0100 Subject: Added a test for two consequitive spaces --- src/test/searchqueryparsertest.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src') diff --git a/src/test/searchqueryparsertest.cpp b/src/test/searchqueryparsertest.cpp index 5d7e84729d..b0d6b3d453 100644 --- a/src/test/searchqueryparsertest.cpp +++ b/src/test/searchqueryparsertest.cpp @@ -320,6 +320,17 @@ TEST_F(SearchQueryParserTest, TextFilterTailingSpace) { EXPECT_STREQ( qPrintable(QString("comment LIKE '%asdf _%'")), qPrintable(pQuery->toSql())); + + // We allow to search for two consequitve spaces + auto pQuery2( + m_parser.parseQuery("comment:\" \"", searchColumns, "")); + + EXPECT_FALSE(pQuery2->match(pTrack)); + + EXPECT_STREQ( + qPrintable(QString("comment LIKE '% _%'")), + qPrintable(pQuery2->toSql())); + } TEST_F(SearchQueryParserTest, TextFilterNegation) { -- cgit v1.2.3 From 8b296fd3ad3ab3a03184fe4d9ff680ee9ce43fc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Tue, 13 Nov 2018 01:13:51 +0100 Subject: fix typos --- src/library/searchquery.cpp | 2 +- src/test/searchqueryparsertest.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index be35d22ae9..d6ffbd3644 100644 --- a/src/library/searchquery.cpp +++ b/src/library/searchquery.cpp @@ -172,7 +172,7 @@ QString TextFilterNode::toSql() const { QString argument = m_argument; if (argument.size() > 0) { if (argument[argument.size() - 1].isSpace()) { - // LIKE eats a tailing space. This can be avoided by adding a '_' + // LIKE eats a trailing space. This can be avoided by adding a '_' // as a delimiter that matches any following character. argument.append('_'); } diff --git a/src/test/searchqueryparsertest.cpp b/src/test/searchqueryparsertest.cpp index b0d6b3d453..f5a3d024c3 100644 --- a/src/test/searchqueryparsertest.cpp +++ b/src/test/searchqueryparsertest.cpp @@ -303,7 +303,7 @@ TEST_F(SearchQueryParserTest, TextFilterDecoration) { qPrintable(pQuery->toSql())); } -TEST_F(SearchQueryParserTest, TextFilterTailingSpace) { +TEST_F(SearchQueryParserTest, TextFilterTrailingSpace) { QStringList searchColumns; searchColumns << "artist" << "album"; -- cgit v1.2.3 From c0e234248cf1658a167049964c07b8d0a14d7640 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Sch=C3=BCrmann?= Date: Thu, 15 Nov 2018 22:26:53 +0100 Subject: remove redundent blank lines --- src/test/searchqueryparsertest.cpp | 1 - src/util/db/dbconnection.cpp | 1 - 2 files changed, 2 deletions(-) (limited to 'src') diff --git a/src/test/searchqueryparsertest.cpp b/src/test/searchqueryparsertest.cpp index f5a3d024c3..82aea93083 100644 --- a/src/test/searchqueryparsertest.cpp +++ b/src/test/searchqueryparsertest.cpp @@ -330,7 +330,6 @@ TEST_F(SearchQueryParserTest, TextFilterTrailingSpace) { EXPECT_STREQ( qPrintable(QString("comment LIKE '% _%'")), qPrintable(pQuery2->toSql())); - } TEST_F(SearchQueryParserTest, TextFilterNegation) { diff --git a/src/util/db/dbconnection.cpp b/src/util/db/dbconnection.cpp index fb3dd40dc1..4a66fa9ff4 100644 --- a/src/util/db/dbconnection.cpp +++ b/src/util/db/dbconnection.cpp @@ -100,7 +100,6 @@ int likeCompareInner( const QChar* string, // The string to compare against int stringSize, const QChar esc) { // The escape character - int iPattern = 0; // Current index in pattern int iString = 0; // Current index in string -- cgit v1.2.3