Commit graph

1169 commits

Author SHA1 Message Date
Berthold Stoeger
f67f07223f Filter widget: remove superfluous space in label
The "Rating label" had a superfluous space at the beginning.
Remove.

Reported-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-19 13:59:24 -08:00
Berthold Stoeger
424f1e98af Filter widget: make Ui class subobject of widget
Commit 8e81d3f100 changed a bunch
of Ui classes to be subobject of the widget. For consistency do
the same with the filter widget.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-19 13:59:24 -08:00
Berthold Stoeger
ed09e6a909 Desktop: Make filterWidget2 a subobject of MainWindow
In commit b0556abdd35f96b816ba11e40bf5707abe0c3ebf, the filter-widget
and the filter were connected by a direct function call. This led
to a rather obscure crash on application-close with Qt 5.12. The
crash is due to the Ui::MainWindow class being a sub-object of MainWindow,
but the FilterWidget2 being *not* a subobject.

What happens is that after calling the MainWindow destructor, the
subobjects are destructed, notably the Ui class. Then the base-class
destructor is called (which makes sense, as destructors are called
in reverse order of constructors).

But: the QObject destructor calls hide() on all still existing child-objects
according to Qt's object hierarchy, notably the visible FilterWidget2.

Now the FilterWidget2, on hiding, updates the MainWindow, which has already
destructed all its subobjects. Crash.

Prevent this crash by making FilterWidget2 a subobject of MainWindow
and thus have it destructed before running the QObject destructor.

Alternative ways would be:
1) Use signal/slot() instead of function calls, as these are automatically
   removed if an object is destroyed.
2) Make the FilterWidget2 subobject a smart-pointer. Thus, we probably
   wouldn't have to include the corresponding header.
3) Make the FilterWidget2 subobject a plain pointer and delete it
   explicitly in the constructor.

Reported-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-19 13:59:24 -08:00
Berthold Stoeger
36fa27050c Filter: update filterData directly without copying
In FilterWidget2::updateFilter() a new FilterData object is generated
and then copied onto the filterData member variable. Instead, modify
filterData directly. This seems also more logical from a semantic
point of view: Do we want to reset fields that were not set by the
user?

Contains trivial whitespace fix.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-19 13:59:24 -08:00
Berthold Stoeger
cc0c4ab2f1 Filter: connect widget and filter
In the latest version of the new filter-widget the connection
between widget and filter was lost. Connect both - but use a
simple function call instead of a signal, since it is not
immediately obivous where the connection should be made.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-19 13:59:24 -08:00
Berthold Stoeger
891fcbf520 Import: control process_imported_dives() by flags
process_imported_dives() takes four boolean parameters. Replace these
by flags. This makes the function calls much more descriptive. Morover,
it becomes easier to add or remove flags.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-19 13:48:17 -08:00
Berthold Stoeger
ff9506b21b Import: don't add to new trip while downloading
Since process_imported_dives() can add dives to a newly generated
trip, this need not be done in the downloading code. This makes
data flow distinctly simpler, as no trip table and no add-new-trip
flag has to be passed down to the libdivecomputer glue code.

Moreover, since now the trip creation is done at the import step
rather than the download step, the latest status of the "add to
new trip" checkbox will be considered.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-19 13:48:17 -08:00
Berthold Stoeger
1cd0863cca Import: add add_to_new_trip flag to process_imported_dives()
If this flag is set, dives that are not assigned to a trip will
be assigned to a new trip. This flag is set if the user checked
"add to new trip" in the download dialog of the desktop version.

Currently this is a no-op as the dives will already have been
added to a new trip by the downloading code. This will be removed
in a subsequent commit.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-19 13:48:17 -08:00
Berthold Stoeger
31eb86c733 Dive import: fix logic of process_imported_dives()
The logic in process_imported_dives() was faulty: Dives are merged
trip-wise in a loop. But if only autogenerated trips were supposed
to be merged, the trip would not be added.

Change the logic to always add the trip if it is not merged. To make
the loop easier to read, factor out the merge-trip-into-existing-trips
logic into a separate function.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-19 13:48:17 -08:00
Robert C. Helling
2c794348c1 Planner: Add checkbox to force OC bailout
This adds a checkbox for rebreather modes of the planner
that force the ascent to be in OC mode. Before, one had
to add a one minute last segment with the mode change but
this is not practical when manually searching for the
maximal bottom time given gas reserves.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2019-01-13 15:02:07 -08:00
Berthold Stoeger
7f2c7aa7de Download: don't refresh display if thread finished
After the downloading finished, the mainwindow-display is reset
via a signal. This is probably an artifact of old times, when
downloading was done into the main dive-list. Nowadays, this seems
to make little sense, as the main dive-list is not changed by download.

Remove the signal.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-13 15:01:42 -08:00
Berthold Stoeger
ea40370389 Cleanup: remove explicit constructor of DiveListBase
DiveListBase had an explicit constructor that initialized the
"firstExecution" member variable. The latter was a development-
artifact that was never used. Remove the member and the constructor.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
82c47bdd79 Undo: make dive-import undoable
On desktop, replace all add_imported_dives() calls by a new undo-command.
This was rather straight forward, as all the preparation work was done
in previous commits.

By using an undo-command, a full UI-reset can be avoided, making the UI
react smoother.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
0249e12589 Import: split process_imported_dives() function
Split the process_imported_dives() function in two:
1) process_imported_dives() processes the dives and generates
   a list of dives and trips to be added and removed.
2) add_imported_dives() calls process_imported_dives() and
   does the actual removal / addition of dives and trips.

The goal is to split preparation and actual work, to
make dive import undo-able.

The code adds extra checks to never merge into the same
dive twice, as this would lead to a double-free() bug.
This should in principle never happen, as dives that
compare equal according to is_same_dive() are merged
in the imported-dives list, but perhaps in some pathologival
corner-cases is_same_dive() turns out to be non-transitive.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
0dfc59f38c Import: add merge_all_trips parameter to process_imported_dives()
When importing log-files we generally want to merge trips. But
when downloading and the user chose "generate new trip", that
new trip should not be merged into existing trips.

Therefore, add a "merge_all_trips" parameter to process_imported_dives().
If false only autogenerated trips [via autogroup] will be merged.
In the future we might want to let the user choose if trips
should be merged when importing log-files.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
1593f2ebad Import: merge dives trip-wise
The old way of merging log-files was not well defined: Trips
were recognized as the same if and only if the first dives
started at the same instant. Later dives did not matter.

Change this to merge dives if they are overlapping.
Moreover, on parsing and download generate trips in a separate
trip-table.

This will be fundamental for undo of dive-import: Firstly, we
don't want to mix trips of imported and not-yet imported dives.
Secondly, by merging trip-wise, we can autogroup the dives
in the import-data to trips and merge these at once. This will
simplify the code to decide to which trip dives should be
autogrouped.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
f542dc4030 Import: add trip_table argument to DiveImportedModel::repopulate()
In the future we want to download trips into a distinct trip-table
instead of the global trip-table to allow for undo of import.

Therefore add a trip_table argument to DiveImportedModel::repopulate()
and a trip_table member to DiveImportedModel. To correctly set these,
add a DownloadThread::trips() function, which currently simply returns
the global trip table.

Finally, make "struct trip_table *" a Q_METATYPE, so that the corresponding
arguments can be passed from QML.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
7e33369dc8 Parser: add trip_table parameter to parsing functions
To allow parsing into arbitrary trip_tables, add the corresponding
parameter to the parsing functions and the parser state. Currently,
all callers pass the global trip_table so there should be no change
in functionality. These arguments will be replaced in subsequent commits.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
ec37c71f5e Core: add trip_table parameter to trip-functions
Currently trips are added to the global trip table. If we want to
make dive-import undoable, we should be able to parse trips of a
log-file into a distinct table. Therefore, add a trip_table
parameter to
	- insert_trip()
	- create_and_hookup_trip_from_dive()
	- autogroup_dives()
	- unregister_trip()
	- remove_dive_from_trip()

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
7df8d8c888 Undo commands: refactor dive-trip handling
Trips were added to the core with the first dive of that trip.
With the recent changes that keep trips ordered by first dive,
this became counter-productive. Keeping a consistent state at
all times would mean resorting the trip table for every dive
that is added.

Instead, add all dives to a trip and *then* add the trip to the
core. Change the data-structures to not register trips-to-be-added
with individual dives, but keep them in a separate vector for
each undo command.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
517fb7a462 Core: keep trips in table(s)
Currently, all trips are kept in a linked list. Replace the list
by a table in analogy to dive_table. Use this to keep the trip_table
sorted as suggested by dump_trip_list(). When inserting a trip into
the table do that after adding the dives, to avoid warnings coming
out of dump_trip_list().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
d1971a64f9 Core: Rename functions to more generic names
Rename
 - dive_get_insertion_index() -> dive_table_get_insertion_index()
 - unregister_dive_from_table() -> remove_from_dive_table()
 - get_idx_in_table() -> get_idx_in_dive_table()
 - sort_table() -> sort_dive_table()
This will make it more straight-forward to generate these functions
from macros.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
825fcc8547 Dive list: add table parameter to autogroup_dives()
Currently autogroup_dives() groups all dives in the global dive
list. Add a table parameter so that dives in any table can be
grouped. Thus it will be possible to pre-group dives on import,
which will be used for undo of import.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Berthold Stoeger
f8327ed51b Core: move autogroup() into divelist.c
After loading or importing, the caller usually called autogroup()
to autogroup dives if so wished by the user. This has already led
to bugs, when autogroup() was forgotten.

