Commit graph

955 commits

Author SHA1 Message Date
Berthold Stoeger
02ef58a48b cleanup: remove pointless cylinder model update
In DivePlannerPointsModel::clear(), the cylinder model is
updated before it is cleared. This must be an artifact.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
891839d254 planner: move same-time check to DivePlannerPointsModel
There must not be two dive planner points at the same time
stamp, as this violates the laws of physics (and internal
assumptions).

The corresponding test was done in the profile code at
two different places with floating point arithmetics.
This is a bad idea, because
1) code duplication
2) danger of rounding issues

Instead, do this in one central point in the planner model
and use integer arithmetics. Simply add a few seconds until
a unique timestamp is obtained.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
dee1fea683 planner: implement move semantics in DivePlannerPointsModel
When reordering the points, the DivePlannerPointsModel would
not emit the appropriate move signals, but simply a data-changed
signal over all elements. This obviously violates Qt's
model/view API, though it is probably harmless. Let's do
the right thing so that the frontend knows that the selected
item changed place.

Also, emit dataChanged only on the actually changed element,
not all elements.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
1b14a211f0 planner: fix removal of points from DivePlannerPointsModel
The beginRemoveRows() function was fed erroneous values. It
is a mystery why this didn't crash. In any case, deletion
of multiple points did not work properly. Instead of trying
to be fancy, remove each point one-by-one.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
35c5ec09b7 planner: insert point at correct position
Instead of inserting the point at the calculated
position, the DivePlannerPointsModel would append it
at the end and then resort the vector. That's just
silly.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
1e525244e6 cleanup: use proper model/view semantics in DivePlannerModel
When clearing the model, use "beginResetModel/endResetModel"
instead of "beginRemoveRows/endRemoveRows".

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
d68c3d8ab5 cleanup: add DivePlannerPointsModel::addDefaultStop() function
When clicking on "+" in the planner, a default stop point was
added using a signal/slot connection. This used the archaic
string-based connect syntax, because it was realized with
default parameters passed to "addStop()". Instead, add a
"addDefaultStop()" slot, which passes the default parameters.
Since all other callers do not use callbacks, unslotify
"addStop()". The slot was the only user of the default parameters,
so they can be removed alltogether.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
5196ea6149 cleanup: constify DivePlannerPoints model accessor functions
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
216a910f56 planner: unslotify two functions in DivePlannerPointsModel
There are a few more candidates, but these conceptually really
shouldn't be slots. getSurfacePressure() is an accessor and
loadFromDive() initializes the model with a dive.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
a988e3c135 core: initialize dive selection after resetting the data
The dive selection was initialized during data-reset. However,
this emitted a signal before all data-reset routines were run.
Ultimately, this led to access-after-free in the statistics code.

Instead, move the select_newest_visible_dive() signal from the
divelist-model to the process_loaded_dives() function. There
is no point in initializing the selection if the dive data
is cleared after all.

This change broke closing of the log, because the UI-selection
was not reset. Therefore, when clearing the data, clear the
selection before proceeding with clearing.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-03-31 13:54:23 +02:00
Berthold Stoeger
642d9c80b3 planner: pass in_planner argument to decoMode()
To remove reliance on global state, pass an "in_planner" argument
to decoMode(). Thus, calls to in_planner() can be removed.

This is a more-or-less automated change. Ultimately it would
probably be better to pass the current deco-mode to the affected
functions instead of calling decoMode() with an in_planner
parameter.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-02-17 07:26:55 -08:00
Berthold Stoeger
b3e4c9c8da desktop: cache photo and geo icons
The icons shown in the dive list were rendered for every single
access. Render them only once. This supposes that the
defaultIconMetrics structure does not change once the icons are
rendered!

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-02-10 14:33:15 -08:00
Berthold Stoeger
e79ac9c7ed cleanup: make a few DivePlannerModel functions private
It simplifies reasoning about control flow a lot if it is known
that functions can't be invoked from a different part of the code
base.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 10:01:50 -08:00
Berthold Stoeger
5e1dcb0655 cleanup: remove dive parameter from DivePlotDataModel::setDive()
This was not used, probably an artifact from days long gone.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 10:01:50 -08:00
Berthold Stoeger
764aa6c512 planner: remove DivePlannerPointsModel::startTimeChanged signal
The way the starting time of a new plan was set was bonkers:

