Commit graph

1048 commits

Author SHA1 Message Date
Berthold Stoeger
01fa983182 undo/cylinder: call undo command to edit cylinder fields
Call an undo command when editing cylinders, but only if on
the EquipmentTab.

To keep code changes small, make a copy of the cylinder first,
then edit the cylinder as before and then either call an undo
command (EquipmentTab) or overwrite the old cylinder (Planner).

The memory management here is a bit strange: Since the undo-command
itself makes a deep-copy of the passed in cylinder, we only do
a shallow copy. If we have to change the type, we allocate the
string with an std::string, so that the memory is automatically
freed at the end of the function. However, this means that in
the planner we have to make a deep copy first, swap old and
new cylinder and finally release the old cylinder. Certainly
not ideal, but for now the pragmatic thing to do.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:35 +02:00
Berthold Stoeger
1dcc885bb2 undo/cylinders: Implement editing of the type
This one is tricky, as when browsing through the types-combobox,
the user is presented with presets without actually changing the
dive. We do not want an undo-command for every change-event in
the combo-box.

Therefore, implement a scheme analoguous to the weight-editing:
A temporary row can be set / committed or reset. Sadly, the
code is more complex because we have to consider the planner,
which is not included in the undo system.

Firstly, the planner uses a different model, therefore all
interactions are channeled through setData() with special roles.
Secondly, in the planner we shouldn't place an undo command,
but simply overwrite the dive.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:35 +02:00
Berthold Stoeger
d597b6dca5 cleanup: remove unused CylindersModelFiltered functions
add() and remove() are not used anymore since this is done using
undo commands. The planner uses CylindersModel instead.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:35 +02:00
Berthold Stoeger
66fc9fcfec CylindersModel: fold CHANGED() macro into setData()
The CHANGED macro was defined in the cleanerTableModel header.
Since it had only one user, expand it there. The macro was very
questionably anyway, as it would set the local "vString" variable.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:35 +02:00
Berthold Stoeger
a75360f58f CylindersModel: test for CHANGED() outside of switch statement
A small code consolidation:

With one exception, all targets of the switch statement would
test for CHANGED(). Instead do the test once and exit early.
This changes the behavior of the function: if not changed, there
will be no more dataChanged-signal. However, this appears to be
the correct thing to do anyway. And it is easily changed if
it matters after all.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:35 +02:00
Berthold Stoeger
a4a06c48bf CylindersModel: remove mark_dive_list_changed
Cylinder-editing is controlled by undo (either by saving a planned
dive or by using the equipment tab). There is no point in setting
the dive_list_changed flag.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:35 +02:00
Berthold Stoeger
d02489f888 cylinders: remove CylindersModel::changed
Nobody is testing that flag anymore.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:35 +02:00
Berthold Stoeger
04ce908e8e CylindersModel: listen and react to signals
React to signals from the undo-commands and update the
model accordingly.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:35 +02:00
Berthold Stoeger
75f37a7d10 CylindersModel: don't test for planner-state in remove()
This is only called from the planner. Therefore, the test is
redundant.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:35 +02:00
Berthold Stoeger
5b7a316593 undo: reorder cylinders on remove-cylinder undo/redo
The cylinders in the events must be reordered if we remove
a cylinder. To avoid duplication of code, move the reordering
function into qthelper.cpp, though it might not be ideal
there.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:35 +02:00
Berthold Stoeger
a37939889b cleanup: remove CylindersModels::rows
Access the number of cylinders in the dive directly instead.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:34 +02:00
Berthold Stoeger
30d289e4a8 CylinderModel: make dive dynamic
The CylinderModel always accessed the global "displayed_dive" and in
some special cases also "current_dive". To implement cylinder undo,
the model should work on an arbitrary dive. Therefore, in analogy
to the weight model, make the dive dynamic.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:34 +02:00
Berthold Stoeger
e008b42a59 core: add create_new_cylinder() function
Turn the code in CylindersModel that creates a new cylinder for
addition into its own function to avoid code duplication. This
will be used from the undo commands.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-04-07 00:13:34 +02:00
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
Dirk Hohndel
16dd16b34b mobile/dive-summary: use 64bit integers for statistics
We still support 32bit ARM platforms, and there long is 32 bits.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-31 08:42:20 -07:00
Dirk Hohndel
4cd7767bec message handler: make the log output less verbose
Skip truly identical / repetitive messages.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-30 09:16:55 -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
Dirk Hohndel
bd746b1d1b Android: use Subsurface as TAG for log messages
Having the file name as TAG was just stupid.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-21 13:27:00 -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
3c2a192864 mobile: remove no longer used DiveListModel
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-10 09:25:57 -07:00
Berthold Stoeger
c34b7857fc mobile/divelist: implement model that shows all dives in trip-order
MobileSwipeModel is probably not an ideal name, but all I could come up with.

One of the main complications here is that our list is reversed with respect to
the source model. We should change that one day.  Probably by moving the
sorting down to the core-model.

Since looking up the source row is somewhat expensive, the lookup is cached for
a single entry because accesses come in bursts for a single dive. This should
be a good compromise and avoids keeping track of a full row-to-dive array.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-10 09:25:57 -07:00
Berthold Stoeger
71b378aa82 mobile/divelist: derive MobileListModel from a base model
In analogy to the DiveTripModel split, derive MobileListModel from a base
model that exports the roles, etc. This will allow us to create a second model,
which nevertheless possesses the same roles and all that without too much code
duplication.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-10 09:25:57 -07:00
Berthold Stoeger
7e1ac2167b mobile/divelist: create memory management class for models
Since we want to add a second model, but not have to manage two models
everywhere, create a class MobileModels that contains both of the models. When
calling reset() on that class, it will reset both of the models, etc.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-10 09:25:57 -07:00
Berthold Stoeger
b6f821886b mobile: unify download code on mobile and desktop
Use the undo-command for importing dives also on mobile. This should make the
whole disconnect-model shenigans unnecessary.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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
Berthold Stoeger
7d6949ce7d mobile/undo: compile WSInfoModel
The weight-undo commands need this. Therefore, we have to compile the
WSInfoModel if we want to access the undo commands from mobile.

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
730fd26814 mobile/divelist: connect click on trip to toggle MobileListModel
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-09 12:41:11 -07:00
Dirk Hohndel
edeaf7fa57 mobile: remove collapsed model that we no longer use
The dive list now uses the mobile list model.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-09 12:41:11 -07:00
Dirk Hohndel
30d242efc0 mobile/divelist: trip date and title roles for new model
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-09 12:41:11 -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
2e52f43d94 divetripmodel: mark derived classes as final
This is an idle "optimization": The compiler may now not need
to access the vtable when calling virtual functions.

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
d6114fc37e mobile/filter: derive numShown from a new Q_PROPERTY
The number of dives was updated when the model of the list was
changed. Since we removed the multi-threading, the model is
not disconnected/connected anymore and therefore we don't get
the appropriate signal. Instead of introducing a different
signal, make the shown-value a Q_PROPERTY. Thus, we can easily
send a changed signal if we have to.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-01 10:21:44 -08:00
Berthold Stoeger
e0766aa4bd filter: introduce people- and tags-filtering in the mobile UI
Add a combo-box where the user can switch between "fulltext",
"people" and "tags" filtering. Connect the combobox to the
already existing filter-code.

