diff options
author | Aaron McCarthy <aaron.mccarthy@jollamobile.com> | 2014-02-19 14:52:07 +1000 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2014-03-14 12:30:09 +0100 |
commit | d2628aeb6ed1ab30d1a825122dc80cfebb5093d2 (patch) | |
tree | 00cec128c5d264346c871ba9bfcdc9a920dfa52b /src/plugins | |
parent | 3f4a3acab163fa6675a1513ab1fccdbda7723dd6 (diff) | |
download | qtlocation-d2628aeb6ed1ab30d1a825122dc80cfebb5093d2.tar.gz |
Parse Nokia route response in helper thread.
Complex and really long routes can take multiple seconds to parse. Use
a helper thread to parse route responses to prevent blocking the main
thread.
Change-Id: I4130510ff15752427f31b429e53d2ab87fa1b84a
Reviewed-by: Alex Blasche <alexander.blasche@digia.com>
Diffstat (limited to 'src/plugins')
4 files changed, 99 insertions, 79 deletions
diff --git a/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp b/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp index 2245b208..72f2c60d 100644 --- a/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp +++ b/src/plugins/geoservices/nokia/qgeoroutereply_nokia.cpp @@ -51,22 +51,21 @@ #include <qgeorouterequest.h> +Q_DECLARE_METATYPE(QList<QGeoRoute>) + QT_BEGIN_NAMESPACE -QGeoRouteReplyNokia::QGeoRouteReplyNokia(const QGeoRouteRequest &request, const QList<QNetworkReply*> &replies, QObject *parent) - : QGeoRouteReply(request, parent), - m_replies(replies) +QGeoRouteReplyNokia::QGeoRouteReplyNokia(const QGeoRouteRequest &request, + const QList<QNetworkReply *> &replies, + QObject *parent) +: QGeoRouteReply(request, parent), m_replies(replies), m_parsers(0) { + qRegisterMetaType<QList<QGeoRoute> >(); + foreach (QNetworkReply *reply, m_replies) { - connect(reply, - SIGNAL(finished()), - this, - SLOT(networkFinished())); - - connect(reply, - SIGNAL(error(QNetworkReply::NetworkError)), - this, - SLOT(networkError(QNetworkReply::NetworkError))); + connect(reply, SIGNAL(finished()), this, SLOT(networkFinished())); + connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), + this, SLOT(networkError(QNetworkReply::NetworkError))); } } @@ -77,7 +76,7 @@ QGeoRouteReplyNokia::~QGeoRouteReplyNokia() void QGeoRouteReplyNokia::abort() { - if (m_replies.isEmpty()) + if (m_replies.isEmpty() && !m_parsers) return; foreach (QNetworkReply *reply, m_replies) { @@ -85,6 +84,7 @@ void QGeoRouteReplyNokia::abort() reply->deleteLater(); } m_replies.clear(); + m_parsers = 0; } void QGeoRouteReplyNokia::networkFinished() @@ -93,53 +93,65 @@ void QGeoRouteReplyNokia::networkFinished() if (!reply) return; - if (reply->error() != QNetworkReply::NoError) { - // Removed because this is already done in networkError, which previously caused _two_ errors to be raised for every error. - //setError(QGeoRouteReply::CommunicationError, m_reply->errorString()); - //m_reply->deleteLater(); - //m_reply = 0; + if (reply->error() != QNetworkReply::NoError) return; - } - QGeoRouteXmlParser parser(request()); - if (parser.parse(reply)) { - addRoutes(parser.results()); - reply->deleteLater(); - m_replies.removeOne(reply); - if (m_replies.isEmpty()) - setFinished(true); - } else { - // add a qWarning with the actual parser.errorString() - setError(QGeoRouteReply::ParseError, "The response from the service was not in a recognisable format."); - abort(); - } + QGeoRouteXmlParser *parser = new QGeoRouteXmlParser(request()); + connect(parser, SIGNAL(results(QList<QGeoRoute>)), + this, SLOT(appendResults(QList<QGeoRoute>))); + connect(parser, SIGNAL(error(QString)), this, SLOT(parserError(QString))); + + ++m_parsers; + parser->parse(reply->readAll()); + + m_replies.removeOne(reply); + reply->deleteLater(); } void QGeoRouteReplyNokia::networkError(QNetworkReply::NetworkError error) { - Q_UNUSED(error) - QNetworkReply *reply = qobject_cast<QNetworkReply *>(sender()); if (!reply) return; - bool resolvedError = false; - if (QNetworkReply::UnknownContentError == error) { - QGeoRouteXmlParser parser(request()); - if (parser.parse(reply)) { - addRoutes(parser.results()); - reply->deleteLater(); - m_replies.removeOne(reply); - resolvedError = true; - if (m_replies.isEmpty()) - setFinished(true); - } - } + if (error == QNetworkReply::UnknownContentError) { + QGeoRouteXmlParser *parser = new QGeoRouteXmlParser(request()); + connect(parser, SIGNAL(results(QList<QGeoRoute>)), + this, SLOT(appendResults(QList<QGeoRoute>))); + connect(parser, SIGNAL(error(QString)), this, SLOT(parserError(QString))); + + ++m_parsers; + parser->parse(reply->readAll()); - if (!resolvedError) { + m_replies.removeOne(reply); + reply->deleteLater(); + } else { setError(QGeoRouteReply::CommunicationError, reply->errorString()); abort(); } } +void QGeoRouteReplyNokia::appendResults(const QList<QGeoRoute> &routes) +{ + if (!m_parsers) + return; + + --m_parsers; + addRoutes(routes); + + if (!m_parsers && m_replies.isEmpty()) + setFinished(true); +} + +void QGeoRouteReplyNokia::parserError(const QString &errorString) +{ + Q_UNUSED(errorString) + + --m_parsers; + + setError(QGeoRouteReply::ParseError, + tr("The response from the service was not in a recognisable format.")); + abort(); +} + QT_END_NAMESPACE diff --git a/src/plugins/geoservices/nokia/qgeoroutereply_nokia.h b/src/plugins/geoservices/nokia/qgeoroutereply_nokia.h index 911e1920..d1684e83 100644 --- a/src/plugins/geoservices/nokia/qgeoroutereply_nokia.h +++ b/src/plugins/geoservices/nokia/qgeoroutereply_nokia.h @@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE +class QGeoRouteXmlParser; + class QGeoRouteReplyNokia : public QGeoRouteReply { Q_OBJECT @@ -66,9 +68,12 @@ public: private Q_SLOTS: void networkFinished(); void networkError(QNetworkReply::NetworkError error); + void appendResults(const QList<QGeoRoute> &routes); + void parserError(const QString &errorString); private: - QList<QNetworkReply*> m_replies; + QList<QNetworkReply *> m_replies; + int m_parsers; }; QT_END_NAMESPACE diff --git a/src/plugins/geoservices/nokia/qgeoroutexmlparser.cpp b/src/plugins/geoservices/nokia/qgeoroutexmlparser.cpp index 60840ec6..e032f8d3 100644 --- a/src/plugins/geoservices/nokia/qgeoroutexmlparser.cpp +++ b/src/plugins/geoservices/nokia/qgeoroutexmlparser.cpp @@ -49,12 +49,12 @@ #include "qgeoroutexmlparser.h" #include <QXmlStreamReader> -#include <QIODevice> #include <QStringList> #include <QString> +#include <QtCore/QThreadPool> -#include <qgeoroute.h> #include <QtPositioning/QGeoRectangle> +#include <QtLocation/QGeoRoute> QT_BEGIN_NAMESPACE @@ -74,28 +74,23 @@ QGeoRouteXmlParser::~QGeoRouteXmlParser() { } -bool QGeoRouteXmlParser::parse(QIODevice *source) +void QGeoRouteXmlParser::parse(const QByteArray &data) { - m_reader.reset(new QXmlStreamReader(source)); - - if (!parseRootElement()) { - m_errorString = m_reader->errorString(); - return false; - } - - m_errorString = ""; - - return true; + m_data = data; + QThreadPool::globalInstance()->start(this); } -QList<QGeoRoute> QGeoRouteXmlParser::results() const +void QGeoRouteXmlParser::run() { - return m_results; -} + m_reader = new QXmlStreamReader(m_data); -QString QGeoRouteXmlParser::errorString() const -{ - return m_errorString; + if (!parseRootElement()) + emit error(m_reader->errorString()); + else + emit results(m_results); + + delete m_reader; + m_reader = 0; } bool QGeoRouteXmlParser::parseRootElement() diff --git a/src/plugins/geoservices/nokia/qgeoroutexmlparser.h b/src/plugins/geoservices/nokia/qgeoroutexmlparser.h index 466bca5e..7e6307e7 100644 --- a/src/plugins/geoservices/nokia/qgeoroutexmlparser.h +++ b/src/plugins/geoservices/nokia/qgeoroutexmlparser.h @@ -49,16 +49,17 @@ #ifndef QROUTEXMLPARSER_H #define QROUTEXMLPARSER_H -#include <QList> -#include <QString> -#include <QScopedPointer> +#include <QtCore/QObject> +#include <QtCore/QRunnable> +#include <QtCore/QString> +#include <QtCore/QList> -#include <qgeoroutesegment.h> -#include <qgeorouterequest.h> -#include <qgeomaneuver.h> +#include <QtLocation/QGeoRouteRequest> +#include <QtLocation/QGeoRouteSegment> +#include <QtLocation/QGeoManeuver> QT_BEGIN_NAMESPACE -class QIODevice; + class QXmlStreamReader; class QGeoRoute; class QGeoCoordinate; @@ -92,15 +93,20 @@ public: int baseTime; }; -class QGeoRouteXmlParser +class QGeoRouteXmlParser : public QObject, public QRunnable { + Q_OBJECT + public: QGeoRouteXmlParser(const QGeoRouteRequest &request); ~QGeoRouteXmlParser(); - bool parse(QIODevice *source); - QList<QGeoRoute> results() const; - QString errorString() const; + void parse(const QByteArray &data); + void run(); + +signals: + void results(const QList<QGeoRoute> &routes); + void error(const QString &errorString); private: bool parseRootElement(); @@ -119,12 +125,14 @@ private: bool parseDynamicSpeedInfo(QGeoDynamicSpeedInfoContainer &speedInfo); QGeoRouteRequest m_request; - QScopedPointer<QXmlStreamReader> m_reader; + QByteArray m_data; + QXmlStreamReader *m_reader; + QList<QGeoRoute> m_results; - QString m_errorString; QList<QGeoManeuverContainer> m_maneuvers; QList<QGeoRouteSegmentContainer> m_segments; }; QT_END_NAMESPACE + #endif |