1) PlannerWidgets::planDive() invokes DivePlannerPointsModel::
   createSimpleDive().

2) createSimpleDive() calls DivePlannerPointsModel::
   setupStartTime()

3) setupStartTime() emits a signal startTimeChanged()

4) startTimeChanged is caught by PlannerWidget and sets
   the UI field

5) change of the UI field emits a timeChanged() signal which
   is connected to DivePlannerPointsModel::setStartTime()

6) setStartTime() sets the time of the plan and displayed_dive
   and emits dataChanged()

7) dataChanged() replots the dive()

8) Back in DivePlannerPointsModel::createSimpleDive() the diveplan
   start time is overwritten with displayed_dive (the value are
   equal owing to 6)

Wow!

But it gets worse:

9) The initial dive plan is set up in createSimpleDive().

Since the profile is drawn in 7) after clearing the displayed_dive
and before constructing the initial plan, the profile is shown
on a dive without samples. It therefore generates a dummy profile.

To make this somewhat less insane, remove the startTimeChanged()
signal in 3), explicitly set the start time of plan and dive to
the one calculated by setupStartTime() and explicitly set the UI
filed in the plannerWidget.

This still indirectly draws the profile via signals in a convoluted
way, but at it straightens out things somewhat. Most importantly,
the profile doesn't have to generate a fake DC.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-20 10:01:50 -08:00
Dirk Hohndel
4c5997bcbe mobile/cleanup: reduce the noise in our logs
There are two sets of messages that tend to dominate the logs
- the RSSI updates from the Qt BLE stack
- the warnings about deprecated signal use in Kirigami

Neither of them provide any value to us when trying to find bugs; and
often they end up hiding the things that we really care about. So let's
just not log them - which is easy as we have our own message handler.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-01-13 16:16:31 -08:00
Berthold Stoeger
235146a95f profile: pass dive to DiveHandler
The DiveHandler shows a context menu where a cylinder can be
chosen. This indirectly accesses the global displayed_dive
variable.

Remove this in a step to make the profile reentrant.

The code was quite ominous: instead of simply generating the
list of cylinders, a global model was reset and then accessed
with Qt's cumbersome model/view API. All this trampling over
global state can be removed by simply making the function
that generates the list globally accessible.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 15:57:39 -08:00
Berthold Stoeger
0104b0a915 profile: explicitly update profile items
Instead of listening to the dive-data-model changed and
axis changed signals, update the profile items explicitly
once per plot() call. This avoids double replotting of the
dive items.

The old code had at least two replots per plot() call:
one after profileYAxis()->setMaximum() and one after
dataModel->emitDataChanged().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 15:57:39 -08:00
Berthold Stoeger
f4103e4998 cleanup: const-ify DivePlotDataModel::*max() functions
These functions return the maximum partial pressures in the
given dive. Obviously, being pure accessors, they should be
const.

This commit also replaces the macro generating these functions
by a call to a function taking a pointer-to-member. Arguably,
C++'s pointer-to-member syntax is just as horrible as macros,
but at least it doesn't mess with syntax highlighting of
my editor and should be better to debug.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 15:57:39 -08:00
Berthold Stoeger
975c123a30 profile: remove redundant code in DiveCalculatedCeiling
The DiveCalculatedCeiling profile-item has a recalc()
function, which calls "dataModel->calculateDecompression()".
This is a questionable reversal of control-flow: The
profile-item should paint the model-data not change it.

The code was supposed to be called under two conditions:

1) The value of the calcceiling3m preferences flag changed.
   This code was buggy for two reasons: Firstly, the cached
   value was always initialized to false, which means that
   sometimes the first call was missed. Secondly, the
   settingsChanged() functions was only called when closing
   the preferences window, not when changing the flag in the
   profile widgets.

