summaryrefslogtreecommitdiffstats
path: root/desktop-widgets/divelistview.cpp
diff options
context:
space:
mode:
authorGravatar Berthold Stoeger <bstoeger@mail.tuwien.ac.at>2018-08-01 19:23:43 +0200
committerGravatar Dirk Hohndel <dirk@hohndel.org>2018-10-11 16:22:27 -0700
commit23db0ba68df5f785a8a2db5ff5b76bbbee31d69f (patch)
tree41204dd19c78c7ecf75493be3b121f3773c0d438 /desktop-widgets/divelistview.cpp
parent0d98da52610161ecbafd50afacbff20996756264 (diff)
downloadsubsurface-23db0ba68df5f785a8a2db5ff5b76bbbee31d69f.tar.gz
Dive list view: replace signal-magic by flag
In DiveListView, we have a very fundamental problem: When On the one hand, we get informed of user-selection in the DiveListView::selectionChanged() slot. This has to set the correct flags in the C-backend. On the other hand, sometimes we have to set the selection programatically, e.g. when selecting a trip. This is done by calling QItemSelectionModel::select(). But: this will *also* call into the above slot, in which we can't tell whether it was a user interaction or an internal call. This can lead to either infinite loops or very inefficient behavior, because the current dive is set numerous times. The current code is aware of that and disconnects the corresponding signal. This is scary, as these signals are set internally by the model and view. Replace this by a global "command executing" flag in DiveListNotifier. The flag is set using a "marker" class, which resets the flag once it goes out of scope (cf. RAII pattern). In DiveListView, only process a selection if the flag is not set. Otherwise simply call the QTreeView base class, to reflect the new selection in the UI. To have a common point for notifications of selection changes, add such a signal to DiveListNotifier. This signal will be used by the DiveListView as well as the Command-objects. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Diffstat (limited to 'desktop-widgets/divelistview.cpp')
-rw-r--r--desktop-widgets/divelistview.cpp38
1 files changed, 23 insertions, 15 deletions
diff --git a/desktop-widgets/divelistview.cpp b/desktop-widgets/divelistview.cpp
index ebeb1f6ef..2a0d7028c 100644
--- a/desktop-widgets/divelistview.cpp
+++ b/desktop-widgets/divelistview.cpp
@@ -24,6 +24,7 @@
#include "desktop-widgets/divelistview.h"
#include "qt-models/divepicturemodel.h"
#include "core/metrics.h"
+#include "core/subsurface-qt/DiveListNotifier.h"
DiveListView::DiveListView(QWidget *parent) : QTreeView(parent), mouseClickSelection(false), sortColumn(0),
currentOrder(Qt::DescendingOrder), dontEmitDiveChangedSignal(false), selectionSaved(false),
@@ -267,19 +268,17 @@ void DiveListView::selectTrip(dive_trip_t *trip)
// works as expected
void DiveListView::clearTripSelection()
{
- // we want to make sure no trips are selected
- disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(selectionChanged(QItemSelection, QItemSelection)));
- disconnect(selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(currentChanged(QModelIndex, QModelIndex)));
+ // This marks the selection change as being internal - ie. we don't process it further.
+ // TODO: This should probably be sold differently.
+ auto marker = diveListNotifier.enterCommand();
+ // we want to make sure no trips are selected
Q_FOREACH (const QModelIndex &index, selectionModel()->selectedRows()) {
dive_trip_t *trip = static_cast<dive_trip_t *>(index.data(DiveTripModel::TRIP_ROLE).value<void *>());
if (!trip)
continue;
selectionModel()->select(index, QItemSelectionModel::Deselect);
}
-
- connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(selectionChanged(QItemSelection, QItemSelection)));
- connect(selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(currentChanged(QModelIndex, QModelIndex)));
}
void DiveListView::unselectDives()
@@ -374,7 +373,7 @@ void DiveListView::selectDives(const QList<int> &newDiveSelection)
scrollTo(idx);
}
// now that everything is up to date, update the widgets
- emit currentDiveChanged();
+ emit diveListNotifier.selectionChanged();
dontEmitDiveChangedSignal = false;
return;
}
@@ -545,11 +544,20 @@ void DiveListView::currentChanged(const QModelIndex &current, const QModelIndex&
void DiveListView::selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)
{
- QItemSelection newSelected = selected.size() ? selected : selectionModel()->selection();
- QItemSelection newDeselected = deselected;
+ if (diveListNotifier.inCommand()) {
+ // This is a programmatical change of the selection.
+ // Call the QTreeView base function to reflect the selection in the display,
+ // but don't process it any further.
+ QTreeView::selectionChanged(selected, deselected);
+ return;
+ }
- disconnect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(selectionChanged(QItemSelection, QItemSelection)));
- disconnect(selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(currentChanged(QModelIndex, QModelIndex)));
+ // This is a manual selection change. This means that the core does not yet know
+ // of the new selection. Update the core-structures accordingly and select/deselect
+ // all dives of a trip if a trip is selected/deselected.
+ const QItemSelection &newDeselected = deselected;
+
+ QItemSelection newSelected = selected.size() ? selected : selectionModel()->selection();
Q_FOREACH (const QModelIndex &index, newDeselected.indexes()) {
if (index.column() != 0)
@@ -581,11 +589,11 @@ void DiveListView::selectionChanged(const QItemSelection &selected, const QItemS
select_dive(get_divenr(dive));
}
}
- QTreeView::selectionChanged(selectionModel()->selection(), newDeselected);
- connect(selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(selectionChanged(QItemSelection, QItemSelection)));
- connect(selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(currentChanged(QModelIndex, QModelIndex)));
if (!dontEmitDiveChangedSignal)
- emit currentDiveChanged();
+ emit diveListNotifier.selectionChanged();
+
+ // Display the new, processed, selection
+ QTreeView::selectionChanged(selectionModel()->selection(), newDeselected);
}
enum asked_user {NOTYET, MERGE, DONTMERGE};