Instead, call autogroup() directly in the process_loaded_dives()
and process_imported_dives() functions. Not only does this prevent
forgetting the call - it also means that autogrouping can be
changed without changing every caller.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-09 20:58:04 -08:00
Robert C. Helling
123f3ef7ec Filter for logged/planned dives
Add filter for dives having a planned dive computer or
a logged dive computer.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2019-01-08 10:39:06 +01:00
Robert C. Helling
c349692d98 Helper function to determined planned dives
... to reduce code duplication.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2019-01-08 10:39:06 +01:00
Berthold Stoeger
f1fc89b978 Dive list: split DiveTripModel into distinct models (tree and list)
The DiveTripModel was used to represent both, trip and list views.
Thus many functions had conditionals checking for the current mode
and both modes had to be represented by the same data structure.

Instead, split the model in two and derive them from a base class,
which implements common functions and defines an interface.

The model can be switched by a call to resetModel(), which invalidates
any pointer obtained by instance(). This is quite surprising
behavior. To handle it, straighten out the control flow:

DiveListView --> MultiFilterSortModel --> DiveTripModelBase

Before, DiveListView accessed DiveTripModelBase directly.

A goal of this commit is to enable usage of the same model by mobile
and desktop.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2019-01-07 09:33:52 -08:00
Lubomir I. Ivanov
0903bef9db update year to 2019 in about screens
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
2019-01-02 09:45:01 -08:00
Lubomir I. Ivanov
85fe844af4 desktop/preferences: rename the default file group
The original name was just "Dives" which is not
descriptive enough. Use "Default file".

Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
2019-01-02 09:43:34 -08:00
Dirk Hohndel
eea0cdee65 Desktop: change preferences dialog name to 'Preferences'
Fixes #1912

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-12-31 09:53:21 -08:00
Berthold Stoeger
99d29a7838 Cleanup: remove unused parameter was_autogen
In commit 6bf4120dbb the trip-flags
were replaced by a simple boolean. This made the was_autogen
parameter to the remove_dive_from_trip() and unregister_dive_from_trip()
functions unused. Remove these parameters.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-12-23 20:00:45 +01:00
John Plaxco
5c0497e14b Fix error message capitalization for web services.
Capitalize the first letter of error message sentences in this
file to be consistent with other error messages in this file
and across the project.

[Dirk Hohndel: edit to remove the changes to the .ts files]

Signed-off-by: John Plaxco <john@johnplaxco.com>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-12-23 10:55:46 -08:00
John Plaxco
53e31c48ee Improve error reporting when exporting a selection of 0 dives.
If no dives are selected when trying to export a selection, a message
is shown that no dives were selected, but it's immediately hidden
behind a message saying that a temporary file could not be created.
In fact, the creation of the temporary file wasn't never attempted,
so the message that the user actually sees is misleading.

The solution chosen here is to duplicate the check that at least some
dives are selected, and abort early if that case is detected, rather
than continuing on to show the additional misleading message. Not
elegant, but it gets the job done.

Better solutions to this include refactoring prepare_dives_for_divelogs
to return something more descriptive than a bool, remove that check
from prepare_dives_for_divelogs entirely since it doesn't seem to be
a good fit there, or switch to exceptions for handling these problems
rather than return values. I don't have sufficient familiarity with
the codebase to attempt these more invasive changes, but they
should be considered in the future.

On a final note, some of the other error messages in this file start
with a capital letter, but the one relevant to this particular PR
does not. Again, I'm not familiar enough with the codebase (or
translations) to know if that's safe to change, so I'll leave that
for another time or another developer.

Reported-by: John Plaxco
Signed-off-by: John Plaxco <john@johnplaxco.com>
2018-12-23 04:55:28 +01:00
Jan Mulder
73213d3c79 core: shift dive time in correct direction
Unsure where this bug got introduced, but when asking for the dive
time to be shifted 1 hour later, the divelist and the dive details
showed 1 our earlier.

Fixes: #1893

Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-12-21 08:08:02 +01:00
Berthold Stoeger
bfe69239df Import: unglobalize downloadTable
To make data flow more clear, unglobalize the downloadTable object.
Make it a subobject of DownloadThread. The difficult part was making
this compatible with QML, because somehow the pointer to the
download-table has to be passed to the DiveImportedModel. Desktop would
simply pass it to the constructor. But with objects generated in QML
this is not possible. Instead, pass the table in the repopulate()
function. This seems to make sense, but for this to work, we have to
declare pointer-to-dive-table as a Q_METATYPE. And this only works
if we use a typedef, because MOC removes the "struct" from "struct
dive_table". This leads to compilation errors, because dive_table is
the symbol-name of the global dive table! Sigh.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-12-17 07:37:32 -08:00
Berthold Stoeger
6febe22b6b Cleanup: remove DiveImportedModel::setImportedDivesIndexes()
This function resets the DiveImportedModel. It takes two
arguments: first and last index. All callers passed in 0
and number-of dives anyway, so remove the arguments.
Since this now does the same as repopulate(), merge the
two functions.

Moreover, implement Qt-model semantics by using a
beginResetModel()/endResetModel() pair. This simplifies the
code.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-12-17 07:37:32 -08:00
Robert C. Helling
f0164e97a2 Show average max depth in statistics tab
This makes more sense than average depth. The min entry is also
about max depth for a dive.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2018-12-17 12:18:26 +01:00
Tomaz Canabrava
705e61b62c Hide unimplemented components from search
Those fields are not ready yet, hide them.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
2018-12-14 01:05:18 +08:00
Tomaz Canabrava
e0f473fcb4 Drop old filter code
Drop tons of now-unused-code.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
2018-12-14 01:05:18 +08:00
Tomaz Canabrava
43178be1f2 Handle Show / Close of the Filter Box
when you close, remove filter. when you open again, restore.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
2018-12-14 01:05:18 +08:00
Tomaz Canabrava
81bb6086c0 Struct FilterData
The idea is that this struct will have all the needed data
that will be passed to the filter model. Everything that happens
on the filterwidget will fill out this struct, then forward it
to the model, that in turn will activate the filter hiding
some of the dives that matches on your divelist.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
2018-12-14 01:05:18 +08:00
Tomaz Canabrava
89413c5f07 Replace the old filter widget for a new one
Wires the code to display the filter widget on the mainwindow.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
2018-12-14 01:05:18 +08:00
Tomaz Canabrava
8378695d7f Start the FilterDive state
Register the new FilterDive widget on the mainwindow
so we can trigger a shortcut to display it.
The shortcut currently doesn't exists.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
2018-12-14 01:05:18 +08:00
Tomaz Canabrava
19f6e8810c Start to implement a simplified version of the filter widget
The idea of this new widget is to be able to filter more
types of data, while keeping it simple and extending the
feature set to something that was impossible with the old
implementation.

While the old implementation had 4 panels that you could
use to filter specific tags / people / types of dives
the new one will let you filter by visibility, temperature
people, name, equipment, etc, in a more natural way
than the old one.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
2018-12-14 01:05:18 +08:00
Berthold Stoeger
662dd823fd Cleanup: remove split_dive_*() functions
In 302f6adb79 dive-splitting was made
undo-able. To this goal, the dive-splitting functions were split in
two types: Those that operate directly on the divelist and those that
only allocate the dives. The former are not in use anymore, therefore
remove them. Since only the latter remain, remove the "_dont_insert"
appendix of the name.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-12-14 00:25:07 +08:00
Berthold Stoeger
0a3d757aab Cleanup: remove combine_trips() function
In f427226b3b a combine_trips_create()
function was introduced that combined trips without deleting the old
trips. This was necessary for making combine-trips function undo-able.

The old combine_trips() function is not used anymore. Therefore remove
it. Rename the combine_trips_create() function to combine_trips() as
no differentiation is needed anymore.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-12-14 00:25:07 +08:00
Berthold Stoeger
2706fa7b8e Dive list: remove trip from model only once
In moveDivesBetweenTrips() a the model is informed of dives
that are moved between trips. A flag tells the model to delete
empty trips. If dives were removed in batches [use case: split
a big trip into multiple smaller trips] the flag would be sent
for every batch. This was handled gracefully by the model code,
but it gave a warning message.

Set the flag only for the last batch, when the trip is *really*
empty.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-12-14 00:09:05 +08:00
Berthold Stoeger
3cdc2661d2 Dive media: add media to closest dive
Currently, when selecting "Load media files even if time does not
match the dive time", the media are added to *all* selected dives.
Instead add it to the closest dive.

This seems like the less surprising behavior. Of course now if the
user really wants to add a media file to multiple dives, they will
have to do it manually.

To avoid a messy interface, this is solved by moving the iterate-
over-selected-dives loop to the core. Thus, a helper-function can
be made local to its translation unit.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-12-13 08:11:22 +01:00
Berthold Stoeger
779e33be5d Cleanup: don't leak filename on picture creation
dive_create_picture() is called from DiveListView::matchImagesToDives()
with a copy of the picture-filename. But:
  - On error the filename is not freed
  - On success the filename is strdup()ed
Thus, in all cases the memory is lost. Instead, pass in a temporary
buffer using qPrintable().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-12-11 23:59:30 +02:00
Robert C. Helling
b75081cc59 Invalidate git cache when removing dive from trip
... otherwise this change is not saved when saving to git.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-12-11 09:26:18 +01:00
Berthold Stoeger
9e565e3552 Cleanup: make "struct dive *" and "struct dive_trip *" Qt metatypes
Just as we did for pointer to struct dive_site, make pointers to
struct dive and struct dive_trip "Qt metatypes". This means that
they can be passed through QVariants without taking a detour via
void *.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-23 13:22:24 -08:00
Berthold Stoeger
5d8830750a Desktop: don't refresh display on autogroup
The whole point of the undo-command system is that the divelist
doesn't have to be refreshed. Therefore, don't do it for autogrouping
/ deautogrouping.

