Commit graph

785 commits

Author SHA1 Message Date
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