Commit graph

130 commits

Author SHA1 Message Date
Dirk Hohndel
00617aa924 core/models: give progress update while populating models
Especially with large dive logs this will prevent the user from thinking
that the app is hung.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-04-04 12:00:25 -07:00
Berthold Stoeger
59b6ad6a0b divelist: don't initialize invalidFont at startup
To mark invalid dives, we use a struck-out font, which was a static
variable at translation unit scope, i.e. initialized at application
startup. Sadly, this crashes on iOS.

It is unclear when we can initialize fonts. Try to move initialization
to the constructore of DiveTripModelBase and make the font a member
of that class. For consistency, also make the invalidBrush a member
of this class.

This now means that the diveData function cannot be static anymore,
since it needs access to the font and brush. But OK.

Reported-by: Dirk Hohndel <dirk@hohndel.org>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-24 09:01:25 -07:00
Dirk Hohndel
5747573019 mobile/models: make dive invalid flag available to mobile UI
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-21 14:31:37 -07:00
Berthold Stoeger
65acd9976c Dive list: mark invalid dives with a struck out font
Mark invalid dives in the dive list by striking them out
and rendering them with a grey color. The color-change is
not sufficient, because the default model delegate ignores
color hints if the item is selected.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-20 15:20:44 -07:00
Berthold Stoeger
9310d72943 models: update divesite-model when clearing/updating dive model
When the dive list is cleared or updated, the entries in the
divesite-model become stale and therefore the divesite-model
(with the actual name LocationInformationModel) also must be
updated. This was done manually in some parts of the code and
forgotten in others. Therefore, do it directly in the clear()
and reset() function of the dive list-model.

This might be a bit of a layering violation: why should one
model call into another if they are not in parent/child
relationship? However, this seems easier than introducing
a global "reset dives" function that coordinates the models.

Moreover, it does not appear 100% safe: if the clearing of
the divesite model causes accesses to the divelist-model,
they happen in the midst of a model reset and we had horrible
bugs with that kind of things. However, I don't think that
should happen.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-18 13:27:16 -07:00
Berthold Stoeger
6e59ee00d8 divetripmodel: remove setData() function
The setData() function was used to edit the number of a dive.
However, that doesn't appear to be functional. Therefore, remove
the code. There is a context-menu entry "renumber dives" for that.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-17 16:54:36 -07:00
Berthold Stoeger
7387b10b29 cleanup: remove current_dive parameter from divesSelected signal
The diveListNotifier.divesSelected() signal is used to inform the
models of a selection change. It sent the current dive as a second
parameter. This is redundant, because the only sender of the signal
sets current_dive just before sending the signal. Remove the
parameter, which appears to be an artifact.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-12 07:09:01 -07:00
Berthold Stoeger
950ae951bc divetripmodel: change current dive if no dives are selected
The DiveTripModelTree::divesSelected() returned early if
no dives were selected. Thus, the current dive was not
updated. Remove the check for no dives.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-12 07:09:01 -07:00
Robert C. Helling
285fa8acbc Grammar: replaces 'indexes' by 'indices'
Grammar-nazi ran

git grep -l 'indexes' | xargs sed -i '' -e 's/indexes/indices/g'

to prevent future wincing when reading the source code.

Unfortunatly, Qt itself is infected as in
QModelIndexList QItemSelection::indexes() const

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2020-03-11 08:26:30 -07:00
Dirk Hohndel
028807ebc5 mobile models: add trip location and notes
First step towards making those accessible and then editable.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-10 09:25:57 -07:00
Dirk Hohndel
ccf5bf6445 dive models: add helper role to find trip above or below dive
This is only used in the mobile UI where the sort direction is fixed and we
refer to dives based on the tree model. So the terms used and the concepts
that these rely on should be guaranteed to be valid.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-10 09:25:57 -07:00
Dirk Hohndel
968278fe91 core: add 'diveInTrip' role to underlying data model
This will allow us to offer differentiated options in the context menu.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-10 09:25:57 -07:00
Berthold Stoeger
3b6b9951ae undo: clear undo-stack when clearing dive data
When the dive data is cleared, all pointers in the undo-stack become stale.
Desktop explicitly called Command::clear() in that case, but mobile doesn't.
Thus, move the clear() call into DiveTripModelBase::clear()

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-10 09:25:49 -07:00
Dirk Hohndel
89f8457857 mobile/divelist: implement trip title and short date for mobile
We pass this through to the underlying data function.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-09 12:41:11 -07:00
Berthold Stoeger
c5d17c3d4d mobile/divelist: copy & paste the roles-code from DiveListModel
To act as a drop-in replacement (at least as much as possible),
move the roles from the old DiveListModel to the common base
model of mobile and desktop.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-09 12:41:11 -07:00
Berthold Stoeger
35b33b8c6a mobile/divelist: add first version of new MobileListModel proxy model
Create a model which represents all top-level items and, potentially, one
expanded trip as a flat list.