Moreover, the divelist-changed flag is also set by the command and
doesn't have to be set explicitly.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-21 10:29:15 -08:00
Berthold Stoeger
2cd7b9db25 Warnings: replace memcpy by assignment
New gcc (v8.2) complains about memcpy()ing an object with non-POD
members. Even though this seems not to be an issue for template_options,
the warning has some merrit. The compiler will recognize when to do
a memcpy() anyway. Moreover, the assignment is easier to read and also
more secure, as a-priory we can't know if Qt's QColor copy-constructor
does some strange things (hopefully not).

Thus, replace memcpy() by simple assignment.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-19 13:51:03 -08:00
Berthold Stoeger
64e6e435f8 Core: remove "when" field of struct dive_trip
The when field gives the time of the first dive. Instead of keeping
this field in sync, replace it by a function that determines the time
of the first dive.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-18 16:50:09 -08:00
Berthold Stoeger
ef98a4ff5a Dive list: keep dives-in-trip list ordered after shift-times
On shift-times, the list of dives in a trip may become disordered.
Reestablish order with sort_table().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-18 16:50:09 -08:00
Berthold Stoeger
6b283e598a Dive list: replace dive-list of trips by a table
The dives of each trip were kept in a list. Replace this by a
struct dive_table. This will make it significantly easier to
keep the dives of a trip in sorted state.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-18 16:50:09 -08:00
Berthold Stoeger
bc7afebc23 Core: add add_dive_to_table() function
Up to now, dives were added to the global dive table with
add_single_dive(). Split out the funtionality to add a dive to
an arbitrary dive in the add_dive_to_table_function(). The
difference compared to record_dive_to_table is that dives
are added at a specific position or the sort-criterion given
by dive_less_than(). This will allow to use a dive tabe for trips
instead of a linked list.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-18 16:50:09 -08:00
Berthold Stoeger
0618aa737f Core: unify insert_trip() and insert_trip_dont_merge()
There were two versions of the insert_trip() function: one
would merge trips if a trip with the same date already existed,
the other wouldn't. The latter was introduced with the dive-list
undo work.

The problem is that the "date" of a trip (i.e. the first dive)
seems ill-defined as this is a volatile value. Moreover in
the context of making dive-import undoable this is a very
dangerous notion, as the caller needs control over when the dives
are added to a trip.

Therefore, unify these two functions and never merge trips.
The decision on merging dives now has to made by the caller.
This will be implemented in a future commit.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-18 16:50:09 -08:00
Berthold Stoeger
7046c8b342 Dive list: invert sort-direction to reflect core
Traditionally, the DiveTripModel has its data sorted in opposite
direction to the core-data (chronologically descending vs. ascending).
This bring a number of subtle problems. For example, when filling
the model, trips are filled according to the *last* dive, whereas
later insertion points are according to the ->when value from the
core, which depends on the *first* dive.

As a start of fixing these subtleties, change the sort direction
to reflect the core-data. Ideally, this should lead to a removal
of the redundant data-representation.

Since the model is now sorted in ascending order, sorting has to
be enabled in the DiveListView constructor to reflect the
default-descending order.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-16 16:57:14 -08:00
Berthold Stoeger
da3ea59a25 Dive list: let sort arrows reflect sort order for NR and DATE
The old code always sorted by "ascending" by default. But
because users typically want their new dives top, "ascending"
was defined for NR and DATE, such that it is actually descending.
Turn these around and intitialize these two fields as
default-descending.

This is possible using the Qt::InitialSortOrderRole role
in DiveTripModel::headerData().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-05 07:55:53 -08:00
Berthold Stoeger
64a1a50e10 Dive list: remove sortColumn and currentOrder members
Since the QHeaderView of DiveListView is now the authority
over sort-column and sort-order, it makes little sense
to keep these as member variables. That would only risk
inconsistencies. Remove them and query the QHeaderView
instead.

We still need to keep track of currentLayout, as we
have to detect if it changes to change the underlying
model from tree to list or vice-versa.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-05 07:55:53 -08:00
Berthold Stoeger
f2f18b4e16 Dive list: split reload() in reload() and setSortOrder()
The DiveListView code had a very fundamental problem with its
header: Each had its own idea of who is responsible for sorting.
Since we can't easily change QHeaderView, accept QHeaderView
as the authority on sort-column and order.

To make this possible, split the reload() function in two
distinct functions:
 - reload() reloads the model and sorts according to the
   current sort criterion.
 - setSortOrder() tells the header to display a certain
   sort criterion. If this is a new criterion, it will then
   emit a signal. In this signal, resort according to that
   criterion.

Thus, the actual sorting code has to be moved from the
headerClicked() to a new sortIndicatorChanged() slot.
Morover, the sorting of the QHeaderView has to be used.

Reported-by: Stefan Fuchs <sfuchs@gmx.de>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-05 07:55:53 -08:00
Berthold Stoeger
76f38ff33b Dive list: invert default sort order for sort by date / number
Commit 6dc1d239f8 introduced a
well-defined sort order in the case of equal contents. It changed
the code for sorting by date to simply use the order of the
source model.

BUT: The source-model was already sorted in descending order
on date. Thus setting the default order on descening by date,
the data was then presented as *ascending* by date.

Change this back to descending by always using default-ascending
in the filter model.

Ultimately, the source model should simply reflect the ordering
of the core-data (ascending on date), but such a change is
too invasive shortly before release.

Reported-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-02 07:46:01 -07:00
Berthold Stoeger
6fb3a499e6 Dive list: remove forceSort parameter from DiveListView::reload()
DiveListView::reload() was called for full reset of the dive list
and for changing the view (tree vs. lis) in DiveListView::headerClicked().
Since the latter does sorting by itself, a parameter "forceSort" was
introduced, which defaulted to true, but was set to false by
DiveListView::headerClicked().

To remove complexity, simply let DiveListView::headerClicked() set
the view by itself and remove tha parameter.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-01 07:28:15 -07:00
Berthold Stoeger
ade0d8e758 Dive list: connect header-signal in constructor
The QHeaderView::sectionPressed() signal was connected everytime
the list-view was reset. Likewise, setSectionsClickable() was
set to true everythime the list-view was reset.

Once in the constructor is enough.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-01 07:28:15 -07:00
Berthold Stoeger
803111ef02 Dive list: make filter model aware of its source
The data-flow from C-core to list-view is as follows:

C-core --> DiveTripModel --> MultiSortFilterModel --> DiveListView

The control-flow, on the other hand, differs as DiveListView
accesses both MultiSortFilterModel and DiveTripModel, whereas
MultiSortFilterModel is mostly unaware of its source model.

This is in principle legitimate, as the MultiSortFilterModel might
be used for different sources. In our particular case, this is
not so. MultiSortFilterModel is written for a particular use case.

Therefore, model control-flow follow after data-flow: Let MultiSortFilterModel
set its own source model and DiveListView access the MultiSortFilterModel,
which then manages its source model.

This is not bike-shedding, but will enable a more flexible and
higher-performance sorting.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-11-01 07:28:15 -07:00
Jan Mulder
68d7e7c4e3 Desktop: do not crash in verbose mode on empty dive site
Import dives from a DC, and have ssrf started in verbose mode. After
downloading dives, hit ok, to add them to the dive list. This crashes
as we cannot get the uuid from the null dive site.

Added a simple guard to fix this.

Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-10-31 14:51:31 +00:00
Berthold Stoeger
dec9401f48 Dive site: fix oversight in 920eb7576f
In commit 920eb7576f "dive_site *"
was included in Qt's "metatype" system to be able to pass it
through QVariants. One instance was forgotten and a "void *"
was passed in. On readout NULL was returned, which made it
impossible to add new dive-sites under certain circumstances.

Convert this one instance to a proper "dive_site *" QVariant.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-30 22:24:07 +00:00
Berthold Stoeger
920eb7576f Dive site: pass pointer-to-dive_site via QVariant
There was this ugly pattern of passing pointers-to-dive_site via
a QVariant of void * type. This is of course inherently unsafe.

Pass these pointers using their proper types instead. This makes
it necessary to register them in Qt's meta-type system. Doing so,
fixes a bug: QML couldn't call into updateDiveSiteCoordinates()
because it didn't know the type and thus the coordinates of
the moved flag were not reflected in the divesite-dialog.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
724055f0af Dive site: replace dive->dive_site_uuid by dive_site
Replace the UUID reference of struct dive by a pointer to dive_site.
This commit is rather large in lines, but nevertheless quite simple
since most of the UUID->pointer work was done in previous commits.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
acd44467c1 Dive site: remove [start|stop]FilterDiveSite signals
This is another case of a weird pattern where an object would
connect it's own signal to the slot of a different object.
There seems to be no reason why the former couldn't simply
call the latter.

Remove the [start|stop]FilterDiveSite signals of LocationInformationWidget
and call the corresponding functions of MultiFilterSortModel directly.
While doing so, replace the UUID argument by a pointer-to-divesite.
It will be converted anyway right at the beginning of the function.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
872d56de01 Dive site: pass pointer to updateDiveSiteCoordinates()
There are two updateDiveSiteCoordinates() member-functions, viz.
in MapWidget and MapWidgetHelper. Adapt them to take a pointer
to dive_site instead of a UUID. This is part of an effort to
replace UUIDs by pointers.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
cedc23f487 Dive site: Pass dive-site pointer to MapWidgetHelper::enterEditMode()
Replace the uuid argument to MapWidgetHelper::enterEditMode() by a
pointer. Likewise, adapt the only caller prepareForGetDiveCoordinates().
This is a small step in a bigger effort to replace dive-site UUIDs
by pointers.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
b9b1b3146b Dive site: remove UUIDs from LocationInformationModel
Replace UUIDs from LocationInformationModel and fix the fallout.
Notably, replace the UUID "column" by a DIVESITE "column".
Getting pointers through Qt's QVariant is horrible, we'll have
to think about a better solution.

