Compare commits

...

125 Commits

Author SHA1 Message Date
Miika Turkia
4d8d7c2a0f NULL terminate the parameters array
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-05 07:30:16 -07:00
Miika Turkia
93e529f371 Parse txt formatted log files
This parses .txt log files produced by Dataplus and Oceanlog software.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-05 07:30:16 -07:00
Miika Turkia
06843f1155 Use encoded file name on import
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-05 07:30:16 -07:00
Miika Turkia
a5611c1d28 Allow parsing of .txt files on import
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-05 07:30:16 -07:00
Dirk Hohndel
6a6f824caa Fix typo
Otherwise this code makes no sense (and has no effect).

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-03 09:56:13 -07:00
Miika Turkia
5916a4e37b Parse date and time from on APD import
This will parse the date and time information on CSV import if the file
name matches the one used by APD log viewer (date and time are available
in the file name). Hard coding the year to 20?? is a bit unfortunate,
but as there is only 2 digits in the year, we have to invent something.
And it would be quite optimistic to assume this will bite us back any
time soon :D

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-03 09:50:50 -07:00
Miika Turkia
bd20b8c9a2 CSV import: import dive number if defined
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-02 12:01:55 -07:00
Miika Turkia
51b7de7812 CSV import: import time field if available
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-02 12:01:55 -07:00
Miika Turkia
f1a24f08fb CSV import: support for user specified date format
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-02 12:01:55 -07:00
Miika Turkia
f3abedd588 Print xsltproc command line on verbose mode
Printed command line can be used to manually test the import function,
allowing faster testing of XSLT changes, and showing debug prints that
are discarded by Subsurface.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-02 12:01:54 -07:00
Miika Turkia
4393f59250 CSV import: use date field on profile import
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-02 12:01:54 -07:00
Miika Turkia
46fa803259 CSV import: convert cylinder size from imperial
This will convert cylinder size when importing from imperial units. I am
using default working pressure of 3000 PSI that is not precisely
correct, but should be close enough for the most common aluminium
cylinders.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-05-02 12:01:54 -07:00
Dirk Hohndel
403a7b959c Update ReleaseNotes
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-26 09:38:53 -07:00
Miika Turkia
97a26166e7 Add Ubuntu Xenial to be built (16.04)
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-26 09:26:52 -07:00
Miika Turkia
21ad9ac62c Abort git authentication attempt
If we have incorrect cloud credentials, we need to return an error on
git authentication call back in order to avoid endless authentication
loop. This might well happen e.g. when changing the password on desktop
and then on laptop Subsurface still thinks the credentials are validated
and ends up in the authentication loop.

The authentication call back on libgit is intended to be used to ask for
user credentials, and as we handle credentials elsewhere, we just need
to fail the authentication attempts. (The threshold for bail out could
have been 1 attempt...)

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:34:24 -07:00
Miika Turkia
4ef2ef1540 Fix time parsing for Divesoft Freedom
Divesoft uses 17 bits for time so parse accordingly.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:32:50 -07:00
Miika Turkia
573489bebc DL7: parse temperature and cylinder pressure
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:32:35 -07:00
Miika Turkia
14aafaa67d Parse date and time in DL7 import
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:32:22 -07:00
Miika Turkia
6df8752d7d Grab the payload of DL7 file
This allows us to parse the DL7 profile data (skipping the header and
footer)

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:32:10 -07:00
Miika Turkia
9d26f40279 CSV import: support min.sec format
Assume a format containing a dot to be min.sec as defined in DL7
specification.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:31:58 -07:00
Miika Turkia
6cc6c04521 Special handling for DL7
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:31:44 -07:00
Miika Turkia
f7ec0b3dd0 Detect DL7 depth units
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:31:36 -07:00
Miika Turkia
d6f6a8c7f8 Basic GUI part for DL7 import
This sets the basic properties properly but is still missing the parsing
of meta-data, especially used units.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:31:27 -07:00
Miika Turkia
9fe0cbaae4 Fix file extension regesp
The original negative lookahead failed in case the file name contains
more than 1 dot as it looks for dot that is not followed by the given
extensions. And such a match exists in the file name. The new version
should look properly if the file ends with any of the given extensions.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:31:15 -07:00
Miika Turkia
979dee2de7 Add CSV parsing trigger for zxu and zxl files
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:03:28 -07:00
Miika Turkia
696541e7b0 Add DAN DL7 file extensions for import UI
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:03:16 -07:00
Miika Turkia
c52bbc660c Detect pipe as field separator in CSV import
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:02:50 -07:00
Miika Turkia
3ce15d236b Add pipe as supported field separator on CSV import
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-25 12:02:15 -07:00
Dirk Hohndel
40af185902 Latest translations
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-19 15:46:24 -07:00
Dirk Hohndel
e56e522ac5 Update ReleaseNotes
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-18 21:00:47 -07:00
Miika Turkia
410ea40229 Import picture URLs from divelogs.de
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-18 20:59:25 -07:00
Miika Turkia
a1fb31a2d8 Fix UDDF import indentation
Only indentation is changed on this commit.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-18 20:59:08 -07:00
Dirk Hohndel
a26c1c6df1 Updates for version 4.5.6
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-18 20:14:40 -07:00
Rick Walsh
ed8e665242 VPM-B profile: declare CVA iteration variables within each loop
The variables that control each CVA iteration should be declared at the start
of each loop so that the values are carried over from one iteration to the
next.

Signed-off-by: Rick Walsh <rickmwalsh@gmail.com>
Signed-off-by: Robert C. Helling <helling@atdotde.de>
2016-04-18 20:10:10 -07:00
Robert C. Helling
15d07a879e Fix time of first ceiling calculation
In our verision of VPM-B for real dives, we take as the deco time the
difference between the time of the deepest ceiling and the time when the
ceiling clears.

When the display of ceilings was set to multiples of 3m this was confused, as
the maximum finder had issues: First of all, it updated the time when the ceiling
was the same (which was almost always the case for stepped ceilings) but changing
>= to > was not enough, since then the first time a deepest stepped ceiling was
reached was used.

This patch uses the actual ceiling (not rounded to the next integer multiple of 3m)
for this calculation to get rid of this problem.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2016-04-18 20:09:58 -07:00
Linus Torvalds
b3b43e0140 Fix dive computer copying
When copying a dive, we need to copy all the dive computers, but the first
one is special since it is embedded inside the "struct dive".

We had special case code for that case, but it only copied the samples and
events.

Use the proper "copy_dc()" for the primary dive computer copying too,
which gets all the details right.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-11 12:23:49 -07:00
Linus Torvalds
7e15c2a7ad Fix seabear import sample overrun bug
The Seabear import fixed up the NDL and TTS in the samples from minutes
(in the import) to seconds (our internal format for all time).  But it
did it with a loop that overran the end of the samples array by one:

	for(int s_nr = 0 ; s_nr <= dive->dc.samples ; s_nr++) {

Fix it to use the proper "<" instead of "<=".

Reported-by: Stuart Vernon <stuartv@force2.net>
Tested-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-11 12:23:39 -07:00
Dirk Hohndel
37e08d5e25 Give git progress dialog a chance to actually display something
The UI only runs when the main thread pauses, but the main thread is busy
doing the git update.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-09 08:33:37 -07:00
Dirk Hohndel
d0754138a4 Update ReleaseNotes
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-09 08:33:37 -07:00
Dirk Hohndel
669e2bf9fe Cloud storage: make first connect a post
But don't wait for it to succeed.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-09 08:33:36 -07:00
Dirk Hohndel
fe8c2ba6ce Update ReleaseNotes
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-02 06:32:18 -05:00
Miika Turkia
e9caf75db0 SDM import: fix logic for sample import
Seems that testing if BOOKMARK is empty is a bad idea. We end up not
getting any samples, but the ones containing a bookmark. So we need to
switch the logic to testing if BOOKMARK contains something and do those
tasks first and otherwise grab a regular sample.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-02 06:31:31 -05:00
Miika Turkia
916ed01830 SDM import: calculate duration if needed
Seems that DiveManager does not always return the dive duration in
DIVETIMESEC field. In this case we can try to calculate the duration
from sample count and interval.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-04-02 06:31:22 -05:00
Dirk Hohndel
3ba21027b9 Get ready for 4,5,5 release
Update README and ReleaseNotes

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-28 16:40:15 -05:00
Robert C. Helling
90bd1b0af7 When changing units from psi to bar first change value, then max
otherwise the max interferes with the value. Furthermore this increases
the max values a bit.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-23 13:55:09 -07:00
Werner Macho
fd10342b24 typo fix
small typo fix for GUI

Signed-off-by: Werner Macho <werner.macho@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-23 13:38:05 -07:00
Dirk Hohndel
c332bf2cfa Don't start Add or Plan while accessing cloud storage
This avoids a race condition where we get confused about our internal
state.

Fixes #1031

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-22 17:20:17 -07:00
Robert C. Helling
e167506bdb Make the reserve gas units aware
In the planner, for recreational mode, there is a setting indicating
the pressure at which the diver should be back at the surface. This
pressure was hardcoded to bar.

Fixes #1027

[Dirk Hohndel: small modifications, more reasonable step for psi,
               more reasonable maxima]

Signed-off-by: Robert C. Helling <helling@atdotde.de>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-22 16:32:39 -07:00
Miika Turkia
0d080f3249 CSV export
Need to discard dive site notes on csv export..

miika

From ab23245e2acee32410fa680d0eaab098af69b5c2 Mon Sep 17 00:00:00 2001
From: Miika Turkia <miika.turkia@gmail.com>
Date: Mon, 21 Mar 2016 17:50:28 +0800
Subject: [PATCH] CSV export: discard dive site notes

The new format of divesite management breaks the CSV export as the notes
of divesites are matched.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-22 08:43:46 -07:00
Rick Walsh
550f07da8b Profile widget: Display gradient factors used in plan
Currently, the gradient factors displayed at the top of the profile are the
gradient factors set in preferences.  This is correct for saved dives, but
when planning dives, the gradient factors displayed at the top of the profile
should be the gradient factors used in the plan.

Signed-off-by: Rick Walsh <rickmwalsh@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-19 11:35:28 -07:00
Dirk Hohndel
3f4d0e317d Fix cmake for libssh2 1.7 and later
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-19 11:17:16 -07:00
Rick Walsh
ea281b66a8 Calculate VPM-B ceiling outside of planner
Doing VPM-B calculations for dives outside of the planner has not been
possible because real dive data does not record either:
	- reference pressure for the Boyle's law compensation (i.e.
first_stop_pressure), or
	- deco_time for the vpmb_next_gradient function used to do the CVA
calculations

However, we can infer these values to be:
	- first_stop_pressure is the deepest ceiling in the dive
	- deco_time is dive time from the deepest ceiling until the
	  ceiling clears (or would have cleared if the diver finished
	  their deco obligations)

With these assumptions, the CVA converges rapidly.

Signed-off-by: Rick Walsh <rickmwalsh@gmail.com>
Signed-off-by: Robert C. Helling <helling@atdotde.de>
2016-03-18 09:54:44 -07:00
Rick Walsh
e15f13d861 Profile: Display VPM-B rather than GF when in VPM-B mode
If we are planning a dive using VPM-B with +x conservatism, we want to
print "VPM-B +x" at the top of the profile, instead of "GF xx/yy".

Accordingly, the variable gradientFactor in profilewidget2.cpp is renamed
decoModelParameters to reflect what it represents.

Signed-off-by: Rick Walsh <rickmwalsh@gmail.com>
Signed-off-by: Robert C. Helling <helling@atdotde.de>
2016-03-18 09:54:30 -07:00
Anton Lundin
ab1dc3ce38 configure OSTC/OSTC3: Bugfix depth parameter unit
The unit for the depth parameters ain't meters, its 0.1 meters. This
caused the values stored to be out of range.

Signed-off-by: Anton Lundin <glance@acc.umu.se>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-18 09:52:43 -07:00
Jeroen Massar
122088c891 Verify that the Xcode Command Line Tools are installed
Otherwise /usr/include does not exist on a clean-ish install

Signed-off-by: Jeroen Massar <jeroen@massar.ch>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-16 07:34:57 -07:00
Jeroen Massar
1bea93d6ee build.sh: detect user's Qt5.5 + Qt5.6
As in master: detect Qt path and Homebrew qt5 + preserve that path in
CMAKE_PREFIX_PATH and pass it along to cmake

Signed-off-by: Jeroen Massar <jeroen@massar.ch>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-16 07:33:58 -07:00
Jeroen Massar
777ee8a5cd Debug reminder: how to get more verbose details out of cmake
Signed-off-by: Jeroen Massar <jeroen@massar.ch>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-16 07:33:17 -07:00
Miika Turkia
e90b409a14 UDDF export: fix dive site support
We need to match the divesites to suppress extra output that breaks the
XML. This is because the divesites are actually gathered by calling a
template.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-16 07:31:46 -07:00
Robert C. Helling
2639281354 Copy picture struct for worker thread
This copies the picture struct when delegating image handling
to a worker thread to prevent a crashe when main thread
frees the picture upon selecting a different dive.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-15 22:38:47 -07:00
Robert C. Helling
2368f3371b Store Thumbnails with image hashes
This drastically improves the time it takes to select a dive
with several pictures at the expense of longer startup and
bigger hash files.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-15 22:38:35 -07:00
Robert C. Helling
126ce41b5c Don't build libdivecomputer examples
... as those don't compile.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-03-15 13:36:26 -07:00
Dirk Hohndel
2163ae026f Update ReleaseNotes
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-28 06:38:58 +01:00
Robert C. Helling
b1c923cd59 If salinity is not density, add density of fresh water
There was a reported case of an import of a dive that gave a salinity of
35g/l. This is an actual salinity (an amount of salt in the water) but
for subsurface the salinity is actually the density of the water. So for
too small values of the salinity add the density of fresh water.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-27 22:31:43 +01:00
Dirk Hohndel
563ff6bdc4 Prepare README and ReleaseNotes for 4.5.4
Just so I don't forget. Still some more testing needed.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-27 00:02:25 +01:00
Miika Turkia
55fbddb756 Initialize the random number generator
We use random numbers for file names, both temporary filename when
creating a zip for divelogs.de upload and for filename on form data for
facebook upload. This does not require for true randomness but we still
want these to not be constant on each run of Subsurface. Thus we need to
initialize the random number generator.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:31:16 +01:00
Miika Turkia
d5f2bb2353 Use full precision on weight system on XSLT transforms
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:31:08 +01:00
Miika Turkia
d38f50d128 Divelogs.de import: encode + character on password
Upload seems to work as is...

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:30:48 +01:00
Miika Turkia
875a9035fb Allow merging of dives with zero depth/duration
Fixes #1003

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:25:08 +01:00
Miika Turkia
7e1ba8e925 Fix Liquivision import crash
When we detect a redundant DC we free the memory reserved for the model.
Thus we need to malloc that memory here.

Fixes #1002

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:24:56 +01:00
Jan Mulder
e15ec99dfe Update copyright for 2016
Trival string update.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:24:38 +01:00
Miika Turkia
a5dde4c34a Mark CCR dive's divetype properly
We used to mark CCR dives by having "SP change" event at time 0:00.
As we nowadays mark CCR dives by setting dc->divemode appropriately,
better to convert the old dives to this format as well. This way we do
not have to take the special old format into account on multiple places
in the source.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:23:43 +01:00
Miika Turkia
43ec76283b Attempt to detect time format on CSV import
This attempts to detect the time format when initially importing a CSV
file. Well, only the minutes:seconds notation is detected currently.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:23:19 +01:00
Miika Turkia
3c83b2218b Attempt to detect date format on CSV import
This tries to detect the date format when initially reading a CSV file
for importing.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:23:10 +01:00
Miika Turkia
9bd9850688 Show only as many stats as there are DC types
After reserving only the required amount of data for stats_by_type, we
showed an extra DC type on the statistics (no more extra space filled
with 0 at the end of the buffer)

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:21:51 +01:00
Miika Turkia
e8afb7120c Support PSI on CSV import
Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:21:25 +01:00
Anton Lundin
7ae578ae6a configure OSTC/OSTC3: Add safety stop parameters
This adds the configure parameters for safety stops on the hwOS(OSTC3)
and OSTC computers.

Signed-off-by: Anton Lundin <glance@acc.umu.se>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:21:07 +01:00
Anton Lundin
c13da59ecc configure OSTC3: Add temperature sensor offset
Signed-off-by: Anton Lundin <glance@acc.umu.se>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:20:59 +01:00
Anton Lundin
19caca1d36 Use libdivecomputer libc wrappers instead of Qt
Signed-off-by: Anton Lundin <glance@acc.umu.se>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:20:51 +01:00
Anton Lundin
57bb04a529 Remove unused headers
Signed-off-by: Anton Lundin <glance@acc.umu.se>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:20:39 +01:00
Anton Lundin
cf095489aa Remove workaround for OSTC Sport 10.22 and below
Now with firmware 10.23, the settings behave as they should, and won't
hang the communication.

Signed-off-by: Anton Lundin <glance@acc.umu.se>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:20:31 +01:00
krisalpha
2a4ce01322 Fix UI issue with location management
The index in the fixpopup function was incorrect which caused the user to
need TWO cursor down presses to move to the second element. I changed the
index value so the user now needs only one key press to traverse up/dowm.

Fixes #954

Signed-off-by: krishan Chopra <choprakrishan61@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:18:49 +01:00
Dirk Hohndel
a01e4fefb4 Don't blindly copy a pointer to the heap
Copying the entry pointer and assuming that it stays valid is of course totally
bogus. This is most likely the reason for the random crashes people have
observed.

See #992

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:18:25 +01:00
Dirk Hohndel
b2eee9db6b Fix crash with empty (or very short) dive list
In commit 37c10c8fd6 ("Add dive type to statistics window") not enough
space is reserved for the newly introduced array if the dive list as fewer
than 4 entries.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:17:33 +01:00
Miika Turkia
403d6dcfb0 Add dive type to statistics window
This adds dive type based division to the "yearly statistics" window.
Thus people can see the stats from individually from OC, CCR, PSCR and
freedive.

See #949

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:16:55 +01:00
Miika Turkia
b73f56bc43 Hide the time from trip tab
This hides the start time when viewing trip details.

See #964

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:16:24 +01:00
Miika Turkia
09cec219f7 Mark date field readonly on trip edit
The date comes from the first dive in trip, thus no need to allow
editing (especially since the edited date seems to be discarded in any
case).

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:16:11 +01:00
Miika Turkia
cd44aabb5f Support for imperial depth on worldmap export
This will use the depth units from user preferences when exporting the
worldmap.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:15:43 +01:00
Miika Turkia
5229c507cb Add automake to the list of Debian dependencies
automake is recommended by autoconf, but depending on the
configuration, the recommended packages might not be installed. Thus
it is better to have it explicitly listed.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:15:23 +01:00
Miika Turkia
4052fea817 Improve group information on USB device
As the group can be something else than dialout on some systems, mention
this on user manual.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:15:02 +01:00
Miika Turkia
f3c8ae2bf8 Fix UDCF import time unit in timedepthmode
The timedepthmode specifies the time in seconds when using si units,
otherwise minutes. This patch implements this support.

Fixes #981

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:14:46 +01:00
Dirk Hohndel
95020f5989 Pull latest translations
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-02-26 09:13:56 +01:00
Dirk Hohndel
ca3b1bb6ef Add Catalan translation
And enable it for builds.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2016-01-29 12:11:55 -08:00
Dirk Hohndel
efc7117c21 Latest translations
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-13 11:40:16 -08:00
Dirk Hohndel
9fe1e0fb34 New strings for translations
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-07 10:41:06 -08:00
Dirk Hohndel
06e704d98a Documentation updates for 4.5.3
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-07 09:45:32 -08:00
Dirk Hohndel
f9d5fe56b3 Revert "NSIS: add a couple of uninstaller checkboxes"
This reverts commit d69c9e08af3c0c00807337dacab66a89075f2eab.

While this is a nice improvement, it requires other patches to work
correctly which go beyond what I'm comfortable having in a "quick update
to 4.5".
2015-12-07 09:32:17 -08:00
Dirk Hohndel
e1768b4771 Uemis downloader: handle yet another corner case
If we looking for dive details and are trying to guess the offset between
object_id and logfilenr, we need to treat logfilenr 0 as special - it
means we read past the end of the list of stored dives and need to walk
backwards.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 13:41:07 -08:00
Lubomir I. Ivanov
76c97f2e57 profilewidget2.cpp: hide the heartbeat graph on an empty state
Opening Subsurface for the first time with heartbeat graph visible
and then immediately doing File->New shows the logo/background in the
profile space while hiding everything except the heartbeat graph.

This patch makes sure that the graph is hidden with everything
else on an empty profile state.

Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 12:19:26 -08:00
Dirk Hohndel
f577967629 Only warn about different number of tanks and gases if there are tanks
Some backends support giving tank data for some, but not all models that
they support (and simply report no tanks for those models that don't
support this). The Suunto Vyper is one of the dive computers where this
happens and without this change we report angry red warnings after a
perfectly correct download.

So this changes the logic to only show that error if there actually were
tanks reported.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:42:29 -08:00
Dirk Hohndel
d6b7ea5f7f Cloud storage: do not store the actual pictures in git
Adding pictures to the repository was a big mistake on my part. It's very
easy for the git repositories to reach a gigabyte and more making sync
times (and especially "first download" times) completely unreasonable.

