blob: e8b016aa8b1feb75198b82332bc3e53546bd0209 [file] [log] [blame]
/****************************************************************************
**
** 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
//! [routecoordinate]
property variant fromCoordinate: QtPositioning.coordinate(59.9483, 10.7695)
property variant toCoordinate: QtPositioning.coordinate(59.9645, 10.671)
//! [routecoordinate]
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
//! [geocode0]
Address {
id :fromAddress
street: "Sandakerveien 116"
city: "Oslo"
country: "Norway"
state : ""
postalCode: "0484"
}
//! [geocode0]
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
Text {
visible: !supportsSsl && map && map.activeMapType && 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 > 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()
}
}
}