2) The datetime of the dive changed. The whole control-flow is
   pretty absurd (due to "bit rot"):
     - The replan-dive command sends a date-time changed signal.
     - The main tab changes the date-time and informs the profile.
     - The profile sends a signal to the item.
     - The item instructs the model to recalculate the
       decompression.
     - The model causes the profile to be redrawn.

In any case, the whole thing is moot, because the decompression
is recalculated for *every* profile plot in create_plot_info_new().

Let's remove the code from the DiveCalculatedCeiling profile-item
and the calculateDecompression() function, which is now not
used anymore.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-01-10 15:57:39 -08:00
Dirk Hohndel
2a579987c2 fix potential crash in GPS code
If we don't have a GpsLocation instance, we shouldn't dereference it.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-01-01 12:38:50 -08:00
Berthold Stoeger
bbbd4c8818 cleanup: remove getDivesInTrip() in qthelper.cpp
This function was not used anywhere. Moreover, remove a few
unused includes from qthelper.h. Surprisingly, a number of users
of qthelper.h depend on these, so readd them at the appropriate
places.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-29 08:34:09 -08:00
Berthold Stoeger
c53bab8965 filter: internalize shown_dives in DiveFilter class
one piece of global state removed!

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-29 08:34:09 -08:00
Berthold Stoeger
51d0c42a5c filter: move shown_dive from divelist.c to divefilter.cpp
Arguably, the number of filtered dives is a matter of the divefilter.
Let's move it there.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-29 08:34:09 -08:00
Berthold Stoeger
e80c0d2c60 filter: reset shown_dives in filter
The shown_dives variable was reset by the dive_list code. Arguably,
the filter should keep track of the number of shown dives, so move
the resetting there. This means adding a new "reset()" member function
to the filter and call that instead of "updateAll()" when the core
data is reset.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-29 08:34:09 -08:00
Berthold Stoeger
1037c15b98 mobile: remove DiveObjectHelper code
When editing a dive, a DiveObjectHelper of the unmodified dive
was created to compare the edited with the old values. Since
the DiveObjectHelper is used here only as a pointless wrapper
around the formatting functions, call these functions directly.

However, note that the code is in principle wrong since the
change to the mobile-models, which do not use the DiveObjectHelper.
The real fix would be to reload the data from the model to prevent
going out-of-sync with respect to the formatting routines!

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-17 13:03:56 -08:00
Berthold Stoeger
ae182c386b printing: remove DiveObjectHelper from printing code
At this point (post grantlee), DiveObjectHelper is just pointless
glue code. Let's remove it from the printing code and call the
formatting functions directly. If necessary, move these functions
to core/string-format.cpp.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-17 13:03:56 -08:00
Berthold Stoeger
bf8261c001 core: create string-format.cpp source file
The mobile version of the list used string formatting functions
defined in DiveObjectHelper and declared in mobilelistmodels.h.
Very confusing. Move them to a separate source file where - in
the long run - all the string-formatting functions, which
are scattered all over the place, can be collected.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-12-17 13:03:56 -08:00
Berthold Stoeger
50b11024d6 core: keep tank infos in a dynamic table
The list of known tank types were kept in a fixed size table.
Instead, use a dynamic table with our horrendous table macros.
This is more flexible and sensible.

While doing this, clean up the TankInfoModel, which was leaking
memory.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-13 11:49:59 -08:00
Berthold Stoeger
2d7be7a0e3 preferences: create global settingsChanged signal
So far, the PreferencesDialog emitted a settingsChanged signal.
This meant that models that listened to that signal had to
conditionally compile out the code for mobile or the connection
had to be made in MainWindow.