This doesn't solve the problem for existing repositories (as the pictures
are already there, in the git history), but at least it prevents us from
storing more pictures out there.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:37:19 -08:00
K. \"pestophagous\" Heller
e4c7c6e8eb Prevent gaschange tank icons from using garbage coords.
Tank icons were shown at incorrect spots on the profile
when the DiveEventItem object held a pointer to a struct
event even after the struct event at that address had
been freed.  When internalEvent is a pointer to freed
memory, internalEvent->time.seconds could have all kinds
of crazy values, which get used in member function
DiveEventItem::recalculatePos to place the tank at bad
x coordinates.

The DiveEventItem(s) no longer store a pointer to memory
that they do not own.  This way, no matter how the path of
execution arrives into slot recalculatePos, we never need
fear that the DiveEventItem will dereference a garbage
pointer to a struct event.

Fixes #968

Signed-off-by: K. Heller <pestophagous@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:37:07 -08:00
Dirk Hohndel
27ea079928 Uemis downloader: ignore leading junk in the data
One user's debug log shows valid data, only not in the format we've seen
before (with the response starting with '{'). Instead he gets a repeat of
the second word in the response to processSync prepended to the expected
output. So let's skip the data until the first '{'.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:36:36 -08:00
Dirk Hohndel
3029bc872c Uemis downloader: don't leak memory
Don't just clear out the buffer pointer, free the memory, first.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:36:30 -08:00
Dirk Hohndel
16ce14a29e User manual: add missing empty line
This way the ASCIIDOC works as expected and creates the numbered list.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:35:44 -08:00
Dirk Hohndel
9c26da3e29 Don't overwrite air temperature
If we already have an air temperature set, don't overwrite it with
potentially less accurate infromation from the first sample.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:35:36 -08:00
Dirk Hohndel
ea9303ff3c Location completion matches on whole name
When typing in a partial location name, the match now considers the whole
text, not just the start of the text. So typing in "Yell" will match both
"Yellow House" and "Mellow Yellow".

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:35:19 -08:00
Robert C. Helling
0a65fe500b Only close html tags if they were opened before
The runtime html table is printed only if printing
a verbatim diveplan is disabled. So the closing tags
should be printed only in that case.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:35:07 -08:00
Wendie Fisher
965b67847f Last set of updates to the user manual in this round
Once again focus on language and readability.

Signed-off-by: Wendie Fisher <wendie@divedad.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:33:30 -08:00
Lubomir I. Ivanov
cd81f37200 subsurfacestartup.c: leave free_prefs() empty
There is a bug on OSX where free() is called on non-allocated
memory in free_prefs(). Most of the preferences are not freed
in free_prefs() while copy_string() is used on them, so let's
not free() any pointers in free_prefs() and leave them
as one-time leaks.

Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:31:02 -08:00
Lubomir I. Ivanov
d48a677259 planner.c: fix 'disclaimer' pointing to stack memory
In add_plan_to_notes() the 'disclaimer' is set to the temporary
buffer 'buf'. By making 'buf' static, 'disclaimer' now points to a
persistent buffer.

Bug was reported as bad characters when printing the planner
deco text.

Reported-by: Stefan Fuchs <sfuchs@gmx.de>
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:30:37 -08:00
Wendie Fisher
8daf6128f6 Next batch of language updates for the user manual
Signed-off-by: Wendie Fisher <wendie@divedad.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:29:59 -08:00
Dirk Hohndel
731e964932 Statistics tab: clear min/max duration with just one dive selected
Otherwise if the user selects more than one dive, then goes back to just a
single dive, the maximum and minimum duration of the previous selected
group of dives stays visible which is clearly incorrect.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:28:06 -08:00
Dirk Hohndel
0c2df219ef Uemis downloader: more debug output
Once again compile time enabled. I guess it would be nice to turn this
into a logfile (just like we have with the libdivecomputer backends).

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:27:55 -08:00
Dirk Hohndel
f29cf77b4e Uemis downloader: recover if dive info is completely missing
I user had a Uemis that had a dive log entry for a certain internal id but
no dive info for it. This appeared to be one of those dreaded dives when
the Uemis decides to start a dive at the end of a flight and then stays in
dive mode until it runs out of battery.

Anyway, if we see a number above and a number below, just give up and move
on.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:27:45 -08:00
Dirk Hohndel
31cdc9320e Uemis downloader: deal with a whole block of deleted dives
If every dive in a download block from the Uemis was deleted we kept
downloading that same block of dives. With this we remember how far we got
even if the dives ended up being deleted.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:27:36 -08:00
Dirk Hohndel
6b9d4669d1 Update Mac bundle build & sign scripts
These are mostly a convenience for me, they'd obviously have to be updated for
someone else trying to use them.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:27:04 -08:00
Dirk Hohndel
d20f0662b4 Uemis downloader: print some information on stderr in verbose mode
On the Mac the info on the download dialog isn't shown. So print it on
stderr as well when in verbose mode.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:26:37 -08:00
Dirk Hohndel
00c1405535 Don't crash if we have no WindowTitleUpdater registered
Subsurface-mobile doesn't have a window title with the name of our file
name at this point, so simply don't try to trigger the update.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:25:31 -08:00
Wendie Fisher
8a43e07408 Updates to the user manual
Small changes to the language to make it easier to read.

Signed-off-by: Wendie Fisher <wendie@divedad.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:24:32 -08:00
Lubomir I. Ivanov
d69c9e08af NSIS: add a couple of uninstaller checkboxes
Add a new dialog/page which is shown right before
the final "uninstall" click.

The dialog may contains two checkboxes - for registry
entries and for the user path. These checkboxes will not be
created if the user has not run the application yet,
as no registry keys will be available.

Selecting the user directory checkbox shows a warning message box,
that the user should make sure no important files are present there.

Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:22:30 -08:00
Miika Turkia
2bf84e6a5e Only include samples with data on UDDF import
According to the specification each proper sample should have depth, so
we can just ignore the empty waypoints.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:21:58 -08:00
Lubomir I. Ivanov
9a3532b0cd subsurfacestartup.c: don't double free 'default_filename'
'default_filename' is obtained from system_default_filename()
but system_default_filename() returns a static pointer
the HEAP memory of which is handled in main().

Remove the free() for 'default_filename' free_prefs()
to prevent a double free().

Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:21:40 -08:00
Miika Turkia
ffc8e0a661 Grab all gas mixes only when no tank data is given
Grabbing all gas mixes was added for Xdeep default cylinders, and it is
not required for other data sources that have tankdata info in the UDDF
file.

See #958

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:21:16 -08:00
Linus Torvalds
3555361e44 Don't overflow cylinder array in xml parsing
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:00:55 -08:00
Miika Turkia
77e259080f Give proper error message when no dives on a zip
We import a few logs that are archived in a zip file. E.g. divelogs.de
import is a zip file named with .dld extension. In case the zip file is
empty, we should return an error message that states that fact, not
parse error. This will also end the input file parsing cleaning up
the error message on the console.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2015-12-06 09:00:22 -08:00
97 changed files with 20327 additions and 8661 deletions

View File

@ -1,5 +1,8 @@
# cmake based build of Subsurface
# Uncomment his to see all commands cmake actually executes
# set(CMAKE_VERBOSE_MAKEFILE ON)
project(Subsurface)
cmake_minimum_required(VERSION 2.8.11)
@ -87,7 +90,7 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_LIBGIT23_API")
if(FORCE_LIBSSH)
find_package(Libssh2 QUIET CONFIG)
if ("${LIBSSH2_VERSION}" STRGREATER "1.6.1")
if ("${LIBSSH2_VERSION}" STRLESS "1.7" AND "${LIBSSH2_VERSION}" STRGREATER "1.6.1")
set(LIBSSH2_LIBRARIES Libssh2::libssh2)
endif()
if(!LIBSSH2_FOUND OR "${LIBSSH2_FOUND}" STREQUAL "")

File diff suppressed because it is too large Load Diff

View File

@ -94,7 +94,7 @@ sudo zypper install git gcc-c++ make autoconf automake libtool cmake libzip-deve
On Debian Jessie and recent Ubuntu flavors this seems to work
sudo apt-get install git g++ make autoconf libtool cmake pkg-config \
sudo apt-get install git g++ make autoconf automake libtool cmake pkg-config \
libxml2-dev libxslt1-dev libzip-dev libsqlite3-dev \
libusb-1.0-0-dev libgit2-dev \
qt5-default qt5-qmake qtchooser qttools5-dev-tools libqt5svg5-dev \

6
README
View File

@ -1,4 +1,4 @@
This is the README file for Subsurface 4.5.1
This is the README file for Subsurface 4.5.6
Please check the ReleaseNotes.txt for details about new features and
changes since Subsurface 4.5 (and earlier versions).
@ -24,11 +24,11 @@ If you want the latest release (instead of the bleeding edge
development version) you can either get this via git or the release tar
ball. After cloning run the following command:
git checkout v4.5.1 (or whatever the last release is)
git checkout v4.5.6 (or whatever the last release is)
or download a tar ball from:
http://subsurface-divelog.org/downloads/Subsurface-4.5.1.tgz
http://subsurface-divelog.org/downloads/Subsurface-4.5.6.tgz
Detailed build instructions can be found in the INSTALL file.

View File

@ -1,11 +1,85 @@
// _Subsurface_ 4.5.1 Release Notes
// _Subsurface_ 4.5.6 Release Notes
_Subsurface_ 4.5.1 - October 2015
_Subsurface_ 4.5.6 - April 2016
---------------------------------
Some of the changes since _Subsurface_ 4.5.0
Some of the changes since _Subsurface_ 4.5.5
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Fix crash when downloading from Bluetooth based dive computers
- Small fixes to VPM-B ceiling calculations
- Import picture URLs from divelogs.de
- Add support for the new version of the Suunto DX
- Don't get caught in endless loop of git authentication errors
- Fix time parsing of Divesoft Freedom
- Support DAN DL7 import
Some of the changes since _Subsurface_ 4.5.4
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Update to latest libdivecomputer which adds support for Cochran
Commander and EMC, Uwatec Aladin Sport, Suunto Zoop/Vyper Novo,
Suunto D4i and D6i with latest firmware, Heinrichs & Weikamp OSTC4,
Aqualung i450T and Cressi Newton.
- In the dive planner, switch pressure unit when planning in recreational
mode and setting a tank reserve
- In the dive planner, show the correct VPM-B + conservatism on the
profile when planning in VPM-B mode and show the planner specific
gradient factors in Bühlman mode.
- Enable showing a VPM-B based "ceiling" on the profile
- Fix bug regarding depth parameter in OSTC/OSTC3 configuration
- Fix bug in CSV export
- Fix bugs in Suunto DM5 import
- Fix potential race when immediately switching to Add dive or Planner
while accessing cloud storage
- Fix issue for some users with cloud storage passwords
Some of the changes since _Subsurface_ 4.5.3
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Update to latest libdivecomputer to fix a number of issues in the
parsing of dive computer data (Shearmos Amphos Air, Shearwater Predator,
several Oceanic models)
- Add support for Oceanic / Aeris F11, DiveSystem iX3M, Shearwater Perdix
- Fix several issues with imports from CSV, divelogs.de and other sources
- Add better support for OSTC3 configuration
- Fix potential rounding error when exporting weight systems
- If XML file contains actual salinity (instead of the density value that
we call salinity), correctly interpret that value
- Add statistics by dive type
- Small UI fixes
Some of the changes since _Subsurface_ 4.5.2
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Fix confusing warning about different number of tanks and gases on some
Suunto dive computers
- Fix missing temperatures on some Suunto dive computers
- Fix several corner cases in the Uemis support
- Fix a few random UI inconsistencies (UI elements not being cleared /
removed / reset in certain circumstances)
- Cloud storage: no longer store picture binary data in the Subsurface
cloud storage - this can cause excessively long sync times
- When matching dive site names when entering a location name, match
anywhere in the location name, not just from the beginning (this makes
it much easier to find existing dive locations if you remember only part
of the name)
- Some fixes for importing data from other formats
- English user manual has been updated for language consistency and
readability
Some of the changes since _Subsurface_ 4.5.1
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- No code changes to Subsurface, just an update to libdivecomputer and new
binaries on all platforms.
Some of the changes since _Subsurface_ 4.5
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Subsurface no longer crashes on Windows when run in the German
localization and using the planner
- avoid a situation in the planner where the user ends up with no usable

View File

@ -6,6 +6,7 @@
#include "pref.h"
#include "helpers.h"
#include "subsurfacewebservices.h"
#include "checkcloudconnection.h"
@ -29,6 +30,9 @@ bool CheckCloudConnection::checkServer()
request.setRawHeader("Accept", "text/plain");
request.setRawHeader("User-Agent", getUserAgent().toUtf8());
request.setUrl(QString(prefs.cloud_base_url) + TEAPOT);
// now set up an authentication test
CloudStorageAuthenticate *csa = new CloudStorageAuthenticate(0);
csa->backend(prefs.cloud_storage_email, prefs.cloud_storage_password);
QNetworkAccessManager *mgr = new QNetworkAccessManager();
reply = mgr->get(request);
connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit()));

View File