Dirk: make combo-box smaller by using a smaller font and restricting
the width. Setting both maximum and preferred widths gives more
consistent results.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-03-01 10:21:44 -08:00
Berthold Stoeger
8cb43ed237 filter: use DiveFilter on mobile
Use the DiveFilter class on mobile to update the filter. This
is mostly for convergence of the mobile and desktop models.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-01 10:21:44 -08:00
Berthold Stoeger
78405c7265 mobile: remove DiveListSortModel::getFilterString()
This member function was never used.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-03-01 10:21:44 -08:00
Berthold Stoeger
f1e1a9634a cleanup: simplify string-comparison in CylindersModel::setData()
Convert to QString instead of a QByteArray. Use qPrintable()
instead of data(). This might do one more UTF16->UTF8 conversion.
However, this is completely irrelevant, since we don't change
the type of a cylinder in a tight loop.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-28 08:12:26 -08:00
Berthold Stoeger
ee1c438d41 cleanup: fix leak in CylindersModel::setData()
The C-string cyl->type.description was set without the old data
being freed. Free the old string before overwriting the pointer.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-28 08:12:26 -08:00
Berthold Stoeger
f55c15e5f9 cleanup: make CylindersModel::cylinderAt private
The last outside use of the function was replaced by calls
to data().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-28 08:12:26 -08:00
Berthold Stoeger
cb80ff746b crash fix: Don't cast to CylindersModel or CylindersModelFiltered
The tank-info-delegate cast its model to CylindersModelFiltered,
since this is what the equipment-tab uses since implementing the
filtering of unused cylinders. However, the planner users the same
delegate and still uses the unfiltered CylindersModel. This means
that the (dynamic) cast returns a null pointer and crashes.

One possibility would be to derive CylindersModelFiltered and
CylindersModel from the same class that defines virtual functions
and cast to that class.

This is a different attempt: don't cast (i.e. stay with a
QAbstractItemModel and play it via Qt's model-view system. Firstly,
replace the passInData function by a role to setData(). Secondly,
read the working-pressure and size via new columns using data().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-28 08:12:26 -08:00
Berthold Stoeger
6570597f5b CylinderModel: remove unnecessary "Is used" header
This header is a rebase artifact and introduces a pointless
column in the cylinder tables. It was erroneously introduced
in 6622f42aab.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-24 04:56:49 -08:00
Berthold Stoeger
dedf8858fb cleanup: remove CleanerTableModel::warningMessage signal
Nobody was ever listening to this signal(?) and the last sender
was removed in ac52034778.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-23 06:57:18 -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
77a1c7c1f4 Dive list: remove filtering in MultiFilterSortModel
Since we're doing the filtering at the core, don't filter
in the sort-model (which is now inappropriately named).

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
1336ea755b Planner: don't filter cylinders
In the planner we used to filter out "unused" cylinders as in the
equipment tab. It is unclear whether that makes sense or can even
easily be reproduced, since such cylinders have to come from an
imported dive.

To be on the save side, let's not do this. Replace the
CylindersFilteredModel introduced recently by a plain
CylindersModel.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-11 20:37:09 -08:00
Berthold Stoeger
190a2a876e Planner: make cylinder-model subobject of planner-model
The cylinder-model had an instance() function, but actually
there were two cylinder models: one used by the equipment tab,
one used by the planner.

This is misleading. Therefore, remove the instance() function
and make the cylinder-model a subobject of the planner-model.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-11 20:37:09 -08:00
Berthold Stoeger
6622f42aab Cylinders: Add CylindersModelFiltered
When the show_unused_cylinders flag is not set, the cylinder tables
in the equipment tab and the planner should not show unused cylinders.
However, the code in CylindersModel is fundamentally broken if the
unused cylinders are not at the end of the list: The correct number
of cylinders is shown, but not the correct cylinders.

Therefore, add a higher-level CylindersModelFiltered model on top
of CylindersModel that does the actual filtering. Some calls are
routed through to the base model (notably those that take indexes,
as these have to be mapped), for some calls the caller has to get
access to the source model first. We might want to adjust this.

For filtering, reuse the already existing show_cylinder function
and export it via CylindersModel.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-11 20:37:09 -08:00
Berthold Stoeger
b37c261c95 Cleanup: make CylindersModel::updateBestMixes non-slot
This was not used as a target of a connection anywhere.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-11 20:37:09 -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
6c7411c776 mobile/summary: use more intuitive time periods
No one will ask you about your dives in the last seven months (and the
existing code actually provided the past 210 days in that case). Instead
do more intuitive periods. Last month, quarter, half year, year.

Use Qt's ability to make sane date calculations easy.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-02-08 10:29:36 -08:00
Berthold Stoeger
a93c303b8b mobile/summary: add section headers
Add section headers to the dive summaries on mobile by adding
a section-property. Of course, this will not work on desktop.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-02-08 10:29:36 -08:00
Berthold Stoeger
1a85b0e941 mobile/summary: create DiveSummaryModel
Instead of passing the dive summary via a completely unstructured
QStringList to QML, implement a dynamic model. For potential reuse
on desktop (though somewhat unlikely) the model has two interfaces,
one for QtWidgets and one for QML. The former is based on columns,
whereas the later is based on roles. The number of columns is
set dynamically. The roles currently support access to two columns.
If more columns should be accessed from QML, more roles have to
be added manually.

This commit only creates the model and hooks it into QMLs global
context, but does not yet change the QML page.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-02-08 10:29:36 -08:00
Berthold Stoeger
5e0ce206a0 Cleanup: remove capture-all lambda clauses
These were forgotten the last time.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-04 16:24:29 +01:00
Berthold Stoeger
3fc2da567b Dive site: ignore dive sites without location in proximity search
When editing a dive site, the user can search for close dive sites
to merge duplicates. Dive sites without location are treated as
being located at 0N0E. This makes no sense, because:

When selecting a dive site without location, we shouldn't list
dive sites close to 0N0E.

Likewise when having a dive site close to 0N0E, we shouldn't list
dive sites that have no location.

Therefore, ignore these cases.

This also means that now dive sites without location are not
considered as close to other dive sites without location. That
might be a debatable point.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-04 02:18:58 +01:00
Berthold Stoeger
9ed886e4be Cleanup: lower-case filenames in core/subsurface-qt/
We tend to use lower-case filenames. Let's do it for these files
as well. Simple search & replace.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-02-04 02:16:46 +01:00
Berthold Stoeger
62b869b24a CylindersModel: don't crash if accessing non-existing cylinder
It shouldn't happen, but currently we overwrite the displayed_dive
without updating the CylindersModel. Thus, CylindersModel may now
crash when the new displayed_dive has less cylinders than the old
one.

For now, catch this condition. Treat the root cause later.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-01-30 19:33:21 +02:00
jan Iversen
d8b035ffe7 diveplanner: add comments explaining different scaling
In some case the scaling (real value <-> UI value) is different
for mobile and desktop. In order to make the difference understandable
comments are added to each function.

Signed-off-by: jan Iversen <jan@casacondor.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-01-25 17:27:25 -08:00
jan Iversen
74d13b0554 diveplanner: move mobile specific calc to diveplannermodel
setBottomSac, setDecoSac and setFactor in diveplannermodel
receives display value which are then converted.

subsurface-mobile have slightly different values, move the
correction of these from plannershared to diveplannermodel, in
order to keep the whole convert in one place.

Signed-off-by: jan Iversen <jan@casacondor.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-01-25 17:26:53 -08:00
jan Iversen
d924afdf52 qt-models: add suffix Display to unit system aware asc/desc setters
Change ascent/descent setter function names to set_<name>Display
to show the value is prepared for displaying (common for desktop and QML).

Signed-off-by: jan Iversen <jan@casacondor.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-01-20 15:45:20 -08:00
jan Iversen
851ab68aa2 qt-models: add getters to diveplanner model
diveplannermodel already contains set_<asc/desc> function that convert from
screen value to real value; this adds get functions that convert real value to
screen value, so now all conversions are done in one place.

Use prefix Display to identify this is values prepared for the UI (both desktop
and QML).

Signed-off-by: jan Iversen <jan@casacondor.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-01-20 15:41:21 -08:00
Dirk Hohndel
e1cd055111 code cleanup: add empty table structures
It seemed to make sense to combine all three types in one commit.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-01-10 02:37:03 +09: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
Dirk Hohndel
e9dcac7514 code cleanup: replace use of toStdVector()
Frankly, I find the old API easier...

Also, replace toList() with values()

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-01-10 02:37:03 +09:00
jan Iversen
1fc54e907f testing: prepare diveplannermodel to be used in testing
In order to make tests for plannerShared, some qt-models must
be linked, and due to the fact that commands are currently not
available for mobile (which also makes the tests) and #ifdef must
be added.

The test version of diveplannermodel will be specially compiled in
(SUBSURFACE_TESTING set) in the tests directory.

