diff options
Diffstat (limited to 'weather/src/networkforecastsource.cpp')
-rw-r--r-- | weather/src/networkforecastsource.cpp | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/weather/src/networkforecastsource.cpp b/weather/src/networkforecastsource.cpp new file mode 100644 index 0000000..98456c8 --- /dev/null +++ b/weather/src/networkforecastsource.cpp @@ -0,0 +1,234 @@ +#include "networkforecastsource.h" +#include "yahooweatherresponse.h" +#include "xoapweatherresponse.h" + +#include <QUrl> +#include <QNetworkRequest> +#include <QNetworkReply> +#include <QDebug> +#include <QBuffer> +#include <QDomDocument> +#include <QDateTime> +#include <QTime> + +#define CITY_NAME_HOST "xoap.weather.com" +#define CITY_NAME_TO_LOCATION_ID_URL "http://" CITY_NAME_HOST "/search/search" +#define CITY_NAME_TO_LOCATION_ID_PARAM "where" + +#define FORECAST_HOST "weather.yahooapis.com" +#define FORECAST_URL "http://" FORECAST_HOST "/forecastrss" +#define FORECAST_LOCATION_PARAM "p" +#define FORECAST_UNIT_PARAM "u" +#define FORECAST_CELSIUS_UNIT "c" + +#define YWEATHER_NS_URI "http://xml.weather.yahoo.com/ns/rss/1.0" +#define YWEATHER_NS_NAME "yweather" + +static int getId() +{ + static int id(0); + return ++id; +} + +// LocationRequestManager + +LocationRequestManager::LocationRequestManager(QObject *parent) + : QObject(parent) +{ + connect(&m_network, SIGNAL(finished(QNetworkReply*)), + this, SLOT(receiveResponse(QNetworkReply*))); +} + +int LocationRequestManager::addRequest(const QString &query) +{ + if (m_requests.contains(query)) + return m_requests[query]; + QUrl url(CITY_NAME_TO_LOCATION_ID_URL); + url.addQueryItem(CITY_NAME_TO_LOCATION_ID_PARAM, query); + m_network.get(QNetworkRequest(url)); + + int result = getId(); + m_requests[query] = result; + return result; +} + +QString LocationRequestManager::readResponse(const QString &query, QNetworkReply *reply) +{ + + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "location id query error: " << query; + return QString(); + } + + QDomDocument doc; + + if (!doc.setContent(reply)) { + qWarning() << "location id parse error: " << query; + return QString(); + } + XoapWeatherResponse reader; + reader.read(doc.documentElement()); + + if (reader.items().count() == 0) { + qWarning() << "empty location id response: " << query; + return QString(); + } + + return reader.items()[0].id(); + +} + +void LocationRequestManager::receiveResponse(QNetworkReply *reply) +{ + const QString query = reply->request().url().queryItemValue(CITY_NAME_TO_LOCATION_ID_PARAM); + + if (query.isNull() || !m_requests.contains(query)) { + qWarning() << "Unexpected location id query response. (query = " << query << ")"; + return; + } + const int reqId = m_requests[query]; + m_requests.remove(query); + + QString locId = readResponse(query, reply); + + if (locId.isEmpty()) + emit locationIdQueryError(reqId, query); + else + emit newLocationId(reqId, locId); +} + +// ForecastRequestmanager + +ForecastRequestmanager::ForecastRequestmanager(QObject *parent) + : QObject(parent) +{ + connect(&m_network, SIGNAL(finished(QNetworkReply*)), + this, SLOT(receiveResponse(QNetworkReply*))); +} + +int ForecastRequestmanager::addRequest(const QString &locId) +{ + if (m_requests.contains(locId)) + return m_requests[locId][0]; + int result = getId(); + doAddRequest(result, locId); + return result; +} + +void ForecastRequestmanager::addRequest(int reqId, const QString &locId) +{ + if (m_requests.contains(locId)) { + m_requests[locId].append(reqId); + return; + } + doAddRequest(reqId, locId); +} + +void ForecastRequestmanager::doAddRequest(int reqId, const QString &locId) +{ + QUrl url(FORECAST_URL); + url.addQueryItem(FORECAST_LOCATION_PARAM, locId); + url.addQueryItem(FORECAST_UNIT_PARAM, FORECAST_CELSIUS_UNIT); + m_network.get(QNetworkRequest (url)); + QList<int> list; + list.append(reqId); + m_requests[locId] = list; +} + +YahooWeatherResponse *ForecastRequestmanager::readResponse(const QString &locId, + QNetworkReply *reply) +{ + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "forecast query error: " << locId; + return 0; + } + + QDomDocument doc; + + if (!doc.setContent(reply)) { + qWarning() << "forecast parse error: " << locId; + return 0; + } + + bool ok = doc.documentElement().childNodes().count() > 0 + && doc.documentElement().childNodes().at(0).isElement(); + if (ok) { + QDomElement element = doc.documentElement().childNodes().at(0).toElement(); + ok = element.elementsByTagName("lastBuildDate").count() == 1; + } + + if (!ok) { + qWarning() << "invalid forecast response: " << locId; + return 0; + } + + return new YahooWeatherResponse(locId, doc.documentElement()); +} + +void ForecastRequestmanager::receiveResponse(QNetworkReply *reply) +{ + const QString locId = reply->request().url().queryItemValue(FORECAST_LOCATION_PARAM); + + if (locId.isNull() || !m_requests.contains(locId)) { + qWarning() << "Unexpected forecast query response. (locId = " << locId << ")"; + return; + } + + const QList<int> list = m_requests[locId]; + m_requests.remove(locId); + + YahooWeatherResponse *result = readResponse(locId, reply); + if (result) + foreach (int reqId, list) { + emit newForecastResponse(reqId, result); + } + else + foreach (int reqId, list) + emit forecastResponseError(reqId); +} + +// NetworkForecastSource + +NetworkForecastSource::NetworkForecastSource(QObject *parent) + : ForecastSource(parent) +{ + connect(&m_locationManager, SIGNAL(newLocationId(int, QString)), + &m_forecastManager, SLOT(addRequest(int, QString))); + + connect(&m_locationManager, SIGNAL(locationIdQueryError(int, QString)), + &m_forecastManager, SLOT(addRequest(int, QString))); + + connect(&m_forecastManager, SIGNAL(forecastResponseError(int)), + this, SLOT(forecastResponseError(int))); + + connect(&m_forecastManager, SIGNAL(newForecastResponse(int, YahooWeatherResponse*)), + this, SLOT(newForecastResponse(int, YahooWeatherResponse*))); +} + +NetworkForecastSource::~NetworkForecastSource() +{ +} + +int NetworkForecastSource::getForecast(const QString &key, bool locationId) +{ + if (locationId) + return m_forecastManager.addRequest(key); + else + return m_locationManager.addRequest(key); +} + +void NetworkForecastSource::newForecastResponse(int reqId, YahooWeatherResponse *forecast) +{ + forecast->print(); + emit forecastReceived(reqId, ForecastData(forecast)); +} + +void NetworkForecastSource::forecastResponseError(int reqId) +{ + emit forecastReceived(reqId, ForecastData(0)); +} + + + + + |