Pass down roles to the source model and let the source model handle that. We'll
have to do some ifdef-ery, but so be it.

Additionally, compile the base model on mobile as well.
This contains a couple of hacks to make things compile at all.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-09 12:41:11 -07:00
Berthold Stoeger
f7cf3e6b16 divetripmodel: send shown changed signal on reset
Once the the mobile app uses the new models, this will be necessary
to get the correct number of filtered dives after startup.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-07 12:04:19 -08:00
Berthold Stoeger
b575a794ea divetripmodel: use change of CURRENT_ROLE to propagate current dive
If compiled on mobile, on change of the current dive, don't send
a signal, but send changed-event with the CURRENT_ROLE for both
dives that changed status (previously selected and newly selected).
Mobile does not use this yet, but will do so with the new flattened
models.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-06 13:46:41 -08:00
Berthold Stoeger
dbddec59d3 divetripmodel: add TRIP_HAS_CURRENT_ROLE
This role returns true if the given trip contains the current
dive. This will be needed by the mobile list model to decide
if a newly added trip should be expanded right away.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-06 13:46:41 -08:00
Berthold Stoeger
a88ab64cf8 divetripmodel: introduce CURRENT_ROLE
Use this role to test whether a dive is the currently displayed dive.
This will be needed to transport changes of the current dive to
the mobile list models.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-06 13:46:41 -08:00
Berthold Stoeger
ee553e059d Filter: move actual filtering loop to core/divefilter.cpp
The DiveFilter class defined the showDive() function to test
whether a dive should be filtered or not. This was used in
DiveTripModel to loop over all dives or all dives affected by
an editing action.

This restricts us in how we do filtering: We can't use indexes
that give us directly the result. To make the filtering more
flexible, move the actual loops that do the filtering to
the DiveFilter class.

The undo-commands likewise called directly the showDive()
function to check whether newly added dives are shown.
Use the new interface here as well.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-22 15:18:31 -08:00
Berthold Stoeger
a45c5faa8c Filter: update current dive if change hides current dive
When changing the filter-criterion and the current dive is
hidden, a new dive is made current. However, when a dive is
hidden because it was edited, it is still shown.

Make this consistent by also selecing a new current dive
in the latter case. Do this by comparing the current_dive
before and after calculating the filter. Since this is now
done in multiple places move this code to the ShownChange
class.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-22 15:18:31 -08:00
Berthold Stoeger
be3d7bffc6 Cleanup: remove shown flag of DiveTripModelTree items
Since we now filter at the model level, items are by definition
shown. No need for a flag.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-22 15:18:31 -08:00
Berthold Stoeger
03a6440b2a Cleanup: remove DiveTripModelBase::SHOWN_ROLE
This role was used by the filter-proxy model as filter criterion.
Since we don't use that model to filter anymore, we can remove
the role.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-22 15:18:31 -08:00
Berthold Stoeger
ae5d2e6b45 Cleanup: remove DiveTripModelBase::sendShownChangedSignals()
This was used by the old filtering code. This is not necessary
anymore.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-22 15:18:31 -08:00
Berthold Stoeger
7633d5feec Dive list: filter dives at DiveTripModel level
We use a QFilterProxyModel to filter out dives that are hidden
according to the current filter-criterion. Instead, filter the
dives already at the DiveTripModel level. Filter out hidden
dives immediately when receiving them. The only difficult case
is when dives are changed, because then visibility can change.
This means that we have three cases to consider:
  1) Visibility unchanged -> send change signal
  2) Change from hidden to unhidden -> add dives to model
  3) Change from unhidden to hidden -> remove dives from model
