Qt 5.9 | Qt Location | Map Viewer (QML) | mapviewer.qml Example File

Qt 5.9.4 Reference Documentation

# mapviewer.qml Example File

mapviewer/mapviewer.qml

      /****************************************************************************
      **
      ** Copyright (C) 2017 The Qt Company Ltd.
      ** Contact: https://www.qt.io/licensing/
      **
      ** This file is part of the examples of the Qt Toolkit.
      **
      ** $QT_BEGIN_LICENSE:BSD$
      ** Commercial License Usage
      ** Licensees holding valid commercial Qt licenses may use this file in
      ** accordance with the commercial license agreement provided with the
      ** Software or, alternatively, in accordance with the terms contained in
      ** a written agreement between you and The Qt Company. For licensing terms
      ** and conditions see https://www.qt.io/terms-conditions. For further
      ** information use the contact form at https://www.qt.io/contact-us.
      **
      ** BSD License Usage
      ** Alternatively, you may use this file under the terms of the BSD license
      ** as follows:
      **
      ** "Redistribution and use in source and binary forms, with or without
      ** modification, are permitted provided that the following conditions are
      ** met:
      **   * Redistributions of source code must retain the above copyright
      **     notice, this list of conditions and the following disclaimer.
      **   * Redistributions in binary form must reproduce the above copyright
      **     notice, this list of conditions and the following disclaimer in
      **     the documentation and/or other materials provided with the
      **     distribution.
      **   * Neither the name of The Qt Company Ltd nor the names of its
      **     contributors may be used to endorse or promote products derived
      **     from this software without specific prior written permission.
      **
      **
      ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
      **
      ** $QT_END_LICENSE$
      **
      ****************************************************************************/

      import QtQuick 2.5
      import QtQuick.Controls 1.4
      import QtLocation 5.6
      import QtPositioning 5.5
      import "map"
      import "menus"
      import "helper.js" as Helper

      ApplicationWindow {
          id: appWindow
          property variant map
          property variant minimap
          property variant parameters

          //defaults
          property variant fromCoordinate: QtPositioning.coordinate(59.9483, 10.7695)
          property variant toCoordinate: QtPositioning.coordinate(59.9645, 10.671)

          function createMap(provider)
          {
              var plugin

              if (parameters && parameters.length>0)
                  plugin = Qt.createQmlObject ('import QtLocation 5.6; Plugin{ name:"' + provider + '"; parameters: appWindow.parameters}', appWindow)
              else
                  plugin = Qt.createQmlObject ('import QtLocation 5.6; Plugin{ name:"' + provider + '"}', appWindow)

              if (minimap) {
                  minimap.destroy()
                  minimap = null
              }

              var zoomLevel = null
              var tilt = null
              var bearing = null
              var fov = null
              var center = null
              var panelExpanded = null
              if (map) {
                  zoomLevel = map.zoomLevel
                  tilt = map.tilt
                  bearing = map.bearing
                  fov = map.fieldOfView
                  center = map.center
                  panelExpanded = map.slidersExpanded
                  map.destroy()
              }

              map = mapComponent.createObject(page);
              map.plugin = plugin;

              if (zoomLevel != null) {
                  map.tilt = tilt
                  map.bearing = bearing
                  map.fieldOfView = fov
                  map.zoomLevel = zoomLevel
                  map.center = center
                  map.slidersExpanded = panelExpanded
              } else {
                  // Use an integer ZL to enable nearest interpolation, if possible.
                  map.zoomLevel = Math.floor((map.maximumZoomLevel - map.minimumZoomLevel)/2)
                  // defaulting to 45 degrees, if possible.
                  map.fieldOfView = Math.min(Math.max(45.0, map.minimumFieldOfView), map.maximumFieldOfView)
              }

              map.forceActiveFocus()
          }

          function getPlugins()
          {
              var plugin = Qt.createQmlObject ('import QtLocation 5.6; Plugin {}', appWindow)
              var myArray = new Array()
              for (var i = 0; i<plugin.availableServiceProviders.length; i++) {
                  var tempPlugin = Qt.createQmlObject ('import QtLocation 5.6; Plugin {name: "' + plugin.availableServiceProviders[i]+ '"}', appWindow)
                  if (tempPlugin.supportsMapping())
                      myArray.push(tempPlugin.name)
              }
              myArray.sort()
              return myArray
          }

          function initializeProviders(pluginParameters)
          {
              var parameters = new Array()
              for (var prop in pluginParameters){
                  var parameter = Qt.createQmlObject('import QtLocation 5.6; PluginParameter{ name: "'+ prop + '"; value: "' + pluginParameters[prop]+'"}',appWindow)
                  parameters.push(parameter)
              }
              appWindow.parameters = parameters
              var plugins = getPlugins()
              mainMenu.providerMenu.createMenu(plugins)
              for (var i = 0; i<plugins.length; i++) {
                  if (plugins[i] === "osm")
                      mainMenu.selectProvider(plugins[i])
              }
          }

          title: qsTr("Mapviewer")
          height: 640
          width: 360
          visible: true
          menuBar: mainMenu

          Address {
              id :fromAddress
              street: "Sandakerveien 116"
              city: "Oslo"
              country: "Norway"
              state : ""
              postalCode: "0484"
          }

          Address {
              id: toAddress
              street: "Holmenkollveien 140"
              city: "Oslo"
              country: "Norway"
              postalCode: "0791"
          }

          MainMenu {
              id: mainMenu

              function toggleMiniMapState()
              {
                  if (minimap) {
                      minimap.destroy()
                      minimap = null
                  } else {
                      minimap = Qt.createQmlObject ('import "map"; MiniMap{ z: map.z + 2 }', map)
                  }
              }

              function setLanguage(lang)
              {
                  map.plugin.locales = lang;
                  stackView.pop(page)
              }

              onSelectProvider: {
                  stackView.pop()
                  for (var i = 0; i < providerMenu.items.length; i++) {
                      providerMenu.items[i].checked = providerMenu.items[i].text === providerName
                  }

                  createMap(providerName)
                  if (map.error === Map.NoError) {
                      selectMapType(map.activeMapType)
                      toolsMenu.createMenu(map);
                  } else {
                      mapTypeMenu.clear();
                      toolsMenu.clear();
                  }
              }

              onSelectMapType: {
                  stackView.pop(page)
                  for (var i = 0; i < mapTypeMenu.items.length; i++) {
                      mapTypeMenu.items[i].checked = mapTypeMenu.items[i].text === mapType.name
                  }
                  map.activeMapType = mapType
              }

              onSelectTool: {
                  switch (tool) {
                  case "AddressRoute":
                      stackView.pop({item:page, immediate: true})
                      stackView.push({ item: Qt.resolvedUrl("forms/RouteAddress.qml") ,
                                         properties: { "plugin": map.plugin,
                                             "toAddress": toAddress,
                                             "fromAddress": fromAddress}})
                      stackView.currentItem.showRoute.connect(map.calculateCoordinateRoute)
                      stackView.currentItem.showMessage.connect(stackView.showMessage)
                      stackView.currentItem.closeForm.connect(stackView.closeForm)
                      break
                  case "CoordinateRoute":
                      stackView.pop({item:page, immediate: true})
                      stackView.push({ item: Qt.resolvedUrl("forms/RouteCoordinate.qml") ,
                                         properties: { "toCoordinate": toCoordinate,
                                             "fromCoordinate": fromCoordinate}})
                      stackView.currentItem.showRoute.connect(map.calculateCoordinateRoute)
                      stackView.currentItem.closeForm.connect(stackView.closeForm)
                      break
                  case "Geocode":
                      stackView.pop({item:page, immediate: true})
                      stackView.push({ item: Qt.resolvedUrl("forms/Geocode.qml") ,
                                         properties: { "address": fromAddress}})
                      stackView.currentItem.showPlace.connect(map.geocode)
                      stackView.currentItem.closeForm.connect(stackView.closeForm)
                      break
                  case "RevGeocode":
                      stackView.pop({item:page, immediate: true})
                      stackView.push({ item: Qt.resolvedUrl("forms/ReverseGeocode.qml") ,
                                         properties: { "coordinate": fromCoordinate}})
                      stackView.currentItem.showPlace.connect(map.geocode)
                      stackView.currentItem.closeForm.connect(stackView.closeForm)
                      break
                  case "Language":
                      stackView.pop({item:page, immediate: true})
                      stackView.push({ item: Qt.resolvedUrl("forms/Locale.qml") ,
                                         properties: { "locale":  map.plugin.locales[0]}})
                      stackView.currentItem.selectLanguage.connect(setLanguage)
                      stackView.currentItem.closeForm.connect(stackView.closeForm)
                      break
                  case "Clear":
                      map.clearData()
                      break
                  case "Prefetch":
                      map.prefetchData()
                      break
                  default:
                      console.log("Unsupported operation")
                  }
              }

              onToggleMapState: {
                  stackView.pop(page)
                  switch (state) {
                  case "FollowMe":
                      map.followme = !map.followme
                      break
                  case "MiniMap":
                      toggleMiniMapState()
                      isMiniMap = minimap
                      break
                  default:
                      console.log("Unsupported operation")
                  }
              }
          }

          MapPopupMenu {
              id: mapPopupMenu

              function show(coordinate)
              {
                  stackView.pop(page)
                  mapPopupMenu.coordinate = coordinate
                  mapPopupMenu.markersCount = map.markers.length
                  mapPopupMenu.mapItemsCount = map.mapItems.length
                  mapPopupMenu.update()
                  mapPopupMenu.popup()
              }

              onItemClicked: {
                  stackView.pop(page)
                  switch (item) {
                  case "addMarker":
                      map.addMarker()
                      break
                  case "getCoordinate":
                      map.coordinatesCaptured(coordinate.latitude, coordinate.longitude)
                      break
                  case "fitViewport":
                      map.fitViewportToMapItems()
                      break
                  case "deleteMarkers":
                      map.deleteMarkers()
                      break
                  case "deleteItems":
                      map.deleteMapItems()
                      break
                  default:
                      console.log("Unsupported operation")
                  }
              }
          }

          MarkerPopupMenu {
              id: markerPopupMenu

              function show(coordinate)
              {
                  stackView.pop(page)
                  markerPopupMenu.markersCount = map.markers.length
                  markerPopupMenu.update()
                  markerPopupMenu.popup()
              }

              function askForCoordinate()
              {
                  stackView.push({ item: Qt.resolvedUrl("forms/ReverseGeocode.qml") ,
                                     properties: { "title": qsTr("New Coordinate"),
                                         "coordinate":   map.markers[map.currentMarker].coordinate}})
                  stackView.currentItem.showPlace.connect(moveMarker)
                  stackView.currentItem.closeForm.connect(stackView.closeForm)
              }

              function moveMarker(coordinate)
              {
                  map.markers[map.currentMarker].coordinate = coordinate;
                  map.center = coordinate;
                  stackView.pop(page)
              }

              onItemClicked: {
                  stackView.pop(page)
                  switch (item) {
                  case "deleteMarker":
                      map.deleteMarker(map.currentMarker)
                      break;
                  case "getMarkerCoordinate":
                      map.coordinatesCaptured(map.markers[map.currentMarker].coordinate.latitude, map.markers[map.currentMarker].coordinate.longitude)
                      break;
                  case "moveMarkerTo":
                      askForCoordinate()
                      break;
                  case "routeToNextPoint":
                  case "routeToNextPoints":
                      map.calculateMarkerRoute()
                      break
                  case "distanceToNextPoint":
                      var coordinate1 = map.markers[currentMarker].coordinate;
                      var coordinate2 = map.markers[currentMarker+1].coordinate;
                      var distance = Helper.formatDistance(coordinate1.distanceTo(coordinate2));
                      stackView.showMessage(qsTr("Distance"),"<b>" + qsTr("Distance:") + "</b> " + distance)
                      break
                  case "drawImage":
                      map.addGeoItem("ImageItem")
                      break
                  case "drawRectangle":
                      map.addGeoItem("RectangleItem")
                      break
                  case "drawCircle":
                      map.addGeoItem("CircleItem")
                      break;
                  case "drawPolyline":
                      map.addGeoItem("PolylineItem")
                      break;
                  case "drawPolygonMenu":
                      map.addGeoItem("PolygonItem")
                      break
                  default:
                      console.log("Unsupported operation")
                  }
              }
          }

          ItemPopupMenu {
              id: itemPopupMenu

              function show(type,coordinate)
              {
                  stackView.pop(page)
                  itemPopupMenu.type = type
                  itemPopupMenu.update()
                  itemPopupMenu.popup()
              }

              onItemClicked: {
                  stackView.pop(page)
                  switch (item) {
                  case "showRouteInfo":
                      stackView.showRouteListPage()
                      break;
                  case "deleteRoute":
                      map.routeModel.reset();
                      break;
                  case "showPointInfo":
                      map.showGeocodeInfo()
                      break;
                  case "deletePoint":
                      map.geocodeModel.reset()
                      break;
                  default:
                      console.log("Unsupported operation")
                  }
              }
          }

          StackView {
              id: stackView
              anchors.fill: parent
              focus: true
              initialItem: Item {
                  id: page
              }

              function showMessage(title,message,backPage)
              {
                  push({ item: Qt.resolvedUrl("forms/Message.qml") ,
                                     properties: {
                                         "title" : title,
                                         "message" : message,
                                         "backPage" : backPage
                                     }})
                  currentItem.closeForm.connect(closeMessage)
              }

              function closeMessage(backPage)
              {
                  pop(backPage)
              }

              function closeForm()
              {
                  pop(page)
              }

              function showRouteListPage()
              {
                  push({ item: Qt.resolvedUrl("forms/RouteList.qml") ,
                                     properties: {
                                         "routeModel" : map.routeModel
                                     }})
                  currentItem.closeForm.connect(closeForm)
              }
          }

          Component {
              id: mapComponent

              MapComponent{
                  width: page.width
                  height: page.height
                  onFollowmeChanged: mainMenu.isFollowMe = map.followme
                  onSupportedMapTypesChanged: mainMenu.mapTypeMenu.createMenu(map)
                  onCoordinatesCaptured: {
                      var text = "<b>" + qsTr("Latitude:") + "</b> " + Helper.roundNumber(latitude,4) + "<br/><b>" + qsTr("Longitude:") + "</b> " + Helper.roundNumber(longitude,4)
                      stackView.showMessage(qsTr("Coordinates"),text);
                  }
                  onGeocodeFinished:{
                      if (map.geocodeModel.status == GeocodeModel.Ready) {
                          if (map.geocodeModel.count == 0) {
                              stackView.showMessage(qsTr("Geocode Error"),qsTr("Unsuccessful geocode"))
                          } else if (map.geocodeModel.count > 1) {
                              stackView.showMessage(qsTr("Ambiguous geocode"), map.geocodeModel.count + " " +
                                                    qsTr("results found for the given address, please specify location"))
                          } else {
                              stackView.showMessage(qsTr("Location"), geocodeMessage(),page)
                          }
                      } else if (map.geocodeModel.status == GeocodeModel.Error) {
                          stackView.showMessage(qsTr("Geocode Error"),qsTr("Unsuccessful geocode"))
                      }
                  }
                  onRouteError: stackView.showMessage(qsTr("Route Error"),qsTr("Unable to find a route for the given points"),page)

                  onShowGeocodeInfo: stackView.showMessage(qsTr("Location"),geocodeMessage(),page)

                  onErrorChanged: {
                      if (map.error != Map.NoError) {
                          var title = qsTr("ProviderError")
                          var message =  map.errorString + "<br/><br/><b>" + qsTr("Try to select other provider") + "</b>"
                          if (map.error == Map.MissingRequiredParameterError)
                              message += "<br/>" + qsTr("or see") + " \'mapviewer --help\' "
                                      + qsTr("how to pass plugin parameters.")
                          stackView.showMessage(title,message);
                      }
                  }
                  onShowMainMenu: mapPopupMenu.show(coordinate)
                  onShowMarkerMenu: markerPopupMenu.show(coordinate)
                  onShowRouteMenu: itemPopupMenu.show("Route",coordinate)
                  onShowPointMenu: itemPopupMenu.show("Point",coordinate)
                  onShowRouteList: stackView.showRouteListPage()
              }
          }
      }