Skip to content

Commit

Permalink
Merge pull request #4536 from ronso0/lib-selection-tweaks
Browse files Browse the repository at this point in the history
Library track selection tweaks
  • Loading branch information
uklotzde authored Jan 7, 2022
2 parents 2db5d90 + a381d33 commit e7fde41
Show file tree
Hide file tree
Showing 18 changed files with 260 additions and 29 deletions.
4 changes: 2 additions & 2 deletions src/library/autodj/dlgautodj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,6 @@ void DlgAutoDJ::saveCurrentViewState() {
m_pTrackTableView->saveCurrentViewState();
}

void DlgAutoDJ::restoreCurrentViewState() {
m_pTrackTableView->restoreCurrentViewState();
bool DlgAutoDJ::restoreCurrentViewState() {
return m_pTrackTableView->restoreCurrentViewState();
}
2 changes: 1 addition & 1 deletion src/library/autodj/dlgautodj.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView {
void loadSelectedTrackToGroup(const QString& group, bool play) override;
void moveSelection(int delta) override;
void saveCurrentViewState() override;
void restoreCurrentViewState() override;
bool restoreCurrentViewState() override;

public slots:
void shufflePlaylistButton(bool buttonChecked);
Expand Down
4 changes: 2 additions & 2 deletions src/library/dlganalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,6 @@ void DlgAnalysis::saveCurrentViewState() {
m_pAnalysisLibraryTableView->saveCurrentViewState();
}

void DlgAnalysis::restoreCurrentViewState() {
m_pAnalysisLibraryTableView->restoreCurrentViewState();
bool DlgAnalysis::restoreCurrentViewState() {
return m_pAnalysisLibraryTableView->restoreCurrentViewState();
}
2 changes: 1 addition & 1 deletion src/library/dlganalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class DlgAnalysis : public QWidget, public Ui::DlgAnalysis, public virtual Libra
return m_pAnalysisLibraryTableModel->currentSearch();
}
void saveCurrentViewState() override;
void restoreCurrentViewState() override;
bool restoreCurrentViewState() override;

public slots:
void tableSelectionChanged(const QItemSelection& selected,
Expand Down
4 changes: 2 additions & 2 deletions src/library/dlghidden.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ void DlgHidden::saveCurrentViewState() {
m_pTrackTableView->saveCurrentViewState();
}

void DlgHidden::restoreCurrentViewState() {
m_pTrackTableView->restoreCurrentViewState();
bool DlgHidden::restoreCurrentViewState() {
return m_pTrackTableView->restoreCurrentViewState();
}

void DlgHidden::setFocus() {
Expand Down
2 changes: 1 addition & 1 deletion src/library/dlghidden.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class DlgHidden : public QWidget, public Ui::DlgHidden, public LibraryView {
void onSearch(const QString& text) override;
QString currentSearch();
void saveCurrentViewState() override;
void restoreCurrentViewState() override;
bool restoreCurrentViewState() override;

public slots:
void clicked();
Expand Down
5 changes: 3 additions & 2 deletions src/library/dlgmissing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,9 @@ bool DlgMissing::hasFocus() const {
void DlgMissing::saveCurrentViewState() {
m_pTrackTableView->saveCurrentViewState();
};
void DlgMissing::restoreCurrentViewState() {
m_pTrackTableView->restoreCurrentViewState();

bool DlgMissing::restoreCurrentViewState() {
return m_pTrackTableView->restoreCurrentViewState();
};

void DlgMissing::setFocus() {
Expand Down
2 changes: 1 addition & 1 deletion src/library/dlgmissing.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class DlgMissing : public QWidget, public Ui::DlgMissing, public LibraryView {
void onSearch(const QString& text) override;
QString currentSearch();
void saveCurrentViewState() override;
void restoreCurrentViewState() override;
bool restoreCurrentViewState() override;

public slots:
void clicked();
Expand Down
7 changes: 5 additions & 2 deletions src/library/libraryview.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,11 @@ class LibraryView {
}
virtual void saveCurrentViewState() {
}
virtual void restoreCurrentViewState() {
}
/// @brief restores current view state.
/// @return true if restore succeeded
virtual bool restoreCurrentViewState() {
return false;
};

/// If applicable, requests that the LibraryView load the selected track to
/// the specified group. Does nothing otherwise.
Expand Down
4 changes: 2 additions & 2 deletions src/library/recording/dlgrecording.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,6 @@ void DlgRecording::saveCurrentViewState() {
m_pTrackTableView->saveCurrentViewState();
}

void DlgRecording::restoreCurrentViewState() {
m_pTrackTableView->restoreCurrentViewState();
bool DlgRecording::restoreCurrentViewState() {
return m_pTrackTableView->restoreCurrentViewState();
}
2 changes: 1 addition & 1 deletion src/library/recording/dlgrecording.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class DlgRecording : public QWidget, public Ui::DlgRecording, public virtual Lib
void moveSelection(int delta) override;
inline const QString currentSearch() { return m_proxyModel.currentSearch(); }
void saveCurrentViewState() override;
void restoreCurrentViewState() override;
bool restoreCurrentViewState() override;

public slots:
void slotRecordingStateChanged(bool);
Expand Down
45 changes: 45 additions & 0 deletions src/library/searchqueryparser.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
#include "library/searchqueryparser.h"

#include <QRegularExpression>

#include "track/keyutils.h"

constexpr char kNegatePrefix[] = "-";
constexpr char kFuzzyPrefix[] = "~";
// see https://stackoverflow.com/questions/1310473/regex-matching-spaces-but-not-in-strings
const QRegularExpression kSplitIntoWordsRegexp = QRegularExpression(
QStringLiteral(" (?=[^\"]*(\"[^\"]*\"[^\"]*)*$)"));

SearchQueryParser::SearchQueryParser(TrackCollection* pTrackCollection)
: m_pTrackCollection(pTrackCollection) {
Expand Down Expand Up @@ -271,3 +276,43 @@ std::unique_ptr<QueryNode> SearchQueryParser::parseQuery(const QString& query,

return pQuery;
}

QStringList SearchQueryParser::splitQueryIntoWords(const QString& query) {
QStringList queryWordList = query.split(kSplitIntoWordsRegexp, QString::SkipEmptyParts);
return queryWordList;
}

bool SearchQueryParser::queryIsLessSpecific(const QString& original, const QString& changed) {
// separate search query into tokens
QStringList oldWordList = SearchQueryParser::splitQueryIntoWords(original);
QStringList newWordList = SearchQueryParser::splitQueryIntoWords(changed);

// we sort the lists for length so the comperator will pop the longest match first
std::sort(oldWordList.begin(), oldWordList.end(), [=](const QString& v1, const QString& v2) {
return v1.length() > v2.length();
});
std::sort(newWordList.begin(), newWordList.end(), [=](const QString& v1, const QString& v2) {
return v1.length() > v2.length();
});

for (int i = 0; i < oldWordList.length(); i++) {
const QString& oldWord = oldWordList.at(i);
for (int j = 0; j < newWordList.length(); j++) {
const QString& newWord = newWordList.at(j);
// Note(ronso0) Look for missing '~' in newWord (fuzzy matching)?
if ((oldWord.startsWith("-") && oldWord.startsWith(newWord)) ||
(!newWord.contains(":") && oldWord.contains(newWord)) ||
(newWord.contains(":") && oldWord.startsWith(newWord))) {
// we found a match and can remove the search term list
newWordList.removeAt(j);
break;
}
}
}
// if the new search query list contains no more terms, we have a reduced
// search term
if (newWordList.empty()) {
return true;
}
return false;
}
4 changes: 4 additions & 0 deletions src/library/searchqueryparser.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ class SearchQueryParser {
const QStringList& searchColumns,
const QString& extraFilter) const;

/// splits the query into a list of terms
static QStringList splitQueryIntoWords(const QString& query);
/// checks if the changed search query is less specific then the original term
static bool queryIsLessSpecific(const QString& original, const QString& changed);

private:
void parseTokens(QStringList tokens,
Expand Down
103 changes: 102 additions & 1 deletion src/test/searchqueryparsertest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,6 @@ TEST_F(SearchQueryParserTest, ShortCrateFilter) {
EXPECT_TRUE(pQuery->match(pTrackC));
}


TEST_F(SearchQueryParserTest, CrateFilterEmpty) {
// Empty should match everything
auto pQuery(m_parser.parseQuery(QString("crate: "), QStringList(), ""));
Expand Down Expand Up @@ -996,3 +995,105 @@ TEST_F(SearchQueryParserTest, CrateFilterWithCrateFilterAndNegation){
") AND (NOT (" + m_crateFilterQuery.arg(searchTermB) + "))"),
qPrintable(pQueryB->toSql()));
}

TEST_F(SearchQueryParserTest, SplitQueryIntoWords) {
QStringList rv = SearchQueryParser::splitQueryIntoWords(QString("a test b"));
QStringList ex = QStringList() << "a"
<< "test"
<< "b";
qDebug() << rv << ex;
EXPECT_EQ(rv, ex);

QStringList rv2 = SearchQueryParser::splitQueryIntoWords(QString("a \"test ' b\" x"));
QStringList ex2 = QStringList() << "a"
<< "\"test ' b\""
<< "x";
qDebug() << rv2 << ex2;
EXPECT_EQ(rv2, ex2);

QStringList rv3 = SearchQueryParser::splitQueryIntoWords(QString("a x"));
QStringList ex3 = QStringList() << "a"
<< "x";
qDebug() << rv3 << ex3;
EXPECT_EQ(rv3, ex3);

QStringList rv4 = SearchQueryParser::splitQueryIntoWords(
QString("a crate:x title:\"S p A C e\" ~key:2m"));
QStringList ex4 = QStringList() << "a"
<< "crate:x"
<< "title:\"S p A C e\""
<< "~key:2m";
qDebug() << rv4 << ex4;
EXPECT_EQ(rv4, ex4);
}

TEST_F(SearchQueryParserTest, QueryIsLessSpecific) {
// Generate a file name for the temporary file
EXPECT_TRUE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("searchme"),
QStringLiteral("searchm")));

EXPECT_TRUE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("A B C"),
QStringLiteral("A C")));

EXPECT_FALSE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("A B C"),
QStringLiteral("A D C")));

EXPECT_TRUE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("A D C"),
QStringLiteral("A D C ")));

EXPECT_TRUE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("A D C "),
QStringLiteral("A D C")));

EXPECT_FALSE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("A B C"),
QStringLiteral("A D C")));

EXPECT_TRUE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("A D C"),
QStringLiteral("A D C ")));

