diff options
Diffstat (limited to 'qt-models')
-rw-r--r-- | qt-models/divetripmodel.cpp | 126 | ||||
-rw-r--r-- | qt-models/divetripmodel.h | 9 | ||||
-rw-r--r-- | qt-models/filtermodels.cpp | 73 | ||||
-rw-r--r-- | qt-models/filtermodels.h | 13 |
4 files changed, 73 insertions, 148 deletions
diff --git a/qt-models/divetripmodel.cpp b/qt-models/divetripmodel.cpp index 7ee09d2a7..2a83b61da 100644 --- a/qt-models/divetripmodel.cpp +++ b/qt-models/divetripmodel.cpp @@ -1,6 +1,5 @@ // 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" @@ -400,9 +399,6 @@ Qt::ItemFlags DiveTripModelBase::flags(const QModelIndex &index) const bool DiveTripModelBase::setData(const QModelIndex &index, const QVariant &value, int role) { - if (role == SHOWN_ROLE) - return setShown(index, value.value<bool>()); - // We only support setting of data for dives and there, only the number. dive *d = diveOrNull(index); if (!d) @@ -688,34 +684,49 @@ dive *DiveTripModelTree::diveOrNull(const QModelIndex &index) const return tripOrDive(index).dive; } -// Set the shown flag that marks whether an entry is shown or hidden by the filter. -// The flag is cached for top-level items (trips and dives outside of trips). -// For dives that belong to a trip (i.e. non-top-level items), the flag is -// simply written through to the core. -bool DiveTripModelTree::setShown(const QModelIndex &idx, bool shown) -{ - if (!idx.isValid()) - return false; - - QModelIndex parent = idx.parent(); - if (!parent.isValid()) { - // An invalid parent means that we're at the top-level - Item &item = items[idx.row()]; - item.shown = shown; // Cache the flag. - if (item.d_or_t.dive) { - // This is a dive -> also register the flag in the core - filter_dive(item.d_or_t.dive, shown); +void DiveTripModelTree::recalculateFilter() +{ + { + // This marker prevents the UI from getting notifications on selection changes. + // It is active until the end of the scope. + // This was actually designed for the undo-commands, so that they can do their work + // without having the UI updated. + // Here, it is used because invalidating the filter can generate numerous + // selection changes, which do full ui reloads. Instead, do that all at once + // as a consequence of the filterReset signal right after the local scope. + auto marker = diveListNotifier.enterCommand(); + DiveFilter *filter = DiveFilter::instance(); + for (Item &item: items) { + if (item.d_or_t.dive) { + dive *d = item.d_or_t.dive; + item.shown = filter->showDive(item.d_or_t.dive); + filter_dive(d, item.shown); + } else { + // Trips are shown if any of the dives is shown + bool showTrip = false; + for (dive *d: item.dives) { + bool shown = filter->showDive(d); + filter_dive(d, shown); + showTrip |= shown; + } + item.shown = showTrip; + } } - } else { - // We're not at the top-level. This must be a dive, therefore - // simply write the flag through to the core. - const Item &parentItem = items[parent.row()]; - filter_dive(parentItem.dives[idx.row()], shown); } - return true; + + // Rerender all trip headers. TODO: be smarter about this and only rerender if the number + // of shown dives changed. + for (int idx = 0; idx < (int)items.size(); ++idx) { + QModelIndex tripIndex = createIndex(idx, 0, noParent); + dataChanged(tripIndex, tripIndex); + } + + emit diveListNotifier.numShownChanged(); + emit diveListNotifier.filterReset(); } + QVariant DiveTripModelTree::data(const QModelIndex &index, int role) const { if (role == SHOWN_ROLE) { @@ -980,13 +991,23 @@ void DiveTripModelTree::divesChanged(const QVector<dive *> &dives) { divesChangedTrip(trip, divesInTrip); }); } +// Update visibility status of dive and return true if visibility changed +static bool updateShown(const QVector<dive *> &dives) +{ + bool changed = false; + DiveFilter *filter = DiveFilter::instance(); + for (dive *d: dives) { + bool newStatus = filter->showDive(d); + changed |= filter_dive(d, newStatus); + } + if (changed) + emit diveListNotifier.numShownChanged(); + return changed; +} + void DiveTripModelTree::divesChangedTrip(dive_trip *trip, const QVector<dive *> &dives) { - // Update filter flags. TODO: The filter should update the flag by itself when - // recieving the signals below. - bool diveChanged = false; - for (dive *d: dives) - diveChanged |= MultiFilterSortModel::instance()->updateDive(d); + bool diveChanged = updateShown(dives); if (!trip) { // This is outside of a trip. Process top-level items range-wise. @@ -1182,16 +1203,6 @@ void DiveTripModelTree::divesSelectedTrip(dive_trip *trip, const QVector<dive *> } } -void DiveTripModelTree::filterFinished() -{ - // If the filter finished, update all trip items to show the correct number of displayed dives - // in each trip. Without doing this, only trip headers of expanded trips were updated. - for (int idx = 0; idx < (int)items.size(); ++idx) { - QModelIndex tripIndex = createIndex(idx, 0, noParent); - dataChanged(tripIndex, tripIndex); - } -} - bool DiveTripModelTree::lessThan(const QModelIndex &i1, const QModelIndex &i2) const { // In tree mode we don't support any sorting! @@ -1248,13 +1259,22 @@ dive *DiveTripModelList::diveOrNull(const QModelIndex &index) const return items[row]; } -bool DiveTripModelList::setShown(const QModelIndex &idx, bool shown) +void DiveTripModelList::recalculateFilter() { - dive *d = diveOrNull(idx); - if (!d) - return false; - filter_dive(d, shown); - return true; + { + // This marker prevents the UI from getting notifications on selection changes. + // It is active until the end of the scope. See comment in DiveTripModelTree::recalculateFilter(). + auto marker = diveListNotifier.enterCommand(); + DiveFilter *filter = DiveFilter::instance(); + + for (dive *d: items) { + bool shown = filter->showDive(d); + filter_dive(d, shown); + } + } + + emit diveListNotifier.numShownChanged(); + emit diveListNotifier.filterReset(); } QVariant DiveTripModelList::data(const QModelIndex &index, int role) const @@ -1308,10 +1328,7 @@ void DiveTripModelList::divesChanged(const QVector<dive *> &divesIn) QVector<dive *> dives = divesIn; std::sort(dives.begin(), dives.end(), dive_less_than); - // Update filter flags. TODO: The filter should update the flag by itself when - // recieving the signals below. - for (dive *d: dives) - MultiFilterSortModel::instance()->updateDive(d); + updateShown(dives); // Since we know that the dive list is sorted, we will only ever search for the first element // in dives as this must be the first that we encounter. Once we find a range, increase the @@ -1372,11 +1389,6 @@ void DiveTripModelList::divesSelected(const QVector<dive *> &dives, dive *curren emit newCurrentDive(createIndex(it - items.begin(), 0)); } -void DiveTripModelList::filterFinished() -{ - // In list mode, we don't have to change anything after filter finished. -} - // Simple sorting helper for sorting against a criterium and if // that is undefined against a different criterium. // Return true if diff1 < 0, false if diff1 > 0. diff --git a/qt-models/divetripmodel.h b/qt-models/divetripmodel.h index 6b3f26fd7..94278229d 100644 --- a/qt-models/divetripmodel.h +++ b/qt-models/divetripmodel.h @@ -78,8 +78,7 @@ public: bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; DiveTripModelBase(QObject *parent = 0); int columnCount(const QModelIndex&) const; - virtual void filterFinished() = 0; - virtual bool setShown(const QModelIndex &idx, bool shown) = 0; + virtual void recalculateFilter() = 0; // Used for sorting. This is a bit of a layering violation, as sorting should be performed // by the higher-up QSortFilterProxyModel, but it makes things so much easier! @@ -123,11 +122,10 @@ private: QModelIndex index(int row, int column, const QModelIndex &parent) const override; QModelIndex parent(const QModelIndex &index) const override; QVariant data(const QModelIndex &index, int role) const override; - void filterFinished() override; bool lessThan(const QModelIndex &i1, const QModelIndex &i2) const override; void divesSelectedTrip(dive_trip *trip, const QVector<dive *> &dives, QVector<QModelIndex> &); dive *diveOrNull(const QModelIndex &index) const override; - bool setShown(const QModelIndex &idx, bool shown); + void recalculateFilter(); void divesChangedTrip(dive_trip *trip, const QVector<dive *> &dives); void divesTimeChangedTrip(dive_trip *trip, timestamp_t delta, const QVector<dive *> &dives); @@ -189,10 +187,9 @@ private: QModelIndex index(int row, int column, const QModelIndex &parent) const override; QModelIndex parent(const QModelIndex &index) const override; QVariant data(const QModelIndex &index, int role) const override; - void filterFinished() override; bool lessThan(const QModelIndex &i1, const QModelIndex &i2) const override; dive *diveOrNull(const QModelIndex &index) const override; - bool setShown(const QModelIndex &idx, bool shown); + void recalculateFilter(); std::vector<dive *> items; // TODO: access core data directly }; diff --git a/qt-models/filtermodels.cpp b/qt-models/filtermodels.cpp index 53b9e2e45..9c1e9d3b5 100644 --- a/qt-models/filtermodels.cpp +++ b/qt-models/filtermodels.cpp @@ -7,13 +7,6 @@ #include "core/subsurface-qt/DiveListNotifier.h" #include "qt-models/divetripmodel.h" -#if !defined(SUBSURFACE_MOBILE) -#include "core/divefilter.h" -#endif - -#include <QDebug> -#include <algorithm> - MultiFilterSortModel *MultiFilterSortModel::instance() { static MultiFilterSortModel self; @@ -22,6 +15,7 @@ MultiFilterSortModel *MultiFilterSortModel::instance() MultiFilterSortModel::MultiFilterSortModel(QObject *parent) : QSortFilterProxyModel(parent) { + connect(&diveListNotifier, &DiveListNotifier::filterReset, this, &MultiFilterSortModel::invalidateFilter); setFilterKeyColumn(-1); // filter all columns setFilterCaseSensitivity(Qt::CaseInsensitive); } @@ -41,73 +35,8 @@ bool MultiFilterSortModel::filterAcceptsRow(int source_row, const QModelIndex &s return m->data(index0, DiveTripModelBase::SHOWN_ROLE).value<bool>(); } -void MultiFilterSortModel::myInvalidate() -{ - QAbstractItemModel *m = sourceModel(); - if (!m) - return; - - { - // This marker prevents the UI from getting notifications on selection changes. - // It is active until the end of the scope. - // This is actually meant for the undo-commands, so that they can do their work - // without having the UI updated. - // Here, it is used because invalidating the filter can generate numerous - // selection changes, which do full ui reloads. Instead, do that all at once - // as a consequence of the filterFinished signal right after the local scope. - auto marker = diveListNotifier.enterCommand(); - - DiveFilter *filter = DiveFilter::instance(); - for (int i = 0; i < m->rowCount(QModelIndex()); ++i) { - QModelIndex idx = m->index(i, 0, QModelIndex()); - - if (m->data(idx, DiveTripModelBase::IS_TRIP_ROLE).toBool()) { - // This is a trip -> loop over all dives and see if any is selected - - bool showTrip = false; - for (int j = 0; j < m->rowCount(idx); ++j) { - QModelIndex idx2 = m->index(j, 0, idx); - dive *d = m->data(idx2, DiveTripModelBase::DIVE_ROLE).value<dive *>(); - if (!d) { - qWarning("MultiFilterSortModel::myInvalidate(): subitem not a dive!?"); - continue; - } - bool show = filter->showDive(d); - if (show) - showTrip = true; - m->setData(idx2, show, DiveTripModelBase::SHOWN_ROLE); - } - m->setData(idx, showTrip, DiveTripModelBase::SHOWN_ROLE); - } else { - dive *d = m->data(idx, DiveTripModelBase::DIVE_ROLE).value<dive *>(); - bool show = (d != NULL) && filter->showDive(d); - m->setData(idx, show, DiveTripModelBase::SHOWN_ROLE); - } - } - - invalidateFilter(); - - // Tell the dive trip model to update the displayed-counts - DiveTripModelBase::instance()->filterFinished(); - countsChanged(); - } - - emit filterFinished(); -} - -bool MultiFilterSortModel::updateDive(struct dive *d) -{ - bool newStatus = DiveFilter::instance()->showDive(d); - return filter_dive(d, newStatus); -} - 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::countsChanged() -{ - updateWindowTitle(); -} diff --git a/qt-models/filtermodels.h b/qt-models/filtermodels.h index d279470b1..2dcce0fc0 100644 --- a/qt-models/filtermodels.h +++ b/qt-models/filtermodels.h @@ -4,31 +4,18 @@ #include "divetripmodel.h" -#include <QStringListModel> #include <QSortFilterProxyModel> -#include <QDateTime> - -#include <stdint.h> -#include <vector> class MultiFilterSortModel : public QSortFilterProxyModel { Q_OBJECT public: static MultiFilterSortModel *instance(); bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override; - bool updateDive(struct dive *d); // returns true if visibility status changed bool lessThan(const QModelIndex &, const QModelIndex &) const override; void resetModel(DiveTripModelBase::Layout layout); - void myInvalidate(); - -signals: - void filterFinished(); - private: MultiFilterSortModel(QObject *parent = 0); - // Dive site filtering has priority over other filters - void countsChanged(); }; #endif |