Instead, introduce a global signal that does this and move
the connects to the listeners to remove inter-dependencies.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-12-12 15:52:40 -08:00
Robert C. Helling
40311362f3 downloader: save downloaded dives
Signed-off-by: Robert C. Helling <helling@atdotde.de>
2020-12-03 13:26:55 -08:00
Robert C. Helling
5e34531e32 downloader: wait for download thread
Signed-off-by: Robert C. Helling <helling@atdotde.de>
2020-12-03 13:26:55 -08:00
Dirk Hohndel
5a8db97819 build-system: add models and shared backends to the downloader
We'll need this in order to be able to actually open dive files and
download things from a dive computer.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-12-03 13:26:55 -08:00
Berthold Stoeger
b36178a00a cylindermodel: remove in_planner() use
in_planner() is problematic, since it is uses desktop-only
application state. Since the cylinder-model already has
an appropriate inPlanner flag, use this instead.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-11-24 10:54:10 +01:00
Berthold Stoeger
e47b812fd0 diveplannermodel: replace in_planner() by isPlanner()
The in_planner() function is problematic, because it depends
on the application state that is only available on desktop.
If we ever want to port the planner to mobile, we have to get
rid of it. Luckily, the DivePlannerModel already has an
appropriate flag that can be used instead.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-11-24 10:54:10 +01:00
Berthold Stoeger
38a784f5af desktop: automatically reload completion-models
Instead of programatically reload the completion models, listen
to the relevant signals in the models. To that goal, derive all
the models from a base class.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-11-14 10:01:50 -08:00
Berthold Stoeger
67d956b44c cleanup: remove macros from qt-models/completionmodels.cpp
There were macros to auto-generate functions to reload the models.
One was only used once and therefore is pointless. The other can
be replaced by a function with a pointer-to-member-variable argument.

While doing this, adapt the coding style.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-11-14 10:01:50 -08:00
Berthold Stoeger
396598430b desktop: fix saving of column-widths of device and site tables
Qt's memory management scheme is completely broken and messes
with common expectations.

QObjects are organized as a tree. The children are destroyed
in the destructor of QObject. This means that they are destructed
after the destructor of the parent object has run and its
sub-object were destructed. Obviously, this makes no sense as
the child objects should be able to access their parent at
any time.

To restore the commonly expected deterministic order of
construction and destruction, one might simply do away with
Qt's silly object tree and organise things using classical
subobjects. However, that breaks with the Qt-generated UI
classes: The objects generated by these classes are *not*
destructed with the UI class. Instead, they are attached
to the widget's QObject tree. Thus these are again destructed
*after* the widget! Who comes up with such a scheme?

In our case this means that we cannot have models used for
TableViews as subobjects, because the TableView needs the
model to save the column widths in the destructor. Which,
as detailed above is called *after* the desctructor of the
widget! Thus, turn these models into heap-allocated objects
and add them to the QObject tree.

Funilly, this exposes another insanity of Qt's QObject tree:
Children are destructed in order of construction! One would
expect that if objects are constructed in the sequence
A, B, C one can expect that C can, at any time, access B and A.
Not so in Qt: The destruction order is likewise A, B, C!

Thus, take care to init the widgets before the model. Jeez.

Finally, print a warning in the column-saving code of
TableWidget, so that these kind of subtleties are caught
in the future.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-11-07 11:37:51 -08:00
Dirk Hohndel
ffecc00f42 cleanup: SkipEmptyParts syntax has changed
Sadly, the new enum has only been available since Qt 5.14, so this is a rather
ugly replacement.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-10-26 19:27:03 -07:00
Berthold Stoeger
0e196310f9 cleanup: split out divecomputer functions from dive.c
Since dive.c is so huge, split out divecomputer-related functions
into divecomputer.[c|h], sample.[c|h] and extradata.[c|h].

This does not give huge compile time improvements, since
struct dive contains a struct divecomputer and therefore
dive.h has to include divecomputer.h. However, it make things
distinctly more clear.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-25 13:59:52 -07:00
Berthold Stoeger
d82a7b8b73 cleanup: remove DiveComputerModel::remove
This was used by the DiveComputerDialog, which does not exist
anymore. The new tab uses the function in the corresponding
sorted model.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-25 13:59:04 -07:00
Berthold Stoeger
c6188bbe47 devices: connect DiveComputerModel to undo-command
Instead of modifying the device table directly, call the undo
commands. Moreover, don't keep our own copy in the mode - show
the original version. Connect to the appropriate signals.