EXPECT_TRUE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("A D C "),
QStringLiteral("A D C")));

EXPECT_FALSE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("A B C"),
QStringLiteral("A D C")));

EXPECT_TRUE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("Abba1 Abba2 Abb"),
QStringLiteral("Abba1 Abba Abb")));

EXPECT_FALSE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("Abba1 Abba2 Abb"),
QStringLiteral("Abba1 Aba Abb")));

EXPECT_TRUE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("Abba1"),
QLatin1String("")));

EXPECT_TRUE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("Abba1"),
QStringLiteral("bba")));

EXPECT_TRUE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("crate:abc"),
QStringLiteral("crate:ab")));

EXPECT_FALSE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("crate:\"a b c\""),
QStringLiteral("crate:\"a c\"")));

EXPECT_FALSE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("-crate:\"a b c\""),
QStringLiteral("crate:\"a b c\"")));

EXPECT_FALSE(SearchQueryParser::queryIsLessSpecific(
QStringLiteral("-crate:\"a b c\""),
QStringLiteral("crate:\"a b c\"")));
}
13 changes: 7 additions & 6 deletions src/widget/wlibrarytableview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -133,12 +133,12 @@ void WLibraryTableView::saveTrackModelState(
m_modelStateCache.insert(key, state, 1);
}

