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
     }
 }