This means that the calls from the DiveComputerManagement
dialog have to be removed, since this mode of editing is
not supported. The whole dialog will be removed in a future
commit.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-25 13:59:04 -07:00
Berthold Stoeger
4467477389 models: update DiveComputerModel when core data is reset
To implement undo-semantics, we want a longer-lived dive-computer-model
(currently, it is regenerated when the dialog is opened). Therefore, it
must be reloaded when the core data is reset. Do this like for other
models: listen to the dataReset() signal of DiveListNotifier.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-25 13:59:04 -07:00
Berthold Stoeger
fa7dfa3710 desktop: add tab-widget for dive computer names
If we want to include dive computer names in the undo system,
there should be visual feedback on undo/redo.

This would mean opening the divecomputer dialog, which would
appear quite strange. Therefore, add a tab. This is not ideal,
but consistent with the dive site tab, which probably shouldn't
be there either. In the future, the UI needs some rethinking.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-25 13:59:04 -07:00
Dirk Hohndel
e30ba8a8e0 cleanup: fix over-eager Coverity warnings
Technically get_dive(i) could return a nullptr. But given the range for i that
can never happen. Still, the test is extremely cheap and doesn't hurt.

Fixes CID 354768
Fixes CID 354766

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2020-10-25 13:58:03 -07:00
Berthold Stoeger
2bcb3d88a0 divecomputer: add device_table pointer to device_data_t
In one weird case (suunto), the code in libdivecomputer.c
generates a device node directly instead of going the usual
way (setting the data in the dc-structure of the imported
dive). It is unclear to me whether that has to be that way,
as it depends on the chronological order of callbacks to
event_cb() and dive_cb().

Therefore add a device_table pointer to device_data_t
so that the downloader can add the device to this table. This
only adds the pointer, but does not yet use it in the
downloading code.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-24 09:51:37 -07:00
Berthold Stoeger
39a4090c0a devices: add devices in Command::importTable()
Add a device_table parameters to Command::importTable() and
add_imported_dives(). The content of this table will be added
to the global device list (respectively removed on undo).

This is currently a no-op, as the parser doesn't yet fill
out the device table, but adds devices directly to the global
device table.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-24 09:51:37 -07:00
Berthold Stoeger
4a50badb57 cleanup: use std::vector in struct device_table
Since we converted from QString to std::string, let's also use
std::vector instead of QVector. We don't need COW semantics
and all the rigmarole. Let's try to keep Qt data structures
out of the core.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-16 14:26:37 -07:00
Berthold Stoeger
fd8bd9d5c7 cleanup: use std::string in struct device
struct device is a core data structure and therefore shouldn't use QString.
QString stores as UTF-16 (which is a very questionable choice in itself).
However, the real problem is that this puts us in lifetime-management
hell when interfacing with C code: The UTF-16 has to be converted to
UTF-8, but when returning such a string, this puts burden on the caller
who has to free it. In fact, instead of looping over devices from C-code
we had a callback that sent down temporary C-strings with qPrintable.

In contrast, std::string is guaranteed to store its data as
contiguous null-terminated and C-compatible strings. Therefore,
replace the QString by std::string. Keep the QString just in
one place that formats a hexadecimal number to avoid any
potential change.

The disadvantage of using std::string is that it will crash
when constructed with a NULL argument, consistent with C-style
functions such as strcmp, etc. Arguably, NULL is different
from the empty string even though we treat both as the same.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-16 14:26:37 -07:00
Berthold Stoeger
215e5a4544 desktop: make divecomputer table sortable
Add a small proxy-model on top of DiveComputerModel so that clicking
on table headers makes the table sortable.

The UI feature here is not as important as the fact that the UI does
its own sorting and we can keep the device-table in the core sorted
differently.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2020-10-11 08:35:20 -07:00