diff options
Diffstat (limited to 'qt-models')
-rw-r--r-- | qt-models/divetripmodel.cpp | 1 | ||||
-rw-r--r-- | qt-models/filtermodels.cpp | 233 | ||||
-rw-r--r-- | qt-models/filtermodels.h | 65 | ||||
-rw-r--r-- | qt-models/maplocationmodel.cpp | 5 |
4 files changed, 12 insertions, 292 deletions
diff --git a/qt-models/divetripmodel.cpp b/qt-models/divetripmodel.cpp index 5fedd432f..7f9ca9e32 100644 --- a/qt-models/divetripmodel.cpp +++ b/qt-models/divetripmodel.cpp @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 #include "qt-models/divetripmodel.h" #include "qt-models/filtermodels.h" +#include "core/divefilter.h" #include "core/gettextfromc.h" #include "core/metrics.h" #include "core/trip.h" diff --git a/qt-models/filtermodels.cpp b/qt-models/filtermodels.cpp index 9736d3335..b04fce127 100644 --- a/qt-models/filtermodels.cpp +++ b/qt-models/filtermodels.cpp @@ -1,113 +1,26 @@ // SPDX-License-Identifier: GPL-2.0 #include "qt-models/filtermodels.h" -#include "qt-models/models.h" #include "core/display.h" #include "core/qthelper.h" -#include "core/divesite.h" #include "core/trip.h" #include "core/subsurface-string.h" #include "core/subsurface-qt/DiveListNotifier.h" #include "qt-models/divetripmodel.h" #if !defined(SUBSURFACE_MOBILE) -#include "desktop-widgets/divelistview.h" -#include "desktop-widgets/mainwindow.h" -#include "desktop-widgets/mapwidget.h" +#include "core/divefilter.h" #endif #include <QDebug> #include <algorithm> -namespace { - // Check if a string-list contains at least one string containing the second argument. - // Comparison is non case sensitive and removes white space. - bool listContainsSuperstring(const QStringList &list, const QString &s) - { - return std::any_of(list.begin(), list.end(), [&s](const QString &s2) - { return s2.trimmed().contains(s.trimmed(), Qt::CaseInsensitive); } ); - } - - // Check whether either all, any or none of the items of the first list is - // in the second list as a super string. - // The mode is controlled by the second argument - bool check(const QStringList &items, const QStringList &list, FilterData::Mode mode) - { - bool negate = mode == FilterData::Mode::NONE_OF; - bool any_of = mode == FilterData::Mode::ANY_OF; - auto fun = [&list, negate](const QString &item) - { return listContainsSuperstring(list, item) != negate; }; - return any_of ? std::any_of(items.begin(), items.end(), fun) - : std::all_of(items.begin(), items.end(), fun); - } - - bool hasTags(const QStringList &tags, const struct dive *d, FilterData::Mode mode) - { - if (tags.isEmpty()) - return true; - QStringList dive_tags = get_taglist_string(d->tag_list).split(","); - dive_tags.append(gettextFromC::tr(divemode_text_ui[d->dc.divemode])); - return check(tags, dive_tags, mode); - } - - bool hasPersons(const QStringList &people, const struct dive *d, FilterData::Mode mode) - { - 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, mode); - } - - bool hasLocations(const QStringList &locations, const struct dive *d, FilterData::Mode mode) - { - if (locations.isEmpty()) - return true; - QStringList diveLocations; - if (d->divetrip) - diveLocations.push_back(QString(d->divetrip->location)); - - if (d->dive_site) - diveLocations.push_back(QString(d->dive_site->name)); - - return check(locations, diveLocations, mode); - } - - // TODO: Finish this implementation. - bool hasEquipment(const QStringList &, const struct dive *, FilterData::Mode) - { - return true; - } - - bool hasSuits(const QStringList &suits, const struct dive *d, FilterData::Mode mode) - { - if (suits.isEmpty()) - return true; - QStringList diveSuits; - if (d->suit) - diveSuits.push_back(QString(d->suit)); - return check(suits, diveSuits, mode); - } - - bool hasNotes(const QStringList &dnotes, const struct dive *d, FilterData::Mode mode) - { - if (dnotes.isEmpty()) - return true; - QStringList diveNotes; - if (d->notes) - diveNotes.push_back(QString(d->notes)); - return check(dnotes, diveNotes, mode); - } - -} - MultiFilterSortModel *MultiFilterSortModel::instance() { static MultiFilterSortModel self; return &self; } -MultiFilterSortModel::MultiFilterSortModel(QObject *parent) : QSortFilterProxyModel(parent), - diveSiteRefCount(0) +MultiFilterSortModel::MultiFilterSortModel(QObject *parent) : QSortFilterProxyModel(parent) { setFilterKeyColumn(-1); // filter all columns setFilterCaseSensitivity(Qt::CaseInsensitive); @@ -121,73 +34,6 @@ void MultiFilterSortModel::resetModel(DiveTripModelBase::Layout layout) setSourceModel(DiveTripModelBase::instance()); } -bool MultiFilterSortModel::showDive(const struct dive *d) const -{ - if (diveSiteMode()) - return dive_sites.contains(d->dive_site); - - if (!filterData.validFilter) - return true; - - if (d->visibility < filterData.minVisibility || d->visibility > filterData.maxVisibility) - return false; - - if (d->rating < filterData.minRating || d->rating > filterData.maxRating) - return false; - - auto temp_comp = prefs.units.temperature == units::CELSIUS ? C_to_mkelvin : F_to_mkelvin; - if (d->watertemp.mkelvin && - (d->watertemp.mkelvin < (*temp_comp)(filterData.minWaterTemp) || d->watertemp.mkelvin > (*temp_comp)(filterData.maxWaterTemp))) - return false; - - if (d->airtemp.mkelvin && - (d->airtemp.mkelvin < (*temp_comp)(filterData.minAirTemp) || d->airtemp.mkelvin > (*temp_comp)(filterData.maxAirTemp))) - return false; - - QDateTime t = filterData.fromDate; - t.setTime(filterData.fromTime); - if (filterData.fromDate.isValid() && filterData.fromTime.isValid() && - d->when < t.toMSecsSinceEpoch()/1000 + t.offsetFromUtc()) - return false; - - t = filterData.toDate; - t.setTime(filterData.toTime); - if (filterData.toDate.isValid() && filterData.toTime.isValid() && - d->when > t.toMSecsSinceEpoch()/1000 + t.offsetFromUtc()) - return false; - - // tags. - if (!hasTags(filterData.tags, d, filterData.tagsMode)) - return false; - - // people - if (!hasPersons(filterData.people, d, filterData.peopleMode)) - return false; - - // Location - if (!hasLocations(filterData.location, d, filterData.locationMode)) - return false; - - // Suit - if (!hasSuits(filterData.suit, d, filterData.suitMode)) - return false; - - // Notes - if (!hasNotes(filterData.dnotes, d, filterData.dnotesMode)) - return false; - - if (!hasEquipment(filterData.equipment, d, filterData.equipmentMode)) - return false; - - // Planned/Logged - if (!filterData.logged && !has_planned(d, true)) - return false; - if (!filterData.planned && !has_planned(d, false)) - return false; - - return true; -} - bool MultiFilterSortModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { QAbstractItemModel *m = sourceModel(); @@ -213,6 +59,7 @@ void MultiFilterSortModel::myInvalidate() shown_dives = 0; + DiveFilter *filter = DiveFilter::instance(); for (int i = 0; i < m->rowCount(QModelIndex()); ++i) { QModelIndex idx = m->index(i, 0, QModelIndex()); @@ -227,7 +74,7 @@ void MultiFilterSortModel::myInvalidate() qWarning("MultiFilterSortModel::myInvalidate(): subitem not a dive!?"); continue; } - bool show = showDive(d); + bool show = filter->showDive(d); if (show) { shown_dives++; showTrip = true; @@ -237,7 +84,7 @@ void MultiFilterSortModel::myInvalidate() m->setData(idx, showTrip, DiveTripModelBase::SHOWN_ROLE); } else { dive *d = m->data(idx, DiveTripModelBase::DIVE_ROLE).value<dive *>(); - bool show = (d != NULL) && showDive(d); + bool show = (d != NULL) && filter->showDive(d); if (show) shown_dives++; m->setData(idx, show, DiveTripModelBase::SHOWN_ROLE); @@ -251,26 +98,13 @@ void MultiFilterSortModel::myInvalidate() countsChanged(); } -#if !defined(SUBSURFACE_MOBILE) - // The shown maps may have changed -> reload the map widget. - // But don't do this in dive site mode, because then we show all - // dive sites and only change the selected flag. - if (!diveSiteMode()) - MapWidget::instance()->reload(); -#endif - emit filterFinished(); - -#if !defined(SUBSURFACE_MOBILE) - if (diveSiteMode()) - MainWindow::instance()->diveList->expandAll(); -#endif } bool MultiFilterSortModel::updateDive(struct dive *d) { bool oldStatus = !d->hidden_by_filter; - bool newStatus = showDive(d); + bool newStatus = DiveFilter::instance()->showDive(d); bool changed = oldStatus != newStatus; if (changed) { filter_dive(d, newStatus); @@ -279,67 +113,12 @@ bool MultiFilterSortModel::updateDive(struct dive *d) return changed; } -void MultiFilterSortModel::startFilterDiveSites(QVector<dive_site *> ds) -{ - if (++diveSiteRefCount > 1) { - setFilterDiveSite(ds); - } else { - std::sort(ds.begin(), ds.end()); - dive_sites = ds; -#if !defined(SUBSURFACE_MOBILE) - // When switching into dive site mode, reload the dive sites. - // We won't do this in myInvalidate() once we are in dive site mode. - MapWidget::instance()->reload(); -#endif - myInvalidate(); - } -} - -void MultiFilterSortModel::stopFilterDiveSites() -{ - if (--diveSiteRefCount > 0) - return; - dive_sites.clear(); - myInvalidate(); -} - -void MultiFilterSortModel::setFilterDiveSite(QVector<dive_site *> ds) -{ - // If the filter didn't change, return early to avoid a full - // map reload. For a well-defined comparison, sort the vector first. - std::sort(ds.begin(), ds.end()); - if (ds == dive_sites) - return; - dive_sites = ds; - -#if !defined(SUBSURFACE_MOBILE) - MapWidget::instance()->setSelected(dive_sites); -#endif - myInvalidate(); -} - -const QVector<dive_site *> &MultiFilterSortModel::filteredDiveSites() const -{ - return dive_sites; -} - -bool MultiFilterSortModel::diveSiteMode() const -{ - return diveSiteRefCount > 0; -} - bool MultiFilterSortModel::lessThan(const QModelIndex &i1, const QModelIndex &i2) const { // Hand sorting down to the source model. return DiveTripModelBase::instance()->lessThan(i1, i2); } -void MultiFilterSortModel::filterDataChanged(const FilterData &data) -{ - filterData = data; - myInvalidate(); -} - void MultiFilterSortModel::countsChanged() { updateWindowTitle(); diff --git a/qt-models/filtermodels.h b/qt-models/filtermodels.h index d4a03d134..d279470b1 100644 --- a/qt-models/filtermodels.h +++ b/qt-models/filtermodels.h @@ -11,67 +11,16 @@ #include <stdint.h> #include <vector> -struct dive; -struct dive_trip; - -struct FilterData { - // The mode ids are chosen such that they can be directly converted from / to combobox indices. - enum class Mode { - ALL_OF = 0, - ANY_OF = 1, - NONE_OF = 2 - }; - - bool validFilter = false; - int minVisibility = 0; - int maxVisibility = 5; - int minRating = 0; - int maxRating = 5; - // The default minimum and maximum temperatures are set such that all - // physically reasonable dives are shown. Note that these values should - // work for both Celcius and Fahrenheit scales. - double minWaterTemp = -10; - double maxWaterTemp = 200; - double minAirTemp = -50; - double maxAirTemp = 200; - QDateTime fromDate = QDateTime(QDate(1980,1,1)); - QTime fromTime = QTime(0,0); - QDateTime toDate = QDateTime::currentDateTime(); - QTime toTime = QTime::currentTime(); - QStringList tags; - QStringList people; - QStringList location; - QStringList suit; - QStringList dnotes; - QStringList equipment; - Mode tagsMode = Mode::ALL_OF; - Mode peopleMode = Mode::ALL_OF; - Mode locationMode = Mode::ANY_OF; - Mode dnotesMode = Mode::ALL_OF; - Mode suitMode = Mode::ANY_OF; - Mode equipmentMode = Mode::ALL_OF; - bool logged = true; - bool planned = true; -}; - class MultiFilterSortModel : public QSortFilterProxyModel { Q_OBJECT public: static MultiFilterSortModel *instance(); bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; - bool showDive(const struct dive *d) const; bool updateDive(struct dive *d); // returns true if visibility status changed bool lessThan(const QModelIndex &, const QModelIndex &) const override; - bool diveSiteMode() const; // returns true if we're filtering on dive site - const QVector<dive_site *> &filteredDiveSites() const; -public -slots: - void myInvalidate(); - void startFilterDiveSites(QVector<dive_site *> ds); - void setFilterDiveSite(QVector<dive_site *> ds); - void stopFilterDiveSites(); + void resetModel(DiveTripModelBase::Layout layout); - void filterDataChanged(const FilterData &data); + void myInvalidate(); signals: void filterFinished(); @@ -79,17 +28,7 @@ signals: private: MultiFilterSortModel(QObject *parent = 0); // Dive site filtering has priority over other filters - QVector<dive_site *> dive_sites; void countsChanged(); - FilterData filterData; - - // We use ref-counting for the dive site mode. The reason is that when switching - // between two tabs that both need dive site mode, the following course of - // events may happen: - // 1) The new tab appears -> enter dive site mode. - // 2) The old tab gets its hide() signal -> exit dive site mode. - // The filter is now not in dive site mode, even if it should - int diveSiteRefCount; }; #endif diff --git a/qt-models/maplocationmodel.cpp b/qt-models/maplocationmodel.cpp index 9b21f7142..c123b19c5 100644 --- a/qt-models/maplocationmodel.cpp +++ b/qt-models/maplocationmodel.cpp @@ -2,6 +2,7 @@ #include "maplocationmodel.h" #include "divelocationmodel.h" #include "core/divesite.h" +#include "core/divefilter.h" #ifndef SUBSURFACE_MOBILE #include "qt-models/filtermodels.h" #include "desktop-widgets/mapwidget.h" @@ -133,9 +134,9 @@ void MapLocationModel::reload(QObject *map) // the dive site tab), we want to show all dive sites, not only those // of the non-hidden dives. Moreover, the selected dive sites are those // that we filter for. - bool diveSiteMode = MultiFilterSortModel::instance()->diveSiteMode(); + bool diveSiteMode = DiveFilter::instance()->diveSiteMode(); if (diveSiteMode) - m_selectedDs = MultiFilterSortModel::instance()->filteredDiveSites(); + m_selectedDs = DiveFilter::instance()->filteredDiveSites(); #endif for (int i = 0; i < dive_site_table.nr; ++i) { struct dive_site *ds = dive_site_table.dive_sites[i]; |