RECENTLY_ADDED_DIVESITE now defines to a special pointer to
struct dive_site (defined as ~0).

This fixes an interesting logic bug:
The old code checked the uuid of the LocationInformationModel (currUuid)
for the value "1", which corresponded to RECENTLY_ADDED_DIVESITE.
If equal, currType would be set to NEW_DIVE_SITE. Later, _currType_
was compared against _RECENTLY_ADDED_DIVESITE_. This would only work
because NEW_DIVE_SITE and RECENTLY_ADDED_DIVESITE both were defined
as 1.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
6f98dca26e Dive site: remove argument from diveSiteSelected signal
The diveSiteSelected signal of DiveLocationLineEdit had the dive-site
UUID as argument. But the receiving slot would not use that argument.
Remove this as a tiny step to remove the UUIDs alltogether.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
ab29f6416b Dive site: replace UUID_ROLE by DIVESITE_ROLE
Access to dive-sites in the LocationInformationModel was via UUID.
Replace this by a direct access to the struct dive_site pointer.
Accordingly, rename the UUID_ROLE to DIVESITE_ROLE.

This is a small step in replacing dive-site UUIDs by pointers
throughout the code base.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
64f0902e0d Dive site: pass dive-site pointers to merge_dive_sites()
Instead of passing uuids, pass a pointer to the dive site.
This is small step in an effort to remove uuids.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
f527a70831 Dive site: pass dive-site pointer to delete_dive_site()
Instead of passing a uuid, pass a pointer to the dive site.
This is small step in an effort to remove uuids.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
8de471f90e Dive site: pass dive-site pointer to is_dive_site_used()
Instead of passing a uuid, pass a pointer to the dive site.
This is small step in an effort to remove uuids.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
14ab95608c Dive site: pass dive-site pointer to nr_of_dives_at_dive_site()
Instead of passing a uuid, pass a pointer to the dive site.
This is small step in an effort to remove uuids.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
d3a7c5448f Dive site: return pointer to dive_site in create_dive_site_*()
This changes more of the dive-site interface to return pointers
instead of UUIDs. Currently, most call sites directly extract
UUIDs afterwards. Ultimately, the UUIDs will be generally replaced
by pointers, which will then simplify these callers.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-29 00:09:31 +00:00
Berthold Stoeger
f8768e40b4 Dive list: remove rememberSelection() without restoreSelection()
Remove three cases of rememberSelection() which did not possess
the corresponding restoreSelection() twins.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-28 15:10:57 +00:00
Berthold Stoeger
323a71941d Dive list: remember/restore selection only on view change
The selection was remembered/restored anytime the sort-order
changed. Yet, this is only necessary if the view (tree, list)
changes. Therefore, handle the selection  only if this is the
case.

This automatically fixes the problem of the trip-selection
not being remembered if the view doesn't change. If the view
does change, trip selection is lost. But since the list view
doesn't have trips to start with, losing trip-selection seems
like an understandable behavior.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-28 15:10:57 +00:00
Berthold Stoeger
139c749c90 Dive list: show sort indicator
On desktop, show the a sort indicator to give a visual feedback on changes
of the sort order. This is trivially done by calling the
setSortIndicatorShown() function in DiveListView's constructor.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-28 15:10:57 +00:00
Berthold Stoeger
f634554d30 Dive list: switch to a default sort order on column-header click
On desktop, clicking on a column header sorts the dive-list. This
has the interesting property that every click reverses the sort
order (unless changing from list to tree-mode). The much more
common idiom seems to be to define a default sort order for each
column and switch to that when changing sort-column. Switch order
after clicking the same column again.

Implement this more common behavior. For now, sort # and date
in descending, all other columns in ascending order.

While doing this, use the proper enum (NR) for setting the default
sort-column instead of its integer representation (0).

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-28 15:10:57 +00:00
Berthold Stoeger
d9588ec5df Cleanup: remove declaration of unused signal
The last use of the LocationInformation::startEditDiveSite()
signal was removed in ff26ffe0d0.
Remove its declaration.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-26 18:48:27 +01:00
Berthold Stoeger
583d8d653a Dive list: emit selectionChanged signal in filterFinished()
In commit 9829e49815 the dive
selection code was moved from the filter to the dive list.
As a consequence of that change, the selectionChanged signal
was not emitted anymore and therefore the map widget was not
informed of the new dive site list. This had funky effects on
the dive-site editing. Notably, changing the location would
move the map, but not update the flag.

Explicitly emit selectionChanged in filterFinished() to fix
dive site editing.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-25 23:24:06 +01:00
Simeon
8cf8d490d6 Fix bug in for loop that can lead to segfault
In case of big log files, where MAX_TANK_INFO is reached, tank_info[i]  != NULL should be checked after i<MAX_TANK_INFO

Signed-off-by: Simeon Geiger <simeon.geiger@gmail.com>
2018-10-25 23:23:03 +01:00
Miika Turkia
bb4c2031ef Show coordinates if no tags from reverse geolookup
This will display the dive site coordinates after the Location label if
there are no associated tags from reverse geolookup. Thus it'll be
clearer for users that we do have GPS location stored for the dive, and
might be able to see more easily if the recorded coordinates are
correct.

Signed-off-by: Miika Turkia <miika.turkia@gmail.com>
2018-10-24 08:04:20 +01:00
Berthold Stoeger
ca211c03e0 Dive site: remove webservice code in MainTab::updateDiveSite()
There was still code in MainTab::updateDiveSite() related to
dive-sites obtained from the obsolete web-service. Remove.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-23 22:07:42 +01:00
Berthold Stoeger
6ed5db4d51 Dive list: remove three unnecessary instances of qobject_cast<>.
In DiveListView, the result of model() was dynamically cast to
QSortFilterProxyModel. But then, only the virtual match() function
was used. The whole point of virtual functions is that you can
cast them on the base-class and it will execute the function of
the derived class. Thus, remove these casts and operate directly
on the QAbstractItemModel base class.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-21 19:57:49 +03:00
Berthold Stoeger
9829e49815 Dive list: move dive-selection code from filter to list
After invalidating the filter, the dive-selection was modified to
ensure that at least one dive is selected. This was done in the
filter code, but it seems preferrable to do this in the dive-list
code, which has direct access to the selection-model.

Therefore, move the code from MultiFilterSortModel to DiveListView.
While doing so, split the code in DiveListView into more functions to:
1) Get the index of the first dive (if any).
2) Select the first dive (if any).

This allows a distinct size reduction of conditional compilation
in MultiFilterSortModel (accesses to MainWindow are not possible
in mobile code).

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-21 19:57:49 +03:00
Linus Torvalds
28e3413ff6 Add 'location_t' data structure
Instead of having people treat latitude and longitude as separate
things, just add a 'location_t' data structure that contains both.

Almost all cases want to always act on them together.

This is really just prep-work for adding a few more locations that we
track: I want to add a entry/exit location to each dive (independent of
the dive site) because of how the Garmin Descent gives us the
information (and hopefully, some day, other dive computers too).

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2018-10-21 19:55:09 +03:00
Jan Mulder
cc225a44f2 Preferences: set deco parameters correctly enabled
And fix another bug in this area of the code. It appeared that
the gflow/gfhigh and conservatism deco parameters where not
enabled at startup, but after toggling the VPM vs BUEHLMANN setting
they were.

So, fix this as well.

Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-10-19 06:25:32 -04:00
Jan Mulder
66c4397efd Preferences: wire-up the deco parameters
The deco parameters need special treatment to wire them up to the
underlying deco model code. And with the new preferences setup this
is a lot of boilerplate.

Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-10-19 06:25:32 -04:00
Berthold Stoeger
3c1002d7ef Dowload: Deselect dives only if at least one dive was downloaded
On dive-download old dives are deselected and a new one is selected.
If no dives were downloaded, accordingly no dives were selected.
This deselect only dives if at least one dive was downloaded.

Fixes #1793

Reported-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-15 20:55:58 -04:00
Dirk Hohndel
a20626a874 Bluetooth cleanup: remove pointless download_mode
This was used to track whether we had selected the native BT mode in the
download dialog. But the information is redundant as we can tell from the
device name whether this is a BT/BLE download or not.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-10-15 19:46:18 +02:00
Dirk Hohndel
5b925d29af Desktop/trivial: fix misleading comment
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-10-15 19:46:18 +02:00
Jan Mulder
0f9edf06e2 Desktop: Enable next/prev DCs only for applicable dives
Does not solve any problem, but might help users that are confused
about the next/prev DC menu items, to select a different profile
for the currently selected dive. So, enable these menu items only
for dives where more than one DC is used.

Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-10-14 20:46:02 +02:00
Jan Mulder
ac9bab7e2f Autogroup only when selected
Comits f427226b3b and 43c3885249 of the undo series introduced 2 calls
of autogroup_dives() without checking the autogroup global boolean.
This is a bug. An import from DC (for example) then triggers an
autogrouping, the divelist is autogrouped, and the UI button
is off.

