diff options
author | Berthold Stoeger <bstoeger@mail.tuwien.ac.at> | 2020-06-01 23:37:36 +0200 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2020-09-29 16:13:03 -0700 |
commit | 634e26cbcea064d6ef3d7550dacf54196547bedb (patch) | |
tree | 39ac7894854c770396e8719bf67239d4147e9a7f | |
parent | 6c443ba8411fb9f019be10e061878f7c9566f560 (diff) | |
download | subsurface-634e26cbcea064d6ef3d7550dacf54196547bedb.tar.gz |
filter: unify desktop and mobile filters
Switch the mobile code to use the constraint-based filter. The one
thing that is still commented out is dive-site mode, since mobile
doesn't (yet) have a dive-site edit feature. And even if it had,
the dive list probably wouldn't be shown at the same time.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
-rw-r--r-- | core/divefilter.cpp | 142 | ||||
-rw-r--r-- | core/divefilter.h | 44 | ||||
-rw-r--r-- | mobile-widgets/qmlmanager.cpp | 26 |
3 files changed, 37 insertions, 175 deletions
diff --git a/core/divefilter.cpp b/core/divefilter.cpp index e1aaf7bce..5765ed673 100644 --- a/core/divefilter.cpp +++ b/core/divefilter.cpp @@ -4,6 +4,12 @@ #include "divelist.h" // for filter_dive #include "qthelper.h" #include "subsurface-qt/divelistnotifier.h" +#ifndef SUBSURFACE_MOBILE +#include "desktop-widgets/mapwidget.h" +#include "desktop-widgets/mainwindow.h" +#include "desktop-widgets/divelistview.h" +#include "qt-models/filtermodels.h" +#endif static void updateDiveStatus(dive *d, bool newStatus, ShownChange &change) { @@ -15,132 +21,6 @@ static void updateDiveStatus(dive *d, bool newStatus, ShownChange &change) } } -#ifdef SUBSURFACE_MOBILE - -#include "tag.h" -static QStringList getTagList(const dive *d) -{ - QStringList res; - for (const tag_entry *tag = d->tag_list; tag; tag = tag->next) - res.push_back(QString(tag->tag->name).trimmed()); - res.append(gettextFromC::tr(divemode_text_ui[d->dc.divemode])); - return res; -} - -// Check if a string-list contains at least one string that starts with the second argument. -// Comparison is non case sensitive and removes white space. -static bool listContainsSuperstring(const QStringList &list, const QString &s) -{ - return std::any_of(list.begin(), list.end(), [&s](const QString &s2) - { return s2.startsWith(s, Qt::CaseInsensitive); } ); -} - -static bool check(const QStringList &items, const QStringList &list) -{ - return std::all_of(items.begin(), items.end(), [&list](const QString &item) - { return listContainsSuperstring(list, item); }); -} - -static bool hasTags(const QStringList &tags, const struct dive *d) -{ - if (tags.isEmpty()) - return true; - return check(tags, getTagList(d)); -} - -static bool hasPersons(const QStringList &people, const struct dive *d) -{ - if (people.isEmpty()) - return true; - QStringList dive_people = QString(d->buddy).split(",", QString::SkipEmptyParts) - + QString(d->divemaster).split(",", QString::SkipEmptyParts); - return check(people, dive_people); -} - -DiveFilter *DiveFilter::instance() -{ - static DiveFilter self; - return &self; -} - -DiveFilter::DiveFilter() -{ -} - -ShownChange DiveFilter::update(const QVector<dive *> &dives) const -{ - dive *old_current = current_dive; - - ShownChange res; - switch (filterData.mode) { - default: - case FilterData::Mode::NONE: - for (dive *d: dives) - updateDiveStatus(d, true, res); - break; - case FilterData::Mode::FULLTEXT: - for (dive *d: dives) - updateDiveStatus(d, fulltext_dive_matches(d, filterData.fullText, StringFilterMode::STARTSWITH), res); - break; - case FilterData::Mode::PEOPLE: - for (dive *d: dives) - updateDiveStatus(d, hasPersons(filterData.tags, d), res); - break; - case FilterData::Mode::TAGS: - for (dive *d: dives) - updateDiveStatus(d, hasTags(filterData.tags, d), res); - break; - } - - res.currentChanged = old_current != current_dive; - return res; -} - -ShownChange DiveFilter::updateAll() const -{ - dive *old_current = current_dive; - - ShownChange res; - int i; - dive *d; - switch (filterData.mode) { - default: - case FilterData::Mode::NONE: - for_each_dive(i, d) - updateDiveStatus(d, true, res); - break; - case FilterData::Mode::FULLTEXT: { - FullTextResult ft = fulltext_find_dives(filterData.fullText, StringFilterMode::STARTSWITH); - for_each_dive(i, d) - updateDiveStatus(d, ft.dive_matches(d), res); - break; - } - case FilterData::Mode::PEOPLE: - for_each_dive(i, d) - updateDiveStatus(d, hasPersons(filterData.tags, d), res); - break; - case FilterData::Mode::TAGS: - for_each_dive(i, d) - updateDiveStatus(d, hasTags(filterData.tags, d), res); - break; - } - - res.currentChanged = old_current != current_dive; - return res; -} - -void DiveFilter::setFilter(const FilterData &data) -{ - filterData = data; - emit diveListNotifier.filterReset(); -} - -#else // SUBSURFACE_MOBILE - -#include "desktop-widgets/mapwidget.h" -#include "desktop-widgets/mainwindow.h" -#include "desktop-widgets/divelistview.h" -#include "qt-models/filtermodels.h" bool FilterData::validFilter() const { @@ -216,6 +96,7 @@ bool DiveFilter::showDive(const struct dive *d) const [d] (const filter_constraint &c) { return filter_constraint_match_dive(c, d); }); } +#ifndef SUBSURFACE_MOBILE void DiveFilter::startFilterDiveSites(QVector<dive_site *> ds) { if (++diveSiteRefCount > 1) { @@ -224,7 +105,7 @@ void DiveFilter::startFilterDiveSites(QVector<dive_site *> ds) std::sort(ds.begin(), ds.end()); dive_sites = ds; // When switching into dive site mode, reload the dive sites. - // We won't do this in myInvalidate() once we are in dive site mode. + // TODO: why here? why not catch the filterReset signal in the map widget MapWidget::instance()->reload(); emit diveListNotifier.filterReset(); } @@ -263,10 +144,15 @@ bool DiveFilter::diveSiteMode() const { return diveSiteRefCount > 0; } +#else +bool DiveFilter::diveSiteMode() const +{ + return false; +} +#endif void DiveFilter::setFilter(const FilterData &data) { filterData = data; emit diveListNotifier.filterReset(); } -#endif // SUBSURFACE_MOBILE diff --git a/core/divefilter.h b/core/divefilter.h index 64f70676b..a0c9b5d2f 100644 --- a/core/divefilter.h +++ b/core/divefilter.h @@ -10,6 +10,8 @@ #include <QStringList> struct dive; +struct dive_trip; +struct dive_site; // Structure describing changes of shown status upon applying the filter struct ShownChange { @@ -18,43 +20,6 @@ struct ShownChange { bool currentChanged; }; -// The dive filter for mobile is currently much simpler than for desktop. -// Therefore, for now we have two completely separate implementations. -// This should be unified in the future. -#ifdef SUBSURFACE_MOBILE - -struct FilterData { - // On mobile, we support searching fulltext (all fields), people (buddies and divemasters) and tags - enum class Mode { - NONE = 0, - FULLTEXT = 1, - PEOPLE = 2, - TAGS = 3 - }; - - Mode mode = Mode::NONE; - FullTextQuery fullText; // For fulltext - QStringList tags; // For people and tags -}; - -class DiveFilter { -public: - static DiveFilter *instance(); - - ShownChange update(const QVector<dive *> &dives) const; // Update filter status of given dives and return dives whose status changed - ShownChange updateAll() const; // Update filter status of all dives and return dives whose status changed - void setFilter(const FilterData &data); -private: - DiveFilter(); - - FilterData filterData; -}; - -#else - -struct dive_trip; -struct dive_site; - struct FilterData { // The mode ids are chosen such that they can be directly converted from / to combobox indices. enum class Mode { @@ -73,11 +38,13 @@ class DiveFilter { public: static DiveFilter *instance(); - bool diveSiteMode() const; // returns true if we're filtering on dive site + bool diveSiteMode() const; // returns true if we're filtering on dive site (on mobile always returns false) +#ifndef SUBSURFACE_MOBILE const QVector<dive_site *> &filteredDiveSites() const; void startFilterDiveSites(QVector<dive_site *> ds); void setFilterDiveSite(QVector<dive_site *> ds); void stopFilterDiveSites(); +#endif void setFilter(const FilterData &data); ShownChange update(const QVector<dive *> &dives) const; // Update filter status of given dives and return dives whose status changed ShownChange updateAll() const; // Update filter status of all dives and return dives whose status changed @@ -96,6 +63,5 @@ private: // The filter is now not in dive site mode, even if it should int diveSiteRefCount; }; -#endif // SUBSURFACE_MOBILE #endif diff --git a/mobile-widgets/qmlmanager.cpp b/mobile-widgets/qmlmanager.cpp index 648532d7d..19057fef9 100644 --- a/mobile-widgets/qmlmanager.cpp +++ b/mobile-widgets/qmlmanager.cpp @@ -29,6 +29,7 @@ #include "core/errorhelper.h" #include "core/file.h" #include "core/divefilter.h" +#include "core/filterconstraint.h" #include "core/qthelper.h" #include "core/qt-gui.h" #include "core/git-access.h" @@ -2084,6 +2085,13 @@ void QMLManager::restartDownload(QAndroidJniObject usbDevice) #endif +static filter_constraint make_filter_constraint(filter_constraint_type type, const QString &s) +{ + filter_constraint res(type); + filter_constraint_set_stringlist(res, s); + return res; +} + void QMLManager::setFilter(const QString filterText, int index) { QString f = filterText.trimmed(); @@ -2091,15 +2099,17 @@ void QMLManager::setFilter(const QString filterText, int index) if (!f.isEmpty()) { // This is ugly - the indices of the mode are hardcoded! switch(index) { - default: - case 0: data.mode = FilterData::Mode::FULLTEXT; break; - case 1: data.mode = FilterData::Mode::PEOPLE; break; - case 2: data.mode = FilterData::Mode::TAGS; break; - } - if (data.mode == FilterData::Mode::FULLTEXT) + default: + case 0: data.fullText = f; - else - data.tags = f.split(",", QString::SkipEmptyParts); + break; + case 1: + data.constraints.push_back(make_filter_constraint(FILTER_CONSTRAINT_PEOPLE, f)); + break; + case 2: + data.constraints.push_back(make_filter_constraint(FILTER_CONSTRAINT_TAGS, f)); + break; + } } DiveFilter::instance()->setFilter(data); } |