Things get complicated by the fact that the tree-version of
the model might have to add/remove full trips!

Suggested-by: Dirk Hohndel <dirk@hohndel.org>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-22 15:18:31 -08:00
Berthold Stoeger
33b8cf8a36 Cleanup: remove filterSelectedDives function in divetripmodel.cpp
The last users of the returned vector were removed in commit
e1abf9485c

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-11 20:34:29 -08:00
Dirk Hohndel
cef30619d0 code cleanup: introduce empty_cylinder constant
This deals with the issue of initializing structs in C++.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-01-10 02:37:03 +09:00
Berthold Stoeger
474fc72e32 Coding style: use std::equal_to instead of lambda
Use std::equal_to instead of lambdas that compare two dive pointers.
One could argue over which version is more readable. For whatever
it's worth, std::equal_to is more compact and expressive.

This removes an old erroneous comment that stated that std::equal_to
is only available since C++14.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-13 07:12:12 -05:00
Berthold Stoeger
7e12ac262b Dive list: implement DiveTripModelBase::reset()
On desktop, resetting the model is realized by generating a new
model object. This is due to the fact that we have two different
models (tree and list) and for switching between those, we have
to create a new object.

On mobile, currently there are no plans to support the list-mode.
Therefore, there is no reason the recreate the object. Instead,
implement a reset() function that reloads the core data.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-11 08:31:57 -05:00
Berthold Stoeger
37b24857ed Filter: correctly send changed signals in list mode
The DiveTripModelList forgot to collect the changed dives
when resetting the filter. Fix that.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-10 18:45:30 -08:00
Berthold Stoeger
f5d480711a Filter: instruct UI of changed current dive
Updating the filter can lead to changes of the current dive.
Keep the UI in the know by re-initializing the selection.
This is not optimal, because the whole selection is reset,
but the pragmatic thing to do for now.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-10 18:45:30 -08:00
Berthold Stoeger
6ec82a3c80 Dive list: remove global pointer to DiveTrip model
This part of the code had that horrible pattern, where reseting
the model would invalidate all pointers to the DiveTrip model.
Internalize these complexities in the MultiFilterSortModel.
All accesses are now performed via that proxy model.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-10 18:45:30 -08:00
Berthold Stoeger
358fddd24e Filter: send filterReset via signal
The old code called directly into the DiveListModel. Instead,
send a signal and hook into the signal from the model. This
will allow us to remove the DiveListModel::instance() function.

This, in turn, is a step towards supporting multiple models
at the same time. However, currently the model manually
sets the hidden_by_filter flag in the core and therefore
only one active model is supported at a time.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-10 18:45:30 -08:00
Berthold Stoeger
a431840075 Selection: move initialization of selection from view to model
The goal here is to unify desktop and mobile by moving
selection code from the desktop-only view.
Currently, initialization of the selection still has to be
called from the view after connecting the appropriate signals.
This is due to the weird way in which create completely new
models when resetting them.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-04 13:00:23 +01:00
Berthold Stoeger
86f384f932 Cleanup: rename newCurrentDive signal to currentDiveChanged
This is more consistent with the rest of the signals.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-04 13:00:23 +01:00
Berthold Stoeger
7d5c15f49a Dive list model: send changed signals for top-level items
In analogy to the tree-model send signals when dives change
their shown status in the list-view. Do this in two passes
(collect changes; send changes) to be able to reuse the
already existing functions.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-04 13:00:23 +01:00
Berthold Stoeger
c54e58e078 Dive trip model: send changed signals for top-level items
Send signals if the shown-status of top level items changed.
Do this in two passes to be able to use the previously created
function.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-04 13:00:23 +01:00
Berthold Stoeger
4ca65894c8 Dive trip model: send changed signals if visibility changed in trips
To avoid having to do full filter reloads, send dive-changed signals
for dives in trips when the shown-status changed. But only for trips
where not all dives are hidden. Because for those, the plan is to
hide the trip as a whole.