Signed-off-by: Jan Iversen <jan@casacondor.com>
2019-12-27 05:40:26 +09:00
jan Iversen
da38b84bc8 build-system: add diveplannermodel to Mobile
add diveplannermodel to GENERIC instead of DESKTOP

as a consequence other models are need, move those
from DESKTOP to GENERIC

Signed-off-by: Jan Iversen <jan@casacondor.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-12-26 08:37:39 -08:00
jan Iversen
63d676d9e4 qt-models: conditionally compile Commands:: in diveplannermodel.cpp
commands (undo) are not available for mobile, but diveplannermodel
is needed

add #ifndef MOBILE around Commands::

Signed-off-by: Jan Iversen <jan@casacondor.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-12-26 08:37:25 -08:00
Robert C. Helling
8c0023e151 Stop Compiler Warning: Change struct to class
Signed-off-by: Robert C. Helling <helling@atdotde.de>
2019-12-16 18:27:37 +01: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
jan Iversen
a96be9af68 qt-models: remove LOG_STP from mobile/desktop
LOG_STP is on longer providing the data needed, since a lot of the startup
is indirectly in QML, furthermore using the xcode project and running profiler
gives much more detailed information

Signed-off-by: Jan Iversen <jani@apache.org>
2019-12-13 07:04:00 -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
e7dafe36aa Dive list: clear dive data via the filter model
The UI talks to the filter model. Therefore route clearing of
data through that model instead of accessing the source model
directly.

This will allow us to remove the DiveTripModel::instance()
function and makes control flow less "jumpy".

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
e114522a44 Cleanup: set description to null in free_[weightsystem|cylinder]
Currently, the caller is responsible for not reusing a freed
weightsystem / cylinder or resetting the description field to
null. This is very unfriendly. Set the description field to null,
because that allows us to call free_* repeatedly on the same
object. Use the new behavior to make the weightsystem model code
a bit cleaner.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-05 10:14:25 -08:00
Berthold Stoeger
a4c95fd8e8 Cleanup: remove WeightModel::changed
Since changes to the weight model are not modal anymore, nobody
queries the changed-flag. Remove it.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-05 10:14:25 -08:00
Berthold Stoeger
72c6b83866 Undo: make weight editing undoable
Implement the EditWeight undo command. Since there is common code
(storage of the old weight), this creates a common base class for
RemoveWeight and EditWeight. The model calls directly into the undo
command, which is somewhat unfortunate as it feels like a layering
violation. It's the easy thing to do for now.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-05 10:14:25 -08:00
Berthold Stoeger
029c9ccf02 Desktop: refactor WSInfoDelegate logic
The WSInfoDelegate (weight-system-info delegate) is used to display
a combo box of known weightsystem-types and auto-fills the weight if
the weightsystem-type is changed.

This would overwrite the weight data of the displayed dive when the
user hovers over the different entries. Moreover, it saves the original
weight in case the user cancels the editing action.

This is not viable when implementing undo of weightsystem changes,
because hovering over entries should not produce individual undo
commands. Instead, implement a special "temporary" row in the
weightsystem model. On canceling of the edit actions, simply reload
the weightsystem from the unmodified dive.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-05 10:14:25 -08:00
Berthold Stoeger
dc67876c79 Cleanup: introduce empty_weightsystem constant
To make things more future-proof, introduce an empty_weightsystem
constant. Replace explicit aggragate initialization of empty
weightsystems by this constant.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-05 10:14:25 -08:00
Berthold Stoeger
92b833a7d8 Cleanup: remove redundant "row" member of WeightModel
Before undoization, the WeightModel could be out-of-sync with
the actual dive and therefore had a row member variable. This
became redundant. Therefore, remove it.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-05 10:14:25 -08:00
Berthold Stoeger
2cfb35b6d7 Cleanup: return value type from WeightModel::weightSystemAt()
There is only one caller of WeightModel::weightSystemAt() and that
certainly does not need a pointer into the weightsystem-table of
the current dive. Return a value type instead of a pointer.

This allows us to mark WeightModel::weightSystemAt() as const and
use it from WeightModel::data(). Slightly cleaner code.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-05 10:14:25 -08:00
Berthold Stoeger
b3f530bfb9 Undo: make weight-deletion an undoable action
This one is a bit more complicated than weight adding, because the
multiple-dive case is not well defined. If multiple dives are selected,
this implementation will search for weights that are identical to the
weight deleted in the currently shown dive. The position of the weight
in the list is ignored.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-05 10:14:25 -08:00
Berthold Stoeger
b3253304a5 Desktop: don't connect to remove() slot of model from TableModel
When connecting a model to the TableModel class, it would connect
clicking on an item to the remove() slot of the model.

This breaks the program flow implied by the undo code:
Ui --> Undo-Command --> Model --> UI

Moreover, the naming of the remove() slot is illogical, because
clicks can also have different effects, as for example in the
cylinder-table.

Therefore, move the connect() call from TableModel to the
callers. In the case of TabDiveSite, move the remove() function
from the model to the TabWidget, where it makes more sense.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-05 10:14:25 -08:00
Berthold Stoeger
147a36647c Undo: make adding of weights an undoable action
Introduce an AddWeight undo command. This is modelled after the
numerous dive-edit undo commands. The redo and undo actions are
connected to the WeightModel via two new signals, weightAdded
and weightRemoved.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-05 10:14:25 -08:00
Berthold Stoeger
76a5a38f5e Cleanup: remove displayed_dive from WeightModel
The WeightModel always acted on the displayed dive. To support undo
of weightsystem changes, operate on an arbitrary dive. This is
in line with other models, where the updateDive() function resets
the model to represent a certain dive.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-05 10:14:25 -08:00
Berthold Stoeger
e46b1e88d9 Selection: move translation of indexes to filter model
The DiveListView caught signals from the DiveTripModel
with the corresponding indexes. However, the DiveListView
is actually connected to the MultiFilterSortModel and
thus has to translate the indexes.

Instead, catch the signals in the MultiFilterSortModel,
transform them and resend. Let the DiveListView get
its signal from the MultiFilterSortModel.

Yes, this makes things less efficient because there is
an extra signal. On the upside, the makes data-flow much
more logical. Selection will have to be fixed anyway.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-12-04 13:00:23 +01: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
d0b3a06e03 Filter: use changed-signals to update filter
The dive-trip models now send changed-events if the shown-status
changed. Thus, there is no reason to fully reset the filter on
filter changes.

Simply tell the filter that it has to react to changes of SHOWN_ROLE.

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
ddfc384b61 Cylinders: Fix crash when removing cylinders
Change the remove() function of the cylinder and weight models
to take the index by value. The code used to take it by reference
and the reference would be invalidated when removing rows from
the model!

Reported-by: Gaetan Bisson <bisson@archlinux.org>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-26 17:21:34 -08: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
6d6d10f03a Filter: move calculation of shown dives to undo command
The filter-model was catching dives-added / dives-deleted signals
from the models to keep track of the number of shown dives.

To simplify the data flow, do this directly in the undo-command.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-19 21:13:40 -08:00
Berthold Stoeger
2d09819ddf Filter: move number of shown dives to core
We mark hidden/shown dives in the core but store the number
of shown dives in the MultiFilterSortModel. Move this datum
to the core for improved locality.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-19 21:13:40 -08:00
Berthold Stoeger
cbd98edb73 Cleanup: remove MultiFilterSortModel::filterChanged()
Nobody was calling this function.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-19 21:13:40 -08:00
Berthold Stoeger
669ca76b08 Cleanup: remove MultiFilterSortModel::clearFilter
Nobody was using that function.

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
36094e4a18 Partially revert 3025e0630d
This commit did the "right" thing by implementing Qt mode semantics
as intended, but for unknown reasons the profile is not properly
cleared on close-file anymore. This code is so convoluted that there
is not point in fighting it at the moment. Revert to remove-rows
instead of reset-model.

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
a474264cc8 Cleanup: fix typos in comment
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
Berthold Stoeger
7c9f46acd2 Core: remove MAX_CYLINDERS restriction
Instead of using fixed size arrays, use a new cylinder_table structure.
The code copies the weightsystem code, but is significantly more complex
because cylinders are such an integral part of the core.

