// Copyright (C) 2017 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only

/*!
    \page location-places-qml.html
    \title QML Places API

    \section1 Overview

    The Places API allows users to discover places of interest and view
    details about them, such as address and contact information.  Some places may have
    additional content associated with them, such as images and reviews.
    The Places API also facilitates management of places and
    categories, allowing users to save and remove them.

    \section1 Introductory Concepts

    \section2 Plugin
    A \l Plugin is an abstraction for a backend. One \l Plugin might access places from a
    REST server while another may access places from a local database. The following
    instantiates a \l Plugin object by providing a name of "osm". The \l Plugin name
    identifies which backend to choose from. Plugins may also be provided with a set of
    \l {PluginParameter} {parameters}, which essentially takes the form of a set of
    key-value pairs. The \l {PluginParameter} {parameters} that can be specified vary
    among the different \l Plugin backends. For documentation on the possible \l
    {PluginParameter} {parameters} and nuances of each \l Plugin, see the \l {Plugin
    references and parameters}{Plugin References}.

    \snippet places_list/places_list.qml Initialize Plugin

    \section2 Models, Views and Delegates
    The QML Places API is built around the notion of models, views and delegates.

    \table
    \row
        \li \b Model
        \li A model holds data items and maintains their structure.
            The model is also responsible for retrieving the items from a data source.
    \row
        \li \b View
        \li A view is a visual container that displays the data and manages how visual
            items are shown such as in a list or a grid.  The view may also
            be responsible for navigating the data, for example, scrolling through
            the visual items during a flicking motion.
    \row
        \li \b Delegate
        \li A delegate defines how individual data elements should appear
            as visual items in the view.  The models expose a set of data roles
            and the delegate uses them to construct  a visual item.  The delegate
            may also define behaviour such as an operation to invoke when a visual
            item is clicked.
    \endtable

    The Common Use Cases section below demonstrates concrete examples of how
    these concepts fit together.

    \section1 Common Use Cases

    \section2 Searching for Places
    Searching is accomplished via the \l PlaceSearchModel.  The \l
    {PlaceSearchModel::plugin} {plugin} property specifies which backend to
    perform search operations against.  Search parameters may be provided
    through properties such as the \l {PlaceSearchModel::searchTerm}
    {searchTerm} and \l {PlaceSearchModel::searchArea} {searchArea}.  A search
    operation can then be started by invoking the \l {PlaceSearchModel::update}
    {update()} method.  For simplicity, the snippet below invokes \l
    {PlaceSearchModel::update} {update()} once construction of the model as
    been completed, typically \l {PlaceSearchModel::update} {update()} would be
    invoked in response to a user action such as a button click.  While the
    search operation is underway the \l {PlaceSearchModel::status} property
    transitions into the \c Loading state and when successfully completed moves
    into the \c Ready state.

    \snippet places_list/places_list.qml PlaceSearchModel

    \section2 Display Search Results using a ListView
    A \l ListView can be used to show the search results found by the model.
    It defines the visual region for where the results are shown, and in the
    case below fills the entirety of its parent.  The \l ListView has built in
    behavior that enables the region to respond to flicking events and to
    scroll appropriately.

    In the snippet below, the search model has been assigned to the ListView's
    \l {ListView::model} {model} property.  When the model is updated with new
    results, the \l ListView is automatically updated to reflect the model's new
    data items.

    A simple delegate has been bound to the \l {ListView}'s \l
    {ListView::delegate} {delegate} property.  The \l PlaceSearchModel exposes
    a set of \l {PlaceSearchModel Roles} {roles} of which the \e title and \e
    place roles have been used below, these are of type string and \l Place
    respectively.  Essentially for each data item that should be visible in the
    view, the view invokes the delegate to create a visual representation of
    the item.

    \table
        \row
            \li
                \snippet places_list/places_list.qml Places ListView
            \li
                \inlineimage places_list.png
    \endtable

    \note For simplicty's sake we have assumed that every search result is of
    \l {Search Result Types} {type} \c PlaceSearchResult and so always have
    access to the \e place role, other search result types may not have a
    \e place role.

    See the \l {Places List(QML)} {Places List} example for full source code.

    \section2 Display Search Results using a MapItemView
    Instead of a \l ListView, the \l PlaceSearchModel can be used in
    conjunction with a \l MapItemView to display markers on a map.  Firstly a
    \l Map is used to define the visual region occupied by the map, in this
    case it fills the entirety of its parent.  Other properties are specified
    such as the \l {Map::plugin} {plugin} providing the maps, and the map's \l
    {Map::center} {center} and \l {Map::zoomLevel} {zoomLevel}.

    Inside the \l Map, a \l MapItemView is declared, where the \l
    {MapItemView::model} {model} property has been set to the search model and
    a \l {MapItemView::delegate} {delegate} consisting of a \l MapQuickItem is
    used to display a marker image.  A marker is shown for every place that
    was found by the search model.  The delegate uses the \e place role
    to position the marker.

    \table
        \row
            \li
                \snippet places_map/places_map.qml Places MapItemView
            \li
                \inlineimage places_map.png
    \endtable

    \note For simplicty's sake we have assumed that every search result is of
    \l {Search Result Types} {type} \c PlaceSearchResult and so always have
    access to the \e place role, other search result types may not have a
    \e place role.

    See the \l {Places Map(QML)} {Places Map} example for full source code.

    \section2 Fetching Place Details
    In order to save bandwidth, sometimes a backend will only return places which
    are partially populated with details.  This can be checked with the
    Place::detailsFetched property which indicates whether all availalable details
    have been fetched or not.  If not, the Place::getDetails() method can be invoked
    to fetch the remaining details.

    \snippet declarative/places.qml Place fetchDetails

    \section2 Saving and Removing Places
    Some backends may support saving and removing places.  This can be done by
    calling the Place::save() and Place::remove() methods respectively.  Note
    that in order to save a \l Place, a \l Plugin must be assigned to specify
    which backend we are saving to.  The \l {Place::status} {status} property will
    transition into the \c Saving state while the save operation is happening and on
    successful completion will move to the \c Ready state.  The following
    snippet shows how to save and remove a place using javascript.

    \snippet declarative/places.qml Place createAndSavePlace
    \codeline
    \snippet declarative/places.qml Place removePlace

    \section2 Learn More
    The above snippets only exhibit a small subset of Places functionality.
    Refer to the \l {Places Types} shown below for richer content such as \l {ImageModel} {images}, \l {ReviewModel} {reviews} etc, as well as more indepth descriptions and explanations.

    See also the \l {Places (QML)}{Places (QML)} example for a more comprehensive demonstration on
    how to use the API.

    \section1 Places Types
    \section2 Data Types
    \annotatedlist qml-QtLocation5-places-data

    \section2 Models
    \annotatedlist qml-QtLocation5-places-models
*/