This commit solves this. I've chosen for a guard in the autogroup_dives()
that now is a no-op when called when the user did not select autogrouping.
In additon, simplified the other calls to this function, as we do
not need to check before calling any more.

Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-10-14 09:22:56 +02:00
Berthold Stoeger
068b01aef2 Cleanup: rename MainWindow member variables
Instead of the weirdly named "information" and the inconsistent
"dive_list" use the logical "mainTab" and the camel-cased
"diveList", respectively.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-13 21:42:53 -04:00
Berthold Stoeger
78e2560296 Cleanup: Turn widget accessor-functions into simple pointers
The keeps track of different sub widgets needed by other parts
of the code, notably:
	MainTab
	PlannerDetails
	PlannerSettingsWidget
	ProfileWidget2
	DivePlannerWidget
	DiveListView
Access to these widgets was provided with accessor functions.
Now these functions were very weird: instead of simply returning
pointers that were stored in the class, they accessed a data
structure which describes the different application states.
But this data structure was "duck-typed", so there was an
implicit agreement at which position the pointers to the
widgets were put inside. The widgets were then down-cast by
the accessor functions. This might make sense if the individual
widgets could for some reason be replaced by other widgets
[dynamic plugins?], but even then it would be strange, as one
would expect to get a pointer to some base class.

Therefore, directly store the properly typed pointers to the
widgets and simply remove the accessor functions. Why bother?

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-13 21:42:53 -04:00
Berthold Stoeger
11a211fb02 Dive site: replace displayed_dive_site by pointer
In the dive-site-edit widget, a copy of the current dive site was
used to store the old (pre-edit) data. This is not necessary, since
we can simply access the data in the original dive site. Thus,
replace the subobject by a simple pointer.

This is part of a series to replace dive-site uuids by pointers.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-13 21:41:41 -04:00
Berthold Stoeger
a823974b70 Dive site: don't use displayed_dive_site to store GPS coordinates
The displayed_dive_site object is used in the dive-site-edit widget
to store the old (before-edit) data. But it was also used to store
the GPS data when changed on the map or the input box. Very confusing.
Instead, use the text field as only authoritative source of the
GPS data.

This introduces a small behavioral change: when changing the text
of the GPS text field, update the list of dive sites at the same
position.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-13 21:41:41 -04:00
Berthold Stoeger
8815f77ea0 Dive site: use own copy of taxonomy in dive-site-edit widget
The dive-site-edit widget uses a copy of the to-be-edited site
to compare with old values. Generally, this seems overkill
(the original dive-site can be used for such a comparison).
But one place where it can't simply be removed is the taxonomy,
because the widget needs a place to store the unsaved data.

Change the code to use an explicit taxonomy structure instead
of the one provided in the copy. This should ultimately allow
removal of the latter.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-13 21:41:41 -04:00
Berthold Stoeger
5d3967ce84 Dive site: un-globalize displayed_dive_site
The global object displayed_dive_site is used a a backing-store
by the dive-site-edit widget. All external accesses were removed,
therefore make the object local to the widget.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-13 21:41:41 -04:00
Berthold Stoeger
954820aa81 Dive site: explicitly init displayed_dive_site on show widget
The global object "displayed_dive_site" is used to store the
old dive site data for the edit-dive-site widget. The fields
of the widget were initialized from this object in the show
event. Therefore the object was updated in numerous parts of
the code to make sure that it was up-to-date. Instead, move
the initialization of the object to the function that also
initiatlizes the fields. Call this function explicitly before
showing the widget.

This makes the data-fow distinctly easier to understand.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-13 21:41:41 -04:00
Berthold Stoeger
f0e349cdd6 Cleanup: remove outdated comment
Remove a comment which is outdated in two ways:
1) The global variable "displayed_dive_site" was not used at all.
2) The location box cannot be used to rename dive sites.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-13 21:41:41 -04:00
Berthold Stoeger
ebd6d4fc45 Dive site: use displayed_dive in MainTab::refreshDisplayedDiveSite
MainTab::refreshDisplayedDiveSite() was used after dive-site edit
to update the information of the location entry box. This should
always display the dive-site of the currently shown/edited dive,
therefore it makes no sense to use the displayed_dive_site here.
Simply use the dive site of displayed_dive.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-13 21:41:41 -04:00
Berthold Stoeger
73b8bd12e5 Dive edit: always use dive site of displayed_dive in updateDiveInfo
The old code had a special case for dive-editing mode:
The dive site uuid of displayed_dive_site instead of displayed_dive
was used.

This makes no sense, because displayed_dive_site is only used by
the dive-site-edit widget, which firstly cannot be activated
during dive-edit and secondly doesn't change the dive site id
anyway.

Thus, use the dive site of the currently edited/displayed dive
in all cases.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-13 21:41:41 -04:00
Berthold Stoeger
397e818be1 Desktop: enable tab-changes-focus for TagWidget
When tabbing through the dive-info screen, a dive-master and a
dive-buddy would be added. The reason is that pressing tab would
be interpreted as a text-input. Disable this behavior by calling
setTabChangesFocus(true) in the TagWidget constructor.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-13 10:06:41 +02:00
Dirk Hohndel
8777945d00 Bluetooth: actually download from the device selected
If we update the device with a shortcut button, this is the reliable way to get
the information we need.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-10-12 08:22:44 -07:00
Dirk Hohndel
ef0e76bc69 Bluetooth: show the user that we are waiting to connect to DC
Previously nothing was shown while we were trying to connect; now we show a busy
indication in the progress bar and ensure that the 'waiting to connect' text is
displayed. The progress bar switches back to showing actual progress once we have
connected and are downloading data.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-10-12 08:22:44 -07:00
Dirk Hohndel
9491c96103 Bluetooth: start discovery if address isn't already known
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-10-12 08:22:44 -07:00
Dirk Hohndel
38cda08819 Bluetooth: run a discovery agent for BT/BLE dive computers on macOS
This way the scan time will be shorter (which on macOS can be 25+ seconds).

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-10-12 08:22:44 -07:00
Berthold Stoeger
5d1c30acbf Cleanup: remove unused function MainTab::showLocation()
The last caller was removed way back in 266e754d08.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-12 13:05:35 +02:00
Jan Mulder
1f76460dfa Whitespace only
Separated from the previous commit as I do not like big whitespace
changes in a small functional commit.

Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-10-12 13:03:54 +02:00
Jan Mulder
a47df05ce5 Edit: prevent not needed change marking
While trying to understand more of the big change from PR 1528,
I found that the divelist was marked changed while it was not
changed at all. Reason is simple. The MODIFY_DIVES code assumes
its called only for truly changed data. But in case of saving
tagged strings, it was not.

This fixes this. And I do not believe this has any visual effects.
Further, the now broken indentation is fixed seperately.

Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-10-12 13:03:54 +02:00
Berthold Stoeger
f39596df06 Map: remove access to displayed_dive_site in GPS-filter model
The location information shows a list of dive sites at the
same location as the edited dive site. This was done by passing
a function to an "SsrfSortFilterProxyModel". Unfortunately,
the latter does only support function pointers without state
and therefore had to access the global "displayed_dive_site"
object.

Replace the SsrfSortFilterProxyModel by a proper subclass of
QSortFilterProxyModel that contains information on the position
and id of the currently edited dive site.

Update the filter model if the location of the dive site changes.
This introduces a behavioral change: editing the GPS location
will lead to an updated list.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:25:32 -07:00
Berthold Stoeger
dd44dc4ab8 Map: pass down dive site in prepareForGetDiveCoordinates()
Instead of reading out the global object "displayed_dive_site",
pass the dive site to be edited in arguments to
prepareForGetDiveCoordinates() and enter edit mode.

Simplify the code in LocationInformationWidget by not using
signals to call the prepareForGetDiveCoordinates() function.
While doing this, collect common code in accept() and reject()
in the already existing resetState() function.

This is another entry in a series of commits that makes
data-flow more clear by removing access to the global
"displayed_dive_site" object.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:25:32 -07:00
Berthold Stoeger
8091497745 Map: split void MapWidget::setEditMode()
The setEditMode(bool) function behaves very differently, when
entering and exiting edit mode. Therefore, split it in two
versions. This will allow to pass arguments that make sense
only when entering the edit mode.

Since setEditMode() doesn't exist anymore, turn the editMode
Q_PROPERTY line to the MEMBER version. Accordingly, remove
the reader function. If QML wants to enter edit mode, it
should invoke the appropriate function and not simply set
the flag.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:25:32 -07:00
Berthold Stoeger
754160d625 Map: pass changed coordinates via signal
The coordinates of a "dragged flag" were passed out-of-bound via
the global "displayed_dive_site" object and then a signal was sent
to notify of the changed coordinates.

Instead, pass the coordinates directly via the signal. This makes
the data- and control-flow more clear.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:25:32 -07:00
Berthold Stoeger
66c5c5f72b Map: remove LocationInformationWidget::coordinatesChanged signal
This was used by LocationInformationWidget to instruct the map
that the coordinates of the current dive site has changed.
There is no reason why this couldn't be a function call, as no
other object ever connect()s to this signal. In fact, such a
function already exists viz. updateLocationOnMap.

Therefore, replace the signal by a simple function call.

