aboutsummaryrefslogtreecommitdiffstats
path: root/qt-models/filtermodels.cpp
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2019-06-22 20:48:59 +0200
committerGravatar bstoeger <32835590+bstoeger@users.noreply.github.com>2019-06-23 20:08:46 +0200
commitcbcddaa396f6668fef7750eb2721bc70ca11d0e4 (patch)
tree5d0d7abcafbf99c31f4b24a20c94ce1ca4c7e87e /qt-models/filtermodels.cpp
parent4b0f90ced33569d50913eb9826a8d96fbc4d9f3a (diff)
downloadsubsurface-cbcddaa396f6668fef7750eb2721bc70ca11d0e4.tar.gz
Dive list: cache shown flag in model (quick-fix for undo-crash)
We have a very fundamental problem with data-duplication in core and qt-models. In a particular case, this led to an easily reproducible crash: 1) An undo command moved the last dive of a trip to another. 2) When an undo-command removed the last dive of a trip to a different trip, the dive was removed from the trip in the core. Then, the model was updated. 3) That lead at first to a rearrangement of the trips, because the trip with the added dive is moved before the trip with the removed dive. 4) In such a case, the filter-model checks the visibility of the trip. 5) Since the trip with the removed dive has no dives in the core, visibility was determined as false. 6) From this point on the mappings of the QSortFilterProxyModel were messed up. Accesses led to crashes. It is unclear whether this is a Qt bug or only a QOI issue. As a quick-fix, cache the visibility flag of trips directly in the Qt-models. Don't set the visibility directly in the core, but go via the Qt-models. Thus, a more clear layering is achieved. In the long run, we can hopefully get rid of the data-duplication in the models. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'qt-models/filtermodels.cpp')
-rw-r--r--qt-models/filtermodels.cpp63
1 files changed, 36 insertions, 27 deletions
diff --git a/qt-models/filtermodels.cpp b/qt-models/filtermodels.cpp
index 8e7239e35..9ef910def 100644
--- a/qt-models/filtermodels.cpp
+++ b/qt-models/filtermodels.cpp
@@ -194,25 +194,9 @@ bool MultiFilterSortModel::showDive(const struct dive *d) const
bool MultiFilterSortModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
- QModelIndex index0 = sourceModel()->index(source_row, 0, source_parent);
- struct dive *d = sourceModel()->data(index0, DiveTripModelBase::DIVE_ROLE).value<struct dive *>();
-
- // For dives, simply check the hidden_by_filter flag
- if (d)
- return !d->hidden_by_filter;
-
- // Since this is not a dive, it must be a trip
- dive_trip *trip = sourceModel()->data(index0, DiveTripModelBase::TRIP_ROLE).value<dive_trip *>();
-
- if (!trip)
- return false; // Oops. Neither dive nor trip, something is seriously wrong.
-
- // Show the trip if any dive is visible
- for (int i = 0; i < trip->dives.nr; ++i) {
- if (!trip->dives.dives[i]->hidden_by_filter)
- return true;
- }
- return false;
+ QAbstractItemModel *m = sourceModel();
+ QModelIndex index0 = m->index(source_row, 0, source_parent);
+ return m->data(index0, DiveTripModelBase::SHOWN_ROLE).value<bool>();
}
void MultiFilterSortModel::filterChanged(const QModelIndex &from, const QModelIndex &to, const QVector<int> &roles)
@@ -225,8 +209,9 @@ void MultiFilterSortModel::filterChanged(const QModelIndex &from, const QModelIn
void MultiFilterSortModel::myInvalidate()
{
- int i;
- struct dive *d;
+ QAbstractItemModel *m = sourceModel();
+ if (!m)
+ return;
{
// This marker prevents the UI from getting notifications on selection changes.
@@ -240,12 +225,36 @@ void MultiFilterSortModel::myInvalidate()
divesDisplayed = 0;
- // Apply filter for each dive
- for_each_dive (i, d) {
- bool show = showDive(d);
- filter_dive(d, show);
- if (show)
- divesDisplayed++;
+ for (int i = 0; i < m->rowCount(QModelIndex()); ++i) {
+ QModelIndex idx = m->index(i, 0, QModelIndex());
+
+ dive_trip *trip = m->data(idx, DiveTripModelBase::TRIP_ROLE).value<dive_trip *>();
+ if (trip) {
+ // 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 = showDive(d);
+ if (show) {
+ divesDisplayed++;
+ 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 = showDive(d);
+ if (show)
+ divesDisplayed++;
+ m->setData(idx, show, DiveTripModelBase::SHOWN_ROLE);
+ }
}
invalidateFilter();