Adds a preference setting in the "Default" settings tab to toggle whether
to display shortened names in the Map.
TODO: instead of using the generic "settingsChanged" signal, it would be much
more efficient to only update items based on the actual setting which was
changed.
Signed-off-by: Michael WERLE <micha@michaelwerle.com>
The memory management of the quadrant widgets is a total mess:
When setting the widget, the QSplitters take ownership, which
means that they will delete the widget in their destructor.
This is inherently incompatible with singletons, which must
not be deleted.
To avoid all these troubles, remove the widgets from the
QSplitters in the desctructor of the MainWindow. This of
course means that we now have to take care about deletion
of the widgets.
For local widgets use std::unique_ptr, for singletons use
a static variable that is deleted on application exit.
Sadly, for the map widget we can't use a normal singleton,
because the QML MapWidget's memory management is buggy.
Add a comment in the source code explaining this.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
To reset the core data structures, the mobile and desktop UIs
were calling into the dive-list models, which then reset the
core data structures, themselves and the unrelated
locationinformation model. The UI code then reset various other
things, such as the TankInformation model or the map. . This was
unsatisfying from a control-flow perspective, as the models should
display the core data, not act on it. Moreover, this meant lots
of intricate intermodule-dependencies.
Thus, straighten up the control flow: give the C core the
possibility to send a "all data reset" event. And do that
in those functions that reset the core data structures.
Let each module react to this event by itself. This removes
inter-module dependencies. For example, the MainWindow now
doesn't have to reset the TankInfoModel or the MapWidget.
Then, to reset the core data structures, let the UI code
simply directly call the respective core functions.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The map widget called the dive list to select dives. This is
inconsistent and complex. The dive list has to call down to
the core anyway. Therefore, change the code to call the common
core function.
This means that we have to transform integer ids into dive-pointers.
That is a bit sad, because the dives were just transformed into
indices. Let's address that in a future commit.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
In the future we might want to use undo-commands for mobile as
well (even if not implementing undo).
Therefore, move the undo-command source from desktop-widgets
to their own commands top-level folder.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
The divesEdited signal sends the changed field as a parameter.
Since some undo-commands change multiple fields, this led to
numerous signals for a single command. This in turn would lead
to multiple profile-reloads and statistic recalculations.
Therefore, turn the enum into a bitfield. For simplicity,
provide a constructor that takes classical flags and turns
them into the bitfield. This is necessary because C-style
named initialization is only supported on C++20 onward!
Is this somewhat overengineered? Yes, maybe.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There is the alternative MapWidget::reload() function, which
centers on the selected dive-site.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
When clicking a dive site on the map, the QML code would set
the selected dive site, but then all dives of dive sites in
the vicinity were set. But still only the clicked-on dive site
was shown.
Therefore, don't set the list of selected dive sites in QML,
but later in DiveListView::selectDives(), where we know all
the dives that were selected.
This, again, gives nasty entanglement of diverse widgets and
models.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
When changing the selection the MapLocationModel was reset.
This lead to crashes on Qt-5.9 which are due to QML accessing
data that was freed during model reset. This putative Qt bug
doesn't happen on newer Qt versions. At least Qt-5.12 is known
to work.
Instead of fighting the bug, let's simply not reset the model
but send a dataChanged() for every element of the MapLocationModel.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Experimentation has shown that the image of a flag will
only be changed after dataChanged() if it is a simple
property. The old code had a complex QML expression and
then - for some reason - it didn't work.
To give us better control over the flags and avoid full
reloads of the map therefore introduce a model-property
pixmap name. The name depends on whether the site is
selected and if not, whether we are in divesite-edit mode.
This makes the code rather convoluted. Firstly, we have
to save whether the site is selected in the map-item.
Secondly we have to access the global map-widget, which
in turn has to go to the map-widget helper (layering
violation!).
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Since the default view is batched by trips, signals were sent trip-wise.
This seemed like a good idea at first, but when more and more parts used
these signals, it became a burden. Therefore push the batching to the
part of the code where it is needed: the trip view.
The divesAdded and divesDeleted are not yet converted, because these
are combined with trip addition/deletion. This should also be detangled,
but not now.
Since the dive-lists were sorted in the processByTrip function, the
dive-list model now does its own sorting. This will have to be
audited.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
These functions were spread out over dive.c and divelist.c.
Move them into their own file to make all this a bit less monolithic.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Currently, dive site names are only updated on full reload.
Instead hook directly into the corresponding signal in the
MapLocationModel to set the name. Also to the coordinates
directly there instead of going via the MapWidgetHelper.
In the MapWidgetHelper, just center on the changed dive site.
Hook into the signal directly there and remove the slot
from the MapWidget. This makes the whole call-chain at least
one call shorter.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
There used to be a flag to avoid reloading of the map. Since this
is not used anymore, remove it.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Since the dive-site-filter is active either on the dive-site-edit
page or the dive-site-list page, use that as the flag for dive-site-edit
mode. Moreover, when the filter is reset, the
MapWidgetHelper::reloadMapLocations() function is called, so we
can use that place to enter/exit edit mode.
This makes it easier to keep everything consistent.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
DiveListView::selectDives() would only select new dives but not clear
the old selection. Thus, callers would have to clear the selection
first. That would lead to two selection-changed signals.
Move the unselectDives() call into DiveListView::selectDives().
The DiveListView has an internal flag to prevent double signals.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This was only used locally and only a stub for calling
MapWidgetHelper::centerOnSelectedDiveSite. Call the latter directly
instead.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
When changing the dive selection, we have to reload the map to show
the correctly highlighted flags. Do this directly by hooking into
the DiveListNotifier::divesChanged signal instead of indirectly
via the MainTab.
Moreover, on reload center on the highlighted dive sites.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This member variable was only used locally in functions.
Accordingly, make it a function-local variable.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
During edit mode, we could get spurious reload() requests owing
to tabs being hidden. This led to undefined behavior:
In some cases entering dive site edit mode would show all dive
sites, in some only the dive site of the currently edited dive.
Therefore, refuse to reload the map while in edit mode. The
corresponding flag already exists.
Partially fixes#2076
Reported-by: Doug Junkins <junkins@foghead.com>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
On reload of the map, the map exits edit mode. Sounds logical
at first, but the whole map-mode code is very unpredictable.
What happened was that when switching from the dive site table
to dive site edit mode, the code would enter map edit mode first.
Then, the dive site tab got its hide-signal, which would reset the
filter. This would reload the map and thus exit mode. Hence the user
can't drag the flag on the map.
Partially fixes#2076
Reported-by: Doug Junkins <junkins@foghead.com>
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Since no dive site field editing enters edit mode anymore,
the whole edit mode state and code can be removed from the
widget.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
Simply hook into the appropriate signal. Thus, the "update dive site
location" button can be removed.
Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
It expands to nullptr anyway and is inconsitent with the rest of the
code. Let's remove this anachronism.
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>
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>
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>
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>
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 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>
Remove qmlRegister in desktop-widgets/mapwidget in order to have a shared
registration in subsurface-helper.cpp
Signed-off-by: Jan Iversen <jani@apache.org>
remove mapWidget entries from subsurface.qrc, and
add reference to map-widget.qrc in CMakelist.txt
Android uses the same CMakelist.txt
Signed-off-by: Jan Iversen <jani@apache.org>
This patch allows updating the location of map markers
while editing a dive site and updating the text in the
LocationInformationWidget in real-time.
Currently it is only possible to see the marker changes by
clicking 'Apply'.
The modification required the following changes:
- add the MapWidget::updateCurrentDiveSiteCoordinatesToMap() slot
and call it each time the GPS text updates
- separate the updateCurrentDiveSiteCoordinates(FromMap/ToMap) logic
by having the FromMap/ToMap suffix to method names
- make MapWidgetHelper::updateCurrentDiveSiteCoordinatesToMap()
call a new MapLocationModel::updateMapLocationCoordinates()
method, which updates selected location coordinates and the model
- add MapLocation::setCoordinateNoEmit() that does not emit
a signal when updating a coordinate
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
Move all the map widget platform agnostic files to the
<subsurface-root>/map-widget folder.
This avoids the confusion about the desktop version of subsurface
using mobile components. The map widget is planned as a shared
component between the mobile and desktop versions.
desktop-widgets/mapwidget[.h/.cpp] still remain as those are specific
to the desktop version.
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
If the QML modules for QtLocation and QtPositioning are
missing the QML in mapwidget.cpp will fail to load,
which can lead to crashes.
To solve the issue check if the QML has loaded and set
a flag 'isReady' to true. If the loading has failed
load another QML which is for showing a red error text
in the lines of `MapWidget.qml failed to load!`.
If the map QML has failed, use a macro in all relevant
MapWidget members to turn them into a NOP. This approach
leaves the rest of the codebase intact - e.g. no checks
in classes which connect to the MapWidget class.
Fixes#596
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
I thought we had this automated, but Lubomirs commits introduced a few
files with dos line endings. This is purely a change of line endings, no
other changes.
Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
The local slot coordinatesChangedLocal() tracks the MapWidgetHelper
coordinatesChanged() signal and emit a coordinatesChanged() signal
to any listeners (e.g. MainWindow).
Also add a small change in centerOnDiveSite(), to not be called if
we are skipping the reload (skipReload is updated by
selectedDivesChanged()).
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
This guard is to prevent a meaningless reload on the map marker list,
when the user selects a new dive and nearby dives. The flag is updated
in selectedDivesChanged() which on it's now cannot possibly trigger
changes in the markers, only the selection. The selection of active flags
is already handled by the model and automatically updated in the QML.
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
The selectedDivesChanged() signal from MapWidgetHelper is connected
to a local slot. One problem here is that this crashes with the calls to
DiveListView().
The dive list widget triggers events that call reload() on the MapWidget
(same happens for Marble's Globe class) and that crashes somewhere in
the QML shared library. TODO: investigate.
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
Apparently, if it's required to import a QML component inside any QML
file from resource, the compoment QRC alias has to have the same name
as the component - e.g. add QRC alias MapWidgetContextMenu.qml allows
creating a MapWidgetContextMenu compoment inside MapWidget.qml.
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>
MapWidgetHelper::reloadMapLocations() is now called from MapWidget::reload()
and MapWidget::repopulateLabels().
The mobile version should do similar.
NOTE: These MapWidget methods names are from the Marble "port".
Signed-off-by: Lubomir I. Ivanov <neolit123@gmail.com>