Filter: move actual filtering loop to core/divefilter.cpp

The DiveFilter class defined the showDive() function to test
whether a dive should be filtered or not. This was used in
DiveTripModel to loop over all dives or all dives affected by
an editing action.

This restricts us in how we do filtering: We can't use indexes
that give us directly the result. To make the filtering more
flexible, move the actual loops that do the filtering to
the DiveFilter class.

The undo-commands likewise called directly the showDive()
function to check whether newly added dives are shown.
Use the new interface here as well.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2020-02-13 23:39:44 +01:00 committed by Dirk Hohndel
parent a45c5faa8c
commit ee553e059d
4 changed files with 63 additions and 45 deletions

View file

@ -68,11 +68,9 @@ dive *DiveListBase::addDive(DiveToAdd &d)
} }
dive *res = d.dive.release(); // Give up ownership of dive dive *res = d.dive.release(); // Give up ownership of dive
// Set the filter flag according to current filter settings // When we add dives, we start in hidden-by-filter status. Once all
bool show = DiveFilter::instance()->showDive(res); // dives have been added, their status will be updated.
res->hidden_by_filter = !show; res->hidden_by_filter = true;
if (show)
++shown_dives;
int idx = dive_table_get_insertion_index(&dive_table, res); int idx = dive_table_get_insertion_index(&dive_table, res);
add_to_dive_table(&dive_table, idx, res); // Return ownership to backend add_to_dive_table(&dive_table, idx, res); // Return ownership to backend
@ -185,19 +183,21 @@ DivesAndSitesToRemove DiveListBase::addDives(DivesAndTripsToAdd &toAdd)
[](const DiveToAdd &d, const DiveToAdd &d2) [](const DiveToAdd &d, const DiveToAdd &d2)
{ return dive_less_than(d.dive.get(), d2.dive.get()); }); { return dive_less_than(d.dive.get(), d2.dive.get()); });
// Remember old number of shown dives
int oldShown = shown_dives;
// Now, add the dives // Now, add the dives
// Note: the idiomatic STL-way would be std::transform, but let's use a loop since // Note: the idiomatic STL-way would be std::transform, but let's use a loop since
// that is closer to classical C-style. // that is closer to classical C-style.
auto it2 = res.rbegin(); auto it2 = res.rbegin();
QVector<dive *> divesToFilter;
divesToFilter.reserve(toAdd.dives.size());
for (auto it = toAdd.dives.rbegin(); it != toAdd.dives.rend(); ++it, ++it2) { for (auto it = toAdd.dives.rbegin(); it != toAdd.dives.rend(); ++it, ++it2) {
*it2 = addDive(*it); *it2 = addDive(*it);
dives.push_back({ (*it2)->divetrip, *it2 }); dives.push_back({ (*it2)->divetrip, *it2 });
divesToFilter.push_back(*it2);
} }
toAdd.dives.clear(); toAdd.dives.clear();
ShownChange change = DiveFilter::instance()->update(divesToFilter);
// If the dives belong to new trips, add these as well. // If the dives belong to new trips, add these as well.
// Remember the pointers so that we can later check if a trip was newly added // Remember the pointers so that we can later check if a trip was newly added
std::vector<dive_trip *> addedTrips; std::vector<dive_trip *> addedTrips;
@ -224,7 +224,7 @@ DivesAndSitesToRemove DiveListBase::addDives(DivesAndTripsToAdd &toAdd)
emit diveListNotifier.divesAdded(trip, createTrip, divesInTrip); emit diveListNotifier.divesAdded(trip, createTrip, divesInTrip);
}); });
if (oldShown != shown_dives) if (!change.newShown.empty() || !change.newHidden.empty())
emit diveListNotifier.numShownChanged(); emit diveListNotifier.numShownChanged();
return { res, sites }; return { res, sites };

View file

