#include "networkforecastsource.h" #include "yahooweatherresponse.h" #include "xoapweatherresponse.h" #include #include #include #include #include #include #include #include #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 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 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)); }