delay a few things on startup, such as setting the visibility mode, which ensures...
[personal-kdebase.git] / workspace / plasma / dataengines / weather / ions / ion_bbcukmet.cpp
blobe39f90c9ab7831f8653b9d09b54ceb7e167c0207
1 /***************************************************************************
2 * Copyright (C) 2007-2008 by Shawn Starr <shawn.starr@rogers.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
18 ***************************************************************************/
20 /* Ion for BBC's Weather from the UK Met Office */
22 #include "ion_bbcukmet.h"
24 class UKMETIon::Private : public QObject
26 public:
27 Private() {
28 m_url = 0;
30 ~Private() {
31 delete m_url;
34 private:
35 struct XMLMapInfo {
36 QString place;
37 QString XMLurl;
38 QString XMLforecastURL;
39 bool ukPlace;
40 QString sourceOptions;
43 public:
44 // Key dicts
45 QHash<QString, UKMETIon::Private::XMLMapInfo> m_place;
46 QVector<QString> m_locations;
47 QStringList m_matchLocations;
49 public:
50 // Weather information
51 QHash<QString, WeatherData> m_weatherData;
53 // Store KIO jobs - Search list
54 QMap<KJob *, QXmlStreamReader*> m_jobXml;
55 QMap<KJob *, QString> m_jobList;
57 QMap<KJob *, QXmlStreamReader*> m_obsJobXml;
58 QMap<KJob *, QString> m_obsJobList;
60 QMap<KJob *, QXmlStreamReader *> m_forecastJobXml;
61 QMap<KJob *, QString> m_forecastJobList;
63 KUrl *m_url;
64 KIO::TransferJob *m_job;
66 QDateTime m_dateFormat;
70 // ctor, dtor
71 UKMETIon::UKMETIon(QObject *parent, const QVariantList &args)
72 : IonInterface(parent, args), d(new Private())
75 Q_UNUSED(args)
78 UKMETIon::~UKMETIon()
80 // Destroy each forecast stored in a QVector
81 foreach(const WeatherData &item, d->m_weatherData) {
82 foreach(WeatherData::ForecastInfo *forecast, item.forecasts) {
83 if (forecast) {
84 delete forecast;
89 // Destroy dptr
90 delete d;
93 // Get the master list of locations to be parsed
94 void UKMETIon::init()
96 setInitialized(true);
99 QMap<QString, IonInterface::ConditionIcons> UKMETIon::setupDayIconMappings(void)
101 // ClearDay, FewCloudsDay, PartlyCloudyDay, Overcast,
102 // Showers, ScatteredShowers, Thunderstorm, Snow,
103 // FewCloudsNight, PartlyCloudyNight, ClearNight,
104 // Mist, NotAvailable
106 QMap<QString, ConditionIcons> dayList;
107 dayList["sunny"] = ClearDay;
108 //dayList["sunny night"] = ClearNight;
109 dayList["clear"] = ClearDay;
110 dayList["sunny intervals"] = PartlyCloudyDay;
111 //dayList["sunny intervals night"] = ClearNight;
112 dayList["partly cloudy"] = PartlyCloudyDay;
113 dayList["cloudy"] = Overcast;
114 //dayList["low level cloud"] = NotAvailable;
115 //dayList["medium level cloud"] = NotAvailable;
116 //dayList["sandstorm"] = NotAvailable;
117 dayList["drizzle"] = LightRain;
118 dayList["misty"] = Mist;
119 dayList["mist"] = Mist;
120 dayList["fog"] = Mist;
121 dayList["foggy"] = Mist;
122 dayList["tropical storm"] = Thunderstorm;
123 dayList["hazy"] = NotAvailable;
124 dayList["light shower"] = Showers;
125 dayList["light rain shower"] = Showers;
126 dayList["light showers"] = Showers;
127 dayList["light rain"] = Showers;
128 dayList["heavy rain"] = Rain;
129 dayList["heavy showers"] = Rain;
130 dayList["heavy shower"] = Rain;
131 dayList["thundery shower"] = Thunderstorm;
132 dayList["thunderstorm"] = Thunderstorm;
133 dayList["cloudy with sleet"] = RainSnow;
134 dayList["sleet shower"] = RainSnow;
135 dayList["sleet showers"] = RainSnow;
136 dayList["sleet"] = RainSnow;
137 dayList["cloudy with hail"] = Hail;
138 dayList["hail shower"] = Hail;
139 dayList["hail showers"] = Hail;
140 dayList["hail"] = Hail;
141 dayList["light snow"] = LightSnow;
142 dayList["light snow shower"] = Flurries;
143 dayList["light snow showers"] = Flurries;
144 dayList["cloudy with light snow"] = LightSnow;
145 dayList["heavy snow"] = Snow;
146 dayList["heavy snow shower"] = Snow;
147 dayList["heavy snow showers"] = Snow;
148 dayList["cloudy with heavy snow"] = Snow;
149 dayList["na"] = NotAvailable;
150 return dayList;
153 QMap<QString, IonInterface::ConditionIcons> UKMETIon::setupNightIconMappings(void)
155 QMap<QString, ConditionIcons> nightList;
156 nightList["clear"] = ClearNight;
157 nightList["clear intervals"] = PartlyCloudyNight;
158 nightList["sunny intervals"] = PartlyCloudyDay; // it's not really sunny
159 nightList["sunny"] = ClearDay;
160 nightList["cloudy"] = Overcast;
161 nightList["partly cloudy"] = PartlyCloudyNight;
162 nightList["drizzle"] = LightRain;
163 nightList["misty"] = Mist;
164 nightList["mist"] = Mist;
165 nightList["fog"] = Mist;
166 nightList["foggy"] = Mist;
167 nightList["tropical storm"] = Thunderstorm;
168 nightList["hazy"] = NotAvailable;
169 nightList["light shower"] = Showers;
170 nightList["light rain shower"] = Showers;
171 nightList["light showers"] = Showers;
172 nightList["light rain"] = Showers;
173 nightList["heavy rain"] = Rain;
174 nightList["heavy showers"] = Rain;
175 nightList["heavy shower"] = Rain;
176 nightList["thundery shower"] = Thunderstorm;
177 nightList["thunderstorm"] = Thunderstorm;
178 nightList["cloudy with sleet"] = NotAvailable;
179 nightList["sleet shower"] = NotAvailable;
180 nightList["sleet showers"] = NotAvailable;
181 nightList["sleet"] = NotAvailable;
182 nightList["cloudy with hail"] = Hail;
183 nightList["hail shower"] = Hail;
184 nightList["hail showers"] = Hail;
185 nightList["hail"] = Hail;
186 nightList["light snow"] = LightSnow;
187 nightList["light snow shower"] = Flurries;
188 nightList["light snow showers"] = Flurries;
189 nightList["cloudy with light snow"] = LightSnow;
190 nightList["heavy snow"] = Snow;
191 nightList["heavy snow shower"] = Snow;
192 nightList["heavy snow showers"] = Snow;
193 nightList["cloudy with heavy snow"] = Snow;
194 nightList["na"] = NotAvailable;
196 return nightList;
199 QMap<QString, IonInterface::ConditionIcons> const& UKMETIon::dayIcons(void)
201 static QMap<QString, ConditionIcons> const dval = setupDayIconMappings();
202 return dval;
205 QMap<QString, IonInterface::ConditionIcons> const& UKMETIon::nightIcons(void)
207 static QMap<QString, ConditionIcons> const nval = setupNightIconMappings();
208 return nval;
211 // Get a specific Ion's data
212 bool UKMETIon::updateIonSource(const QString& source)
214 // We expect the applet to send the source in the following tokenization:
215 // ionname|validate|place_name - Triggers validation of place
216 // ionname|weather|place_name - Triggers receiving weather of place
218 QStringList sourceAction = source.split('|');
220 if (sourceAction[1] == QString("validate")) {
221 // Look for places to match
222 findPlace(sourceAction[2], source);
223 return true;
225 } else if (sourceAction[1] == QString("weather")) {
226 if (sourceAction.count() >= 3) {
227 d->m_place[QString("bbcukmet|%1").arg(sourceAction[2])].XMLurl = sourceAction[3];
228 getXMLData(QString("%1|%2").arg(sourceAction[0]).arg(sourceAction[2]));
229 return true;
230 } else {
231 return false;
234 return false;
237 // Gets specific city XML data
238 void UKMETIon::getXMLData(const QString& source)
240 KUrl url;
241 url = d->m_place[source].XMLurl;
243 d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
244 d->m_job->addMetaData("cookies", "none"); // Disable displaying cookies
245 d->m_obsJobXml.insert(d->m_job, new QXmlStreamReader);
246 d->m_obsJobList.insert(d->m_job, source);
248 if (d->m_job) {
249 connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
250 SLOT(observation_slotDataArrived(KIO::Job *, const QByteArray &)));
251 connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(observation_slotJobFinished(KJob *)));
255 // Parses city list and gets the correct city based on ID number
256 void UKMETIon::findPlace(const QString& place, const QString& source)
258 KUrl url;
259 url = "http://www.bbc.co.uk/cgi-perl/weather/search/new_search.pl?x=0&y=0&=Submit&search_query=" + place + "&tmpl=wap";
261 d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
262 d->m_job->addMetaData("cookies", "none"); // Disable displaying cookies
263 d->m_jobXml.insert(d->m_job, new QXmlStreamReader);
264 d->m_jobList.insert(d->m_job, source);
266 if (d->m_job) {
267 connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
268 SLOT(setup_slotDataArrived(KIO::Job *, const QByteArray &)));
269 connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(setup_slotJobFinished(KJob *)));
271 // Handle redirects for direct hit places.
272 connect(d->m_job, SIGNAL(redirection(KIO::Job *, const KUrl &)), this,
273 SLOT(setup_slotRedirected(KIO::Job *, const KUrl &)));
277 void UKMETIon::getFiveDayForecast(const QString& source)
279 KUrl url;
280 url = d->m_place[source].XMLforecastURL;
281 QString xmlMap = d->m_place[source].XMLforecastURL;
282 xmlMap.replace("weather/5day.shtml", "weather/mobile/5day.wml");
283 url = xmlMap;
285 d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
286 d->m_job->addMetaData("cookies", "none"); // Disable displaying cookies
287 d->m_forecastJobXml.insert(d->m_job, new QXmlStreamReader);
288 d->m_forecastJobList.insert(d->m_job, source);
290 if (d->m_job) {
291 connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
292 SLOT(forecast_slotDataArrived(KIO::Job *, const QByteArray &)));
293 connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(forecast_slotJobFinished(KJob *)));
297 bool UKMETIon::readSearchXMLData(const QString& key, QXmlStreamReader& xml)
300 while (!xml.atEnd()) {
301 xml.readNext();
303 if (xml.isEndElement()) {
304 break;
307 if (xml.isStartElement()) {
308 if (xml.name() == "wml") {
309 parseSearchLocations(key, xml);
310 } else {
311 parseUnknownElement(xml);
316 return !xml.error();
319 void UKMETIon::parseSearchLocations(const QString& source, QXmlStreamReader& xml)
321 int flag = 0;
322 QString url;
323 QString place;
324 QStringList tokens;
325 QString tmp;
326 int counter = 2;
327 int currentParagraph = 0;
329 Q_ASSERT(xml.isStartElement() && xml.name() == "wml");
331 while (!xml.atEnd()) {
332 xml.readNext();
334 if (xml.isEndElement() && xml.name() == "wml") {
335 break;
338 if (xml.isStartElement() && xml.name() == "p") {
339 currentParagraph++;
342 if (currentParagraph == 2) {
343 if (xml.isCharacters() && !xml.isWhitespace()) {
344 QString dataText = xml.text().toString().trimmed();
345 if (dataText.contains("No locations")) {
346 break;
351 if (xml.isStartElement()) {
352 if (xml.name() == "a" && !xml.attributes().value("href").isEmpty()) {
353 if (xml.attributes().value("href").toString().contains("5day.wml")) {
355 // Split URL to determine station ID number
356 tokens = xml.attributes().value("href").toString().split('=');
357 if (xml.attributes().value("href").toString().contains("world")) {
358 url = "http://feeds.bbc.co.uk/weather/feeds/obs/world/" + tokens[1] + ".xml";
359 flag = 0;
360 } else {
361 url = "http://feeds.bbc.co.uk/weather/feeds/obs/id/" + tokens[1] + ".xml";
362 flag = 1;
364 place = xml.readElementText();
365 tmp = QString("bbcukmet|%1").arg(place);
367 // Duplicate places can exist
368 if (d->m_locations.contains(tmp)) {
370 QString dupePlace = place;
371 tmp = QString("bbcukmet|%1").arg(QString("%1 (#%2)").arg(dupePlace).arg(counter));
372 place = QString("%1 (#%2)").arg(dupePlace).arg(counter);
373 counter++;
376 if (flag) { // This is a UK specific location
377 d->m_place[tmp].XMLurl = url;
378 d->m_place[tmp].place = place;
379 d->m_place[tmp].ukPlace = true;
380 } else {
381 d->m_place[tmp].XMLurl = url;
382 d->m_place[tmp].place = place;
383 d->m_place[tmp].ukPlace = false;
385 d->m_locations.append(tmp);
390 validate(source);
393 // handle when no XML tag is found
394 void UKMETIon::parseUnknownElement(QXmlStreamReader& xml)
396 while (!xml.atEnd()) {
397 xml.readNext();
399 if (xml.isEndElement()) {
400 break;
403 if (xml.isStartElement()) {
404 parseUnknownElement(xml);
409 void UKMETIon::setup_slotRedirected(KIO::Job *job, const KUrl &url)
411 QString obsUrl;
412 QString place;
413 QString tmp;
414 bool flag = false;
415 QStringList tokens = url.url().split('=');
416 if (url.url().contains("xhtml")) { // We don't care about the first redirection (there is two)
417 if (url.url().contains("world")) {
418 obsUrl = "http://feeds.bbc.co.uk/weather/feeds/obs/world/" + tokens[2] + ".xml";
419 flag = false;
420 } else {
421 obsUrl = "http://feeds.bbc.co.uk/weather/feeds/obs/id/" + tokens[2] + ".xml";
422 flag = true;
424 place = d->m_jobList[job].split('|')[2]; // Contains the source name (place in this case)
425 tmp = QString("bbcukmet|%1").arg(place);
426 place[0] = place[0].toUpper();
428 if (flag) { // This is a UK specific location
429 d->m_place[tmp].XMLurl = obsUrl;
430 d->m_place[tmp].place = place;
431 d->m_place[tmp].ukPlace = true;
432 } else {
433 d->m_place[tmp].XMLurl = obsUrl;
434 d->m_place[tmp].place = place;
435 d->m_place[tmp].ukPlace = false;
437 d->m_locations.append(tmp);
438 validate(d->m_jobList[job]);
442 void UKMETIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data)
444 QByteArray local = data;
445 if (data.isEmpty() || !d->m_jobXml.contains(job)) {
446 return;
449 // XXX: BBC doesn't convert unicode strings so this breaks XML formatting. Not pretty.
450 if (local.startsWith("<?xml version")) {
451 local.replace("<?xml version=\"1.0\"?>", "<?xml version=\"1.0\" encoding=\"cp1252\" ?>");
454 // Send to xml.
455 d->m_jobXml[job]->addData(local);
458 void UKMETIon::setup_slotJobFinished(KJob *job)
460 if (job->error() == 149) {
461 setData(d->m_jobList[job], "validate", QString("bbcukmet|timeout"));
462 disconnectSource(d->m_jobList[job], this);
463 d->m_jobList.remove(job);
464 delete d->m_jobXml[job];
465 d->m_jobXml.remove(job);
466 return;
468 // If Redirected, don't go to this routine
469 if (!d->m_locations.contains(QString("bbcukmet|%1").arg(d->m_jobList[job]))) {
470 readSearchXMLData(d->m_jobList[job], *d->m_jobXml[job]);
472 d->m_jobList.remove(job);
473 delete d->m_jobXml[job];
474 d->m_jobXml.remove(job);
477 void UKMETIon::observation_slotDataArrived(KIO::Job *job, const QByteArray &data)
479 QByteArray local = data;
480 if (data.isEmpty() || !d->m_obsJobXml.contains(job)) {
481 return;
484 // XXX: I don't know what to say about this. But horrible. We can't really do much about this :/
485 // No, it's not UTF-8, it really lies.
486 if (local.startsWith("<?xml version")) {
487 local.replace("encoding=\"UTF-8\"?>", "encoding=\"cp1252\" ?>");
490 // Send to xml.
491 d->m_obsJobXml[job]->addData(local);
494 void UKMETIon::observation_slotJobFinished(KJob *job)
496 setData(d->m_obsJobList[job], Data());
497 readObservationXMLData(d->m_obsJobList[job], *d->m_obsJobXml[job]);
498 d->m_obsJobList.remove(job);
499 delete d->m_obsJobXml[job];
500 d->m_obsJobXml.remove(job);
503 void UKMETIon::forecast_slotDataArrived(KIO::Job *job, const QByteArray &data)
505 QByteArray local = data;
506 if (data.isEmpty() || !d->m_forecastJobXml.contains(job)) {
507 return;
510 // XXX: BBC doesn't convert unicode strings so this breaks XML formatting. Not pretty.
511 // No, it's not UTF-8, it really lies.
512 if (local.startsWith("<?xml version")) {
513 local.replace("<?xml version=\"1.0\"?>", "<?xml version=\"1.0\" encoding=\"cp1252\" ?>");
515 // Send to xml.
516 d->m_forecastJobXml[job]->addData(local);
519 void UKMETIon::forecast_slotJobFinished(KJob *job)
521 setData(d->m_forecastJobList[job], Data());
522 readFiveDayForecastXMLData(d->m_forecastJobList[job], *d->m_forecastJobXml[job]);
523 d->m_forecastJobList.remove(job);
524 delete d->m_forecastJobXml[job];
525 d->m_forecastJobXml.remove(job);
528 void UKMETIon::parsePlaceObservation(const QString &source, WeatherData& data, QXmlStreamReader& xml)
530 Q_ASSERT(xml.isStartElement() && xml.name() == "rss");
532 while (!xml.atEnd()) {
533 xml.readNext();
535 if (xml.isEndElement() && xml.name() == "rss") {
536 break;
539 if (xml.isStartElement()) {
540 if (xml.name() == "channel") {
541 parseWeatherChannel(source, data, xml);
547 void UKMETIon::parseWeatherChannel(const QString& source, WeatherData& data, QXmlStreamReader& xml)
549 Q_ASSERT(xml.isStartElement() && xml.name() == "channel");
551 while (!xml.atEnd()) {
552 xml.readNext();
554 if (xml.isEndElement() && xml.name() == "channel") {
555 break;
558 if (xml.isStartElement()) {
559 if (xml.name() == "title") {
560 data.stationName = xml.readElementText().split("Observations for")[1].trimmed();
562 data.stationName.replace("United Kingdom", "UK");
563 data.stationName.replace("United States of America", "USA");
565 } else if (xml.name() == "item") {
566 parseWeatherObservation(source, data, xml);
567 } else {
568 parseUnknownElement(xml);
574 void UKMETIon::parseWeatherObservation(const QString& source, WeatherData& data, QXmlStreamReader& xml)
576 Q_UNUSED(data)
577 Q_ASSERT(xml.isStartElement() && xml.name() == "item");
579 while (!xml.atEnd()) {
580 xml.readNext();
582 if (xml.isEndElement() && xml.name() == "item") {
583 break;
586 if (xml.isStartElement()) {
587 if (xml.name() == "title") {
588 QString conditionString = xml.readElementText();
590 // Get the observation time.
591 QStringList conditionData = conditionString.split(':');
593 data.obsTime = conditionData[0];
594 // Friday at 0200 GMT
595 d->m_dateFormat = QDateTime::fromString(data.obsTime.split("at")[1].trimmed(), "hhmm 'GMT'");
596 data.iconPeriodHour = d->m_dateFormat.toString("HH").toInt();
597 //data.iconPeriodAP = d->m_dateFormat.toString("ap");
599 data.condition = conditionData[1].split('.')[0].trimmed();
601 } else if (xml.name() == "link") {
602 d->m_place[source].XMLforecastURL = xml.readElementText();
603 } else if (xml.name() == "description") {
604 QString observeString = xml.readElementText();
605 QStringList observeData = observeString.split(':');
607 data.temperature_C = observeData[1].split(QChar(176))[0].trimmed();
608 data.temperature_F = observeData[1].split('(')[1].split(QChar(176))[0];
610 data.windDirection = observeData[2].split(',')[0].trimmed();
611 data.windSpeed_miles = observeData[3].split(',')[0].split(' ')[1];
613 data.humidity = observeData[4].split(',')[0].split(' ')[1];
615 data.pressure = observeData[5].split(',')[0].split(' ')[1].split("mB")[0];
617 data.pressureTendency = observeData[5].split(',')[1].trimmed();
619 data.visibilityStr = observeData[6].trimmed();
621 } else {
622 parseUnknownElement(xml);
628 bool UKMETIon::readObservationXMLData(const QString& source, QXmlStreamReader& xml)
630 WeatherData data;
632 while (!xml.atEnd()) {
633 xml.readNext();
635 if (xml.isEndElement()) {
636 break;
639 if (xml.isStartElement()) {
640 if (xml.name() == "rss") {
641 parsePlaceObservation(source, data, xml);
642 } else {
643 parseUnknownElement(xml);
649 d->m_weatherData[source] = data;
651 // Get the 5 day forecast info next.
652 getFiveDayForecast(source);
654 return !xml.error();
657 bool UKMETIon::readFiveDayForecastXMLData(const QString& source, QXmlStreamReader& xml)
659 while (!xml.atEnd()) {
660 xml.readNext();
662 if (xml.isEndElement()) {
663 break;
666 if (xml.isStartElement()) {
667 if (xml.name() == "wml") {
668 parseFiveDayForecast(source, xml);
669 } else {
670 parseUnknownElement(xml);
674 updateWeather(source);
675 return !xml.error();
678 void UKMETIon::parseFiveDayForecast(const QString& source, QXmlStreamReader& xml)
680 Q_ASSERT(xml.isStartElement() && xml.name() == "wml");
681 bool validNumber = false;
682 int currentParagraph = 0;
683 bool skipPlace = false;
684 int dataItem = 0;
686 enum DataItem {
687 Day,
688 Summary,
689 MaxTemp,
690 MinTemp,
691 WindSpeed
694 // Flush out the old forecasts when updating.
695 d->m_weatherData[source].forecasts.clear();
697 WeatherData::ForecastInfo *forecast = new WeatherData::ForecastInfo;
699 QRegExp numParser("(Max|Min|Wind)\\s+-*([0-9]+)");
700 while (!xml.atEnd()) {
701 xml.readNext();
703 if (xml.isStartElement() && xml.name() == "p") {
704 currentParagraph++;
707 if (currentParagraph == 3) {
708 if (xml.isCharacters() && !xml.isWhitespace()) {
709 QString dataText = xml.text().toString().trimmed();
710 if (!skipPlace) {
711 skipPlace = true;
712 } else {
713 if (numParser.indexIn(dataText) != -1 && numParser.capturedTexts().count() >= 3) {
714 validNumber = true;
716 switch (dataItem) {
717 case Day:
718 forecast->period = dataText;
719 dataItem++;
720 break;
721 case Summary:
722 forecast->summary = dataText;
723 forecast->iconName = getWeatherIcon(dayIcons(), forecast->summary.toLower());
724 dataItem++;
725 break;
726 case MaxTemp:
727 forecast->tempHigh = numParser.capturedTexts()[0].remove("Max").toInt();
728 dataItem++;
729 validNumber = false;
730 break;
731 case MinTemp:
732 forecast->tempLow = numParser.capturedTexts()[0].remove("Min").toInt();
733 dataItem++;
734 validNumber = false;
735 break;
736 case WindSpeed:
737 forecast->windSpeed = numParser.capturedTexts()[0].remove("Wind").toInt();
738 forecast->windDirection = dataText.split('(')[1].split(')')[0];
739 dataItem = 0;
740 d->m_weatherData[source].forecasts.append(forecast);
741 forecast = new WeatherData::ForecastInfo;
742 validNumber = false;
743 break;
750 delete forecast;
753 void UKMETIon::validate(const QString& source)
755 bool beginflag = true;
757 if (!d->m_locations.count()) {
758 QStringList invalidPlace = source.split('|');
759 if (d->m_place[QString("bbcukmet|%1").arg(invalidPlace[2])].place.isEmpty()) {
760 setData(source, "validate", QString("bbcukmet|invalid|multiple|%1").arg(invalidPlace[2]));
762 d->m_locations.clear();
763 return;
764 } else {
765 QString placeList;
766 foreach(const QString &place, d->m_locations) {
767 if (beginflag) {
768 placeList.append(QString("%1|extra|%2").arg(place.split('|')[1]).arg(d->m_place[place].XMLurl));
769 beginflag = false;
770 } else {
771 placeList.append(QString("|place|%1|extra|%2").arg(place.split('|')[1]).arg(d->m_place[place].XMLurl));
774 if (d->m_locations.count() > 1) {
775 setData(source, "validate", QString("bbcukmet|valid|multiple|place|%1").arg(placeList));
776 } else {
777 placeList[0] = placeList[0].toUpper();
778 setData(source, "validate", QString("bbcukmet|valid|single|place|%1").arg(placeList));
781 d->m_locations.clear();
784 void UKMETIon::updateWeather(const QString& source)
786 QString weatherSource = source;
787 weatherSource.replace("bbcukmet|", "bbcukmet|weather|");
788 weatherSource.append(QString("|%1").arg(d->m_place[source].XMLurl));
790 QMap<QString, QString> dataFields;
791 QStringList fieldList;
792 QVector<QString> forecastList;
793 int i = 0;
795 setData(weatherSource, "Place", place(source));
796 setData(weatherSource, "Station", station(source));
797 setData(weatherSource, "Observation Period", observationTime(source));
798 setData(weatherSource, "Current Conditions", condition(source));
800 // Tell applet which icon to use for conditions and provide mapping for condition type to the icons to display
801 if (periodHour(source) >= 0 && periodHour(source) < 6) {
802 setData(weatherSource, "Condition Icon", getWeatherIcon(nightIcons(), condition(source)));
803 } else if (periodHour(source) >= 18) {
804 setData(weatherSource, "Condition Icon", getWeatherIcon(nightIcons(), condition(source)));
805 } else {
806 setData(weatherSource, "Condition Icon", getWeatherIcon(dayIcons(), condition(source)));
809 setData(weatherSource, "Humidity", humidity(source));
810 setData(weatherSource, "Visibility", visibility(source));
812 dataFields = temperature(source);
813 setData(weatherSource, "Temperature", dataFields["temperature"]);
814 setData(weatherSource, "Temperature Unit", dataFields["temperatureUnit"]);
816 dataFields = pressure(source);
817 setData(weatherSource, "Pressure", dataFields["pressure"]);
818 setData(weatherSource, "Pressure Unit", dataFields["pressureUnit"]);
819 setData(weatherSource, "Pressure Tendency", dataFields["pressureTendency"]);
821 dataFields = wind(source);
822 setData(weatherSource, "Wind Speed", dataFields["windSpeed"]);
823 setData(weatherSource, "Wind Speed Unit", dataFields["windUnit"]);
824 setData(weatherSource, "Wind Direction", dataFields["windDirection"]);
826 // 5 Day forecast info
827 forecastList = forecasts(source);
829 // Set number of forecasts per day/night supported
830 setData(weatherSource, QString("Total Weather Days"), d->m_weatherData[source].forecasts.size());
832 foreach(const QString &forecastItem, forecastList) {
833 fieldList = forecastItem.split('|');
835 setData(weatherSource, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6") \
836 .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[2]).arg(fieldList[3]) \
837 .arg(fieldList[4]).arg(fieldList[5]));
838 i++;
841 setData(weatherSource, "Credit", "Supported by backstage.bbc.co.uk / Data from UK MET Office");
842 setData(weatherSource, "Credit Url", d->m_place[source].XMLforecastURL);
845 QString UKMETIon::place(const QString& source)
847 return d->m_weatherData[source].stationName;
850 QString UKMETIon::station(const QString& source)
852 return d->m_weatherData[source].stationName;
855 QString UKMETIon::observationTime(const QString& source)
857 return d->m_weatherData[source].obsTime;
861 bool UKMETIon::night(const QString& source)
863 if (d->m_weatherData[source].iconPeriodAP == "pm") {
864 return true;
866 return false;
867 } */
869 int UKMETIon::periodHour(const QString& source)
871 return d->m_weatherData[source].iconPeriodHour;
874 QString UKMETIon::condition(const QString& source)
876 return d->m_weatherData[source].condition;
879 QMap<QString, QString> UKMETIon::temperature(const QString& source)
881 QMap<QString, QString> temperatureInfo;
883 temperatureInfo.insert("temperature", QString(d->m_weatherData[source].temperature_C));
884 temperatureInfo.insert("temperatureUnit", QString::number(WeatherUtils::Celsius));
885 return temperatureInfo;
888 QMap<QString, QString> UKMETIon::wind(const QString& source)
890 QMap<QString, QString> windInfo;
891 if (d->m_weatherData[source].windSpeed_miles == "N/A") {
892 windInfo.insert("windSpeed", "N/A");
893 windInfo.insert("windUnit", QString::number(WeatherUtils::NoUnit));
894 } else {
895 windInfo.insert("windSpeed", QString(d->m_weatherData[source].windSpeed_miles));
896 windInfo.insert("windUnit", QString::number(WeatherUtils::MilesAnHour));
898 windInfo.insert("windDirection", d->m_weatherData[source].windDirection);
899 return windInfo;
902 QString UKMETIon::humidity(const QString& source)
904 if (d->m_weatherData[source].humidity == "N/A%") {
905 return "N/A";
907 return d->m_weatherData[source].humidity;
910 QString UKMETIon::visibility(const QString& source)
912 return d->m_weatherData[source].visibilityStr;
915 QMap<QString, QString> UKMETIon::pressure(const QString& source)
917 QMap<QString, QString> pressureInfo;
918 if (d->m_weatherData[source].pressure == "N/A") {
919 pressureInfo.insert("pressure", "N/A");
920 return pressureInfo;
923 pressureInfo.insert("pressure", QString(d->m_weatherData[source].pressure));
924 pressureInfo.insert("pressureUnit", QString::number(WeatherUtils::Millibars));
926 pressureInfo.insert("pressureTendency", d->m_weatherData[source].pressureTendency);
927 return pressureInfo;
930 QVector<QString> UKMETIon::forecasts(const QString& source)
932 QVector<QString> forecastData;
934 for (int i = 0; i < d->m_weatherData[source].forecasts.size(); ++i) {
936 if (d->m_weatherData[source].forecasts[i]->period.contains("Saturday")) {
937 d->m_weatherData[source].forecasts[i]->period.replace("Saturday", "Sat");
940 if (d->m_weatherData[source].forecasts[i]->period.contains("Sunday")) {
941 d->m_weatherData[source].forecasts[i]->period.replace("Sunday", "Sun");
944 if (d->m_weatherData[source].forecasts[i]->period.contains("Monday")) {
945 d->m_weatherData[source].forecasts[i]->period.replace("Monday", "Mon");
948 if (d->m_weatherData[source].forecasts[i]->period.contains("Tuesday")) {
949 d->m_weatherData[source].forecasts[i]->period.replace("Tuesday", "Tue");
952 if (d->m_weatherData[source].forecasts[i]->period.contains("Wednesday")) {
953 d->m_weatherData[source].forecasts[i]->period.replace("Wednesday", "Wed");
956 if (d->m_weatherData[source].forecasts[i]->period.contains("Thursday")) {
957 d->m_weatherData[source].forecasts[i]->period.replace("Thursday", "Thu");
959 if (d->m_weatherData[source].forecasts[i]->period.contains("Friday")) {
960 d->m_weatherData[source].forecasts[i]->period.replace("Friday", "Fri");
963 forecastData.append(QString("%1|%2|%3|%4|%5|%6") \
964 .arg(d->m_weatherData[source].forecasts[i]->period) \
965 .arg(d->m_weatherData[source].forecasts[i]->iconName) \
966 .arg(d->m_weatherData[source].forecasts[i]->summary) \
967 .arg(d->m_weatherData[source].forecasts[i]->tempHigh) \
968 .arg(d->m_weatherData[source].forecasts[i]->tempLow) \
969 .arg("N/U"));
970 //.arg(d->m_weatherData[source].forecasts[i]->windSpeed)
971 //arg(d->m_weatherData[source].forecasts[i]->windDirection));
974 return forecastData;
977 #include "ion_bbcukmet.moc"