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 ()
}
}
}