From 1deacaecf905e40c16ca0eada767dbc8d1abe4d6 Mon Sep 17 00:00:00 2001 From: Dakes Date: Tue, 6 Jun 2023 21:58:33 +0200 Subject: [PATCH] FilterParser: Add ability to filter by rating Playlists can now be filtered by the rating from 0-5 like: rating:0 rating:<3 rating:!=0 or by a float value, like: rating:f0.1 rating:>=f0.5 --- src/playlist/playlistfilter.cpp | 1 + src/playlist/playlistfilterparser.cpp | 126 +++++++++++++++++++++++++- src/playlist/playlistfilterparser.h | 1 + 3 files changed, 127 insertions(+), 1 deletion(-) diff --git a/src/playlist/playlistfilter.cpp b/src/playlist/playlistfilter.cpp index 74605b37a..94e2f5573 100644 --- a/src/playlist/playlistfilter.cpp +++ b/src/playlist/playlistfilter.cpp @@ -56,6 +56,7 @@ PlaylistFilter::PlaylistFilter(QObject *parent) column_names_["filename"] = Playlist::Column_Filename; column_names_["grouping"] = Playlist::Column_Grouping; column_names_["comment"] = Playlist::Column_Comment; + column_names_["rating"] = Playlist::Column_Rating; numerical_columns_ << Playlist::Column_Year << Playlist::Column_OriginalYear diff --git a/src/playlist/playlistfilterparser.cpp b/src/playlist/playlistfilterparser.cpp index 0efe2d28d..9a91edc98 100644 --- a/src/playlist/playlistfilterparser.cpp +++ b/src/playlist/playlistfilterparser.cpp @@ -117,6 +117,67 @@ class LexicalLeComparator : public SearchTermComparator { QString search_term_; }; +// Float Comparators are for the rating +class FloatEqComparator : public SearchTermComparator { + public: + explicit FloatEqComparator(const float value) : search_term_(value) {} + bool Matches(const QString &element) const override { + return search_term_ == element.toFloat(); + } + private: + float search_term_; +}; + +class FloatNeComparator : public SearchTermComparator { + public: + explicit FloatNeComparator(const float &value) : search_term_(value) {} + bool Matches(const QString &element) const override { + return search_term_ != element.toFloat(); + } + private: + float search_term_; +}; + +class FloatGtComparator : public SearchTermComparator { + public: + explicit FloatGtComparator(const float &value) : search_term_(value) {} + bool Matches(const QString &element) const override { + return element.toFloat() > search_term_; + } + private: + float search_term_; +}; + +class FloatGeComparator : public SearchTermComparator { + public: + explicit FloatGeComparator(const float &value) : search_term_(value) {} + bool Matches(const QString &element) const override { + return element.toFloat() >= search_term_; + } + private: + float search_term_; +}; + +class FloatLtComparator : public SearchTermComparator { + public: + explicit FloatLtComparator(const float &value) : search_term_(value) {} + bool Matches(const QString &element) const override { + return element.toFloat() < search_term_; + } + private: + float search_term_; +}; + +class FloatLeComparator : public SearchTermComparator { + public: + explicit FloatLeComparator(const float &value) : search_term_(value) {} + bool Matches(const QString &element) const override { + return element.toFloat() <= search_term_; + } + private: + float search_term_; +}; + class GtComparator : public SearchTermComparator { public: explicit GtComparator(const int value) : search_term_(value) {} @@ -454,7 +515,34 @@ FilterTree *FilterParser::createSearchTermTreeNode(const QString &col, const QSt // here comes a mess :/ // well, not that much of a mess, but so many options -_- SearchTermComparator *cmp = nullptr; - if (prefix == "!=" || prefix == "<>") { + + // Handle the float based Rating Column + if (columns_[col] == Playlist::Column_Rating) { + float parsedSearch = parseRating(search); + + if (prefix == "=") { + cmp = new FloatEqComparator(parsedSearch); + } + else if (prefix == "!=" || prefix == "<>") { + cmp = new FloatNeComparator(parsedSearch); + } + else if (prefix == ">") { + cmp = new FloatGtComparator(parsedSearch); + } + else if (prefix == ">=") { + cmp = new FloatGeComparator(parsedSearch); + } + else if (prefix == "<") { + cmp = new FloatLtComparator(parsedSearch); + } + else if (prefix == "<=") { + cmp = new FloatLeComparator(parsedSearch); + } + else { + cmp = new FloatEqComparator(parsedSearch); + } + } + else if (prefix == "!=" || prefix == "<>") { cmp = new NeComparator(search); } else if (!col.isEmpty() && columns_.contains(col) && numerical_columns_.contains(columns_[col])) { @@ -504,6 +592,7 @@ FilterTree *FilterParser::createSearchTermTreeNode(const QString &col, const QSt cmp = new DefaultComparator(search); } } + if (columns_.contains(col)) { if (columns_[col] == Playlist::Column_Length) { cmp = new DropTailComparatorDecorator(cmp); @@ -552,3 +641,38 @@ int FilterParser::parseTime(const QString &time_str) { seconds = seconds * 60 + accum; return seconds; } + +// The rating column contains the rating as a float from 0-1 or -1 if unrated. +// If the rating is a number from 0-5, map it to 0-1 +// To use float values directly, the search term can be prefixed with "f" (rating:>f0.2) +// If search is 0, or by default, uses -1 +float FilterParser::parseRating(const QString &rating_str) { + if (rating_str.isEmpty()) { + return -1; + } + float rating = -1; + bool ok = false; + float rating_input = rating_str.toFloat(&ok); + // is valid int from 0-5: convert to float + if (ok && rating_input >= 0 && rating_input <= 5) { + rating = rating_input / 5.; + } + + // check if the search is a float + else if (rating_str.at(0) == 'f') { + QString rating_float = rating_str; + rating_float = rating_float.remove(0, 1); + + ok = false; + rating_float.toFloat(&ok); + if (ok) { + rating = rating_float.toFloat(&ok); + } + } + // Songs with zero rating have -1 in the DB + if (rating == 0) { + rating = -1; + } + + return rating; +} diff --git a/src/playlist/playlistfilterparser.h b/src/playlist/playlistfilterparser.h index 74ee2ee06..46d75e726 100644 --- a/src/playlist/playlistfilterparser.h +++ b/src/playlist/playlistfilterparser.h @@ -89,6 +89,7 @@ class FilterParser { FilterTree *createSearchTermTreeNode(const QString &col, const QString &prefix, const QString &search) const; static int parseTime(const QString &time_str); + static float parseRating(const QString &rating_str); QString::const_iterator iter_; QString::const_iterator end_;