Moreover, the uuid and coordinates of the dive site were transported
via the global "displayed_dive_site" object. Instead, pass this
information in the parameters of the function. This makes it
easier to reason about data- and control-flow.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:25:32 -07:00
Berthold Stoeger
ad57871a2c Geo lookup: don't pass arguments / result via global object
The reverseGeoLookup() fetches dive-site data via GPS coordinates.
The coordinates and the result were passed via the global
"displayed_dive_site" object. To make data-flow more clear,
pass data as in and out parameters instead.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:25:02 -07:00
Berthold Stoeger
ce8199cdfd Cleanup: remove ReverseGeoLookupThread
Fetching the taxonomy from GPS coordinates was implemented in
a QThread. But the only access to the main function was a
direct call to run(). Thus, the thread was *never* started.
The function call was always asynchronous [it was using an
event loop though, so the UI doesn't hang]. Notably this
means that the signals connected to the thread would never
fire. And the spinner would never be activated.

Thus:
1) Turn the thread into a simple function.
2) Remove the spinner.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:25:02 -07:00
Berthold Stoeger
76e5c5ac67 Dive site: remove access to displayed dive site from LocationFilterDelegate
When editing a dive, in the location box a list of dive sites is
shown containing the distance to the current dive site. This was
implemented via the global displayed_dive_site object, which is
set when switching between dives. This seems like an unnecessary
indirection. Instead, use the current_dive macro.

This is part of a series to refactor dive-site handling to use
pointers instead of UUIDs and a general push to reduce global state.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:25:02 -07:00
Berthold Stoeger
b19adecb9f Undo: make adding of planned dive undo-able
Planned dives were still added by directly calling core code.
This could confuse the undo-machinery, leading to crashes.

Instead, use the proper undo-command. The problem is that as
opposed to the other AddDive-commands, planned dives may
belong to a trip. Thus, the interface to the AddDive command
was changed to respect the divetrip field. Make sure that
the other callers reset that field (actually, it should never
be set). Add a comment describing the perhaps surprising
interface (the passed-in dive, usually displayed dive, is
reset).

Moreover, a dive cloned in the planner is not assigned a
new number. Thus, add an argument to the AddDive-command,
which expresses whether a new number should be generated
for the to-be-added dive.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
7150d1c6f6 Filter: Make filters aware of added / removed dives
Instead of reloading all the filter, only increment / decrement the
count of the entries of added / removed dives.

Originally, this was planned to be done via the signals from the
divelist, but it turned out that this was suboptimal, because
if the filter decides that the new item is selected, this has to
be done *before* adding the dive. Otherwise, it wouldn't be shown.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
11e0b7ac0a Dive commands: set filter flag when adding dives
When adding dives to the list, set the filter flag accordingly.
Thus, dives that are hidden by the filter are not shown on
redo/undo.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
3c6cdfd8c0 Dive list: propagate current-item to frontend
The command-objects select a current item, but this selection
was not propagated to the front-end. The current item is the
base for keyboard-navigation through the dive-list and therefore
should be set correctly.

It took some experimentation to get the flags right:
 QItemSelectionModel::Current
Hopefully, these are the correct flags across all supported
Qt versions!

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
b16be29595 Dive list: expand trips if dives are selected
If dives are deleted, the trip(s) containing the dives are expanded.
Thus, on undo it seems natural to re-expand the trip.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
2a61664ceb Undo: correctly fill dive-list vector
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
1afd295c41 Undo: use vectors for MergeDives and SplitDive
The MergeDives and SplitDive commands used addDive() and removeDive()
calls to manage their dives. Unfortunately, these calls don't send
the proper signals and thus the dive-list was not updated. Instead,
use one- and two-element vectors, which are passed to addDives()
and removeDives() [note the plural].

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
7067e33596 Undo: select dives after add, remove, merge, split dive commands
Select the proper dives after the add, remove, split and merge
dives commands on undo *and* redo. Generally, select the added
dives. For undo of add, remember the pre-addition selection.
For redo of remove, select the closest dive to the first removed
dive.

The biggest part of the commit is the signal-interface between
the dive commands and the dive-list model and dive-list view.
This is done in two steps:
1) To the DiveTripModel in batches of trips. The dive trip model
   transforms the dives into indices.
2) To the DiveListView. The DiveListView has to translate the
   DiveTripModel indexes to actual indexes via its QSortFilterProxy-
   model.

For code-reuse, derive all divelist-changing commands from a new base-class,
which has a flag that describes whether the divelist changed. The helper
functions which add and remove dives are made members of the base class and
set the flag is a selected dive is added or removed.

To properly detect when the current dive was deleted it
became necessary to turn the current dive from an index
to a pointer, because indices are not stable.

Unfortunately, in some cases an index was expected and these
places now have to transform the dive into an index. These
should be converted in due course.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
23db0ba68d Dive list view: replace signal-magic by flag
In DiveListView, we have a very fundamental problem: When
On the one hand, we get informed of user-selection in the
DiveListView::selectionChanged() slot. This has to set the
correct flags in the C-backend.

On the other hand, sometimes we have to set the selection
programatically, e.g. when selecting a trip. This is done
by calling QItemSelectionModel::select().

But: this will *also* call into the above slot, in which
we can't tell whether it was a user interaction or an
internal call. This can lead to either infinite loops or
very inefficient behavior, because the current dive
is set numerous times.

The current code is aware of that and disconnects the
corresponding signal. This is scary, as these signals are
set internally by the model and view. Replace this
by a global "command executing" flag in DiveListNotifier.
The flag is set using a "marker" class, which resets the flag
once it goes out of scope (cf. RAII pattern).

In DiveListView, only process a selection if the flag is not
set. Otherwise simply call the QTreeView base class, to reflect
the new selection in the UI.

To have a common point for notifications of selection changes,
add such a signal to DiveListNotifier. This signal will be
used by the DiveListView as well as the Command-objects.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
0d98da5261 Dive list: remember selected dives
Don't delesect dives, when unregistering them from the backend.
If a previously selected dive is added, select it in the dive-list.
For this purpose introduce a SELECTED_ROLE to query the DiveTripModel
for selected dives.

Unfortunately, when adding multiple selected dives, current_dive_changed
is called for each of them, making this very slow. This will have
to be fixed in subsequent commits.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
96d8727399 Undo: use dive * instead of unique index in renumber-dives
Now, that pointers to dives are stable, we might just as well
use dive * instead of the unique-id. This also affects the
merge-dive command, as this uses the same renumbering machinery.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
26901a8dbd Undo: disable undo- and redo-actions in edit mode
We have to avoid that undo/redo removes the currently edited
dive from under our feet. This code can be removed once proper
undo/redo (including editing) is implemented.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
63b65a7e20 Undo: implement autogrouping of trips in DiveAdd
If the autogroup flag is set, search for appropriate trips in
DiveAdd() and add the dive to this trip. If no trip exists, add
a new trip.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
ec7d85835f Dive list: implement proper Qt-model semantics for DiveTripModel
Previously, each dive-list modifying function would lead to a
full model reset. Instead, implement proper Qt-model semantics
using beginInsertRows()/endInsertRows(), beginRemoveRows()/
endRemoveRows(), dataChange().

To do so, a DiveListNotifer singleton is generatated, which
broadcasts all changes to the dive-list. Signals are sent by
the commands and received by the DiveTripModel. Signals are
batched by dive-trip. This seems to be an adequate compromise
for the two kinds of list-views (tree and list). In the common
usecase mostly dives of a single trip are affected.

Thus, batching of dives is performed in two positions:
- At command-level to batch by trip
- In DiveTripModel to feed batches of contiguous elements
  to Qt's begin*/end*-functions.

This is conceptually simple, but rather complex code. To avoid
repetition of complex loops, the batching is implemented in
templated-functions, which are passed lambda-functions, which
are called for each batch.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
6ac4ddbeed Core: introduce insert_trip_dont_merge() function
insert_trip() adds a trip to the backend, but merges trips if
there exists a trip with the same date. This is a disaster
for the MergeTrips command, because this command adds a new
trip and removes the previous two. Of course if the added trip
is merged, this cannot work.

Therefore, add an insert_trip_dont_merge() function, which
adds the trip, but doesn't merge.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
43c3885249 Undo: isolate undo-commands
This refactors the undo-commands (which are now only "commands").

- Move everything in namespace Command. This allows shortening of
  names without polluting the global namespace. Moreover, the prefix
  Command:: will immediately signal that the undo-machinery is
  invoked. This is more terse than UndoCommands::instance()->...
- Remove the Undo in front of the class-names. Creating an "UndoX"
  object to do "X" is paradoxical.
- Create a base class for all commands that defines the Qt-translation
  functions. Thus all translations end up in the "Command" context.
- Add a workToBeDone() function, which signals whether this should be
  added to the UndoStack. Thus the caller doesn't have to check itself
  whether this any work will be done. Note: Qt5.9 introduces "setObsolete"
  which does the same.
- Split into public and internal header files. In the public header
  file only export the function calls, thus hiding all implementation
  details from the caller.
- Split in different translation units: One for the stubs, one for
  the base classes and one for groups of commands. Currently, there
  is only one class of commands: divelist-commands.
- Move the undoStack from the MainWindow class into commands_base.cpp.
  If we want to implement MDI, this can easily be moved into an
  appropriate Document class.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
f427226b3b Undo: make diverse trip-related operations undo-able
AddDivesToTrip, CreateTrip, AutogroupDives, RemoveAutogenTrips
and MergeTrips basically all did the same thing as RemoveDivesFromTrip,
which was already implemented. Thus, factor our the common functionality
and hook it up to make all these functions undo-able.

Don't do the autogroup-call everytime the dive-list is rebuilt
(that would create innumberable undo-actions), but only on dive-load /
import or if expressly asked by the user [by switching the autogroup
flag].

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
dd9af8e72e Undo: make editing of dive-time an undoable operation
The whole undo system assumes that the indexes in the dive table
do not change under its feet. On desktop, there seems only one
exception left: editing of the dive time. To circumvent this,
hook editing of the dive-time to the already existing UndoShiftTime
command.

This introduces a temporary UI-inconsistency: this is the only
edit that is reflected in the undo-list. This will be fixed in
due course, when other edit actions are also made undoable.

