Commit graph

18695 commits

Author SHA1 Message Date
Berthold Stoeger
8939b6a99b profile: remove enableToolbar() signal
When showing the "empty-state", the profile toolbar was
disabled. This was done via a "reverse" signal from the
profile to the MainWindow. Instead control the toolbar
in the MainWindow directly. Break out the plot-dive
functionality into a member function and there test
whether a dive is shown or not.

The signal makes no sense in the context of mobile
or printing.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-10 14:15:35 -07:00
Berthold Stoeger
8c72ac6b9b profile: remove force parameter from ProfileWidget2::plotDive()
The last user was removed in 2789bb05b1.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-10 14:15:35 -07:00
Berthold Stoeger
4daf687876 profile: remove [disable|enable]Shortcuts() signals
When switching to the "plan" or "add" (which should rather be
called "edit", by the way) mode of the profile, the "shortcuts"
for copy&paste, undo&redo, etc. are disabled. When switching
to "profile" mode, they are reenabled.

This was done in a most convoluted way:

- The MainWindow calls the set*State() function of the profile.
- The Profile emits [disable|enable]Shortcuts() signals.
- The MainWindow catches these signals and does the enabling
  or disabling.

Not only is this very hard to reason about, it is also in
contradiction to the profile being part of the display layer.

Moreover, in editCurrentDive() the MainWindow disabled the
shortcuts itself, so this was all redundant.

For the sake of sanity, let's just move this logic to the
MainWindow, unslotify the [disable|enable]Shortcuts() functions
and make them private.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-10 14:15:35 -07:00
Berthold Stoeger
11c54b85f6 planner: split DivePlannerPointsModel::remove() in two
There are two cases in this function: with and without holding
the control-key. The former deletes one point, the latter all
points starting with the selected point to the end.

The code was interlaced making it very hard to reason about.
Notably, it was buggy: with control, all points could be
deleted, leading to a crash.

Split the function in two versions, with their own bound
checking. This produces a bit of duplicate code, which
might be broken out later.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
a0f6b4d0b4 planner: avoid starting unneeded variation thread
When updating the dive profile, a thread is started to calculate
plan-variations. This is done even when only editing the profile
or when variation calculation is disabled by the user. The thread
then exits if it shouldn't calculate the variations.

Turn this around: test whether variations should be calculated
before starting the thread.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
0f8560276d planner: remove DivePlannerPointsModel::recalc flag
There was no user of that flag left.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
f0f3b4a13c planner: call removeDeco() explicitly
removeDeco() was called by addStop() if the recalc flag was
set. If the caller didn't want to call removeDeco() it had
to clear and restore the flag.

Instead, call removeDeco() explicitly when needed.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
c7dcd7fbf0 planner: don't clear recalc in DivePlannerPointsModel::clear()
There are no more external users of this flag, therefore clearing
that flag is a no-op.

Moreover, clear the cylinders array and the preserved_until
flag befor emitting the model-reset signal.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
601861ef5e planner: split DivePlannerPointsModel::removePoints() in two
Split the function in one external version, that updates the
dive profile and cylinders and one internal version, that
does no recalculations. In the latter case, the caller is
responsible for updating the dive.

Thus, the recalculation flag-clearing can be removed from
removeDeco().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
cbee716316 planner: don't export recalc flag of DivePlannerPointsModel
This is not queried anymore, so remove the accessor function.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
77a6bc6d62 profile/planner: don't update dive in ProfileWidget2::plotDive()
In planner or profile-edit mode, the plotDive() function takes
the current plan and turns it into a dive profile. Not only
is this a layering violation (the display layer modifying the
dive), it is also fundamentally flawed. The control-flow is
out of control, if you wish. There are numerous reasons why
the profile needs to be replot, many of which do not need
a recalculated dive profile.

Move the code that updates the dive-profile to the
DivePlannerPointsModel. Thus, the profile recalculations
and replots can be pooled. This will break the planner, since
there now might be missing calls to the profile recalculation.
But it already has some positive effects: when removing
multiple points, the profile is only recalculated once.

This will need much more work, but it is a start.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
337d9318ad planner: split addStop() into external and internal versions
The DivePlannerPointsModel::addStop() function is called by
the profile to add a planner-stop. It is also used internally
to create profiles.

If we ever want to include this in the undo system, we have
to split these into to versions. One will ultimately place
an undo command and update the profile, the other one doesn't.

For now, this makes the external interface simpler, as some
parameters are redundant.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
71e117669d profile: populate dive handlers when switching to edit/plan mode
The dive handlers are only updated by signals. This means that
switching into edit-mode has to be done in steps:
 1) initialize the DivePointsPlannerModel
 2) switch profile mode
 3) load dive into DivePointsPlannerModel