Two functions to access the cylinders were added:
get_cylinder() and get_or_create_cylinder()
The former does a simple array access and supposes that the cylinder
exists. The latter is used by the parser(s) and if a cylinder with
the given id does not exist, cylinders up to that id are generated.

One point will make C programmers cringe: the cylinder structure is
passed by value. This is due to the way the table-macros work. A
refactoring of the table macros is planned. It has to be noted that
the size of a cylinder_t is 64 bytes, i.e. 8 long words on a 64-bit
architecture, so passing on the stack is probably not even significantly
slower than passing as reference.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-09 19:19:04 +01:00
Berthold Stoeger
cd4f66014f Cleanup: Make cylinder formatting functions const-clean
In qt-models/cylindermodel.cpp the various formatting functions
can take a pointer-to-const cylinder. Thus, the data() function
can likewise treat the cylinder as const - as it should.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-09 19:19:04 +01:00
Berthold Stoeger
4e86d99714 Cleanup: free plot data on exit
Some widgets copy the full plot info. Free these data on exit to
prevent monstrous valgrind reports.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-09 19:19:04 +01:00
Berthold Stoeger
00289cd222 Profile: dynamically allocate plot pressure data
All accesses to the pressure data were converted to use functions.
Therefore it is now rather trivial to dynamically allocate the
pressure array and just change the functions.

The only thing to take care of is the idiosyncratic memory
management. Make sure to free and copy the buffer in the
appropriate places.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-09 19:19:04 +01:00
Berthold Stoeger
bef1eac7fa Profile: use pressure data functions in DivePlotDataModel
The model was accessing the pressure data directly. Instead,
use the accessor functions so that the core structure can
be changed more easily.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-09 19:19:04 +01:00
Berthold Stoeger
3025e0630d Cleanup: implement proper Qt-model semantics in DivePlotData model
User beginResetModel()/endResetModel() pairs to reset the model.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-09 19:19:04 +01:00
Berthold Stoeger
ff653f721c Cylinders: dynamically allocate cylinder arrays
When keeping track of cylinder related data, the code was using
static arrays of MAX_CYLINDERS length. If we want to use dynamically
sized cylinder arrays, these have to be dynamically allocated.
In C++ code, this is trivial: simply replace the C-style arrays
by std::vector<>. Don't use QVector, as no reference counting or
COW semantics are needed here. These are purely local and unshared
arrays.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-09 19:19:04 +01:00
Berthold Stoeger
11467fa326 Core: dynamically allocate the result of get_gas_used()
get_gas_used() returns the volume of used gases. Currently,
an array with MAX_CYLINDERS is passed in. If we want to make the
number of cylinders dynamic, the function must use an arbitrarilly
sized array.

Therefore, return a dynamically allocated array and free it
in the caller.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-11-09 19:19:04 +01:00
Dirk Hohndel
2c11544d93 Mobile: correctly update filter text and update all three models
This is even harder because setActiveTrip is called from an action slot from
QML. If the C++ code called from that slot causes the object to which this slot
belongs to be destroyed, we get very strange crashes. The only workaround I
could come up with was to update the filter asynchronously.

This all seems very ugly and fragile.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-11-08 20:50:05 +01:00
Dirk Hohndel
2c9bf775b7 Mobile: ensure the sort order is always set
This shouldn't be necessary every time we replace the sort model,
but it can't hurt, either (famous last words?).

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-11-08 20:50:05 +01:00
Dirk Hohndel
6095a5f04f Mobile: add second filter proxy model for dive list
This one significantly reduces the number of dives that are handed to the
ListView in QML. For every trip that isn't expanded (only zero or one trips are
expanded at any time, so almost all the others are collapsed), send only first
dive to the View to allow creation of the section. Hide the rest so we don't
have all these invisible, zero height entries for the vertical dive list.

A big part of this commit is moving a few functions from the DiveListSortModel
to the CollapsedDiveListSortModel. Those are the ones that are needed for the
trip header.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-11-08 20:50:05 +01:00
Robert C. Helling
9c8fbe494d Planner: Add option to treat O2 as narcotic
When computing the best mix for a target depth, for helium, one
can either require that the partial pressure of N2 is the same
as at the target depth or the partial pressure of N2 plus O2.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2019-10-31 00:30:38 -07:00
Dirk Hohndel
130946fcf4 Cleanup: NULL check pointer before dereferencing
I we have no dive, whatever this is shouldn't be shown.

Found by Coverity. Fixes CID 350093

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-10-27 07:35:46 -07:00
Dirk Hohndel
08fcda60ac Cleanup: add missing break statements
The current code of course works just fine. But there's a risk someone might
add something to one of these cases and not realize that there is an implicit
fall through going on. This is cleaner.

Found by Coverity. Fixes CID 350079

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-10-27 07:35:46 -07:00
Dirk Hohndel
c9a39bb08e Cleanup: avoid resource leak in dive planner model
Found by Coverity. Fixes CID 350121

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-10-26 19:17:53 -07:00
Dirk Hohndel
4f9783ff60 Cleanup: avoid out of bounds access
This is extremely unlikely to ever happen since we reserve space for a
hundred weight models, but hey, doing this right is quite easy, so let's
fix it.

Found by Coverity. Fixes CID #350117

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-10-26 19:17:53 -07:00
Berthold Stoeger
c479c5ca36 Desktop: use undo command when replanning dive
Instead of copying the displayed dive, generate an undo command.
This makes the replanning an undoable action and fixes a bug
where the dive details have not been updated correctly.

Fixes #2280

Reported-by: Stefan Fuchs <sfuchs@gmx.de>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-26 11:36:23 -07:00
Dirk Hohndel
158a2ec159 Mobile: remove remaining accesses to DiveObjectHelper from QML
Add a couple more roles and remove the dive role that allows accesss to
the DiveObjectHelper in the first place.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-10-20 16:08:55 -04:00
Dirk Hohndel
613a3112d2 Mobile: get dive details directly from the model
By getting a DiveObjectHelper and then dereferencing that we ended up
creating hundres and hundreds of these objects, only to immediately
destroy them after using a tiny part of the data.

Instead make those data available directly from the model, without
having to create a DiveObjectHelper forst.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-10-20 16:08:55 -04:00
Berthold Stoeger
769403a4b2 Planner: copy deco state before passing it to worker thread
The planner has a computeVariations() function that can be run
in a worker thread. The code was not thread safe: a deco_state
object allocated on the stack of the caller was passed down to
the worker thread. It's well possible that the object would go
out of scope before the thread run.

Therefore, when running in the background, copy the object first
and free it in the worker thread.

Side note: Qt makes proper memory management again as difficult
as possible: You can't pass a std::unique_ptr<> to QtConcurrent::run,
because move-only objects are not supported. Not very friendly!

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-20 16:20:58 +02:00
Berthold Stoeger
1e1f33c0f5 Cleanup: Make constructor of singletons private
This guarantees that they are actually singletons: there can
only be one application-wide instantiation of these objects.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-04 09:19:10 -07:00
Berthold Stoeger
3db50aedea Cleanup: Turn DiveListSortModel into classical singleton
To make this class available from QMLManager, the run_ui()
function would create the object and then set a pointer in
QMLManager. It works, but is inconsistent with the rest of
the code. Therefore, make it a classical singleton class,
which is generated on demand.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-04 09:19:10 -07:00
Berthold Stoeger
2a9a3dda20 Cleanup: turn GpsListModel into standard singleton
GpsListModel was one of those "special" singletons that could
be created explicitly with new. This would make sense if a
parameter were passed to the constructor. We only passed null,
so one might as well turn that into a classical singleton with
default constructor.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-04 09:19:10 -07:00
Berthold Stoeger
36d42a6a57 Cleanup: turn DiveListModel into standard singleton
DiveListModel was one of those "special" singletons that could
be created explicitly with new. This would make sense if a
parameter were passed to the constructor. We only passed null,
so one might as well turn that into a classical singleton with
default constructor.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-04 09:19:10 -07:00
Berthold Stoeger
2560734624 Cleanup: initialize DiveListSortModel in constructor
The model was initialized in the global run_ui() function.
Move that into the constructor of the class.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-04 09:19:10 -07:00
Berthold Stoeger
4d5acc8461 Import: remove DiveImportedModel::lastIndex
This is redundant, as the actual size is stored in the dive table.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-02 08:04:49 -07:00
Berthold Stoeger
a33f381dc6 Cleanup: remove DiveImportedModel::firstIndex
This index was never set to anything else than 0. Might as
well remove it.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-02 08:04:49 -07:00
Berthold Stoeger
5037fcdbdc Import: avoid model inconsistency in DiveImportedModel::recordDives()
DiveImportedModel::recordDives() called add_imported_dives(). But that
actually consumes the dive and dive-site tables. Which in turn will
lead to an inconsistent model.