/*!
    \page location-places-cpp.html
    \title Places (C++)

    \section1 Overview

    The Places API allows users to discover places/points of interest
    and view details about them such as address and contact information;
    some places may even have rich content such as images and reviews.
    The Places API also facilitates management of places and
    categories, allowing users to save and remove them.

    \section1 Place Definition
    \include place-definition.qdocinc

    \section1 Common Operations

    \section2 Initializing a Manager
    All places functionality is facilitated by a QPlaceManager instance.  One must specify
    a QGeoServiceProvider in order to create the QPlaceManager

    \snippet places/requesthandler.h Initialize Manager

    \section2 Discovery/Search

    In order to perform a search operation we simply create a QPlaceSearchRequest
    and set the desired search parameters, such as a search term and search center.

    \snippet places/requesthandler.h Search for places cpp

    The request  is an asynchronous operation so we need a slot to handle the
    completion of the request. In the handler we check that there are no errors and that our search result
    type is a place.  If so we can then retrieve some of the core details of the
    place.  At the end of the slot, we delete the reply since they are for single use only.

    \snippet places/requesthandler.h Search for places handler cpp

    \b {Note:} Depending upon the plugin backend that was chosen, the search results may contain places
    which have further details that can be fetched on a place by place basis.  To fetch these other details
    see \l {Fetching Place Details}.

    \section3 Recommendations
    Recommendations can be retrieved by supplying a place id via QPlaceSearchRequest::setRecommendationId().
    Any places similar to the given place are retrieved.

    \section3 Paging
    If the plugin supports paging, the limit parameter may be provided to the search request.
    \snippet places/requesthandler.h Search paging

    \section2 Fetching Place Details
    A place that has been returned from a search request may have more details
    that can be fetched.  The following demonstrates how to check if there
    are further details and if so how to request them.

    \snippet places/requesthandler.h Details check
    \dots
    \dots
    \snippet places/requesthandler.h Details handler cpp

    \section2 Fetching Rich Content
    Rich content such as images and reviews is retrieved through the manager and then if required assigned to a place.
    \snippet places/requesthandler.h Image request

    We can handle the content request as shown below.
    \snippet places/requesthandler.h Image handler

    It is important to note that the results in the QPlaceContentReply,
    is a QPlaceContent::Collection which is essentially a QMap<int, QPlaceContent>.  The key \c {int} in this case is the
    index of the content, and the value is the content itself.  Due to the way Content is implemented
    it is possible to convert a content type as follows
    \code
        QPlaceImage image = content; //provided that 'content' has a type QPlace::ImageType
    \endcode

    The usage of the QPlaceContent::Collection and the conversion between content and its subtypes means
    that code for handling the mechanics of paging reviews, images and editorials can be easily shared.

    \section2 Search Suggestions
    The retrieval of search term suggestions is very similar to performing a place search. A QPlaceSearchRequest
    is used just like a place search, the only difference being that the search term is set to a
    partially completed string.

    \snippet places/requesthandler.h Suggestion request
    And when the request is done, we can use the reply to show the suggestions.
    \snippet places/requesthandler.h Suggestion handler

    \target Saving a place cpp
    \section2 Saving a Place
    The saving of a new place is performed as follows, we create a QPlace instance
    and populate it with information such as a name, address and coordinate.  Once
    done we can invoke QPlaceManager::savePlace() to begin a save operation.
    \snippet places/requesthandler.h Save place pt1
    \dots
    \snippet places/requesthandler.h Save place pt2

    Once a place is saved the reply contains the new identifier for that place.
    \snippet places/requesthandler.h Save place handler

    Note that to save an already \e existing place, the QPlace::placeId() must
    be filled in with the correct identifier.  Otherwise a new place will be created if empty or the
    wrong place overwritten if the identifier is incorrect.

    When a place is saved, the QPlaceManager may emit QPlaceManager::placedAdded() or QPlaceManager::placeUpdated()
    signals.  However whether a manager does so or not is provider specific, managers accessing places
    from a web service will typically not emit these signals while managers accessing places locally stored generally will.

    \section3 Caveats
    \input place-caveats.qdocinc

    \section3 Saving Between Managers
    When saving places between managers, there are a few things to be aware of.
    Some fields of a place such as the id, categories and icons are manager specific entities
    for example the categories in one manager may not be recognized in another.
    Therefore trying to save a place directly from one manager to another is not possible.

    The typical approach is to use the QPlaceManager::compatiblePlace() function,
    it creates a copy of a place, but only copies data that the manager supports.
    Manager specific data such as the place identifier is not copied over.  The new
    copy is now suitable for saving into the manager.  If the manager supports matching by alternative
    identifiers, an alternative identifier attribute is assigned to the copy (see \l {Matching places between managers})

    \snippet places/requesthandler.h Save to different manager

    \target Removing a place cpp
    \section2 Removing a Place
    The removal of a place is performed as follows:
    \snippet places/requesthandler.h Remove place
    \dots
    \dots
    \snippet places/requesthandler.h Remove place handler

    When a place is removed, the QPlaceManager may emit the QPlaceManager::placeRemoved() signal.  Whether a
    manager does so is provider specific.  Managers accessing places from a web service will typically not emit
    these signals, while managers accessing places stored locally generally will.

    \section2 Using Categories

    Categories are keywords that can describe a place. For example, 'park', 'theater',
    'restaurant'. A place could be described by many categories, it could be a park and a music venue and a ferry or bus stop.

    To use categories they must first be initialized.
    \snippet places/requesthandler.h Initialize categories
    \dots
    \dots
    \snippet places/requesthandler.h Initialize categories reply

    After the categories have been initialized we can then use these category functions.
    \list
        \li QPlaceManager::childCategories()
        \li QPlaceManager::category()
        \li QPlaceManager::parentCategoryId()
        \li QPlaceManager::childCategoryIds();
    \endlist

    To retrieve the top level categories
    we use the QPlaceManager::childCategories() function but do not provide
    a category identifier.

    \snippet places/requesthandler.h Top level categories

    If we did provide an identifier then we could retrieve a category's children.

    \snippet places/requesthandler.h Child categories

    \section2 Saving a Category
    The following shows how to save a category
    \snippet places/requesthandler.h Save category
    \dots
    \dots
    \snippet places/requesthandler.h Save category handler

    When a category is saved, the QPlaceManager may emit QPlaceManager::categoryAdded() or QPlaceManager::categoryUpdated()
    signals.  However whether a manager does so or not is provider specific, managers accessing places
    from a web service will typically not emit these signals while managers accessing places locally stored generally will.


    \section2 Removing a Category
    Category removal is very similar to removing a place
    \snippet places/requesthandler.h Remove category
    \dots
    \dots
    \snippet places/requesthandler.h Remove category handler

    When a category is removed, the QPlaceManager may emit the QPlaceManager::categoryRemoved() signal.  Whether a
    manager does so is provider specific.  Managers accessing places from a web service will typically not emit
    these signals, while managers accessing places stored locally generally will.

    \section2 Matching Places Between Managers
    Sometimes you may want to cross reference whether places from one manager match those from another manager.
    Such a situation may arise where one manager provides read-only access to places (origin manager) while another second r/w
    manager (destination manager) is used to save selected favorites from the first. During a search
    of the origin manager we may want to know which ones have been 'favorited' into the destination manager and perhaps display
    a customized favorite name rather than the original name.

    The matching mechanism can vary between managers, but is typically accomplished through an alternative identifier.
    As part of the save process, the place identifier from the origin manager is saved as an alternative identifier attribute in the destination manager
    (which can have its own place identifier scheme).  In the following example, the origin manager is from the 'here' QGeoServiceProider, therefore
    as part of the saving process an alternative identifier attribute, x_id_here, is set for the place saved into the destination manager
    (when QPlaceManager::compatiblePlace() is called)

    \input place-crossref.qdocinc

    In order to perform the matching, we create a QPlaceMatchRequest and assign it the search results from the origin manager.
    The QPlaceMatchRequest will be used on the destination manager to return corresponding places.  We also specify
    matching parameters which are key value pairs.  As mentioned previously, this can vary depending on the manager but typically
    the key is QPlaceMatchRequest::AlternativeId to indicate we are matching by alternative id, the value in this case would be
    x_id_here which specifies which alternative identifier attribute we are using to do the matching.

    \snippet places/requesthandler.h Match places
    \dots
    \dots
    \snippet places/requesthandler.h Match places handler

    \section1 Classes in Places

    \section2 Data Classes
    \annotatedlist QtLocation-places-data

    \section2 Request Classes
    \annotatedlist QtLocation-places-requests

    \target Places Reply Classes
    \section2 Reply classes
    \annotatedlist QtLocation-places-replies

    \section2 Manager Classes
    \annotatedlist QtLocation-places-manager
*/

