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>