diff options
Diffstat (limited to 'mobile-widgets')
-rw-r--r-- | mobile-widgets/qml/MapWidget.qml | 355 | ||||
-rw-r--r-- | mobile-widgets/qml/MapWidgetContextMenu.qml | 124 | ||||
-rw-r--r-- | mobile-widgets/qml/MapWidgetError.qml | 13 | ||||
-rw-r--r-- | mobile-widgets/qml/icons/mapwidget-context-menu.png | bin | 242 -> 0 bytes | |||
-rw-r--r-- | mobile-widgets/qml/icons/mapwidget-marker-gray.png | bin | 2033 -> 0 bytes | |||
-rw-r--r-- | mobile-widgets/qml/icons/mapwidget-marker-selected.png | bin | 1995 -> 0 bytes | |||
-rw-r--r-- | mobile-widgets/qml/icons/mapwidget-marker.png | bin | 1801 -> 0 bytes | |||
-rw-r--r-- | mobile-widgets/qml/icons/mapwidget-toggle-satellite.png | bin | 6288 -> 0 bytes | |||
-rw-r--r-- | mobile-widgets/qml/icons/mapwidget-toggle-street.png | bin | 5916 -> 0 bytes | |||
-rw-r--r-- | mobile-widgets/qml/icons/mapwidget-zoom-in.png | bin | 256 -> 0 bytes | |||
-rw-r--r-- | mobile-widgets/qml/icons/mapwidget-zoom-out.png | bin | 242 -> 0 bytes | |||
-rw-r--r-- | mobile-widgets/qmlmapwidgethelper.cpp | 264 | ||||
-rw-r--r-- | mobile-widgets/qmlmapwidgethelper.h | 53 |
13 files changed, 0 insertions, 809 deletions
diff --git a/mobile-widgets/qml/MapWidget.qml b/mobile-widgets/qml/MapWidget.qml deleted file mode 100644 index 2a3283482..000000000 --- a/mobile-widgets/qml/MapWidget.qml +++ /dev/null @@ -1,355 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -import QtQuick 2.0 -import QtLocation 5.3 -import QtPositioning 5.3 -import org.subsurfacedivelog.mobile 1.0 - -Item { - id: rootItem - property int nSelectedDives: 0 - - MapWidgetHelper { - id: mapHelper - map: map - editMode: false - onSelectedDivesChanged: nSelectedDives = list.length - onEditModeChanged: editMessage.isVisible = editMode === true ? 1 : 0 - onCoordinatesChanged: {} - Component.onCompleted: { - map.plugin = Qt.createQmlObject(pluginObject, rootItem) - map.mapType = { "STREET": map.supportedMapTypes[0], "SATELLITE": map.supportedMapTypes[1] } - map.activeMapType = map.mapType.SATELLITE - } - } - - Map { - id: map - anchors.fill: parent - zoomLevel: defaultZoomIn - - property var mapType - readonly property var defaultCenter: QtPositioning.coordinate(0, 0) - readonly property real defaultZoomIn: 12.0 - readonly property real defaultZoomOut: 1.0 - readonly property real textVisibleZoom: 11.0 - readonly property real zoomStep: 2.0 - property var newCenter: defaultCenter - property real newZoom: 1.0 - property real newZoomOut: 1.0 - property var clickCoord: QtPositioning.coordinate(0, 0) - property bool isReady: false - - Component.onCompleted: isReady = true - onZoomLevelChanged: { - if (isReady) - mapHelper.calculateSmallCircleRadius(map.center) - } - - MapItemView { - id: mapItemView - model: mapHelper.model - delegate: MapQuickItem { - id: mapItem - anchorPoint.x: 0 - anchorPoint.y: mapItemImage.height - coordinate: model.coordinate - z: mapHelper.model.selectedUuid === model.uuid ? mapHelper.model.count - 1 : 0 - sourceItem: Image { - id: mapItemImage - source: "qrc:///mapwidget-marker" + (mapHelper.model.selectedUuid === model.uuid ? "-selected" : (mapHelper.editMode ? "-gray" : "")) - SequentialAnimation { - id: mapItemImageAnimation - PropertyAnimation { target: mapItemImage; property: "scale"; from: 1.0; to: 0.7; duration: 120 } - PropertyAnimation { target: mapItemImage; property: "scale"; from: 0.7; to: 1.0; duration: 80 } - } - MouseArea { - drag.target: (mapHelper.editMode && mapHelper.model.selectedUuid === model.uuid) ? mapItem : undefined - anchors.fill: parent - onClicked: { - if (!mapHelper.editMode) - mapHelper.model.setSelectedUuid(model.uuid, true) - } - onDoubleClicked: map.doubleClickHandler(mapItem.coordinate) - onReleased: { - if (mapHelper.editMode && mapHelper.model.selectedUuid === model.uuid) { - mapHelper.updateCurrentDiveSiteCoordinates(mapHelper.model.selectedUuid, mapItem.coordinate) - } - } - } - Item { - // Text with a duplicate for shadow. DropShadow as layer effect is kind of slow here. - y: mapItemImage.y + mapItemImage.height - visible: map.zoomLevel >= map.textVisibleZoom - Text { - id: mapItemTextShadow - x: mapItemText.x + 2; y: mapItemText.y + 2 - text: mapItemText.text - font.pointSize: mapItemText.font.pointSize - color: "black" - } - Text { - id: mapItemText - text: model.name - font.pointSize: 11.0 - color: mapHelper.model.selectedUuid === model.uuid ? "white" : "lightgrey" - } - } - } - } - } - - SequentialAnimation { - id: mapAnimationZoomIn - NumberAnimation { - target: map; property: "zoomLevel"; to: map.newZoomOut; duration: Math.abs(map.newZoomOut - map.zoomLevel) * 200 - } - ParallelAnimation { - CoordinateAnimation { target: map; property: "center"; to: map.newCenter; duration: 1000 } - NumberAnimation { - target: map; property: "zoomLevel"; to: map.newZoom ; duration: 2000; easing.type: Easing.InCubic - } - } - } - - ParallelAnimation { - id: mapAnimationZoomOut - NumberAnimation { target: map; property: "zoomLevel"; from: map.zoomLevel; to: map.newZoom; duration: 3000 } - SequentialAnimation { - PauseAnimation { duration: 2000 } - CoordinateAnimation { target: map; property: "center"; to: map.newCenter; duration: 2000 } - } - } - - ParallelAnimation { - id: mapAnimationClick - CoordinateAnimation { target: map; property: "center"; to: map.newCenter; duration: 500 } - NumberAnimation { target: map; property: "zoomLevel"; to: map.newZoom; duration: 500 } - } - - MouseArea { - anchors.fill: parent - onDoubleClicked: map.doubleClickHandler(map.toCoordinate(Qt.point(mouseX, mouseY))) - } - - function doubleClickHandler(coord) { - newCenter = coord - newZoom = zoomLevel + zoomStep - if (newZoom > maximumZoomLevel) - newZoom = maximumZoomLevel - mapAnimationClick.restart() - } - - function animateMapZoomOut() { - newCenter = defaultCenter - newZoom = defaultZoomOut - mapAnimationZoomIn.stop() - mapAnimationZoomOut.restart() - } - - function pointIsVisible(pt) { - return !isNaN(pt.x) - } - - function stopZoomAnimations() { - mapAnimationZoomIn.stop() - mapAnimationZoomOut.stop() - } - - function centerOnCoordinate(coord) { - stopZoomAnimations() - if (coord.latitude === 0.0 && coord.longitude === 0.0) { - // Do nothing - } else { - var newZoomOutFound = false - var zoomStored = zoomLevel - newZoomOut = zoomLevel - newCenter = coord - while (zoomLevel > minimumZoomLevel) { - var pt = fromCoordinate(coord) - if (pointIsVisible(pt)) { - newZoomOut = zoomLevel - newZoomOutFound = true - break - } - zoomLevel-- - } - if (!newZoomOutFound) - newZoomOut = defaultZoomOut - zoomLevel = zoomStored - newZoom = zoomStored - mapAnimationZoomIn.restart() - mapAnimationZoomOut.stop() - } - } - - function centerOnRectangle(topLeft, bottomRight, centerRect) { - stopZoomAnimations() - if (newCenter.latitude === 0.0 && newCenter.longitude === 0.0) { - // Do nothing - } else { - var centerStored = QtPositioning.coordinate(center.latitude, center.longitude) - var zoomStored = zoomLevel - var newZoomOutFound = false - newCenter = centerRect - // calculate zoom out - newZoomOut = zoomLevel - while (zoomLevel > minimumZoomLevel) { - var ptCenter = fromCoordinate(centerStored) - var ptCenterRect = fromCoordinate(centerRect) - if (pointIsVisible(ptCenter) && pointIsVisible(ptCenterRect)) { - newZoomOut = zoomLevel - newZoomOutFound = true - break - } - zoomLevel-- - } - if (!newZoomOutFound) - newZoomOut = defaultZoomOut - // calculate zoom in - center = newCenter - zoomLevel = maximumZoomLevel - var diagonalRect = topLeft.distanceTo(bottomRight) - while (zoomLevel > minimumZoomLevel) { - var c0 = toCoordinate(Qt.point(0.0, 0.0)) - var c1 = toCoordinate(Qt.point(width, height)) - if (c0.distanceTo(c1) > diagonalRect) { - newZoom = zoomLevel - 2.0 - break - } - zoomLevel-- - } - if (newZoom > defaultZoomIn) - newZoom = defaultZoomIn - zoomLevel = zoomStored - center = centerStored - mapAnimationZoomIn.restart() - mapAnimationZoomOut.stop() - } - } - - function deselectMapLocation() { - stopZoomAnimations() - } - } - - Rectangle { - id: editMessage - radius: padding - color: "#b08000" - border.color: "white" - x: (map.width - width) * 0.5; y: padding - width: editMessageText.width + padding * 2.0 - height: editMessageText.height + padding * 2.0 - visible: false - opacity: 0.0 - property int isVisible: -1 - property real padding: 10.0 - onOpacityChanged: visible = opacity != 0.0 - states: [ - State { when: editMessage.isVisible === 1; PropertyChanges { target: editMessage; opacity: 1.0 }}, - State { when: editMessage.isVisible === 0; PropertyChanges { target: editMessage; opacity: 0.0 }} - ] - transitions: Transition { NumberAnimation { properties: "opacity"; easing.type: Easing.InOutQuad }} - Text { - id: editMessageText - y: editMessage.padding; x: editMessage.padding - verticalAlignment: Text.AlignVCenter - color: "white" - font.pointSize: 11.0 - text: qsTr("Drag the selected dive location") - } - } - - Image { - id: toggleImage - x: 10; y: x - width: 40 - height: 40 - source: "qrc:///mapwidget-toggle-" + (map.activeMapType === map.mapType.SATELLITE ? "street" : "satellite") - SequentialAnimation { - id: toggleImageAnimation - PropertyAnimation { target: toggleImage; property: "scale"; from: 1.0; to: 0.8; duration: 120 } - PropertyAnimation { target: toggleImage; property: "scale"; from: 0.8; to: 1.0; duration: 80 } - } - MouseArea { - anchors.fill: parent - onClicked: { - map.activeMapType = map.activeMapType === map.mapType.SATELLITE ? map.mapType.STREET : map.mapType.SATELLITE - toggleImageAnimation.restart() - } - } - } - - Image { - id: imageZoomIn - x: 10 + (toggleImage.width - imageZoomIn.width) * 0.5; y: toggleImage.y + toggleImage.height + 10 - width: 20 - height: 20 - source: "qrc:///mapwidget-zoom-in" - SequentialAnimation { - id: imageZoomInAnimation - PropertyAnimation { target: imageZoomIn; property: "scale"; from: 1.0; to: 0.8; duration: 120 } - PropertyAnimation { target: imageZoomIn; property: "scale"; from: 0.8; to: 1.0; duration: 80 } - } - MouseArea { - anchors.fill: parent - onClicked: { - map.newCenter = map.center - map.newZoom = map.zoomLevel + map.zoomStep - if (map.newZoom > map.maximumZoomLevel) - map.newZoom = map.maximumZoomLevel - mapAnimationClick.restart() - imageZoomInAnimation.restart() - } - } - } - - Image { - id: imageZoomOut - x: imageZoomIn.x; y: imageZoomIn.y + imageZoomIn.height + 10 - source: "qrc:///mapwidget-zoom-out" - width: 20 - height: 20 - SequentialAnimation { - id: imageZoomOutAnimation - PropertyAnimation { target: imageZoomOut; property: "scale"; from: 1.0; to: 0.8; duration: 120 } - PropertyAnimation { target: imageZoomOut; property: "scale"; from: 0.8; to: 1.0; duration: 80 } - } - MouseArea { - anchors.fill: parent - onClicked: { - map.newCenter = map.center - map.newZoom = map.zoomLevel - map.zoomStep - mapAnimationClick.restart() - imageZoomOutAnimation.restart() - } - } - } - - function openLocationInGoogleMaps(latitude, longitude) { - var loc = latitude + " " + longitude - var url = "https://www.google.com/maps/place/" + loc + "/@" + loc + ",5000m/data=!3m1!1e3!4m2!3m1!1s0x0:0x0" - Qt.openUrlExternally(url) - } - - MapWidgetContextMenu { - id: contextMenu - y: 10; x: map.width - y - onActionSelected: { - switch (action) { - case contextMenu.actions.OPEN_LOCATION_IN_GOOGLE_MAPS: - openLocationInGoogleMaps(map.center.latitude, map.center.longitude) - break - case contextMenu.actions.COPY_LOCATION_DECIMAL: - mapHelper.copyToClipboardCoordinates(map.center, false) - break - case contextMenu.actions.COPY_LOCATION_SEXAGESIMAL: - mapHelper.copyToClipboardCoordinates(map.center, true) - break - case contextMenu.actions.SELECT_VISIBLE_LOCATIONS: - mapHelper.selectVisibleLocations() - break - } - } - } -} diff --git a/mobile-widgets/qml/MapWidgetContextMenu.qml b/mobile-widgets/qml/MapWidgetContextMenu.qml deleted file mode 100644 index 17450a729..000000000 --- a/mobile-widgets/qml/MapWidgetContextMenu.qml +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -import QtQuick 2.0 - -Item { - id: container - signal actionSelected(int action) - - readonly property var actions: { - "OPEN_LOCATION_IN_GOOGLE_MAPS": 0, - "COPY_LOCATION_DECIMAL": 1, - "COPY_LOCATION_SEXAGESIMAL": 2, - "SELECT_VISIBLE_LOCATIONS": 3 - } - readonly property var menuItemData: [ - { idx: actions.OPEN_LOCATION_IN_GOOGLE_MAPS, itemText: qsTr("Open location in Google Maps") }, - { idx: actions.COPY_LOCATION_DECIMAL, itemText: qsTr("Copy location to clipboard (decimal)") }, - { idx: actions.COPY_LOCATION_SEXAGESIMAL, itemText: qsTr("Copy location to clipboard (sexagesimal)") }, - { idx: actions.SELECT_VISIBLE_LOCATIONS, itemText: qsTr("Select visible dive locations") } - ] - readonly property real itemTextPadding: 10.0 - readonly property real itemHeight: 34.0 - readonly property int itemAnimationDuration: 100 - readonly property color colorItemBackground: "#dedede" - readonly property color colorItemBackgroundSelected: "grey" - readonly property color colorItemText: "black" - readonly property color colorItemTextSelected: "#dedede" - readonly property color colorItemBorder: "black" - property int listViewIsVisible: -1 - property real maxItemWidth: 0.0 - - Image { - id: contextMenuImage - x: -width - source: "qrc:///mapwidget-context-menu" - - SequentialAnimation { - id:contextMenuImageAnimation - PropertyAnimation { target: contextMenuImage; property: "scale"; from: 1.0; to: 0.8; duration: 80 } - PropertyAnimation { target: contextMenuImage; property: "scale"; from: 0.8; to: 1.0; duration: 60 } - } - - MouseArea { - anchors.fill: parent - onClicked: { - contextMenuImageAnimation.restart() - listViewIsVisible = (listViewIsVisible !== 1) ? 1 : 0 - } - } - } - - ListModel { - id: listModel - property int selectedIdx: -1 - Component.onCompleted: { - for (var i = 0; i < menuItemData.length; i++) - append(menuItemData[i]); - } - } - - Component { - id: listItemDelegate - Rectangle { - color: model.idx === listModel.selectedIdx ? colorItemBackgroundSelected : colorItemBackground - width: maxItemWidth - height: itemHeight - border.color: colorItemBorder - Text { - x: itemTextPadding - height: itemHeight - verticalAlignment: Text.AlignVCenter - text: model.itemText - font.pointSize: 10.0 - color: model.idx === listModel.selectedIdx ? colorItemTextSelected : colorItemText - onWidthChanged: { - if (width + itemTextPadding * 2.0 > maxItemWidth) - maxItemWidth = width + itemTextPadding * 2.0 - } - Behavior on color { ColorAnimation { duration: itemAnimationDuration }} - } - Behavior on color { ColorAnimation { duration: itemAnimationDuration }} - } - } - - ListView { - id: listView - y: contextMenuImage.y + contextMenuImage.height + 10; - width: maxItemWidth; - height: listModel.count * itemHeight - visible: false - opacity: 0.0 - interactive: false - model: listModel - delegate: listItemDelegate - - onCountChanged: x = -maxItemWidth - onVisibleChanged: listModel.selectedIdx = -1 - onOpacityChanged: visible = opacity != 0.0 - - Timer { - id: timerListViewVisible - running: false - repeat: false - interval: itemAnimationDuration + 50 - onTriggered: listViewIsVisible = 0 - } - - MouseArea { - anchors.fill: parent - onClicked: { - if (opacity < 1.0) - return; - var idx = listView.indexAt(mouseX, mouseY) - listModel.selectedIdx = idx - container.actionSelected(idx) - timerListViewVisible.restart() - } - } - states: [ - State { when: listViewIsVisible === 1; PropertyChanges { target: listView; opacity: 1.0 }}, - State { when: listViewIsVisible === 0; PropertyChanges { target: listView; opacity: 0.0 }} - ] - transitions: Transition { NumberAnimation { properties: "opacity"; easing.type: Easing.InOutQuad }} - } -} diff --git a/mobile-widgets/qml/MapWidgetError.qml b/mobile-widgets/qml/MapWidgetError.qml deleted file mode 100644 index 346e95f07..000000000 --- a/mobile-widgets/qml/MapWidgetError.qml +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -import QtQuick 2.0 - -Item { - Text { - anchors.fill: parent - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - color: "red" - text: qsTr("MapWidget.qml failed to load! -The QML modules QtPositioning and QtLocation could be missing!") - } -} diff --git a/mobile-widgets/qml/icons/mapwidget-context-menu.png b/mobile-widgets/qml/icons/mapwidget-context-menu.png Binary files differdeleted file mode 100644 index 6ab7cf77d..000000000 --- a/mobile-widgets/qml/icons/mapwidget-context-menu.png +++ /dev/null diff --git a/mobile-widgets/qml/icons/mapwidget-marker-gray.png b/mobile-widgets/qml/icons/mapwidget-marker-gray.png Binary files differdeleted file mode 100644 index 856db9f5b..000000000 --- a/mobile-widgets/qml/icons/mapwidget-marker-gray.png +++ /dev/null diff --git a/mobile-widgets/qml/icons/mapwidget-marker-selected.png b/mobile-widgets/qml/icons/mapwidget-marker-selected.png Binary files differdeleted file mode 100644 index 57f4efa27..000000000 --- a/mobile-widgets/qml/icons/mapwidget-marker-selected.png +++ /dev/null diff --git a/mobile-widgets/qml/icons/mapwidget-marker.png b/mobile-widgets/qml/icons/mapwidget-marker.png Binary files differdeleted file mode 100644 index a1be73866..000000000 --- a/mobile-widgets/qml/icons/mapwidget-marker.png +++ /dev/null diff --git a/mobile-widgets/qml/icons/mapwidget-toggle-satellite.png b/mobile-widgets/qml/icons/mapwidget-toggle-satellite.png Binary files differdeleted file mode 100644 index 7ee536929..000000000 --- a/mobile-widgets/qml/icons/mapwidget-toggle-satellite.png +++ /dev/null diff --git a/mobile-widgets/qml/icons/mapwidget-toggle-street.png b/mobile-widgets/qml/icons/mapwidget-toggle-street.png Binary files differdeleted file mode 100644 index 04a668c3f..000000000 --- a/mobile-widgets/qml/icons/mapwidget-toggle-street.png +++ /dev/null diff --git a/mobile-widgets/qml/icons/mapwidget-zoom-in.png b/mobile-widgets/qml/icons/mapwidget-zoom-in.png Binary files differdeleted file mode 100644 index 8c2521c3e..000000000 --- a/mobile-widgets/qml/icons/mapwidget-zoom-in.png +++ /dev/null diff --git a/mobile-widgets/qml/icons/mapwidget-zoom-out.png b/mobile-widgets/qml/icons/mapwidget-zoom-out.png Binary files differdeleted file mode 100644 index bd372f17d..000000000 --- a/mobile-widgets/qml/icons/mapwidget-zoom-out.png +++ /dev/null diff --git a/mobile-widgets/qmlmapwidgethelper.cpp b/mobile-widgets/qmlmapwidgethelper.cpp deleted file mode 100644 index ba197f63f..000000000 --- a/mobile-widgets/qmlmapwidgethelper.cpp +++ /dev/null @@ -1,264 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include <QApplication> -#include <QClipboard> -#include <QGeoCoordinate> -#include <QDebug> -#include <QVector> - -#include "qmlmapwidgethelper.h" -#include "core/dive.h" -#include "core/divesite.h" -#include "core/helpers.h" -#include "qt-models/maplocationmodel.h" - -#define MIN_DISTANCE_BETWEEN_DIVE_SITES_M 50.0 -#define SMALL_CIRCLE_RADIUS_PX 26.0 - -MapWidgetHelper::MapWidgetHelper(QObject *parent) : QObject(parent) -{ - m_mapLocationModel = new MapLocationModel(this); - connect(m_mapLocationModel, SIGNAL(selectedLocationChanged(MapLocation *)), - this, SLOT(selectedLocationChanged(MapLocation *))); -} - -void MapWidgetHelper::centerOnDiveSite(struct dive_site *ds) -{ - int idx; - struct dive *dive; - QVector<struct dive_site *> selDS; - QVector<QGeoCoordinate> selGC; - QGeoCoordinate dsCoord; - - for_each_dive (idx, dive) { - struct dive_site *dss = get_dive_site_for_dive(dive); - if (!dive_site_has_gps_location(dss) || !dive->selected) - continue; - // only store dive sites with GPS - selDS.append(dss); - selGC.append(QGeoCoordinate(dss->latitude.udeg * 0.000001, - dss->longitude.udeg * 0.000001)); - } - if (!dive_site_has_gps_location(ds) && !selDS.size()) { - // only a single dive site with no GPS selected - m_mapLocationModel->setSelectedUuid(ds ? ds->uuid : 0, false); - QMetaObject::invokeMethod(m_map, "deselectMapLocation"); - - } else if (selDS.size() == 1) { - // a single dive site with GPS selected - ds = selDS.at(0); - m_mapLocationModel->setSelectedUuid(ds->uuid, false); - dsCoord.setLatitude(ds->latitude.udeg * 0.000001); - dsCoord.setLongitude(ds->longitude.udeg * 0.000001); - QMetaObject::invokeMethod(m_map, "centerOnCoordinate", Q_ARG(QVariant, QVariant::fromValue(dsCoord))); - } else if (selDS.size() > 1) { - /* more than one dive sites with GPS selected. - * find the most top-left and bottom-right dive sites on the map coordinate system. */ - ds = selDS.at(0); - m_mapLocationModel->setSelectedUuid(ds->uuid, false); - qreal minLat = 0.0, minLon = 0.0, maxLat = 0.0, maxLon = 0.0; - bool start = true; - foreach(QGeoCoordinate gc, selGC) { - qreal lat = gc.latitude(); - qreal lon = gc.longitude(); - if (start) { - minLat = maxLat = lat; - minLon = maxLon = lon; - start = false; - continue; - } - if (lat < minLat) - minLat = lat; - else if (lat > maxLat) - maxLat = lat; - if (lon < minLon) - minLon = lon; - else if (lon > maxLon) - maxLon = lon; - } - // pass rectangle coordinates to QML - QGeoCoordinate coordTopLeft(minLat, minLon); - QGeoCoordinate coordBottomRight(maxLat, maxLon); - QGeoCoordinate coordCenter(minLat + (maxLat - minLat) * 0.5, minLon + (maxLon - minLon) * 0.5); - QMetaObject::invokeMethod(m_map, "centerOnRectangle", - Q_ARG(QVariant, QVariant::fromValue(coordTopLeft)), - Q_ARG(QVariant, QVariant::fromValue(coordBottomRight)), - Q_ARG(QVariant, QVariant::fromValue(coordCenter))); - } -} - -void MapWidgetHelper::reloadMapLocations() -{ - struct dive_site *ds; - int idx; - QMap<QString, MapLocation *> locationNameMap; - m_mapLocationModel->clear(); - MapLocation *location; - QVector<MapLocation *> locationList; - qreal latitude, longitude; - - if (displayed_dive_site.uuid && dive_site_has_gps_location(&displayed_dive_site)) { - latitude = displayed_dive_site.latitude.udeg * 0.000001; - longitude = displayed_dive_site.longitude.udeg * 0.000001; - location = new MapLocation(displayed_dive_site.uuid, QGeoCoordinate(latitude, longitude), - QString(displayed_dive_site.name)); - locationList.append(location); - locationNameMap[QString(displayed_dive_site.name)] = location; - } - for_each_dive_site(idx, ds) { - if (!dive_site_has_gps_location(ds) || ds->uuid == displayed_dive_site.uuid) - continue; - latitude = ds->latitude.udeg * 0.000001; - longitude = ds->longitude.udeg * 0.000001; - QGeoCoordinate dsCoord(latitude, longitude); - QString name(ds->name); - // don't add dive locations with the same name, unless they are - // at least MIN_DISTANCE_BETWEEN_DIVE_SITES_M apart - if (locationNameMap.contains(name)) { - MapLocation *existingLocation = locationNameMap[name]; - QGeoCoordinate coord = qvariant_cast<QGeoCoordinate>(existingLocation->getRole(MapLocation::Roles::RoleCoordinate)); - if (dsCoord.distanceTo(coord) < MIN_DISTANCE_BETWEEN_DIVE_SITES_M) - continue; - } - location = new MapLocation(ds->uuid, dsCoord, name); - locationList.append(location); - locationNameMap[name] = location; - } - m_mapLocationModel->addList(locationList); -} - -void MapWidgetHelper::selectedLocationChanged(MapLocation *location) -{ - int idx; - struct dive *dive; - m_selectedDiveIds.clear(); - QGeoCoordinate locationCoord = location->coordinate(); - for_each_dive (idx, dive) { - struct dive_site *ds = get_dive_site_for_dive(dive); - if (!dive_site_has_gps_location(ds)) - continue; - const qreal latitude = ds->latitude.udeg * 0.000001; - const qreal longitude = ds->longitude.udeg * 0.000001; - QGeoCoordinate dsCoord(latitude, longitude); - if (locationCoord.distanceTo(dsCoord) < m_smallCircleRadius) - m_selectedDiveIds.append(idx); - } - emit selectedDivesChanged(m_selectedDiveIds); -} - -void MapWidgetHelper::selectVisibleLocations() -{ - int idx; - struct dive *dive; - bool selectedFirst = false; - m_selectedDiveIds.clear(); - for_each_dive (idx, dive) { - struct dive_site *ds = get_dive_site_for_dive(dive); - if (!dive_site_has_gps_location(ds)) - continue; - const qreal latitude = ds->latitude.udeg * 0.000001; - const qreal longitude = ds->longitude.udeg * 0.000001; - QGeoCoordinate dsCoord(latitude, longitude); - QPointF point; - QMetaObject::invokeMethod(m_map, "fromCoordinate", Q_RETURN_ARG(QPointF, point), - Q_ARG(QGeoCoordinate, dsCoord)); - if (!qIsNaN(point.x())) { - if (!selectedFirst) { - m_mapLocationModel->setSelectedUuid(ds->uuid, false); - selectedFirst = true; - } - m_selectedDiveIds.append(idx); - } - } - emit selectedDivesChanged(m_selectedDiveIds); -} - -/* - * Based on a 2D Map widget circle with center "coord" and radius SMALL_CIRCLE_RADIUS_PX, - * obtain a "small circle" with radius m_smallCircleRadius in meters: - * https://en.wikipedia.org/wiki/Circle_of_a_sphere - * - * The idea behind this circle is to be able to select multiple nearby dives, when clicking on - * the map. This code can be in QML, but it is in C++ instead for performance reasons. - * - * This can be made faster with an exponential regression [a * exp(b * x)], with a pretty - * decent R-squared, but it becomes bound to map provider zoom level mappings and the - * SMALL_CIRCLE_RADIUS_PX value, which makes the code hard to maintain. - */ -void MapWidgetHelper::calculateSmallCircleRadius(QGeoCoordinate coord) -{ - QPointF point; - QMetaObject::invokeMethod(m_map, "fromCoordinate", Q_RETURN_ARG(QPointF, point), - Q_ARG(QGeoCoordinate, coord)); - QPointF point2(point.x() + SMALL_CIRCLE_RADIUS_PX, point.y()); - QGeoCoordinate coord2; - QMetaObject::invokeMethod(m_map, "toCoordinate", Q_RETURN_ARG(QGeoCoordinate, coord2), - Q_ARG(QPointF, point2)); - m_smallCircleRadius = coord2.distanceTo(coord); -} - -void MapWidgetHelper::copyToClipboardCoordinates(QGeoCoordinate coord, bool formatTraditional) -{ - bool savep = prefs.coordinates_traditional; - prefs.coordinates_traditional = formatTraditional; - - const int lat = lrint(1000000.0 * coord.latitude()); - const int lon = lrint(1000000.0 * coord.longitude()); - const char *coordinates = printGPSCoords(lat, lon); - QApplication::clipboard()->setText(QString(coordinates), QClipboard::Clipboard); - - free((void *)coordinates); - prefs.coordinates_traditional = savep; -} - -void MapWidgetHelper::updateCurrentDiveSiteCoordinates(quint32 uuid, QGeoCoordinate coord) -{ - MapLocation *loc = m_mapLocationModel->getMapLocationForUuid(uuid); - if (loc) - loc->setCoordinate(coord); - displayed_dive_site.latitude.udeg = lrint(coord.latitude() * 1000000.0); - displayed_dive_site.longitude.udeg = lrint(coord.longitude() * 1000000.0); - emit coordinatesChanged(); -} - -bool MapWidgetHelper::editMode() -{ - return m_editMode; -} - -void MapWidgetHelper::setEditMode(bool editMode) -{ - m_editMode = editMode; - MapLocation *exists = m_mapLocationModel->getMapLocationForUuid(displayed_dive_site.uuid); - // if divesite uuid doesn't exist in the model, add a new MapLocation. - if (editMode && !exists) { - QGeoCoordinate coord(0.0, 0.0); - m_mapLocationModel->add(new MapLocation(displayed_dive_site.uuid, coord, - QString(displayed_dive_site.name))); - QMetaObject::invokeMethod(m_map, "centerOnCoordinate", - Q_ARG(QVariant, QVariant::fromValue(coord))); - } - emit editModeChanged(); -} - -QString MapWidgetHelper::pluginObject() -{ - QString str; - str += "import QtQuick 2.0;"; - str += "import QtLocation 5.3;"; - str += "Plugin {"; - str += " id: mapPlugin;"; - str += " name: 'googlemaps';"; - str += " PluginParameter { name: 'googlemaps.maps.language'; value: '%lang%' }"; - str += " PluginParameter { name: 'googlemaps.cachefolder'; value: '%cacheFolder%' }"; - str += " Component.onCompleted: {"; - str += " if (availableServiceProviders.indexOf(name) === -1) {"; - str += " console.warn('MapWidget.qml: cannot find a plugin named: ' + name);"; - str += " }"; - str += " }"; - str += "}"; - QString lang = uiLanguage(NULL).replace('_', '-'); - str.replace("%lang%", lang); - QString cacheFolder = QString(system_default_directory()).append("/googlemaps"); - str.replace("%cacheFolder%", cacheFolder.replace("\\", "/")); - return str; -} diff --git a/mobile-widgets/qmlmapwidgethelper.h b/mobile-widgets/qmlmapwidgethelper.h deleted file mode 100644 index 36d25d178..000000000 --- a/mobile-widgets/qmlmapwidgethelper.h +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#ifndef QMLMAPWIDGETHELPER_H -#define QMLMAPWIDGETHELPER_H - -#include <QObject> - -class QGeoCoordinate; -class MapLocationModel; -class MapLocation; -struct dive_site; - -class MapWidgetHelper : public QObject { - - Q_OBJECT - Q_PROPERTY(QObject *map MEMBER m_map) - Q_PROPERTY(MapLocationModel *model MEMBER m_mapLocationModel NOTIFY modelChanged) - Q_PROPERTY(bool editMode READ editMode WRITE setEditMode NOTIFY editModeChanged) - Q_PROPERTY(QString pluginObject READ pluginObject NOTIFY pluginObjectChanged) - -public: - explicit MapWidgetHelper(QObject *parent = NULL); - - void centerOnDiveSite(struct dive_site *); - void reloadMapLocations(); - Q_INVOKABLE void copyToClipboardCoordinates(QGeoCoordinate coord, bool formatTraditional); - Q_INVOKABLE void calculateSmallCircleRadius(QGeoCoordinate coord); - Q_INVOKABLE void updateCurrentDiveSiteCoordinates(quint32 uuid, QGeoCoordinate coord); - Q_INVOKABLE void selectVisibleLocations(); - bool editMode(); - void setEditMode(bool editMode); - QString pluginObject(); - -private: - QObject *m_map; - MapLocationModel *m_mapLocationModel; - qreal m_smallCircleRadius; - QList<int> m_selectedDiveIds; - bool m_editMode; - -private slots: - void selectedLocationChanged(MapLocation *); - -signals: - void modelChanged(); - void editModeChanged(); - void selectedDivesChanged(QList<int> list); - void coordinatesChanged(); - void pluginObjectChanged(); -}; - -extern "C" const char *printGPSCoords(int lat, int lon); - -#endif |