UndoShiftTime is changed to take pointers to dives (which should
be stable by now) instead of uniq-ids.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
ba9c35215e Dive editing: don't repeatedly loop through whole dive list
On dive editing, for every changed field the code looped through
the whole dive-list and modified the selected dives. Instead,
get the list of selected dives once and use that.

Whereas this may look like a gratuitous optimization, it will
make things easier for subsequent commits. Notably, we can
pass the list of selected dives to an "UndoObject".

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
c30efc95d4 Undo: clear undo history on load / import
Keeping undo-history across load makes little sense. The user was
expressly reminded that they have unsaved work.

For import (from other logs or the dive-computer) an undo-functionality
would be desirable. Nevertheless, this is rather complex since
new and old dives are merged. Implementation would require a finer
backend<->undocommand interface. Thus, leave this for now until more
experience with the undo system is acquired.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
014c04f8bd Undo: implement rudimentary support for undo of dive-merging
For this, an output-parameter was added to the backend merge_dives()
function. When non-zero, instead of adding the merged dive to
the preferred trip, the preferred trip is returned to the caller.

Since the new UndoObject, just like the delete-dives UndoObject,
needs to remove/readd a set of dives, the corresponding functionality
was split-off in a helper function.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
302f6adb79 Undo: implement rudimentary support for undo of dive-splitting
For this, the core functionality of the split_dive() and
split_dive_at_time() functions were split out into new
split_dive_dont_insert() and split_dive_at_time_dont_insert(),
which do not add the new dives to the log. Thus, the undo-command
can take ownership of these dives, without having to remove them
first.

The split-dive functionality is temporarily made desktop-only
until mobile also supports "UndoObjects".

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
12df9faaa2 Undo: implement undo of manual dive-creation
Play manual addition of dives via an UndoCommand. Since this does in
large parts the same thing as undo/redo of dive deletion (just the
other way round and only a single instead of multiple dive), factor
out the functions that add/delete dives and take care of trips.

The UI-interaction is just mindless copy&paste and will have to
be adapted.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
61467ea0d5 Cleanup: let MainTab::updateDiveSite() take dive * instead of id
Both callers have a dive * and transform that into an id,
the callee transforms it right back to the dive *. Simply pass
the dive directly. This will allow us to use the function for
dives that have not yet been added.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
403dd5a891 Undo: fix multi-level undo of delete-dive and remove-dive-from-trip
The original undo-code was fundamentally broken. Not only did it leak
resources (copied trips were never freed), it also kept references
to trips or dives that could be changed by other commands. Thus,
anything more than a single undo could lead to crashes.

Two ways of fixing this were considered
1) Don't store pointers, but unique dive-ids and trip-ids.
   Whereas such unique ids exist for dives, they would have to be
   implemented for trips.
2) Don't free objects in the backend.
   Instead, take ownership of deleted objects in the undo-object.
   Thus, all references in previous undo-objects are guaranteed to
   still exist (unless the objects are deleted elsewhere).

After some contemplation, the second method was chosen, because
it is significantly less intrusive. While touching the undo-objects,
clearly separate backend from ui-code, such that they can ultimately
be reused for mobile.

Note that if other parts of the code delete dives, crashes can still
be provoked. Notable examples are split/merge dives. These will have
to be fixed later. Nevertheless, the new code is a significant
improvement over the old state.

While touching the code, implement proper translation string based
on Qt's plural-feature (using %n).

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-11 16:22:27 -07:00
Berthold Stoeger
d6010b5155 Dive locations: factor out common code of models
For increased maintainability, use the same columns, roles and
the same accessor function for both dive-site models.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-09 21:00:44 -07:00
Berthold Stoeger
f40612d48d Map: avoid ugly "invalid dive site" message in location box
Under certain conditions the user was presented an ugly
"invalid dive site" message. The condition would arise because
the proxy-model which selects the list of dive sites and the code
which creates a proposed dive site name had different filter
conditions:
- The proxy would select any dive site containing the text
- The name-proposing code searched for dive sites *starting*
  with the text.

If the user entered a text contained by a dive site name, but
no dive site would start with the second line was filled with
a dummy text. This text would be kept if it contained the text
entered by the user.

To avoid this problem, if no dive site is found, use an empty
string instead. This will be filtered out by the proxy because
it does not contain the user-entered string.

Yes, that's horribly subtle, therefore add a comment. But ultimately,
this should be solved in a less brittle way.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-09 21:00:44 -07:00
Berthold Stoeger
0aef04352a Map: zoom on dive sites when flipping through dive site list
The dive site list was connected to centerOnDiveSite(). Apparently,
the currently selected dive site should have been shown in the map.
Yet, this never worked, because the actual dive site of the selected
dive had precedence in centerOnDiveSite().

It seems that centerOnDiveSite() had actually to purposes:
1) center on the passed in dive site
2) center on the dive sites of the selected dives

Therefore, split this function in two separate functions for
each of these use-cases. This allows us to remove some pre-processor
magic (mobile vs. desktop) and to remove a parameter from the
MainTab::diveSiteChanged() signal.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-08 13:29:51 -07:00
Berthold Stoeger
df16866292 Statistics: only consider selected dives in HTML export statistics
If only selected dives were exported into HTML, the statistics would
nevertheless cover all dives. A counter-intuitive behavior. Fix by
adding a selected_only flag to calculate_stats_summary().

Reported-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-07 17:50:51 +03:00
Berthold Stoeger
b61f6f66d8 Statistics: un-globalize stats_selection
The statistics of the selected dives were calculated
a) into a global objects and
b) at a completely different place than where they're used.

There's no plausible reason for either. There fore render
into a caller-provided structure at the place of use.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-07 17:50:51 +03:00
Berthold Stoeger
97991e2b9f Statistics: remove global state / calculate only when needed
Statistics were calculated into global variables every time the
current dive was changed.

Calculate statistics only when needed and into a structure
provided by the caller.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-07 17:50:51 +03:00
Berthold Stoeger
6dc1dcaea5 Import: pass "downloaded" parameter to process_imported_dives()
process_imported_dives() is more efficient for downloaded than for
imported (from a file) dives, because it checks only the divecomputer
of the first dive.

This condition is checked via the "downloaded" flag of the first
dive. Instead, pass an argument to process_imported_dives().

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-06 19:47:06 -07:00
Berthold Stoeger
810903bdb9 Import: pass a dive table to process_imported_dives()
Dives were directly imported into the global dive table and then
merged in process_imported_dives(). Make this interface more flexible,
by passing an independent dive table.

The dive table of the to-be-imported dives will be sorted and merged.
Then each dive is inserted in a one-by-one manner to into the global
dive table.

This actually introduces (at least) two functional changes:
1) If a new dive spans two old dives, it will only be merged to the
   first dive. But this seems like a pathological case, which is of
   dubious value anyway.
2) Dives unrelated to the import will not be merged. The old code
   would happily merge dives that were not even close to the
   newly imported dives. A surprising behavior.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-06 19:47:06 -07:00
Berthold Stoeger
c32e71e64d Dive information: fix surface interval calculation
The old surface interval calculation had fundamental issues:

1) process_all_dives(), which calculates the statistics over *all*
   dives was used to get the pointer to the previous dive.
2) If two dives in the table had the same time, one of those would
   have been considered the "previous" dive.
3) If the dive, for which the surface interval is calculated is
   not yet in the table, no previous dive would be determined.

Fix all this by creating a get_surface_interval() function and
removing the "get previous dive" functionality of process_all_dives().
Remove the process_all_dives() call from TabDiveInformation::updateData().

Reported-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-07 05:41:48 +03:00
Berthold Stoeger
5a78730561 Import: Make DiveLogImportDialog modal
By making this modal, we can use a local variable and remove the
nasty "deleteLater()" hack to reclaim the resources after the
dialog closes.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-04 10:22:11 +02:00
Berthold Stoeger
3f51849dc3 Cleanup: move CSVApps into .cpp file
No point in having this in the header file as it is not used
outside.

Remove the CSVAPPS macro, as this was never used. One thing less
to maintain.

Remove the sentinel with name = NULL, as we can simply use
range-based for.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-04 10:22:11 +02:00
Berthold Stoeger
a4051749fd Import: import Poseidon MkVI logs via DiveLogImportDialog
Poseidon MkVI logs (.txt) were special cased in MainWindow.cpp,
which led to a user-interface inconsistency. In some cases
[user chooses ".txt" (non-Poseidon) and ".csv"], *two*
import-dialogs were shown.

Move handling of Poseidon MkVI logs into DiveLogImportDialog.
There are already other "special" cases handled in this dialog.

At the moment, this shows the first 10 depth-values, which is
kind of useless, as this will all be at surface level. We
might think about something more useful.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-10-04 10:22:11 +02:00
Dirk Hohndel
ac8936004e update-manager: actually remember that we asked the user
Otherwise we get that annoying question every time the git version changes.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-10-02 13:20:44 -07:00
Dirk Hohndel
1f59629a76 Bluetooth: use standard Qt code on Windows
We shouldn't need our hand crafted code anymore.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-30 08:09:37 -07:00
Berthold Stoeger
574065b314 Cleanup: reinstate override modifiers
This reverts commit 1c4a859c8d,
where the override modifiers were removed owing to the noisy
"inconsistent override modifiers" which is default-on in clang.

This warning was disabled in 77577f717f,
so we can reinstate the overrides.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-29 15:23:25 -07:00
Berthold Stoeger
d7e3d68f36 Cleanup: Devirtualize WebServices::downloadTimedOut()
This member function was not overriden in a derived class. No point
in it being virtual.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-09-29 15:16:11 -07:00
Berthold Stoeger
7c22e4d805 Cleanup: don't derive UserSurveyServices from WebServices
UserSurveyServices derives from WebServices and therefore has
to define three pure virtual functions [startDownload(),
startUpload(), buttonClicked()] as no-ops. Interestingly,
a comment in the header says
	"need to declare them as no ops or Qt4 is unhappy"
