Map Viewer (QML)▲
Sélectionnez
/****************************************************************************
**
** 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 &
amp;&
amp; parameters.length&
gt;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&
lt;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&
lt;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 &
lt;
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 &
lt;
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
Text
{
visible
:
!
supportsSsl &
amp;&
amp; map &
amp;&
amp; map.activeMapType &
amp;&
amp; activeMapType.metadata.isHTTPS
text
:
"The active map type\n
requires (missing) SSL\n
support"
horizontalAlignment
:
Text.AlignHCenter
font.pixelSize
:
appWindow.width /
12
font.bold
:
true
color
:
"grey"
anchors.centerIn
:
parent
z
:
12
}
}
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 &
gt;
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()
}
}
}