void WLibraryTableView::restoreTrackModelState(
bool WLibraryTableView::restoreTrackModelState(
const QAbstractItemModel* model, const QString& key) {
//qDebug() << "restoreTrackModelState:" << model << key;
//qDebug() << m_modelStateCache.keys();
if (model == nullptr) {
return;
return false;
}

ModelState* state = m_modelStateCache.take(key);
Expand All @@ -148,7 +148,7 @@ void WLibraryTableView::restoreTrackModelState(
verticalScrollBar()->setValue(0);
horizontalScrollBar()->setValue(0);
setCurrentIndex(QModelIndex());
return;
return false;
}

verticalScrollBar()->setValue(state->verticalScrollPosition);
Expand All @@ -171,6 +171,7 @@ void WLibraryTableView::restoreTrackModelState(

// reinsert the state into the cache
m_modelStateCache.insert(key, state, 1);
return true;
}

void WLibraryTableView::setTrackTableFont(const QFont& font) {
Expand Down Expand Up @@ -212,13 +213,13 @@ void WLibraryTableView::saveCurrentViewState() {
saveTrackModelState(currentModel, key);
}

void WLibraryTableView::restoreCurrentViewState() {
bool WLibraryTableView::restoreCurrentViewState() {
const QAbstractItemModel* currentModel = model();
QString key = getModelStateKey();
if (!currentModel || key.isEmpty()) {
return;
return false;
}
restoreTrackModelState(currentModel, key);
return restoreTrackModelState(currentModel, key);
}

void WLibraryTableView::focusInEvent(QFocusEvent* event) {
Expand Down
7 changes: 5 additions & 2 deletions src/widget/wlibrarytableview.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,12 @@ class WLibraryTableView : public QTableView, public virtual LibraryView {
/// item selection and current index values associated with model by given
/// key and restores it
/// @param key unique for trackmodel
void restoreTrackModelState(const QAbstractItemModel* model, const QString& key);
/// @return true if restore succeeded
bool restoreTrackModelState(const QAbstractItemModel* model, const QString& key);
void saveCurrentViewState() override;
void restoreCurrentViewState() override;
/// @brief restores current view state.
/// @return true if restore succeeded
bool restoreCurrentViewState() override;

signals:
void loadTrack(TrackPointer pTrack);
Expand Down
Loading

0 comments on commit e7fde41

Please sign in to comment.