blob: a511f0ea2311d4282350233edad4e05994c2b725 [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 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 !")
}
}
}
//! [PlaceSearchSuggestionModel search text changed 1]
SearchBar {
id: searchBar
//! [PlaceSearchSuggestionModel search text changed 1]
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()
//! [PlaceSearchSuggestionModel search text changed 2]
onSearchTextChanged: {
if (searchText.length >= 3 && suggestionModel != null) {
suggestionModel.searchTerm = searchText;
suggestionModel.update();
}
}
//! [PlaceSearchSuggestionModel search text changed 2]
onDoSearch: {
if (searchText.length > 0)
placeSearchModel.searchForText(searchText);
}
onShowMap: stackView.pop(page)
//! [PlaceSearchSuggestionModel search text changed 3]
}
//! [PlaceSearchSuggestionModel search text changed 3]
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);
}
//! [PlaceRecommendationModel search]
function searchForSimilar(place) {
stackView.pop(page)
searchBar.showSearch(place.name)
placeSearchModel.searchForRecommendations(place.placeId);
}
//! [PlaceRecommendationModel search]
anchors.fill: parent
focus: true
initialItem: Item {
id: page
//! [PlaceSearchModel model]
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;
}
}
}
//! [PlaceSearchModel model]
//! [PlaceSearchSuggestionModel model]
PlaceSearchSuggestionModel {
id: suggestionModel
searchArea: searchRegion
onStatusChanged: {
if (status == PlaceSearchSuggestionModel.Ready)
stackView.showSuggestions()
}
}
//! [PlaceSearchSuggestionModel model]
//! [CategoryModel model]
CategoryModel {
id: categoryModel
hierarchical: true
}
//! [CategoryModel model]
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
}
}