/**************************************************************************** ** ** 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; i0) 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 + "

" + qsTr("Try to select other provider") + ""; if (map.error == Map.MissingRequiredParameterError) message += "
" + 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 } }