2) and 3) cannot be exchanged, or the dive handlers are not
initialized.

To avoid this sandwitching of profile- and model-initialization,
populate the dive handlers when switching the profile mode.
Thus, the profile can be switched into edit/plan mode when
the DivePointsPlannerModel is fully initialized.

This will be important in upcoming commits, when the initialization
of the dive is moved from the profile to the DivePointsPlannerModel.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
51b16a43c4 cleanup: make DivePlannerPointsModel::removeDeco() private
No outside users.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
7c398973fd cleanup: remove unused function DivePlannerPointsModel::size()
This is not a virtual function and does not seem to be called
anywhere..?

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
93ec9f11e8 cleanup: remove unused member DivePlannerPointsModel::addingDeco
This was never used.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
4b801f1f50 planner: split createTemporaryPlan() function.
The DivePlannerPointsModel::createTemporaryPlan() function had
two distinct and independent parts:
 1) create the data points.
 2) create the dive sample and calculate variations.
The second part was only exectuted if the recalc flag was set.
Out of the two callers, one was explicitly disabling and setting
the recalc flag to avoid the second part.

The much more logical thing is to simply split the function in
two and only call the first part.

To avoid any functional change, the second caller (the profile)
still tests for the recalc flag. However, if it shouldn't replot
a new plan, why calculate it in the first place!? And why does
the display function change the plan at all? This appears all
very ill-thought out and should be changed in due course.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
7b9c8e344a cleanup: unify whitespace in switch statement
The way the blocks in DivePlannerPointsModel::setData()'s
switch statement were demarked messed with my mind.
There were at least three variants. Let's try to be consistent.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
4009d4c87f planner: remove DivePlannerPointsModel::setRecalc()
The only external user of setRecalc() was turning recalculation
on. In fact, this happened when constructing the planner-widget.
However, for example editing of the profile only works when
the recalc flag is on.

This is all very confusing, let's just turn the flag on by
default and remove the accessor. Internally, the planner can
simply use the std::exchange function to set and reset the
recalc flag.

Perhaps the setting/resetting can be replaced by simple
        recalc = true;
        ...
        recalc = false;
pairs. It is unclear whether there is need for recursion.
Something to be investigated.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
457be51ff6 profile: remove redundant replot() calls in key events
When moving "dive handlers" with the cursor keys, the
profile was replot twice:

- First the recalculation of the planner model was suspended.
- The "stop" was moved.
- This led to a replot by a signal from the planner model.
  However, the old profile was shown, since the recalculation
  was suspended.
- The recalculation was reenabled.
- The profile war replot, resulting now in the correct profile.

A classical case of bit rot.

Instead, don't suspend calculation in the first place. This
shows the correct profile on the first replot and the second
replot can be removed.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
a3d8191896 profile: make ItemPos initialization constant
The ItemPos structure describes the position of various chart
elements on the scene. It had two problems:

- The identifiers were starting with an underscore followed
  by a capital letter. This is reserved to the compiler.
- The global object was initialized in the ProfileWidget's
  constructor. This means that if there are multiple
  ProfileWidgets, the structure is reinitialized even though
  it is constant.

Remove the underscores (what was the point anyway?) and
initialize the structure in its own constructor. Moreover,
make the object const to drive the point home.

If this ever needs to be variable, each ProfileWidget
should get its own copy of the object.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
ed8ad9ac80 desktop: query DivePlannerPointsModel for planner state
MainTab::updateDiveInfo() is not executed when in the planner.
To decide whether the application is in the planner state,
it queried the profile. Instead, query the DivePlannerPointsModel.

Currently, there is no autoritative carrier of that flag.
However, the MainTab has a dependency on DivePlannerPointsModel
anyway, and therefore this removes a dependency on the
profile. This brings us closer to a state where we can have
multiple profiles.

Ultimately, it is hoped that the whole check can be removed
at this place, making the point moot.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
b4c307c775 planner: set profile to planner state in main window
Remove mainwindow-access from the planner, by setting
the profile to planner state in the owner of the profile,
viz. the MainWindow.

The MainWindow sets the application state to planner, so
it seems legit that it also sets the profile state.

This removes a further interdependency.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
4d60662531 desktop: remove check for editMode in maintab
The accept / reject message is only shown in edit-mode, no
need to check it. This is a step in simplification / removal
of the edit mode.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
2789bb05b1 profile: display arbitrary dive
So far the profile operated on the global displayed_dive. Instead,
take the dive to be displayed as a parameter to the plotDive()
functions.

