summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2020-06-01 23:37:36 +0200
committerGravatar Dirk Hohndel <dirk@hohndel.org>2020-09-29 16:13:03 -0700
commit634e26cbcea064d6ef3d7550dacf54196547bedb (patch)
tree39ac7894854c770396e8719bf67239d4147e9a7f
parent6c443ba8411fb9f019be10e061878f7c9566f560 (diff)
downloadsubsurface-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.cpp142
-rw-r--r--core/divefilter.h44
-rw-r--r--mobile-widgets/qmlmanager.cpp26
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);
}