@ -8,10 +8,12 @@ DiveFilter::DiveFilter()
{ {
} }
bool DiveFilter::showDive(const struct dive *d) const ShownChange DiveFilter::update(const QVector<dive *> &) const
{
}
ShownChange DiveFilter::updateAll() const
{ {
// TODO: Do something useful
return true;
} }
#else // SUBSURFACE_MOBILE #else // SUBSURFACE_MOBILE
@ -24,6 +26,37 @@ bool DiveFilter::showDive(const struct dive *d) const
#include "core/divesite.h" #include "core/divesite.h"
#include "qt-models/filtermodels.h" #include "qt-models/filtermodels.h"
void DiveFilter::updateDiveStatus(dive *d, ShownChange &change) const
{
bool newStatus = showDive(d);
if (filter_dive(d, newStatus)) {
if (newStatus)
change.newShown.push_back(d);
else
change.newHidden.push_back(d);
}
}
ShownChange DiveFilter::update(const QVector<dive *> &dives) const
{
dive *old_current = current_dive;
ShownChange res;
for (dive *d: dives)
updateDiveStatus(d, res);
res.currentChanged = old_current != current_dive;
return res;
}
ShownChange DiveFilter::updateAll() const
{
dive *old_current = current_dive;
ShownChange res;
for (int i = 0; i < dive_table.nr; ++i)
updateDiveStatus(get_dive(i), res);
res.currentChanged = old_current != current_dive;
return res;
}
namespace { namespace {
// Pointer to function that takes two strings and returns whether // Pointer to function that takes two strings and returns whether
// the first matches the second according to a criterion (substring, starts-with, exact). // the first matches the second according to a criterion (substring, starts-with, exact).

View file

@ -3,6 +3,16 @@
#ifndef DIVE_FILTER_H #ifndef DIVE_FILTER_H
#define DIVE_FILTER_H #define DIVE_FILTER_H
#include <QVector>
struct dive;
// Structure describing changes of shown status upon applying the filter
struct ShownChange {
QVector<dive *> newShown;
QVector<dive *> newHidden;
bool currentChanged;
};
// The dive filter for mobile is currently much simpler than for desktop. // The dive filter for mobile is currently much simpler than for desktop.
// Therefore, for now we have two completely separate implementations. // Therefore, for now we have two completely separate implementations.
// This should be unified in the future. // This should be unified in the future.
@ -12,7 +22,8 @@ class DiveFilter {
public: public:
static DiveFilter *instance(); static DiveFilter *instance();
bool showDive(const struct dive *d) const; 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
private: private:
DiveFilter(); DiveFilter();
}; };
@ -21,9 +32,7 @@ private:
#include <QDateTime> #include <QDateTime>
#include <QStringList> #include <QStringList>
#include <QVector>
struct dive;
struct dive_trip; struct dive_trip;
struct dive_site; struct dive_site;
@ -82,15 +91,18 @@ class DiveFilter {
public: public:
static DiveFilter *instance(); static DiveFilter *instance();
bool showDive(const struct dive *d) const;
bool diveSiteMode() const; // returns true if we're filtering on dive site bool diveSiteMode() const; // returns true if we're filtering on dive site
const QVector<dive_site *> &filteredDiveSites() const; const QVector<dive_site *> &filteredDiveSites() const;
void startFilterDiveSites(QVector<dive_site *> ds); void startFilterDiveSites(QVector<dive_site *> ds);
void setFilterDiveSite(QVector<dive_site *> ds); void setFilterDiveSite(QVector<dive_site *> ds);
void stopFilterDiveSites(); void stopFilterDiveSites();
void setFilter(const FilterData &data); 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
private: private:
DiveFilter(); DiveFilter();
void updateDiveStatus(dive *d, ShownChange &change) const;
bool showDive(const struct dive *d) const; // Should that dive be shown?
QVector<dive_site *> dive_sites; QVector<dive_site *> dive_sites;
FilterData filterData; FilterData filterData;

View file

@ -432,41 +432,18 @@ bool DiveTripModelBase::setData(const QModelIndex &index, const QVariant &value,
return true; return true;
} }
// Structure describing changes of shown status
struct ShownChange {
QVector<dive *> newShown;
QVector<dive *> newHidden;
bool currentChanged;
void filterDive(dive *d, const DiveFilter *filter);
};
void ShownChange::filterDive(dive *d, const DiveFilter *filter)
{
bool newStatus = filter->showDive(d);
if (filter_dive(d, newStatus)) {
if (newStatus)
newShown.push_back(d);
else
newHidden.push_back(d);
}
}
// Update visibility status of dive and return dives whose visibility changed. // Update visibility status of dive and return dives whose visibility changed.
// Attention: the changed dives are removed from the original vector! // Attention: the changed dives are removed from the original vector!
static ShownChange updateShown(QVector<dive *> &dives) static ShownChange updateShown(QVector<dive *> &dives)
{ {
DiveFilter *filter = DiveFilter::instance(); DiveFilter *filter = DiveFilter::instance();
dive *old_current = current_dive; ShownChange res = filter->update(dives);
ShownChange res;
for (dive *d: dives)
res.filterDive(d, filter);
if (!res.newShown.empty() || !res.newHidden.empty()) if (!res.newShown.empty() || !res.newHidden.empty())
emit diveListNotifier.numShownChanged(); emit diveListNotifier.numShownChanged();
for (dive *d: res.newHidden) for (dive *d: res.newHidden)
dives.removeAll(d); dives.removeAll(d);
for (dive *d: res.newShown) for (dive *d: res.newShown)
dives.removeAll(d); dives.removeAll(d);
res.currentChanged = old_current != current_dive;
return res; return res;
} }
@ -474,13 +451,9 @@ static ShownChange updateShown(QVector<dive *> &dives)
static ShownChange updateShownAll() static ShownChange updateShownAll()
{ {
DiveFilter *filter = DiveFilter::instance(); DiveFilter *filter = DiveFilter::instance();
dive *old_current = current_dive; ShownChange res = filter->updateAll();
ShownChange res;
for (int i = 0; i < dive_table.nr; ++i)
res.filterDive(get_dive(i), filter);
if (!res.newShown.empty() || !res.newHidden.empty()) if (!res.newShown.empty() || !res.newHidden.empty())
emit diveListNotifier.numShownChanged(); emit diveListNotifier.numShownChanged();
res.currentChanged = old_current != current_dive;
return res; return res;
} }