Properly reset the model by using the consumeTables() function.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-02 08:04:49 -07:00
Berthold Stoeger
087a80194a Import: keep dive and dive site tables in DiveImportedModel
The DiveImportedModel and DownloadThread used the same table
of dives and dive sites. This made it very hard to keep the
model consistent: Every modification of the download thread
would make the model inconsistent and could lead to memory
corruption owing to dangling pointers.

Therefore, keep a copy in the model. When updating the model,
use move-semantics, i.e. move the data and reset the tables
of the thread to zero elements.

Since the DiveImportedModel and the DownloadThread are very
tightly integrated, remove the accessor-functions of the
dive and dive-site tables. They fulfilled no purpose
whatsoever as they gave the same access-rights as a public
field.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-02 08:04:49 -07:00
Berthold Stoeger
81268adfd3 Import: extract number of dives from model not from thread
The plan is to make the model the authoritative source of
the imported dives. Therefore, access the number of
downloaded dives from there.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-02 08:04:49 -07:00
Berthold Stoeger
8f3c85f58d Import: get tables from DiveImportedModel not DownloadThread
When importing dives, consume the tables from DiveImportedModel
and not the DownloadThread. This appears more logical and avoids
an inconsistent state of the DiveImportedModel: On import the
tables would be reset, but the DiveImportedModel wasn't
informed of that.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-02 08:04:49 -07:00
Berthold Stoeger
30b384cebd Import: keep model state consistent when deleting unselected dives
In DiveImportedModel::deleteDeselected(), unselected dives were
deleted from the dive-table. But this left the model in an
inconsistent state and the frontend was not informed of the
missing dives.

Fix this by invoking the appropriate beginRemoveRows()/
endRemoveRows() pairs. Move the functionality into its
own function so that it can be reused by the desktop version.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-02 08:04:49 -07:00
Berthold Stoeger
ad7ffa0af0 Import: Make DownloadThread a subobject of DiveImportedModel
Currently, desktop and mobile are accessing the DownloadThread
and the DiveImportedModel concurrently. This makes a big data
flow mess. To achieve a more hierarchical data flow, start
by making the DownloadThread a subobject of DiveImportedModel.

Start the download by calling a function in DiveImportedModel.

Route the finished signal through DiveImportedModel. Thus,
the model can reload itself with the new data.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-10-02 08:04:49 -07:00
Berthold Stoeger
eecca6aab0 Mobile: replace model-reset by row-addition in DiveListModel::reload()
Owing to apparent QML breakage, a model-reset leads to the DiveDetail
page being reloaded for every dive in the list(!). Therefore, add
rows instead.

This leads to extremely subtle code, as it is now imperative that
the model has been properly cleared beforehand. Nevertheless, for
now we have to do this to fix a severe performance regression.

Fixes #2295

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-27 16:33:37 -07:00
Berthold Stoeger
649ac1f83a Mobile: clear dive data via model
Clearing the dive data directly in the core leaves us with an
inconsistent model. Therefore, clear via the model.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-27 16:33:37 -07:00
Dirk Hohndel
9ae7040a91 Revert the singleton PR
It turns out that this isn't working the way it was intended to.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-09-27 16:26:58 -07:00
Berthold Stoeger
4d3686edec Cleanup: Pass gpsTrackers directly to GpsListModel::update()
Instead of using the GpsLocation singleton in GpsListModel::update()
to extract the gpsTrackers, pass the gpsTrackers as function argument.

The caller has direct access to the GpsLocation object anyway and this
make things less entangled.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-25 13:35:30 -07:00
Berthold Stoeger
05200f9266 Cleanup: unify idiosyncratic singletons
The way we handle singletons in QML, QML insists on allocating the
objects. This leads to a very idiosyncratic way of handling
singletons: The global instance pointer is set in the constructor.

Unify all these by implementing a "SillySingleton" template. All
of the weird singleton-classes can derive from this template and
don't have to bother with reimplementing the instance() function
with all the safety-checks, etc.

This serves firstly as documentation but also improves debugging
as we will now see wanted and unwanted creation and destruction
of these weird singletons.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-25 13:35:30 -07:00
Berthold Stoeger
9322c54b6a Mobile: pass section directly to tripTitle() and tripShortDate()
Instead of converting the section-heading string to a trip-pointer
in QML and pass that to the tripTitle() and tripShortDate()
functions, pass the string and convert in C++ code.

Hopefully, this makes the code more robust.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-21 16:12:23 -07:00
Berthold Stoeger
ce751bd696 Mobile: pass trip-ids through QML, not formatted pointers
The section heading in the QtQuick ListView has to be a string.
Therefore, we passed a pointer formatted using hexadecimal notation.
Later, that was converted back without being checked.
A very scary proposition, so let's pass unique integer trip-id instead.
This means that on converting back we have to scan the trip table,
but that is a very minor cost comsidering to the gained robustness.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-21 16:12:23 -07:00
Berthold Stoeger
b3e5e5eef4 Cleanup: remove bogus assignment in startFilterDiveSites()
In MultiFilterSortModel::startFilterDiveSites(), the setting of the
dive sites to be filtered is done later in the code. Therefore,
remove the assignment in the first line of the function. Under
some circumstances, this would prevent a needed map reload!

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-21 16:07:24 -07:00
Berthold Stoeger
20e847f9d8 Mobile: Map directly from source in DiveListSortModel::getIdxForId()
Instead of looping over all dives and search the dive with the given
id, let the source model determine the index and map that. Thus,
we do only one mapping and don't generate a ton of DiveObjectHelpers.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
62f1a92068 Mobile: provide direct access to dives in DiveListModel
Accesses were via DiveObjectHelpers. Provide a direct access to
struct dive *. Use this for the filter - there is no point in
mass generating DiveHelperObjects in the filter code.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
ca939300e2 Mobile: create DiveObjectHelper only when needed
In DiveListModel::data() a DiveObjectHelper was created for any
data-access. Create it only when a DiveObjectHelper is actually
returned.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
a4f3580e10 Mobile: remove dive argument from DiveListModel::insertDive()
Since DiveListModel does not keep its own list of dives anymore,
insertDive() doesn't use the DiveObjectHelper argument. Remove it.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
0026aa3955 Mobile: replace clear()/addAllDives() pairs by reload()
The clear()/addAllDives() pair was bogus as the former didn't
clear the model (this is not possible anymore - the model
represents the core dive list) and the latter readded all
dives again.

