While in theory the DEVINFO event should give us the correct detected
product, it's also possible that the code that usually detects the
product gave up and returns an unknown model.
Try to have the message reflect that situation more accurately.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
process_imported_dives() takes four boolean parameters. Replace these
by flags. This makes the function calls much more descriptive. Morover,
it becomes easier to add or remove flags.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Since process_imported_dives() can add dives to a newly generated
trip, this need not be done in the downloading code. This makes
data flow distinctly simpler, as no trip table and no add-new-trip
flag has to be passed down to the libdivecomputer glue code.
Moreover, since now the trip creation is done at the import step
rather than the download step, the latest status of the "add to
new trip" checkbox will be considered.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
If this flag is set, dives that are not assigned to a trip will
be assigned to a new trip. This flag is set if the user checked
"add to new trip" in the download dialog of the desktop version.
Currently this is a no-op as the dives will already have been
added to a new trip by the downloading code. This will be removed
in a subsequent commit.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The logic in process_imported_dives() was faulty: Dives are merged
trip-wise in a loop. But if only autogenerated trips were supposed
to be merged, the trip would not be added.
Change the logic to always add the trip if it is not merged. To make
the loop easier to read, factor out the merge-trip-into-existing-trips
logic into a separate function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Since recent commits, dive-trips are not added directly to the core,
but into separate trip tables (see ec37c71f5e).
These commits did not finish the work for the download-from-dc
case.
Add an extra trip_table field to device_data_t. If trips are created
(user selected "Download into new trip"), the trip will be created
in that table.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Commit 4d06ddd723 removed deletion of
unused dive sites on save. The corresponding variables were not
removed leading to compiler warnings. Remove the variables too.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
When no real name is set in /etc/passwd the username ends
up being ",,,". Git does not like that. Actually, only the
part before the first comma is the name, the rest is office
and phone number. We don't want those.
Before we only testing for the username being a NULL pointer.
Reported-by: Keith Grimes
Signed-off-by: Robert C. Helling <helling@atdotde.de>
This adds a checkbox for rebreather modes of the planner
that force the ascent to be in OC mode. Before, one had
to add a one minute last segment with the mode change but
this is not practical when manually searching for the
maximal bottom time given gas reserves.
Signed-off-by: Robert C. Helling <helling@atdotde.de>
Split the process_imported_dives() function in two:
1) process_imported_dives() processes the dives and generates
a list of dives and trips to be added and removed.
2) add_imported_dives() calls process_imported_dives() and
does the actual removal / addition of dives and trips.
The goal is to split preparation and actual work, to
make dive import undo-able.
The code adds extra checks to never merge into the same
dive twice, as this would lead to a double-free() bug.
This should in principle never happen, as dives that
compare equal according to is_same_dive() are merged
in the imported-dives list, but perhaps in some pathologival
corner-cases is_same_dive() turns out to be non-transitive.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The installment of the divelist-undo system has made it unnecessary
to adopt the uniq-id of the merged-into dive. On the contrary, we
want to avoid two dives with the same dive-id in the divelist at
all costs, since get_divenr() still uses the id and thus may fetch
the wrong dive.
Therefore, don't copy the dive-id on merge.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
When importing log-files we generally want to merge trips. But
when downloading and the user chose "generate new trip", that
new trip should not be merged into existing trips.
Therefore, add a "merge_all_trips" parameter to process_imported_dives().
If false only autogenerated trips [via autogroup] will be merged.
In the future we might want to let the user choose if trips
should be merged when importing log-files.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The old way of merging log-files was not well defined: Trips
were recognized as the same if and only if the first dives
started at the same instant. Later dives did not matter.
Change this to merge dives if they are overlapping.
Moreover, on parsing and download generate trips in a separate
trip-table.
This will be fundamental for undo of dive-import: Firstly, we
don't want to mix trips of imported and not-yet imported dives.
Secondly, by merging trip-wise, we can autogroup the dives
in the import-data to trips and merge these at once. This will
simplify the code to decide to which trip dives should be
autogrouped.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In the future we want to download trips into a distinct trip-table
instead of the global trip-table to allow for undo of import.
Therefore add a trip_table argument to DiveImportedModel::repopulate()
and a trip_table member to DiveImportedModel. To correctly set these,
add a DownloadThread::trips() function, which currently simply returns
the global trip table.
Finally, make "struct trip_table *" a Q_METATYPE, so that the corresponding
arguments can be passed from QML.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
To allow parsing into arbitrary trip_tables, add the corresponding
parameter to the parsing functions and the parser state. Currently,
all callers pass the global trip_table so there should be no change
in functionality. These arguments will be replaced in subsequent commits.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently trips are added to the global trip table. If we want to
make dive-import undoable, we should be able to parse trips of a
log-file into a distinct table. Therefore, add a trip_table
parameter to
- insert_trip()
- create_and_hookup_trip_from_dive()
- autogroup_dives()
- unregister_trip()
- remove_dive_from_trip()
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently, all trips are kept in a linked list. Replace the list
by a table in analogy to dive_table. Use this to keep the trip_table
sorted as suggested by dump_trip_list(). When inserting a trip into
the table do that after adding the dives, to avoid warnings coming
out of dump_trip_list().
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In 64e6e435f8 the trip->when field
was replaced by a function. This forgot to adapt dump_trip_list(),
which is only compiled if DEBUG_TRIP is defined. Fix the function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Rename
- dive_get_insertion_index() -> dive_table_get_insertion_index()
- unregister_dive_from_table() -> remove_from_dive_table()
- get_idx_in_table() -> get_idx_in_dive_table()
- sort_table() -> sort_dive_table()
This will make it more straight-forward to generate these functions
from macros.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This function was not used outside of divelist.c, therefore make it
local. Moreover rename it to add_to_divetable so that the name
is generic and can be generated by a macro.
Moreover, remove the special case idx = -1, which would determine
the insertion index. Instead let the single caller who used this
feature do this.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently autogroup_dives() groups all dives in the global dive
list. Add a table parameter so that dives in any table can be
grouped. Thus it will be possible to pre-group dives on import,
which will be used for undo of import.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
After loading or importing, the caller usually called autogroup()
to autogroup dives if so wished by the user. This has already led
to bugs, when autogroup() was forgotten.
Instead, call autogroup() directly in the process_loaded_dives()
and process_imported_dives() functions. Not only does this prevent
forgetting the call - it also means that autogrouping can be
changed without changing every caller.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Unused dive sites were deleted on save. This clashed with the undo
system in the following scenario:
1) Delete single-use dive site.
2) Save (dive site deleted)
3) Undo (reference to freed dive site)
Therefore, as a quick-fix, keep the referenced dive site around.
Note that this also means that empty dive sites must not be
deleted, as it might refer to a dive in the undo system. Instead
only clear references to empty dive sites in the global dive
table. Factor this functionality out, as it was common to the
XML and git savers.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The starTimestamp is 4 hours apart on 2 different DCs within the sample
log. DiveDate on the dive_logs table seems to be correct, but must be
converted from human readable format.
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Seems that Shearwater cloud stores sample rate into the database and
it is not constant within the log.
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
This works to some extent to part of a sample log I received. However,
still quite a bit more work is needed.
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
I encountered this while implementing Shearwater Cloud import, but it
makes sense to increase the size for dive id for Shearwater Desktop as
well.
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
wcslen() returns the number of characters in a wchar_t string.
In the case of WideCharToMultiByte() an estimate for the size of
the utf8 buffer is needed. Using wcslen() is incorrect for such a buffer,
because for any non-ASCII character the estimate will be off by 1 byte.
Call the following instead to obtain the proper UTF8 buffer size
for the conversation:
WideCharToMultiByte(CP_UTF8, 0, utf16, -1, NULL, 0, NULL, NULL);
Also fix some missing "\n" in fprintf() calls.
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
After upgrading to Qt 5.12.0, download over BT from a DC did not work
any more. On the console the message "Connecting to port is not
supported (Uuid required)". Linus noticed earlier that we do rather
strange processing in this part of the code related to selecting port 1
or port 5. This all seems not needed (any more), but broader testing is
advised. This being stripped from the code, the mentioned error from Qt
persisted. That is strange in itself, as we did not reference port
numbers any more.
Step 2 in this commit is actually using an uuid to the call to
connectToService. Choosing an uuid seems relatively straightforward as
we can use the same one we already use for Android. That is the default
BT RFCOMM Serial Port Profile uuid. Interestingly, when changing to this
uuid we run immediately in a Qt runtime error telling us "QDBusPendingReply:
type ManagedObjectList is not registered with QtDBus.". For these 2
unexpected Qt messages, QTBUG-72742 was made. Studying the Qt source
code at this point reveals a possible workaround. Simply create a local
QBluetoothLocalDevice object, which, behind the scenes registers the Qt
internal ManagedObjectList with QtDBus.
In the meantime, Qt agrees that QTBUG-72742 is valid, and that a fix is
to be expected in a future version. At that point in time, the
declaration of the QBluetoothLocalDevice can be deleted again.
In the end, interfacing over BT works again.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
This is an attempt to fix issue #1896. While this seems a Qt issue in
combination with very specific Android devices, this might be a fix. Do
not check for a very specific state of the local BT controller, but just
check if it is powered on.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
In commit 6bf4120dbb the trip-flags
were replaced by a simple boolean. This made the was_autogen
parameter to the remove_dive_from_trip() and unregister_dive_from_trip()
functions unused. Remove these parameters.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Just like with the Aqualung i770R in 7697003498 this name follows the
pattern of a model number in ASCII encoding, followed by the serial
number of the device.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
To make data flow more clear, unglobalize the downloadTable object.
Make it a subobject of DownloadThread. The difficult part was making
this compatible with QML, because somehow the pointer to the
download-table has to be passed to the DiveImportedModel. Desktop would
simply pass it to the constructor. But with objects generated in QML
this is not possible. Instead, pass the table in the repopulate()
function. This seems to make sense, but for this to work, we have to
declare pointer-to-dive-table as a Q_METATYPE. And this only works
if we use a typedef, because MOC removes the "struct" from "struct
dive_table". This leads to compilation errors, because dive_table is
the symbol-name of the global dive table! Sigh.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
DCDeviceData was using that weird pattern where the instance
variable was set in the constructor. There is no apparent
reason to do so, therefore convert to a "normal" singleton.
Access that directly in QMLManager instead of saving it in
a member variable first.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The simplified filter-widget doesn't present lists of existing values
with counts. Thus, a whole slew of count_dives_with_*() functions
can be removed.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
These two functions were called in different contexts:
- unregister_dive(): from the undo-commands to remove the dive
from the global dive table, but not delete it. The dive was
already removed from its trip.
- delete_single_dive(): from non-undo code. Most of it not in
use and removed in a sibling-commit. Here, the dive is supposed
to be removed from its trip and a new selection is calculated.
delete_single_dive() calls unregister_dive(), which removes the
dive from its trip. Move remove_dive_from_trip() from the former
to the latter and make both functions independent. Instead
of deleting the dive explicitly in delete_single_dive(), call
the delete_dive_from_table() function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
All callers of add_dive_to_trip() work on freshly generated dives,
with one exception, that was redundant anyway. Therefore it is not
necessary to remove the dive from a potential previous trip. Move the
responsibility of removing the dive from a trip to the caller,
respectively remove the redundant call. Add a warning message in the
case that trip is set.
Background: On import (either download or file-import) we might not
want to add trips to the global trip-list. For example to enable undo
of import but more generally to detangle that data flow. Thus,
add_dive_to_trip() should not mingle with the global trip-list,
which it has to do if a trip is deleted because the old dive was
removed.
Analysis of the add_dive_to_trip() callers:
1) core/dive.c
pick_trip():
called on freshly generated merged dive.
finish_split():
called on two freshly generated split dives.
2) core/divelist.c
create_and_hookup_trip_from_dive():
called on freshly downloaded dive in dive_cb().
called on freshly downloaded dive in record_uemis_dive().
autogroup_dives():
called on dive from get_dives_to_autogroup(), which only
finds dives that are outside of trips.
combine_trips():
unused - removed in sibling commit.
try_to_merge_into():
this call was actually erroneous - dive was already added
to trip in try_to_merge(). Remove call.
3) core/libdivecomputer.c
dive_cb():
called on freshly downloaded dive.
4) core/uemis_downloader.c
record_uemis_dive():
called on freshly downloaded dive.
5) core/load_git.c
create_new_dive():
called on freshly allocated dive.
6) core/parse.c
dive_end():
called on freshly parsed dive.
7) desktop-widgets/command_divelist.cpp
DiveListBase::addDive():
called on dive which is newly added to core.
moveDiveToTrip():
called on dive that was removed from trip a few lines above.
8) mobile-widgets/qmlmanager.cpp
QMLManager::undoDelete():
called on dive where divetrip was reset in the previous line.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In 302f6adb79 dive-splitting was made
undo-able. To this goal, the dive-splitting functions were split in
two types: Those that operate directly on the divelist and those that
only allocate the dives. The former are not in use anymore, therefore
remove them. Since only the latter remain, remove the "_dont_insert"
appendix of the name.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In 014c04f8bd merging dives was included
in the undo-system. This made the merge_two_dives() function caller-less.
Remove it.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In f427226b3b autogrouping / removal
of autogrouping was moved into the undo-machinery. This made the
remove_autogen_trips() function caller-less. Remove it.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In f427226b3b a combine_trips_create()
function was introduced that combined trips without deleting the old
trips. This was necessary for making combine-trips function undo-able.
The old combine_trips() function is not used anymore. Therefore remove
it. Rename the combine_trips_create() function to combine_trips() as
no differentiation is needed anymore.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently, when selecting "Load media files even if time does not
match the dive time", the media are added to *all* selected dives.
Instead add it to the closest dive.
This seems like the less surprising behavior. Of course now if the
user really wants to add a media file to multiple dives, they will
have to do it manually.
To avoid a messy interface, this is solved by moving the iterate-
over-selected-dives loop to the core. Thus, a helper-function can
be made local to its translation unit.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
EMPTY_DIVE_STRING used to be a string-literal representing missing
information ("--"). In 6985c123d4 it
was replaced by the actual empty string. Using a literal to represent
the empty string seems a bit pointless, therefore remove it completely.
Notably:
QString(EMPTY_DIVE_STRING) -> QString()
if (temp.isEmpty()) temp = EMPTY_DIVE_STRING; -> noop
if (s == EMPTY_DIVE_STRING) -> if (s.isEmpty())
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In dive.h there was a redundant 'extern "C"' block defined inside
another 'extern "C"' block. Remove.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Desktop used the hidden_in_filter flag in struct dive, mobile
used its own vector plus a new showndives member in struct dive_trip.
Unifiy these to use the same core-facility, viz. hidden_by_filter.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
These functionality was used by the desktop filter. To unify desktop
and mobile, move it into two new functions in divelist.c
Since one of them is the only caller of is_same_day() move that
likewise into divelist.c and make it of static linkage.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
QML's ListView uses the "section" property to test if items belong to the
same section. Apparently, this must be a string and therefore we can't
pass e.g. a dive-trip object. Therefore a specially formatted string
was passed in, which was guaranteed to be unique (contained the dive-trip
pointer value) and the fully formatted trip-title and short-date.
The disadvantage of that approach is that the formatting is performed for
every dive and not every trip. Perhaps not a problem now, but it makes
it for example necessary to cache the number of filtered dives.
To be more flexible, pass in only the pointer value formatted as
hexadecimal string and provide a function to convert that string
back to a trip-pointer (in the form of a QVariant, so that it can
be passed to QML). Moreover provide two functions for formatting the
title and the short-date.
The three new functions are members of DiveListSortModel. This might not
be the perfect place, but it is easy to reach from the DiveListView.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The DiveObjectHelper::trip() function was
1) Misnamed: it returned the *location* of the trip
2) Not used outside of DiveObjectHelper
Remove it.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Just as we did for pointer to struct dive_site, make pointers to
struct dive and struct dive_trip "Qt metatypes". This means that
they can be passed through QVariants without taking a detour via
void *.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Implement the protocol in Erik Baker's document
"Oxygen Toxicity Calculations". This code uses a
third-order polynomial approximation of Baker's
equation 2. Provision is made for
PSCR and CCR dive logs and dive plans. In the
case of dive logs, the values of o2 sensors are
used if there are data from such sensors. For CCR
only the data from the first O2 sensor is used even if
there are more than one sensor. This is a potential
weakness, but this function is probably NOT the
place to calculate mean o2 values accross all sensors
and to emulate voting logic to reject info from
aberrant sensors.
Signed-off-by: willemferguson <willemferguson@zoology.up.ac.za>
Signed-off-by: Robert C. Helling <helling@atdotde.de>
In 64e6e435f8 the when field of struct
trip was removed. Accordingly it was not read from git repositories.
This produced a large amount of user-visible error messages.
Reinstate the trip-date and time parsing functions, but ignore
the value.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Commit 6b283e598a replaced the linked
list of dives in a trip by a table. Embarassingly, on dive deletion
the index of the dive in the table was compared for "!= 0" instead
of ">= 0". Thus, the first dive of a trip wouldn't be deleted, which
ultimately led to a crash, as different parts of the code were now
in disagreement over whether the trip is empty or not.
Fix the comparison.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The only remaining use of the tripflag was to mark dives that
were removed explicitly from a trip, i.e. shouldn't be autogrouped.
Therefore replace the enum by a simple boolean.
Currently, there is no way of unsetting the notrip flag. But this
shouldn't result in a user-visible change.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The distinction between ASSIGNED_TRIP and IN_TRIP was used to
prefer non-autogenerated trips on merging of dives. But owing
to bit rot this seem to have worked only partially anyway:
The IN_TRIP field was set in create_and_hookup_trip_from_dive()
and immediately overwritten in add_dive_to_trip() called
in the next line.
Instead, use the trip->autogen flag to check for priority and
remove the ASSIGNED_TRIP flag alltogether.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Since upgrading to gcc 8.2 it produces noisy warnings about
potentially truncated strings. It doesn't recognize that
filenr can never become >4000. So clamp it down explicitly.
Do this by adding a function that does the assembly of the
filename path. Adding unnecessary code to silence compiler warnings
is dubious, but in this case it might be reasonable.
Fix a second instance by increasing the stack-allocated buffer
to 32 bytes. Hopefully nobody has more divespots than would
fit in a 9-decimal digit number!
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
When adding the dive to its trip before having filled out "when", the
dive gets added at the first position (when=0), which is usually not
correct. Instead, add the dive to its trip when all fields are correctly
filled out.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The when field gives the time of the first dive. Instead of keeping
this field in sync, replace it by a function that determines the time
of the first dive.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
To make sorting more controlled, move all sorting functions into
the core. For this, introduce a "dive_or_trip" structure, which
represents a top-level item. Adapt the DiveTripModel accordingly.
There are now three sorting functions:
1) dive_less_than
2) trip_less_than
3) dive_or_trip_less_than
These should be used by all sorting code. By moving them to a
single place, the mess can hopefully be cleaned up.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
As a step towards proper sorting, introduce a trip_less_than()
function in core. It simply sorts by the first dive, which should
be unique as dives may belong to only one trip.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The dives of each trip were kept in a list. Replace this by a
struct dive_table. This will make it significantly easier to
keep the dives of a trip in sorted state.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Up to now, dives were added to the global dive table with
add_single_dive(). Split out the funtionality to add a dive to
an arbitrary dive in the add_dive_to_table_function(). The
difference compared to record_dive_to_table is that dives
are added at a specific position or the sort-criterion given
by dive_less_than(). This will allow to use a dive tabe for trips
instead of a linked list.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There were two versions of the insert_trip() function: one
would merge trips if a trip with the same date already existed,
the other wouldn't. The latter was introduced with the dive-list
undo work.
The problem is that the "date" of a trip (i.e. the first dive)
seems ill-defined as this is a volatile value. Moreover in
the context of making dive-import undoable this is a very
dangerous notion, as the caller needs control over when the dives
are added to a trip.
Therefore, unify these two functions and never merge trips.
The decision on merging dives now has to made by the caller.
This will be implemented in a future commit.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The Cressi specific PID was not used
when serial_ftdi_open_device tried
to open the device.
Reported-by: Daniel Krupp
Signed-off-by: Daniel Krupp <daniel.krupp@gmail.com>
The DiveTripModel places dives after trips in chronologically
ascending mode if the dive and the trip start at the same instant.
But in the core the sort order was undefined. This could lead
to a discrepancy. Therefore, implement the same sort-criterion
in the core code.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Update table of maximum oxygen exposure durations, used in CNS calulations.
This table shows the official NOAA maximum O2 exposure limits
(in seconds) for different PO2 values. It also gives
slope values for linear interpolation for intermediate PO2 values
between the tabulated PO2 values in the 1st column.
Top & bottom rows are inserted that are not in the NOAA table:
(1) For PO2 > 1.6 the same slope value as between
1.5 & 1.6 is used. This exptrapolation for PO2 > 1.6 likely
gives an underestimate above 1.6 but is better than the
value for PO2=1.6 (45 min). (2) The NOAA table only
tabulates values for PO2 >= 0.6. Since O2-uptake occurs down to
PO2=0.5, the same slope is used as for 0.7 > PO2 > 0.6.
This gives a conservative estimate for 0.6 > PO2 > 0.5. To
preserve the integer structure of the table, all slopes are
given as slope*10: divide by 10 to get the valid slope.
The columns below are:
po2 (mbar), Maximum Single Exposure (seconds), single_slope,
Maximum 24 hour Exposure (seconds), 24h_slope */
Then update Calculations of the CNS for a single dive -
this only takes the first divecomputer into account.
The previous version of the code did a table lookup and
used the max O2 exposure for the next-higher PO2 category.
This gave a shorter max O2 exposure time and a higher CNS
contribution for a specific dive segment, resulting in a
slightly conservative value of CNS, often some 2 - 3 % too high.
This code does an interpolation for PO2 values inbetween
PO2 entries in the lookup table and therefore results in a more
accurate maximum O2 exposure time for that PO2.
The maximum O2 exposure duration for each segment
is also calculated based on the mean depth of the two
samples (start & end) that define each segment. The CNS
contribution of each segment is found by dividing the
time duration of the segment by its maximum exposure duration.
The contributions of all segments of the dive are summed to
get the total CNS% value. This is a partial implementation
of the proposals in Erik Baker's document "Oxygen Toxicity Calculations" */
Overall, this PR does not radically alter the existing CNS calculation,
it only makes it more accurate and more consistent by doing
interpolation and by using mean segment depth to find PO2.
Signed-off-by: willemferguson <willemferguson@zoology.up.ac.za>
Adapt get_trip_date_string() to use the same logic as get_dive_date_string():
Use the static "loc" object to translate date. Before, the trip
date was shown in C locale.
Reported-by: Philippe Massart <philippe@philmassart.net>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There was a stray semi-colon on the beginning of a line in
DiveObjectHelper.cpp. Remove it.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Usage of the flags expanded, selected and fixup was removed some
time ago. Remove the flags too.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
For unrecognized locales we use en_US by default. It makes much more sense for
South Africa to use en_GB.
Reported-by: Willem Ferguson <willemferguson@zoology.up.ac.za>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
And fix a crash very similar to the previous commit. When trying to
save (to git) with an empty dive site, ssrf crashes.
Again, add a simple guard to prevent this.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
With the fixed sematics of get_gasmix to return the new gasmix for
the time of a gas switch (added comments to make this clear), in the
OTU calculation we need the previous gasmix for the interval up to the
current time.
Signed-off-by: Robert C. Helling <helling@atdotde.de>
This fixes a subtle bug introduced in 5c4569247a which
unified two functions finding the gasmix at a given time
during the dive. There was a slight difference, though:
Does a gaschange exactly at that time count or not? For
the planner to work, the answer has to be in the affirmative.
Signed-off-by: Robert C. Helling <helling@atdotde.de>
Now that struct dive_site * is a proper Q_METATYPE it is not
necessary anymore to pass dive-sites as opaque uintptr_t types.
Simply pass a QVariants or directly via dive_site *.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There was this ugly pattern of passing pointers-to-dive_site via
a QVariant of void * type. This is of course inherently unsafe.
Pass these pointers using their proper types instead. This makes
it necessary to register them in Qt's meta-type system. Doing so,
fixes a bug: QML couldn't call into updateDiveSiteCoordinates()
because it didn't know the type and thus the coordinates of
the moved flag were not reflected in the divesite-dialog.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Replace the UUID reference of struct dive by a pointer to dive_site.
This commit is rather large in lines, but nevertheless quite simple
since most of the UUID->pointer work was done in previous commits.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
MapWidgetHelper::reloadMapLocations() used an array of uuids to
add dive sites to the map only once. Replace this by an array
of pointers. This is a small piece of a larger effort to remove
dive site UUIDs.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Replace UUIDs by pointers to dive-site in mobile code. In both
cases, the value is transported via a QVariant. The function
getCoordinatesForUUID(), which was only used from mobile, can
be replaced by a getCoordinatesFor() function taking a variant
supposed to contain a dive-site pointer. Likewise, the variant
of the centerOnDiveSite function is now supposed to wrap a
pointer-to-divesite.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Another small step in removing dive-site UUIDs: use a pointer
instead of a UUID in the "uemis_helper" structure.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of passing uuids, pass a pointer to the dive site.
This is small step in an effort to remove uuids.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of passing a uuid, pass a pointer to the dive site.
This is small step in an effort to remove uuids.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of passing a uuid, pass a pointer to the dive site.
This is small step in an effort to remove uuids.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of passing a uuid, pass a pointer to the dive site.
This is small step in an effort to remove uuids.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This changes more of the dive-site interface to return pointers
instead of UUIDs. Currently, most call sites directly extract
UUIDs afterwards. Ultimately, the UUIDs will be generally replaced
by pointers, which will then simplify these callers.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The uemis downloader uses a cache for location to divesite id.
Trivially, the divesite-uuid can be replaced by a pointer. This
is a tiny step to remove divesite UUIDs.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
As a first step in removing dive-site uuids, change the interface
of the get_dive_site_*() functions to return pointers instead
of uuids. This makes code a bit more complicated in places where
the uuid is extracted afterwards (needed NULL check). Nevertheless,
these places should disappear once pointers instead of uuids are
stored in the dive-structures.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Including ssrf-version.h in an include file that a lot of files depend on
caused a ton of unnecessary recompiles with every commit. This should reduce
that problem.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
The reverseGeoLookup() function defined in qthelper.cpp has long
ago moved to its own compilation unit. It is not even defined in
the headers anymore. Remove it and the now unnecessary <QNetwork*>
includes.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
When creating a trip header (as it is used in the mobile app right now), we need
to show the number of dives shown, not the total number of dives in that trip.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
We assume that any dive that gets added to a trip initially gets shown. The
filter logic then needs to make sure it adjusts this number (which then makes
it easy to tell the user how many dives of that trip are visible with the
current filter).
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This feels a bit like cheating, but if we need to be able to make modifications
to the underlying dive and only have the helper object (for example inside of a
view model), doing everything through the helper object can turn into a real
performance issue.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
With this we can make it configurable if the search should include the notes field
and if the search should be case sensitive or not.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Otherwise we could match the end of one string and the beginning of the next,
so having a buddy name Linus and a dive master named Alvin would be matched
by USA.
Also add Notes to the full text search (I had forgotten those earlier).
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
A static variable was used to collect two parts of the location
string. Instead, explicitly store these two parts in two different
strings and concetenate them. One fewer variable and the program
flow is thus hopefully more clear.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Introduce a parser_state structure, which describes (most) of the
global parser state. Create such a structure in the entry routines
to the parser and pass it down to the individual functions. The
parser state is initialized and freed with the init_parser_state()
and free_parser_state() functions.
The main benefits are:
1) Isolation of parser state.
2) Keeping the global name space tidy.
3) Prevent memory leaks which could happen in truncated files by
freeing all the parser state after parse.
A somewhat controversial point might be that the individual
parsing functions are split in those that need parser-state and
those that don't. This means that there are now two versions of
the MATCH macro, viz. one for the former and one for the latter.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This is consistent with most other free_*() functions in the core
code and will make cleanup of parser state less verbose.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Export the free_picture() function from dive.c. The parser may need
this in case of truncated files to free its temporary resources.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Recently, the subsurface webservice was removed. Remove the corresponding
code in the parser. This removes a static variable, which was used
to generate unique dive-site ids.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The variables country and city used in divinglog_place()
were never freed. Free them when the pointers are reset.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The utf8_string() function is used to extract whitespace-trimmed
strings. The function would happily overwrite the pointer to
the old string, which could therefore leak (suppose an XML has
redundant attributes).
Therefore preemtively free the string output parameter. This makes
it of course necessary to only pass in NULL-initialized pointers
or pointers to owned string.
The code survives the current set of parser-tests.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of having people treat latitude and longitude as separate
things, just add a 'location_t' data structure that contains both.
Almost all cases want to always act on them together.
This is really just prep-work for adding a few more locations that we
track: I want to add a entry/exit location to each dive (independent of
the dive site) because of how the Garmin Descent gives us the
information (and hopefully, some day, other dive computers too).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
The deco parameters need special treatment to wire them up to the
underlying deco model code. And with the new preferences setup this
is a lot of boilerplate.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
On parsing of dive computer extra data, key/value pairs are stored
in global state. They are added to the dive computer with
add_extra_data(), which makes a copy of the string. The local
copies of the strings are never freed.
free() the strings after storing them. The data still leaks in case
of unfinished parsing of extra_data tags, but this will be
taken care of in a subsequent commit.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
delete_current_divecomputer() had some duplicate code to release
dive-computer resources. Use the free_dc_contents() function instead.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The serial and fw_version strings of struct divecomputer were copied
by pointer. This worked because they were never freed or modified.
Instead, do a deep copy of the strings and free them when appropriate.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
On dive computer copy, the extra data (a list of key/value pairs)
was simply copied as a pointer. This worked because the list was
never freed nor modified. Copy and free the list on dive computer
copy and free, respectively.
This made it necessary to move the STRUCTURE_LIST_* macros up in
the dive.c file.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In commit e5dca8228e a fixed order
of the arguments to merge_dives() was introduced: first dive old,
second dive downloaded. This made the dl variable, which pointed
to the downloaded dive useless. One instance was forgotten, which
led to a null-dereference.
Remove.
Reported-by: Dirk Hohndel <dirk@hohndel.org>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
xml_parsing_units stores the units of the currently parsed XML
file. It is not used outside of parse-xml.c. Therefore, make
it of static linkage and remove the declaration from dive.h.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
sanitize_cylinder_type(), which is indirectly called from fixup_dive(),
had ft^3 -> mliter conversion code, which was executed on the
condition "xml_parsing_units.volume == CUFT".
But nowhere in the code base would xml_parsing_units.volume ever be
set to non-metric. Moreover, xml_parsing_units reflects the units
of the latest parsed XML file, but fixup_dive() is called in numerous
contexts not related to XML parsing. Therefore, the whole piece of
code seems highly questionable.
Remove this code.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Dive site data was collected in "cur_dive_site", which was then
merged into an existing or a new dive site. But only the struct
dive_site pointed to by "cur_dive_site" and the taxonomy data
were freed, not the textual data such as name or description.
Therefore, split out the approrpriate free-ing from the
delete_dive_site() function and call that instead of a simple
free().
A similar situation occured for dives that would not be added
to the dive-table because they were deemed incomplete. Use
free_dive() here instead of a simple free() too.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
I incorrectly thought that 'ci_pointing_to_guiding_tissue' was the only
missing initialization, because that is the only one valgrind pointed at.
... that is, until I started looking at a few more dives, which showed
that there were other parts tht weren't initialized either, like
double tolerated_by_tissue[16];
double tissue_inertgas_saturation[16];
double crushing_onset_tension[16]; // total inert gas tension in the t* moment
so just make sure to clear the whole data structure, to avoid any random
behavior due to uninitialized deco state.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
In select_dive(), the selected dive would only be made the
current dive, if it wasn't previously selected. If multiple
dives were selected and the user clicked on one of them which
is not the current dive, then the current dive would be
deselected and thus not be the current dive anymore. The
only remaining dive would not be made the current dive,
because it was already selected. End result: null dive shown.
Therefore, always make the selected dive the current dive,
even if it is already selected.
Fixes#1792
Reported-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
copy_dc_renumber() is an internal function to copy dive computers
and renumber the cylinders. Since only the structure was copied,
in the case of multi-dc dives, the merged dives shared the same
computer. If one of them was freed, use-after-free crashes would happen.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This was used to track whether we had selected the native BT mode in the
download dialog. But the information is redundant as we can tell from the
device name whether this is a BT/BLE download or not.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
process_imported_dives() might delete the currently selected
dives. This could lead to use-after-free problems. Therefore,
reset the currently selected dive to the last dive.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
On dive import, dives to be added may be merged into already
existing dives. In such a case, the dive to be added is deleted.
Before doing so, it must be removed from the trip is belongs to
to avoid corruption of the trip-list.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
On merging make a deep copy of the picture list, to avoid a use-after-free
crash after the orginal dive is deleted.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In commit 8c2383b495 dive merging was
changed to not modify the original dive. On import, dives were then
merged and the original deleted. The merge_weightsystem_info() was
not adapted accordingly (deep copy of string instead of pointer),
leading to a use-after-free crash.
Resolve this by doing a deep copy.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of calling free() on all dives, call free_dive() which also
frees additional allocated data, not only the dive struct.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There were two declaration of clear_table(), one in dive.h and one
in parse.h. The definition was in parse.c. Since the parser doesn't
even use the function, move the function and its declaration to
divelist.[ch] and remove the redundant declaration in dive.h.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This variable was only used in the divinglog_dive() function. There,
it was initialized right at the beginning and therefore there seems
to be no point in conserving its value across function-calls.
Make the variable local and remove the global version.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Comits f427226b3b and 43c3885249 of the undo series introduced 2 calls
of autogroup_dives() without checking the autogroup global boolean.
This is a bug. An import from DC (for example) then triggers an
autogrouping, the divelist is autogrouped, and the UI button
is off.
This commit solves this. I've chosen for a guard in the autogroup_dives()
that now is a no-op when called when the user did not select autogrouping.
In additon, simplified the other calls to this function, as we do
not need to check before calling any more.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
The dive-site-edit widget uses a copy of the to-be-edited site
to compare with old values. Generally, this seems overkill
(the original dive-site can be used for such a comparison).
But one place where it can't simply be removed is the taxonomy,
because the widget needs a place to store the unsaved data.
Change the code to use an explicit taxonomy structure instead
of the one provided in the copy. This should ultimately allow
removal of the latter.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The global object displayed_dive_site is used a a backing-store
by the dive-site-edit widget. All external accesses were removed,
therefore make the object local to the widget.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The global object "displayed_dive_site" is used to store the
old dive site data for the edit-dive-site widget. The fields
of the widget were initialized from this object in the show
event. Therefore the object was updated in numerous parts of
the code to make sure that it was up-to-date. Instead, move
the initialization of the object to the function that also
initiatlizes the fields. Call this function explicitly before
showing the widget.
This makes the data-fow distinctly easier to understand.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The name seems crazy until you realize that FQ is 0x4651 which is the model
number of the i770R. And the six digits are the serial number of the device.
Still crazy, but at least now you understand WHY.
Thanks to Jef for decoding that.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This makes no sense, but apparently we need to start a fresh scan in order to be able
to talk to a different BLE dive computer on the Mac.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
On macOS, we cannot connect to a BT/BLE device until we have scanned it. Right
now this just sits quietly and waits, which given how long this can take is
rather unsatisfying and might look like Subsurface is hung.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Since we trigger a scan even without the dialog to pick the right
device, we need to remember all devices that we find.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Instead of only starting the scan when explicitly asked to do so in the BT
dialog, create the discovery agent when the download dialog opens, since on
macOS we cannot connect to a device without having scanned for it first.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
The reverseGeoLookup() fetches dive-site data via GPS coordinates.
The coordinates and the result were passed via the global
"displayed_dive_site" object. To make data-flow more clear,
pass data as in and out parameters instead.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
By making reply a std::unique_ptr<>, the function can be quit
from any point and the reply will be freed. This is valid according
to Qt's documentation as we're not deleting during signal processing.
This commit fixes a leak: reply was overwritten with the address of
a new object without freeing the old object.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
According to Qt's docs, the QNetworkAccessManager is supposed
to be a long-living object. Therefore, don't create one on
every geo-lookup, but a single object for all geo-lookups.
By making the object function-local it is only initiaized
on first use. Morover this limits the amount of concurrent
geo lookups.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Fetching the taxonomy from GPS coordinates was implemented in
a QThread. But the only access to the main function was a
direct call to run(). Thus, the thread was *never* started.
The function call was always asynchronous [it was using an
event loop though, so the UI doesn't hang]. Notably this
means that the signals connected to the thread would never
fire. And the spinner would never be activated.
Thus:
1) Turn the thread into a simple function.
2) Remove the spinner.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Ultimately, we want to use a single dive-list and not replicate
it in the Qt-model code. To this goal, let's start with using
the same sort function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
For undo, it is crucial that commands don't modify existing dives.
Unfortunately, dive merging would write into the data-structures
of the to-be-merged dives. To prevent it from doing so, make the
input dives const-pointers.
This led to a whole cascade of functions that had to take const
and significant churn.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Select the proper dives after the add, remove, split and merge
dives commands on undo *and* redo. Generally, select the added
dives. For undo of add, remember the pre-addition selection.
For redo of remove, select the closest dive to the first removed
dive.
The biggest part of the commit is the signal-interface between
the dive commands and the dive-list model and dive-list view.
This is done in two steps:
1) To the DiveTripModel in batches of trips. The dive trip model
transforms the dives into indices.
2) To the DiveListView. The DiveListView has to translate the
DiveTripModel indexes to actual indexes via its QSortFilterProxy-
model.
For code-reuse, derive all divelist-changing commands from a new base-class,
which has a flag that describes whether the divelist changed. The helper
functions which add and remove dives are made members of the base class and
set the flag is a selected dive is added or removed.
To properly detect when the current dive was deleted it
became necessary to turn the current dive from an index
to a pointer, because indices are not stable.
Unfortunately, in some cases an index was expected and these
places now have to transform the dive into an index. These
should be converted in due course.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In DiveListView, we have a very fundamental problem: When
On the one hand, we get informed of user-selection in the
DiveListView::selectionChanged() slot. This has to set the
correct flags in the C-backend.
On the other hand, sometimes we have to set the selection
programatically, e.g. when selecting a trip. This is done
by calling QItemSelectionModel::select().
But: this will *also* call into the above slot, in which
we can't tell whether it was a user interaction or an
internal call. This can lead to either infinite loops or
very inefficient behavior, because the current dive
is set numerous times.
The current code is aware of that and disconnects the
corresponding signal. This is scary, as these signals are
set internally by the model and view. Replace this
by a global "command executing" flag in DiveListNotifier.
The flag is set using a "marker" class, which resets the flag
once it goes out of scope (cf. RAII pattern).
In DiveListView, only process a selection if the flag is not
set. Otherwise simply call the QTreeView base class, to reflect
the new selection in the UI.
To have a common point for notifications of selection changes,
add such a signal to DiveListNotifier. This signal will be
used by the DiveListView as well as the Command-objects.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Don't delesect dives, when unregistering them from the backend.
If a previously selected dive is added, select it in the dive-list.
For this purpose introduce a SELECTED_ROLE to query the DiveTripModel
for selected dives.
Unfortunately, when adding multiple selected dives, current_dive_changed
is called for each of them, making this very slow. This will have
to be fixed in subsequent commits.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
If the autogroup flag is set, search for appropriate trips in
DiveAdd() and add the dive to this trip. If no trip exists, add
a new trip.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Previously, each dive-list modifying function would lead to a
full model reset. Instead, implement proper Qt-model semantics
using beginInsertRows()/endInsertRows(), beginRemoveRows()/
endRemoveRows(), dataChange().
To do so, a DiveListNotifer singleton is generatated, which
broadcasts all changes to the dive-list. Signals are sent by
the commands and received by the DiveTripModel. Signals are
batched by dive-trip. This seems to be an adequate compromise
for the two kinds of list-views (tree and list). In the common
usecase mostly dives of a single trip are affected.
Thus, batching of dives is performed in two positions:
- At command-level to batch by trip
- In DiveTripModel to feed batches of contiguous elements
to Qt's begin*/end*-functions.
This is conceptually simple, but rather complex code. To avoid
repetition of complex loops, the batching is implemented in
templated-functions, which are passed lambda-functions, which
are called for each batch.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
insert_trip() adds a trip to the backend, but merges trips if
there exists a trip with the same date. This is a disaster
for the MergeTrips command, because this command adds a new
trip and removes the previous two. Of course if the added trip
is merged, this cannot work.
Therefore, add an insert_trip_dont_merge() function, which
adds the trip, but doesn't merge.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
AddDivesToTrip, CreateTrip, AutogroupDives, RemoveAutogenTrips
and MergeTrips basically all did the same thing as RemoveDivesFromTrip,
which was already implemented. Thus, factor our the common functionality
and hook it up to make all these functions undo-able.
Don't do the autogroup-call everytime the dive-list is rebuilt
(that would create innumberable undo-actions), but only on dive-load /
import or if expressly asked by the user [by switching the autogroup
flag].
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
For this, an output-parameter was added to the backend merge_dives()
function. When non-zero, instead of adding the merged dive to
the preferred trip, the preferred trip is returned to the caller.
Since the new UndoObject, just like the delete-dives UndoObject,
needs to remove/readd a set of dives, the corresponding functionality
was split-off in a helper function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
For this, the core functionality of the split_dive() and
split_dive_at_time() functions were split out into new
split_dive_dont_insert() and split_dive_at_time_dont_insert(),
which do not add the new dives to the log. Thus, the undo-command
can take ownership of these dives, without having to remove them
first.
The split-dive functionality is temporarily made desktop-only
until mobile also supports "UndoObjects".
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Play manual addition of dives via an UndoCommand. Since this does in
large parts the same thing as undo/redo of dive deletion (just the
other way round and only a single instead of multiple dive), factor
out the functions that add/delete dives and take care of trips.
The UI-interaction is just mindless copy&paste and will have to
be adapted.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The original undo-code was fundamentally broken. Not only did it leak
resources (copied trips were never freed), it also kept references
to trips or dives that could be changed by other commands. Thus,
anything more than a single undo could lead to crashes.
Two ways of fixing this were considered
1) Don't store pointers, but unique dive-ids and trip-ids.
Whereas such unique ids exist for dives, they would have to be
implemented for trips.
2) Don't free objects in the backend.
Instead, take ownership of deleted objects in the undo-object.
Thus, all references in previous undo-objects are guaranteed to
still exist (unless the objects are deleted elsewhere).
After some contemplation, the second method was chosen, because
it is significantly less intrusive. While touching the undo-objects,
clearly separate backend from ui-code, such that they can ultimately
be reused for mobile.
Note that if other parts of the code delete dives, crashes can still
be provoked. Notable examples are split/merge dives. These will have
to be fixed later. Nevertheless, the new code is a significant
improvement over the old state.
While touching the code, implement proper translation string based
on Qt's plural-feature (using %n).
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Disable the Download button when one of the fields vendor, product,
connection is not filled in. The app will crash when trying.
In addition, make the underlying core code to actual download
more safe by checking this, and silently fail instead of crash.
And, yes, this is a double fix in this scenario, but the core code
is used in more places, so better safe than sorry.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
Since a known DC will have the name prepended to the BT/BLE addresss
we need to substring match the BT address.
Signed-off-by: Joakim Bygdell <j.bygdell@gmail.com>
By saving the device address together with the vendor and product we fix the
corner case where a user with two DCs would not get quick select buttons if they
where the same vendor and model.
Signed-off-by: Joakim Bygdell <j.bygdell@gmail.com>
The LocationInformationModel added two dummy sites to the front
of the list (add new dive site). This was never used - desktop
uses its own model, mobile only extracts the list of dive site
names with a custom function. Remove this functionality.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
With removal of the git_local_only from the preferences (see
ae653703a5), the users choice, in the mobile app, was not
stored any more in between sessions. This resulted in issue
1725.
So, in order to store that user preference, we need a new
preference. This is added here, but its not yet hooked up
in the app yet. This deals only with the preference handling.
And adapted tests are included.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
We bundle our version of libdivecomputer and don't expect Subsurface to work
with a different version, certainly not with something older than 0.5.
I kept the checks for SAMPLE_EVENT_STRING and DC_FIELD_STRING and DC_SAMPLE_TTS
because maybe there's a situation where being able to compile with a current
upstream version is useful.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Commit 810903bdb9 ("Import: pass a dive table to process_imported_dives()")
introduced the variables
struct dive *old_dive, *merged;
into process_imported_dives(), but never used them. It seems to be an
artifact of having split the function to use the try_to_merge_into()
helper function (that has those same variable names and _does_ use
them), but forgetting the original variables from the pre-split case.
Gcc understandably warns about it:
core/divelist.c: In function ‘process_imported_dives’:
core/divelist.c:1351:26: warning: unused variable ‘merged’ [-Wunused-variable]
struct dive *old_dive, *merged;
^~~~~~
core/divelist.c:1351:15: warning: unused variable ‘old_dive’ [-Wunused-variable]
struct dive *old_dive, *merged;
^~~~~~~~
and the trivial fix is to just remove that line that declares the stale
and unused variables.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
bperrybap reported on github that the ftdi timeouts can be excessive:
"the timeout period while waiting for read data to be 10x or even 100x
longer than it should be when there are read issues on the data cable
particularly when using Android and USB OTG cables. i.e. a 5 second
read timeout for not receiving data can be as long as 7 minutes"
and the reason is that the code at one point tried to use the regular
"gettimeofday()" to handle timeouts, but that doesn't exist in Windows.
We already have Windows-specific code to sleep for a number of
milliseconds in "ftdi_serial_sleep()", let's just extend that same
concept and add a "ftdi_serial_get_msec()" that returns the number of
msec's since some arbitrary point in time.
On Windows, that's just "GetTickCount()", and in sane environments it's
just a trivial wrapper around gettimeofday() to turn sec/usec into msec.
NOTE! The actual msec value doesn't have any meaning. Only the
difference between two calls to ftdi_serial_get_msec() is meaningful.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Some divecomputer backends (ok, right now really only the Aqualung i770R
and i300C) want to know the bluetooth name of the dive computer they
connect to, because the name contains identifying information like the
serial number.
This just adds the support for that to our Qt BLE code.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
If only selected dives were exported into HTML, the statistics would
nevertheless cover all dives. A counter-intuitive behavior. Fix by
adding a selected_only flag to calculate_stats_summary().
Reported-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The statistics of the selected dives were calculated
a) into a global objects and
b) at a completely different place than where they're used.
There's no plausible reason for either. There fore render
into a caller-provided structure at the place of use.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Statistics were calculated into global variables every time the
current dive was changed.
Calculate statistics only when needed and into a structure
provided by the caller.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This flag had two distinct uses:
- signal that dives were downloaded, not imported
- use to mark imported dives
Both are not used anymore, therefore remove the flag.
The uemis downloaded misused the flag to mark deleted
dives. Instead misuse the "hidden_by_filter" flag.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
process_imported_dives() is more efficient for downloaded than for
imported (from a file) dives, because it checks only the divecomputer
of the first dive.
This condition is checked via the "downloaded" flag of the first
dive. Instead, pass an argument to process_imported_dives().
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Dive importing is now performed via a distinct table which is
merged into the main dive table. Thus, it is known which of the
dive is new and which is old. This information can now be
implicitely encoded in the parameter-position of merge_dive()
[i.e. pass old as first and new as second dive].
This makes marking of downloaded dives via a flag unnecessary.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Dives are now in all cases imported via distinct dive_tables.
Therefore the "preexisting" marker is useless. Remove.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Dives were directly imported into the global dive table and then
merged in process_imported_dives(). Make this interface more flexible,
by passing an independent dive table.
The dive table of the to-be-imported dives will be sorted and merged.
Then each dive is inserted in a one-by-one manner to into the global
dive table.
This actually introduces (at least) two functional changes:
1) If a new dive spans two old dives, it will only be merged to the
first dive. But this seems like a pathological case, which is of
dubious value anyway.
2) Dives unrelated to the import will not be merged. The old code
would happily merge dives that were not even close to the
newly imported dives. A surprising behavior.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The old surface interval calculation had fundamental issues:
1) process_all_dives(), which calculates the statistics over *all*
dives was used to get the pointer to the previous dive.
2) If two dives in the table had the same time, one of those would
have been considered the "previous" dive.
3) If the dive, for which the surface interval is calculated is
not yet in the table, no previous dive would be determined.
Fix all this by creating a get_surface_interval() function and
removing the "get previous dive" functionality of process_all_dives().
Remove the process_all_dives() call from TabDiveInformation::updateData().
Reported-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Because some BLE operations can be very slow (device and service
discovery etc), we have some rather excessive default timeout for BLE
(currently set to 12 seconds).
But once we actually have started doing IO, that long timeout can be a
big performance problem, when the libdivecomputer backend has support
for retry and packet loss.
For that reason, libdivecomputer has a 'set_timeout()' function that
allows the divecomputer backend to say how quickly it expects the dive
computer to answer before the backend will start resending packets.
Let's just implement that for the actual IO side of BLE too. The
default timeout value remains the general BLE timeout, and this only
affects the actual IO phase, but it improves things enormously for the
case where there is packet loss at that point.
For example, on the Aqualung i770R, the timeout for packet loss ends up
now being just one second rather than the full 12 seconds of default BLE
timeout. Which gets the retry going much faster.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
When we enable notifications, we actually want to make sure to wait for
that write to have completed before we start communicating with the
device, because otherwise we might lose notification events.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
In commit 30fb7bf35c ("qt-ble: set up infrastructure for better
preferred service choice") I moved the service filtering from the
addService() callback into the "select_preferred_service()" function
that picks the right service for the device.
That was nice for debugging, since it meant that we showed the details
of _all_ services, but it also meant that we ended up starting service
discovery on _all_ services, whether they looked at all interesting or
not.
And that can make the BLE device discovery process quite a bit slower.
The debugging advantage is real, but honestly, service discovery can
generally be better done with specialized tools like the Nordic nRF app,
so the debugging advantage of just listing all the details of all the
services is not really worth the discovery slowdown in general.
So move the basic "filter by uuid" back to the service discovery phase,
and don't bother starting service detail discovery for the services that
we can dismiss immediately just based on the service UUID.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
The error handling was incorrect for the case where we successfully
opened the libdivecomputer iostream in divecomputer_device_open(), but
the dc_device_open() call failed.
When the dc_device_open() failed, we would (correctly) not do the
dc_device_close() but we would _also_ not do the dc_iostream_close() to
close the underlying file descriptor, which is wrong.
Normally this isn't all that noticeable, partly because the common case
is that dc_device_open() succeeds if you actually do have a dive
computer connected, but also because most of the time it just leaked a
file descriptor or something like that.
However, particularly for the POSIX serial device case, libdivecomputer
does a
ioctl(device->fd, TIOCEXCL, NULL)
call to make serial opens exclusive. This is what we want - but if we
then fail at closing the serial file descriptor, we won't be able to
retry the import at all because now the next open will fail with EBUSY.
So the error handling was incorrect, and while it doesn't usually matter
all that much, it can be quite noticeable particularly when you have
transient errors.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
If no dives were downloaded in do_libdivecomputer_import(), an
error message would be produced. To check for downloaded dives,
the function would access the global downloadTable instead of
the actual table the dives are imported to (at the moment the
same - but the interface allows for a different table).
Move the error-creation to the caller to avoid this situation.
An alternative option would be to check the actual table the
dives were supposed to be downloaded to. But from a program-logic
point of view "no dives" does not seem like an error condition.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The Uemis downloader determines the dive-number to be downloaded
by either checking the download-table [interrupted connection] or
the global dive table [fresh download].
The downloadTable is passed in the device data structure, but
in the function to determine the latest dive, the global
downloadTable is accessed directly [thus supposing that this
table was passed in device data].
Instead, use the table from device data to avoid funny surprises
should we change to a non-global download table.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
On DAN-file import after each dive except the first, the dive-list
was processed. This seem bogus and inefficient. An artefact from
old code? In any case, remove.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Since we now keep track of up to 4 DCs we don't want to display the last used one
but rather the one that is connected.
Signed-off-by: Joakim Bygdell <j.bygdell@gmail.com>
Currently, we can only delete dives that are indexed in the main
dive table. In the future, we will have to delete dives outside
of this table (e.g. for undo). Therefore, split out the free_dive()
function from delete_single_dive(), which takes an index into
the main dive table.
In the process, adopt the dive freeing-code from clear_dive(),
which frees more data than the code in delete_single_dive().
This potentially fixes a memory-leak.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This reverts commit 1c4a859c8d,
where the override modifiers were removed owing to the noisy
"inconsistent override modifiers" which is default-on in clang.
This warning was disabled in 77577f717f,
so we can reinstate the overrides.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
In d815e0c947 a dive_table pointer
was added to the parsing functions to allow parsing into tables
other than the global dive table. This will be necessary for undo of
import and implementation a cleaner interface. A few cases, notably
CSV and proprietary formats were forgotten.
Implement parsing into arbitrary tables also for these cases.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
A few of these prototypes were already in import-csv.h.
Put them in an 'extern "C" { ... }' block.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The existing BLE dive computers treat BLE as the packetized protocol it
is, and read whole packets at a time.
However, the Mares BlueLink backend treats it as just a basic "serial
over BLE" transport, and for historical reasons reads the reply packets
in smaller chunks.
This allows that kind of IO behavior, where if the divecomputer backend
reads just a part of a packet, we'll split the packet, return the part
the user asked for, and push back the leftover packet onto the received
packet queue.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
We traditionally only allow samples to have a time format of 'mm:ss', so
if you have a dive over an hour, you would just have a minutes field
larger than 60 minutes.
But Matthew Critchley is trying to import some dives from his VMS
Redbare CCR, and the sample timestamp format he has is of the type
'hh:mm:ss'.
That could be fixed by a xslt translation, but there's no real reason
why we couldn't just support that format too.
Reported-by: Matthew Critchley <matthew.s.critchley@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This is perhaps overly verbose, but the timing details helped figure out
some EON Core download issues, and it's nice to see when things actually
happen.
It's also good to see when the data actually enters our queues, and when
we read and write the packets. That might help debug the issues Fabio
is seeing with the Mares Bluelink.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
We used to just find all services and connect the characteristics change
signal etc to them all, but we really only care about the actual
preferred service that we'll be using.
So move the qt ble signal connection to after we've selected the
preferred service that we will actually be enabling notifications on and
do the writes to.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
XMP is a media-metadata standard based on XML which may be used
across a variety of media formats. Some video-processing software
writes XMP data without updating the native metadata fields.
Therefore, we should aim at reading XMP metadata and give priority
of XMP data over native fields.
Pros:
- Support for *all* common media formats.
Cons:
- XML (complex, verbose, chaotic).
- Does not even come close to fulfilling its promise of being
well defined (see below).
Implement a simple XMP-parser using libxml2. Connect the XMP-parser to
the existing Quicktime/MP4 parser.
First problem encountered: According to the spec, XMP data supposed
to be put in the 'XMP_' atom. But for example exiftools instead
writes an 'uuid' atom with a special 16-byte uid. Implement both,
more options will probably follow.
Second problem: two versions of recording the creation date were found
1) The content of a <exif:DateTimeOriginal> tag.
2) The xmp::CreateDate attribute of a <rdf:Description> tag.
Here too, more versions are expected to surface and will have
to be supported in due course (with an obvious priority problem).
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
We use that in the mobile app to scale the whole app, as all sizes there
are relative to the default font.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
We used to just blindly pick "first" and "last" characteristic from the
preferred service, and that was stupid but happened to work for the dive
computers we supported. Note that for some of them, "first" and "last"
was actually the *same* characteristic, since it could be a single one
that supported both.
However, this first/last hack definitely doesn't work for the Mares
BlueLink BLE dongle, and it's really all pretty wrong anyway.
So re-organize the code to actually look at the properties of the
characteristics. I don't have a BlueLink to test with, but my EON Core
and Shearwater Perdix AI are still happy with this, and the code
conceptually makes a lot more sense.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
And remove some includes and defines that are not used any more after
removal of the GPS webservice code.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
Fix multiple run-time errors in connect call introduced in 504e912512.
1) Set the proper signature of the signal. 2) make the used slot
a real slot (so move it to the proper section in the header) and
3) set the proper signature for the slot.
Highly unlikely that normal users notice the runtime errors and
possibly unwantend behavior, as this all deals with the subtile GPS
service update threshold.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
We used to just pick the first non-standard service we found (with a
special case for the Heinrichs Weikamp dive computers that have an
actual registered standard service).
We then waited for that service to finish discovery, and started using
it.
This changes the logic to wait for _all_ services to finish discovery,
and then after that we pick the one we like best. Right now the rule
for picking a preferred service is the same one we had before, but the
difference is that we now have the full discovery data, so we *could* do
something better.
Plus this makes our debug messages a lot more legible, when we don't
have the mix of overlapping service discovery with the actual IO we do
to the preferred service.
NOTE! This doesn't much matter for most of the dive computers that we
currently support BLE for. They don't tend to have a lot of odd
services.
But at least both the Mares BlueLink and the Garmin Descent both have
multiple services and it's not obvious which one to use, and this will
make it not only easier to debug those, it will make it easier to pick
the right preferred service descriptor to use.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This is not only much clearer (and smaller code), but it also lowers the
latency for the waiting, since we don't always wait for the full 100ms.
Get rid of the now unused "waitfor()" function that just unconditionally
waited for 100ms.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
process_dives() is used to post-process the dive table after loading
or importing. The first parameter states whether this was after
load or import.
Especially in the light of undo, load and import are fundamentally
different things. Notably, that latter should be undo-able, whereas
the former is not. Therefore, as a first step to make import undo-able,
split the function in two versions and remove the first parameter.
It turns out the the load-version is very light. It only sets the
DC nicknames and sorts the dive-table. There seems to be no reason
to merge dives.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
We only store the address part of the connection name, so don't try to find an
exact match, try to find the sub-string.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This does feel clumsy and complicated. This is a lot of special case
handling and a lot of boilerplate for something that really should be
quite simple.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
In visit_on_node() in core/parse-xml.c the name is extracted into
a static buffer. There seems to be no need for this being static,
as the name is only passed to the entry() function which (hopefully)
does not store a reference to the name anywhere.
If it does, this would need a *big* *fat* comment.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The existing code creates a deterministic ID (not exactly "unique") in order to
help us avoid merge conflicts in git-storage mode. But as a side effect, if we
re-download the same dive twice from a dive computer that supports GPS (right
now only the Garmin Descent Mk1) we are guaranteed to create the same dive site
uuid when we do this. So when we download a dive - whether we will actually
*use* that dive later or not - we will be filling in the dive site information
with the data we got from the dive computer.
... and in the process we will be overwriting any data that was filled in
manually. The name of the dive site, but also possibly even the GPS of the dive
site (maybe the user decided to edit that using the map, because while the
automatically downloaded GPS data was "correct", maybe the user wanted to
change it to be the actual under-water location using the satellite data,
rather than the place where you started the dive or where you surfaced).
In order to avoid this collision, this patch just makes the libdivecomputer
download not use the dive time, but "time of download" for the dive site time,
and thus effectively generate a new uuid for every download.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
On import of dive media, the timestamp is read from the
metadata to check if the image belongs to the selected dives.
The pictures are then listed in a dialog.
Currently, the metadata is read twice if images are outside
of a dive: once in picture_check_valid() and if it turns
out that the picture is not valid again in picture_get_time()
to display the proper timestamp.
Even though metadata-extraction is reasonably fast, this is
a bit of an embarrassment.
Instead, read the timestamps only once in the constructor of
the dialog and from then on only used these timestamps. Keep
the timestamps in a QVector. Rename the picture_check_valid()
function to picture_check_valid_time() and pass a timestamp
instead of a filename.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The merge_one_sample() function adds a sample to the destination
dive if dives are merged. For long periods between samples at surface
depths, it adds a surface interval.
To decrease the number of global objects, make the sample structure
non-static. Of course, initialization of an on-stack structure is
slower. Therefore move it into the corresponding if. Thus, the
structure will be initialized only once per surface-interval.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Unit_system is read from git storage but units are set from locale when the
app starts. To prevent a miss-match between unit and unit_system we have to
always update the preferences variable when set_unit_system is called so that
the user doesn't end up with imperial units when the preferences say metric.
Signed-off-by: Joakim Bygdell <j.bygdell@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Using dc_serial_open as a fallback to ftdi_open is just wrong, and will
never work, just mask the real error and introduce read herrings.
Signed-off-by: Anton Lundin <glance@acc.umu.se>
Add a checkbox that triggers replacement of all English characters by
x's in notes, buddy, dive guide and (while we are at it) suit.
This is ment for people sharing logs for debugging that are concious
about privacy issues. It leaves the lenth of strings in tact as well
as special charcters as those might be needed to track down a particular
parsing problem.
Signed-off-by: Robert C. Helling <helling@atdotde.de>
Automate calling of setGpsTimeThreshold when qPref..::time_threshold changes
and thus avoiding the need to call setGpsTimeThreshold directly.
Signed-off-by: Jan Iversen <jani@apache.org>
Windows doesn't have nanosleep() unless libwinpthread is used.
Since the nanosleep() usage in serial_ftdi_sleep():
- does not break in case of EINTR
- has input in milliseconds
the WINAPI Sleep() should be a good alternative.
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
1) Add a missing <div>
2) More importantly: recognize html content via <div>-tags instead of
<table>-tags.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
QML is quite special, the variables needs to start with lower case in C++
and are used starting with upper case in QML
Signed-off-by: Jan Iversen <jani@apache.org>
In order to address the C++ object directy in qml, a different
registration is needed.
qmlRegisterType, registers the C++ class, allowing qml code to inherit
from it and make qml objects. This is needed for graphical elemnets
like profile and map
setContentProperty, registers the C++ object, thus allowing signals to be
catched.
Signed-off-by: Jan Iversen <jani@apache.org>
Instead of having all register calls in subsurface-helper.cpp let
qPref.cpp handle all qPref registration, since they also need to be
different
update subsurface-helper and testqml accordingly.
Signed-off-by: Jan Iversen <jani@apache.org>
QML demands signals to be of the form
<name>Changed
Changing all of qPref
REMARK: this commit is not compileable, since it only change qPref and not
the rest of the system
Signed-off-by: Jan Iversen <jani@apache.org>
And finnaly, get rid of the definition in the overall struct.
And one usage of the preferences was still around.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
Despite the fast that this code is sitting in core, its used mainly
from mobile. In 987e221f8e, the buttons to interact with the GPS
webservice were deleted from the UI. Now, delete all the code that
was used under these buttons.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
This the first of a set of cleanups related to the removal of 2
preferences: save_userid_local and userid. The commits are
ordered so that a sane running state remains, should a
bisect ever lands here.
Here, just read a git or XML logbook including the to be removed
preferences, as existing users can have this data sitting around.
The only thing done here is not to store the possibly read data
for the mentioned preferences.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
It's a mamber of the cloud storage authentication class, used to hold the
proposed new password until the backend has accepted it.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Commit f5b11daffd changed gasmix
arguments and return values to be passed by value instead of
using pointers.
Notably, get_gasmix() is fed a default-value and returns a
new value. In the old code, NULL was passed in in a first
loop iteration and non-NULL was always returned in the first
iteration. Thus, an equality comparison of passed-in an
returned gasmix would always fail in the first loop iteration.
The new code passed in air as default. Now if air was also
returned, then the matching gases were not calculated in
calculate_sac(). To revert to the old behavior, pass in
an invalid gasmix.
Moreover, give names to the invalid and air gasmixes.
Reported-by: tormento <turment@gmail.com>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
These are Deco N2 Low/High and Deco He Low/High events. They all appear
to be recorded at the same time, different events at same second.
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Measured He is documented (in comment). Will need information if all
measurements are needed or just start/end. First case would be added to
dive prifle, possibly cluttering it, second would be extra data.
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
This will record the ending battery status to extra data. Would need
info from CCR divers whether this suffices or if we should record also
the starting volatage or even every single reading.
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Add a variable reflecting the current_state to all DISK_* macros, in order to
check if the original variable in struct preferences is changed.
Only save to disk if actually changed
[Dirk Hohndel: merged Jan's commit and renamed the variable and adjusted the
commit message... but fundamentally the commit is still what Jan
wrote, so he should get the credit]
Signed-off-by: Jan Iversen <jani@apache.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
We had a couple of instances of names being incorrectly merged with their
group, this should handle that better. It's a bit of a big hammer to use, but
it seems to work (and it makes it easy to then git grep for cases that don't
use the new helper function.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
get_units() returns a pointer to the units struct in the preferences.
Callers should not modify the preferences via this struct, therefore
make the return value point to const.
This is a small step in constifying the global preferences structure.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
subsurface_webservice_uid ends up in the wrong group due missing
/. Notice that this does not fix the issues I mentioned in #1648.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
We had a special-case for the Shearwater case, let's just make it
slightly more generic and add Garmin to the list of vendors that want a
random BLE address rather than a static one.
The Bluez model of having to state this explicitly - but not giving the
information to the user - is completely broken and this is all very
annoying, credit goes to Wojciech Więckowski for pointing this out.
Of course, right now we don't actually know how to parse the BLE stream
from the Garmin Descent, but with this (and some libdivecomputer
hackery) I actually get connected and start receiving data. That we
then can't parse, but that's hopefully just a libdivecomputer update
away.
Pointed-out-by: Wojciech Więckowski <xplwowi@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
That just means that we're not in deco, the same way as giving a nonzero
NDL value does. But if you don't have NDL, this is a much more
convenient way of saying "not in deco".
The Garmin Descent gives us stop information, but not necessarily NDL,
and really wants this.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
libdivecomputer didn't use to have a TTS sample value, but we're adding
one, so add conditional support for it if it exists.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Writing logs to the path where the executable is located,
might not be possible if the current user doesn't have
permissions to write there.
Obtain the user path and write the log files to the
user path instead - e.g.:
c:\users\myuser\appdata\roaming\subsurface\subsurface_*.log
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
Modify the funcion system_default_path_append() to
both receive and return wchar_t types.
Remove fallback in system_default_path_append()
as this is now redundant.
Add a function utf16_to_utf8() and use that
in places where system_default_path_append() needs
to be converted to utf8.
Move both utf16_to_utf8*() and utf8_to_utf16*()
near the top of the file.
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
The match() function in parse-xml.c calls a very specific callback,
which doesn't take a context-parameter. To be able to call other
callbacks, split out the actual name-comparison.
Moreover, remove the "plen" parameter, as this was called with
strlen(pattern) in all cases anyway. Replace the old logic which
potentially accessed a byte beyond the end of name with a simply
classical C-style loop.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The match() function compares a pattern with a name with
a twist: The name may either end in '\0' or '.'. If pattern
and name match, a parsing function is called on a buffer and
a destination value. The result of the parsing is not checked.
This seems awfully XML-specific and therefore move the function
from the general parse.c to the specialized parse-xml.c unit
and make it of local linkage.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Dive computers that do GPS can report their GPS data as one or more
string fields, and if the first tree letters of the description is
"GPS", then we'll take the string and turn it into a dive site for that
dive.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
In commit 1bc361b2ea ("core/tests: add uuidString to qPrefUpdateManager") a
typo was introduced for the preference name.
Reported-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This is part of the whole "let's support the notion of dive computers
being exported as USB storage devices" push.
With an older libdivecomputer, we'll just fall back on failing the
operation, but we still want to support the generic notion of
DC_TRANSPORT_USBSTORAGE since we have our own internal Uemis downloader.
That one won't ever get to the open phase, since it's caught earlier.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This removes some special-case code for Uemis, replacing it with simply
passing in the device transport information.
This makes device enumeration work for the Garmin Descent (if it is
listed by libdivecomputer as a USB storage device, that is).
I don't actually do any of the libdivecomputer parsing yet, and only
have a stub for the Garmin Descent, but now the directory selection
works with that stub. The actual download obviously does not.
[Dirk Hohndel: removed obsolete FIXME from code]
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
The logic for finding a mount point for the Garmin FIT devices is
basically exactly the same as for the UEMISSDA, even if the rest of the
sequence is not the same.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
update testgitstorage.cpp to use qPrefProxy and qPrefCloudStorage
remove core/prefs-macros.h since it is unused
Signed-off-by: Jan Iversen <jani@apache.org>
Add class variable tooltip_position to qPrefDisplay
Add class variable lastDir to qPrefDisplay
qPrefDisplay is updated to use new qPrefPrivate functions
Adjust test cases incl. qml tests
qPrefAnimations only has 1 variable, that really is a display variable
Merge the variable into qPrefDisplay, to simplify setup (and avoid loading
extra page in qml).
correct theme to save in correct place, and make it a static
class variable
Signed-off-by: Jan Iversen <jani@apache.org>
uiLanguage overloaded qPrefLanguage and used useSystemLanguage instead
of use_system_language
Replace local load using QSettings with qPrefLanguage
Signed-off-by: Jan Iversen <jani@apache.org>
Some variables are not in structure prefs, but are static class
variables, these will not be synced on exit, because they can only
be changed through the setter, but loaded on startup.
Signed-off-by: Jan Iversen <jani@apache.org>
Small cleanup, using static methods is simpler and faster
Added propSetValue and propValue instead of exposing setting
variable.
Signed-off-by: Jan Iversen <jani@apache.org>
To enable undo of divelog-importing it is crucial that parse_file()
can parse into arbitrary dive tables.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
A trivial cleanup: replace void by properly typed pointers in
cylinder_none() and weightsystem_none(). Moreover, remove the
unused function no_weightsystems().
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
make next_check (in qPrefUpdateManager) long instead of string
Correct test cases (compare time_t not strings)
Add test case to check time_t works as expected
Signed-off-by: Jan Iversen <jani@apache.org>
This is another entry in the series to make more things
"const-clean" with the ultimate goal of merge_dive() take
const pointers.
This concerns functions taking pointers to events and
the fallout from making these const.
The somewhat debatable part of this commit might be
that get_next_event() is split in a two distinct
(const and non-const) versions with different names,
since C doesn't allow overloading. The linker should
recognize that these functions are identical and remove
one of them.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Accessor-functions without noticeable logic, such as depth_to_bar()
can trivially be made "const-clean".
Moreover, let get_dive_location() return a "const char *". The
non-const version must have been an oversight, as the caller
must not free() or overwrite the string.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In a previous commit, the get_gasmix_* functions were changed to
return by value. For consistency, also pass gasmix by value.
Note that on common 64-bit platforms struct gasmix is the size
of a pointer [2 * 32 bit vs. 64 bit] and therefore uses the
same space on the stack. On 32-bit platforms, the stack use
is probably doubled, but in return a dereference is avoided.
Supporting arbitrary gas-mixes (H2, Ar, ...) will be such an
invasive change that going back to pointers is probably the
least of our worries.
This commit is a step in const-ifying input parameters (passing
by value is the ultimate way of signaling that the input parameter
will not be changed [unless there are references to said parameter]).
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There were two functions for getting gas-mixes at a certain timestamp:
- get_gasmix() for repeated queries.
- get_gas_at_time() for a single query.
Since the latter is a special case of the former, simply call
the former in the latter. Moreover, rename to get_gasmix_at_time()
for consistency.
Replace on get_gasmix() call, which was outside of a loop by the
corresponding get_gasmix_at_time() call.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently, get_gasmix_from_event() and get_gasmix() return pointers
to either static or to (possibly changing) dive data. This seems like
a dangerous practice and the returned data should be used immediately.
Instead, return the gasmix by value. This is in preparation of
const-ifying input parameters of a number of core functions, which
will ultimately let the merge() function take const-arguments in
preparation of undo of dive-merging.
On common 64-bit systems gasmix (two "int"s) is the size of a pointer
and can be returned in a register.
On 32-bit systems a pointer to the struct to be filled out will be
passed.
Since get_gasmix() now returns a value, the first invocation is
tested by a NULL-initialized "struct event *". Document this in
a comment.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
remove use of SettingsObjectWrapper::
remove include of SettingsObjectWrapper.h
use qPrefFoo:: for setters and getters
replace prefs.foo with qPrefXYZ::foo() where feasible
(this expands to the same code, but gives us more control
over the variable).
Signed-off-by: Jan Iversen <jani@apache.org>
Make methods static to allow fast and esay access
use qPrefXYZ::foo() instead of qPrefXYZ::instance()->foo()
Signed-off-by: Jan Iversen <jani@apache.org>
Prepare qPref.* to run load/sync
Make variables and methods static to give easy access
Make getter inline to give faster access
Signed-off-by: Jan Iversen <jani@apache.org>:wq
The compiler complained about assigning the "const char *" returned by
mb_cstring() to a "char *". The warning is correct, as the returned
buffer still belongs to the membuffer. The code only worked because
destruction of the membuffer was "forgotten".
Fix this by using the "detach_buffer()" function, which passes ownership
to the caller and accordingly returns a "char *".
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Conceptually, the doFilter() functions shouldn't modify the dive
they test. Therefore, make the argument const. To do this, constify
the parameter of get_dive_location(), which likewise seems to be
the right thing to do.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
remove General from SettingsObjectWrapper and reference qPrefGeneral
update files using SettingsObjectWrapper/General to use qPrefGeneral
this activated qPrefGeneral and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct diveComputer
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
remove PartialPressureGas from SettingsObjectWrapper and reference qPrefPartialPressureGas
update files using SettingsObjectWrapper/PartialPressureGas to use qPrefPartialPressureGas
this activated qPrefPartialPressureGas and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct diveComputer
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
remove Geocoding from SettingsObjectWrapper and reference qPrefFacebook
update files using SettingsObjectWrapper/Geocoding to use qPrefFacebook
this activated qPrefGeocoding and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct preferences
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
remove Language from SettingsObjectWrapper and reference qPrefLanguage
update files using SettingsObjectWrapper/Language to use qPrefLanguage
this activated qPrefLanguage and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct preferences
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
remove LocationService from SettingsObjectWrapper and reference qPrefLocationService
update files using SettingsObjectWrapper/LocationService to use qPrefLocationService
this activated qPrefLocationService and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct prefs
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
remove TechnicalDetails from SettingsObjectWrapper and reference qPrefTechnicalDetails
update files using SettingsObjectWrapper/TechnicalDetails to use qPrefTechnicalDetails
this activated qPrefTechnicalDetails and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct diveComputer
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
remove buehlmann(), setBuehlmann(bool)
buehlmann() is really planner_deco_mode == BUEHLMANN, so no need for a function
setBuehlmann is dangerous, because buehlmann is saved on disk, but not in prefs.* and thus can lead to inconsistency between bool buehlmann and planner_deco_moce.
Signed-off-by: Jan Iversen <jani@apache.org>
Remove individual store to disk for divePlanner in SettingsObjectWrapper
The save was double effect, qPrefDivePlanner::instance()->sync(), which
was preciding already do this.
Signed-off-by: Jan Iversen <jani@apache.org>
If we get launched by an intent, we need to delay processing that Intent
until after the app is initialized. This is the helper function we'll use
for that.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
This always looked like a thread number and really made no sense since
we had a much more informative debug message just a couple lines above.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
And try to guess which one from the device string we get from the Intent.
The function is named to indicate its future use (because once the user
plugs in such a device, we should show the download page).
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
remove UpdateManager from SettingsObjectWrapper and reference qPrefUpdateManager
update files using SettingsObjectWrapper/UpdateManager to use qPrefUpdateManager
this activated qPrefUpdateManager and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct diveComputer
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
remove DivePlanner from SettingsObjectWrapper and reference qPrefDivePlanner
update files using SettingsObjectWrapper/DivePlanner to use qPrefDivePlanner
this activated qPrefDivePlanner and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct diveComputer
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
remove Units from SettingsObjectWrapper and reference qPrefUnits
update files using SettingsObjectWrapper/Units to use qPrefUnits
this activated qPrefUnits and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct diveComputer
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
There was a comment reading
/*++GETTEXT: these are three letter months - we allow up to six code bytes*/
but this is not valid (anymore), since the array contains only
untranslated strings, which will be translated on-the-fly.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The function is not only used at startup and arguably belongs
the the file with the rest of the low-level divelist functions.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Commit df156a56c0 replaced "virtual"
by "override" where appropriate. Unfortunately, this had the
unintended consequence of producing numerous clang warnings. If
clang finds a override-modified function in a class definition,
it warns for *all* overriden virtual functions without the override
modifier.
To solve this, go the easy route and remove all overrides. At least
it is consistent.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In metadata.cpp, replace a silly
"if (!memcmp(...) != 0)"
by the intended
"if (!memcmp(...))"
Obviously, both have the same effect. Fixes a warning.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The keyword "virtual" signalizes that the function is virtual,
i.e. the function of the derived class is called, even if the
call is on the parent class.
It is not necessary to repeat the "virtual" keyword in derived
classes. To highlight derived virtual functions, the keyword
"override" should be used instead. It results in a hard compile-
error, if no function is overridden, thus avoiding subtle bugs.
Replace "virtual" by "override" where appropriate. Moreover,
replace Q_DECL_OVERRIDE by override, since we require reasonably
recent compilers anyway. Likewise, replace /* reimp */ by
"override" for consistency and compiler support.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
WindowsTitleUpdate is such a trivial object (a QObject with a single
signal and no own state), that it's not really understandable why
it would need all that "singleton" boiler-plate. Just make it
a default constructed/destructed global object.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
remove Proxy from SettingsObjectWrapper and reference qPrefProxy
update files using SettingsObjectWrapper/Proxy to use qPrefProxy
this activated qPrefProxy and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct prefs
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
When BT_SUPPORT is not enabled, don't default to "true" for using bluetooth for downloading dives.
Otherwise, bluetooth will be forced since the bluetooth button has been removed and is never overridden.
Fixes#1541
Signed-off-by: Kristaps Dzonsons <kristaps@bsd.lv>
Extract thumbnails using ffmpeg.
Behavior is controlled by three new preferences fields:
- extract_video_thumbnails (bool): if true, thumbnails are calculated.
- extract_video_thumbnail_position (int 0..100): position in video
where thumbnail is fetched.
- ffmpeg_executable (string): path of ffmpeg executable.
If ffmpeg refuses to start, extract_video_thumbnails is set to false
to avoid unnecessary churn.
Video thumbnails are marked by an overlay.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
remove Facebook from SettingsObjectWrapper and reference qPrefFacebook
update files using SettingsObjectWrapper/Facebook to use qPrefFacebook
this activated qPrefFacebook and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct diveComputer
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
remove set_git_url and git_url_changed, because it is not possible
to set git_url, this is done inderectly through set_base_url
Update disk_base_url to generated git_url for both load/sync
Signed-off-by: Jan Iversen <jani@apache.org>
We can argue about any of the changes here, but they are the result of our
whitespace.pl script - so if any of this is offensive to you, part of the
resolution will be fixing the script...
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
userid was saved outside all groups, even though it belongs to cloudStorage
Add code to save in new location and read from new/old location
Signed-off-by: Jan Iversen <jani@apache.org>
remove DiveComputer from SettingsObjectWrapper and reference qPrefDiveComputer
update files using SettingsObjectWrapper/DiveComputer to use qPrefDiveComputer
this activated qPrefDiveComputer and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct diveComputer
- set function have set_<name>
- signal function have <name>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way
SettingsObjectWrapper handles it) secures the same storage name
is used. Having the set/get/load/sync functions grouped together
makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
Expand SET_, DISK_ and HANDLE_ macros with field for substructure
Structure prefs contains e.g. prefs.dive_computer.vendor an extra field
are added to the macros to allow this.
Signed-off-by: Jan Iversen <jani@apache.org>
expend LOADSYNC* into DISK_* macros
remove LOADSYNC* from qPrefPrivate.h
update qPrefDisplay to not use LOADSYNC*
Signed-off-by: Jan Iversen <jani@apache.org>
Add static and inline to getter in all qPref header files
Remove call to GET_PREFERENCE_* in qPrefDisplay.cpp
Remove GET_PREFERENCE_* from qPrefPrivate.h
static inline is slightly faster than a function call, but it saves
a lot of coding lines (no lines in qPref*.cpp). Getters are a direct
reference to struct preferences, so they will normally only be used
from QML.
Signed-off-by: Jan Iversen <jani@apache.org>
Add static and inline to getter in all qPref header files
Remove call to GET_PREFERENCE_* in qPrefDisplay.cpp
static inline is slightly faster than a function call, but it saves
a lot of coding lines (no lines in qPref*.cpp). Getters are a direct
reference to struct preferences, so they will normally only be used
from QML.
Signed-off-by: Jan Iversen <jani@apache.org>
Add copy_txt function to qPrefPrivate class
Remove macro COPY_TXT from qPrefPrivate.h
Replace use of COPY_TXT with copy_txt in qPref classes
copy_txt is only once, COPY_TXT was expanded approx. 160 times, so
this commit saves space (and removes a macro).
Signed-off-by: Jan Iversen <jani@apache.org>
Paint a rectangle on top of thumbnails indicating the run-time
of the video.
Use the z=100.0-101.0 range for painting the thumbnails, whereby
the z-value increases uniformly from first to last thumbnail
(sorted by timestamp). The duration-bars are placed at z-values
midway between those of the thumbnails.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Video thumbnails are more complex than simple picture thumbnails.
We store a duration and might want to store multiple images.
Therefore, refactor the thumbnailing in imagedownloader.cpp. Move
the thumbnail-writing down in the call chain to where the thumbnails
are created, since we have more information there (i.e. whether we
could parse the file but not extract an image, etc.).
Split the write-to-cache function into three versions:
- pictures
- videos
- unknown
Define the video-thumbnail on-disk format as
- uint32 MEDIATYPE_VIDEO
- uint32 duration of video in seconds
- uint32 number of pictures
for each picture:
- uint32 offset in msec from begining of video
- QImage frame
Currently, we write 0 pictures. This will be filled in subsequent commits.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
remove CloudStorage from SettingsObjectWrapper and reference qPrefCloudStorage
update files using SettingsObjectWrapper/CloudStorage to use qPrefCloudStorage
this activated qPrefCloudStorage and removed the similar class from
SettingsObjectWrapper.
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct preferences
- set function have set_<name> (from struct preferences>)
- signal function have <name>_changed (from struct preferences>)
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way SettingsObjectWrapper
handles it) secures the same storage name is used. Having the set/get/load/sync
functions grouped together makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
There were numerous inlined functions in dive.h. For many of them
inlining is dubious. Let's uninline most of them, with the exception
of trivial accessors and interpolate().
On current master, this gave a size reduction of 5 pages:
-rwxrwxr-x 1 bs bs 5863656 Jul 18 20:57 subsurface-inline
-rwxrwxr-x 1 bs bs 5843176 Jul 18 20:48 subsurface-noinline
-----------------------------------------------------------
20480
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
If the last dive of a trip is removed, the trip is deleted.
On redo the dive is added to a non existing trip, leading to a
segfault.
Therefore, keep a copy of the trip to reinstate it on redo.
Note: this cannot work for a sequence of multiple commands.
One would have to rewrite the whole undo-history. Nevertheless,
let's do this as a stop-gap measure.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Add qPrefPrivate class which contains one QSettings variable,
delete QSettings from qPref* class definitions
this secures there are only instance of QSettings
(QSettings needs to be in a QObject class to work)
Signed-off-by: Jan Iversen <jani@apache.org>
remove QSettings header file from qPref.h (which is included in many files)
to isolate the use of QSettings in the total system.
Signed-off-by: Jan Iversen <jani@apache.org>
The index-field was misused by the IO routines to mark which dives
had been saved. Somewhat questionable, but let's at least name the
field accordingly.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
find_trip_by_idx() and find_matching_trip() weren't used anywhere.
The trip index actually is only misused as a "trip saved"-flag.
trip_has_selected_dives() only existed as a comment.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
A number of small cleanups to the color-table:
1) Make the profile_color map of static linkage - it is not
used outside of this file.
2) Remove the third color, which originally was planned for
printing. It was not accessed anywhere.
3) Replace QVector<QColor> by std::array<QColor, 2>. Using a
reference-counted, copy-on-write, dynamic container for static
data seems like overkill. std::array<QColor, 2> has exactly the
same run-time impact as QColor[2], but allows for assignment.
4) Use brace-initialization and remove the unneeded COLOR macro.
5) Remove the fill_profile_color function. Simply use static
initialization.
6) Move #includes from .h to .cpp file.
7) Remove text_render_options(_t), which were not used anywhere.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
dive_getUniqID() is used to create unique dive ids, which are
stable during application lifetime. It was passed a dive, checked
that the id was not set (if it was that it is know to the application)
and set a new id (in contradiction to its name!) if it hadn't any.
There were three callers:
alloc_dive(): called the function on a zeroed dive struct.
fixup_dive(): called the function only if the dive had a 0 id.
MainWindow::setupForAddAndPlan(): called the function on a zeroed dive
struct.
Thus, in all three callers the id is guaranteed to be zero and
the whole keeping-track-of-ids logic is moot. Remove the logic,
don't pass a dive struct to dive_getUniqID() and move the function
to the C-backend.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
On top of the file filter for all media files add a file filter
for images only, one for videos only and one for all files.
Signed-off-by: Stefan Fuchs <sfuchs@gmx.de>
DISK_LOADSYNC_INT used double correct to int
DISK_LOADSYNC_INT used double correct to int
Signed-off-by: Jan Iversen <jani@apache.org>Signed-off-by: Jan Iversen <jani@apache.org>
SettingsObjectWrapper contained some delicate font handling mixing font and
font_size, breaking that into 2 parts broke font handling on some platforms
Copy font + font_size handling 1-1 from SettingsObjectWrapper
Signed-off-by: Jan Iversen <jani@apache.org>
Whereas extraction of the dive-duration is trivial, AVIs don't seem
to have a standardized way of saving the creation time. This commit
implements support for two versions randomly found on the internet.
Additional version will follow if need arises. AVI seems not to be
a particular popular format for either vacation or professional
videographers.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
We want the duration of videos for two reasons:
- To display the duration of the video in the profile plot.
- To be able to determine which dive a video is closer to if the
start is not during a dive.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Gracefully handle drag & drop to the profile, which changes the
offset of the pictures. To do this, keep the pictures in the
DivePictureModel and the ProfileWidget2 sorted by offset and
re-arrange if needed to keep the list sorted. This needs some
code reshuffling.
Introduce a helper-function that moves ranges in arrays.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Disables the WindowContextHelpButtonHint by default on Qt::Sheet and
Qt::Dialog widgets. This hides the ? button on Windows, which only
makes sense if you use QWhatsThis functionality.
This value has been added in Qt 5.10.
Signed-off-by: Stefan Fuchs <sfuchs@gmx.de>
When I switched over from our own custom IO implementation to the new
upstream custom IO model in libdivecomputer, I completely missed the
fact that the libdivecomputer custom IO model also does a custom _sleep_
function.
I'm not entirely sure what the point was, and it broke things even in
libdivecopmputer itself when some of the new sleep functions were
broken.
Anyway, we didn't export any sleep functions at all for the bluetooth,
BLE and FTDI cases, the the libdivecomputer code didn't fall back to any
sane default sleep implementation either, so the end result was no
sleeping at all.
Which didn't matter for most divecomputers.
But it seems like at least some OSTC dive computers did care, at least
in certain situations, and both Miika and Anton had trouble downloading
with their OSTC Sport dive computers. Using the serial line protocol
and the legacy /dev/rfcomm model worked fine, because then it used the
sleeping functions in the POSIX serial code inside libdivecomputer.
This just adds trivial sleeping functions for the affected download
protocols. Maybe I should have just made libdivecomputer have a sane
default instead, but this wasn't hard either (the hard part was trying
to figure out why the downloads worked for some people and not for
others).
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
remove Animations from SettingsObjectWrapper and reference qPrefAnimations
update files using SettingsObjectWrapper/Animations to user qPrefAnimations
this activated qPrefAnimations
Signed-off-by: Jan Iversen <jani@apache.org>
Update set/get functions to follow common name scheme:
- get function have same name as in struct preferences
- set function have set_<name in struct preferences>
- signal function have <name in struct preferences>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way SettingsObjectWrapper
handles it) secures the same storage name is used. Having the set/get/load/sync
functions grouped together makes it easier to get an overview.
REMARK: this commit only defines the class, it is not active in production
Signed-off-by: Jan Iversen <jani@apache.org>
ensure SettingsObjectWrapper load() loads all display variables.
Copy font setting code from SettingsObjectWrapper to qPrefDisplay
Signed-off-by: Jan Iversen <jani@apache.org>
Add qPrefDisplay sync to sync in SettingsObjectWrapper.
If a program part change display variables in struct preferences, they would
not be saved on disk.
Signed-off-by: Jan Iversen <jani@apache.org>
add the prepared class qPrefDisplay to SettingsObjectWrapper and thereby making it active.
As a consequence of the uniform naming standard desktop-widgets/preferences_defaults.cpp and
tests/testpreferences.cpp have been updated.
Signed-off-by: Jan Iversen <jani@apache.org>
add subsurface-helper.cpp to share functions between mobile and desktop
move mobile qml registrations to a shared function (avoiding differences in registrations)
Target is to replace current subsurface-desktop-main + subsurface-desktop-helper and
subsurface-mobile-main + subsurface-mobile-helper with
subsurface-*-main + subsurface-helper
Signed-off-by: Jan Iversen <jani@apache.org>
As per discussion in #1460 there is no point in showing decimal values
for pressures in the equipment tab on desktop or in the dive edit view on
mobile.
Signed-off-by: Joakim Bygdell <j.bygdell@gmail.com>
add canonical_version and mobile_version to qPref
Having a property in qPref, allows the use in qml, and prepare the
interface for qml testing.
Signed-off-by: Jan Iversen <jani@apache.org>
add enum to qPref and remove elsewhere
update source core to reference qPref.
the enum cannot be in pref.h because it is to be used in qml and Q_ENUM
need the enum to be defined as part of the class
Signed-off-by: Jan Iversen <jani@apache.org>
Show different images for IO-error and unknow file format.
Use file-extensions to recognize video files if we couldn't
parse them.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
As long as ProfileWidget2 and DivePictureModel showed the same set of
pictures and any change would lead to a full recalculation of the set,
it made sense to let ProfileWidget2 use DivePictureModel's data.
Recently, keeping the two lists in sync become more and more of a
burden. Therefore, disconnect ProfileWidget2 and DivePictureModel. This
will lead to some code-duplication and perhaps a temporary drop in
UI-performance, but in the end the code is distinctly simpler and also
more flexible.
Thus, for example the DivePhotoTab could be changed to support headings
without having to touch ProfileWidget2 at all.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
When generating thumbnails, test for video files. If it is, use
a dummy-thumbnail. Write only the type (video), but no image to
the thumbnail cache, for forward-compatibility.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
subsurface_user_info() only works on Linux (linux.c),
but it doesn't allocate values on the heap.
Solve this ownership problem by always allocating
.name and .email on the heap in subsurface_user_info()
and freeing in the caller.
If subsurface_user_info() did not modify any of the
values from NULL, use default ones, but allocate them
on the heap too.
Ref #1346
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
change qPrefDisplay.cpp to use qPref_private macros, for each variable. The macros
used depend on how standard the variable is handled.
Remark: this commit is production code, but qPrefDisplay is NOT integrated into
SettingsObjectWrapper and thus not active in the live system
Signed-off-by: Jan Iversen <jani@apache.org>
Add macros to handle get/set/loadsync function set functions in qPref
These macros are only convinience functions to write less for all those
variables who are traited standardized.
Signed-off-by: Jan Iversen <jani@apache.org>
Add macros to handle full function set functions in qPref
Remark: the function name is fixed to be "set_<name>" where name is
identical to the variable in struct preferences
This is not our standard naming, but is consistent with struct
preferences (that also use different name schemes).
Signed-off-by: Jan Iversen <jani@apache.org>
Add macros to handle full getter functions
Remark: it is assumed the name of getter function is identical to
the name in struct preferences.
Signed-off-by: Jan Iversen <jani@apache.org>
Use a private QSettings variable, instead of declaring it each time
Add macros to handle full disk* functions
Signed-off-by: Jan Iversen <jani@apache.org>
copy Display from SettingsObjectWrapper to qPref as its own class
file. Update Display to use a common load/sync scheme.
Update set/get functions to follow common name scheme:
- get function have same name as in struct preferences
- set function have set_<name in struct preferences>
- signal function have <name in struct preferences>_changed
one class one .h/.cpp is the C++ idiom. Having load/sync of each
variable in 1 functions (in contrast to the distributed way SettingsObjectWrapper
handles it) secures the same storage name is used. Having the set/get/load/sync
functions grouped together makes it easier to get an overview.
REMARK: this commit are made to show the use of the low level LOADSYNC macros, which will
be used for special cases. This class is NOT linked into the live system.
Signed-off-by: Jan Iversen <jani@apache.org>
In commit f3ef38ca0d ("Dive pictures: remove hashes") we removed picture
hashes, but removing them from the git parser causes an ugly red warning when
opening an existing cloud storage repo. With this patch we just silently ignore
the hash.
Fixes#1473
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
While we shouldn't have a dive that references a dive site that doesn't exist,
if we do, we shouldn't crash. And a dive site that doesn't exist is most
definitely 'empty'.
Reported-by: Benjamin Fogel <nystire@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
commit ec0511e824 ("ios: concentrate build dirs") moved the translations around
without updating the way they are accessed, causing our release 2.1.0 on iOS to
not be localized.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Only the first computer is taken into account to find
surface intervals. All further dive computers are split
according to time.
Signed-off-by: Robert C. Helling <helling@atdotde.de>
There were two catch-all classes for translations outside of class
context. gettextFromC was used exclusively from C, but C++ used
both, gettextFromC and QObject. Some of the string were even present
in both. Therefore, unify to gettextFromC throughout the code base.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Remove cloud_storage_status from qmlprefs.h.
usage to qPref::
enum cloud_storage_status is not used from C, but only from C++, and
having the same structure defined multiple times is a maintenance
challenge.
Signed-off-by: Jan Iversen <jani@apache.org>