summaryrefslogtreecommitdiffstats
path: root/weather
diff options
context:
space:
mode:
authorLuiz Agostini <luiz.agostini@openbossa.org>2009-11-10 00:15:56 -0300
committerLuiz Agostini <luiz.agostini@openbossa.org>2009-11-10 01:02:37 -0300
commit7821f5e49c28b4b8e72caeb7ab4f11c6d5e3555e (patch)
tree236503c0eb05d368ed5159c3a881e21515287e5a /weather
parent658f5c70b84d5ef8dec79472ac461d0e272137c5 (diff)
Weather: real content.
Signed-off-by: Luiz Agostini <luiz.agostini@openbossa.org>
Diffstat (limited to 'weather')
-rw-r--r--weather/addcitytool.cpp31
-rw-r--r--weather/addcitytool.h5
-rw-r--r--weather/bootmanager.cpp21
-rw-r--r--weather/bootmanager.h4
-rw-r--r--weather/demoforecastsource.cpp140
-rw-r--r--weather/demoforecastsource.h44
-rw-r--r--weather/fake_content.xml27
-rw-r--r--weather/forecastdata.cpp78
-rw-r--r--weather/forecastdata.h60
-rw-r--r--weather/forecastprovider.cpp110
-rw-r--r--weather/forecastprovider.h28
-rw-r--r--weather/forecastsource.h18
-rw-r--r--weather/main.cpp11
-rw-r--r--weather/networkforecastsource.cpp237
-rw-r--r--weather/networkforecastsource.h75
-rw-r--r--weather/resources.qrc1
-rw-r--r--weather/settings.cpp1
-rw-r--r--weather/sym_iap_util.h131
-rw-r--r--weather/weather.ini33
-rw-r--r--weather/weather.pro18
-rw-r--r--weather/xoapweatherresponse.cpp48
-rw-r--r--weather/xoapweatherresponse.h43
-rw-r--r--weather/yahooweatherresponse.cpp163
-rw-r--r--weather/yahooweatherresponse.h181
24 files changed, 1303 insertions, 205 deletions
diff --git a/weather/addcitytool.cpp b/weather/addcitytool.cpp
index 9cd0089..4d0e4ed 100644
--- a/weather/addcitytool.cpp
+++ b/weather/addcitytool.cpp
@@ -119,19 +119,22 @@ AddCitySearchScreen::AddCitySearchScreen(const QRectF &boundingRect, QGraphicsIt
}
-void AddCitySearchScreen::forecastResponse(const ForecastData &forecast)
+void AddCitySearchScreen::forecastResponse(int reqId, const ForecastData &forecast)
{
- if (forecast.key() == m_city) {
+ if (reqId == m_reqId) {
reset();
- emit forecastReceived(forecast);
+ if (!forecast.isNull() && !forecast.error())
+ emit forecastReceived(forecast);
+ else
+ emit forecastRequestError(m_city);
}
}
void AddCitySearchScreen::setCityName(const QString &name)
{
m_city = name;
- ForecastProvider::connectToResponseSignal(this, SLOT(forecastResponse(ForecastData)));
- ForecastProvider::getForecast(m_city, false);
+ ForecastProvider::connectToResponseSignal(this, SLOT(forecastResponse(int, ForecastData)));
+ m_reqId = ForecastProvider::getForecast(m_city, false);
m_loading->start();
m_loading->show();
update();
@@ -297,6 +300,8 @@ AddCitySearchScreen *AddCityTool::createSearchScreen()
AddCitySearchScreen *result = new AddCitySearchScreen(boundingRect(), this);
connect(result, SIGNAL(forecastReceived(ForecastData)),
this, SLOT(forecastReceived(ForecastData)));
+ connect(result, SIGNAL(forecastRequestError(QString)),
+ this, SLOT(forecastRequestError(QString)));
result->setPos(0.0, 0.0);
return result;
}
@@ -324,14 +329,14 @@ void AddCityTool::errorScreenClosed()
void AddCityTool::forecastReceived(const ForecastData &forecast)
{
- if (forecast.error()) {
- m_ErrorScreen->setCityName(forecast.key(), AddCityErrorScreen::NotFound);
- setCurrentScreen(m_ErrorScreen);
- }
- else {
- emit newForecast(forecast);
- setCurrentScreen(m_firstScreen);
- }
+ emit newForecast(forecast);
+ setCurrentScreen(m_firstScreen);
+}
+
+void AddCityTool::forecastRequestError(const QString &name)
+{
+ m_ErrorScreen->setCityName(name, AddCityErrorScreen::NotFound);
+ setCurrentScreen(m_ErrorScreen);
}
void AddCityTool::citySelected(const QString &city)
diff --git a/weather/addcitytool.h b/weather/addcitytool.h
index f5f83e6..bc313b0 100644
--- a/weather/addcitytool.h
+++ b/weather/addcitytool.h
@@ -61,15 +61,17 @@ public:
signals:
void forecastReceived(const ForecastData &forecast);
+ void forecastRequestError(const QString &name);
private:
QString m_city;
+ int m_reqId;
Loading *m_loading;
void reset();
private slots:
- void forecastResponse(const ForecastData &forecast);
+ void forecastResponse(int reqId, const ForecastData &forecast);
};
class AddCityErrorScreen : public QObject, public QGraphicsPixmapItem
@@ -128,6 +130,7 @@ signals:
private slots:
void errorScreenClosed();
void forecastReceived(const ForecastData &forecast);
+ void forecastRequestError(const QString &name);
void citySelected(const QString &city);
};
diff --git a/weather/bootmanager.cpp b/weather/bootmanager.cpp
index de2b6ff..08a3738 100644
--- a/weather/bootmanager.cpp
+++ b/weather/bootmanager.cpp
@@ -17,7 +17,6 @@
BootManager::BootManager(QObject *parent)
: QObject(parent)
- , m_pendingResponses(0)
, m_imagesLoaded(false)
{
}
@@ -25,12 +24,11 @@ BootManager::BootManager(QObject *parent)
void BootManager::run()
{
m_keys = Settings::getCurrentCities();
- ForecastProvider::connectToResponseSignal(this, SLOT(forecastResponse(ForecastData)));
+ ForecastProvider::connectToResponseSignal(this, SLOT(forecastResponse(int, ForecastData)));
foreach (const QString & city, m_keys) {
- ForecastProvider::getForecast(city);
+ m_requests.append(ForecastProvider::getForecast(city, true));
m_data.append(ForecastData());
}
- m_pendingResponses = m_keys.count();
PixmapLoader::connectToOnIdleSignal(this, SLOT(pixmapLoaderIsIdle()));
int count = ForecastHungItem::loadImages();
count += ForecastRain::loadImages();
@@ -48,15 +46,14 @@ void BootManager::run()
PixmapLoader::disconnectReceiver(this);
}
-void BootManager::forecastResponse(const ForecastData &forecast)
+void BootManager::forecastResponse(int reqId, const ForecastData &forecast)
{
- int idx = m_keys.indexOf(forecast.key());
- if (idx >= 0) {
- if (m_data[idx].isNull())
- --m_pendingResponses;
- m_data[idx] = forecast;
+ if (m_requests.removeAll(reqId)) {
+ int idx = m_keys.indexOf(forecast.key());
+ if (idx >= 0)
+ m_data[idx] = forecast;
}
- if (!m_pendingResponses) {
+ if (m_requests.isEmpty()) {
ForecastProvider::disconnectReceiver(this);
if (m_imagesLoaded)
emit ready();
@@ -67,6 +64,6 @@ void BootManager::pixmapLoaderIsIdle()
{
PixmapLoader::disconnectReceiver(this);
m_imagesLoaded = true;
- if (!m_pendingResponses)
+ if (m_requests.isEmpty())
emit ready();
}
diff --git a/weather/bootmanager.h b/weather/bootmanager.h
index a94e0f1..b061547 100644
--- a/weather/bootmanager.h
+++ b/weather/bootmanager.h
@@ -18,13 +18,13 @@ signals:
void ready();
private slots:
- void forecastResponse(const ForecastData &forecast);
+ void forecastResponse(int reqId, const ForecastData &forecast);
void pixmapLoaderIsIdle();
private:
QStringList m_keys;
QList<ForecastData> m_data;
- int m_pendingResponses;
+ QList<int> m_requests;
bool m_imagesLoaded;
};
diff --git a/weather/demoforecastsource.cpp b/weather/demoforecastsource.cpp
new file mode 100644
index 0000000..db6f5cc
--- /dev/null
+++ b/weather/demoforecastsource.cpp
@@ -0,0 +1,140 @@
+#include "demoforecastsource.h"
+#include "forecast.h"
+
+#include <QTimer>
+#include <QFile>
+#include <QDebug>
+
+struct CityInfo
+{
+ const char * name;
+ const int lower;
+ const int temp;
+ const int upper;
+ const bool night;
+};
+
+static const CityInfo cityNames[Forecast::UnknownForecast] = {
+ {"Araxa", -7, -4, -1, true}, // MostlyCloudy
+ {"Belo Horizonte", 18, 22, 27, false}, // Cloudy
+ {"Recife", 25, 31, 34, true}, // MostlySunny
+ {"Ipojuca", 22, 29, 36, false}, // PartlyCloudy
+ {"Fortaleza", 31, 34, 36, true}, // Sunny
+ {"Sao Paulo", -1, 10, 12, false}, // Flurries
+ {"Uberlandia", -26, -23, -20, false}, // Fog
+ {"Governador Valadares", 3, 17, 18, true}, // Haze
+ {"Brasilia", 22, 25, 30, false}, // Sand
+ {"Florianopolis", 0, 8, 10, true}, // Dust
+ {"Gravata", -10, -2, 3, false}, // Icy
+ {"Maceio", 22, 35, 38, true}, // Sleet
+ {"Porto Alegre", -8, -6, -4, true}, // ChanceOfSleet
+ {"Batatais", -20, -12, -10, false}, // Snow
+ {"Ribeirao Preto", -20, -17, 0, true}, // ChanceOfSnow
+ {"Campinas", 1, 4, 10, false}, // Mist
+ {"Campo belo", 12, 19, 21, true}, // Rain
+ {"Sertaozinho", 10, 15, 17, true}, // ChanceOfRain
+ {"Pirassununga", -15, -12, 2, false}, // Storm
+ {"Goiania", 7, 13, 18, true}, // ChanceOfStorm
+ {"Manaus", 35, 41, 44, false}, // Thunderstorm
+ {"Belem", -14, -13, -5, true} // ChanceOfThunderstorm
+};
+
+DemoForecastSource::DemoForecastSource(int waitTime, QObject *parent)
+ : ForecastSource(parent)
+ , m_waitTime(waitTime)
+ , m_idSeq(0)
+{
+ createContentList();
+}
+
+
+int DemoForecastSource::findByLocId(const QString &locId)
+{
+ if (!locId.isEmpty())
+ for (int i = 0; i < m_requests.count(); ++i)
+ if (m_requests[i].m_locId == locId)
+ return i;
+ return -1;
+}
+
+int DemoForecastSource::findByQuery(const QString &query)
+{
+ if (!query.isEmpty())
+ for (int i = 0; i < m_requests.count(); ++i)
+ if (m_requests[i].m_cityQuery == query)
+ return i;
+ return -1;
+}
+
+QString DemoForecastSource::findCity(const QString &name)
+{
+ QString city = name.toUpper();
+ for (int i = 0; i < m_list.count(); ++i) {
+ if (city == m_list[i].cityName().toUpper())
+ return m_list[i].key();
+ }
+ return QString();
+}
+
+int DemoForecastSource::getForecast(const QString &key, bool locationId)
+{
+
+ int idx = locationId ? findByLocId(key) : findByQuery(key);
+ if (idx >= 0)
+ return m_requests[idx].m_reqId;
+
+ QString locId = locationId ? key : findCity(key);
+
+ Request request;
+ request.m_locId = locId;
+ request.m_cityQuery = key;
+ request.m_reqId = getId();
+ m_requests.append(request);
+ if (m_waitTime > 0)
+ QTimer::singleShot(m_waitTime, this, SLOT(sendResponse()));
+ else sendResponse();
+ return request.m_reqId;
+}
+
+void DemoForecastSource::createContentList()
+{
+ QFile file(":fake_content.xml");
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning() << "cannot open fake content file.";
+ return;
+ }
+ QDomDocument doc;
+ QString msg;
+ if (!doc.setContent(&file, &msg)) {
+ qWarning() << "fake content parse error: " << msg;
+ return;
+ }
+ if (doc.documentElement().childNodes().count() == 0) {
+ qWarning() << "fake content is empty.";
+ return;
+ }
+ QDomElement root = doc.documentElement();
+ for (int i = 0; i < root.childNodes().count(); ++i) {
+ if (root.childNodes().at(i).isElement()) {
+ QDomElement element = root.childNodes().at(i).toElement();
+ QString id = element.attribute("locId");
+ if (!id.isEmpty() && element.childNodes().count() == 1 &&
+ element.childNodes().at(0).isElement()) {
+ QDomElement child = element.childNodes().at(0).toElement();
+ m_list.append(ForecastData(new YahooWeatherResponse(id, child)));
+ }
+ }
+ }
+}
+
+void DemoForecastSource::sendResponse()
+{
+ if (!m_requests.isEmpty()) {
+ Request request = m_requests.takeFirst();
+ for (int i = 0; i < m_list.count(); ++i) {
+ if (m_list[i].key() == request.m_locId)
+ emit forecastReceived(request.m_reqId, m_list[i]);
+ }
+ emit forecastReceived(request.m_reqId, ForecastData(0));
+ }
+}
diff --git a/weather/demoforecastsource.h b/weather/demoforecastsource.h
new file mode 100644
index 0000000..dbfd715
--- /dev/null
+++ b/weather/demoforecastsource.h
@@ -0,0 +1,44 @@
+#ifndef DEMOFORECASTSOURCE_H
+#define DEMOFORECASTSOURCE_H
+
+#include "forecastsource.h"
+#include "yahooweatherresponse.h"
+
+#include <QList>
+
+class DemoForecastSource : public ForecastSource
+{
+ Q_OBJECT
+public:
+ DemoForecastSource(int waitTime, QObject *parent = 0);
+ int getForecast(const QString &key, bool locationId);
+
+private:
+
+ class Request
+ {
+ public:
+ int m_reqId;
+ QString m_locId;
+ QString m_cityQuery;
+ };
+
+ const int m_waitTime;
+ QList<Request> m_requests;
+ QList<ForecastData> m_list;
+ int m_idSeq;
+
+ void createContentList();
+ QString findCity(const QString &name);
+
+ int getId() { return ++m_idSeq; }
+
+ int findByLocId(const QString &locId);
+ int findByQuery(const QString &query);
+
+private slots:
+ void sendResponse();
+
+};
+
+#endif // DEMOFORECASTSOURCE_H
diff --git a/weather/fake_content.xml b/weather/fake_content.xml
new file mode 100644
index 0000000..2bff5f0
--- /dev/null
+++ b/weather/fake_content.xml
@@ -0,0 +1,27 @@
+<fake-content>
+ <item locId="INDT0001">
+ <rss version="2.0" xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
+ <channel>
+ <lastBuildDate>Mon, 09 Nov 2009 7:56 am PST</lastBuildDate>
+ <ttl>1440</ttl>
+
+ <yweather:units temperature="C" distance="mi" pressure="in" speed="mph"/>
+ <yweather:wind chill="46" direction="0" speed="0" />
+ <yweather:atmosphere humidity="76" visibility="10" pressure="30.11" rising="1" />
+ <yweather:astronomy sunrise="5:41 am" sunset="6:02 pm"/>
+ <item>
+ <geo:lat>37.39</geo:lat>
+ <geo:long>-122.03</geo:long>
+ <pubDate>Mon, 09 Nov 2009 7:56 am PST</pubDate>
+
+ <yweather:condition text="Mostly Cloudy" code="27" temp="22" date="Mon, 09 Nov 2009 7:56 am PST" />
+ <yweather:forecast day="Mon" date="9 Nov 2009" low="18" high="31" text="Mostly Cloudy" code="30" />
+ <yweather:forecast day="Tue" date="10 Nov 2009" low="49" high="68" text="Mostly Cloudy" code="28" />
+ <guid isPermaLink="false">USCA1116_2009_11_09_7_56_PST</guid>
+ </item>
+ <yweather:location city="Mostly Cloudy" region="" country=""/>
+
+ </channel>
+ </rss>
+ </item>
+</fake-content>
diff --git a/weather/forecastdata.cpp b/weather/forecastdata.cpp
new file mode 100644
index 0000000..45e2567
--- /dev/null
+++ b/weather/forecastdata.cpp
@@ -0,0 +1,78 @@
+#include "forecastdata.h"
+
+struct ConditionTypeData
+{
+ const int id;
+ Forecast::ForecastType type;
+};
+
+static const int ContitionTypeCount = 47;
+static const ConditionTypeData ContitionType[ContitionTypeCount] = {
+ {1, Forecast::Storm},
+ {2, Forecast::Thunderstorm},
+ {3, Forecast::Thunderstorm},
+ {4, Forecast::Thunderstorm},
+ {5, Forecast::Sleet},
+ {6, Forecast::Rain},
+ {7, Forecast::Sleet},
+ {8, Forecast::Mist},
+ {9, Forecast::Mist},
+ {10, Forecast::Rain},
+ {11, Forecast::Rain},
+ {12, Forecast::Rain},
+ {13, Forecast::Flurries},
+ {14, Forecast::Flurries},
+ {15, Forecast::Snow},
+ {16, Forecast::Snow},
+ {17, Forecast::Snow},
+ {18, Forecast::Sleet},
+ {19, Forecast::Haze},
+ {20, Forecast::Fog},
+ {21, Forecast::Haze},
+ {22, Forecast::Fog},
+ {23, Forecast::Cloudy},
+ {24, Forecast::Cloudy},
+ {25, Forecast::Cloudy},
+ {26, Forecast::Cloudy},
+ {27, Forecast::MostlyCloudy},
+ {28, Forecast::MostlyCloudy},
+ {29, Forecast::PartlyCloudy},
+ {30, Forecast::PartlyCloudy},
+ {31, Forecast::Sunny},
+ {32, Forecast::Sunny},
+ {33, Forecast::MostlySunny},
+ {34, Forecast::MostlySunny},
+ {35, Forecast::Sleet},
+ {36, Forecast::Sunny},
+ {37, Forecast::Thunderstorm},
+ {38, Forecast::Thunderstorm},
+ {39, Forecast::Thunderstorm},
+ {40, Forecast::Storm},
+ {41, Forecast::Snow},
+ {42, Forecast::Sleet},
+ {43, Forecast::Snow},
+ {44, Forecast::PartlyCloudy},
+ {45, Forecast::Thunderstorm},
+ {46, Forecast::Sleet},
+ {47, Forecast::Thunderstorm}
+};
+
+
+Forecast::ForecastType ForecastData::type() const
+{
+ if (m_data) {
+ for (int i = 0; i < ContitionTypeCount; ++i)
+ if (ContitionType[i].id == m_data->condition().code())
+ return ContitionType[i].type;
+ }
+ return Forecast::UnknownForecast;
+}
+
+bool ForecastData::night() const
+{
+ if (!m_data)
+ return false;
+ return m_data->condition().date().time() < m_data->astronomy().sunrise()
+ || m_data->condition().date().time() > m_data->astronomy().sunset();
+}
+
diff --git a/weather/forecastdata.h b/weather/forecastdata.h
index eaf711f..bf5b9cd 100644
--- a/weather/forecastdata.h
+++ b/weather/forecastdata.h
@@ -3,60 +3,42 @@
#include <QString>
#include "forecast.h"
+#include "yahooweatherresponse.h"
+
+#include <QSharedPointer>
+
+class YahooWeatherResponse;
class ForecastData
{
public:
- ForecastData()
- : m_error(false)
- , m_lower(0)
- , m_current(0)
- , m_upper(0)
- , m_isNull(true)
- {}
- ForecastData(bool error, Forecast::ForecastType type, bool night, const QString &key,
- const QString &cityName, int lower, int current, int upper)
- : m_type(type)
- , m_night(night)
- , m_error(error)
- , m_key(key)
- , m_cityName(cityName)
- , m_lower(lower)
- , m_current(current)
- , m_upper(upper)
- , m_isNull(false)
- {}
-
- Forecast::ForecastType type() const { return m_type; }
- bool night() const { return m_night; }
+ ForecastData() : m_error(false), m_data(0) {}
+ ForecastData(YahooWeatherResponse *data) : m_error(!data), m_data(data) {}
+
+ Forecast::ForecastType type() const;
+ bool night() const;
bool error() const { return m_error; }
- QString key() const { return m_key; }
- QString cityName() const { return m_cityName; }
- int lower() const { return m_lower; }
- int current() const { return m_current; }
- int upper() const { return m_upper; }
- bool isNull() const { return m_isNull; }
+ QString key() const { return m_data ? m_data->locationCode() : QString(); }
+ QString cityName() const { return m_data ? m_data->location().city() : QString(); }
+ int lower() const { return m_data ? m_data->forecast(0).low() : 0; }
+ int current() const { return m_data ? m_data->condition().temperature() : 0; }
+ int upper() const { return m_data ? m_data->forecast(0).high() : 0; }
+ bool isNull() const { return !m_error && !m_data; }
inline bool operator==(const ForecastData &other);
bool operator!=(const ForecastData &other) { return !operator==(other); }
private:
- Forecast::ForecastType m_type;
- bool m_night;
bool m_error;
- QString m_key;
- QString m_cityName;
- int m_lower;
- int m_current;
- int m_upper;
- bool m_isNull;
+
+ QSharedPointer<YahooWeatherResponse> m_data;
};
bool ForecastData::operator==(const ForecastData &other)
{
- return m_type == other.m_type && m_night == other.m_night && m_error == other.m_error
- && m_key == other.m_key && m_cityName == other.m_cityName && m_lower == other.m_lower
- && m_current == other.m_current && m_upper == other.m_upper;
+ return type() == other.type() && night() == other.night() && error() == other.error()
+ && key() == other.key() && cityName() == other.cityName() && lower() == other.lower()
+ && current() == other.current() && upper() == other.upper();
}
#endif // FORECASTDATA_H
diff --git a/weather/forecastprovider.cpp b/weather/forecastprovider.cpp
index 94c7341..5bda3fe 100644
--- a/weather/forecastprovider.cpp
+++ b/weather/forecastprovider.cpp
@@ -4,52 +4,21 @@
#include "forecast.h"
-struct CityInfo
-{
- const char * name;
- const int lower;
- const int temp;
- const int upper;
- const bool night;
-};
-
-static const CityInfo cityNames[Forecast::UnknownForecast] = {
- {"Araxa", -7, -4, -1, true}, // MostlyCloudy
- {"Belo Horizonte", 18, 22, 27, false}, // Cloudy
- {"Recife", 25, 31, 34, true}, // MostlySunny
- {"Ipojuca", 22, 29, 36, false}, // PartlyCloudy
- {"Fortaleza", 31, 34, 36, true}, // Sunny
- {"Sao Paulo", -1, 10, 12, false}, // Flurries
- {"Uberlandia", -26, -23, -20, false}, // Fog
- {"Governador Valadares", 3, 17, 18, true}, // Haze
- {"Brasilia", 22, 25, 30, false}, // Sand
- {"Florianopolis", 0, 8, 10, true}, // Dust
- {"Gravata", -10, -2, 3, false}, // Icy
- {"Maceio", 22, 35, 38, true}, // Sleet
- {"Porto Alegre", -8, -6, -4, true}, // ChanceOfSleet
- {"Batatais", -20, -12, -10, false}, // Snow
- {"Ribeirao Preto", -20, -17, 0, true}, // ChanceOfSnow
- {"Campinas", 1, 4, 10, false}, // Mist
- {"Campo belo", 12, 19, 21, true}, // Rain
- {"Sertaozinho", 10, 15, 17, true}, // ChanceOfRain
- {"Pirassununga", -15, -12, 2, false}, // Storm
- {"Goiania", 7, 13, 18, true}, // ChanceOfStorm
- {"Manaus", 35, 41, 44, false}, // Thunderstorm
- {"Belem", -14, -13, -5, true} // ChanceOfThunderstorm
-};
-
ForecastProvider::ForecastProvider()
+ : m_source(0)
{
}
ForecastProvider::~ForecastProvider()
{
- qDeleteAll(m_requests);
}
-void ForecastProvider::getForecast(const QString &key, bool refresh)
+int ForecastProvider::getForecast(const QString &key, bool locationId)
{
- instance()->doGetForecast(key, refresh);
+ ForecastProvider *obj = instance();
+ if (obj->m_source)
+ return obj->m_source->getForecast(key, locationId);
+ return -1;
}
ForecastProvider *ForecastProvider::instance()
@@ -58,65 +27,28 @@ ForecastProvider *ForecastProvider::instance()
return result;
}
-void ForecastProvider::connectToResponseSignal(QObject *receiver, const char *method)
-{
- QObject::connect(instance(), SIGNAL(forecastResponse(ForecastData)),
- receiver, method, Qt::QueuedConnection);
-}
-void ForecastProvider::disconnectReceiver(QObject *receiver)
+void ForecastProvider::setForecastSource(ForecastSource *source)
{
- instance()->disconnect(receiver);
-}
-
-void ForecastProvider::doSendRequest(const QString &key)
-{
- qsrand(QTime(0, 0).secsTo(QTime::currentTime()) * qrand());
- m_dumbRequestList.append(key);
- QTimer::singleShot((qrand() % 400) + 100, this, SLOT(receiveDumbResponse()));
-}
-
-void ForecastProvider::receiveDumbResponse()
-{
- QString key = m_dumbRequestList.takeFirst();
- for (int i = 0; i < Forecast::UnknownForecast; ++i) {
- if (key.compare(cityNames[i].name, Qt::CaseInsensitive) == 0) {
- ForecastData response(false, Forecast::ForecastType(i), cityNames[i].night, key,
- cityNames[i].name, cityNames[i].lower, cityNames[i].temp,
- cityNames[i].upper);
- forecastReceived(response);
- return;
- }
+ ForecastProvider *obj = instance();
+ if (obj->m_source) {
+ disconnect(obj->m_source, SIGNAL(forecastReceived(int, ForecastData)),
+ obj, SIGNAL(forecastResponse(int, ForecastData)));
+ obj->m_source->deleteLater();
}
- forecastReceived(ForecastData(true, Forecast::UnknownForecast, false, key, "", 0, 0, 0));
+ obj->m_source = source;
+ if (obj->m_source)
+ connect(obj->m_source, SIGNAL(forecastReceived(int, ForecastData)),
+ obj, SIGNAL(forecastResponse(int, ForecastData)), Qt::QueuedConnection);
}
-void ForecastProvider::doGetForecast(const QString &key, bool refresh)
+void ForecastProvider::connectToResponseSignal(QObject *receiver, const char *method)
{
- ForecastRequestInfo *request = 0;
- if (!m_requests.contains(key)) {
- request = new ForecastRequestInfo();
- m_requests[key] = request;
- doSendRequest(key);
- return;
- }
- request = m_requests[key];
- if (!request->m_ready)
- return;
- if (refresh) {
- request->m_ready = false;
- doSendRequest(key);
- return;
- }
- emit forecastResponse(request->m_response);
+ QObject::connect(instance(), SIGNAL(forecastResponse(int, ForecastData)),
+ receiver, method, Qt::QueuedConnection);
}
-void ForecastProvider::forecastReceived(const ForecastData &forecast)
+void ForecastProvider::disconnectReceiver(QObject *receiver)
{
- if (!m_requests.contains(forecast.key()))
- return;
- ForecastRequestInfo *request = m_requests[forecast.key()];
- request->m_ready = true;
- request->m_response = forecast;
- emit forecastResponse(request->m_response);
+ instance()->disconnect(receiver);
}
diff --git a/weather/forecastprovider.h b/weather/forecastprovider.h
index 602b773..fcb75dd 100644
--- a/weather/forecastprovider.h
+++ b/weather/forecastprovider.h
@@ -8,44 +8,30 @@
#include <QMap>
#include "forecastdata.h"
+#include "forecastsource.h"
class ForecastProvider : public QObject
{
Q_OBJECT
public:
- static void getForecast(const QString &key, bool refresh = false);
+ static int getForecast(const QString &key, bool locationId);
+
static void connectToResponseSignal(QObject *receiver, const char *method);
static void disconnectReceiver(QObject *receiver);
+ static void setForecastSource(ForecastSource *source);
+
signals:
- void forecastResponse(const ForecastData &forecast);
+ void forecastResponse(int reqId, const ForecastData &forecast);
private:
- struct ForecastRequestInfo
- {
- ForecastRequestInfo() : m_ready(false) {}
- bool m_ready;
- ForecastData m_response;
- };
-
- QMap<QString, ForecastRequestInfo*> m_requests;
+ ForecastSource *m_source;
ForecastProvider();
~ForecastProvider();
static ForecastProvider *instance();
- void doGetForecast(const QString &key, bool refresh);
- void forecastReceived(const ForecastData &forecast);
-
- void doSendRequest(const QString &key);
-
-private:
- QStringList m_dumbRequestList;
-
-private slots:
- void receiveDumbResponse();
-
};
#endif // FORECASTPROVIDER_H
diff --git a/weather/forecastsource.h b/weather/forecastsource.h
new file mode 100644
index 0000000..8c7cfbe
--- /dev/null
+++ b/weather/forecastsource.h
@@ -0,0 +1,18 @@
+#ifndef FORECASTSOURCE_H
+#define FORECASTSOURCE_H
+
+#include <QObject>
+#include "forecastdata.h"
+
+class ForecastSource : public QObject
+{
+ Q_OBJECT
+public:
+ ForecastSource(QObject *parent = 0) : QObject(parent) {}
+ virtual int getForecast(const QString &key, bool locationId) = 0;
+
+signals:
+ void forecastReceived(int id, const ForecastData &data);
+};
+
+#endif // FORECASTSOURCE_H
diff --git a/weather/main.cpp b/weather/main.cpp
index e35a7fc..e90a959 100644
--- a/weather/main.cpp
+++ b/weather/main.cpp
@@ -40,6 +40,14 @@
#include "forecastdata.h"
#include "settings.h"
+#include "forecastprovider.h"
+#include "demoforecastsource.h"
+#include "networkforecastsource.h"
+
+#if defined (Q_OS_SYMBIAN)
+#include "sym_iap_util.h"
+#endif
+
int main(int argc, char **argv)
{
qRegisterMetaType<ForecastData>("ForecastData");
@@ -52,9 +60,12 @@ int main(int argc, char **argv)
MainView mainView;
// mainView.setFixedSize(windowSize);
+ ForecastProvider::setForecastSource(new NetworkForecastSource());
+
#ifdef Q_OS_SYMBIAN
mainView.showFullScreen();
Settings::fixedPortraitOrientation();
+ qt_SetDefaultIap();
#else
mainView.show();
#endif
diff --git a/weather/networkforecastsource.cpp b/weather/networkforecastsource.cpp
new file mode 100644
index 0000000..c2a7dbe
--- /dev/null
+++ b/weather/networkforecastsource.cpp
@@ -0,0 +1,237 @@
+#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)
+{
+ qDebug() << "----------------------------------------------";
+ qDebug() << "forecast response received: " << reqId;
+ forecast->print();
+ qDebug() << "----------------------------------------------";
+ emit forecastReceived(reqId, ForecastData(forecast));
+}
+
+void NetworkForecastSource::forecastResponseError(int reqId)
+{
+ emit forecastReceived(reqId, ForecastData(0));
+}
+
+
+
+
+
diff --git a/weather/networkforecastsource.h b/weather/networkforecastsource.h
new file mode 100644
index 0000000..49f26c5
--- /dev/null
+++ b/weather/networkforecastsource.h
@@ -0,0 +1,75 @@
+#ifndef NETWORKFORECASTSOURCE_H
+#define NETWORKFORECASTSOURCE_H
+
+#include "forecastdata.h"
+#include "forecastsource.h"
+#include <QObject>
+#include <QMap>
+#include <QStringList>
+#include <QNetworkAccessManager>
+
+class LocationRequestManager : public QObject
+{
+ Q_OBJECT
+public:
+ LocationRequestManager(QObject *parent = 0);
+ int addRequest(const QString &query);
+
+signals:
+ void newLocationId(int reqId, const QString &locId);
+ void locationIdQueryError(int reqId, const QString &query);
+
+private slots:
+ void receiveResponse(QNetworkReply *reply);
+
+private:
+ QMap<QString, int> m_requests;
+ QNetworkAccessManager m_network;
+
+ QString readResponse(const QString &query, QNetworkReply *reply);
+};
+
+class ForecastRequestmanager : public QObject
+{
+ Q_OBJECT
+public:
+ ForecastRequestmanager(QObject *parent = 0);
+
+ int addRequest(const QString &locId);
+
+public slots:
+ void addRequest(int reqId, const QString &locId);
+
+signals:
+ void newForecastResponse(int reqId, YahooWeatherResponse *forecast);
+ void forecastResponseError(int reqId);
+
+private slots:
+ void receiveResponse(QNetworkReply *reply);
+
+private:
+ QMap<QString, QList<int> > m_requests;
+ QNetworkAccessManager m_network;
+
+ YahooWeatherResponse *readResponse(const QString &query, QNetworkReply *locId);
+ void doAddRequest(int reqId, const QString &locId);
+};
+
+class NetworkForecastSource : public ForecastSource
+{
+ Q_OBJECT
+public:
+ NetworkForecastSource(QObject *parent = 0);
+ ~NetworkForecastSource();
+ int getForecast(const QString &key, bool locationId);
+
+private:
+ LocationRequestManager m_locationManager;
+ ForecastRequestmanager m_forecastManager;
+
+private slots:
+ void newForecastResponse(int reqId, YahooWeatherResponse *forecast);
+ void forecastResponseError(int reqId);
+};
+
+#endif // NETWORKFORECASTSOURCE_H
diff --git a/weather/resources.qrc b/weather/resources.qrc
index b4a8863..94386d5 100644
--- a/weather/resources.qrc
+++ b/weather/resources.qrc
@@ -96,5 +96,6 @@
<file>images/weather_elements/scroll.png</file>
<file>images/weather_elements/scroll_knob.png</file>
<file>images/weather_elements/city_name_background_bigger.png</file>
+ <file>fake_content.xml</file>
</qresource>
</RCC>
diff --git a/weather/settings.cpp b/weather/settings.cpp
index 896c90d..3c926dc 100644
--- a/weather/settings.cpp
+++ b/weather/settings.cpp
@@ -78,7 +78,6 @@ public:
CitySortHelper(const QMap<QString, int> &map) : m_map(map) {}
bool operator()(const QString &city1, const QString &city2)
{
- qDebug() << city1 << m_map[city1] << city2 << m_map[city2] << (m_map[city1] < m_map[city2]);
return m_map[city1] < m_map[city2];
}
diff --git a/weather/sym_iap_util.h b/weather/sym_iap_util.h
new file mode 100644
index 0000000..14df5af
--- /dev/null
+++ b/weather/sym_iap_util.h
@@ -0,0 +1,131 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the either Technology Preview License Agreement or the
+** Beta Release License Agreement.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain
+** additional rights. These rights are described in the Nokia Qt LGPL
+** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
+** package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#ifndef QSYM_IAP_UTIL_H
+#define QSYM_IAP_UTIL_H
+
+#include <es_sock.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <rconnmon.h>
+
+QString qt_TDesC2QStringL(const TDesC& aDescriptor)
+{
+#ifdef QT_NO_UNICODE
+ return QString::fromLocal8Bit(aDescriptor.Ptr(), aDescriptor.Length());
+#else
+ return QString::fromUtf16(aDescriptor.Ptr(), aDescriptor.Length());
+#endif
+}
+
+static void qt_SetDefaultIapL()
+{
+ TUint count;
+ TRequestStatus status;
+ TUint ids[15];
+
+ RSocketServ serv;
+ CleanupClosePushL(serv);
+
+ RConnection conn;
+ CleanupClosePushL(conn);
+
+ RConnectionMonitor monitor;
+ CleanupClosePushL(monitor);
+
+ monitor.ConnectL();
+ monitor.GetConnectionCount(count, status);
+ User::WaitForRequest(status);
+ if(status.Int() != KErrNone) {
+ User::Leave(status.Int());
+ }
+
+ TUint numSubConnections;
+
+ if(count > 0) {
+ for (TInt i = 1; i <= count; i++) {
+ User::LeaveIfError(monitor.GetConnectionInfo(i, ids[i-1], numSubConnections));
+ }
+ /*
+ * get IAP value for first active connection
+ */
+ TBuf< 50 > iapName;
+ monitor.GetStringAttribute(ids[0], 0, KIAPName, iapName, status);
+ User::WaitForRequest(status);
+ if (status.Int() != KErrNone) {
+ User::Leave(status.Int());
+ } else {
+ QString strIapName = qt_TDesC2QStringL(iapName);
+ struct ifreq ifReq;
+ strcpy(ifReq.ifr_name, strIapName.toLatin1().data());
+ User::LeaveIfError(setdefaultif(&ifReq));
+ }
+ } else {
+ /*
+ * no active connections yet
+ * use IAP dialog to select one
+ */
+ User::LeaveIfError(serv.Connect());
+ User::LeaveIfError(conn.Open(serv));
+ User::LeaveIfError(conn.Start());
+
+ _LIT(KIapNameSetting, "IAP\\Name");
+ TBuf8<50> iap8Name;
+ User::LeaveIfError(conn.GetDesSetting(TPtrC(KIapNameSetting), iap8Name));
+ iap8Name.ZeroTerminate();
+
+ conn.Stop();
+
+ struct ifreq ifReq;
+ strcpy(ifReq.ifr_name, (char*)iap8Name.Ptr());
+ User::LeaveIfError(setdefaultif(&ifReq));
+ }
+ CleanupStack::PopAndDestroy(&monitor);
+ CleanupStack::PopAndDestroy(&conn);
+ CleanupStack::PopAndDestroy(&serv);
+}
+
+static int qt_SetDefaultIap()
+{
+ TRAPD(err, qt_SetDefaultIapL());
+ return err;
+}
+
+#endif // QSYM_IAP_UTIL_H
diff --git a/weather/weather.ini b/weather/weather.ini
index 59f46a6..bfce791 100644
--- a/weather/weather.ini
+++ b/weather/weather.ini
@@ -1,27 +1,12 @@
[General]
-windowSize = @Size(480 864)
+windowSize=@Size(360 640)
[Cities]
-Araxa = 1
-Belo Horizonte = 2
-Recife = 3
-Ipojuca = 4
-Fortaleza = 5
-Sao Paulo = 6
-Uberlandia = 7
-Governador Valadares = 8
-Brasilia = 9
-Florianopolis = 10
-Gravata = 11
-Maceio = 12
-Porto Alegre = 13
-Batatais = 14
-Ribeirao Preto = 15
-Campinas = 16
-Campo belo = 17
-Sertaozinho = 18
-Pirassununga = 19
-Goiania = 20
-Manaus = 21
-Belem = 22
-[Cities]
+NOXX0029=0
+ASXX0112=1
+USND0343=2
+UKXX0085=3
+BRXX0309=4
+IDXX0022=5
+CHXX0049=6
+INXX0012=7
diff --git a/weather/weather.pro b/weather/weather.pro
index bbbdddf..50d2c0b 100644
--- a/weather/weather.pro
+++ b/weather/weather.pro
@@ -1,6 +1,7 @@
TEMPLATE = app
TARGET = weather
-QT += network
+QT += network \
+ xml
target.path = $$PREFIX/bin
INSTALLS += target
RESOURCES += resources.qrc
@@ -50,7 +51,13 @@ HEADERS += mainview.h \
citylist.h \
citymanager.h \
addcitytool.h \
- painttextitem.h
+ painttextitem.h \
+ forecastsource.h \
+ demoforecastsource.h \
+ networkforecastsource.h \
+ yahooweatherresponse.h \
+ xoapweatherresponse.h \
+ sym_iap_util.h
SOURCES += mainview.cpp \
main.cpp \
settings.cpp \
@@ -73,4 +80,9 @@ SOURCES += mainview.cpp \
citylist.cpp \
citymanager.cpp \
addcitytool.cpp \
- painttextitem.cpp
+ painttextitem.cpp \
+ demoforecastsource.cpp \
+ networkforecastsource.cpp \
+ yahooweatherresponse.cpp \
+ xoapweatherresponse.cpp \
+ forecastdata.cpp
diff --git a/weather/xoapweatherresponse.cpp b/weather/xoapweatherresponse.cpp
new file mode 100644
index 0000000..3c520e2
--- /dev/null
+++ b/weather/xoapweatherresponse.cpp
@@ -0,0 +1,48 @@
+#include "xoapweatherresponse.h"
+
+#include <QDebug>
+
+static inline int strToInt(const QString &str, int defaultValue)
+{
+ bool ok;
+ int result = str.toInt(&ok);
+ return ok ? result : defaultValue;
+}
+
+static inline QString getNodeContentText(QDomNode node)
+{
+ if (node.childNodes().count() == 0 || !node.childNodes().at(0).isText())
+ return QString();
+ return node.childNodes().at(0).nodeValue();
+}
+
+void XoapWeatherResponse::Item::read(QDomElement element)
+{
+ m_id = element.attribute("id");
+ m_type = strToInt(element.attribute("type"), 0);
+ m_texts.clear();
+ m_texts << getNodeContentText(element).split(",", QString::SkipEmptyParts);
+}
+
+XoapWeatherResponse::XoapWeatherResponse()
+{
+}
+
+void XoapWeatherResponse::read(QDomElement element)
+{
+ m_version = element.attribute("ver");
+ for (int i = 0; i < element.childNodes().count(); ++i) {
+ if (element.childNodes().at(i).isElement()) {
+ Item item;
+ item.read(element.childNodes().at(i).toElement());
+ m_list.append(item);
+ }
+ }
+}
+
+void XoapWeatherResponse::print()
+{
+ qDebug() << m_version << m_list.count() << " items";
+ for (int i = 0; i < m_list.count(); ++i)
+ qDebug() << "item " << i << " : " << m_list[i].id() << m_list[i].type() << m_list[i].texts();
+}
diff --git a/weather/xoapweatherresponse.h b/weather/xoapweatherresponse.h
new file mode 100644
index 0000000..1fd13cd
--- /dev/null
+++ b/weather/xoapweatherresponse.h
@@ -0,0 +1,43 @@
+#ifndef XOAPWEATHERRESPONSE_H
+#define XOAPWEATHERRESPONSE_H
+
+#include <QString>
+#include <QStringList>
+#include <QDomElement>
+#include <QTime>
+#include <QDate>
+#include <QDateTime>
+
+class XoapWeatherResponse
+{
+public:
+ class Item
+ {
+ public:
+ Item() : m_type(0) {}
+ void read(QDomElement element);
+
+ QStringList texts() const { return m_texts; }
+ int type() const { return m_type; }
+ QString id() const { return m_id; }
+
+ private:
+ QStringList m_texts;
+ int m_type;
+ QString m_id;
+
+ };
+ XoapWeatherResponse();
+ void read(QDomElement element);
+ void print();
+
+ QString versionid() const { return m_version; }
+ const QList<Item> &items() const { return m_list; }
+
+
+private:
+ QString m_version;
+ QList<Item> m_list;
+};
+
+#endif // XOAPWEATHERRESPONSE_H
diff --git a/weather/yahooweatherresponse.cpp b/weather/yahooweatherresponse.cpp
new file mode 100644
index 0000000..325b632
--- /dev/null
+++ b/weather/yahooweatherresponse.cpp
@@ -0,0 +1,163 @@
+#include "yahooweatherresponse.h"
+#include <QDebug>
+
+static inline int strToInt(const QString &str, int defaultValue)
+{
+ bool ok;
+ int result = str.toInt(&ok);
+ return ok ? result : defaultValue;
+}
+
+static inline float strToFloat(const QString &str, qreal defaultValue)
+{
+ bool ok;
+ float result = str.toFloat(&ok);
+ return ok ? result : defaultValue;
+}
+
+static inline YahooWeatherResponse::PressureState readPressure(const QString &str)
+{
+ switch (strToInt(str, 0)) {
+ case 1: return YahooWeatherResponse::Rising;
+ case 2: return YahooWeatherResponse::Falling;
+ default: return YahooWeatherResponse::Steady;
+ }
+}
+
+static inline QString getNodeContentText(QDomNode node)
+{
+ if (node.childNodes().count() == 0 || !node.childNodes().at(0).isText())
+ return QString();
+ return node.childNodes().at(0).nodeValue();
+}
+
+static const QDateTime readDateTime(const QString &str)
+{
+ QString text = str.right(str.length() - str.indexOf(',') - 1);
+ int len = text.indexOf("am", 15);
+ len = len < 0 ? text.indexOf("pm", 15) : len;
+ text = text.left(len + 2).trimmed();
+ return QDateTime::fromString(text, "dd MMM yyyy h:mm ap");
+}
+
+YahooWeatherResponse::Location::Location(QDomElement element)
+ : m_city(element.attribute("city"))
+ , m_region(element.attribute("region"))
+ , m_country(element.attribute("country"))
+{}
+
+YahooWeatherResponse::Units::Units(QDomElement element)
+ : m_temperature(element.attribute("temperature") == "f" ? Fahrenheit : Celsius)
+ , m_distance(element.attribute("distance") == "mi" ? Miles : Kilometers)
+ , m_pressure(element.attribute("pressure") == "in" ? PoundsPerSquare : Millibars)
+ , m_speed(element.attribute("speed") == "mph" ? MilesPerHour : KilometersPerHour)
+{}
+
+YahooWeatherResponse::Wind::Wind(QDomElement element)
+ : m_chill(strToInt(element.attribute("chill"), 0))
+ , m_direction(strToInt(element.attribute("direction"), 0))
+ , m_speed(strToInt(element.attribute("speed"), 0))
+{}
+
+YahooWeatherResponse::Atmosphere::Atmosphere(QDomElement element)
+ : m_humidity(strToInt(element.attribute("humidity"), 0))
+ , m_visibility(strToFloat(element.attribute("visibility"), 0.0) * 100)
+ , m_pressure(strToFloat(element.attribute("pressure"), 0.0))
+ , m_pressureState(readPressure(element.attribute("rising")))
+{}
+
+YahooWeatherResponse::Astronomy::Astronomy(QDomElement element)
+ : m_sunrise(QTime::fromString(element.attribute("sunrise"), "h:mm ap"))
+ , m_sunset(QTime::fromString(element.attribute("sunset"), "h:mm ap"))
+{}
+
+YahooWeatherResponse::Condition::Condition(QDomElement element)
+ : m_text(element.attribute("text"))
+ , m_code(strToInt(element.attribute("code"), 3200))
+ , m_temperature(strToInt(element.attribute("temp"), 0))
+ , m_date(readDateTime(element.attribute("date")))
+{}
+
+YahooWeatherResponse::Forecast::Forecast(QDomElement element)
+ : m_date(QDate::fromString(element.attribute("date"), "dd MMM yyyy"))
+ , m_low(strToInt(element.attribute("low"), 0))
+ , m_high(strToInt(element.attribute("high"), 0))
+ , m_text(element.attribute("text"))
+ , m_code(strToInt(element.attribute("code"), 3200))
+{}
+
+void YahooWeatherResponse::readItem(QDomElement item)
+{
+ int idx = 0;
+ for (int i = 0; i < item.childNodes().count(); ++i) {
+ QDomNode node = item.childNodes().at(i);
+ if (node.nodeName() == "geo:lat")
+ m_latitude = strToFloat(getNodeContentText(node), 0.0);
+ if (node.nodeName() == "geo:long")
+ m_longitude = strToFloat(getNodeContentText(node), 0.0);
+ if (node.nodeName() == "pubDate")
+ m_pubDate = readDateTime(getNodeContentText(node));
+ if (node.nodeName() == "yweather:condition")
+ m_condition = Condition(node.toElement());
+ if (node.nodeName() == "yweather:forecast")
+ m_forecast[idx++] = Forecast(node.toElement());
+ idx = idx > 1 ? 0 : idx;
+ }
+}
+
+YahooWeatherResponse::YahooWeatherResponse(const QString &locationCode, QDomElement element)
+ : m_locationCode(locationCode)
+{
+ QDomNodeList channels = element.elementsByTagName("channel");
+ if (channels.count() == 0)
+ return;
+ QDomElement channel = channels.item(0).toElement();
+ for (int i = 0; i < channel.childNodes().count(); ++i) {
+ QDomNode node = channel.childNodes().at(i);
+
+ if (node.nodeName() == "lastBuildDate")
+ m_buildDate = readDateTime(getNodeContentText(node));
+
+ if (node.nodeName() == "ttl")
+ m_timeToLive = strToInt(getNodeContentText(node), 30);
+
+ if (node.nodeName() == "yweather:location")
+ m_location = Location(node.toElement());
+
+ if (node.nodeName() == "yweather:units")
+ m_units = Units(node.toElement());
+
+ if (node.nodeName() == "yweather:wind")
+ m_wind = Wind(node.toElement());
+
+ if (node.nodeName() == "yweather:atmosphere")
+ m_atmosphere = Atmosphere(node.toElement());
+
+ if (node.nodeName() == "yweather:astronomy")
+ m_astronomy = Astronomy(node.toElement());
+
+ if (node.nodeName() == "item")
+ readItem(node.toElement());
+
+ }
+}
+
+void YahooWeatherResponse::print()
+{
+ qDebug() << "location code" << m_locationCode;
+ qDebug() << "buildDate" << m_buildDate;
+ qDebug() << "timeToLive" << m_timeToLive;
+
+ qDebug() << "latitude" << m_latitude;
+ qDebug() << "longitude" << m_longitude;
+ qDebug() << "pubDate" << m_pubDate;
+
+ qDebug() << "astronomy" << m_astronomy.sunrise() << m_astronomy.sunset();
+ qDebug() << "atmosphere" << m_atmosphere.humidity() << m_atmosphere.visibility() << m_atmosphere.pressure() << m_atmosphere.pressureState();
+ qDebug() << "condition" << m_condition.text() << m_condition.code() << m_condition.temperature() << m_condition.date();
+ qDebug() << "forecast" << m_forecast[0].text() << m_forecast[0].code() << m_forecast[0].low() << m_forecast[0].high() << m_forecast[0].date();
+ qDebug() << "forecast" << m_forecast[1].text() << m_forecast[1].code() << m_forecast[1].low() << m_forecast[1].high() << m_forecast[1].date();
+ qDebug() << "location" << m_location.city() << m_location.region() << m_location.country();
+ qDebug() << "units" << m_units.distance() << m_units.pressure() << m_units.speed() << m_units.temperature();
+ qDebug() << "wind" << m_wind.chill() << m_wind.direction() << m_wind.speed();
+}
diff --git a/weather/yahooweatherresponse.h b/weather/yahooweatherresponse.h
new file mode 100644
index 0000000..ac9d20e
--- /dev/null
+++ b/weather/yahooweatherresponse.h
@@ -0,0 +1,181 @@
+#ifndef YAHOOWEATHERRESPONSE_H
+#define YAHOOWEATHERRESPONSE_H
+
+#include <QString>
+#include <QDomElement>
+#include <QTime>
+#include <QDate>
+#include <QDateTime>
+
+class YahooWeatherResponse
+{
+public:
+ enum TemperatureUnit { Fahrenheit, Celsius };
+ enum DistanceUnit { Miles, Kilometers };
+ enum PressureUnit { PoundsPerSquare, Millibars };
+ enum SpeedUnit { MilesPerHour, KilometersPerHour };
+ enum PressureState { Steady, Rising, Falling };
+
+ class Location
+ {
+ public:
+ Location() {};
+ Location(QDomElement element);
+ QString city() const { return m_city; }
+ QString region() const { return m_region; }
+ QString country() const { return m_country; }
+
+ private:
+ QString m_city;
+ QString m_region;
+ QString m_country;
+ };
+
+ class Units
+ {
+ public:
+ Units() {};
+ Units(QDomElement element);
+ TemperatureUnit temperature() const { return m_temperature; }
+ DistanceUnit distance() const { return m_distance; }
+ PressureUnit pressure() const { return m_pressure; }
+ SpeedUnit speed() const { return m_speed; }
+
+ private:
+ TemperatureUnit m_temperature;
+ DistanceUnit m_distance;
+ PressureUnit m_pressure;
+ SpeedUnit m_speed;
+ };
+
+ class Wind
+ {
+ public:
+ Wind() {};
+ Wind(QDomElement element);
+ int chill() const { return m_chill; }
+ int direction() const { return m_direction; }
+ int speed() const { return m_speed; }
+
+ private:
+ int m_chill;
+ int m_direction;
+ int m_speed;
+ };
+
+ class Atmosphere
+ {
+ public:
+ Atmosphere() {};
+ Atmosphere(QDomElement element);
+ int humidity() const { return m_humidity; }
+ float visibility() const { return m_visibility; }
+ float pressure() const { return m_pressure; }
+ PressureState pressureState() const { return m_pressureState; }
+
+ private:
+ int m_humidity;
+ float m_visibility;
+ float m_pressure;
+ PressureState m_pressureState;
+ };
+
+ class Astronomy
+ {
+ public:
+ Astronomy() {};
+ Astronomy(QDomElement element);
+ QTime sunrise() const { return m_sunrise; }
+ QTime sunset() const { return m_sunset; }
+
+ private:
+ QTime m_sunrise;
+ QTime m_sunset;
+ };
+
+ class Condition
+ {
+ public:
+ Condition() {};
+ Condition(QDomElement element);
+ QString text() const { return m_text; }
+ int code() const { return m_code; }
+ int temperature() const { return m_temperature; }
+ QDateTime date() const { return m_date; }
+
+ private:
+ QString m_text;
+ int m_code;
+ int m_temperature;
+ QDateTime m_date;
+ };
+
+ class Forecast
+ {
+ public:
+ Forecast() {};
+ Forecast(QDomElement element);
+
+ QDate date() const { return m_date; }
+ int low() const { return m_low; }
+ int high() const { return m_high; }
+ QString text() const { return m_text; }
+ int code() const { return m_code; }
+
+ private:
+ QDate m_date;
+ int m_low;
+ int m_high;
+ QString m_text;
+ int m_code;
+ };
+
+public:
+ YahooWeatherResponse(const QString &locationCode, QDomElement element);
+
+ QString locationCode() const { return m_locationCode; }
+
+ Location location() const { return m_location; }
+ Units units() const { return m_units; }
+ Wind wind() const { return m_wind; }
+ Atmosphere atmosphere() const { return m_atmosphere; }
+ Astronomy astronomy() const { return m_astronomy; }
+ Condition condition() const { return m_condition; }
+ Forecast forecast(int idx) const { return m_forecast[idx]; }
+
+ QDateTime buildDate() const { return m_buildDate; }
+ int timeToLive() const { return m_timeToLive; }
+ float latitude() const { return m_latitude; }
+ float longitude() const { return m_longitude; }
+ QDateTime pubDate() const { return m_pubDate; }
+
+ void print();
+
+
+private:
+ QString m_locationCode;
+ QDateTime m_buildDate;
+ int m_timeToLive;
+ float m_latitude;
+ float m_longitude;
+ QDateTime m_pubDate;
+
+ Location m_location;
+ Units m_units;
+ Wind m_wind;
+ Atmosphere m_atmosphere;
+ Astronomy m_astronomy;
+ Condition m_condition;
+ Forecast m_forecast[2];
+
+ void readItem(QDomElement item);
+
+// <guid isPermaLink="false">USCA1116_2009_11_08_18_56_PST</guid>
+
+
+
+
+
+};
+
+#endif // YAHOOWEATHERRESPONSE_H