地点后端

概述

为客户端提供访问地点信息的 QPlaceManager 接口,取决于 QPlaceManagerEngine 的实现。该引擎提供由管理器调用的后端函数实现。

地点后端实现者需要从 QPlaceManagerEngine 继承,并为其后端提供相关虚拟函数的实现。大多数这些函数都是异步的,因此实现者还需要从适当的 回复类 继承。回复对象负责管理异步请求;它们用于在请求完成时通知,并保留该请求的结果。《QPlaceManagerEngine》为所有虚拟函数提供默认实现。异步函数的默认实现返回一个在事件循环的下一次迭代中将会发出 errorOccurred() 和 finished() 信号的回复。

实现/继承回复对象

回复对象将按如下方式继承:

class SearchReply : public QPlaceSearchReply
{
public:
    explicit SearchReply(ManagerEngine *engine)
        : QPlaceSearchReply(engine), m_engine(engine){}

    ~SearchReply();
    void setResults(const QList<QPlaceSearchResult> &results);
    void setRequest(const QPlaceSearchRequest &request);
    ...
    void triggerDone(QPlaceReply::Error error = QPlaceReply::NoError,
                     const QString &errorString = QString());

    ManagerEngine *m_engine;
};

QPlaceManagerEngine 的实现必须确保在请求函数返回以及应用程序代码有机会连接这些信号之前,延迟发出任何由回复对象发出的信号。典型做法是使用 QMetaObject::invokeMethod() 带有一个 Qt::QueuedConnection 来发出信号。

void SearchSuggestionReply::triggerDone(QPlaceReply::Error error,
                         const QString &errorString)
{
    if (error != QPlaceReply::NoError) {
        this->setError(error,errorString);
        QMetaObject::invokeMethod(m_engine, "errorOccurred", Qt::QueuedConnection,
                                  Q_ARG(QPlaceReply *,this),
                                  Q_ARG(QPlaceReply::Error, error),
                                  Q_ARG(QString, errorString));
        QMetaObject::invokeMethod(this, "errorOccurred", Qt::QueuedConnection,
                                  Q_ARG(QPlaceReply::Error, error),
                                  Q_ARG(QString, errorString));
    }

    this->setFinished(true);
    QMetaObject::invokeMethod(m_engine, "finished", Qt::QueuedConnection,
                              Q_ARG(QPlaceReply *,this));
    QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
}

请注意,即使在遇到错误的情况下,也应该始终在回复完成时发出 finished 信号,即如果有错误,应在错误和 finished 信号同时发出,如果没有错误,则只有 finished 信号发出。

QPlaceSearchReply::setResults() 和 QPlaceSearchReply::setRequest() 的受保护函数公开,以便插件可以分配结果和请求。因为这两个函数并未公开导出,所以不会引发太多问题。一个替代方案是在 SearchReply 中声明一个友元类。

一般来说,将引擎实例设置为回复的parent。如果开发人员在完成时未能丢弃回复,则当销毁引擎时,引擎会清理这些回复。通常,回复还会有一个指向引擎的指针引用,可以用来发出 QPlaceManagerEngine::finished() 和 QPlaceManagerEngine::error() 信号。这只是回复实现的一种可能方式。

图标URL地址

图标URL地址通过QPlaceManagerEngine::constructIconUrl()函数提供。期望的行为是引擎将使用QPlaceIcon::parameters()来构造适当的URL。当一个QPlace对象从管理器返回,无论是从搜索还是查询获取地点详情,都期望引擎将所需参数正确填充。

后端可以自由选择参数键和值,但如果后端每个图标只有一个URL,建议使用QPlaceIcon::SingleUrl作为键。

类别

管理器的类别相对静态;对于访问远程地点数据存储引擎,可能会选择缓存类别结构,而不是每次调用QPlaceManagerEngine::initializeCategories()时都查询服务器。根据类别的动态性,始终下载最新的类别集可能更合适。