which is of course not true as these functions are not
declared by Qt.

There seems to be no point in deriving from WebServices,
therefore don't do it. These function definitions can then
be removed.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-09-29 15:16:11 -07:00
Berthold Stoeger
41089b74a9 Cleanup: don't use QByteArray::data() to create copy
QByteArray::data() provides access to the underlying data
for direct manipulation. Thus, the construct
	csv = fileNamePtr.data();
found in MainWindow::importTxtFiles() suggests that modifications
to csv also affect fileNamePtr. This is *not* the case, because
csv itself is a QByteArray. It is therefore constructed from
the data.

Replace this treacherous construct by a simple assignment.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-09-29 14:01:22 -07:00
Berthold Stoeger
3923f54e10 Cleanup: don't needlessly recalculate dive list on CSV import
On CSV import, the dive list was recalculated after the import
dialog was shown. This is pointless, as no dives are yet imported.
Remove.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-09-29 14:01:22 -07:00
Berthold Stoeger
6e24762a6c Cleanup: Don't leak DiveLogImportDialog objects
The non-modal DiveLogImportDialog was only implicitly deleted when
the MainWindow was destroyed. Instead hook into the accept() and
reject() functions and schedule for deletion with deleteLater().

Quite the horrible proposition, but in line with Qt's object model.
Consider making the dialog modal instead. There seems to be no
upside for this being modal.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-09-29 14:01:22 -07:00
Berthold Stoeger
32a4ce6169 Parser: parse text-based files into arbitrary table
In d815e0c947 a dive_table pointer
was added to the parsing functions to allow parsing into tables
other than the global dive table. This will be necessary for undo of
import and implementation a cleaner interface. A few cases, notably
CSV and proprietary formats were forgotten.

Implement parsing into arbitrary tables also for these cases.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-09-28 15:06:00 -07:00
Berthold Stoeger
3137fbe973 Cleanup: remove redundant prototypes from dive.h
A few of these prototypes were already in import-csv.h.
Put them in an 'extern "C" { ... }' block.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-09-28 07:47:39 -07:00
Dirk Hohndel
ebb3fc8a0c Desktop/remember DCs: insert the remember connection into dropdown
This still doesn't do the right thing for BT/BLE connections on a Mac, but it
should work on Linux and possibly Mac.

We definitely need to figure out how to get the Mac to successfully connect back
to a BT/BLE device.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-24 18:51:21 +02:00
Berthold Stoeger
35b8a4f404 Core: split process_dives() in post-import and post-load versions
process_dives() is used to post-process the dive table after loading
or importing. The first parameter states whether this was after
load or import.

Especially in the light of undo, load and import are fundamentally
different things. Notably, that latter should be undo-able, whereas
the former is not. Therefore, as a first step to make import undo-able,
split the function in two versions and remove the first parameter.

It turns out the the load-version is very light. It only sets the
DC nicknames and sorts the dive-table. There seems to be no reason
to merge dives.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-09-23 11:50:53 -07:00
Dirk Hohndel
f5411b7d68 Desktop/settings: hook up button to clear remembered DCs
And at least admit that the reset settings button isn't hooked up at all.
OOOOPS.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-23 11:49:30 -07:00
Dirk Hohndel
b5fe44bb87 Desktop/settings: add button to forget remembered dive computers
This isn't hooked up, yet.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-23 11:49:30 -07:00
Dirk Hohndel
0d7c1e9918 Desktop/remember DCs: avoid highlighted button
On macOS the first of the four DC buttons was highlighted for some reason.
Explicitly setting autoDefault to no solved that problem.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-23 11:49:30 -07:00
Dirk Hohndel
413b05ab89 Desktop/remember DCs: move non-UI-specific code into the core layer
This way we can use the same functionality from the mobile UI as well.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-23 11:49:30 -07:00
Dirk Hohndel
4eb8ed1b29 Desktop/remember DCs: hook up the shortcut buttons
The straight forward code to update the currentIndex of the combobox doesn't
appear to work on macOS (but works fine on Linux). Calling the event loop and
then calling update afterwards seems very unintuitive, but it appears to fix
the issue in my testing.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-23 11:49:30 -07:00
Dirk Hohndel
99261775ce Desktop/remember DCs: remember dive computers that were used
The algorithm tries to keep the order of the buttons the same. So if a dive
computer was used that's already remembered, don't reorder the buttons. But if
a new dive computer is used, add it as the first one and move the others back,
potentially dropping the oldest one.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-23 11:49:30 -07:00
Dirk Hohndel
e2ee8c57df Desktop/remember DCs: base UI
Simply create the buttons that can be used as shortcuts to previously used dive
computers. This isn't hooked up at all.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-23 11:49:30 -07:00
Berthold Stoeger
21b1550739 Dive media: on import read metadata only once
On import of dive media, the timestamp is read from the
metadata to check if the image belongs to the selected dives.
The pictures are then listed in a dialog.

Currently, the metadata is read twice if images are outside
of a dive: once in picture_check_valid() and if it turns
out that the picture is not valid again in picture_get_time()
to display the proper timestamp.

Even though metadata-extraction is reasonably fast, this is
a bit of an embarrassment.

Instead, read the timestamps only once in the constructor of
the dialog and from then on only used these timestamps. Keep
the timestamps in a QVector. Rename the picture_check_valid()
function to picture_check_valid_time() and pass a timestamp
instead of a filename.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-09-19 14:44:34 -07:00
Jan Mulder
7efcb0594c Desktop UI: small layout correction export dialog
2 UI items where poorly aligned. Fixed here.

Reported-by: willemferguson <willemferguson@zoology.up.ac.za>
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-09-16 08:07:33 -07:00
Tomaz Canabrava
7319b50a5d code cleanup: replace lring with file local function
And simplify the code.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-15 15:51:26 -07:00
Tomaz Canabrava
77d7e550fe code cleanup: no need for default if we test every case
Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-15 15:51:26 -07:00
Tomaz Canabrava
7ab35f7858 code cleanup: use ByteArray.size() instead of strlen
Removes a size_t vs int warning

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-15 15:51:26 -07:00
Tomaz Canabrava
00ef514da3 code cleanup: pre-calculate the test and pass it directly
Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-15 15:51:26 -07:00
Tomaz Canabrava
6d552d61b9 code cleanup: allocate the vector in one go
The << alternative can reallocate the vector, but we know it's size, so
preallocate.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-15 15:51:26 -07:00
Tomaz Canabrava
858740e8a1 code cleanup: simplify if / else chains
Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-15 15:51:26 -07:00
Tomaz Canabrava
9e6a3bee0d code cleanup: remove allocations
Simply create the string in one go.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-15 15:51:26 -07:00
Tomaz Canabrava
2d6633eee0 code cleanup: use nullptr in C++ files
Using 0 or NULL are C idioms.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-15 15:51:26 -07:00
Tomaz Canabrava
17a6f28827 code cleanup: unamed namespace instead of global or static variables
Unamed namespace behaves the same way as static variables in C source.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-15 15:51:26 -07:00
Tomaz Canabrava
3b4877a073 code cleanup: sort headers alphabetically
This was driving me nuts.

Signed-off-by: Tomaz Canabrava <tcanabrava@kde.org>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-15 15:51:26 -07:00
willemferguson
809471fe4d Update the dive list context menu to reflect new media interface
A minor change to the UI. The wording of the two items in the dive
list context menu "Load image(s) from file(s)" and "Load
image from web" are updated since we now deal with both images
and videos. So it becomes "Load media from file(s)".... etc.

Signed-off-by: willemferguson <willemferguson@zoology.up.ac.za>
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-15 07:20:55 -07:00
Jan Mulder
d16bcd8978 Desktop: remove "edit dive" from log menu
Nowadays, we edit dives just by starting to enter data for the dive.
There is no need to explicitly ask to start editing the dive, using the
now removed menu option. This was a left-over of a long past history.

This is fallout from PR #1673.

Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-09-14 13:18:42 -07:00
Dirk Hohndel
313351c396 Add Q_OBJECT macro to two more classes
These also showed up as concerns when creating translation strings.
Adding them thankfully didn't create new strings, but not having them
potentially leads to incorrect runtime behavior.

Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
2018-09-14 11:55:24 -07:00
Jan Mulder
5133a38d25 Desktop: disable UI elements that make no sense during editing
As described in the referenced issue, we where able to navigate to
nonlogical static pages (like information, statistics. extra data) when
adding a dive. These are output style pages that make no sense on
edit or add. Further, disable access to some pages when entering edit mode.

Notice that the small change in file mainwindow.cpp is simply
because this this not work at all, and became superfluous any
way.

Fixes: #1445

Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
2018-09-14 10:00:54 +02:00
Robert C. Helling
afe363fa85 Optional anonymization upon export
Add a checkbox that triggers replacement of all English characters by
x's in notes, buddy, dive guide and (while we are at it) suit.

This is ment for people sharing logs for debugging that are concious
about privacy issues. It leaves the lenth of strings in tact as well
as special charcters as those might be needed to track down a particular
parsing problem.

Signed-off-by: Robert C. Helling <helling@atdotde.de>
2018-09-13 08:16:54 -07:00
Berthold Stoeger
31f1af07c2 Planner: fix display of "overlapping dives" message
1) Add a missing <div>

2) More importantly: recognize html content via <div>-tags instead of
   <table>-tags.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
2018-09-12 14:17:55 -07:00