The idea is that this struct will have all the needed data
that will be passed to the filter model. Everything that happens
on the filterwidget will fill out this struct, then forward it
to the model, that in turn will activate the filter hiding
some of the dives that matches on your divelist.
Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
The dive list was sorted using the default-sorter of
QSortFilterProxy model. This is mighty inflexible as it
considers only one column. This has the funky effect that
for rows with identical elements, the sort order depends
on the previous sorting.
Implement a lessThan() function in the MultiFilterSortModel,
which simply hands the sorting down to the actual model.
This might be considered a layering violation, but it makes
things so much easier.
Sadly, it seems like the column-to-be-sorted is transported
in the provided indices. Therefore, the comparison is chosen
using a switch for *every* comparison. It would seem much
more logical to set a function pointer once and use that.
Further investigations are necessary.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The data-flow from C-core to list-view is as follows:
C-core --> DiveTripModel --> MultiSortFilterModel --> DiveListView
The control-flow, on the other hand, differs as DiveListView
accesses both MultiSortFilterModel and DiveTripModel, whereas
MultiSortFilterModel is mostly unaware of its source model.
This is in principle legitimate, as the MultiSortFilterModel might
be used for different sources. In our particular case, this is
not so. MultiSortFilterModel is written for a particular use case.
Therefore, model control-flow follow after data-flow: Let MultiSortFilterModel
set its own source model and DiveListView access the MultiSortFilterModel,
which then manages its source model.
This is not bike-shedding, but will enable a more flexible and
higher-performance sorting.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This is another case of a weird pattern where an object would
connect it's own signal to the slot of a different object.
There seems to be no reason why the former couldn't simply
call the latter.
Remove the [start|stop]FilterDiveSite signals of LocationInformationWidget
and call the corresponding functions of MultiFilterSortModel directly.
While doing so, replace the UUID argument by a pointer-to-divesite.
It will be converted anyway right at the beginning of the function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently, the filter is recalculated if a filter-entry is changed.
This also happens if the counts of a filter-entry changes. This
is to be avoided, as it causes unnecessary churn.
Therefore, send the proper role with the dataChanged() signal
and add a new slot, which invalidates only if a field with the
Qt::CheckStateRole is changed.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of reloading all the filter, only increment / decrement the
count of the entries of added / removed dives.
Originally, this was planned to be done via the signals from the
divelist, but it turned out that this was suboptimal, because
if the filter decides that the new item is selected, this has to
be done *before* adding the dive. Otherwise, it wouldn't be shown.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This reverts commit 1c4a859c8d,
where the override modifiers were removed owing to the noisy
"inconsistent override modifiers" which is default-on in clang.
This warning was disabled in 77577f717f,
so we can reinstate the overrides.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
All callers of FilterModelBase::updateList() sorted the items
(except the last one). Thus we can do the sorting inside the
function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Since FilterModelBase now contains complex data (counts and checked),
we might just as well make it a full model and keep track of
the name as well. I.e. do not derive from QStringListModel but from
QAbstractListModel and add the name to the item structure.
Implement proper reset / add / rename semantics. This is overkill at the
moment, as after all any modification the model will be reset, but
ultimately it will allow us to be smarter and only update rows when
needed.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently, in FilterModelBase::data() the number of dives is recalculated.
This happens for every mouse-over event!
Calculate the number of dives only on recalculation and store the count
in the items-struct.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In the future, we might be smarter about the dive-counts and calculate
them only once and incrementally (if e.g. new dives are added).
Prepare for more complex caching by turning the checked boolean into
a struct, which can then be extended by a count and other things
(e.g. the name).
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The filter code was an unholy intermixture of backend and frontend
logic, which made it hard to access it from outside of the UI.
Notably, it expected that Qt would call filterAcceptsRow on all rows.
For trip-view, apparently the filter functions were called twice
(once for filtering the trip, then for filtering the individual dives).
Make the filtering explicit, by calling showDive() for all dives in
MultiFilterSortModel::myInvalidate(), setting the hidden_by_filter
flags accordingly and ultimately invalidating the filter.
The UI code only accesses the hidden_by_filter flag set previously.
The "justCleared" flag can then be removed, since accessing the filter
does not have side effects. Moreover, there is no noticeable performance
gain by returning out early.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
To make dive-filtering accessible from other parts of the code,
break out the actual dive-filtering code into a function that
takes a pointer-to-dive instead of QModelIndex.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Conceptually, the doFilter() functions shouldn't modify the dive
they test. Therefore, make the argument const. To do this, constify
the parameter of get_dive_location(), which likewise seems to be
the right thing to do.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Change the signature from of the virtual doFilter() functions from
bool doFilter(struct dive *d, QModelIndex&, QAbstractItemModel*) const;
to
bool LocationFilterModel::doFilter(struct dive *d) const;
as the QModelIndex and QAbstractItemModel parameters were not used.
This makes this functions independent from Qt's model/view
framework. This is in preparation for making the undo-machinery
compatible with the filtering.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Commit df156a56c0 replaced "virtual"
by "override" where appropriate. Unfortunately, this had the
unintended consequence of producing numerous clang warnings. If
clang finds a override-modified function in a class definition,
it warns for *all* overriden virtual functions without the override
modifier.
To solve this, go the easy route and remove all overrides. At least
it is consistent.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The keyword "virtual" signalizes that the function is virtual,
i.e. the function of the derived class is called, even if the
call is on the parent class.
It is not necessary to repeat the "virtual" keyword in derived
classes. To highlight derived virtual functions, the keyword
"override" should be used instead. It results in a hard compile-
error, if no function is overridden, thus avoiding subtle bugs.
Replace "virtual" by "override" where appropriate. Moreover,
replace Q_DECL_OVERRIDE by override, since we require reasonably
recent compilers anyway. Likewise, replace /* reimp */ by
"override" for consistency and compiler support.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Introduce toggle buttons which mean "filter all dives except
those fulfilling the selected criteria".
The old code used to check for rowCount() == 0. This should never happen,
because there is always a row "empty field". This check was moved into
the preamble of the functions to seperate it from the actual logic.
Fixes#435
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
To every filter list add a menu button that allows selection of all,
selection of none or inversion of selection.
Implements #435.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The *FilterModels had a number of of virtual functions, which only
accessed members of the base class. Moreover, these functions were
identical and generated with macros. Therefore, move these functions
to the base class.
The one excption is data(), which uses different count functions
(passed as a macro parameter). Thus, introduce a virtual countDives()
function and likewise move data() to the base class. A function pointer
might be even more clear, but since the rest of the code/Qt relies
heavily on runtime polymorphism, let's do the same here.
The only macros left are those creating the singleton accessors.
This could be more clearly realized by templates, but let's
likewise keep it the way is.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There were two classes, MultiFilterInterface and FiterModelBase.
The latter derives from the former and from QStringListModel.
The former was not used anywhere else. Moreover, in contradiction
to its name, MultiFilterInterface is not an interface (in the Java
sense), because it actually has (non-virtual) data members. All in
all, the data model is very weird.
Merge these two classes, since there seems to be no gain whatsoever
from keeping MultiFilterInterface separate.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
If the user implicitly adds a dive site by editing a dive, and
a location filter is active, check the new dive site in the
location filter.
This is done by informing the LocationFilterModel of the new
dive site name prior to repopulation. The LocationFilterModel
then adds a corresponding entry and marks it as checked.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Since commit 01d961086c, the location filter
list is updated if a dive site is edited. The problem is that if the
name of a selected dive site is changed, the selection is lost.
Therefore, before repopulating, inform the location filter that a dive
site changed its name. The location filter then internally changes the
name and can properly transfer the old selection on repopulate. This is
performed via the new LocationInformationWidget::nameChanged signal,
which is connected to the new LocationFilterModel::changeName slot.
A special case to be handled is the following:
[ ] Site 1
[x] Site 2
and "Site 2" being renamed to "Site 1", i.e. both sites being merged.
Here, the merging is detected and "Site 1" will likewise be checked:
[x] Site 1
[x] Site 1
No merging is performed, as the list will be repopulated anyway.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Update the filters if the list of dives is updated by calling
MultiFilterSortModel::instance()->myInvalidate();
This had the side effect of clearing all selections. Thus, in
the repopulate() methods of the FilterModels, check those
entries that were checked previously. Since all the filter
models use the same code, introduce a base class FilterModelBase.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This replaces a dynamically allocated array of bool by std::vector<char>.
1) This makes the code shorter and less error prone, because memory
management has not to be done by hand.
2) It fixes a bug in the old code:
memset(checkState, false, list.count()) is wrong, because bool is
not guaranteed to be the same size as char!
Two notes:
1) QMap<>, QVector<>, etc. are used numerous times in the code, so
this doesn't introduce a new C++ concept. Here, the std:: version
is used, because there is no need for reference counting, COW
semantics, etc.
2) std::vector<char> is used instead of std::vector<bool>, because
the latter does a pessimization where a bitfield is used!
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This is an attempt to help share code between the desktop version of
Subsurface and the mobile version.
More code will be moved around and the models will be split in a way that
will help recompile times and also creation of different interfaces for
different form-factors.
Signed-off-by: Tomaz Canabrava <tomaz.canabrava@intel.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>