places.qml Example File
places/places.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 QtQuick.Layouts 1.2
import QtPositioning 5.5
import QtLocation 5.6
import "items"
ApplicationWindow {
id : appWindow
property Map map
property variant parameters
property variant searchLocation : map ? map .center : QtPositioning .coordinate ()
property variant searchRegion : QtPositioning .circle (searchLocation )
property variant searchRegionItem
property Plugin favoritesPlugin
function getPlugins () {
var plugin = Qt .createQmlObject ('import QtLocation 5.3; Plugin {}' , appWindow );
var myArray = new Array ;
for (var i = 0; i < plugin .availableServiceProviders .length ; i++) {
var tempPlugin = Qt .createQmlObject ('import QtLocation 5.3; Plugin {name: "' + plugin .availableServiceProviders [i ]+ '"}' , appWindow )
if (tempPlugin .supportsPlaces () && 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.3; 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 ])
}
}
function createMap (provider) {
var plugin;
if (parameters && parameters .length > 0 )
plugin = Qt .createQmlObject ('import QtLocation 5.3; Plugin{ name:"' + provider + '"; parameters: appWindow.parameters}' , appWindow )
else
plugin = Qt .createQmlObject ('import QtLocation 5.3; Plugin{ name:"' + provider + '"}' , appWindow )
if (map )
map .destroy ();
map = mapComponent .createObject (page );
map .plugin = plugin ;
map .zoomLevel = (map .maximumZoomLevel - map .minimumZoomLevel )/ 2
categoryModel .plugin = plugin ;
categoryModel .update ();
placeSearchModel .plugin = plugin ;
suggestionModel .plugin = plugin ;
}
title : qsTr ("Places" )
width : 360
height : 640
visible : true
menuBar : mainMenu
toolBar : searchBar
MainMenu {
id : mainMenu
onSelectProvider : {
stackView .pop (page )
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 ) {
settingsMenu .createMenu (map );
} else {
settingsMenu .clear ();
}
}
onSelectSetting : {
stackView .pop ({tem:page ,immediate: true })
switch (setting ) {
case "searchCenter" :
stackView .push ({ item: Qt .resolvedUrl ("forms/SearchCenter.qml" ) ,
properties: { "coordinate": map .center }})
stackView .currentItem .changeSearchCenter .connect (stackView .changeSearchCenter )
stackView .currentItem .closeForm .connect (stackView .closeForm )
break
case "searchBoundingBox" :
stackView .push ({ item: Qt .resolvedUrl ("forms/SearchBoundingBox.qml" ) ,
properties: { "searchRegion": searchRegion }})
stackView .currentItem .changeSearchBoundingBox .connect (stackView .changeSearchBoundingBox )
stackView .currentItem .closeForm .connect (stackView .closeForm )
break
case "searchBoundingCircle" :
stackView .push ({ item: Qt .resolvedUrl ("forms/SearchBoundingCircle.qml" ) ,
properties: { "searchRegion": searchRegion }})
stackView .currentItem .changeSearchBoundingCircle .connect (stackView .changeSearchBoundingCircle )
stackView .currentItem .closeForm .connect (stackView .closeForm )
break
case "SearchOptions" :
stackView .push ({ item: Qt .resolvedUrl ("forms/SearchOptions.qml" ) ,
properties: { "plugin": map .plugin ,
"model": placeSearchModel }})
stackView .currentItem .changeSearchSettings .connect (stackView .changeSearchSettings )
stackView .currentItem .closeForm .connect (stackView .closeForm )
break
default :
console .log ("Unsupported setting !" )
}
}
}
SearchBar {
id : searchBar
width : appWindow .width
searchBarVisbile : stackView .depth > 1 &&
stackView .currentItem &&
stackView .currentItem .objectName != "suggestionView" ? false : true
onShowCategories : {
if (map && map .plugin ) {
stackView .pop ({tem:page ,immediate: true })
stackView .enterCategory ()
}
}
onGoBack : stackView .pop ()
onSearchTextChanged : {
if (searchText .length >= 3 && suggestionModel != null ) {
suggestionModel .searchTerm = searchText ;
suggestionModel .update ();
}
}
onDoSearch : {
if (searchText .length > 0 )
placeSearchModel .searchForText (searchText );
}
onShowMap : stackView .pop (page )
}
StackView {
id : stackView
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 enterCategory (index)
{
push ({ item: Qt .resolvedUrl ("views/CategoryView.qml" ) ,
properties: { "categoryModel": categoryModel ,
"rootIndex" : index
}})
currentItem .showSubcategories .connect (stackView .enterCategory )
currentItem .searchCategory .connect (placeSearchModel .searchForCategory )
}
function showSuggestions ()
{
if (currentItem .objectName != "suggestionView" ) {
stackView .pop (page )
push ({ item: Qt .resolvedUrl ("views/SuggestionView.qml" ) ,
properties: { "suggestionModel": suggestionModel }
})
currentItem .objectName = "suggestionView"
currentItem .suggestionSelected .connect (searchBar .showSearch )
currentItem .suggestionSelected .connect (placeSearchModel .searchForText )
}
}
function showPlaces ()
{
if (currentItem .objectName != "searchResultView" ) {
stackView .pop ({tem:page ,immediate: true })
push ({ item: Qt .resolvedUrl ("views/SearchResultView.qml" ) ,
properties: { "placeSearchModel": placeSearchModel }
})
currentItem .showPlaceDetails .connect (showPlaceDatails )
currentItem .showMap .connect (searchBar .showMap )
currentItem .objectName = "searchResultView"
}
}
function showPlaceDatails (place, distance)
{
push ({ item: Qt .resolvedUrl ("forms/PlaceDetails.qml" ) ,
properties: { "place": place ,
"distanceToPlace": distance }
})
currentItem .searchForSimilar .connect (searchForSimilar )
currentItem .showReviews .connect (showReviews )
currentItem .showEditorials .connect (showEditorials )
currentItem .showImages .connect (showImages )
}
function showEditorials (place)
{
push ({ item: Qt .resolvedUrl ("views/EditorialView.qml" ) ,
properties: { "place": place }
})
currentItem .showEditorial .connect (showEditorial )
}
function showReviews (place)
{
push ({ item: Qt .resolvedUrl ("views/ReviewView.qml" ) ,
properties: { "place": place }
})
currentItem .showReview .connect (showReview )
}
function showImages (place)
{
push ({ item: Qt .resolvedUrl ("views/ImageView.qml" ) ,
properties: { "place": place }
})
}
function showEditorial (editorial)
{
push ({ item: Qt .resolvedUrl ("views/EditorialPage.qml" ) ,
properties: { "editorial": editorial }
})
}
function showReview (review)
{
push ({ item: Qt .resolvedUrl ("views/ReviewPage.qml" ) ,
properties: { "review": review }
})
}
function changeSearchCenter (coordinate)
{
stackView .pop (page )
map .center = coordinate ;
if (searchRegionItem ) {
map .removeMapItem (searchRegionItem );
searchRegionItem .destroy ();
}
}
function changeSearchBoundingBox (coordinate,widthDeg,heightDeg)
{
stackView .pop (page )
map .center = coordinate
searchRegion = QtPositioning .rectangle (map .center , widthDeg , heightDeg )
if (searchRegionItem ) {
map .removeMapItem (searchRegionItem );
searchRegionItem .destroy ();
}
searchRegionItem = Qt .createQmlObject ('import QtLocation 5.3; MapRectangle { color: "#46a2da"; border.color: "#190a33"; border.width: 2; opacity: 0.25 }' , page , "MapRectangle" );
searchRegionItem .topLeft = searchRegion .topLeft ;
searchRegionItem .bottomRight = searchRegion .bottomRight ;
map .addMapItem (searchRegionItem );
}
function changeSearchBoundingCircle (coordinate,radius)
{
stackView .pop (page )
map .center = coordinate ;
searchRegion = QtPositioning .circle (coordinate , radius )
if (searchRegionItem ) {
map .removeMapItem (searchRegionItem );
searchRegionItem .destroy ();
}
searchRegionItem = Qt .createQmlObject ('import QtLocation 5.3; MapCircle { color: "#46a2da"; border.color: "#190a33"; border.width: 2; opacity: 0.25 }' , page , "MapRectangle" );
searchRegionItem .center = searchRegion .center ;
searchRegionItem .radius = searchRegion .radius ;
map .addMapItem (searchRegionItem );
}
function changeSearchSettings (orderByDistance, orderByName, locales)
{
stackView .pop (page )
/*if (isFavoritesEnabled) {
if (favoritesPlugin == null)
favoritesPlugin = Qt.createQmlObject('import QtLocation 5.3; Plugin { name: "places_jsondb" }', page);
favoritesPlugin.parameters = pluginParametersFromMap(pluginParameters);
placeSearchModel.favoritesPlugin = favoritesPlugin;
} else {
placeSearchModel.favoritesPlugin = null;
}*/
placeSearchModel .favoritesPlugin = null ;
placeSearchModel .relevanceHint = orderByDistance ? PlaceSearchModel .DistanceHint :
orderByName ? PlaceSearchModel .LexicalPlaceNameHint :
PlaceSearchModel .UnspecifiedHint ;
map .plugin .locales = locales .split (Qt .locale ().groupSeparator );
}
function searchForSimilar (place) {
stackView .pop (page )
searchBar .showSearch (place .name )
placeSearchModel .searchForRecommendations (place .placeId );
}
anchors .fill: parent
focus : true
initialItem : Item {
id : page
PlaceSearchModel {
id : placeSearchModel
searchArea : searchRegion
function searchForCategory (category) {
searchTerm = "" ;
categories = category ;
recommendationId = "" ;
searchArea = searchRegion
limit = -1 ;
update ();
}
function searchForText (text) {
searchTerm = text ;
categories = null ;
recommendationId = "" ;
searchArea = searchRegion
limit = -1 ;
update ();
}
function searchForRecommendations (placeId) {
searchTerm = "" ;
categories = null ;
recommendationId = placeId ;
searchArea = null ;
limit = -1 ;
update ();
}
onStatusChanged : {
switch (status ) {
case PlaceSearchModel .Ready :
if (count > 0 )
stackView .showPlaces ()
else
stackView .showMessage (qsTr ("Search Place Error" ),qsTr ("Place not found !" ))
break ;
case PlaceSearchModel .Error :
stackView .showMessage (qsTr ("Search Place Error" ),errorString ())
break ;
}
}
}
PlaceSearchSuggestionModel {
id : suggestionModel
searchArea : searchRegion
onStatusChanged : {
if (status == PlaceSearchSuggestionModel .Ready )
stackView .showSuggestions ()
}
}
CategoryModel {
id : categoryModel
hierarchical : true
}
Component {
id : mapComponent
MapComponent {
width : page .width
height : page .height
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 );
}
}
MapItemView {
model : placeSearchModel
delegate : MapQuickItem {
coordinate : model .type === PlaceSearchModel .PlaceResult ? place .location .coordinate : QtPositioning .coordinate ()
visible : model .type === PlaceSearchModel .PlaceResult
anchorPoint .x: image .width * 0.28
anchorPoint .y: image .height
sourceItem : Image {
id : image
source : "resources/marker.png"
MouseArea {
anchors .fill: parent
onClicked : stackView .showPlaceDatails (model .place ,model .distance )
}
}
}
}
}
}
}
}
Rectangle {
color : "white"
opacity : busyIndicator .running ? 0.8 : 0
anchors .fill: parent
Behavior on opacity { NumberAnimation {} }
}
BusyIndicator {
id : busyIndicator
anchors .centerIn: parent
running : placeSearchModel .status == PlaceSearchModel .Loading ||
categoryModel .status === CategoryModel .Loading
}
}