If this flag is set, dives that are not assigned to a trip will
be assigned to a new trip. This flag is set if the user checked
"add to new trip" in the download dialog of the desktop version.
Currently this is a no-op as the dives will already have been
added to a new trip by the downloading code. This will be removed
in a subsequent commit.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The logic in process_imported_dives() was faulty: Dives are merged
trip-wise in a loop. But if only autogenerated trips were supposed
to be merged, the trip would not be added.
Change the logic to always add the trip if it is not merged. To make
the loop easier to read, factor out the merge-trip-into-existing-trips
logic into a separate function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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>
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>
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>
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>
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>
When importing log-files we generally want to merge trips. But
when downloading and the user chose "generate new trip", that
new trip should not be merged into existing trips.
Therefore, add a "merge_all_trips" parameter to process_imported_dives().
If false only autogenerated trips [via autogroup] will be merged.
In the future we might want to let the user choose if trips
should be merged when importing log-files.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The old way of merging log-files was not well defined: Trips
were recognized as the same if and only if the first dives
started at the same instant. Later dives did not matter.
Change this to merge dives if they are overlapping.
Moreover, on parsing and download generate trips in a separate
trip-table.
This will be fundamental for undo of dive-import: Firstly, we
don't want to mix trips of imported and not-yet imported dives.
Secondly, by merging trip-wise, we can autogroup the dives
in the import-data to trips and merge these at once. This will
simplify the code to decide to which trip dives should be
autogrouped.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In the future we want to download trips into a distinct trip-table
instead of the global trip-table to allow for undo of import.
Therefore add a trip_table argument to DiveImportedModel::repopulate()
and a trip_table member to DiveImportedModel. To correctly set these,
add a DownloadThread::trips() function, which currently simply returns
the global trip table.
Finally, make "struct trip_table *" a Q_METATYPE, so that the corresponding
arguments can be passed from QML.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
To allow parsing into arbitrary trip_tables, add the corresponding
parameter to the parsing functions and the parser state. Currently,
all callers pass the global trip_table so there should be no change
in functionality. These arguments will be replaced in subsequent commits.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently trips are added to the global trip table. If we want to
make dive-import undoable, we should be able to parse trips of a
log-file into a distinct table. Therefore, add a trip_table
parameter to
- insert_trip()
- create_and_hookup_trip_from_dive()
- autogroup_dives()
- unregister_trip()
- remove_dive_from_trip()
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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>
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>
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>
Currently autogroup_dives() groups all dives in the global dive
list. Add a table parameter so that dives in any table can be
grouped. Thus it will be possible to pre-group dives on import,
which will be used for undo of import.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
After loading or importing, the caller usually called autogroup()
to autogroup dives if so wished by the user. This has already led
to bugs, when autogroup() was forgotten.
Instead, call autogroup() directly in the process_loaded_dives()
and process_imported_dives() functions. Not only does this prevent
forgetting the call - it also means that autogrouping can be
changed without changing every caller.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
In 302f6adb79 dive-splitting was made
undo-able. To this goal, the dive-splitting functions were split in
two types: Those that operate directly on the divelist and those that
only allocate the dives. The former are not in use anymore, therefore
remove them. Since only the latter remain, remove the "_dont_insert"
appendix of the name.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In 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>
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>
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>
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>
... 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>
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>
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>
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>
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>
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>
The dives of each trip were kept in a list. Replace this by a
struct dive_table. This will make it significantly easier to
keep the dives of a trip in sorted state.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Up to now, dives were added to the global dive table with
add_single_dive(). Split out the funtionality to add a dive to
an arbitrary dive in the add_dive_to_table_function(). The
difference compared to record_dive_to_table is that dives
are added at a specific position or the sort-criterion given
by dive_less_than(). This will allow to use a dive tabe for trips
instead of a linked list.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There were two versions of the insert_trip() function: one
would merge trips if a trip with the same date already existed,
the other wouldn't. The latter was introduced with the dive-list
undo work.
The problem is that the "date" of a trip (i.e. the first dive)
seems ill-defined as this is a volatile value. Moreover in
the context of making dive-import undoable this is a very
dangerous notion, as the caller needs control over when the dives
are added to a trip.
Therefore, unify these two functions and never merge trips.
The decision on merging dives now has to made by the caller.
This will be implemented in a future commit.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
There was this ugly pattern of passing pointers-to-dive_site via
a QVariant of void * type. This is of course inherently unsafe.
Pass these pointers using their proper types instead. This makes
it necessary to register them in Qt's meta-type system. Doing so,
fixes a bug: QML couldn't call into updateDiveSiteCoordinates()
because it didn't know the type and thus the coordinates of
the moved flag were not reflected in the divesite-dialog.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Replace the UUID reference of struct dive by a pointer to dive_site.
This commit is rather large in lines, but nevertheless quite simple
since most of the UUID->pointer work was done in previous commits.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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>
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>
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>
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>
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>
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>
Instead of passing uuids, pass a pointer to the dive site.
This is small step in an effort to remove uuids.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of passing a uuid, pass a pointer to the dive site.
This is small step in an effort to remove uuids.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of passing a uuid, pass a pointer to the dive site.
This is small step in an effort to remove uuids.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Instead of passing a uuid, pass a pointer to the dive site.
This is small step in an effort to remove uuids.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This changes more of the dive-site interface to return pointers
instead of UUIDs. Currently, most call sites directly extract
UUIDs afterwards. Ultimately, the UUIDs will be generally replaced
by pointers, which will then simplify these callers.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Remove three cases of rememberSelection() which did not possess
the corresponding restoreSelection() twins.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
The deco parameters need special treatment to wire them up to the
underlying deco model code. And with the new preferences setup this
is a lot of boilerplate.
Signed-off-by: Jan Mulder <jlmulder@xs4all.nl>
On 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>
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>
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>
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>
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>
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>
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>
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>
The dive-site-edit widget uses a copy of the to-be-edited site
to compare with old values. Generally, this seems overkill
(the original dive-site can be used for such a comparison).
But one place where it can't simply be removed is the taxonomy,
because the widget needs a place to store the unsaved data.
Change the code to use an explicit taxonomy structure instead
of the one provided in the copy. This should ultimately allow
removal of the latter.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The global object displayed_dive_site is used a a backing-store
by the dive-site-edit widget. All external accesses were removed,
therefore make the object local to the widget.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The global object "displayed_dive_site" is used to store the
old dive site data for the edit-dive-site widget. The fields
of the widget were initialized from this object in the show
event. Therefore the object was updated in numerous parts of
the code to make sure that it was up-to-date. Instead, move
the initialization of the object to the function that also
initiatlizes the fields. Call this function explicitly before
showing the widget.
This makes the data-fow distinctly easier to understand.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
Select the proper dives after the add, remove, split and merge
dives commands on undo *and* redo. Generally, select the added
dives. For undo of add, remember the pre-addition selection.
For redo of remove, select the closest dive to the first removed
dive.
The biggest part of the commit is the signal-interface between
the dive commands and the dive-list model and dive-list view.
This is done in two steps:
1) To the DiveTripModel in batches of trips. The dive trip model
transforms the dives into indices.
2) To the DiveListView. The DiveListView has to translate the
DiveTripModel indexes to actual indexes via its QSortFilterProxy-
model.
For code-reuse, derive all divelist-changing commands from a new base-class,
which has a flag that describes whether the divelist changed. The helper
functions which add and remove dives are made members of the base class and
set the flag is a selected dive is added or removed.
To properly detect when the current dive was deleted it
became necessary to turn the current dive from an index
to a pointer, because indices are not stable.
Unfortunately, in some cases an index was expected and these
places now have to transform the dive into an index. These
should be converted in due course.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In DiveListView, we have a very fundamental problem: When
On the one hand, we get informed of user-selection in the
DiveListView::selectionChanged() slot. This has to set the
correct flags in the C-backend.
On the other hand, sometimes we have to set the selection
programatically, e.g. when selecting a trip. This is done
by calling QItemSelectionModel::select().
But: this will *also* call into the above slot, in which
we can't tell whether it was a user interaction or an
internal call. This can lead to either infinite loops or
very inefficient behavior, because the current dive
is set numerous times.
The current code is aware of that and disconnects the
corresponding signal. This is scary, as these signals are
set internally by the model and view. Replace this
by a global "command executing" flag in DiveListNotifier.
The flag is set using a "marker" class, which resets the flag
once it goes out of scope (cf. RAII pattern).
In DiveListView, only process a selection if the flag is not
set. Otherwise simply call the QTreeView base class, to reflect
the new selection in the UI.
To have a common point for notifications of selection changes,
add such a signal to DiveListNotifier. This signal will be
used by the DiveListView as well as the Command-objects.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Don't delesect dives, when unregistering them from the backend.
If a previously selected dive is added, select it in the dive-list.
For this purpose introduce a SELECTED_ROLE to query the DiveTripModel
for selected dives.
Unfortunately, when adding multiple selected dives, current_dive_changed
is called for each of them, making this very slow. This will have
to be fixed in subsequent commits.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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>
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>
If the autogroup flag is set, search for appropriate trips in
DiveAdd() and add the dive to this trip. If no trip exists, add
a new trip.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Previously, each dive-list modifying function would lead to a
full model reset. Instead, implement proper Qt-model semantics
using beginInsertRows()/endInsertRows(), beginRemoveRows()/
endRemoveRows(), dataChange().
To do so, a DiveListNotifer singleton is generatated, which
broadcasts all changes to the dive-list. Signals are sent by
the commands and received by the DiveTripModel. Signals are
batched by dive-trip. This seems to be an adequate compromise
for the two kinds of list-views (tree and list). In the common
usecase mostly dives of a single trip are affected.
Thus, batching of dives is performed in two positions:
- At command-level to batch by trip
- In DiveTripModel to feed batches of contiguous elements
to Qt's begin*/end*-functions.
This is conceptually simple, but rather complex code. To avoid
repetition of complex loops, the batching is implemented in
templated-functions, which are passed lambda-functions, which
are called for each batch.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
insert_trip() adds a trip to the backend, but merges trips if
there exists a trip with the same date. This is a disaster
for the MergeTrips command, because this command adds a new
trip and removes the previous two. Of course if the added trip
is merged, this cannot work.
Therefore, add an insert_trip_dont_merge() function, which
adds the trip, but doesn't merge.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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>
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>
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>
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>
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>
For this, an output-parameter was added to the backend merge_dives()
function. When non-zero, instead of adding the merged dive to
the preferred trip, the preferred trip is returned to the caller.
Since the new UndoObject, just like the delete-dives UndoObject,
needs to remove/readd a set of dives, the corresponding functionality
was split-off in a helper function.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
For this, the core functionality of the split_dive() and
split_dive_at_time() functions were split out into new
split_dive_dont_insert() and split_dive_at_time_dont_insert(),
which do not add the new dives to the log. Thus, the undo-command
can take ownership of these dives, without having to remove them
first.
The split-dive functionality is temporarily made desktop-only
until mobile also supports "UndoObjects".
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Play manual addition of dives via an UndoCommand. Since this does in
large parts the same thing as undo/redo of dive deletion (just the
other way round and only a single instead of multiple dive), factor
out the functions that add/delete dives and take care of trips.
The UI-interaction is just mindless copy&paste and will have to
be adapted.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
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>
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>
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>
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>
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>
If only selected dives were exported into HTML, the statistics would
nevertheless cover all dives. A counter-intuitive behavior. Fix by
adding a selected_only flag to calculate_stats_summary().
Reported-by: Jan Mulder <jlmulder@xs4all.nl>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The statistics of the selected dives were calculated
a) into a global objects and
b) at a completely different place than where they're used.
There's no plausible reason for either. There fore render
into a caller-provided structure at the place of use.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Statistics were calculated into global variables every time the
current dive was changed.
Calculate statistics only when needed and into a structure
provided by the caller.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>