Implement the signal sending in its own function so that it can be
reused for top-level items and the list-view.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-04 13:00:23 +01:00
Berthold Stoeger
3cc6576913 Dive list model: move filtering of trip-items to own function
Implementing proper model semantics (only sending a changed
signal for items that actually changed) will be somewhat
complicated. Therefore, move the filtering of trip-items
to its own function to make the nesting a little bit less
deep.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-04 13:00:23 +01:00
Berthold Stoeger
635d67ee7f Dive list: clear internal data when clearing model
The DiveListModelBase::clear() implementation was flawed: It cleared
the data in the core, but left the data in the model untouched.
The code was relying on the fact that the caller would reset the
model manually. Not a good idea.

Therefore, clear the internal data to keep the model consistent at
all times.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-19 21:13:40 -08:00
Berthold Stoeger
9f573df971 Dive list: update selection after clearing model
When clearing the model the selection is cleared. Send the according
signal.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-19 21:13:40 -08:00
Berthold Stoeger
3003c6e1ee 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>
2019-11-19 21:13:40 -08:00
Berthold Stoeger
9ffafbc326 Filter: move num_shown logic from model to core
Since the number of shown dives is stored in the core, let's also
keep it updated there.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-19 21:13:40 -08:00
Berthold Stoeger
b76f207158 Filter: split out filter from model
Split out the actual filtering from the MultiFilterSortModel.
Create a DiveFilter class that does the actual filtering.
Currently, mobile and desktop have their own version of this
class, though ultimately we may want to merge them.

The idea here is that the trip-model and undo-commands have
direct access to the filter-function and thus can take care
of keeping track of the number of shown dives, etc.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-19 21:13:40 -08:00
Berthold Stoeger
8a33c04894 Cleanup: use DiveTripModelBase::clear() to reset the log
Introduce a DiveTripModelBase::clear() function that cleanly
clears all dive data inside a beginResetModel()/endResetModel()
pair. Thus, the UI will be cleanly reset and we can remove
explicit calls to
 - graphics->setEmptyState()
 - mainTab->clearTabs()
 - mainTab->clearTabs()
 - diveList->reload()
from MainWindow::closeCurrentFile().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-16 08:29:53 -08:00
Berthold Stoeger
2f77716e8f Dive list: signal correct trip in DiveTripModelTree::topLevelChanged
DiveTripModelTree::topLevelChanged() has pretty complex code, as
it has to handle the fact that when adding/removing a dive from
a trip, the trip can change its position.

The code did not account for the fact that when moving an object
back in the top level list, one has to subtract one from the new
index, because the object was removed somewhere in the front of
the list.

To make matters worse, when an entry stayed where it was, this
was realized by moving the entry right behind itself, which of
course means that it stays where it is. But this meant that in
the by far most common case (no moving) the wrong entry was
updated.

Fix this by subtracting 1 from the new index when moving an
entry to the back.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-15 13:50:35 -08:00
Berthold Stoeger
5e29245e68 Refactoring: move undo commands to top level
In the future we might want to use undo-commands for mobile as
well (even if not implementing undo).

Therefore, move the undo-command source from desktop-widgets
to their own commands top-level folder.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-14 21:02:07 +01:00
Berthold Stoeger
e434b5aa40 Cleanup: introduce DiveTripModelBase::IS_TRIP_ROLE
To test whether an entry is a trip, we passed a pointer to the
trip through a QVariant and tested that for null-ity.

Passing pointers through QVariants has given us myriads of
problems in QML, therefore introduce a bool IS_TRIP_ROLE

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-11 22:44:58 +01:00
Berthold Stoeger
794066b236 Cylinders: access cylinders with get_cylinder()
Instead of accessing the cylinder table directly, use the get_cylinder()
function. This gives less unwieldy expressions. But more importantly,
the function does bound checking. This is crucial for now as the code
hasn't be properly audited since the change to arbitrarily sized
cylinder tables. Accesses of invalid cylinder indexes may lead to
silent data-corruption that is sometimes not even noticed by
valgrind. Returning NULL instead of an invalid pointer will make
debugging much easier.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-09 19:19:04 +01:00