Warning, /education/marble/src/apps/marble-maps/MainScreen.qml is written in an unsupported language. File is not indexed.

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2015 Gábor Péterffy <peterffy95@gmail.com>
0004 // SPDX-FileCopyrightText: 2015 Dennis Nienhüser <nienhueser@kde.org>
0005 // SPDX-FileCopyrightText: 2015 Mikhail Ivchenko <ematirov@gmail.com>
0006 //
0007 
0008 import QtQuick 2.7
0009 import QtQuick.Controls 2.2
0010 import QtQuick.Window 2.2
0011 import QtQuick.Controls.Material 2.0
0012 
0013 
0014 import org.kde.marble 0.20
0015 import org.kde.kirigami 2.0 as Kirigami
0016 
0017 Kirigami.AbstractApplicationWindow {
0018     id: app
0019     title: qsTr("Marble Maps")
0020     visible: true
0021 
0022     width: 600
0023     height: 400
0024 
0025     Material.theme: Material.Light
0026     Material.accent: Material.Blue
0027 
0028     color: "#f9f9f9" // Keep the background white while no dialog is loaded
0029 
0030     property alias state: stateTracker.state
0031 
0032     property var selectedPlacemark
0033     property bool showOsmTags: false
0034     property int currentWaypointIndex: 0
0035 
0036     property real animatedMargin: app.state === "none" ? 0 : -dialogLoader.height
0037     property bool dialogExpanded: animatedMargin === -dialogLoader.height
0038     property real mapOffset: !dialogExpanded ? animatedMargin / 2 : 0
0039 
0040     Behavior on animatedMargin {
0041         NumberAnimation {
0042             id: dialogAnimation
0043             duration: 200
0044             easing.type: Easing.OutQuart
0045         }
0046     }
0047 
0048     onSelectedPlacemarkChanged: {
0049         if (!selectedPlacemark) {
0050             app.state = "none"
0051         }
0052         else {
0053             bookmarkButton.bookmark = bookmarks.isBookmark(selectedPlacemark.longitude, selectedPlacemark.latitude)
0054         }
0055     }
0056 
0057     SystemPalette{
0058         id: palette
0059         colorGroup: SystemPalette.Active
0060     }
0061 
0062     Settings {
0063         id: settings
0064     }
0065 
0066 
0067     property bool aboutToQuit: false
0068 
0069     onClosing: {
0070         if (app.aboutToQuit || Qt.platform.os !== "android") {
0071             close.accepted = true // we will quit
0072             return
0073         } else if (sidePanel.drawerOpen) {
0074             sidePanel.close()
0075         } else if (pageStack.depth > 1) {
0076             pageStack.pop()
0077         } else if (navigationManager.visible) {
0078             navigationManager.visible = false
0079         } else if (app.state !== "none") {
0080             app.state = "none"
0081         } else if(search.searchResultsVisible.visible){
0082             search.searchResultsVisible = false
0083         }
0084         else {
0085             if(search.searchResultsVisible){
0086                 search.searchResultsVisible = false
0087             }
0088             app.aboutToQuit = true
0089             quitHelper.visible = true
0090         }
0091         close.accepted = false
0092     }
0093 
0094     globalDrawer: Kirigami.GlobalDrawer {
0095         id: sidePanel
0096         title: qsTr("Settings")
0097 
0098         handleVisible: false
0099         property alias showAccessibility: accessibilityAction.checked
0100 
0101         Settings {
0102             id: sidePanelSettings
0103             property bool showUpdateInfo: Number(value("MarbleMaps", "updateInfoVersion", "0")) < 1
0104             Component.onDestruction: {
0105                 sidePanelSettings.setValue("MarbleMaps", "showAccessibility", accessibilityAction.checked ? "true" : "false")
0106             }
0107         }
0108 
0109         actions: [
0110             Kirigami.Action {
0111                 id: publicTransportAction
0112                 text: qsTr("Public Transport")
0113                 checkable: true
0114                 checked: marbleMaps.showPublicTransport
0115                 iconName: "qrc:///material/directions-bus.svg"
0116                 visible: true
0117                 onTriggered: {
0118                     sidePanel.close()
0119                     marbleMaps.showPublicTransport = checked
0120                     publicTransportDialog.open()
0121                 }
0122             },
0123             Kirigami.Action {
0124                 id: outdoorActivitiesAction
0125                 checkable: true
0126                 checked: marbleMaps.showOutdoorActivities
0127                 text: qsTr("Outdoor Activities")
0128                 visible: true
0129                 iconName: "qrc:///material/directions-run.svg"
0130                 onTriggered: {
0131                     sidePanel.close()
0132                     marbleMaps.showOutdoorActivities = checked
0133                 }
0134             },
0135             Kirigami.Action {
0136                 id: accessibilityAction
0137                 checkable: true
0138                 checked: settings.value("MarbleMaps", "showAccessibility", "false") === "true"
0139                 text: qsTr("Accessibility")
0140                 visible: true
0141                 iconName: "qrc:///material/wheelchair.svg"
0142                 onTriggered: {
0143                     sidePanelSettings.value("MarbleMaps", "showAccessibility", "false") === "true"
0144                 }
0145             },
0146             Kirigami.Action{ enabled: false},
0147             Kirigami.Action {
0148                 text: qsTr("About")
0149                 iconName: "qrc:///marble.svg"
0150                 visible: true
0151                 onTriggered: {
0152                     app.state = "about"
0153                     sidePanel.close()
0154                     source = ""
0155                     app.pageStack.push("qrc:///AboutDialog.qml")
0156                 }
0157             },
0158             Kirigami.Action {
0159                 text: qsTr("Bookmarks")
0160                 iconName: "qrc:///material/star.svg"
0161                 onTriggered: {
0162                     app.state = "bookmarks"
0163                     sidePanel.close()
0164                     app.pageStack.push("qrc:///Bookmarks.qml")
0165                 }
0166             },
0167             Kirigami.Action {
0168                 text: qsTr("Layer Options")
0169                 iconName: "qrc:///settings.png"
0170                 onTriggered: {
0171                     app.state = "options"
0172                     sidePanel.close()
0173                     app.pageStack.push("qrc:///Options.qml")
0174                 }
0175             },
0176             Kirigami.Action {
0177                 text: qsTr("Routing")
0178                 iconName: "qrc:///material/directions.svg"
0179                 onTriggered: {
0180                     app.state = "route"
0181                 }
0182             }
0183         ]
0184 
0185         Binding {
0186             target: pageStack.currentItem
0187             property: "marbleQuickItem"
0188             value: marbleMaps
0189             when: app.state === "bookmarks"
0190         }
0191     }
0192 
0193     pageStack: StackView {
0194         anchors.fill: parent
0195         initialItem: page
0196     }
0197 
0198     Kirigami.Page {
0199         id: page
0200         padding: 0
0201         topPadding: 0
0202         leftPadding: 0
0203         rightPadding: 0
0204         bottomPadding: 0
0205         title: qsTr("Marble Maps")
0206 
0207         Item {
0208             id: mapItem
0209 
0210             width: parent.width
0211             height: parent.height - dialogLoader.height - bottomMenu.height
0212 
0213             PinchArea {
0214                 anchors.fill: parent
0215                 enabled: true
0216 
0217                 onPinchStarted: marbleMaps.handlePinchStarted(pinch.center)
0218                 onPinchFinished: marbleMaps.handlePinchFinished(pinch.center)
0219                 onPinchUpdated: marbleMaps.handlePinchUpdated(pinch.center, pinch.scale);
0220 
0221                 MarbleMaps {
0222                     id: marbleMaps
0223 
0224                     property string currentPositionProvider: "QtPositioning"
0225                     property bool wlanOnly: false
0226                     property bool smallZoom : radius < 2 * Math.max(app.width, app.height)
0227 
0228                     anchors.fill: parent
0229                     visible: true
0230 
0231                     // Theme settings.
0232                     projection: smallZoom ? MarbleItem.Spherical : MarbleItem.Mercator
0233                     mapThemeId: settings.value("MarbleMaps", "mapThemeId", "earth/vectorosm/vectorosm.dgml")
0234 
0235                     // Visibility of layers/plugins.
0236                     showFrameRate: false
0237                     showAtmosphere: smallZoom
0238                     showCompass: false
0239                     showClouds: false
0240                     showCrosshairs: false
0241                     showGrid: smallZoom
0242                     showOverviewMap: false
0243                     showOtherPlaces: false
0244                     showScaleBar: false
0245                     showBackground: smallZoom
0246                     showPublicTransport: settings.value("MarbleMaps", "showPublicTransport", "false") === "true"
0247                     positionProvider: suspended ? "" : currentPositionProvider
0248                     keepScreenOn: !suspended && navigationManager.guidanceModeEnabled
0249                     showPositionMarker: false
0250                     animationViewContext: dialogAnimation.running
0251 
0252                     placemarkDelegate: Image {
0253                         id: balloon
0254                         property int xPos: 0
0255                         property int yPos: 0
0256                         property real animationOffset: 0
0257                         property var placemark: null
0258                         x: xPos - 0.5 * width
0259                         y: yPos - height - 30 * Screen.pixelDensity * animationOffset
0260                         opacity: 1.0 - animationOffset
0261 
0262                         Connections {
0263                             target: app
0264                             onSelectedPlacemarkChanged:  balloonAnimation.restart()
0265                         }
0266 
0267                         NumberAnimation {
0268                             id: balloonAnimation
0269                             target: balloon
0270                             property: "animationOffset"
0271                             from: 1
0272                             to: 0
0273                             duration: 1000
0274                             easing.type: Easing.OutBounce
0275                         }
0276 
0277 
0278                         width: Screen.pixelDensity*6
0279                         height: width
0280                         source: "qrc:///ic_place.png"
0281                         onPlacemarkChanged: {
0282                             app.selectedPlacemark = placemark
0283                             if (placemark) {
0284                                 app.state = "place"
0285                             } else {
0286                                 app.state = "none"
0287                             }
0288                         }
0289                     }
0290 
0291                     onPositionAvailableChanged: {
0292                         updateIndicator();
0293                     }
0294                     onPositionVisibleChanged: {
0295                         updateIndicator();
0296                     }
0297                     onVisibleLatLonAltBoxChanged: {
0298                         !panningDetectionTimer.restart();
0299                         updateIndicator();
0300                     }
0301                     onCurrentPositionChanged: {
0302                         updateIndicator();
0303                     }
0304 
0305                     onZoomChanged: {
0306                         zoomDetectionTimer.restart()
0307                     }
0308 
0309                     Component.onCompleted: {
0310                         setPluginSetting("coordinate-grid", "gridColor", "#999999");
0311                         setPluginSetting("coordinate-grid", "tropicsColor", "#888888");
0312                         setPluginSetting("coordinate-grid", "equatorColor", "#777777");
0313                         setPluginSetting("coordinate-grid", "primaryLabels", "false");
0314                         setPluginSetting("coordinate-grid", "secondaryLabels", "false");
0315                         marbleMaps.loadSettings()
0316                     }
0317                     Component.onDestruction: marbleMaps.writeSettings()
0318 
0319                     Connections {
0320                         target: Qt.application
0321                         onStateChanged: {
0322                             if (Qt.application.state === Qt.ApplicationInactive || Qt.application.state === Qt.ApplicationSuspended) {
0323                                 marbleMaps.writeSettings()
0324                             }
0325                         }
0326                     }
0327 
0328                     function updateIndicator() {
0329                         if ( !positionVisible && positionAvailable ) {
0330                             zoomToPositionButton.updateIndicator();
0331                         }
0332                     }
0333 
0334                     RoutingManager {
0335                         id: routingManager
0336                         anchors.fill: parent
0337                         marbleItem: marbleMaps
0338                         visible: hasRoute
0339 
0340                         function addToRoute() {
0341                             ensureRouteHasDeparture()
0342                             routingManager.addViaByPlacemarkAtIndex(routingManager.waypointCount(), selectedPlacemark)
0343                             routingManager.clearSearchResultPlacemarks()
0344                             selectedPlacemark = null
0345                             app.state = "route"
0346                         }
0347                         function ensureRouteHasDeparture() {
0348                             if (routingManager.routeRequestModel.count === 0) {
0349                                 if (marbleMaps.positionAvailable) {
0350                                     routingManager.addViaByPlacemark(marbleMaps.currentPosition)
0351                                 }
0352                             }
0353                         }
0354 
0355                     }
0356 
0357                     Timer {
0358                         id: zoomDetectionTimer
0359                         interval: 1000
0360                     }
0361                     Timer {
0362                         id: panningDetectionTimer
0363                         interval: 1000
0364                     }
0365 
0366                     PositionMarker {
0367                         id: positionMarker
0368                         x: navigationManager.snappedPositionMarkerScreenPosition.x - positionMarker.width / 2
0369                         y: navigationManager.snappedPositionMarkerScreenPosition.y - positionMarker.height / 2
0370                         angle: marbleMaps.angle
0371                         visible: marbleMaps.positionAvailable && marbleMaps.positionVisible
0372                         radius: navigationManager.screenAccuracy / 2
0373                         showAccuracy: navigationManager.deviated
0374                         allowRadiusAnimation: !zoomDetectionTimer.running
0375                         allowPositionAnimation: !panningDetectionTimer.running
0376                         speed: marbleMaps.speed
0377 
0378                         MouseArea {
0379                             anchors.fill: parent
0380                             onPressed: app.state = "position"
0381                         }
0382                     }
0383 
0384                     MouseArea {
0385                         anchors.fill: parent
0386                         propagateComposedEvents: true
0387                         onPressed: {
0388                             marbleMaps.focus = true;
0389                             mouse.accepted = false;
0390                         }
0391                     }
0392                 }
0393 
0394                 NavigationManager {
0395                     id: navigationManager
0396                     width: parent.width
0397                     height: parent.height
0398                     visible: false
0399                     marbleItem: marbleMaps
0400                     hasRoute: routingManager.hasRoute
0401                 }
0402             }
0403 
0404             BoxedText {
0405                 id: distanceIndicator
0406                 text: qsTr("%1 km").arg(zoomToPositionButton.distance < 10 ? zoomToPositionButton.distance.toFixed(1) : zoomToPositionButton.distance.toFixed(0))
0407                 anchors {
0408                     bottom: zoomToPositionButton.top
0409                     horizontalCenter: zoomToPositionButton.horizontalCenter
0410                 }
0411 
0412                 visible: marbleMaps.positionAvailable && !marbleMaps.positionVisible
0413             }
0414 
0415             PositionButton {
0416                 id: zoomToPositionButton
0417                 anchors {
0418                     right: parent.right
0419                     rightMargin: Screen.pixelDensity * 1
0420                     bottom: mapItem.bottom
0421                     bottomMargin: 10
0422                 }
0423 
0424                 enabled: marbleMaps.positionAvailable
0425 
0426                 iconSource: marbleMaps.positionAvailable ? "qrc:///gps_fixed.png" : "qrc:///gps_not_fixed.png"
0427 
0428                 onClicked: marbleMaps.centerOnCurrentPosition()
0429 
0430                 property real distance: 0
0431 
0432                 function updateIndicator() {
0433                     var point = marbleMaps.mapFromItem(zoomToPositionButton, diameter * 0.5, diameter * 0.5);
0434                     distance = 0.001 * marbleMaps.distanceFromPointToCurrentLocation(point);
0435                     angle = marbleMaps.angleFromPointToCurrentLocation(point);
0436                 }
0437 
0438                 showDirection: marbleMaps.positionAvailable && !marbleMaps.positionVisible
0439             }
0440         }
0441 
0442 
0443         Row {
0444             id: bottomMenu
0445             anchors.left: parent.left
0446             anchors.right: parent.right
0447             anchors.bottom: dialogLoader.top
0448             width: parent.width
0449             height: bottomMenu.visible ? routeEditorButton.height + Screen.pixelDensity * 2 : 0
0450             anchors.topMargin: app.animatedMargin
0451             visible: app.state === "place" || app.state === "route"
0452 
0453             onVisibleChanged: bottomMenuAnimation.start()
0454 
0455             NumberAnimation {
0456                 id: bottomMenuAnimation
0457                 target: bottomMenu
0458                 property: "y"
0459                 from: app.height - bottomMenu.height
0460                 to: 0
0461                 duration: 500
0462                 easing.type: Easing.InExpo
0463             }
0464 
0465             Item {
0466                 id: bottomMenuBackground
0467                 anchors.fill: parent
0468                 Rectangle {
0469                     color: Material.accent
0470                     anchors.fill : parent
0471                 }
0472             }
0473 
0474             Row {
0475                 anchors.centerIn: parent
0476                 spacing: Kirigami.Units.gridUnit * 2
0477 
0478                 FlatButton {
0479                     id: routeEditorButton
0480                     property string currentProfileIcon: "qrc:///material/directions-car.svg"
0481                     height: Screen.pixelDensity * 6
0482                     width: height
0483                     enabled: app.state !== "route" || routingManager.hasRoute
0484                     imageSource: "qrc:///material/directions.svg"
0485 
0486                     onClicked: {
0487                         if (app.state === "route") {
0488                             app.state = "none"
0489                             navigationManager.visible = true
0490                         } else if (app.state === "place") {
0491                             app.state = "route"
0492                             routingManager.addToRoute()
0493                         } else {
0494                             app.state = "route"
0495                             navigationManager.visible = false
0496                         }
0497                     }
0498                     states: [
0499                         State {
0500                             name: ""
0501                             PropertyChanges { target: routeEditorButton; imageSource: "qrc:///material/directions.svg"; }
0502                         },
0503                         State {
0504                             name: "routingAction"
0505                             when: app.state === "route"
0506                             PropertyChanges { target: routeEditorButton; imageSource: "qrc:///material/navigation.svg"; }
0507                         },
0508                         State {
0509                             name: "placeAction"
0510                             when: app.state === "place"
0511                             PropertyChanges { target: routeEditorButton; imageSource: "qrc:///material/directions.svg" }
0512                         }
0513                     ]
0514                 }
0515 
0516                 FlatButton {
0517                     id: bookmarkButton
0518                     anchors.verticalCenter: parent.verticalCenter
0519                     height: Screen.pixelDensity * 6
0520                     width: height
0521                     property bool bookmark: bookmarks.isBookmark(app.selectedPlacemark.longitude, app.selectedPlacemark.latitude)
0522                     enabled: app.state === "place"
0523                     visible: app.state === "place"
0524                     imageSource: bookmark ? "qrc:///material/star.svg" : "qrc:///material/star_border.svg"
0525                     onClicked: {
0526                         if (bookmarkButton.bookmark) {
0527                             bookmarks.removeBookmark(app.selectedPlacemark.longitude, app.selectedPlacemark.latitude)
0528                         } else {
0529                             bookmarks.addBookmark(app.selectedPlacemark, "Default")
0530                         }
0531                         bookmarkButton.bookmark = !bookmarkButton.bookmark
0532                     }
0533                 }
0534             }
0535         }
0536 
0537 
0538         BorderImage {
0539             anchors.top: mapItem.bottom
0540             anchors.bottom: dialogLoader.bottom
0541             anchors.right: parent.right
0542             anchors.left: parent.left
0543             anchors.margins: -14
0544             border { top: 14; left: 14; right: 14; bottom: 14 }
0545             source: "qrc:///border_shadow.png"
0546         }
0547 
0548         Search {
0549             id: search
0550             anchors.fill: parent
0551             marbleQuickItem: marbleMaps
0552             visible: !navigationManager.visible
0553 
0554             onItemSelected: {
0555                 if (routingManager) {
0556                     routingManager.addSearchResultAsPlacemark(suggestedPlacemark);
0557                 }
0558                 app.selectedPlacemark = suggestedPlacemark;
0559                 app.state = "place"
0560             }
0561             onMenuButtonClicked: sidePanel.open()
0562         }
0563 
0564         Loader {
0565             id: dialogLoader
0566             focus: true
0567             width: childrenRect.width
0568             height : childrenRect.height
0569 
0570             anchors {
0571                 left: parent.left
0572                 right: parent.right
0573                 top: parent.bottom
0574                 bottom: bottomMenu.top
0575                 topMargin: app.animatedMargin
0576                 bottomMargin: Kirigami.Units.gridUnits * 10
0577             }
0578 
0579             NumberAnimation {
0580                 id: loaderAnimation
0581                 target: dialogLoader.item
0582                 property: "y"
0583                 from: dialogLoader.height === 0 ? app.height : app.height - dialogLoader.item.height
0584                 to: 0
0585                 duration: 500
0586                 easing.type: Easing.InExpo
0587             }
0588 
0589             onLoaded: {
0590                 app.state != "none" ? loaderAnimation.running = true : loaderAnimation.running = false
0591                 if (app.state === "place") {
0592                     dialogLoader.item.map = marbleMaps
0593                     dialogLoader.item.placemark = app.selectedPlacemark
0594                     dialogLoader.item.showOsmTags = app.showOsmTags
0595                     dialogLoader.item.showAccessibility = sidePanel.showAccessibility
0596                 } else if (app.state === "route") {
0597                     item.routingManager = routingManager
0598                     item.routingProfile = routingManager.routingProfile
0599                     item.currentIndex =  Qt.binding(function() { return app.currentWaypointIndex })
0600                 } else if (app.state == "position") {
0601                     dialogLoader.item.map = marbleMaps
0602                     dialogLoader.item.navigationManager = navigationManager
0603                 } else if (app.state == "none"){
0604                     dialogLoader.height = 0
0605                 }
0606             }
0607 
0608             Connections {
0609                 target: dialogLoader.item
0610                 onCurrentProfileIconChanged: routeEditorButton.currentProfileIcon = dialogLoader.item.currentProfileIcon
0611                 ignoreUnknownSignals: true
0612             }
0613         }
0614 
0615         Rectangle {
0616             width: parent.width
0617             color: Kirigami.Theme.textColor
0618             opacity: 0.4
0619             height: 1
0620             anchors.bottom: dialogLoader.top
0621         }
0622 
0623         Item {
0624             id: stateTracker
0625             state: "none"
0626 
0627             states: [
0628                 State {
0629                     name: "none"
0630                     PropertyChanges { target: dialogLoader; source: "" }
0631                 },
0632                 State {
0633                     name: "position"
0634                     PropertyChanges { target: dialogLoader; source: "CurrentPosition.qml" }
0635                 },
0636                 State {
0637                     name: "route"
0638                     PropertyChanges { target: dialogLoader; source: "RouteEditor.qml" }
0639                 },
0640                 State {
0641                     name: "place"
0642                     PropertyChanges { target: dialogLoader; source: "PlacemarkDialog.qml" }
0643                 },
0644                 State {
0645                     name: "about"
0646                     PropertyChanges { target: dialogLoader; source: "" }
0647                 },
0648                 State {
0649                     name: "settings"
0650                     PropertyChanges { target: dialogLoader; source: "SettingsDialog.qml" }
0651                 },
0652                 State {
0653                     name: "developer"
0654                     PropertyChanges { target: dialogLoader; source: "DeveloperDialog.qml" }
0655                 },
0656                 State {
0657                     name: "options"
0658                     PropertyChanges { target: dialogLoader; source: "" }
0659                 },
0660                 State {
0661                     name: "bookmarks"
0662                     PropertyChanges { target: dialogLoader; source: "" }
0663                 }
0664             ]
0665         }
0666 
0667         BoxedText {
0668             id: quitHelper
0669             visible: false
0670             text: qsTr("Press again to close.")
0671             anchors.bottom: parent.bottom
0672             anchors.bottomMargin: Screen.pixelDensity * 5
0673             anchors.horizontalCenter: parent.horizontalCenter
0674             onVisibleChanged: {
0675                 if (visible) {
0676                     quitTimer.restart()
0677                 }
0678             }
0679 
0680             Timer {
0681                 id: quitTimer
0682                 interval: 3000;
0683                 running: false;
0684                 repeat: false
0685                 onTriggered: {
0686                     app.aboutToQuit = false
0687                     quitHelper.visible = false
0688                 }
0689             }
0690         }
0691 
0692         Bookmarks {
0693             id: bookmarks
0694             map: marbleMaps
0695         }
0696     }
0697 }
0698