Replace this by a reload() function.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
57b77c90b9 Cleanup: remove DiveListSortModel::addAllDives()
This function was never used.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
f8c5c8bedf Mobile: Generate DiveObjectHelpers on the fly
Instead of keeping track of a list of DiveObjectHelpers, generate
them on-the-fly in DiveListModel. Thus, there is less danger of
model and core getting out of sync. On the flip-side, now the
DiveListModel and the DiveListSortModel might get out of sync.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
be763452ad DiveObjectHelper: Turn DiveObjectHelper into Q_GADGET based object
DiveObjectHelper is a tiny wrapper around dive * to allow access
to dive data from QML and grantlee. It doesn't have to be a
full-fledged QObject with support for signals, etc. Therefore,
turn it into a Q_GADGET based object. This allows us passing the
object around as object, not as pointer to DiveObjectHelper.
This makes memory-management distinctly easier.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
a79c45e401 Mobile: return depthDuration directly from DiveListModel
We don't want to generate a DiveObjectHelper numerous times for
every item in the dive list. Therefore, return this data directly
from the model. In this case, don't remove from DiveObjectHelper,
as these data might be used by grantlee templates.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
c4831d7ace Mobile: return location directly from DiveListModel
We don't want to generate a DiveObjectHelper numerous times for
every item in the dive list. Therefore, return this datum directly
from the model. In this case, don't remove from DiveObjectHelper,
as this datum might be used by grantlee templates.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
4b389e267d Mobile: return dive-number directly from DiveListModel
We don't want to generate a DiveObjectHelper numerous times for
every item in the dive list. Therefore, return this datum directly
from the model. In this case, don't remove from DiveObjectHelper,
as this datum might be used by grantlee templates.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
bf081866e9 Mobile: return dive-id directly from DiveListModel
We don't want to generate a DiveObjectHelper numerous times for
every item in the dive list. Therefore, return this datum directly
from the model. In this case, don't remove from DiveObjectHelper,
as this datum might be used by grantlee templates.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
c6b3309d13 Mobile: return dateTime directly from DiveListModel
We don't want to generate a DiveObjectHelper numerous times for
every item in the dive list. Therefore, return this data directly
from the model. In this case, don't remove from DiveObjectHelper,
as these data might be used by grantlee templates.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
54720e6cff Mobile: move tripNrDive from DiveObjectHelper to DiveListModel
We don't want to generate a DiveObjectHelper numerous times for
every item in the dive list. Therefore, return this datum directly
from the model.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
1b9581369a Mobile: move tripId from DiveObjectHelper to DiveListModel
The canonical way of displaying lists in Qt is via models.
Thus, return the tripId directly from the DiveListModel instead
of going indirectly via a DiveObjectHelper. In the future, this
will allow us to make the DiveObjectHelper value-based, as it
is not generated numerous times for every list item.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
b7cddcc737 Mobile: remove full-text properties from DiveObjectHelper
These properties are not needed anymore, because the full text search
was decoupled from the DiveObjectHelper.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
37a3daf2dd Mobile: decouple full text search from DiveObjectHelper
1) The full text search was looping over the DiveListModel when
   it could simply loop over the core model. Do that instead.

2) Don't generate a DiveObjectHelper to do a full text search.
   Currently this is harmless as the DiveObjectHelper is only
   a disguised "dive *". But from a conceptual point of view,
   it represents the full representation of a dive and we don't
   want to generate that in a tight loop.

This will help in
1) Making the DiveObjectHelper a non-reference object.
2) Moving fulltext search to the core and thus making it available
   to desktop and more performant.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-14 13:20:59 +02:00
Berthold Stoeger
4706b0f11a Planner: remove planner disclaimer from old notes
There used to be code to remove the old planner notes when replanning
a dive. It used a global variable and seemed rather brittle. Moreover,
the place that set the global variable was inadvertently removed.
Therefore has been effectively dead code.

Reimplement the functionality, but be more robust by considering
that the deco-type may have changed: Split the translated disclaimer
string in two parts, before and after the "%s" place-holder.
Search for these two parts. Remove the disclaimer and everything
after the disclaimer.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-10 21:31:21 +02:00
Berthold Stoeger
7d2fe2b7c6 Cleanup: remove redundant Roles:: qualifier in maplocationmodel.cpp
"Roles" is a C-style enum (i.e. not C++-style enum class). Since that
means that the names spill into the outer namespace, the names
themselves are prefixed with "Role". Nevertheless the code qualified
the names with "Roles::". This is redundant and unnecessary.

Remove this redundancy to show that we understand how the language
works.

Note: we could also transform the enum into an enum class and remove
the "Role" prefix from the names. That would arguably be "cleaner",
but then the enum doesn't auto-convert to/from int, but Qt uses int
to pass the roles to functions. So let's go the simple way that
avoids casting.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
46e120f81a Cleanup: remove includes from maplocationmodel.cpp
Neither "QDebug" nor "algorithm" were necessary.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
c5f355ee8b Cleanup: remove default constructor from MapLocation
Since this is no longer a Q_METATYPE, nobody will try to
default construct this object. Remove the default constructor
and guarantee that there will be no null divesite.

Of course, the lack of default constructor means that the
default argument to the "selected" member variable should
be removed.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
0c374af176 Map: don't derive MapLocation from QObject
Map location is
1) A plain value type
2) Never passed to QML

Make it a simple C++ class.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
4eaf6b20be Cleanup: remove accessor functions from MapLocation
Let's face it: this is a value type. No point in having Java-style
getters and setters. Replace by plain old and boring member variables.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
fe07a47989 Cleanup: remove MapLocation::coordinateChanged signal
Nobody was listening for that signal. Remove it. This, quite
obviously, makse the setCoordinateNoEmit() function redundant.
Merge with setCoordinateNoEmit().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
15f418e046 Cleanup: remove Q_PROPERTIEs from MapLocation
We never dish out an object of this type to QML. It is unclear how
Q_PROPERTIEs could be of any use.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
406e83ac30 Cleanup: remove MapLocationModel::count() and the attribute count
These were not used anywhere and the function was redundant [same
result as rowCount()].

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
b9c35e21ea Cleanup: remove MapLocationModel::get() function
It was not called anymore.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
8e2d3254a2 Cleanup: remove Q_INVOKABLE from MapLocationModel::setSelected()
The function does not appear to be called from QML anymore.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
773604f0df Cleanup: remove MapLocationModel::isSelected() function
That function was replaced by a model-attribute.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
1d01fff006 Map: export isSelected as attribute from MapLocationModel
Recently we changed the MapLocationModel-items to store whether
they are selected. Thus, we can directly export an isSelected
flag instead of calling a function taking a dive-site argument.

1) This makes the QML easier to read.
2) This avoids passing pointers through QML which has caused
   us lots of pain.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
9322092e41 Cleanup: simplify role handling in MapLocationModel
To connect a model to QML, one is supposed to provide a
  QHash<int, QByteArray> MapLocationModel::roleNames()
function that returns a role -> attribute-name hash.

That was realized by filling the hash in the constructor,
storing it as a member variable, using static strings that
were declared in the class-definition and defined in the
translation unit.

Adding a new role was a pain and the whole thing was totally
pointless as the attribute names were used nowhere else and
the roleNames() function is called only once.

Simply do, what we do everywhere else: initialize the hash
in the roleNames() function and use normal string literals.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
f27d440bb3 Dive site: don't emit divesChanged signals when editing dive site
When editing the dive site, for certain fields a divesChanged signal
was emitted so that the dive-list can be updated.

Arguably it is wrong to decide which fields are relevant to the
dive list in the undo-command code. Therefore, let the list
catch the dive-site-edited signal and decide itself.

But the actual reason for this commit is that if the dive-site
field of a dive changes, we might have to reload the dive-location-model
because suddenly a new dive site appears. Now if this is done
in QML context on some Qt version (notably 5.9) we get crashes
later on. But that can happen if the user moves a flag. So in that
case only send a diveSiteChanged signal.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
093adf1ea8 Map: highlight correct dive sites in dive site mode
Since changing the highlighting to use the selected dive, dive
sites with no dive were never highlighted in dive site mode.
Obviously, because there was no dive to be selected.

Therefore special-case all dive-site selection code to recognize
when we are in dive site mode.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
fc706a0d72 Filter: reload map on myInvalidate
Since selection change doesn't to a full map reload, we have to
reload the map on filter changes, since the shown dive sites change.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
652b78657e Map: calculate the z value in the model
Since not fully reloading the map on selection change,
the selected sites were not moved to the top. Not calculating
the z-value in QML, but making it a simple model property
helps.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
488eb15423 Desktop: show all selected dive sites on click
When clicking a dive site on the map, the QML code would set
the selected dive site, but then all dives of dive sites in
the vicinity were set. But still only the clicked-on dive site
was shown.