@ -1,8 +1,6 @@
#include "configuredivecomputerthreads.h"
#include "libdivecomputer/hw.h"
#include "libdivecomputer.h"
#include <QDateTime>
#include <QStringList>
#define OSTC3_GAS1 0x10
#define OSTC3_GAS2 0x11
@ -54,6 +52,11 @@
#define OSTC3_DYNAMIC_ASCEND_RATE 0x3F
#define OSTC3_GRAPHICAL_SPEED_INDICATOR 0x40
#define OSTC3_ALWAYS_SHOW_PPO2 0x41
#define OSTC3_TEMP_SENSOR_OFFSET 0x42
#define OSTC3_SAFETY_STOP_LENGTH 0x43
#define OSTC3_SAFETY_STOP_START_DEPTH 0x44
#define OSTC3_SAFETY_STOP_END_DEPTH 0x45
#define OSTC3_SAFETY_STOP_RESET_DEPTH 0x46
#define OSTC3_HW_OSTC_3 0x0A
#define OSTC3_HW_OSTC_3P 0x1A
@ -408,7 +411,7 @@ static dc_status_t read_ostc3_settings(dc_device_t *device, DeviceDetails *m_dev
dc_status_t rc;
dc_event_progress_t progress;
progress.current = 0;
progress.maximum = 52;
progress.maximum = 57;
unsigned char hardware[1];
//Read hardware type
@ -648,17 +651,13 @@ static dc_status_t read_ostc3_settings(dc_device_t *device, DeviceDetails *m_dev
READ_SETTING(OSTC3_BOTTOM_GAS_CONSUMPTION, bottomGasConsumption);
READ_SETTING(OSTC3_DECO_GAS_CONSUMPTION, decoGasConsumption);
READ_SETTING(OSTC3_MOD_WARNING, modWarning);
//Skip things not supported on the sport, if its a sport.
if (m_deviceDetails->model == "Sport") {
EMIT_PROGRESS();
EMIT_PROGRESS();
EMIT_PROGRESS();
} else {
READ_SETTING(OSTC3_DYNAMIC_ASCEND_RATE, dynamicAscendRate);
READ_SETTING(OSTC3_GRAPHICAL_SPEED_INDICATOR, graphicalSpeedIndicator);
READ_SETTING(OSTC3_ALWAYS_SHOW_PPO2, alwaysShowppO2);
}
READ_SETTING(OSTC3_DYNAMIC_ASCEND_RATE, dynamicAscendRate);
READ_SETTING(OSTC3_GRAPHICAL_SPEED_INDICATOR, graphicalSpeedIndicator);
READ_SETTING(OSTC3_ALWAYS_SHOW_PPO2, alwaysShowppO2);
READ_SETTING(OSTC3_SAFETY_STOP_LENGTH, safetyStopLength);
READ_SETTING(OSTC3_SAFETY_STOP_START_DEPTH, safetyStopStartDepth);
READ_SETTING(OSTC3_SAFETY_STOP_END_DEPTH, safetyStopEndDepth);
READ_SETTING(OSTC3_SAFETY_STOP_RESET_DEPTH, safetyStopResetDepth);
#undef READ_SETTING
@ -669,6 +668,13 @@ static dc_status_t read_ostc3_settings(dc_device_t *device, DeviceDetails *m_dev
m_deviceDetails->pressureSensorOffset = (signed char)uData[0];
EMIT_PROGRESS();
rc = hw_ostc3_device_config_read(device, OSTC3_TEMP_SENSOR_OFFSET, uData, sizeof(uData));
if (rc != DC_STATUS_SUCCESS)
return rc;
// OSTC3 stores the tempSensorOffset in two-complement
m_deviceDetails->tempSensorOffset = (signed char)uData[0];
EMIT_PROGRESS();
//read firmware settings
unsigned char fData[64] = { 0 };
rc = hw_ostc3_device_version(device, fData, sizeof(fData));
@ -689,7 +695,7 @@ static dc_status_t write_ostc3_settings(dc_device_t *device, DeviceDetails *m_de
dc_status_t rc;
dc_event_progress_t progress;
progress.current = 0;
progress.maximum = 51;
progress.maximum = 56;
//write gas values
unsigned char gas1Data[4] = {
@ -912,17 +918,14 @@ static dc_status_t write_ostc3_settings(dc_device_t *device, DeviceDetails *m_de
WRITE_SETTING(OSTC3_BOTTOM_GAS_CONSUMPTION, bottomGasConsumption);
WRITE_SETTING(OSTC3_DECO_GAS_CONSUMPTION, decoGasConsumption);
WRITE_SETTING(OSTC3_MOD_WARNING, modWarning);
//Skip things not supported on the sport, if its a sport.
if (m_deviceDetails->model == "Sport") {
EMIT_PROGRESS();
EMIT_PROGRESS();
EMIT_PROGRESS();
} else {
WRITE_SETTING(OSTC3_DYNAMIC_ASCEND_RATE, dynamicAscendRate);
WRITE_SETTING(OSTC3_GRAPHICAL_SPEED_INDICATOR, graphicalSpeedIndicator);
WRITE_SETTING(OSTC3_ALWAYS_SHOW_PPO2, alwaysShowppO2);
}
WRITE_SETTING(OSTC3_DYNAMIC_ASCEND_RATE, dynamicAscendRate);
WRITE_SETTING(OSTC3_GRAPHICAL_SPEED_INDICATOR, graphicalSpeedIndicator);
WRITE_SETTING(OSTC3_ALWAYS_SHOW_PPO2, alwaysShowppO2);
WRITE_SETTING(OSTC3_TEMP_SENSOR_OFFSET, tempSensorOffset);
WRITE_SETTING(OSTC3_SAFETY_STOP_LENGTH, safetyStopLength);
WRITE_SETTING(OSTC3_SAFETY_STOP_START_DEPTH, safetyStopStartDepth);
WRITE_SETTING(OSTC3_SAFETY_STOP_END_DEPTH, safetyStopEndDepth);
WRITE_SETTING(OSTC3_SAFETY_STOP_RESET_DEPTH, safetyStopResetDepth);
#undef WRITE_SETTING
@ -933,17 +936,19 @@ static dc_status_t write_ostc3_settings(dc_device_t *device, DeviceDetails *m_de
return rc;
EMIT_PROGRESS();
// OSTC3 stores the tempSensorOffset in two-complement
data[0] = (unsigned char)m_deviceDetails->pressureSensorOffset;
rc = hw_ostc3_device_config_write(device, OSTC3_TEMP_SENSOR_OFFSET, data, sizeof(data));
if (rc != DC_STATUS_SUCCESS)
return rc;
EMIT_PROGRESS();
//sync date and time
if (m_deviceDetails->syncTime) {
QDateTime timeToSet = QDateTime::currentDateTime();
dc_datetime_t time;
time.year = timeToSet.date().year();
time.month = timeToSet.date().month();
time.day = timeToSet.date().day();
time.hour = timeToSet.time().hour();
time.minute = timeToSet.time().minute();
time.second = timeToSet.time().second();
rc = hw_ostc3_device_clock(device, &time);
dc_datetime_t now;
dc_datetime_localtime(&now, dc_datetime_now());
rc = hw_ostc3_device_clock(device, &now);
}
EMIT_PROGRESS();
@ -1264,6 +1269,16 @@ static dc_status_t read_ostc_settings(dc_device_t *device, DeviceDetails *m_devi
m_deviceDetails->aGFHigh = read_ostc_cf(data, 68);
// CF69: Allow Gradient Factor change
m_deviceDetails->aGFSelectable = read_ostc_cf(data, 69);
// CF70: Safety Stop Duration [s]
m_deviceDetails->safetyStopLength = read_ostc_cf(data, 70);
// CF71: Safety Stop Start Depth [m]
m_deviceDetails->safetyStopStartDepth = read_ostc_cf(data, 71);
// CF72: Safety Stop End Depth [m]
m_deviceDetails->safetyStopEndDepth = read_ostc_cf(data, 72);
// CF73: Safety Stop Reset Depth [m]
m_deviceDetails->safetyStopResetDepth = read_ostc_cf(data, 73);
// CF74: Battery Timeout [min]
#ifdef DEBUG_OSTC_CF
for (int cf = 64; cf <= 95 && cf <= max_CF; cf++)
printf("CF %d: %d\n", cf, read_ostc_cf(data, cf));
@ -1565,6 +1580,16 @@ static dc_status_t write_ostc_settings(dc_device_t *device, DeviceDetails *m_dev
write_ostc_cf(data, 68, max_CF, m_deviceDetails->aGFHigh);
// CF69: Allow Gradient Factor change
write_ostc_cf(data, 69, max_CF, m_deviceDetails->aGFSelectable);
// CF70: Safety Stop Duration [s]
write_ostc_cf(data, 70, max_CF, m_deviceDetails->safetyStopLength);
// CF71: Safety Stop Start Depth [m]
write_ostc_cf(data, 71, max_CF, m_deviceDetails->safetyStopStartDepth);
// CF72: Safety Stop End Depth [m]
write_ostc_cf(data, 72, max_CF, m_deviceDetails->safetyStopEndDepth);
// CF73: Safety Stop Reset Depth [m]
write_ostc_cf(data, 73, max_CF, m_deviceDetails->safetyStopResetDepth);
// CF74: Battery Timeout [min]
#ifdef DEBUG_OSTC_CF
for (int cf = 64; cf <= 95 && cf <= max_CF; cf++)
printf("CF %d: %d\n", cf, read_ostc_cf(data, cf));

View File

@ -3,9 +3,7 @@
#include <QObject>
#include <QThread>
#include <QVariant>
#include "libdivecomputer.h"
#include <QDateTime>
#include "devicedetails.h"
class DeviceThread : public QThread {

4
deco.c
View File

@ -244,7 +244,7 @@ double tissue_tolerance_calc(const struct dive *dive, double pressure)
double lowest_ceiling = 0.0;
double tissue_lowest_ceiling[16];
if (prefs.deco_mode != VPMB || !in_planner()) {
if (prefs.deco_mode != VPMB) {
for (ci = 0; ci < 16; ci++) {
tissue_inertgas_saturation[ci] = tissue_n2_sat[ci] + tissue_he_sat[ci];
buehlmann_inertgas_a[ci] = ((buehlmann_N2_a[ci] * tissue_n2_sat[ci]) + (buehlmann_He_a[ci] * tissue_he_sat[ci])) / tissue_inertgas_saturation[ci];
@ -509,7 +509,7 @@ void add_segment(double pressure, const struct gasmix *gasmix, int period_in_sec
tissue_n2_sat[ci] += n2_satmult * pn2_oversat * n2_f;
tissue_he_sat[ci] += he_satmult * phe_oversat * he_f;
}
if(prefs.deco_mode == VPMB && in_planner())
if(prefs.deco_mode == VPMB)
calc_crushing_pressure(pressure);
return;
}

View File

@ -73,6 +73,11 @@ DeviceDetails::DeviceDetails(QObject *parent) :
modWarning(false),
dynamicAscendRate(false),
graphicalSpeedIndicator(false),
alwaysShowppO2(false)
alwaysShowppO2(false),
tempSensorOffset(0),
safetyStopLength(0),
safetyStopStartDepth(0),
safetyStopEndDepth(0),
safetyStopResetDepth(0)
{
}

View File

@ -91,6 +91,11 @@ public:
bool dynamicAscendRate;
bool graphicalSpeedIndicator;
bool alwaysShowppO2;
int tempSensorOffset;
unsigned safetyStopLength;
unsigned safetyStopStartDepth;
unsigned safetyStopEndDepth;
unsigned safetyStopResetDepth;
};

48
dive.c
View File

@ -474,11 +474,10 @@ void copy_dive(struct dive *s, struct dive *d)
d->weightsystem[i].description = copy_string(s->weightsystem[i].description);
STRUCTURED_LIST_COPY(struct picture, s->picture_list, d->picture_list, copy_pl);
STRUCTURED_LIST_COPY(struct tag_entry, s->tag_list, d->tag_list, copy_tl);
/* Copy the embedded dc first, then copy the list */
copy_dc(&s->dc, &d->dc);
STRUCTURED_LIST_COPY(struct divecomputer, s->dc.next, d->dc.next, copy_dc);
/* this only copied dive computers 2 and up. The first dive computer is part
* of the struct dive, so let's make copies of its samples and events */
copy_samples(&s->dc, &d->dc);
copy_events(&s->dc, &d->dc);
}
/* make a clone of the source dive and clean out the source dive;
@ -525,6 +524,22 @@ void selective_copy_dive(struct dive *s, struct dive *d, struct dive_components
}
#undef CONDITIONAL_COPY_STRING
struct event *clone_event(const struct event *src_ev)
{
struct event *ev;
if (!src_ev)
return NULL;
size_t size = sizeof(*src_ev) + strlen(src_ev->name) + 1;
ev = (struct event*) malloc(size);
if (!ev)
exit(1);
memcpy(ev, src_ev, size);
ev->next = NULL;
return ev;
}
/* copies all events in this dive computer */
void copy_events(struct divecomputer *s, struct divecomputer *d)
{
@ -534,9 +549,7 @@ void copy_events(struct divecomputer *s, struct divecomputer *d)
ev = s->events;
pev = &d->events;
while (ev != NULL) {
int size = sizeof(*ev) + strlen(ev->name) + 1;
struct event *new_ev = malloc(size);
memcpy(new_ev, ev, size);
struct event *new_ev = clone_event(ev);
*pev = new_ev;
pev = &new_ev->next;
ev = ev->next;
@ -1102,6 +1115,8 @@ static void fixup_water_salinity(struct dive *dive)
for_each_dc (dive, dc) {
if (dc->salinity) {
if (dc->salinity < 500)
dc->salinity += FRESHWATER_SALINITY;
sum += dc->salinity;
nr++;
}
@ -2148,6 +2163,9 @@ static int find_sample_offset(struct divecomputer *a, struct divecomputer *b)
*/
static int similar(unsigned long a, unsigned long b, unsigned long expected)
{
if (!a && !b)
return 1;
if (a && b) {
unsigned long min, max, diff;
@ -2338,6 +2356,20 @@ static void free_pic(struct picture *picture)
}
}
// When handling pictures in different threads, we need to copy them so we don't
// run into problems when the main thread frees the picture.
struct picture *clone_picture(struct picture *src)
{
struct picture *dst;
dst = alloc_picture();
copy_pl(src, dst);
return dst;
}
static int same_sample(struct sample *a, struct sample *b)
{
if (a->time.seconds != b->time.seconds)
@ -3368,7 +3400,7 @@ void dive_set_geodata_from_picture(struct dive *dive, struct picture *picture)
}
}
static void picture_free(struct picture *picture)
void picture_free(struct picture *picture)
{
if (!picture)
return;

5
dive.h
View File

@ -376,6 +376,7 @@ struct picture {
for (struct picture *picture = (_divestruct).picture_list; picture; picture = picture->next)
extern struct picture *alloc_picture();
extern struct picture *clone_picture(struct picture *src);
extern bool dive_check_picture_time(struct dive *d, int shift_time, timestamp_t timestamp);
extern void dive_create_picture(struct dive *d, char *filename, int shift_time, bool match_all);
extern void dive_add_picture(struct dive *d, struct picture *newpic);
@ -385,6 +386,7 @@ extern bool picture_check_valid(char *filename, int shift_time);
extern void picture_load_exif_data(struct picture *p);
extern timestamp_t picture_get_timestamp(char *filename);
extern void dive_set_geodata_from_picture(struct dive *d, struct picture *pic);
extern void picture_free(struct picture *picture);
extern int explicit_first_cylinder(struct dive *dive, struct divecomputer *dc);
extern int get_depth_at_time(struct divecomputer *dc, int time);
@ -409,6 +411,8 @@ static inline int calculate_depth_to_mbar(int depth, pressure_t surface_pressure
mbar = SURFACE_PRESSURE;
if (!salinity)
salinity = SEAWATER_SALINITY;
if (salinity < 500)
salinity += FRESHWATER_SALINITY;
specific_weight = salinity / 10000.0 * 0.981;
mbar += rint(depth / 10.0 * specific_weight);
return mbar;
@ -725,6 +729,7 @@ extern int split_dive(struct dive *);
extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer_downloaded);
extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded);
extern void renumber_dives(int start_nr, bool selected_only);
extern struct event *clone_event(const struct event *src_ev);
extern void copy_events(struct divecomputer *s, struct divecomputer *d);
extern void free_events(struct event *ev);
extern void copy_cylinders(struct dive *s, struct dive *d, bool used_only);

107
file.c
View File

@ -105,6 +105,9 @@ int try_to_open_zip(const char *filename, struct memblock *mem)
success++;
}
subsurface_zip_close(zip);
if (!success)
return report_error(translate("gettextFromC", "No dives in the input file '%s'"), filename);
}
return success;
}
@ -828,7 +831,7 @@ int parse_txt_file(const char *filename, const char *csv)
record_dive(dive);
return 1;
} else {
return report_error(translate("gettextFromC", "No matching DC found for file '%s'"), csv);
return 0;
}
return 0;
@ -856,22 +859,86 @@ int parse_csv_file(const char *filename, char **params, int pnr, const char *csv
if (filename == NULL)
return report_error("No CSV filename");
time(&now);
timep = localtime(&now);
strftime(tmpbuf, MAXCOLDIGITS, "%Y%m%d", timep);
params[pnr++] = "date";
params[pnr++] = strdup(tmpbuf);
/* As the parameter is numeric, we need to ensure that the leading zero
* is not discarded during the transform, thus prepend time with 1 */
strftime(tmpbuf, MAXCOLDIGITS, "1%H%M", timep);
params[pnr++] = "time";
params[pnr++] = strdup(tmpbuf);
params[pnr++] = NULL;
mem.size = 0;
if (!strcmp("DL7", csvtemplate)) {
char *ptr = NULL;
char *NL = NULL;
char *iter = NULL;
char *tmp = NULL;
csvtemplate = "csv";
if (readfile(filename, &mem) < 0)
return report_error(translate("gettextFromC", "Failed to read '%s'"), filename);
/* Determine NL (new line) character and the start of CSV data */
if ((ptr = strstr(mem.buffer, "\r\n")) != NULL) {
NL = "\r\n";
} else if ((ptr = strstr(mem.buffer, "\n")) != NULL) {
NL = "\n";
} else {
fprintf(stderr, "DEBUG: failed to detect NL\n");
return -1;
}
ptr = strstr(mem.buffer, "ZDH");
if (ptr) {
iter = ptr + 1;
for (i = 0; i <= 4 && iter; ++i) {
iter = strchr(iter, '|');
if (iter)
++iter;
}
/* Setting date */
memcpy(tmpbuf, iter, 8);
tmpbuf[8] = 0;
params[pnr++] = "date";
params[pnr++] = strdup(tmpbuf);
/* Setting time, gotta prepend it with 1 to
* avoid octal parsing (this is stripped out in
* XSLT */
tmpbuf[0] = '1';
memcpy(tmpbuf + 1, iter + 8, 6);
tmpbuf[7] = 0;
params[pnr++] = "time";
params[pnr++] = strdup(tmpbuf);
params[pnr++] = NULL;
}
ptr = strstr(mem.buffer, "ZDP");
if (ptr)
ptr = strstr(ptr, NL);
if (ptr)
ptr += strlen(NL);
/* Move the CSV data to the start of mem buffer */
memmove(mem.buffer, ptr, mem.size - (ptr - (char*)mem.buffer));
ptr = strstr(mem.buffer, "ZDP");
if (ptr) {
*ptr = 0;
} else {
fprintf(stderr, "DEBUG: failed to find end ZDP\n");
return -1;
}
mem.size = ptr - (char*)mem.buffer;
} else if (strcmp(params[0], "date")) {
time(&now);
timep = localtime(&now);
strftime(tmpbuf, MAXCOLDIGITS, "%Y%m%d", timep);
params[pnr++] = "date";
params[pnr++] = strdup(tmpbuf);
/* As the parameter is numeric, we need to ensure that the leading zero
* is not discarded during the transform, thus prepend time with 1 */
strftime(tmpbuf, MAXCOLDIGITS, "1%H%M", timep);
params[pnr++] = "time";
params[pnr++] = strdup(tmpbuf);
params[pnr++] = NULL;
}
if (try_to_xslt_open_csv(filename, &mem, csvtemplate))
return -1;
@ -1057,6 +1124,14 @@ int parse_manual_file(const char *filename, char **params, int pnr)
if (try_to_xslt_open_csv(filename, &mem, "manualCSV"))
return -1;
#ifndef SUBSURFACE_MOBILE
if (verbose >= 2) {
fprintf(stderr, "(echo '<manualCSV>'; cat %s;echo '</manualCSV>') | xsltproc ", filename);
for (i=0; params[i]; i+=2)
fprintf(stderr, "--stringparam %s %s ", params[i], params[i+1]);
fprintf(stderr, "%s/xslt/manualcsv2xml.xslt -\n", SUBSURFACE_SOURCE);
}
#endif
ret = parse_xml_buffer(filename, mem.buffer, mem.size, &dive_table, (const char **)params);
free(mem.buffer);

View File

@ -188,8 +188,23 @@ int credential_ssh_cb(git_cred **out,
unsigned int allowed_types,
void *payload)
{
(void) url;
(void) allowed_types;
(void) payload;
static int attempt = 0;
const char *priv_key = format_string("%s/%s", system_default_directory(), "ssrf_remote.key");
const char *passphrase = prefs.cloud_storage_password ? strdup(prefs.cloud_storage_password) : strdup("");
/* Bail out from libgit authentication loop when credentials are
* incorrect */
if (attempt++ > 2) {
report_error("Authentication to cloud storage failed.");
attempt = 0;
return GIT_EUSER;
}
return git_cred_ssh_key_new(out, username_from_url, NULL, priv_key, passphrase);
}
@ -199,8 +214,22 @@ int credential_https_cb(git_cred **out,
unsigned int allowed_types,
void *payload)
{
(void) url;
(void) username_from_url;
(void) payload;
(void) allowed_types;
static int attempt = 0;
const char *username = prefs.cloud_storage_email_encoded;
const char *password = prefs.cloud_storage_password ? strdup(prefs.cloud_storage_password) : strdup("");
/* Bail out from libgit authentication loop when credentials are
* incorrect */
if (attempt++ > 2) {
report_error("Authentication to cloud storage failed.");
attempt = 0;
return GIT_EUSER;
}
return git_cred_userpass_plaintext_new(out, username, password);
}

View File

@ -77,7 +77,7 @@ static int parse_gasmixes(device_data_t *devdata, struct dive *dive, dc_parser_t
int ntanks = 0;
rc = dc_parser_get_field(parser, DC_FIELD_TANK_COUNT, 0, &ntanks);
if (rc == DC_STATUS_SUCCESS) {
if (ntanks != ngases) {
if (ntanks && ntanks != ngases) {
shown_warning = true;
report_error("different number of gases (%d) and tanks (%d)", ngases, ntanks);
}
@ -695,7 +695,7 @@ static int dive_cb(const unsigned char *data, unsigned int size,
dc_parser_destroy(parser);
/* Various libdivecomputer interface fixups */
if (first_temp_is_air && dive->dc.samples) {
if (dive->dc.airtemp.mkelvin == 0 && first_temp_is_air && dive->dc.samples) {
dive->dc.airtemp = dive->dc.sample[0].temperature;
dive->dc.sample[0].temperature.mkelvin = 0;
}

View File

@ -114,17 +114,17 @@ static void parse_dives (int log_version, const unsigned char *buf, unsigned int
model = *(buf + ptr);
switch (model) {
case 0:
dc->model = "Xen";
dc->model = strdup("Xen");
break;
case 1:
case 2:
dc->model = "Xeo";
dc->model = strdup("Xeo");
break;
case 4:
dc->model = "Lynx";
dc->model = strdup("Lynx");
break;
default:
dc->model = "Liquivision";
dc->model = strdup("Liquivision");
break;
}
ptr++;

View File

@ -9,6 +9,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <git2.h>
#include <libdivecomputer/parser.h>
#include "gettext.h"
@ -744,6 +745,16 @@ static void parse_dc_event(char *line, struct membuffer *str, void *_dc)
if (str->len)
name = mb_cstring(str);
ev = add_event(dc, event.time.seconds, event.type, event.flags, event.value, name);
/*
* Older logs might mark the dive to be CCR by having an "SP change" event at time 0:00.
* Better to mark them being CCR on import so no need for special treatments elsewhere on
* the code.
*/
if (ev && event.time.seconds == 0 && event.type == SAMPLE_EVENT_PO2 && dc->divemode==OC) {
dc->divemode = CCR;
}
if (ev && event_is_gaschange(ev)) {
/*
* We subtract one here because "0" is "no index",

View File

@ -58,6 +58,14 @@ int main(int argc, char **argv)
#else
git_libgit2_init();
#endif
/*
* Initialize the random number generator - not really secure as
* this is based only on current time, but it should not matter
* that much in our context. Moreover this is better than
* the constant numbers we used to get before.
*/
qsrand(time(NULL));
setup_system_prefs();
copy_prefs(&default_prefs, &prefs);
fill_profile_color();

View File

@ -20,12 +20,35 @@ rm -rf ./Subsurface.app
LIBRARY_PATH=${DIR}/install-root/lib make -j8
LIBRARY_PATH=${DIR}/install-root/lib make install
# HACK TIME... QtXml is missing. screw this
cp -a /Users/hohndel/Qt/5.5/clang_64/lib/QtXml.framework Subsurface.app/Contents/Frameworks
rm -rf Subsurface.app/Contents/Frameworks/QtXml.framework/Versions/5/Headers
rm -rf Subsurface.app/Contents/Frameworks/QtXml.framework/Headers
rm -rf Subsurface.app/Contents/Frameworks/QtXml.framework/QtXml.prl
rm -rf Subsurface.app/Contents/Frameworks/QtXml.framework/Versions/5/*_debug
rm -rf Subsurface.app/Contents/Frameworks/QtXml.framework/*_debug*
install_name_tool -id @executable_path/../Frameworks/QtXml Subsurface.app/Contents/Frameworks/QtXml.framework/QtXml
install_name_tool -change @rpath/QtCore.framework/Versions/5/QtCore @executable_path/../Frameworks/QtCore.framework/QtCore Subsurface.app/Contents/Frameworks/QtXml.framework/QtXml
# now adjust a few references that macdeployqt appears to miss
EXECUTABLE=Subsurface.app/Contents/MacOS/Subsurface
for i in libssrfmarblewidget libgit2; do
for i in libssh libssrfmarblewidget libgit2; do
OLD=$(otool -L ${EXECUTABLE} | grep $i | cut -d\ -f1 | tr -d "\t")
cp ${DIR}/install-root/lib/$(basename ${OLD}) Subsurface.app/Contents/Frameworks
SONAME=$(basename $OLD)
install_name_tool -change ${OLD} @executable_path/../Frameworks/${SONAME} ${EXECUTABLE}
if [[ "$i" = "libssh" ]] ; then
LIBSSH=$(basename ${OLD})
fi
if [[ "$i" = "libgit2" ]] ; then
install_name_tool -change ${LIBSSH} @executable_path/../Frameworks/${LIBSSH} Subsurface.app/Contents/Frameworks/${SONAME}
fi
done
# next deal with libGrantlee
LIBG=Subsurface.app/Contents/Frameworks/libGrantlee_Templates.5.dylib
for i in QtScript.framework/Versions/5/QtScript QtCore.framework/Versions/5/QtCore ; do
install_name_tool -change @rpath/$i @executable_path/../Frameworks/$i ${LIBG}
done
# it seems the compiler in XCode 4.6 doesn't build Grantlee5 correctly,
@ -34,13 +57,16 @@ done
#
# -disabled for now as this is still under more investigation-
# cp -a /Users/hohndel/src/tmp/Subsurface.app/Contents Subsurface.app/
cp ${DIR}/tmp/Subsurface.app/Contents/Frameworks/lib{sql,usb,zip}* Subsurface.app/Contents/Frameworks
# clean up shared library dependency in the Grantlee plugins
for i in Subsurface.app/Contents/PlugIns/grantlee/5.0/*.so; do
OLD=$(otool -L $i | grep libGrantlee_Templates | cut -d\ -f1 | tr -d "\t")
SONAME=$(basename $OLD )
install_name_tool -change ${OLD} @executable_path/../Frameworks/${SONAME} $i;
mv $i Subsurface.app/Contents/PlugIns/grantlee
done
rmdir Subsurface.app/Contents/PlugIns/grantlee/5.0
# copy things into staging so we can create a nice DMG
rm -rf ./staging

View File

@ -5,9 +5,10 @@
echo -- signing staging/Subsurface.app
cd staging
echo -- signing Qt frameworks
echo -- signing Qt frameworks and shared libraries
codesign --keychain /Users/hohndel/Library/Keychains/login.keychain -s Dirk ./Subsurface.app//Contents/Frameworks/QtConcurrent.framework/Versions/5/QtConcurrent \
for i in \
./Subsurface.app//Contents/Frameworks/QtConcurrent.framework/Versions/5/QtConcurrent \
./Subsurface.app//Contents/Frameworks/QtCore.framework/Versions/5/QtCore \
./Subsurface.app//Contents/Frameworks/QtGui.framework/Versions/5/QtGui \
./Subsurface.app//Contents/Frameworks/QtMultimedia.framework/Versions/5/QtMultimedia \
@ -25,10 +26,20 @@ codesign --keychain /Users/hohndel/Library/Keychains/login.keychain -s Dirk ./Su
./Subsurface.app//Contents/Frameworks/QtWebKit.framework/Versions/5/QtWebKit \
./Subsurface.app//Contents/Frameworks/QtWebKitWidgets.framework/Versions/5/QtWebKitWidgets \
./Subsurface.app//Contents/Frameworks/QtWidgets.framework/Versions/5/QtWidgets \
./Subsurface.app//Contents/Frameworks/QtXmlPatterns.framework/Versions/5/QtXMLPatterns
./Subsurface.app//Contents/Frameworks/QtBluetooth.framework/Versions/5/QtBluetooth \
./Subsurface.app//Contents/Frameworks/QtDbus.framework/Versions/5/QtDbus \
./Subsurface.app//Contents/Frameworks/QtXml.framework/Versions/5/QtXml \
./Subsurface.app//Contents/Frameworks/QtWebChannel.framework/Versions/5/QtWebChannel \
./Subsurface.app//Contents/Frameworks/*.dylib
do
codesign --keychain /Users/hohndel/Library/Keychains/login.keychain -s Dirk $i
done
echo -- signing plugins
find ./Subsurface.app/Contents/PlugIns -name \*.dylib | xargs codesign --keychain /Users/hohndel/Library/Keychains/login.keychain -s Dirk
for i in $(find ./Subsurface.app/Contents/PlugIns -name \*.dylib -o -name \*.so)
do
codesign --keychain /Users/hohndel/Library/Keychains/login.keychain -s Dirk $i
done
echo -- finally sign .app
codesign --keychain /Users/hohndel/Library/Keychains/login.keychain -s Dirk ./Subsurface.app
codesign -v --keychain /Users/hohndel/Library/Keychains/login.keychain -s Dirk ./Subsurface.app

View File

@ -99,6 +99,12 @@ rel=wily
sed -i "s/${prev}/${rel}/g" debian/changelog
debuild -S
# and now for wily
prev=wily
rel=xenial
sed -i "s/${prev}/${rel}/g" debian/changelog
debuild -S
# and now for precise (precise can't build Qt5 based packages)
# with the switch to cmake the amount of effort to build Qt4 packages
# on precise just doesn't seem worth it anymore

View File

@ -1398,32 +1398,36 @@ static void try_to_fill_dive(struct dive *dive, const char *name, char *buf)
return;
if (MATCH("visibility.dive", get_rating, &dive->visibility))
return;
if (MATCH("size.cylinder", cylindersize, &dive->cylinder[cur_cylinder_index].type.size))
return;
if (MATCH("workpressure.cylinder", pressure, &dive->cylinder[cur_cylinder_index].type.workingpressure))
return;
if (MATCH("description.cylinder", utf8_string, &dive->cylinder[cur_cylinder_index].type.description))
return;
if (MATCH("start.cylinder", pressure, &dive->cylinder[cur_cylinder_index].start))
return;
if (MATCH("end.cylinder", pressure, &dive->cylinder[cur_cylinder_index].end))
return;
if (MATCH("use.cylinder", cylinder_use, &dive->cylinder[cur_cylinder_index].cylinder_use))
return;
if (MATCH("description.weightsystem", utf8_string, &dive->weightsystem[cur_ws_index].description))
return;
if (MATCH("weight.weightsystem", weight, &dive->weightsystem[cur_ws_index].weight))
return;
if (MATCH("weight", weight, &dive->weightsystem[cur_ws_index].weight))
return;
if (MATCH("o2", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2))
return;
if (MATCH("o2percent", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2))
return;
if (MATCH("n2", gasmix_nitrogen, &dive->cylinder[cur_cylinder_index].gasmix))
return;
if (MATCH("he", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.he))
return;
if (cur_ws_index < MAX_WEIGHTSYSTEMS) {
if (MATCH("description.weightsystem", utf8_string, &dive->weightsystem[cur_ws_index].description))
return;
if (MATCH("weight.weightsystem", weight, &dive->weightsystem[cur_ws_index].weight))
return;
if (MATCH("weight", weight, &dive->weightsystem[cur_ws_index].weight))
return;
}
if (cur_cylinder_index < MAX_CYLINDERS) {
if (MATCH("size.cylinder", cylindersize, &dive->cylinder[cur_cylinder_index].type.size))
return;
if (MATCH("workpressure.cylinder", pressure, &dive->cylinder[cur_cylinder_index].type.workingpressure))
return;
if (MATCH("description.cylinder", utf8_string, &dive->cylinder[cur_cylinder_index].type.description))
return;
if (MATCH("start.cylinder", pressure, &dive->cylinder[cur_cylinder_index].start))
return;
if (MATCH("end.cylinder", pressure, &dive->cylinder[cur_cylinder_index].end))
return;
if (MATCH("use.cylinder", cylinder_use, &dive->cylinder[cur_cylinder_index].cylinder_use))
return;
if (MATCH("o2", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2))
return;
if (MATCH("o2percent", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.o2))
return;
if (MATCH("n2", gasmix_nitrogen, &dive->cylinder[cur_cylinder_index].gasmix))
return;
if (MATCH("he", gasmix, &dive->cylinder[cur_cylinder_index].gasmix.he))
return;
}
if (MATCH("air.divetemperature", temperature, &dive->airtemp))
return;
if (MATCH("water.divetemperature", temperature, &dive->watertemp))
@ -1647,6 +1651,15 @@ static void event_end(void)
ev = add_event(dc, cur_event.time.seconds,
cur_event.type, cur_event.flags,
cur_event.value, cur_event.name);
/*
* Older logs might mark the dive to be CCR by having an "SP change" event at time 0:00. Better
* to mark them being CCR on import so no need for special treatments elsewhere on the code.
*/
if (ev && cur_event.time.seconds == 0 && cur_event.type == SAMPLE_EVENT_PO2 && dc->divemode==OC) {
dc->divemode = CCR;
}
if (ev && event_is_gaschange(ev)) {
/* See try_to_fill_event() on why the filled-in index is one too big */
ev->gas.index = cur_event.gas.index-1;
@ -3331,7 +3344,7 @@ int parse_dlf_buffer(unsigned char *buffer, size_t size)
while (ptr < buffer + size) {
time = ((ptr[0] >> 4) & 0x0f) +
((ptr[1] << 4) & 0xff0) +
(ptr[2] & 0x0f) * 3600; /* hours */
((ptr[2] << 12) & 0x1f000);
event = ptr[0] & 0x0f;
switch (event) {
case 0:

View File

@ -534,7 +534,8 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool
const unsigned int sz_temp = 100000;
char *buffer = (char *)malloc(sz_buffer);
char *temp = (char *)malloc(sz_temp);
char buf[1000], *deco;
char *deco;
static char buf[1000];
int len, lastdepth = 0, lasttime = 0, lastsetpoint = -1, newdepth = 0, lastprintdepth = 0, lastprintsetpoint = -1;
struct gasmix lastprintgasmix = {{ -1 }, { -1 }};
struct divedatapoint *dp = diveplan->dp;
@ -775,7 +776,8 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool
lastsetpoint = dp->setpoint;
lastentered = dp->entered;
} while ((dp = nextdp) != NULL);
len += snprintf(buffer + len, sz_buffer - len, "</tbody></table></div>");
if (!plan_verbatim)
len += snprintf(buffer + len, sz_buffer - len, "</tbody></table></div>");
dive->cns = 0;
dive->maxcns = 0;

186
profile.c
View File

@ -28,6 +28,9 @@ unsigned int dc_number = 0;
static struct plot_data *last_pi_entry_new = NULL;
void populate_pressure_information(struct dive *, struct divecomputer *, struct plot_info *, int);
extern bool in_planner();
extern pressure_t first_ceiling_pressure;
#ifdef DEBUG_PI
/* debugging tool - not normally used */
static void dump_pi(struct plot_info *pi)
@ -866,6 +869,8 @@ static void calculate_ndl_tts(struct plot_data *entry, struct dive *dive, double
int ascent_depth = entry->depth;
/* at what time should we give up and say that we got enuff NDL? */
int cylinderindex = entry->cylinderindex;
/* If iterating through a dive, entry->tts_calc needs to be reset */
entry->tts_calc = 0;
/* If we don't have a ceiling yet, calculate ndl. Don't try to calculate
* a ndl for lower values than 3m it would take forever */
@ -927,69 +932,136 @@ static void calculate_ndl_tts(struct plot_data *entry, struct dive *dive, double
*/
void calculate_deco_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, bool print_mode)
{
int i;
int i, count_iteration = 0;
double surface_pressure = (dc->surface_pressure.mbar ? dc->surface_pressure.mbar : get_surface_pressure_in_mbar(dive, true)) / 1000.0;
int last_ndl_tts_calc_time = 0;
for (i = 1; i < pi->nr; i++) {
struct plot_data *entry = pi->entry + i;
int j, t0 = (entry - 1)->sec, t1 = entry->sec;
int time_stepsize = 20;
bool first_iteration = true;
int deco_time = 0, prev_deco_time = 10000000;
char *cache_data_initial = NULL;
/* For VPM-B outside the planner, cache the initial deco state for CVA iterations */
if (prefs.deco_mode == VPMB && !in_planner())
cache_deco_state(&cache_data_initial);
/* For VPM-B outside the planner, iterate until deco time converges (usually one or two iterations after the initial)
* Set maximum number of iterations to 10 just in case */
while ((abs(prev_deco_time - deco_time) >= 30) && (count_iteration < 10)) {
int last_ndl_tts_calc_time = 0, first_ceiling = 0, current_ceiling, final_tts = 0 , time_clear_ceiling = 0, time_deep_ceiling = 0;
for (i = 1; i < pi->nr; i++) {
struct plot_data *entry = pi->entry + i;
int j, t0 = (entry - 1)->sec, t1 = entry->sec;
int time_stepsize = 20;
entry->ambpressure = depth_to_bar(entry->depth, dive);
entry->gfline = MAX((double)prefs.gflow, (entry->ambpressure - surface_pressure) / (gf_low_pressure_this_dive - surface_pressure) *
(prefs.gflow - prefs.gfhigh) +
prefs.gfhigh) *
(100.0 - AMB_PERCENTAGE) / 100.0 + AMB_PERCENTAGE;
if (t0 > t1) {
fprintf(stderr, "non-monotonous dive stamps %d %d\n", t0, t1);
int xchg = t1;
t1 = t0;
t0 = xchg;
}
if (t0 != t1 && t1 - t0 < time_stepsize)
time_stepsize = t1 - t0;
for (j = t0 + time_stepsize; j <= t1; j += time_stepsize) {
int depth = interpolate(entry[-1].depth, entry[0].depth, j - t0, t1 - t0);
add_segment(depth_to_bar(depth, dive),
&dive->cylinder[entry->cylinderindex].gasmix, time_stepsize, entry->o2pressure.mbar, dive, entry->sac);
if ((t1 - j < time_stepsize) && (j < t1))
time_stepsize = t1 - j;
}
if (t0 == t1)
entry->ceiling = (entry - 1)->ceiling;
else
entry->ceiling = deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, !prefs.calcceiling3m);
for (j = 0; j < 16; j++) {
double m_value = buehlmann_inertgas_a[j] + entry->ambpressure / buehlmann_inertgas_b[j];
entry->ceilings[j] = deco_allowed_depth(tolerated_by_tissue[j], surface_pressure, dive, 1);
entry->percentages[j] = tissue_inertgas_saturation[j] < entry->ambpressure ?
tissue_inertgas_saturation[j] / entry->ambpressure * AMB_PERCENTAGE :
AMB_PERCENTAGE + (tissue_inertgas_saturation[j] - entry->ambpressure) / (m_value - entry->ambpressure) * (100.0 - AMB_PERCENTAGE);
}
/* should we do more calculations?
* We don't for print-mode because this info doesn't show up there */
if (prefs.calcndltts && !print_mode) {
/* only calculate ndl/tts on every 30 seconds */
if ((entry->sec - last_ndl_tts_calc_time) < 30) {
struct plot_data *prev_entry = (entry - 1);
entry->stoptime_calc = prev_entry->stoptime_calc;
entry->stopdepth_calc = prev_entry->stopdepth_calc;
entry->tts_calc = prev_entry->tts_calc;
entry->ndl_calc = prev_entry->ndl_calc;
continue;
entry->ambpressure = depth_to_bar(entry->depth, dive);
entry->gfline = MAX((double)prefs.gflow, (entry->ambpressure - surface_pressure) / (gf_low_pressure_this_dive - surface_pressure) *
(prefs.gflow - prefs.gfhigh) +
prefs.gfhigh) *
(100.0 - AMB_PERCENTAGE) / 100.0 + AMB_PERCENTAGE;
if (t0 > t1) {
fprintf(stderr, "non-monotonous dive stamps %d %d\n", t0, t1);
int xchg = t1;
t1 = t0;
t0 = xchg;
}
if (t0 != t1 && t1 - t0 < time_stepsize)
time_stepsize = t1 - t0;
for (j = t0 + time_stepsize; j <= t1; j += time_stepsize) {
int depth = interpolate(entry[-1].depth, entry[0].depth, j - t0, t1 - t0);
add_segment(depth_to_bar(depth, dive),
&dive->cylinder[entry->cylinderindex].gasmix, time_stepsize, entry->o2pressure.mbar, dive, entry->sac);
if ((t1 - j < time_stepsize) && (j < t1))
time_stepsize = t1 - j;
}
if (t0 == t1) {
entry->ceiling = (entry - 1)->ceiling;
} else {
/* Keep updating the VPM-B gradients until the start of the ascent phase of the dive. */
if (prefs.deco_mode == VPMB && !in_planner() && (entry - 1)->ceiling >= first_ceiling && first_iteration == true) {
nuclear_regeneration(t1);
vpmb_start_gradient();
/* For CVA calculations, start by guessing deco time = dive time remaining */
deco_time = pi->maxtime - t1;
vpmb_next_gradient(deco_time, surface_pressure / 1000.0);
}
entry->ceiling = deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, !prefs.calcceiling3m);
if (prefs.calcceiling3m)
current_ceiling = deco_allowed_depth(tissue_tolerance_calc(dive, depth_to_bar(entry->depth, dive)), surface_pressure, dive, true);
else
current_ceiling = entry->ceiling;
/* If using VPM-B outside the planner, take first_ceiling_pressure as the deepest ceiling */
if (prefs.deco_mode == VPMB && !in_planner()) {
if (current_ceiling > first_ceiling) {
time_deep_ceiling = t1;
first_ceiling = current_ceiling;
first_ceiling_pressure.mbar = depth_to_mbar(first_ceiling, dive);
if (first_iteration) {
nuclear_regeneration(t1);
vpmb_start_gradient();
/* For CVA calculations, start by guessing deco time = dive time remaining */
deco_time = pi->maxtime - t1;
vpmb_next_gradient(deco_time, surface_pressure / 1000.0);
}
}
// Use the point where the ceiling clears as the end of deco phase for CVA calculations
if (current_ceiling > 0)
time_clear_ceiling = 0;
else if (time_clear_ceiling == 0)
time_clear_ceiling = t1;
}
}
for (j = 0; j < 16; j++) {
double m_value = buehlmann_inertgas_a[j] + entry->ambpressure / buehlmann_inertgas_b[j];
entry->ceilings[j] = deco_allowed_depth(tolerated_by_tissue[j], surface_pressure, dive, 1);
entry->percentages[j] = tissue_inertgas_saturation[j] < entry->ambpressure ?
tissue_inertgas_saturation[j] / entry->ambpressure * AMB_PERCENTAGE :
AMB_PERCENTAGE + (tissue_inertgas_saturation[j] - entry->ambpressure) / (m_value - entry->ambpressure) * (100.0 - AMB_PERCENTAGE);
}
last_ndl_tts_calc_time = entry->sec;
/* We are going to mess up deco state, so store it for later restore */
char *cache_data = NULL;
cache_deco_state(&cache_data);
calculate_ndl_tts(entry, dive, surface_pressure);
/* Restore "real" deco state for next real time step */
restore_deco_state(cache_data);
free(cache_data);
/* should we do more calculations?
* We don't for print-mode because this info doesn't show up there
* If the ceiling hasn't cleared by the last data point, we need tts for VPM-B CVA calculation
* It is not necessary to do these calculation on the first VPMB iteration, except for the last data point */
if ((prefs.calcndltts && !print_mode && (prefs.deco_mode != VPMB || in_planner() || !first_iteration)) ||
(prefs.deco_mode == VPMB && !in_planner() && i == pi->nr - 1)) {
/* only calculate ndl/tts on every 30 seconds */
if ((entry->sec - last_ndl_tts_calc_time) < 30 && i != pi->nr - 1) {
struct plot_data *prev_entry = (entry - 1);
entry->stoptime_calc = prev_entry->stoptime_calc;
entry->stopdepth_calc = prev_entry->stopdepth_calc;
entry->tts_calc = prev_entry->tts_calc;
entry->ndl_calc = prev_entry->ndl_calc;
continue;
}
last_ndl_tts_calc_time = entry->sec;
/* We are going to mess up deco state, so store it for later restore */
char *cache_data = NULL;
cache_deco_state(&cache_data);
calculate_ndl_tts(entry, dive, surface_pressure);
if (prefs.deco_mode == VPMB && !in_planner() && i == pi->nr - 1)
final_tts = entry->tts_calc;
/* Restore "real" deco state for next real time step */
restore_deco_state(cache_data);
free(cache_data);
}
}
if (prefs.deco_mode == VPMB && !in_planner()) {
prev_deco_time = deco_time;
// Do we need to update deco_time?
if (final_tts > 0)
deco_time = pi->maxtime + final_tts - time_deep_ceiling;
else if (time_clear_ceiling > 0)
deco_time = time_clear_ceiling - time_deep_ceiling;
vpmb_next_gradient(deco_time, surface_pressure / 1000.0);
final_tts = 0;
last_ndl_tts_calc_time = 0;
first_ceiling = 0;
first_iteration = false;
count_iteration ++;
restore_deco_state(cache_data_initial);
} else {
// With Buhlmann, or not in planner, iterating isn't needed. This makes the while condition false.
prev_deco_time = deco_time = 0;
}
}
free(cache_data_initial);
#if DECO_CALC_DEBUG & 1
dump_tissues();
#endif

View File

@ -5,19 +5,21 @@
#include <QtConcurrent>
extern QHash <QString, QImage > thumbnailCache;
SPixmap scaleImages(picturepointer picture)
{
static QHash <QString, QImage > cache;
SPixmap ret;
ret.first = picture;
if (cache.contains(picture->filename) && !cache.value(picture->filename).isNull()) {
ret.second = cache.value(picture->filename);
if (thumbnailCache.contains(picture->filename) && !thumbnailCache.value(picture->filename).isNull()) {
ret.second = thumbnailCache.value(picture->filename);
} else {
int dim = defaultIconMetrics().sz_pic;
QImage p = SHashedImage(picture);
if(!p.isNull()) {
p = p.scaled(dim, dim, Qt::KeepAspectRatio);
cache.insert(picture->filename, p);
thumbnailCache.insert(picture->filename, p);
}
ret.second = p;
}

View File

@ -479,7 +479,10 @@ void DivePlannerPointsModel::setSafetyStop(bool value)
void DivePlannerPointsModel::setReserveGas(int reserve)
{
prefs.reserve_gas = reserve * 1000;
if (prefs.units.pressure == units::BAR)
prefs.reserve_gas = reserve * 1000;
else
prefs.reserve_gas = psi_to_mbar(reserve);
emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1));
}

View File

@ -19,7 +19,7 @@ int DivePlotDataModel::columnCount(const QModelIndex &parent) const
QVariant DivePlotDataModel::data(const QModelIndex &index, int role) const
{
if ((!index.isValid()) || (index.row() >= pInfo.nr))
if ((!index.isValid()) || (index.row() >= pInfo.nr) || pInfo.entry == 0)
return QVariant();
plot_data item = pInfo.entry[index.row()];
@ -167,6 +167,8 @@ void DivePlotDataModel::clear()
if (rowCount() != 0) {
beginRemoveRows(QModelIndex(), 0, rowCount() - 1);
pInfo.nr = 0;
free(pInfo.entry);
pInfo.entry = 0;
diveId = -1;
dcNr = -1;
endRemoveRows();
@ -179,7 +181,10 @@ void DivePlotDataModel::setDive(dive *d, const plot_info &info)
Q_ASSERT(d != NULL);
diveId = d->id;
dcNr = dc_number;
free(pInfo.entry);
pInfo = info;
pInfo.entry = (struct plot_data *)malloc(sizeof(struct plot_data) * pInfo.nr);
memcpy(pInfo.entry, info.entry, sizeof(plot_data) * pInfo.nr);
beginInsertRows(QModelIndex(), 0, pInfo.nr - 1);
endInsertRows();
}

View File

@ -202,4 +202,18 @@ void YearlyStatisticsModel::update_yearly_stats()
rootItem->children.append(item);
item->parent = rootItem;
}
/* Show the statistic sorted by dive type */
if (stats_by_type != NULL && stats_by_type[0].selection_size) {
YearStatisticsItem *item = new YearStatisticsItem(stats_by_type[0]);
for (i = 1; i <= NUM_DC_TYPE; ++i) {
if (stats_by_type[i].selection_size == 0)
continue;
YearStatisticsItem *iChild = new YearStatisticsItem(stats_by_type[i]);
item->children.append(iChild);
iChild->parent = item;
}
rootItem->children.append(item);
item->parent = rootItem;
}
}

View File

@ -20,7 +20,7 @@ SubsurfaceAbout::SubsurfaceAbout(QWidget *parent, Qt::WindowFlags f) : QDialog(p
"Subsurface %1 </span><br><br>"
"Multi-platform divelog software<br>"
"<span style='font-size: 8pt'>"
"Linus Torvalds, Dirk Hohndel, Tomaz Canabrava, and others, 2011-2015"
"Linus Torvalds, Dirk Hohndel, Tomaz Canabrava, and others, 2011-2016"
"</span>").arg(versionString));
QShortcut *close = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), this);

View File

@ -470,6 +470,11 @@ void ConfigureDiveComputerDialog::populateDeviceDetailsOSTC3()
deviceDetails->dynamicAscendRate = ui.dynamicAscendRate->isChecked();
deviceDetails->graphicalSpeedIndicator = ui.graphicalSpeedIndicator->isChecked();
deviceDetails->alwaysShowppO2 = ui.alwaysShowppO2->isChecked();
deviceDetails->tempSensorOffset = ui.tempSensorOffsetDoubleSpinBox->value() * 10;
deviceDetails->safetyStopLength = ui.safetyStopLengthSpinBox->value();
deviceDetails->safetyStopStartDepth = ui.safetyStopStartDepthDoubleSpinBox->value() * 10;
deviceDetails->safetyStopEndDepth = ui.safetyStopEndDepthDoubleSpinBox->value() * 10;
deviceDetails->safetyStopResetDepth = ui.safetyStopResetDepthDoubleSpinBox->value() * 10;
//set gas values
gas gas1;
@ -599,6 +604,10 @@ void ConfigureDiveComputerDialog::populateDeviceDetailsOSTC()
deviceDetails->bottomGasConsumption = ui.bottomGasConsumption_3->value();
deviceDetails->decoGasConsumption = ui.decoGasConsumption_3->value();
deviceDetails->graphicalSpeedIndicator = ui.graphicalSpeedIndicator_3->isChecked();
deviceDetails->safetyStopLength = ui.safetyStopLengthSpinBox_3->value();
deviceDetails->safetyStopStartDepth = ui.safetyStopStartDepthDoubleSpinBox_3->value() * 10;
deviceDetails->safetyStopEndDepth = ui.safetyStopEndDepthDoubleSpinBox_3->value() * 10;
deviceDetails->safetyStopResetDepth = ui.safetyStopResetDepthDoubleSpinBox_3->value() * 10;
//set gas values
gas gas1;
@ -845,6 +854,11 @@ void ConfigureDiveComputerDialog::reloadValuesOSTC3()
ui.dynamicAscendRate->setChecked(deviceDetails->dynamicAscendRate);
ui.graphicalSpeedIndicator->setChecked(deviceDetails->graphicalSpeedIndicator);
ui.alwaysShowppO2->setChecked(deviceDetails->alwaysShowppO2);
ui.tempSensorOffsetDoubleSpinBox->setValue((double)deviceDetails->tempSensorOffset / 10.0);
ui.safetyStopLengthSpinBox->setValue(deviceDetails->safetyStopLength);
ui.safetyStopStartDepthDoubleSpinBox->setValue(deviceDetails->safetyStopStartDepth / 10.0);
ui.safetyStopEndDepthDoubleSpinBox->setValue(deviceDetails->safetyStopEndDepth / 10.0);
ui.safetyStopResetDepthDoubleSpinBox->setValue(deviceDetails->safetyStopResetDepth / 10.0);
//load gas 1 values
ui.ostc3GasTable->setItem(0, 1, new QTableWidgetItem(QString::number(deviceDetails->gas1.oxygen)));
@ -968,6 +982,10 @@ setNumberOfDives
ui.bottomGasConsumption_3->setValue(deviceDetails->bottomGasConsumption);
ui.decoGasConsumption_3->setValue(deviceDetails->decoGasConsumption);
ui.graphicalSpeedIndicator_3->setChecked(deviceDetails->graphicalSpeedIndicator);
ui.safetyStopLengthSpinBox_3->setValue(deviceDetails->safetyStopLength);
ui.safetyStopStartDepthDoubleSpinBox_3->setValue(deviceDetails->safetyStopStartDepth / 10.0);
ui.safetyStopEndDepthDoubleSpinBox_3->setValue(deviceDetails->safetyStopEndDepth / 10.0);
ui.safetyStopResetDepthDoubleSpinBox_3->setValue(deviceDetails->safetyStopResetDepth / 10.0);
//load gas 1 values
ui.ostcGasTable->setItem(0, 1, new QTableWidgetItem(QString::number(deviceDetails->gas1.oxygen)));
@ -1252,6 +1270,6 @@ void ConfigureDiveComputerDialog::dc_close()
ui.DiveComputerList->setEnabled(true);
ui.logToFile->setEnabled(true);
ui.updateFirmwareButton->setEnabled(false);
ui.progressBar->setFormat("Disonnected from device");
ui.progressBar->setFormat("Disconnected from device");
ui.progressBar->setValue(0);
}

View File

@ -253,6 +253,35 @@
<string>Basic settings</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="4">
<widget class="QComboBox" name="brightnessComboBox">
<item>
<property name="text">
<string>Eco</string>
</property>
</item>
<item>
<property name="text">
<string>Medium</string>
</property>
</item>
<item>
<property name="text">
<string>High</string>
</property>
</item>
</widget>
</item>
<item row="7" column="4">
<widget class="QSpinBox" name="salinitySpinBox">
<property name="suffix">
<string>%</string>
</property>
<property name="maximum">
<number>5</number>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QComboBox" name="languageComboBox">
<item>
@ -324,23 +353,6 @@
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLineEdit" name="firmwareVersionLineEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Language</string>
</property>
<property name="buddy">
<cstring>languageComboBox</cstring>
</property>
</widget>
</item>
<item row="3" column="4">
<widget class="QComboBox" name="dateFormatComboBox">
<item>
@ -360,23 +372,21 @@
</item>
</widget>
</item>
<item row="5" column="4">
<widget class="QComboBox" name="brightnessComboBox">
<item>
<property name="text">
<string>Eco</string>
</property>
</item>
<item>
<property name="text">
<string>Medium</string>
</property>
</item>
<item>
<property name="text">
<string>High</string>
</property>
</item>
<item row="0" column="4">
<widget class="QLineEdit" name="firmwareVersionLineEdit">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="3">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Language</string>
</property>
<property name="buddy">
<cstring>languageComboBox</cstring>
</property>
</widget>
</item>
<item row="3" column="3">
@ -419,13 +429,13 @@
</property>
</widget>
</item>
<item row="7" column="4">
<widget class="QSpinBox" name="salinitySpinBox">
<property name="suffix">
<string>%</string>
<item row="14" column="3" colspan="2">
<widget class="QPushButton" name="resetButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="maximum">
<number>5</number>
<property name="text">
<string>Reset device to default settings</string>
</property>
</widget>
</item>
@ -479,7 +489,7 @@
</item>
</widget>
</item>
<item row="9" column="2">
<item row="12" column="2">
<spacer name="verticalSpacer1">
<property name="orientation">
<enum>Qt::Vertical</enum>
@ -492,36 +502,6 @@
</property>
</spacer>
</item>
<item row="11" column="3" colspan="2">
<widget class="QPushButton" name="resetButton">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Reset device to default settings</string>
</property>
</widget>
</item>
<item row="8" column="3">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Compass gain</string>
</property>
<property name="buddy">
<cstring>compassGainComboBox</cstring>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Custom text</string>
</property>
<property name="buddy">
<cstring>customTextLlineEdit</cstring>
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<widget class="QLineEdit" name="customTextLlineEdit">
<property name="sizePolicy">
@ -535,6 +515,16 @@
</property>
</widget>
</item>
<item row="8" column="3">
<widget class="QLabel" name="label_15">
<property name="text">
<string>Compass gain</string>
</property>
<property name="buddy">
<cstring>compassGainComboBox</cstring>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QLabel" name="label_62">
<property name="text">
@ -542,6 +532,16 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Custom text</string>
</property>
<property name="buddy">
<cstring>customTextLlineEdit</cstring>
</property>
</widget>
</item>
<item row="1" column="4">
<widget class="QLineEdit" name="modelLineEdit">
<property name="readOnly">
@ -549,16 +549,6 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Dive mode</string>
</property>
<property name="buddy">
<cstring>diveModeComboBox</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="diveModeComboBox">
<item>
@ -583,13 +573,13 @@
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_11">
<item row="2" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Sampling rate</string>
<string>Dive mode</string>
</property>
<property name="buddy">
<cstring>samplingRateComboBox</cstring>
<cstring>diveModeComboBox</cstring>
</property>
</widget>
</item>
@ -607,13 +597,13 @@
</item>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_13">
<item row="3" column="0">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Dive mode color</string>
<string>Sampling rate</string>
</property>
<property name="buddy">
<cstring>diveModeColour</cstring>
<cstring>samplingRateComboBox</cstring>
</property>
</widget>
</item>
@ -648,6 +638,16 @@
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_13">
<property name="text">
<string>Dive mode color</string>
</property>
<property name="buddy">
<cstring>diveModeColour</cstring>
</property>
</widget>
</item>
<item row="7" column="0" colspan="3">
<widget class="QCheckBox" name="safetyStopCheckBox">
<property name="text">
@ -655,6 +655,122 @@
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QLabel" name="label_65">
<property name="text">
<string>End Depth</string>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QSpinBox" name="safetyStopLengthSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> s</string>
</property>
<property name="minimum">
<number>60</number>
</property>
<property name="maximum">
<number>240</number>
</property>
<property name="value">
<number>180</number>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_63">
<property name="text">
<string>Length</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_64">
<property name="text">
<string>Start Depth</string>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QLabel" name="label_66">
<property name="text">
<string>Reset Depth</string>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QDoubleSpinBox" name="safetyStopStartDepthDoubleSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>2.100000000000000</double>
</property>
<property name="maximum">
<double>6.100000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>5.100000000000000</double>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QDoubleSpinBox" name="safetyStopEndDepthDoubleSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>1.900000000000000</double>
</property>
<property name="maximum">
<double>3.000000000000000</double>
</property>
<property name="value">
<double>2.900000000000000</double>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QDoubleSpinBox" name="safetyStopResetDepthDoubleSpinBox">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>8.100000000000000</double>
</property>
<property name="maximum">
<double>15.100000000000000</double>
</property>
<property name="value">
<double>10.100000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="advancedSettings">
@ -1043,6 +1159,32 @@
</property>
</widget>
</item>
<item row="14" column="3">
<widget class="QLabel" name="label_71">
<property name="text">
<string>Temperature sensor offset</string>
</property>
</widget>
</item>
<item row="14" column="4">
<widget class="QDoubleSpinBox" name="tempSensorOffsetDoubleSpinBox">
<property name="suffix">
<string>°C</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>-2.000000000000000</double>
</property>
<property name="maximum">
<double>2.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="gasSettings">
@ -1795,17 +1937,7 @@
<string>Basic settings</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_4">
<item row="5" column="3">
<widget class="QLabel" name="label_45">
<property name="text">
<string>Salinity</string>
</property>
<property name="buddy">
<cstring>salinitySpinBox</cstring>
</property>
</widget>
</item>
<item row="0" column="0">
<item row="0" column="0" colspan="2">
<widget class="QLabel" name="label_38">
<property name="text">
<string>Serial No.</string>
@ -1815,7 +1947,21 @@
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<item row="6" column="0">
<widget class="QLabel" name="label_68">
<property name="text">
<string>Length</string>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QLineEdit" name="firmwareVersionLineEdit_3">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="0" column="2" colspan="2">
<widget class="QLineEdit" name="serialNoLineEdit_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@ -1828,7 +1974,7 @@
</property>
</widget>
</item>
<item row="0" column="3">
<item row="0" column="5">
<widget class="QLabel" name="label_39">
<property name="text">
<string>Firmware version</string>
@ -1838,14 +1984,7 @@
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLineEdit" name="firmwareVersionLineEdit_3">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<item row="1" column="0" colspan="2">
<widget class="QLabel" name="label_40">
<property name="text">
<string>Custom text</string>
@ -1855,7 +1994,7 @@
</property>
</widget>
</item>
<item row="1" column="1" colspan="2">
<item row="1" column="2" colspan="2">
<widget class="QLineEdit" name="customTextLlineEdit_3">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@ -1868,83 +2007,38 @@
</property>
</widget>
</item>
<item row="5" column="4">
<widget class="QDoubleSpinBox" name="salinityDoubleSpinBox_3">
<property name="suffix">
<string>kg/</string>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>1.040000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="7" column="2">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>177</height>
</size>
</property>
</spacer>
</item>
<item row="5" column="0" colspan="3">
<widget class="QCheckBox" name="dateTimeSyncCheckBox_3">
<property name="text">
<string>Sync dive computer time with PC</string>
</property>
</widget>
</item>
<item row="6" column="0" colspan="3">
<widget class="QCheckBox" name="safetyStopCheckBox_3">
<property name="text">
<string>Show safety stop</string>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QComboBox" name="dateFormatComboBox_3">
<item>
<property name="text">
<string>MM/DD/YY</string>
</property>
</item>
<item>
<property name="text">
<string>DD/MM/YY</string>
</property>
</item>
<item>
<property name="text">
<string>YY/MM/DD</string>
</property>
</item>
</widget>
</item>
<item row="1" column="3">
<item row="1" column="5">
<widget class="QLabel" name="label_41">
<property name="text">
<string>Number of dives</string>
</property>
</widget>
</item>
<item row="1" column="4">
<item row="4" column="0" rowspan="2" colspan="4">
<widget class="QCheckBox" name="safetyStopCheckBox_3">
<property name="text">
<string>Show safety stop</string>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QSpinBox" name="numberOfDivesSpinBox_3">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="2" column="0" colspan="2">
<widget class="QLabel" name="label_47">
<property name="text">
<string>Sampling rate</string>
</property>
<property name="buddy">
<cstring>samplingRateComboBox</cstring>
</property>
</widget>
</item>
<item row="2" column="2" colspan="2">
<widget class="QSpinBox" name="samplingRateSpinBox_3">
<property name="minimumSize">
<size>
@ -1963,17 +2057,7 @@
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_47">
<property name="text">
<string>Sampling rate</string>
</property>
<property name="buddy">
<cstring>samplingRateComboBox</cstring>
</property>
</widget>
</item>
<item row="2" column="3">
<item row="2" column="5">
<widget class="QLabel" name="label_42">
<property name="text">
<string>Date format</string>
@ -1983,6 +2067,180 @@
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QComboBox" name="dateFormatComboBox_3">
<item>
<property name="text">
<string>MM/DD/YY</string>
</property>
</item>
<item>
<property name="text">
<string>DD/MM/YY</string>
</property>
</item>
<item>
<property name="text">
<string>YY/MM/DD</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0" colspan="4">
<widget class="QCheckBox" name="dateTimeSyncCheckBox_3">
<property name="text">
<string>Sync dive computer time with PC</string>
</property>
</widget>
</item>
<item row="3" column="5">
<widget class="QLabel" name="label_45">
<property name="text">
<string>Salinity</string>
</property>
<property name="buddy">
<cstring>salinitySpinBox</cstring>
</property>
</widget>
</item>
<item row="3" column="6">
<widget class="QDoubleSpinBox" name="salinityDoubleSpinBox_3">
<property name="suffix">
<string>kg/</string>
</property>
<property name="minimum">
<double>1.000000000000000</double>
</property>
<property name="maximum">
<double>1.040000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="10" column="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>177</height>
</size>
</property>
</spacer>
</item>
<item row="7" column="0">
<widget class="QLabel" name="label_67">
<property name="text">
<string>Start Depth</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="label_69">
<property name="text">
<string>End Depth</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QLabel" name="label_70">
<property name="text">
<string>Reset Depth</string>
</property>
</widget>
</item>
<item row="6" column="2">
<widget class="QSpinBox" name="safetyStopLengthSpinBox_3">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> s</string>
</property>
<property name="minimum">
<number>10</number>
</property>
<property name="maximum">
<number>250</number>
</property>
<property name="value">
<number>180</number>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QDoubleSpinBox" name="safetyStopStartDepthDoubleSpinBox_3">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>3.000000000000000</double>
</property>
<property name="maximum">
<double>6.500000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>5.100000000000000</double>
</property>
</widget>
</item>
<item row="8" column="2">
<widget class="QDoubleSpinBox" name="safetyStopEndDepthDoubleSpinBox_3">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>2.500000000000000</double>
</property>
<property name="maximum">
<double>5.000000000000000</double>
</property>
<property name="value">
<double>2.900000000000000</double>
</property>
</widget>
</item>
<item row="9" column="2">
<widget class="QDoubleSpinBox" name="safetyStopResetDepthDoubleSpinBox_3">
<property name="enabled">
<bool>false</bool>
</property>
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="minimum">
<double>7.500000000000000</double>
</property>
<property name="maximum">
<double>20.100000000000001</double>
</property>
<property name="value">
<double>10.100000000000000</double>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="advancedSettings_3">
@ -2754,5 +3012,133 @@
</hint>
</hints>
</connection>
<connection>
<sender>safetyStopCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>safetyStopLengthSpinBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>safetyStopCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>safetyStopStartDepthDoubleSpinBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>safetyStopCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>safetyStopEndDepthDoubleSpinBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>safetyStopCheckBox</sender>
<signal>toggled(bool)</signal>
<receiver>safetyStopResetDepthDoubleSpinBox</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>safetyStopCheckBox_3</sender>
<signal>toggled(bool)</signal>
<receiver>safetyStopLengthSpinBox_3</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>safetyStopCheckBox_3</sender>
<signal>toggled(bool)</signal>
<receiver>safetyStopStartDepthDoubleSpinBox_3</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>safetyStopCheckBox_3</sender>
<signal>toggled(bool)</signal>
<receiver>safetyStopEndDepthDoubleSpinBox_3</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
<connection>
<sender>safetyStopCheckBox_3</sender>
<signal>toggled(bool)</signal>
<receiver>safetyStopResetDepthDoubleSpinBox_3</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -5,6 +5,7 @@
#include <QShortcut>
#include <QDrag>
#include <QMimeData>
#include <QRegExp>
static QString subsurface_mimedata = "subsurface/csvcolumns";
static QString subsurface_index = "subsurface/csvindex";
@ -15,6 +16,7 @@ const DiveLogImportDialog::CSVAppConfig DiveLogImportDialog::CSVApps[CSVAPPS] =
{ "Manual import", },
{ "APD Log Viewer - DC1", 0, 1, 15, 6, 3, 4, 5, 17, -1, -1, 18, -1, 2, "Tab" },
{ "APD Log Viewer - DC2", 0, 1, 15, 6, 7, 8, 9, 17, -1, -1, 18, -1, 2, "Tab" },
{ "DL7", 1, 2, -1, -1, -1, -1, -1, -1, -1, 8, -1, 10, -1, "|" },
{ "XP5", 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, "Tab" },
{ "SensusCSV", 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, "," },
{ "Seabear CSV", 0, 1, 5, -1, -1, -1, -1, -1, 2, 3, 4, 6, -1, ";" },
@ -26,6 +28,7 @@ static enum {
MANUAL,
APD,
APD2,
DL7,
XP5,
SENSUS,
SEABEAR,
@ -331,15 +334,17 @@ DiveLogImportDialog::DiveLogImportDialog(QStringList fn, QWidget *parent) : QDia
column = 0;
delta = "0";
hw = "";
txtLog = false;
/* Add indexes of XSLTs requiring special handling to the list */
specialCSV << SENSUS;
specialCSV << SUBSURFACE;
specialCSV << DL7;
for (int i = 0; !CSVApps[i].name.isNull(); ++i)
ui->knownImports->addItem(CSVApps[i].name);
ui->CSVSeparator->addItems( QStringList() << tr("Tab") << "," << ";");
ui->CSVSeparator->addItems( QStringList() << tr("Tab") << "," << ";" << "|");
loadFileContents(-1, INITIAL);
@ -378,6 +383,7 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
bool seabear = false;
bool xp5 = false;
bool apd = false;
bool dl7 = false;
// reset everything
ColumnNameProvider *provider = new ColumnNameProvider(this);
@ -459,8 +465,38 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
blockSignals(true);
ui->knownImports->setCurrentText("XP5");
blockSignals(false);
} else if (firstLine.contains("FSH")) {
QString units = "Metric";
dl7 = true;
while ((firstLine = f.readLine().trimmed()).length() > 0 && !f.atEnd()) {
/* DL7 actually defines individual units (e.g. depth, temp, pressure, etc.)
* and there are quite a few other options as well, but let's use metric
* unless depth unit is clearly Imperial. */
if (firstLine.contains("ThFt")) {
units = "Imperial";
}
}
firstLine = "|Sample time|Sample depth||||||Sample temperature||Sample pressure";
blockSignals(true);
ui->knownImports->setCurrentText("DL7");
ui->CSVUnits->setCurrentText(units);
blockSignals(false);
} else if (firstLine.contains("Life Time Dive")) {
txtLog = true;
while ((firstLine = f.readLine().trimmed()).length() >= 0 && !f.atEnd()) {
if (firstLine.contains("Dive Profile")) {
f.readLine();
break;
}
}
firstLine = f.readLine().trimmed();
}
// Special handling for APD Log Viewer
if ((triggeredBy == KNOWNTYPES && (value == APD || value == APD2)) || (triggeredBy == INITIAL && fileNames.first().endsWith(".apd", Qt::CaseInsensitive))) {
apd=true;
@ -479,11 +515,14 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
int tabs = firstLine.count('\t');
int commas = firstLine.count(',');
int semis = firstLine.count(';');
if (tabs > commas && tabs > semis)
int pipes = firstLine.count('|');
if (tabs > commas && tabs > semis && tabs > pipes)
separator = "\t";
else if (commas > tabs && commas > semis)
else if (commas > tabs && commas > semis && commas > pipes)
separator = ",";
else if (semis > tabs && semis > commas)
else if (pipes > tabs && pipes > commas && pipes > semis)
separator = "|";
else if (semis > tabs && semis > commas && semis > pipes)
separator = ";";
if (ui->CSVSeparator->currentText() != separator) {
blockSignals(true);
@ -493,8 +532,14 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
}
}
if (triggeredBy == INITIAL || (triggeredBy == KNOWNTYPES && value == MANUAL) || triggeredBy == SEPARATOR) {
int count = -1;
QString line = f.readLine().trimmed();
QStringList columns;
if (line.length() > 0)
columns = line.split(separator);
// now try and guess the columns
Q_FOREACH (QString columnText, currColumns) {
count++;
/*
* We have to skip the conversion of 2 to for APD Log
* viewer as that would mess up the sensor numbering. We
@ -513,13 +558,28 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
provider->removeRow(idx);
headers.append(foundHeading);
matchedSome = true;
if (foundHeading == QString::fromLatin1("Date") && columns.count() >= count) {
QString date = columns.at(count);
if (date.contains('-')) {
ui->DateFormat->setCurrentText("yyyy-mm-dd");
} else if (date.contains('/')) {
ui->DateFormat->setCurrentText("mm/dd/yyyy");
}
} else if (foundHeading == QString::fromLatin1("Time") && columns.count() >= count) {
QString time = columns.at(count);
if (time.contains(':')) {
ui->DurationFormat->setCurrentText("Minutes:seconds");
}
}
} else {
headers.append("");
}
}
if (matchedSome) {
ui->dragInstructions->setText(tr("Some column headers were pre-populated; please drag and drop the headers so they match the column they are in."));
if (triggeredBy != KNOWNTYPES && !seabear && !xp5 && !apd) {
if (triggeredBy != KNOWNTYPES && !seabear && !xp5 && !apd && !dl7) {
blockSignals(true);
ui->knownImports->setCurrentIndex(0); // <- that's "Manual import"
blockSignals(false);
@ -633,6 +693,20 @@ void DiveLogImportDialog::loadFileContents(int value, whatChanged triggeredBy)
* actual data.
*/
while (strlen(f.readLine()) > 3 && !f.atEnd());
} else if (dl7) {
while ((firstLine = f.readLine().trimmed()).length() > 0 && !f.atEnd()) {
if (firstLine.contains("ZDP")) {
firstLine = f.readLine().trimmed();
break;
}
}
} else if (txtLog) {
while ((firstLine = f.readLine().trimmed()).length() >= 0 && !f.atEnd()) {
if (firstLine.contains("Dive Profile")) {
firstLine = f.readLine().trimmed();
break;
}
}
}
while (rows < 10 && !f.atEnd()) {
@ -658,6 +732,14 @@ char *intdup(int index)
int DiveLogImportDialog::setup_csv_params(QStringList r, char **params, int pnr)
{
params[pnr++] = strdup("dateField");
params[pnr++] = intdup(r.indexOf(tr("Date")));
params[pnr++] = strdup("datefmt");
params[pnr++] = intdup(ui->DateFormat->currentIndex());
params[pnr++] = strdup("starttimeField");
params[pnr++] = intdup(r.indexOf(tr("Time")));
params[pnr++] = strdup("numberField");
params[pnr++] = intdup(r.indexOf(tr("Dive #")));
params[pnr++] = strdup("timeField");
params[pnr++] = intdup(r.indexOf(tr("Sample time")));
params[pnr++] = strdup("depthField");
@ -699,6 +781,51 @@ int DiveLogImportDialog::setup_csv_params(QStringList r, char **params, int pnr)
return pnr;
}
int DiveLogImportDialog::parseTxtHeader(QString fileName, char **params, int pnr)
{
QFile f(fileNames.first());
QString date;
QString time;
QString line;
f.open(QFile::ReadOnly);
while ((line = f.readLine().trimmed()).length() >= 0 && !f.atEnd()) {
if (line.contains("Dive Profile")) {
f.readLine();
break;
} else if (line.contains("Dive Date: ")) {
date = line.replace(QString::fromLatin1("Dive Date: "), QString::fromLatin1(""));
if (date.contains('-')) {
QStringList fmtDate = date.split('-');
date = fmtDate[0] + fmtDate[1] + fmtDate[2];
} else if (date.contains('/')) {
QStringList fmtDate = date.split('/');
date = fmtDate[2] + fmtDate[0] + fmtDate[1];
} else {
QStringList fmtDate = date.split('.');
date = fmtDate[2] + fmtDate[1] + fmtDate[0];
}
} else if (line.contains("Elapsed Dive Time: ")) {
// Skipping dive duration for now
} else if (line.contains("Dive Time: ")) {
time = line.replace(QString::fromLatin1("Dive Time: "), QString::fromLatin1(""));
if (time.contains(':')) {
QStringList fmtTime = time.split(':');
time = fmtTime[0] + fmtTime[1];
}
}
}
f.close();
params[pnr++] = strdup("date");
params[pnr++] = strdup(date.toLatin1());
params[pnr++] = strdup("time");
params[pnr++] = strdup(time.toLatin1());
return pnr;
}
void DiveLogImportDialog::on_buttonBox_accepted()
{
@ -753,15 +880,24 @@ void DiveLogImportDialog::on_buttonBox_accepted()
}
// Seabear CSV stores NDL and TTS in Minutes, not seconds
struct dive *dive = dive_table.dives[dive_table.nr - 1];
for(int s_nr = 0 ; s_nr <= dive->dc.samples ; s_nr++) {
for(int s_nr = 0 ; s_nr < dive->dc.samples ; s_nr++) {
struct sample *sample = dive->dc.sample + s_nr;
sample->ndl.seconds *= 60;
sample->tts.seconds *= 60;
}
} else {
char *params[37];
char *params[49];
int pnr = 0;
QRegExp apdRe("^.*[/\\][0-9a-zA-Z]*_([0-9]{6})_([0-9]{6})\\.apd");
if (txtLog) {
pnr = parseTxtHeader(fileNames[i], params, pnr);
} else if (apdRe.exactMatch(fileNames[i])) {
params[pnr++] = strdup("date");
params[pnr++] = strdup("20" + apdRe.cap(1).toLatin1());
params[pnr++] = strdup("time");
params[pnr++] = strdup("1" + apdRe.cap(2).toLatin1());
}
pnr = setup_csv_params(r, params, pnr);
parse_csv_file(fileNames[i].toUtf8().data(), params, pnr - 1,
specialCSV.contains(ui->knownImports->currentIndex()) ? CSVApps[ui->knownImports->currentIndex()].name.toUtf8().data() : "csv");
@ -826,9 +962,18 @@ void DiveLogImportDialog::on_buttonBox_accepted()
parse_manual_file(fileNames[i].toUtf8().data(), params, pnr - 1);
} else {
char *params[37];
char *params[49];
int pnr = 0;
QRegExp apdRe("^.*[/\\][0-9a-zA-Z]*_([0-9]{6})_([0-9]{6})\\.apd");
if (txtLog) {
pnr = parseTxtHeader(fileNames[i], params, pnr);
} else if (apdRe.exactMatch(fileNames[i])) {
params[pnr++] = strdup("date");
params[pnr++] = strdup("20" + apdRe.cap(1).toLatin1());
params[pnr++] = strdup("time");
params[pnr++] = strdup("1" + apdRe.cap(2).toLatin1());
}
pnr = setup_csv_params(r, params, pnr);
parse_csv_file(fileNames[i].toUtf8().data(), params, pnr - 1,
specialCSV.contains(ui->knownImports->currentIndex()) ? CSVApps[ui->knownImports->currentIndex()].name.toUtf8().data() : "csv");

View File

@ -87,6 +87,7 @@ slots:
void loadFileContentsKnownTypesSelected(int value);
void loadFileContents(int value, enum whatChanged triggeredBy);
int setup_csv_params(QStringList r, char **params, int pnr);
int parseTxtHeader(QString fileName, char **params, int pnr);
private:
bool selector;
@ -97,6 +98,7 @@ private:
ColumnNameResult *resultModel;
QString delta;
QString hw;
bool txtLog;
struct CSVAppConfig {
QString name;
@ -116,7 +118,7 @@ private:
QString separator;
};
#define CSVAPPS 8
#define CSVAPPS 9
static const CSVAppConfig CSVApps[CSVAPPS];
};

View File

@ -23,16 +23,17 @@ void loadPicture(struct picture *picture)
SHashedImage::SHashedImage(struct picture *picture) : QImage()
{
QUrl url = QUrl::fromUserInput(QString(picture->filename));
QUrl url = QUrl::fromUserInput(localFilePath(QString(picture->filename)));
if(url.isLocalFile())
load(url.toLocalFile());
if (isNull()) {
// Hash lookup.
load(fileFromHash(picture->hash));
if (!isNull()) {
QtConcurrent::run(updateHash, picture);
QtConcurrent::run(updateHash, clone_picture(picture));
} else {
QtConcurrent::run(loadPicture, picture);
QtConcurrent::run(loadPicture, clone_picture(picture));
}
} else {
QByteArray hash = hashFile(url.toLocalFile());
@ -46,6 +47,11 @@ ImageDownloader::ImageDownloader(struct picture *pic)
picture = pic;
}
ImageDownloader::~ImageDownloader()
{
picture_free(picture);
}
void ImageDownloader::load(){
QUrl url = QUrl::fromUserInput(QString(picture->filename));
if (url.isValid()) {
@ -64,6 +70,7 @@ void ImageDownloader::load(){
void ImageDownloader::saveImage(QNetworkReply *reply)
{
QByteArray imageData = reply->readAll();
qDebug() << "downloaded ";
QImage image = QImage();
image.loadFromData(imageData);
if (image.isNull())

View File

@ -11,6 +11,7 @@ class ImageDownloader : public QObject {
Q_OBJECT;
public:
ImageDownloader(struct picture *picture);
~ImageDownloader();
void load();
private:
struct picture *picture;

View File

@ -306,7 +306,6 @@ PlannerSettingsWidget::PlannerSettingsWidget(QWidget *parent, Qt::WindowFlags f)
ui.display_runtime->setChecked(prefs.display_runtime);
ui.display_transitions->setChecked(prefs.display_transitions);
ui.safetystop->setChecked(prefs.safetystop);
ui.reserve_gas->setValue(prefs.reserve_gas / 1000);
ui.bottompo2->setValue(prefs.bottompo2 / 1000.0);
ui.decopo2->setValue(prefs.decopo2 / 1000.0);
ui.backgasBreaks->setChecked(prefs.doo2breaks);
@ -448,6 +447,18 @@ void PlannerSettingsWidget::settingsChanged()
ui.bottomSAC->setValue((double) prefs.bottomsac / 1000.0);
ui.decoStopSAC->setValue((double) prefs.decosac / 1000.0);
}
if(get_units()->pressure == units::BAR) {
ui.reserve_gas->setSuffix(tr("bar"));
ui.reserve_gas->setSingleStep(1);
ui.reserve_gas->setValue(prefs.reserve_gas / 1000);
ui.reserve_gas->setMaximum(300);
} else {
ui.reserve_gas->setSuffix(tr("psi"));
ui.reserve_gas->setSingleStep(10);
ui.reserve_gas->setMaximum(5000);
ui.reserve_gas->setValue(mbar_to_PSI(prefs.reserve_gas));
}
ui.bottomSAC->blockSignals(false);
ui.decoStopSAC->blockSignals(false);
updateUnitsUI();

View File

@ -290,7 +290,7 @@ bool DiveLocationFilterProxyModel::filterAcceptsRow(int source_row, const QModel
return true;
QString sourceString = sourceModel()->index(source_row, DiveLocationModel::NAME).data(Qt::DisplayRole).toString();
return sourceString.toLower().startsWith(location_line_edit->text().toLower());
return sourceString.toLower().contains(location_line_edit->text().toLower());
}
bool DiveLocationFilterProxyModel::lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const
@ -570,7 +570,7 @@ void DiveLocationLineEdit::fixPopupPosition()
view->setGeometry(pos.x(), pos.y(), w, h);
if (!view->currentIndex().isValid() && view->model()->rowCount()) {
view->setCurrentIndex(view->model()->index(0, 0));
view->setCurrentIndex(view->model()->index(0, 1));
}
}

View File

@ -523,6 +523,9 @@ void MainTab::updateDiveInfo(bool clear)
ui.TypeLabel->setVisible(false);
ui.waterTempLabel->setVisible(false);
ui.watertemp->setVisible(false);
ui.dateEdit->setReadOnly(true);
ui.label->setVisible(false);
ui.timeEdit->setVisible(false);
ui.diveTripLocation->show();
ui.location->hide();
ui.editDiveSiteButton->hide();
@ -561,6 +564,9 @@ void MainTab::updateDiveInfo(bool clear)
ui.DiveType->setVisible(true);
ui.waterTempLabel->setVisible(true);
ui.watertemp->setVisible(true);
ui.dateEdit->setReadOnly(false);
ui.label->setVisible(true);
ui.timeEdit->setVisible(true);
/* and fill them from the dive */
ui.rating->setCurrentStars(displayed_dive.rating);
ui.visibility->setCurrentStars(displayed_dive.visibility);
@ -674,6 +680,9 @@ void MainTab::updateDiveInfo(bool clear)
if (amount_selected > 1) {
ui.timeLimits->setMaximum(get_time_string_s(stats_selection.longest_time.seconds, 0, (displayed_dive.dc.divemode == FREEDIVE)));
ui.timeLimits->setMinimum(get_time_string_s(stats_selection.shortest_time.seconds, 0, (displayed_dive.dc.divemode == FREEDIVE)));
} else {
ui.timeLimits->setMaximum("");
ui.timeLimits->setMinimum("");
}
ui.timeLimits->overrideMaxToolTipText(tr("Longest dive"));
ui.timeLimits->overrideMinToolTipText(tr("Shortest dive"));

View File

@ -62,6 +62,7 @@ extern "C" int updateProgress(int percent)
{
if (progressDialog)
progressDialog->setValue(percent);
qApp->processEvents();
return progressDialogCanceled;
}
@ -686,6 +687,10 @@ void MainWindow::on_actionEditDeviceNames_triggered()
bool MainWindow::plannerStateClean()
{
if (progressDialog)
// we are accessing the cloud, so let's not switch into Add or Plan mode
return false;
if (DivePlannerPointsModel::instance()->currentMode() != DivePlannerPointsModel::NOTHING ||
information()->isEditing()) {
QMessageBox::warning(this, tr("Warning"), tr("Please save or cancel the current dive edit before trying to add a dive."));
@ -1621,6 +1626,8 @@ void MainWindow::importFiles(const QStringList fileNames)
void MainWindow::importTxtFiles(const QStringList fileNames)
{
QStringList csvFiles;
if (fileNames.isEmpty())
return;
@ -1630,7 +1637,18 @@ void MainWindow::importTxtFiles(const QStringList fileNames)
fileNamePtr = QFile::encodeName(fileNames.at(i));
csv = fileNamePtr.data();
csv.replace(strlen(csv.data()) - 3, 3, "csv");
parse_txt_file(fileNamePtr.data(), csv);
QFileInfo check_file(csv);
if (check_file.exists() && check_file.isFile()) {
if (parse_txt_file(fileNamePtr.data(), csv) == 0)
csvFiles += fileNames.at(i);
} else {
csvFiles += fileNamePtr;
}
}
if (csvFiles.size()) {
DiveLogImportDialog *diveLogImport = new DiveLogImportDialog(csvFiles, this);
diveLogImport->show();
}
process_dives(true, false);
refreshDisplay();
@ -1690,8 +1708,8 @@ void MainWindow::loadFiles(const QStringList fileNames)
void MainWindow::on_actionImportDiveLog_triggered()
{
QStringList fileNames = QFileDialog::getOpenFileNames(this, tr("Open dive log file"), lastUsedDir(),
tr("Dive log files (*.ssrf *.can *.csv *.db *.sql *.dld *.jlb *.lvd *.sde *.udcf *.uddf *.xml *.txt *.dlf *.apd"
"*.SSRF *.CAN *.CSV *.DB *.SQL *.DLD *.JLB *.LVD *.SDE *.UDCF *.UDDF *.xml *.TXT *.DLF *.APD);;"
tr("Dive log files (*.ssrf *.can *.csv *.db *.sql *.dld *.jlb *.lvd *.sde *.udcf *.uddf *.xml *.txt *.dlf *.apd *.zxu *.zxl"
"*.SSRF *.CAN *.CSV *.DB *.SQL *.DLD *.JLB *.LVD *.SDE *.UDCF *.UDDF *.xml *.TXT *.DLF *.APD *.ZXU *.ZXL);;"
"Cochran files (*.can *.CAN);;"
"CSV files (*.csv *.CSV);;"
"DiveLog.de files (*.dld *.DLD);;"
@ -1705,15 +1723,18 @@ void MainWindow::on_actionImportDiveLog_triggered()
"APD log viewer (*.apd *.APD);;"
"Datatrak/WLog Files (*.log *.LOG);;"
"OSTCtools Files (*.dive *.DIVE);;"
"DAN DL7 (*.zxu *.zxl *.ZXU *.ZXL);;"
"All files (*)"));
if (fileNames.isEmpty())
return;
updateLastUsedDir(QFileInfo(fileNames[0]).dir().path());
QStringList logFiles = fileNames.filter(QRegExp("^.*\\.(?!(csv|txt|apd))", Qt::CaseInsensitive));
QStringList logFiles = fileNames.filter(QRegExp("^(?!.*\\.(csv|txt|apd|zxu|zxl))", Qt::CaseInsensitive));
QStringList csvFiles = fileNames.filter(".csv", Qt::CaseInsensitive);
csvFiles += fileNames.filter(".apd", Qt::CaseInsensitive);
csvFiles += fileNames.filter(".zxu", Qt::CaseInsensitive);
csvFiles += fileNames.filter(".zxl", Qt::CaseInsensitive);
QStringList txtFiles = fileNames.filter(".txt", Qt::CaseInsensitive);
if (logFiles.size()) {

View File

@ -19,6 +19,10 @@ DiveEventItem::DiveEventItem(QObject *parent) : DivePixmapItem(parent),
setFlag(ItemIgnoresTransformations);
}
DiveEventItem::~DiveEventItem()
{
free(internalEvent);
}
void DiveEventItem::setHorizontalAxis(DiveCartesianAxis *axis)
{
@ -48,7 +52,9 @@ void DiveEventItem::setEvent(struct event *ev)
{
if (!ev)
return;
internalEvent = ev;
free(internalEvent);
internalEvent = clone_event(ev);
setupPixmap();
setupToolTipString();
recalculatePos(true);

View File

@ -11,6 +11,7 @@ class DiveEventItem : public DivePixmapItem {
Q_OBJECT
public:
DiveEventItem(QObject *parent = 0);
virtual ~DiveEventItem();
void setEvent(struct event *ev);
struct event *getEvent();
void eventVisibilityChanged(const QString &eventName, bool visible);

View File

@ -87,7 +87,7 @@ ProfileWidget2::ProfileWidget2(QWidget *parent) : QGraphicsView(parent),
gasPressureItem(new DiveGasPressureItem()),
diveComputerText(new DiveTextItem()),
diveCeiling(new DiveCalculatedCeiling()),
gradientFactor(new DiveTextItem()),
decoModelParameters(new DiveTextItem()),
reportedCeiling(new DiveReportedCeiling()),
pn2GasItem(new PartialPressureGasItem()),
pheGasItem(new PartialPressureGasItem()),
@ -204,7 +204,7 @@ void ProfileWidget2::addItemsToScene()
diveComputerText->setData(SUBSURFACE_OBJ_DATA, SUBSURFACE_OBJ_DC_TEXT);
scene()->addItem(diveComputerText);
scene()->addItem(diveCeiling);
scene()->addItem(gradientFactor);
scene()->addItem(decoModelParameters);
scene()->addItem(reportedCeiling);
scene()->addItem(pn2GasItem);
scene()->addItem(pheGasItem);
@ -288,11 +288,11 @@ void ProfileWidget2::setupItemOnScene()
rulerItem->setAxis(timeAxis, profileYAxis);
tankItem->setHorizontalAxis(timeAxis);
// show the gradient factor at the top in the center
gradientFactor->setY(0);
gradientFactor->setX(50);
gradientFactor->setBrush(getColor(PRESSURE_TEXT));
gradientFactor->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
// show the deco model parameters at the top in the center
decoModelParameters->setY(0);
decoModelParameters->setX(50);
decoModelParameters->setBrush(getColor(PRESSURE_TEXT));
decoModelParameters->setAlignment(Qt::AlignHCenter | Qt::AlignBottom);
setupItem(reportedCeiling, timeAxis, profileYAxis, dataModel, DivePlotDataModel::CEILING, DivePlotDataModel::TIME, 1);
setupItem(diveCeiling, timeAxis, profileYAxis, dataModel, DivePlotDataModel::CEILING, DivePlotDataModel::TIME, 1);
@ -509,7 +509,10 @@ void ProfileWidget2::plotDive(struct dive *d, bool force)
// this copies the dive and makes copies of all the relevant additional data
copy_dive(d, &displayed_dive);
gradientFactor->setText(QString("GF %1/%2").arg(prefs.gflow).arg(prefs.gfhigh));
if (prefs.deco_mode == VPMB)
decoModelParameters->setText(QString("VPM-B +%1").arg(prefs.conservatism_level));
else
decoModelParameters->setText(QString("GF %1/%2").arg(prefs.gflow).arg(prefs.gfhigh));
} else {
DivePlannerPointsModel *plannerModel = DivePlannerPointsModel::instance();
plannerModel->createTemporaryPlan();
@ -518,7 +521,10 @@ void ProfileWidget2::plotDive(struct dive *d, bool force)
plannerModel->deleteTemporaryPlan();
return;
}
gradientFactor->setText(QString("GF %1/%2").arg(diveplan.gflow).arg(diveplan.gfhigh));
if (prefs.deco_mode == VPMB)
decoModelParameters->setText(QString("VPM-B +%1").arg(prefs.conservatism_level));
else
decoModelParameters->setText(QString("GF %1/%2").arg(diveplan.gflow).arg(diveplan.gfhigh));
}
// special handling for the first time we display things
@ -926,7 +932,7 @@ void ProfileWidget2::setEmptyState()
toolTipItem->setVisible(false);
diveComputerText->setVisible(false);
diveCeiling->setVisible(false);
gradientFactor->setVisible(false);
decoModelParameters->setVisible(false);
reportedCeiling->setVisible(false);
rulerItem->setVisible(false);
tankItem->setVisible(false);
@ -941,6 +947,8 @@ void ProfileWidget2::setEmptyState()
gflineItem->setVisible(false);
mouseFollowerHorizontal->setVisible(false);
mouseFollowerVertical->setVisible(false);
heartBeatAxis->setVisible(false);
heartBeatItem->setVisible(false);
#define HIDE_ALL(TYPE, CONTAINER) \
Q_FOREACH (TYPE *item, CONTAINER) item->setVisible(false);
@ -1053,7 +1061,7 @@ void ProfileWidget2::setProfileState()
diveComputerText->setPos(itemPos.dcLabel.on);
diveCeiling->setVisible(prefs.calcceiling);
gradientFactor->setVisible(prefs.calcceiling);
decoModelParameters->setVisible(prefs.calcceiling);
reportedCeiling->setVisible(prefs.dcceiling);
if (prefs.calcalltissues) {
@ -1131,7 +1139,7 @@ void ProfileWidget2::setAddState()
/* show the same stuff that the profile shows. */
currentState = ADD; /* enable the add state. */
diveCeiling->setVisible(true);
gradientFactor->setVisible(true);
decoModelParameters->setVisible(true);
setBackgroundBrush(QColor("#A7DCFF"));
}
@ -1165,7 +1173,7 @@ void ProfileWidget2::setPlanState()
/* show the same stuff that the profile shows. */
currentState = PLAN; /* enable the add state. */
diveCeiling->setVisible(true);
gradientFactor->setVisible(true);
decoModelParameters->setVisible(true);
setBackgroundBrush(QColor("#D7E3EF"));
}

View File

@ -171,7 +171,7 @@ private:
QList<DiveEventItem *> eventItems;
DiveTextItem *diveComputerText;
DiveCalculatedCeiling *diveCeiling;
DiveTextItem *gradientFactor;
DiveTextItem *decoModelParameters;
QList<DiveCalculatedTissue *> allTissues;
DiveReportedCeiling *reportedCeiling;
PartialPressureGasItem *pn2GasItem;

View File

@ -818,7 +818,7 @@ void DivelogsDeWebServices::startDownload()
QUrlQuery body;
body.addQueryItem("user", ui.userID->text());
body.addQueryItem("pass", ui.password->text());
body.addQueryItem("pass", ui.password->text().replace("+", "%2b"));
reply = manager()->post(request, body.query(QUrl::FullyEncoded).toLatin1());
connect(reply, SIGNAL(finished()), this, SLOT(listDownloadFinished()));
@ -855,7 +855,7 @@ void DivelogsDeWebServices::listDownloadFinished()
QUrlQuery body;
body.addQueryItem("user", ui.userID->text());
body.addQueryItem("pass", ui.password->text());
body.addQueryItem("pass", ui.password->text().replace("+", "%2b"));
body.addQueryItem("ids", diveList.idList);
reply = manager()->post(request, body.query(QUrl::FullyEncoded).toLatin1());

View File

@ -1108,6 +1108,7 @@ extern "C" void reverseGeoLookup(degrees_t latitude, degrees_t longitude, uint32
QHash<QString, QByteArray> hashOf;
QMutex hashOfMutex;
QHash<QByteArray, QString> localFilenameOf;
QHash <QString, QImage > thumbnailCache;
extern "C" char * hashstring(char * filename)
{
@ -1131,6 +1132,7 @@ void read_hashes()
QDataStream stream(&hashfile);
stream >> localFilenameOf;
stream >> hashOf;
stream >> thumbnailCache;
hashfile.close();
}
}
@ -1142,6 +1144,7 @@ void write_hashes()
QDataStream stream(&hashfile);
stream << localFilenameOf;
stream << hashOf;
stream << thumbnailCache;
hashfile.commit();
} else {
qDebug() << "cannot open" << hashfile.fileName();
@ -1179,9 +1182,11 @@ void learnHash(struct picture *picture, QByteArray hash)
QString localFilePath(const QString originalFilename)
{
if (hashOf.contains(originalFilename) && localFilenameOf.contains(hashOf[originalFilename]))
return localFilenameOf[hashOf[originalFilename]];
else
if (hashOf.contains(originalFilename))
if (localFilenameOf.contains(hashOf[originalFilename]))
if (localFilenameOf[hashOf[originalFilename]] != "")
return localFilenameOf[hashOf[originalFilename]];
return originalFilename;
}
@ -1197,6 +1202,7 @@ void updateHash(struct picture *picture) {
char *old = picture->hash;
picture->hash = strdup(hash.toHex());
free(old);
picture_free(picture);
}
void hashPicture(struct picture *picture)
@ -1206,13 +1212,14 @@ void hashPicture(struct picture *picture)
if (!same_string(picture->hash, "") && !same_string(picture->hash, oldHash))
mark_divelist_changed((true));
free(oldHash);
picture_free(picture);
}
extern "C" void cache_picture(struct picture *picture)
{
QString filename = picture->filename;
if (!hashOf.contains(filename))
QtConcurrent::run(hashPicture, picture);
QtConcurrent::run(hashPicture, clone_picture(picture));
}
void learnImages(const QDir dir, int max_recursions, bool recursed)

View File

@ -629,6 +629,8 @@ static int save_one_picture(git_repository *repo, struct dir *dir, struct pictur
offset -= h *3600;
error = blob_insert(repo, dir, &buf, "%c%02u=%02u=%02u",
sign, h, FRACTION(offset, 60));
#if 0
/* storing pictures into git was a mistake. This makes for HUGE git repositories */
if (!error) {
/* next store the actual picture; we prefix all picture names
* with "PIC-" to make things easier on the parsing side */
@ -638,6 +640,7 @@ static int save_one_picture(git_repository *repo, struct dir *dir, struct pictur
error = blob_insert_fromdisk(repo, dir, localfn, mb_cstring(&namebuf));
free((void *)localfn);
}
#endif
return error;
}

View File

@ -259,6 +259,29 @@ void put_HTML_time(struct membuffer *b, struct dive *dive, const char *pre, cons
put_format(b, "%s%02u:%02u:%02u%s", pre, tm.tm_hour, tm.tm_min, tm.tm_sec, post);
}
void put_HTML_depth(struct membuffer *b, struct dive *dive, const char *pre, const char *post)
{
const char *unit;
double value;
struct units *units_p = get_units();
if (!dive->maxdepth.mm) {
put_format(b, "%s--%s", pre, post);
return;
}
value = get_depth_units(dive->maxdepth.mm, NULL, &unit);
switch (units_p->length) {
case METERS:
default:
put_format(b, "%s%.1f %s%s", pre, value, unit, post);
break;
case FEET:
put_format(b, "%s%.0f %s%s", pre, value, unit, post);
break;
}
}
void put_HTML_airtemp(struct membuffer *b, struct dive *dive, const char *pre, const char *post)
{
const char *unit;

View File

@ -9,6 +9,7 @@ extern "C" {
#include "membuffer.h"
void put_HTML_date(struct membuffer *b, struct dive *dive, const char *pre, const char *post);
void put_HTML_depth(struct membuffer *b, struct dive *dive, const char *pre, const char *post);
void put_HTML_airtemp(struct membuffer *b, struct dive *dive, const char *pre, const char *post);
void put_HTML_watertemp(struct membuffer *b, struct dive *dive, const char *pre, const char *post);
void put_HTML_time(struct membuffer *b, struct dive *dive, const char *pre, const char *post);

View File

@ -28,6 +28,18 @@ if [[ ! -d "subsurface" ]] ; then
exit 1
fi
# Verify that the Xcode Command Line Tools are installed
if [ $PLATFORM = Darwin ] ; then
if [ ! -d /usr/include ] ; then
echo "Error: Xcode Command Line Tools are not installed"
echo ""
echo "Please run:"
echo " xcode-select --install"
echo "to install them (you'll have to agree to Apple's licensing terms etc), then run build.sh again"
exit 1;
fi
fi
mkdir -p install-root
INSTALL_ROOT=$SRC/install-root
@ -118,7 +130,7 @@ fi
if [ ! -f configure ] ; then
autoreconf --install
fi
./configure --prefix=$INSTALL_ROOT
./configure --prefix=$INSTALL_ROOT --disable-examples
make -j4
make install
@ -142,7 +154,14 @@ fi
mkdir -p build
cd build
if [ $PLATFORM = Darwin ] ; then
export CMAKE_PREFIX_PATH=~/Qt/5.5/clang_64/lib/cmake
if [ -d "~/Qt/5.5" ] ; then
export CMAKE_PREFIX_PATH=~/Qt/5.5/clang_64/lib/cmake
elif [ -d "~/Qt/5.6" ] ; then
export CMAKE_PREFIX_PATH=~/Qt/5.6/clang_64/lib/cmake
elif [ -d /usr/local/opt/qt5/lib ] ; then
# Homebrew location for qt5 package
export CMAKE_PREFIX_PATH=/usr/local/opt/qt5/lib/cmake
fi
fi
cmake -DCMAKE_BUILD_TYPE=Release -DQTONLY=TRUE -DQT5BUILD=ON \
-DCMAKE_INSTALL_PREFIX=$INSTALL_ROOT \
@ -200,7 +219,7 @@ fi
cd $SRC/subsurface
mkdir -p build
cd build
export CMAKE_PREFIX_PATH=$INSTALL_ROOT/lib/cmake
export CMAKE_PREFIX_PATH="$INSTALL_ROOT/lib/cmake;${CMAKE_PREFIX_PATH}"
cmake -DCMAKE_BUILD_TYPE=Debug .. \
-DLIBGIT2_INCLUDE_DIR=$INSTALL_ROOT/include \
-DLIBGIT2_LIBRARIES=$INSTALL_ROOT/lib/libgit2.$SH_LIB_EXT \
@ -208,6 +227,7 @@ cmake -DCMAKE_BUILD_TYPE=Debug .. \
-DLIBDIVECOMPUTER_LIBRARIES=$INSTALL_ROOT/lib/libdivecomputer.a \
-DMARBLE_INCLUDE_DIR=$INSTALL_ROOT/include \
-DMARBLE_LIBRARIES=$INSTALL_ROOT/lib/libssrfmarblewidget.$SH_LIB_EXT \
-DCMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH \
-DNO_PRINTING=OFF \
-DUSE_LIBGIT23_API=1

View File

@ -20,6 +20,7 @@ stats_t stats_selection;
stats_t *stats_monthly = NULL;
stats_t *stats_yearly = NULL;
stats_t *stats_by_trip = NULL;
stats_t *stats_by_type = NULL;
static void process_temperatures(struct dive *dp, stats_t *stats)
{
@ -100,7 +101,7 @@ void process_all_dives(struct dive *dive, struct dive **prev_dive)
int prev_month = 0, prev_year = 0;
int trip_iter = 0;
dive_trip_t *trip_ptr = 0;
unsigned int size;
unsigned int size, tsize;
*prev_dive = NULL;
memset(&stats, 0, sizeof(stats));
@ -117,18 +118,35 @@ void process_all_dives(struct dive *dive, struct dive **prev_dive)
free(stats_yearly);
free(stats_monthly);
free(stats_by_trip);
free(stats_by_type);
size = sizeof(stats_t) * (dive_table.nr + 1);
tsize = sizeof(stats_t) * (NUM_DC_TYPE + 1);
stats_yearly = malloc(size);
stats_monthly = malloc(size);
stats_by_trip = malloc(size);
if (!stats_yearly || !stats_monthly || !stats_by_trip)
stats_by_type = malloc(tsize);
if (!stats_yearly || !stats_monthly || !stats_by_trip || !stats_by_type)
return;
memset(stats_yearly, 0, size);
memset(stats_monthly, 0, size);
memset(stats_by_trip, 0, size);
memset(stats_by_type, 0, tsize);
stats_yearly[0].is_year = true;
/* Setting the is_trip to true to show the location as first
* field in the statistics window */
stats_by_type[0].location = strdup("All (by type stats)");
stats_by_type[0].is_trip = true;
stats_by_type[1].location = strdup("OC");
stats_by_type[1].is_trip = true;
stats_by_type[2].location = strdup("CCR");
stats_by_type[2].is_trip = true;
stats_by_type[3].location = strdup("pSCR");
stats_by_type[3].is_trip = true;
stats_by_type[4].location = strdup("Freedive");
stats_by_type[4].is_trip = true;
/* this relies on the fact that the dives in the dive_table
* are in chronological order */
for_each_dive (idx, dp) {
@ -154,6 +172,13 @@ void process_all_dives(struct dive *dive, struct dive **prev_dive)
stats_yearly[year_iter].selection_size++;
stats_yearly[year_iter].period = current_year;
/* stats_by_type[0] is all the dives combined */
stats_by_type[0].selection_size++;
process_dive(dp, &(stats_by_type[0]));
process_dive(dp, &(stats_by_type[dp->dc.divemode + 1]));
stats_by_type[dp->dc.divemode + 1].selection_size++;
if (dp->divetrip != NULL) {
if (trip_ptr != dp->divetrip) {
trip_ptr = dp->divetrip;

View File

@ -39,6 +39,7 @@ extern stats_t stats_selection;
extern stats_t *stats_yearly;
extern stats_t *stats_monthly;
extern stats_t *stats_by_trip;
extern stats_t *stats_by_type;
extern char *get_time_string_s(int seconds, int maxdays, bool freediving);
extern char *get_minutes(int seconds);

View File

@ -308,12 +308,5 @@ void copy_prefs(struct preferences *src, struct preferences *dest)
*/
void free_prefs(void)
{
free((void*)prefs.default_filename);
free((void*)prefs.default_cylinder);
free((void*)prefs.divelist_font);
free((void*)prefs.cloud_storage_password);
free(prefs.proxy_host);
free(prefs.proxy_user);
free(prefs.proxy_pass);
free(prefs.userid);
// nop
}

View File

@ -6,6 +6,7 @@ set_directory_properties(PROPERTIES CLEAN_NO_CUSTOM 1)
set(TRANSLATION_FILES
subsurface_source.ts
subsurface_bg_BG.ts
subsurface_ca.ts
subsurface_cs.ts
subsurface_da_DK.ts
subsurface_de_CH.ts

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -73,6 +73,8 @@ static int max_mem_used = -1;
static int next_table_index = 0;
static int dive_to_read = 0;
static int max_deleted_seen = -1;
/* helper function to parse the Uemis data structures */
static void uemis_ts(char *buffer, void *_when)
{
@ -172,6 +174,8 @@ static void uemis_info(const char *fmt, ...)
vsnprintf(buffer, sizeof(buffer), fmt, ap);
va_end(ap);
progress_bar_text = buffer;
if (verbose)
fprintf(stderr, "Uemis downloader: %s\n", buffer);
}
static long bytes_available(int file)
@ -512,6 +516,7 @@ static bool uemis_get_answer(const char *path, char *request, int n_param_in,
}
trigger_response(reqtxt_file, "n", filenr, file_length);
usleep(timeout);
free(mbuf);
mbuf = NULL;
mbuf_size = 0;
while (searching || assembling_mbuf) {
@ -969,6 +974,12 @@ static char *uemis_get_divenr(char *deviceidstr, int force)
maxdiveid = dc->diveid;
}
}
if (max_deleted_seen >= 0 && maxdiveid < max_deleted_seen) {
maxdiveid = max_deleted_seen;
#if UEMIS_DEBUG & 4
fprintf(debugfile, "overriding max seen with max deleted seen %d\n", max_deleted_seen);
#endif
}
snprintf(divenr, 10, "%d", maxdiveid);
return strdup(divenr);
}
@ -1031,6 +1042,9 @@ static int get_memory(struct dive_table *td, int checkpoint)
max_mem_used = filenr / td->nr;
/* check if a full block of dive logs + dive details and dive spot fit into the UEMIS buffer */
#if UEMIS_DEBUG & 4
fprintf(debugfile, "max_mem_used %d (from td->nr %d) * block_size %d > max_files %d - filenr %d?\n", max_mem_used, td->nr, UEMIS_LOG_BLOCK_SIZE, UEMIS_MAX_FILES, filenr);
#endif
if (max_mem_used * UEMIS_LOG_BLOCK_SIZE > UEMIS_MAX_FILES - filenr)
return UEMIS_MEM_FULL;
break;
@ -1109,9 +1123,14 @@ static bool get_matching_dive(int idx, char *newmax, int *uemis_mem_status, stru
char log_file_no_to_find[20];
char dive_to_read_buf[10];
bool found = false;
bool found_below = false;
bool found_above = false;
int deleted_files = 0;
snprintf(log_file_no_to_find, sizeof(log_file_no_to_find), "logfilenr{int{%d", dive->dc.diveid);
#if UEMIS_DEBUG & 2
fprintf(debugfile, "Looking for dive details to go with divelog id %d\n", dive->dc.diveid);
#endif
while (!found) {
if (import_thread_cancelled)
break;
@ -1154,10 +1173,11 @@ static bool get_matching_dive(int idx, char *newmax, int *uemis_mem_status, stru
fprintf(debugfile, "TRY matching divelog id %d from %s with dive details %d but details are deleted\n", dive->dc.diveid, d_time, dive_to_read);
#endif
deleted_files++;
max_deleted_seen = dive_to_read;
/* mark this log entry as deleted and cleanup later, otherwise we mess up our array */
dive->downloaded = false;
#if UEMIS_DEBUG & 2
fprintf(debugfile, "Deleted dive from %s, with id %d from table\n", d_time, dive->dc.diveid);
fprintf(debugfile, "Deleted dive from %s, with id %d from table -- newmax is %s\n", d_time, dive->dc.diveid, newmax);
#endif
}
} else {
@ -1165,13 +1185,19 @@ static bool get_matching_dive(int idx, char *newmax, int *uemis_mem_status, stru
char *logfilenr = strstr(mbuf, "logfilenr");
if (logfilenr) {
sscanf(logfilenr, "logfilenr{int{%u", &nr_found);
if (nr_found >= dive->dc.diveid)
if (nr_found >= dive->dc.diveid || nr_found == 0) {
found_above = true;
dive_to_read = dive_to_read - 2;
} else {
found_below = true;
}
if (dive_to_read < -1)
dive_to_read = -1;
}
}
}
if (found_above && found_below)
break;
dive_to_read++;
} else {
/* At this point the memory of the UEMIS is full, let's cleanup all divelog files were
@ -1233,6 +1259,8 @@ const char *do_uemis_import(device_data_t *data)
param_buff[1] = "notempty";
newmax = uemis_get_divenr(deviceid, force_download);
if (verbose)
fprintf(stderr, "Uemis downloader: start looking at dive nr %s", newmax);
first = start = atoi(newmax);
dive_to_read = first;
@ -1250,27 +1278,30 @@ const char *do_uemis_import(device_data_t *data)
param_buff[3] = 0;
success = uemis_get_answer(mountpath, "getDivelogs", 3, 0, &result);
uemis_mem_status = get_memory(data->download_table, UEMIS_CHECK_DETAILS);
if (success && mbuf && uemis_mem_status != UEMIS_MEM_FULL) {
/* first, remove any leading garbage... this needs to start with a '{' */
char *realmbuf = mbuf;
if (mbuf)
realmbuf = strchr(mbuf, '{');
if (success && realmbuf && uemis_mem_status != UEMIS_MEM_FULL) {
#if UEMIS_DEBUG & 16
do_dump_buffer_to_file(mbuf, "Divelogs");
do_dump_buffer_to_file(realmbuf, "Divelogs");
#endif
/* process the buffer we have assembled */
if (!process_raw_buffer(data, deviceidnr, mbuf, &newmax, keep_number, NULL)) {
if (!process_raw_buffer(data, deviceidnr, realmbuf, &newmax, keep_number, NULL)) {
/* if no dives were downloaded, mark end appropriately */
if (end == -2)
end = start - 1;
success = false;
}
if (once) {
char *t = first_object_id_val(mbuf);
char *t = first_object_id_val(realmbuf);
if (t && atoi(t) > start)
start = atoi(t);
free(t);
once = false;
}
/* clean up mbuf */
endptr = strstr(mbuf, "{{{");
endptr = strstr(realmbuf, "{{{");
if (endptr)
*(endptr + 2) = '\0';
/* last object_id we parsed */
@ -1296,20 +1327,32 @@ const char *do_uemis_import(device_data_t *data)
/* Do some memory checking here */
uemis_mem_status = get_memory(data->download_table, UEMIS_CHECK_LOG);
if (uemis_mem_status != UEMIS_MEM_OK)
if (uemis_mem_status != UEMIS_MEM_OK) {
#if UEMIS_DEBUG & 4
fprintf(debugfile, "d_u_i out of memory, bailing\n");
#endif
break;
}
/* if the user clicked cancel, exit gracefully */
if (import_thread_cancelled)
if (import_thread_cancelled) {
#if UEMIS_DEBUG & 4
fprintf(debugfile, "d_u_i thread cancelled, bailing\n");
#endif
break;
}
/* if we got an error or got nothing back, stop trying */
if (!success || !param_buff[3])
if (!success || !param_buff[3]) {
#if UEMIS_DEBUG & 4
fprintf(debugfile, "d_u_i after download nothing found, giving up\n");
#endif
break;
}
#if UEMIS_DEBUG & 2
if (debug_round != -1)
if (debug_round-- == 0)
if (debug_round-- == 0) {
fprintf(debugfile, "d_u_i debug_round is now 0, bailing\n");
goto bail;
}
#endif
} else {
/* some of the loading from the UEMIS failed at the divelog level
@ -1319,6 +1362,9 @@ const char *do_uemis_import(device_data_t *data)
*/
if (uemis_mem_status == UEMIS_MEM_FULL)
do_delete_dives(data->download_table, match_dive_and_log);
#if UEMIS_DEBUG & 4
fprintf(debugfile, "d_u_i out of memory, bailing instead of processing\n");
#endif
break;
}
}

View File

@ -27,5 +27,6 @@ void WindowTitleUpdate::emitSignal()
extern "C" void updateWindowTitle()
{
WindowTitleUpdate *wt = WindowTitleUpdate::instance();
wt->emitSignal();
if (wt)
wt->emitSignal();
}

View File

@ -40,9 +40,9 @@ void writeMarkers(struct membuffer *b, const bool selected_only)
snprintf(pre, sizeof(pre), "<p>%s ", translate("gettextFromC", "Duration:"));
snprintf(post, sizeof(post), " %s</p>", translate("gettextFromC", "min"));
put_duration(b, dive->duration, pre, post);
snprintf(pre, sizeof(pre), "<p>%s ", translate("gettextFromC", "Max. depth:"));
snprintf(post, sizeof(post), " %s</p>", translate("gettextFromC", "m"));
put_depth(b, dive->maxdepth, pre, post);
put_string(b, "<p> ");
put_HTML_quoted(b, translate("gettextFromC", "Max. depth:"));
put_HTML_depth(b, dive, " ", "</p>");
put_string(b, "<p> ");
put_HTML_quoted(b, translate("gettextFromC", "Air temp.:"));
put_HTML_airtemp(b, dive, " ", "</p>");

View File

@ -25,10 +25,20 @@
</xsl:attribute>
<xsl:attribute name="duration">
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec" select="DIVETIMESEC"/>
<xsl:with-param name="units" select="$units"/>
</xsl:call-template>
<xsl:choose>
<xsl:when test="DIVETIMESEC != ''">
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec" select="DIVETIMESEC"/>
<xsl:with-param name="units" select="$units"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec" select="SAMPLECNT * SAMPLEINTERVAL"/>
<xsl:with-param name="units" select="$units"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:choose>
@ -178,7 +188,36 @@
<!-- dive sample - all the depth and temp readings -->
<xsl:for-each select="SAMPLE">
<xsl:choose>
<xsl:when test="BOOKMARK = ''">
<xsl:when test="BOOKMARK != ''">
<xsl:choose>
<xsl:when test="substring-before(BOOKMARK, ':') = 'Heading'">
<event name="heading">
<xsl:attribute name="value">
<xsl:value-of select="substring-before(substring-after(BOOKMARK, ': '), '°')"/>
</xsl:attribute>
<xsl:attribute name="time">
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec" select="SAMPLETIME"/>
<xsl:with-param name="units" select="'si'"/>
</xsl:call-template>
</xsl:attribute>
</event>
</xsl:when>
<xsl:otherwise>
<xsl:if test="BOOKMARK != 'Surface'">
<event name="{BOOKMARK}">
<xsl:attribute name="time">
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec" select="SAMPLETIME"/>
<xsl:with-param name="units" select="'si'"/>
</xsl:call-template>
</xsl:attribute>
</event>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<sample>
<xsl:attribute name="time">
<xsl:call-template name="timeConvert">
@ -201,31 +240,6 @@
</xsl:call-template>
</xsl:attribute>
</sample>
</xsl:when>
<xsl:when test="substring-before(BOOKMARK, ':') = 'Heading'">
<event name="heading">
<xsl:attribute name="value">
<xsl:value-of select="substring-before(substring-after(BOOKMARK, ': '), '°')"/>
</xsl:attribute>
<xsl:attribute name="time">
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec" select="SAMPLETIME"/>
<xsl:with-param name="units" select="'si'"/>
</xsl:call-template>
</xsl:attribute>
</event>
</xsl:when>
<xsl:otherwise>
<xsl:if test="BOOKMARK != 'Surface'">
<event name="{BOOKMARK}">
<xsl:attribute name="time">
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec" select="SAMPLETIME"/>
<xsl:with-param name="units" select="'si'"/>
</xsl:call-template>
</xsl:attribute>
</event>
</xsl:if>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>

View File

@ -127,7 +127,7 @@
<!-- Handling last value -->
<xsl:when test="count($values) = 1">
<xsl:value-of select="format-number($value + $sum, '#.#')"/>
<xsl:value-of select="format-number($value + $sum, '#.###')"/>
</xsl:when>
<!-- More than one value to sum -->

View File

@ -2,6 +2,9 @@
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:include href="commonTemplates.xsl"/>
<xsl:strip-space elements="*"/>
<xsl:param name="dateField" select="dateField"/>
<xsl:param name="datefmt" select="datefmt"/>
<xsl:param name="starttimeField" select="starttimeField"/>
<xsl:param name="timeField" select="timeField"/>
<xsl:param name="depthField" select="depthField"/>
<xsl:param name="tempField" select="tempField"/>
@ -30,6 +33,7 @@
<xsl:choose>
<xsl:when test="$separatorIndex = 0"><xsl:text> </xsl:text></xsl:when>
<xsl:when test="$separatorIndex = 2"><xsl:text>;</xsl:text></xsl:when>
<xsl:when test="$separatorIndex = 3"><xsl:text>|</xsl:text></xsl:when>
<xsl:otherwise><xsl:text>,</xsl:text></xsl:otherwise>
</xsl:choose>
</xsl:variable>
@ -39,12 +43,73 @@
<dives>
<dive>
<xsl:attribute name="date">
<xsl:value-of select="concat(substring($date, 1, 4), '-', substring($date, 5, 2), '-', substring($date, 7, 2))"/>
<xsl:choose>
<xsl:when test="$dateField >= 0">
<xsl:variable name="indate">
<xsl:call-template name="getFieldByIndex">
<xsl:with-param name="index" select="$dateField"/>
<xsl:with-param name="line" select="substring-after(substring-after(., $lf), $lf)"/>
</xsl:call-template>
</xsl:variable>
<xsl:variable name="separator">
<xsl:choose>
<xsl:when test="substring-before($indate, '.') != ''">
<xsl:value-of select="'.'"/>
</xsl:when>
<xsl:when test="substring-before($indate, '-') != ''">
<xsl:value-of select="'-'"/>
</xsl:when>
<xsl:when test="substring-before($indate, '/') != ''">
<xsl:value-of select="'/'"/>
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:choose>
<!-- dd.mm.yyyy -->
<xsl:when test="$datefmt = 0">
<xsl:value-of select="translate(concat(substring-after(substring-after($indate, $separator), $separator), '-', substring-before(substring-after($indate, $separator), $separator), '-', substring-before($indate, $separator)), ' ', '')"/>
</xsl:when>
<!-- mm.yy.yyyy -->
<xsl:when test="$datefmt = 1">
<xsl:value-of select="translate(concat(substring-after(substring-after($indate, $separator), $separator), '-', substring-before($indate, $separator), '-', substring-before(substring-after($indate, $separator), $separator)), ' ', '')"/>
</xsl:when>
<!-- yyyy.mm.dd -->
<xsl:when test="$datefmt = 2">
<xsl:value-of select="translate(concat(substring-before($indate, $separator), '-', substring-before(substring-after($indate, $separator), $separator), '-', substring-after(substring-after($indate, $separator), $separator)), ' ', '')"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="'1900-1-1'"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(substring($date, 1, 4), '-', substring($date, 5, 2), '-', substring($date, 7, 2))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:attribute name="time">
<xsl:value-of select="concat(substring($time, 2, 2), ':', substring($time, 4, 2))"/>
<xsl:choose>
<xsl:when test="$starttimeField >= 0">
<xsl:call-template name="getFieldByIndex">
<xsl:with-param name="index" select="$starttimeField"/>
<xsl:with-param name="line" select="substring-after(substring-after(., $lf), $lf)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(substring($time, 2, 2), ':', substring($time, 4, 2))"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
<xsl:if test="$numberField >= 0">
<xsl:attribute name="number">
<xsl:call-template name="getFieldByIndex">
<xsl:with-param name="index" select="$numberField"/>
<xsl:with-param name="line" select="substring-after(substring-after(., $lf), $lf)"/>
</xsl:call-template>
</xsl:attribute>
</xsl:if>
<!-- If the dive is CCR, create oxygen and diluent cylinders -->
<xsl:if test="$po2Field >= 0 or $setpointField >= 0 or $o2sensor1Field >= 0 or $o2sensor2Field >= 0 or $o2sensor3Field >= 0">
@ -165,7 +230,15 @@
<xsl:call-template name="sec2time">
<xsl:with-param name="timeSec">
<xsl:value-of select="$value"/>
<xsl:choose>
<xsl:when test="substring-after($value, '.') != ''">
<!-- Well, I suppose it was min.sec -->
<xsl:value-of select="substring-before($value, '.') * 60 + substring-after($value, '.')" />
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$value"/>
</xsl:otherwise>
</xsl:choose>
</xsl:with-param>
</xsl:call-template>
</xsl:when>
@ -334,10 +407,20 @@
<xsl:if test="$pressureField >= 0">
<xsl:attribute name="pressure">
<xsl:call-template name="getFieldByIndex">
<xsl:with-param name="index" select="$pressureField"/>
<xsl:with-param name="line" select="$line"/>
</xsl:call-template>
<xsl:variable name="pressure">
<xsl:call-template name="getFieldByIndex">
<xsl:with-param name="index" select="$pressureField"/>
<xsl:with-param name="line" select="$line"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$units = 0">
<xsl:value-of select="$pressure"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(format-number(($pressure div 14.5037738007), '#'), ' bar')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:if>
</sample>

View File

@ -164,6 +164,14 @@
</xsl:attribute>
</sample>
</xsl:for-each>
<xsl:for-each select="PICTURES/PICTURE">
<picture>
<xsl:attribute name="filename">
<xsl:value-of select="concat('https://divelogs.de', @path, .)"/>
</xsl:attribute>
</picture>
</xsl:for-each>
</dive>
</xsl:template>
</xsl:stylesheet>

View File

@ -264,10 +264,20 @@
<cylinder>
<xsl:if test="$cylindersizeField &gt; 0">
<xsl:attribute name="size">
<xsl:call-template name="getFieldByIndex">
<xsl:with-param name="index" select="$cylindersizeField"/>
<xsl:with-param name="line" select="$line"/>
</xsl:call-template>
<xsl:variable name="size">
<xsl:call-template name="getFieldByIndex">
<xsl:with-param name="index" select="$cylindersizeField"/>
<xsl:with-param name="line" select="$line"/>
</xsl:call-template>
</xsl:variable>
<xsl:choose>
<xsl:when test="$units = 0">
<xsl:value-of select="$size"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="format-number((translate($size, translate($size, '0123456789', ''), '') * 14.7 div 3000) div 0.35315, '#.#')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:if>
<xsl:if test="$startpressureField &gt; 0">

View File

@ -90,13 +90,24 @@
<!-- samples recorded at irregular internal, but storing time stamp -->
<xsl:when test="timedepthmode">
<xsl:variable name="timeconvert">
<xsl:choose>
<xsl:when test="//units = 'si'">
<xsl:value-of select="60"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<debug name="{$timeconvert}"/>
<!-- gas change -->
<xsl:for-each select="SAMPLES/SWITCH|samples/switch">
<event name="gaschange">
<xsl:variable name="timeSec" select="following-sibling::T|following-sibling::t"/>
<xsl:attribute name="time">
<xsl:value-of select="concat(floor($timeSec div 60), ':',
format-number(floor($timeSec mod 60), '00'), ' min')"/>
<xsl:value-of select="concat(floor($timeSec div $timeconvert), ':',
format-number(floor($timeSec mod $timeconvert), '00'), ' min')"/>
</xsl:attribute>
<xsl:attribute name="value">
<xsl:value-of select="ancestor::DIVE/GASES/MIX[MIXNAME=current()]/O2|ancestor::dive/gases/mix[mixname=current()]/o2 * 100" />
@ -110,8 +121,8 @@
<sample>
<xsl:variable name="timeSec" select="preceding-sibling::T[position()=1]|preceding-sibling::t[position()=1]"/>
<xsl:attribute name="time">
<xsl:value-of select="concat(floor($timeSec div 60), ':',
format-number(floor($timeSec mod 60), '00'), ' min')"/>
<xsl:value-of select="concat(floor($timeSec div $timeconvert), ':',
format-number(floor($timeSec mod $timeconvert), '00'), ' min')"/>
</xsl:attribute>
<xsl:attribute name="depth">
<xsl:value-of select="concat(., ' m')"/>

View File

@ -38,6 +38,7 @@
<xsl:template match="/divelog/settings"/>
<xsl:template match="/divelog/divesites"/>
<xsl:template match="/divelog/dives">
<uddf version="3.2.0" xmlns="http://www.streit.cc/uddf/3.2/">
@ -121,7 +122,6 @@
</diver>
<divesite>
<!-- There must be at least one divebase. Subsurface doesn't track this as a concept, so just assign them all to a single divebase. -->
<divebase id="allbase">
<name>Subsurface Divebase</name>
@ -235,6 +235,13 @@
<xsl:value-of select="substring-after(@gps, ' ')"/>
</longitude>
</geography>
<xsl:if test="notes != ''">
<sitedata>
<notes>
<xsl:value-of select="notes"/>
</notes>
</sitedata>
</xsl:if>
</site>
</xsl:template>

View File

@ -60,6 +60,9 @@
</xsl:template>
<xsl:template match="dive|u:dive|u1:dive">
<xsl:variable name="tankdata">
<xsl:value-of select="count(//tankdata|//u:tankdata|//u1:tankdata)"/>
</xsl:variable>
<dive>
<!-- Count the amount of temeprature samples during the dive -->
<xsl:variable name="temperatureSamples">
@ -278,7 +281,7 @@
</xsl:for-each>
</xsl:if>
<xsl:if test="/uddf/gasdefinitions != ''">
<xsl:if test="/uddf/gasdefinitions != '' and $tankdata = 0">
<xsl:for-each select="/uddf/gasdefinitions/mix">
<cylinder description="unknown">
<xsl:attribute name="o2">
@ -455,106 +458,108 @@
</xsl:for-each>
<xsl:for-each select="samples/waypoint|u:samples/u:waypoint|u1:samples/u1:waypoint|samples/d">
<sample>
<xsl:attribute name="time">
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec">
<xsl:value-of select="divetime|u:divetime|u1:divetime|preceding-sibling::t[1]"/>
</xsl:with-param>
</xsl:call-template>
</xsl:attribute>
<xsl:choose>
<xsl:when test="depth != ''">
<xsl:attribute name="depth">
<xsl:value-of select="concat(format-number(depth, '0.00'), ' m')"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="u:depth|u1:depth != ''">
<xsl:attribute name="depth">
<xsl:value-of select="concat(format-number(u:depth|u1:depth, '0.00'), ' m')"/>
</xsl:attribute>
</xsl:when>
<xsl:when test=". != 0">
<xsl:attribute name="depth">
<xsl:value-of select="concat(format-number(., '0.00'), ' m')"/>
</xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:if test="temperature != '' and $temperatureSamples &gt; 0">
<xsl:attribute name="temp">
<xsl:value-of select="concat(format-number(temperature - 273.15, '0.0'), ' C')"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="u:temperature|u1:temperature != '' and $temperatureSamples &gt; 0">
<xsl:attribute name="temp">
<xsl:value-of select="concat(format-number(u:temperature|u1:temperature - 273.15, '0.0'), ' C')"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="tankpressure|u:tankpressure|u1:tankpressure != ''">
<xsl:attribute name="pressure">
<xsl:value-of select="concat(format-number(tankpressure|u:tankpressure|u1:tankpressure div 100000, '0.0'), ' bar')"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="otu|u:otu|u1:otu &gt; 0">
<xsl:attribute name="otu">
<xsl:value-of select="otu|u:otu|u1:otu"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="cns|u:cns|u1:cns &gt; 0">
<xsl:attribute name="cns">
<xsl:value-of select="cns|u:cns|u1:cns"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="setpo2|u:setpo2|u1:setpo2 != ''">
<xsl:attribute name="po2">
<xsl:call-template name="convertPascal">
<xsl:with-param name="value">
<xsl:value-of select="setpo2|u:setpo2|u1:setpo2"/>
</xsl:with-param>
</xsl:call-template>
</xsl:attribute>
</xsl:if>
<xsl:if test="nodecotime|u:nodecotime|u1:nodecotime &gt; 0">
<xsl:attribute name="ndl">
<xsl:if test="./depth|./u:depth|./u1:depth != ''">
<sample>
<xsl:attribute name="time">
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec">
<xsl:value-of select="nodecotime|u:nodecotime|u1:nodecotime"/>
<xsl:value-of select="divetime|u:divetime|u1:divetime|preceding-sibling::t[1]"/>
</xsl:with-param>
</xsl:call-template>
</xsl:attribute>
</xsl:if>
<xsl:if test="decostop|u:decostop|u1:decostop">
<xsl:attribute name="stoptime">
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec">
<xsl:value-of select="decostop/@duration|u:decostop/@duration|u1:decostop/@duration"/>
</xsl:with-param>
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="stopdepth">
<xsl:value-of select="decostop/@decodepth|u:decostop/@decodepth|u1:decostop/@decodepth"/>
</xsl:attribute>
<xsl:attribute name="in_deco">
<xsl:choose>
<xsl:when test="decostop/@kind|u:decostop/@kind|u1:decostop/@kind != 'mandatory'">
<xsl:value-of select="0"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:if>
</sample>
<xsl:choose>
<xsl:when test="depth != ''">
<xsl:attribute name="depth">
<xsl:value-of select="concat(format-number(depth, '0.00'), ' m')"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="u:depth|u1:depth != ''">
<xsl:attribute name="depth">
<xsl:value-of select="concat(format-number(u:depth|u1:depth, '0.00'), ' m')"/>
</xsl:attribute>
</xsl:when>
<xsl:when test=". != 0">
<xsl:attribute name="depth">
<xsl:value-of select="concat(format-number(., '0.00'), ' m')"/>
</xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:if test="temperature != '' and $temperatureSamples &gt; 0">
<xsl:attribute name="temp">
<xsl:value-of select="concat(format-number(temperature - 273.15, '0.0'), ' C')"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="u:temperature|u1:temperature != '' and $temperatureSamples &gt; 0">
<xsl:attribute name="temp">
<xsl:value-of select="concat(format-number(u:temperature|u1:temperature - 273.15, '0.0'), ' C')"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="tankpressure|u:tankpressure|u1:tankpressure != ''">
<xsl:attribute name="pressure">
<xsl:value-of select="concat(format-number(tankpressure|u:tankpressure|u1:tankpressure div 100000, '0.0'), ' bar')"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="otu|u:otu|u1:otu &gt; 0">
<xsl:attribute name="otu">
<xsl:value-of select="otu|u:otu|u1:otu"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="cns|u:cns|u1:cns &gt; 0">
<xsl:attribute name="cns">
<xsl:value-of select="cns|u:cns|u1:cns"/>
</xsl:attribute>
</xsl:if>
<xsl:if test="setpo2|u:setpo2|u1:setpo2 != ''">
<xsl:attribute name="po2">
<xsl:call-template name="convertPascal">
<xsl:with-param name="value">
<xsl:value-of select="setpo2|u:setpo2|u1:setpo2"/>
</xsl:with-param>
</xsl:call-template>
</xsl:attribute>
</xsl:if>
<xsl:if test="nodecotime|u:nodecotime|u1:nodecotime &gt; 0">
<xsl:attribute name="ndl">
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec">
<xsl:value-of select="nodecotime|u:nodecotime|u1:nodecotime"/>
</xsl:with-param>
</xsl:call-template>
</xsl:attribute>
</xsl:if>
<xsl:if test="decostop|u:decostop|u1:decostop">
<xsl:attribute name="stoptime">
<xsl:call-template name="timeConvert">
<xsl:with-param name="timeSec">
<xsl:value-of select="decostop/@duration|u:decostop/@duration|u1:decostop/@duration"/>
</xsl:with-param>
</xsl:call-template>
</xsl:attribute>
<xsl:attribute name="stopdepth">
<xsl:value-of select="decostop/@decodepth|u:decostop/@decodepth|u1:decostop/@decodepth"/>
</xsl:attribute>
<xsl:attribute name="in_deco">
<xsl:choose>
<xsl:when test="decostop/@kind|u:decostop/@kind|u1:decostop/@kind != 'mandatory'">
<xsl:value-of select="0"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="1"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:if>
</sample>
</xsl:if>
</xsl:for-each>
</divecomputer>
</dive>

View File

@ -17,6 +17,8 @@
<xsl:apply-templates select="dive|trip/dive"/>
</xsl:template>
<xsl:template match="divesites/site/notes"/>
<xsl:template match="dive">
<xsl:text>&quot;</xsl:text>
<xsl:value-of select="@number"/>