将地点保存到管理器

由于包含特定于管理器的数据(如图标和类别),地点通常不能直接在管理器之间保存。为了便于保存到自己的管理器,引擎实现者应实现QPlaceManagerEngine::compatiblePlace()函数。此函数返回输入地点的副本,删除或修改必要的属性以便副本可以保存到管理器中。

构造兼容地点可能涉及忽略原始地点的某些属性,例如如果不支持联系信息,则从兼容地点中排除这些属性。在其他时候,这还可能涉及修改某些属性,例如修改图标参数以方便将原始地点的图标复制或下载到后端可以访问的位置。

在管理器之间交叉引用地点

有时可能出现需要在管理器之间交叉引用和匹配地点的情况。这种情况下,一个管理器可能提供了地点的只读访问权限(源管理器),而另一个第二个读写管理器(目标管理器)用于保存从第一个管理器选择的收藏夹。在源管理器中进行搜索时,我们可能想知道哪些已被添加到目标管理器的收藏夹,并可能显示自定义收藏名而不是原始名称。

替代标识符交叉引用

为了实现交叉引用,需要在原始地点和收藏地点之间建立一个链接,这通常是通过替代标识符属性来处理的。收藏地点包含一个替代标识符属性,其中包含原始地点的标识符。

origin R/O manager(here)       destination R/W manager (places_jsondb)
                        Save
Place id: ae246         --->    Place id: 0001
Attribute type: x_provider      Attribute type: x_id_here
Attribute value: here           Attribute text value: ae246

使用替代标识符实现交叉引用有三个先决条件。第一个是源管理器必须提供x_provider属性,其值为管理器QGeoServiceProvider的名称。属性标签应保持为空,表示不应将属性显示给用户。

注意:通常期望所有管理器都设置x_provider属性。

第二点是,目标管理器中的 QPlaceManager::compatiblePlace() 使用初始地点的 x_provider 属性,并将保存地点的替代标识符属性设置。替代标识符属性的键是 x_id_<提供者名称>,而文本值是初始地点的标识符。应将 x_provider 属性传递给兼容地点。保存时,保存地点的 x_provider 被认为是目标管理器。

第三点是,目标管理器的 QPlaceManager::matchingPlaces() 接受 QPlaceMatchRequest::AlternativeId 作为参数键和替代标识符属性键作为值,在这种情况下 x_id_<提供者名称> 将是预期值。这表示 QPlaceMatchRequest 中的地点标识符应与 x_id_<提供者名称> 替代标识符属性匹配。

请注意,如果目标管理器要方便从任何任意管理器保存和交叉引用,则它必须内部允许保存任意键值对,因为我们无法事先知道提供者名称,也无法知道 ids 将具有什么结构。

链接的其他方法

如果源管理器不提供地点 ID,可能需要提供其他交叉引用/匹配的途径。一种方法可能是通过地点坐标来这样做,如果源管理器中的一个地点坐标与目标管理器中的一个地点坐标相同或非常接近,那么它们几乎肯定是同一地点。在这种情况下,管理器可能需要实现 QPlaceManager::matchingPlaces() 以接受一个具有 'proximity' 作为参数键和一个参数值,该参数值是测定匹配所需的两个地点之间的距离。例如,如果源地点和目标地点相距 50 米以内,则可以认为它们是同一地点。

然而,一般建议通过上述提到的替代标识符来实现交叉引用。

用户可读属性与非用户可读扩展属性

如果某个属性不是想让最终用户可读的,则标签字段应保持为空,作为这一事实的指示。

© 2024 Qt 公司有限。此处包含的文档贡献是各自所有者的版权。此处提供的文档是根据自由软件基金会发布的 GNU 自由文档许可的第 1.3 版 的条款许可的。Qt 及其相应的标志是芬兰及其它全球国家/地区 Qt 公司的商标。所有其他商标均为其各自所有者的财产。