Therefore, don't set the list of selected dive sites in QML,
but later in DiveListView::selectDives(), where we know all
the dives that were selected.

This, again, gives nasty entanglement of diverse widgets and
models.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
b39f2406c6 Map: don't fully reset model on selection change
When changing the selection the MapLocationModel was reset.
This lead to crashes on Qt-5.9 which are due to QML accessing
data that was freed during model reset. This putative Qt bug
doesn't happen on newer Qt versions. At least Qt-5.12 is known
to work.

Instead of fighting the bug, let's simply not reset the model
but send a dataChanged() for every element of the MapLocationModel.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
bce31ab862 Map: generate pixmap name in model
Experimentation has shown that the image of a flag will
only be changed after dataChanged() if it is a simple
property. The old code had a complex QML expression and
then - for some reason - it didn't work.

To give us better control over the flags and avoid full
reloads of the map therefore introduce a model-property
pixmap name. The name depends on whether the site is
selected and if not, whether we are in divesite-edit mode.
This makes the code rather convoluted. Firstly, we have
to save whether the site is selected in the map-item.
Secondly we have to access the global map-widget, which
in turn has to go to the map-widget helper (layering
violation!).

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
28cb75b73d Map: explicitly reload selected map on click
When clicking on a flag
 1) The QML would call MapLocationModel::setSelected() with
    fromClick = true
 2) MapLocationModel::setSelected() would emit a signal
    selectedLocationChanged()
 3) MapWidgetHelper would catch that signal and do the actual
    processing.
Other functions would call MapLocationModel::setSelected() with
fromClick = false, which would not emit the selectedLocationChanged()
signal.

Detangle this a bit by calling the selectedLocationChanged() function
directly from QML and remove the fromClick parameter.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-09-06 11:48:47 -07:00
Berthold Stoeger
b3fd824d18 Map: catch null divesites in map widget selection code
Just to be sure, refuse to add null divesites to the selection.

Moreover, refuse to call the setSelected function on a null-divesite.
I got an unfriendly Qt-Warning there:

"Passing incompatible arguments to C++ functions from JavaScript is
dangerous and deprecated."
"This will throw a JavaScript TypeError in future releases of Qt!"

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-08-28 07:12:01 -07:00
Berthold Stoeger
25b30da244 Profile: properly initialize plot_info structures
The create_plot_info_new() function releases old plot data. This
can only work if the plot_info structure was initialized previously.
The ProfileWidget2 did that by a memset, but other parts of the code
did not.

Therefore, introduce a init_plot_info() function and call that when
generating a plot_info struct. Constructors would make this so much
easier - but since this is called from C, we can't use them.

Fixes #2251

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-08-28 07:10:09 -07:00
Berthold Stoeger
14dd93b655 Mobile: fix bound check in DiveListModel::data()
Indexes go from 0 to count - 1. Thus, the comparison for invalid
indexes has to read ">= count", not "> count".

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-08-13 07:27:48 -07:00
Berthold Stoeger
f18ea2e3b6 Location model: treat invalid indexes gracefully
There have been crash reports in DiveSiteSortedModel::allSiteNames().
The only conceivable reason that this crashes is that the core knows
about more sites than the model and therefore on mapToSource() we
get an invalid index, which is translated to -1. Accessing the name
of that dive site will crash.

Handle such invalid indexes gracefully.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-08-10 09:55:11 -07:00
Berthold Stoeger
00944f7a02 Core: pass dive, cylinder-id to fill_default_cylinder
The fill_default_cylinder() function calculated the MOD based
on the currently displayed dive. This does not seem to make sense:
- When importing dives, why would we care about the altitude and
  salinity of the currently displayed dive, possibly from a different
  trip.
- The planner is supposed to be thread-safe and should not touch
  global variables.

Of course this means that the importing-functions have to fill
out altitude and salinity before creating the default cylinder,
but this is their problem. For a freshly created dive they will
get the default values, which still seems less random than the
values from the displayed dive.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-08-08 16:26:31 -07:00
Berthold Stoeger
52e5d9c605 Cleanup: move planner/deco related declarations planner/deco.h
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-08-08 16:26:31 -07:00
Berthold Stoeger
b0f1b25806 Crash fix: prevent crash in MapLocationModel::reload
Commit 0c38754916 introduced a
bug in MapLocationModel::reload() by setting an entry in the
name-to-location map before the location was initialized.

Move the setting of the map entry back where it was before:
after the assignment of the location variable.

Moreover, define the location variable directly on allocation
of the location to avoid thus bugs in the future.

Why did we not get a "might be used unitialized" warning
anyway?

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-07-27 14:57:31 -07:00
Berthold Stoeger
726d08c2f7 Undo: make editing of dive number undoable
When pressing F2 in the dive list, the number can be edited.
Make this action undoable by implementing a EditNumber command.

This command is differs from the other undo commands, as not the
currently selected dives are changed. This means that the EditCommand
needs an alternative constructor taking a single dive. This constructor
was implemented in the base class so that all edit commands can now
be called with a single dive.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-07-19 21:44:13 -07:00
Berthold Stoeger
a5e7f4253a Core: dynamically resize weight table
Replace the fixed-size weightsystem table by a dynamically
relocated table. Reuse the table-macros used in other parts
of the code.

The table stores weightsystem entries, not pointers to
weightsystems. Thus, ownership of the description string is
taken when adding a weightsystem. An extra function adds
a cloned weightsystem at the end of the table.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-07-18 06:01:07 -07:00
Berthold Stoeger
8f119dcf72 Cleanup: remove includes from qthelper.h
To reduce interdependencies, remove the dive.h and divelist.h
includes in qthelper.h

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-07-18 05:42:55 -07:00
Berthold Stoeger
0136d76cf4 Cleanup: move deco function declarations to deco.h
Another tiny step in making dive.h smaller: move function
declarations to deco.h if these functions are defined in deco.c
and don't directly concern dives.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-07-18 05:42:55 -07:00
Berthold Stoeger
16214e753a Cleanup: remove includes from qt-models/models.h
qt-models/models.h included dive.h and divelist.h. Remove these
unnecessary includes, to reduce interdependencies. A drop in the
bucket, for sure.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-07-18 05:42:55 -07:00
Berthold Stoeger
2e230da361 Cleanup: unify selection signals
For historic reasons, there where three distinct signals concerning
dive-selection from the undo-machinery:
1) divesSelected: sent newly selected dives
2) currentDiveChanged: sent if the current dive changed
3) selectionChanged: sent at the end of a command if either the selection
   or the current dive changed

Since now the undo-commands do a full reset of the selection, merge these
three signals into a single signal.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-23 20:08:46 +02:00
Berthold Stoeger
e1abf9485c Undo: unify selection behavior in dive-list commands
Some commands tried to retain the current selection on undo/redo,
others set the selection to the modified dives.

The latter was introduced because it was easier in some cases, but
it is probably more user-friendly because the user gets feedback
on the change.

Therefore, unify to always select the affected dives on undo()/redo().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-23 20:08:46 +02:00
Berthold Stoeger
27944a52b1 Undo: don't send signals batched by trip
Since the default view is batched by trips, signals were sent trip-wise.
This seemed like a good idea at first, but when more and more parts used
these signals, it became a burden. Therefore push the batching to the
part of the code where it is needed: the trip view.

The divesAdded and divesDeleted are not yet converted, because these
are combined with trip addition/deletion. This should also be detangled,
but not now.

Since the dive-lists were sorted in the processByTrip function, the
dive-list model now does its own sorting. This will have to be
audited.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-23 20:08:46 +02:00
Berthold Stoeger
cbcddaa396 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>
2019-06-23 20:08:46 +02:00
Berthold Stoeger
38ba434966 Cleanup: return directly from data() methods
There is this anti-pattern in QModel data() functions to assign
to a "ret" variable and return at the end of the function. This
is inefficient, as the object is not directly constructed at
the space reserved by the caller.