This is necessary if we want to have multiple concurrent
profile objects. Think for example for printing or for mobile
where multiple dive objects are active at the same time.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
36f0ba9abe profile: don't check for stepping past maximum time / depth
When moving a planner point with the cursor, nothing
is wrong with extending the dive time by stepping
beyond the current maximum. Same for depth.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
752724aa1e profile: fix logic in keyDeleteAction()
The code took care to not delete planner-points when no
points are selected. However, it assumed that all selected
objects are planner-points. But then it checked whether
the selected object actually is a planner-point. So which
is it?

Remove the outter check for an empty selection. This makes
things more logical and more robust, should there ever
be other objects that can be selected.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
1ec0790d50 planner: remove displayed_dive from DivePlannerModel
To remove global state, make the dive that DivePlannerModel
works on a member variable. Pass the dive in createSimpleDive()
and loadFromDive(). Moreover, this should pave the way to more
fine-grained undo in the planner. Ultimately, the planner
should not be modal.

Attention: for now, the dive must still be displayed_dive,
because of the convoluted way in which the profile and the
planner work on the same dive.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
e419ebf55a planner: move clearing of model into loadFromDive() function
Both loadFromDive() callers were clearing the model before
calling loadFromDive(). Move the clearing into that function
since it makes no sense to load into a non-cleared model.

Apparently this changes the way that no-cylinder dives are
treated and the code in ProfileWidget2::repositionDiveHandlers()
must now explicitly check for that condition.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
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
91136b2c51 profile: remove special casing of handle moving
When moving the handle with the mouse, the old code tried
to be smart about changing the active handle when crossing
handles.

To me this always felt weird and it was inconsistent with
mouse-move. Theregore, simply do nothing special at all. The
user should hopefully get an intiutive grasp of what's going
on when moving one handler across another.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
b9673df60b profile: pass DivePlannerPointsModel at construction time
This model is only needed when in plan mode. To enable multiple
profilewidgets at the same time (e.g. for the mobile app or
for printing), make the pointer to DivePlannerPointsModel a
member variable that is initialized at construction time.

Moreover, allow passing null as the DivePlannerPointsModel,
in which case planning will be disabled. This will be useful
for simple printing.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
94633d2156 profile: connect to DivePointsPlannerModel in separate function
The connection to the DivePointsPlannerModel was done in two
distinct functions: setAddState() and setPlanState(), which
means that these could easily get out-of-sync. Factor this out
into a single function.

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
79ddb23edf profile: implement proper model/view semantics in ProfileWidget2
The ProfileWidget2 slots, which reacted to model changes were
broken. They did not add / remove items at the changed positions,
but arbitrarily at the end. Moreover, they assumed that only
a single item was added / removed and thus violated the model/view
API.

This worked because the handles are completely reset after each
operation and the model only ever touched single items.
Nevertheless, this has to be fixed if we ever want finer grained
undo.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 13:53:23 -07:00
Berthold Stoeger
396758d489 profile use unique_ptr to manage dive handler objects
Instead of manually deleting them (and the gases). Currently
there is only one point where these are deleted, but if
we implement proper Qt model/view semantics, this makes things
less headachy.

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
8cd389c0af printing: use sensible font-size in profiles
The font-size in printed profiles is based on the size of the profile
in the main window. This makes no sense. Why should changing the
window size change the font-size on printouts?

Matter of fact, when making shrinking the height of the window to
its minimum, comical printouts are obtained (font way too big).

Therefore use an arbitrary rule: Say that profiles 600 pixels high
look reasonable and then scale up to the actual size on the printout.

This may need some tweaking for high-DPI mode. But that seems not
to be supported on desktop anyway?

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-04-02 08:22:00 -07:00
Dirk Hohndel
56ffa95459 mobile/user-manual: update date and version
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-03-31 10:20:44 -07:00
Dirk Hohndel
12e59010eb Update translations from Transifex
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-03-31 10:11:03 -07:00
Dirk Hohndel
faf349bbda prepare for 5.0.1
Update README and ReleaseNotes.

Also remove outdated workflow badge, add a couple new one, and hack around a
rendering issue where the last character of longer workflow names gets
overwritten by the status - which resulted in the arguably most important info
(which Qt version) being hidden.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-03-31 09:07:01 -07:00
Berthold Stoeger
991d1bdf19 profile: fix color on pressure-item
The "in_planner" condition was inadvertently inverted in
c6d78bc134 and therefore the wrong data was used to draw
the line (density instead of SAC). Revert to original.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2021-03-31 08:48:38 -07:00
Dirk Hohndel
0521f79fae build-system: make ASAN builds easier
This is a bit lacking sophistication (you need to remember to make clean
before rebuilding when changing this option, etc), but it works well
enough for my purpuses.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2021-03-31 08:03:04 -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