summaryrefslogtreecommitdiffstats
path: root/qt-models/divetripmodel.cpp
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2019-11-17 19:53:18 +0100
committerGravatar Dirk Hohndel <dirk@hohndel.org>2019-11-19 21:13:40 -0800
commit3003c6e1eed330978193d6859eca2f79ee68aa54 (patch)
tree1baeb54aeca0eda10d273779cf3704095a170d2e /qt-models/divetripmodel.cpp
parent9ffafbc326b38bd2d0bb870fa4721b6c94280c28 (diff)
downloadsubsurface-3003c6e1eed330978193d6859eca2f79ee68aa54.tar.gz
Filter: move recalculation of filter from FilterModel to TripModel
The way this was accessed via Qt's model semantics was horrible. This gives arguably more readable code, since we don't have to shoehorn things through QVariants. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'qt-models/divetripmodel.cpp')
-rw-r--r--qt-models/divetripmodel.cpp126
1 files changed, 69 insertions, 57 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.