Change the functions in WeightModel and CylinderModel to return
the objects directly.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-19 13:11:10 -07:00
Berthold Stoeger
7f4d9db962 Cleanup: move trip-related functions into own translation unit
These functions were spread out over dive.c and divelist.c.
Move them into their own file to make all this a bit less monolithic.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-19 13:11:10 -07:00
Berthold Stoeger
6200909ba4 Cleanup: move tag functions into own translation unit
Make dive.h a bit slimmer. It's only a drop in the bucket - but at
least when modifying tag functions not the *whole* application is
rebuilt anymore.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-06-19 13:11:10 -07:00
Berthold Stoeger
879f52180c Cleanup: fix a few comments and debug messages
This is just minor fixes that are not user-visible:
Fix a few erroneous comments and a debug message. These are
copy & paste mistakes and mistakes introduced during code-
refactoring.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-20 21:23:16 -07:00
Dirk Hohndel
2feedf46fa Cleanup: small coding style fixes
And addressing a cut and paste error in a comment.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2019-05-15 07:42:14 -07:00
Berthold Stoeger
e362afe43c Cleanup: remove UTF8 macros
At some places we use UTF8 string literals. Therefore, we effectively
only support UTF8 build systems. We might just as well remove all
the other UTF_* macros and use direct string literals.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-12 12:25:43 -07:00
Berthold Stoeger
44c65fec88 Map: automatically update names on the map
Currently, dive site names are only updated on full reload.
Instead hook directly into the corresponding signal in the
MapLocationModel to set the name. Also to the coordinates
directly there instead of going via the MapWidgetHelper.

In the MapWidgetHelper, just center on the changed dive site.
Hook into the signal directly there and remove the slot
from the MapWidget. This makes the whole call-chain at least
one call shorter.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-11 12:06:19 -07:00
Berthold Stoeger
0da86dfd86 Map: in edit mode place no-gps dive sites at center of map
Move the code to add the first selected dive site from
MapWidgetHelper::enterEditMode() to MapLocationModel::reload().

Thus, the list of sites is built only at one place. For this
it is necessary to pass a pointer to the map, so that new
dive sites can be added at the center of the map.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-11 12:06:19 -07:00
Berthold Stoeger
0c38754916 Map: construct list of dive sites from dive site table
Instead of looping over the dive table and extract dive sites,
loop over the dive site table.

This makes it possible to show dive sites that have no dive
associated with them.

But we have to create to functions that check whether a dive
site has any shown dives or has any selected dives.

Moreover, change the code to add near dive sites of the same
name if in edit mode. Other wise (erroneously added?) dive
sites with the same name cannot be moved on the map.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-11 12:06:19 -07:00
Berthold Stoeger
29c6aea797 Filter: prevent selection-change notifications in filter invalidation
Invalidating the filter can cause numerous selection-change notifications.
These cause a full UI reload. Therefore, go into "command" mode that was
implemented for the undo commands. Then, all selection-changes are
considered as "programmatical" and ignored.

At the end of filter invalidation, a filter-finished signal causes a
proper reload anyway.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-11 12:06:19 -07:00
Berthold Stoeger
83926213ea Filter: don't reload when dive sites are set to the same value
When switching between the dive-site-table to the dive-site-edit
tabs, the filter would be set to a dive site. Usually, this would
be the same dive site as before. Nevertheless, this caused a full
map-reload. Detect if the dive-sites to be filtered are the same
and turn this operation into a no-op.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-11 12:06:19 -07:00
Berthold Stoeger
065423896d Filter: add reference counting for dive-site mode
The dive-site-edit and dive-site-table tabs both put the filter
into a special dive-site mode. When switching between both, it
could happen that the one got its show befor the other got
its hide event.

Thus, the first would start dive-site filtering and the second
stop it. Now the app was not in filter mode even though it should.

To solve this problem, add reference counting for the filter's
dive-site mode. In both tabs call the enter/exit functions
on show/hide. In the dive-site-table tab, when the selection
changes, use a set function that doesn't modify the reference count.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-11 12:06:19 -07:00
Berthold Stoeger
cd5489e08d Map: in dive-site-edit mode, select those maps we filter for
When dive sites are edited, we shouldn't highlight the sites
of the current dive, but the currently edited site(s).

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-11 12:06:19 -07:00
Berthold Stoeger
d29f82c52d Map: make edit mode depend on dive-site-filtering
Since the dive-site-filter is active either on the dive-site-edit
page or the dive-site-list page, use that as the flag for dive-site-edit
mode. Moreover, when the filter is reset, the
MapWidgetHelper::reloadMapLocations() function is called, so we
can use that place to enter/exit edit mode.

This makes it easier to keep everything consistent.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-11 12:06:19 -07:00
Berthold Stoeger
a35d1bd0e7 Map: show multiple selected dive sites
If multiple dives are selected, highlight all corresponding sites.
For that, replace the MapLocationModel::m_selectedDs pointer by
a QVector<>. Fill the vector in MapLocationModel::reload() and
add a isSelected() member function.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-11 12:06:19 -07:00
Berthold Stoeger
446dfed6e7 Map: move calculation of list from map-helper to map-model
The map model keeps track of the dive site positions on the
map. Therefore, it seems more logical to have the code calculating
the map position in the model, not in the helper-class.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-11 12:06:19 -07:00
Berthold Stoeger
3e05d61eb9 Map: show all dive sites when in dive-site filter mode
When on the dive site tab or editing a dive site, we want
to show all dive sites so that the user can related different
dive sites. Therefore export a "in dive site mode" flag from
the filter model and don't filter in that case in MapWidgetHelper.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-05-11 12:06:19 -07:00
Doug Junkins
00ec824129 Create DivesiteImportDialog to select sites to import
Creates the dialog box to select which sites to import from the file
selected in mainwindow.cpp. The DivesiteImportModel is created as a
table to display and select which sites are to be imported. Once the
sites are selected, the Command::importDiveSites command is called to
add the sites to the core dive site table with undo/redo functions.

Signed-off-by: Doug Junkins <junkins@foghead.com>
2019-05-06 10:48:44 +02:00
Berthold Stoeger
cab0147093 Cleanup: implement proper Qt-model semantics in WeightInfoModel
- Use a beginResetModel()/endResetModel() pair instead of distinct
addRows / removeRows pairs.

- Reuse the update function in the constructor().

- Let "rows" be the number of rows, not the number of rows minus one.

- Remove updateInfo() function as it does the same as update().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-04-29 13:06:39 -07:00
Berthold Stoeger
36d8dcc3bf Cleanup: implement proper Qt-model semantics in TankInfoModel
- Use a beginResetModel()/endResetModel() pair instead of distinct
addRows / removeRows pairs.

- Reuse the update function in the constructor().

- Let "rows" be the number of rows, not the number of rows minus one.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-04-29 13:06:39 -07:00
Berthold Stoeger
4f0fd86d35 Cleanup: remove biggerString() functions
The TankInfoModel and WeightInfoModel had biggerString() functions
to determine the correct column widths for the tank- and weight-type
columns. The users were removed around 2013. Remove these functions
and the corresponding member variable.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-04-29 13:06:39 -07:00
Robert C. Helling
52105e5217 Write dive data as video subtitles
This commit adds an entry to the dive media context
menu which offers to write a subtitle file. This
creates an .ass file for the selected videos.

In an attempt to to clutter the screen too much, don't
show irrelevant entries (zero temperature or
NDL and show TTS only for dives with stops).

VLC is able to show these subtitles directly, they
can be integrated into the video file with ffmpeg.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2019-04-16 20:38:19 +02:00
Berthold Stoeger
88dc32fdfc Core: turn add_single_dive() to append_dive()
The only external caller of add_single_dive() used it to append a
dive to the global dive list. Rename the function accordingly and
remove the index parameter.

The internal caller can use the local insert_dive() function, which
doesn't consider selection. That shouldn't be a problem, as the
caller is doing import.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-04-15 10:24:31 +12:00
Berthold Stoeger
8695d8bdb1 Dive sites: show dives at selected dive sites
When in dive site tab and some dive sites are selected, show only
dives at those sites. Simply read the selection and pass it to the
filter.

Start and stop filtering when switching to and from the tab,
respectively.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-04-12 18:19:07 +03:00