/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:FDL$ ** 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. ** ** GNU Free Documentation License Usage ** Alternatively, this file may be used under the terms of the GNU Free ** Documentation License version 1.3 as published by the Free Software ** Foundation and appearing in the file included in the packaging of ** this file. Please review the following information to ensure ** the GNU Free Documentation License version 1.3 requirements ** will be met: https://www.gnu.org/licenses/fdl-1.3.html. ** $QT_END_LICENSE$ ** ****************************************************************************/ /*! \page location-places-backend.html \title Places Backend \brief The Places backend is responsible for managing a places datastore whether it is located remotely or locally \section1 Overview The QPlaceManager interface, provided to clients to allow access to place information, depends directly on an implementation of QPlaceManagerEngine. The engine provides the backend function implementations which are called by the manager. A places backend implementer needs to derive from QPlaceManagerEngine and provide implementations for the virtual functions relevant for their backend. Most of these functions are asynchronous and so implementers will also need to derive the appropriate \l {Places Reply Classes}{reply classes}. The reply objects are responsible for managing an asynchronous request; they are used to notify when a request is complete and hold the results of that request. QPlaceManagerEngine provides a default implementation for all virtual functions. The default implementations for the asynchronous functions return a reply that will emit the error() and finished() signals at the next iteration through the event loop. \section1 Implementing/Inheriting Reply Objects A reply object would be inherited as follows: \snippet places/requesthandler.h Implement reply pt1 \dots \snippet places/requesthandler.h Implement reply pt2 The implementation of a QPlaceManagerEngine must ensure that any signals emitted by the reply objects are delayed until the request functions have returned and the application code has a chance to connect those signals to slots. The typical approach is to use \l {QMetaObject::invokeMethod()} with a \l {Qt::QueuedConnection} to emit the signals. \snippet places/requesthandler.h Trigger done Note that the \c finished signals should always be emitted when a reply is complete, even if an error has been encountered, that is, if there is an error, both the \c error and \c finished signals should be emitted while if there is no error, only the \c finished signals are emitted. The protected functions of QPlaceSearchReply::setResults() and QPlaceSearchReply::setRequest() are made publicly accessible so the plugin can assign results and requests. Because these functions are not publically exported, accessibility is not so much of an issue. An alternative would have been to declare a friend class in SearchReply. Typically the engine instance would be made the \c parent of the reply. If the developer fails to discard the replies when finished, the engine can clean those upon destruction. Commonly, the reply also has a pointer reference back to the engine, which may be used to emit the QPlaceManagerEngine::finished() and QPlaceManagerEngine::error() signals. This is just one of many ways the reply could be implemented. \section1 Icon URLs Icon URLs are provided through the QPlaceManagerEngine::constructIconUrl() function. The expected behaviour is that the engine will use the QPlaceIcon::parameters() in order to construct an appropriate URL. When a QPlace object is returned from the manager either from a search or a query to get place details, it is expected the engine will correctly populate the parameters as necessary. The backend is free to choose what the parameter key and values are, however if a backend only ever has one URL per icon it is recommended that the QPlaceIcon::SingleUrl be used as the key. \section1 Categories The categories of a manager engine are relatively static entities; for engines accessing remote place datastores it may be desirable to cache the category structure rather than querying a server every time QPlaceManagerEngine::initializeCategories() is called. Depending on how dynamic the categories are, always downloading the freshest set of categories may be more appropriate. \section1 Saving Places to the Manager A place generally cannot be saved directly between managers as is because it contains manager specific data such as icons and categories. In order to facilitate saving to one's own manager, engine implementers should implement the QPlaceManagerEngine::compatiblePlace() function. This function returns a copy of the input place with properties pruned or modified as necessary such that the copy can be saved into manager. Construction of a compatible place may involve ignoring certain properties from the original place, for example if contact details are not supported, these are left out of the compatible place. Other times it may involve modifying certain properties, for example modifying the icon parameters to facilitate copying or downloading of the original place's icon to a location that the backend can access. \section1 Cross-Referencing Places Between Managers Sometimes a situation may arise where we wish to cross-reference and match places between managers. 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 the customized favorite name rather than the original name. \section2 Alternative Identifier Cross-Referencing In order to accomplish cross-referencing, there needs to be a link between the original place and the favorited place and this is typically handled via an alternative identifier attribute. The favorited place contains an alternative identifier attribute which has the identifier of the original place. \include place-crossref.qdocinc There are 3 prerequisites for implementing cross-referencing by alternative identifier. The first is that the origin manager must provide the x_provider attribute with the value being the name of the manager's QGeoServiceProvider. The attribute label should be kept empty, indicating the attribute should not be displayed to users. \note It is generally expected that all managers should set the \c x_provider attribute. The second is that QPlaceManager::compatiblePlace() of the destination manager use the \c x_provider attribute of the initial place and set an alternative identifier attribute of the place to be saved. The key of the alternative identifier attribute is \c x_id_ and the text value is the identifier of the initial place. The \c x_provider attribute should not be passed to the compatible place. When it is saved, the x_provider of the saved place is considered to be the destination manager. The third is that QPlaceManager::matchingPlaces() of the destination manager accept the QPlaceMatchRequest::AlternativeId as a parameter key and the alternative identifier attribute key as the value, in this case \c x_id_ would be the expected value. This indicates that the identifiers of places in the QPlaceMatchRequest should be matched against the \c x_id_ alternative identifier attributes. Note that if the destination manager is to facilitate saving and cross-referencing from any arbitrary manager, it internally must accommodate saving of arbitrary key value pairs since we cannot know the provider names before hand, nor can we know what structure the ids will be. \section3 Other Methods of Linking If an origin manager does not supply a place id, it may be necessary to provide some other means of cross-referencing/matching. One approach might be to do so via the place coordinates, if the coordinate of a place in the origin manager is identical or close to a place in the destination manager, there is a high likelihood that they are the same place. In this case, the manager might implement QPlaceManager::matchingPlaces() to accept a QPlaceMatchRequest with a parameter key of 'proximity' and a parameter value of the distance two places must be in order to detect a match. for example if an origin place and destination place are within 50m of each other, they can be considered the same place. Generally however it is recommended that cross referencing be implemented via alternative identifiers as mentioned above. \section3 User Readable vs Non-User Readable Extended Attributes If an attribute is not intended to be readable by end users, the label field should be kept empty as an indicator of this fact. */