diff options
author | Uwe Klotz <uklotz@mixxx.org> | 2018-11-16 00:14:10 +0100 |
---|---|---|
committer | Uwe Klotz <uklotz@mixxx.org> | 2018-11-16 00:14:10 +0100 |
commit | d0a441d9cee780282eb4ce3e42d20e9412050ea7 (patch) | |
tree | 30f2f321d1b264f4904f64e89c3c3e244067aa35 /src/library | |
parent | 54261f3b8f3221578aa95c928ca5217852eeac9b (diff) | |
parent | 3a609d743841d5cebd883b66325cea66909986b6 (diff) |
Merge branch '2.2' of git@github.com:mixxxdj/mixxx.git
# Conflicts:
# src/dialog/dlgabout.cpp
Diffstat (limited to 'src/library')
-rw-r--r-- | src/library/banshee/bansheefeature.cpp | 1 | ||||
-rw-r--r-- | src/library/banshee/bansheeplaylistmodel.cpp | 73 | ||||
-rw-r--r-- | src/library/banshee/bansheeplaylistmodel.h | 4 | ||||
-rw-r--r-- | src/library/baseexternallibraryfeature.cpp | 11 | ||||
-rw-r--r-- | src/library/baseexternalplaylistmodel.cpp | 9 | ||||
-rw-r--r-- | src/library/baseexternalplaylistmodel.h | 1 | ||||
-rw-r--r-- | src/library/crate/cratetablemodel.cpp | 4 | ||||
-rw-r--r-- | src/library/librarytablemodel.cpp | 4 | ||||
-rw-r--r-- | src/library/playlisttablemodel.cpp | 4 | ||||
-rw-r--r-- | src/library/searchquery.cpp | 26 | ||||
-rw-r--r-- | src/library/searchquery.h | 6 | ||||
-rw-r--r-- | src/library/searchqueryparser.cpp | 16 | ||||
-rw-r--r-- | src/library/trackmodel.h | 4 |
13 files changed, 109 insertions, 54 deletions
diff --git a/src/library/banshee/bansheefeature.cpp b/src/library/banshee/bansheefeature.cpp index e0a6b4c75a..bdb16b58e1 100644 --- a/src/library/banshee/bansheefeature.cpp +++ b/src/library/banshee/bansheefeature.cpp @@ -139,6 +139,7 @@ void BansheeFeature::appendTrackIdsFromRightClickIndex(QList<TrackId>* 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..d46661b965 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" @@ -31,39 +32,50 @@ #define CLM_COMPOSER "composer" #define CLM_PREVIEW "preview" +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(sTableNumber.fetchAndAddAcquire(1)); } BansheePlaylistModel::~BansheePlaylistModel() { + dropTempTable(); } -void BansheePlaylistModel::setTableModel(int playlistId) { - //qDebug() << "BansheePlaylistModel::setTableModel" << playlistId; - if (m_playlistId == playlistId) { - qDebug() << "Already focused on playlist " << playlistId; - return; - } - +void BansheePlaylistModel::dropTempTable() { 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("DROP TABLE IF EXISTS %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; + } + + dropTempTable(); if (playlistId >= 0) { // setup new playlist m_playlistId = playlistId; QSqlQuery query(m_pTrackCollection->database()); - QString strQuery("CREATE TEMP TABLE IF NOT EXISTS " BANSHEE_TABLE - " (" CLM_VIEW_ORDER " INTEGER, " + QString strQuery("CREATE TEMP TABLE IF NOT EXISTS %1" + " (" CLM_TRACK_ID " INTEGER, " + CLM_VIEW_ORDER " INTEGER, " CLM_ARTIST " TEXT, " CLM_TITLE " TEXT, " CLM_DURATION " INTEGER, " @@ -82,12 +94,13 @@ 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 - " (" CLM_VIEW_ORDER ", " + QString strQuery2("INSERT INTO %1" + " (" CLM_TRACK_ID ", " + CLM_VIEW_ORDER ", " CLM_ARTIST ", " CLM_TITLE ", " CLM_DURATION ", " @@ -106,6 +119,7 @@ void BansheePlaylistModel::setTableModel(int playlistId) { CLM_PLAYCOUNT ", " CLM_COMPOSER ") " "VALUES (:" + CLM_TRACK_ID ", :" CLM_VIEW_ORDER ", :" CLM_ARTIST ", :" CLM_TITLE ", :" @@ -125,6 +139,7 @@ void BansheePlaylistModel::setTableModel(int playlistId) { CLM_PLAYCOUNT ", :" CLM_COMPOSER ") "); + query.prepare(strQuery2.arg(m_tempTableName)); QList<struct BansheeDbConnection::PlaylistEntry> list = m_pConnection->getPlaylistEntries(playlistId); @@ -133,6 +148,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); @@ -165,11 +183,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 @@ -189,10 +210,10 @@ void BansheePlaylistModel::setTableModel(int playlistId) { << CLM_COMPOSER; QSharedPointer<BaseTrackCache> trackSource( - new BaseTrackCache(m_pTrackCollection, BANSHEE_TABLE, CLM_VIEW_ORDER, + new BaseTrackCache(m_pTrackCollection, m_tempTableName, CLM_TRACK_ID, trackSourceColumns, false)); - setTable(BANSHEE_TABLE, CLM_VIEW_ORDER, tableColumns, trackSource); + setTable(m_tempTableName, CLM_TRACK_ID, tableColumns, trackSource); setSearch(""); setDefaultSort(fieldIndex(PLAYLISTTRACKSTABLE_POSITION), Qt::AscendingOrder); setSort(defaultSortColumn(), defaultSortOrder()); @@ -327,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()) { @@ -365,6 +395,7 @@ QString BansheePlaylistModel::getTrackLocation(const QModelIndex& index) const { } bool BansheePlaylistModel::isColumnInternal(int column) { - Q_UNUSED(column); - return false; + return (column == fieldIndex(ColumnCache::COLUMN_PLAYLISTTRACKSTABLE_TRACKID) || + (PlayerManager::numPreviewDecks() == 0 && + column == fieldIndex(ColumnCache::COLUMN_LIBRARYTABLE_PREVIEW))); } diff --git a/src/library/banshee/bansheeplaylistmodel.h b/src/library/banshee/bansheeplaylistmodel.h index efda77a878..d89fc20a8a 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; @@ -41,9 +43,11 @@ class BansheePlaylistModel : public BaseSqlTableModel { private: QString getFieldString(const QModelIndex& index, const QString& fieldName) const; QVariant getFieldVariant(const QModelIndex& index, const QString& fieldName) const; + void dropTempTable(); BansheeDbConnection* m_pConnection; int m_playlistId; + QString m_tempTableName; }; #endif // BANSHEEPLAYLISTMODEL_H diff --git a/src/library/baseexternallibraryfeature.cpp b/src/library/baseexternallibraryfeature.cpp index 87807a62e7..b527c119d3 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<TrackId> trackIds; QString playlist; @@ -96,15 +96,14 @@ void BaseExternalLibraryFeature::slotImportAsMixxxPlaylist() { } // This is a common function for all external Librarys copied to Mixxx DB -void BaseExternalLibraryFeature::appendTrackIdsFromRightClickIndex(QList<TrackId>* trackIds, QString* pPlaylist) { +void BaseExternalLibraryFeature::appendTrackIdsFromRightClickIndex( + QList<TrackId>* trackIds, QString* pPlaylist) { if (!m_lastRightClickedIndex.isValid()) { 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(); + DEBUG_ASSERT(pPlaylist); + *pPlaylist = m_lastRightClickedIndex.data().toString(); QScopedPointer<BaseSqlTableModel> pPlaylistModelToAdd( getPlaylistModelForPlaylist(*pPlaylist)); 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; diff --git a/src/library/crate/cratetablemodel.cpp b/src/library/crate/cratetablemodel.cpp index 661ac606a4..ca059ffe10 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_CRATE - | 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 8c659f9b93..e1bc686c7d 100644 --- a/src/library/playlisttablemodel.cpp +++ b/src/library/playlisttablemodel.cpp @@ -242,12 +242,10 @@ TrackModel::CapabilitiesFlags PlaylistTableModel::getCapabilities() const { | TRACKMODELCAPS_REORDER | TRACKMODELCAPS_ADDTOCRATE | TRACKMODELCAPS_ADDTOPLAYLIST - | TRACKMODELCAPS_IMPORTMETADATA + | TRACKMODELCAPS_EDITMETADATA | TRACKMODELCAPS_LOADTODECK | TRACKMODELCAPS_LOADTOSAMPLER | TRACKMODELCAPS_LOADTOPREVIEWDECK - | TRACKMODELCAPS_MANIPULATEBEATS - | TRACKMODELCAPS_CLEAR_BEATS | TRACKMODELCAPS_RESETPLAYED; if (m_iPlaylistId != m_pTrackCollection->getPlaylistDAO().getPlaylistIdFromName(AUTODJ_TABLE)) { diff --git a/src/library/searchquery.cpp b/src/library/searchquery.cpp index 13dee24ef8..04e6814e03 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; } } @@ -157,8 +169,16 @@ 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.size() > 0) { + if (argument[argument.size() - 1].isSpace()) { + // LIKE eats a trailing space. This can be avoided by adding a '_' + // as a delimiter that matches any following character. + argument.append('_'); + } + } + 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/searchquery.h b/src/library/searchquery.h index c36f1ad400..20241dec5a 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/library/searchqueryparser.cpp b/src/library/searchqueryparser.cpp index 7ab0c83cdd..c8b0a47a30 100644 --- a/src/library/searchqueryparser.cpp +++ b/src/library/searchqueryparser.cpp @@ -136,15 +136,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<CrateFilterNode>( - &m_pTrackCollection->crates(), argument); + &m_pTrackCollection->crates(), argument); } else { pNode = std::make_unique<TextFilterNode>( - m_pTrackCollection->database(), m_fieldToSqlColumns[field], argument); + m_pTrackCollection->database(), + m_fieldToSqlColumns[field], argument); } } } else if (m_numericFilterMatcher.indexIn(token) != -1) { @@ -154,7 +155,7 @@ void SearchQueryParser::parseTokens(QStringList tokens, if (!argument.isEmpty()) { pNode = std::make_unique<NumericFilterNode>( - m_fieldToSqlColumns[field], argument); + m_fieldToSqlColumns[field], argument); } } else if (m_specialFilterMatcher.indexIn(token) != -1) { bool fuzzy = token.startsWith(kFuzzyPrefix); @@ -190,6 +191,7 @@ void SearchQueryParser::parseTokens(QStringList tokens, } // Don't trigger on a lone minus sign. if (!token.isEmpty()) { + QString argument = getTextArgument(token, &tokens); // For untagged strings we search the track fields as well // as the crate names the track is in. This allows the user // to use crates like tags @@ -197,14 +199,14 @@ void SearchQueryParser::parseTokens(QStringList tokens, std::unique_ptr<OrNode> gNode = std::make_unique<OrNode>(); gNode->addNode(std::make_unique<CrateFilterNode>( - &m_pTrackCollection->crates(), token)); + &m_pTrackCollection->crates(), argument)); gNode->addNode(std::make_unique<TextFilterNode>( - m_pTrackCollection->database(), queryColumns, token)); + m_pTrackCollection->database(), queryColumns, argument)); pNode = std::move(gNode); } else { pNode = std::make_unique<TextFilterNode>( - m_pTrackCollection->database(), queryColumns, token); + m_pTrackCollection->database(), queryColumns, argument); } } } diff --git a/src/library/trackmodel.h b/src/library/trackmodel.h index a877be7ed5..1c4a17fb49 100644 --- a/src/library/trackmodel.h +++ b/src/library/trackmodel.h @@ -35,13 +35,11 @@ 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, |