Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / workspace / plasma / dataengines / weather / ions / ion_envcan.cpp
blob37c9f92079675e3fd62bbc63b0c50956525c86a3
1 /***************************************************************************
2 * Copyright (C) 2007 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 Environment Canada XML data */
22 #include "ion_envcan.h"
24 class EnvCanadaIon::Private : public QObject
26 public:
27 Private() {}
28 ~Private() {}
30 private:
31 struct XMLMapInfo {
32 QString cityName;
33 QString territoryName;
34 QString cityCode;
35 QString sourceOptions;
38 public:
39 // Key dicts
40 QHash<QString, EnvCanadaIon::Private::XMLMapInfo> m_place;
41 QHash<QString, QString> m_locations;
42 QString m_code;
43 QString m_territory;
44 QString m_cityName;
46 // Weather information
47 QHash<QString, WeatherData> m_weatherData;
49 // Store KIO jobs
50 QMap<KJob *, QXmlStreamReader*> m_jobXml;
51 QMap<KJob *, QString> m_jobList;
52 QXmlStreamReader m_xmlSetup;
53 KUrl *m_url;
54 KIO::TransferJob *m_job;
56 int m_timezoneType; // Ion option: Timezone may be local time or UTC time
57 int m_measureType; // Ion option: Units may be Metric or Imperial
61 // ctor, dtor
62 EnvCanadaIon::EnvCanadaIon(QObject *parent, const QVariantList &args)
63 : IonInterface(parent), d(new Private())
65 Q_UNUSED(args)
68 EnvCanadaIon::~EnvCanadaIon()
70 // Destroy each warning stored in a QVector
71 foreach(WeatherData item, d->m_weatherData) {
72 foreach(WeatherData::WarningInfo *warning, item.warnings) {
73 if (warning) {
74 delete warning;
77 foreach(WeatherData::ForecastInfo *forecast, item.forecasts) {
78 if (forecast) {
79 delete forecast;
84 // Destroy dptr
85 delete d;
88 // Get the master list of locations to be parsed
89 void EnvCanadaIon::init()
91 // Get the real city XML URL so we can parse this
92 getXMLSetup();
95 QStringList EnvCanadaIon::validate(const QString& source) const
97 QStringList placeList;
98 QHash<QString, QString>::const_iterator it = d->m_locations.constBegin();
99 while (it != d->m_locations.constEnd()) {
100 if (it.value().toLower().contains(source.toLower())) {
101 placeList.append(QString("place|%1").arg(it.value().split("|")[1]));
103 ++it;
106 // Check if placeList is empty if so, return nothing.
107 if (placeList.isEmpty()) {
108 return QStringList();
110 placeList.sort();
111 return placeList;
114 // Get a specific Ion's data
115 bool EnvCanadaIon::updateIonSource(const QString& source)
117 kDebug() << "updateIonSource() SOURCE: " << source;
118 // We expect the applet to send the source in the following tokenization:
119 // ionname|validate|place_name - Triggers validation of place
120 // ionname|weather|place_name - Triggers receiving weather of place
122 QStringList sourceAction = source.split('|');
123 if (sourceAction[1] == QString("validate")) {
124 kDebug() << "Initiate Validating of place: " << sourceAction[2];
126 QStringList result = validate(QString("%1|%2").arg(sourceAction[0]).arg(sourceAction[2]));
128 if (result.size() == 1) {
129 setData(source, "validate", QString("envcan|valid|single|%1").arg(result.join("|")));
130 return true;
131 } else if (result.size() > 1) {
132 setData(source, "validate", QString("envcan|valid|multiple|%1").arg(result.join("|")));
133 return true;
134 } else if (result.size() == 0) {
135 setData(source, "validate", QString("envcan|invalid|single|%1").arg(sourceAction[2]));
136 return true;
139 } else if (sourceAction[1] == QString("weather")) {
140 getXMLData(QString("%1|%2").arg(sourceAction[0]).arg(sourceAction[2]));
141 return true;
143 return false;
146 // Parses city list and gets the correct city based on ID number
147 void EnvCanadaIon::getXMLSetup()
150 d->m_url = new KUrl("http://dd.weatheroffice.ec.gc.ca/EC_sites/xml/siteList.xml");
152 KIO::TransferJob *job = KIO::get(d->m_url->url(), KIO::NoReload, KIO::HideProgressInfo);
154 if (job) {
155 connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
156 SLOT(setup_slotDataArrived(KIO::Job *, const QByteArray &)));
157 connect(job, SIGNAL(result(KJob *)), this, SLOT(setup_slotJobFinished(KJob *)));
161 // Gets specific city XML data
162 void EnvCanadaIon::getXMLData(const QString& source)
164 KUrl url;
165 url = "http://dd.weatheroffice.ec.gc.ca/EC_sites/xml/" + d->m_place[source].territoryName + "/" + d->m_place[source].cityCode + "_e.xml";
167 kDebug() << "URL Location: " << url.url();
169 d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
170 d->m_jobXml.insert(d->m_job, new QXmlStreamReader);
171 d->m_jobList.insert(d->m_job, source);
173 if (d->m_job) {
174 connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
175 SLOT(slotDataArrived(KIO::Job *, const QByteArray &)));
176 connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(slotJobFinished(KJob *)));
180 void EnvCanadaIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data)
182 Q_UNUSED(job)
184 if (data.isEmpty()) {
185 return;
188 // Send to xml.
189 d->m_xmlSetup.addData(data);
192 void EnvCanadaIon::slotDataArrived(KIO::Job *job, const QByteArray &data)
195 if (data.isEmpty() || !d->m_jobXml.contains(job)) {
196 return;
199 // Send to xml.
200 d->m_jobXml[job]->addData(data);
203 void EnvCanadaIon::slotJobFinished(KJob *job)
205 // Dual use method, if we're fetching location data to parse we need to do this first
206 readXMLData(d->m_jobList[job], *d->m_jobXml[job]);
207 d->m_jobList.remove(job);
208 delete d->m_jobXml[job];
209 d->m_jobXml.remove(job);
212 void EnvCanadaIon::setup_slotJobFinished(KJob *job)
214 Q_UNUSED(job)
215 readXMLSetup();
216 setInitialized(true);
219 // Parse the city list and store into a QMap
220 bool EnvCanadaIon::readXMLSetup()
222 QString tmp;
223 while (!d->m_xmlSetup.atEnd()) {
224 d->m_xmlSetup.readNext();
226 if (d->m_xmlSetup.isStartElement()) {
228 // XML ID code to match filename
229 if (d->m_xmlSetup.name() == "site") {
230 d->m_code = d->m_xmlSetup.attributes().value("code").toString();
233 if (d->m_xmlSetup.name() == "nameEn") {
234 d->m_cityName = d->m_xmlSetup.readElementText(); // Name of cities
237 if (d->m_xmlSetup.name() == "provinceCode") {
238 d->m_territory = d->m_xmlSetup.readElementText(); // Provinces/Territory list
239 tmp = "envcan|" + d->m_cityName + ", " + d->m_territory; // Build the key name.
241 // Set the mappings
242 d->m_place[tmp].cityCode = d->m_code;
243 d->m_place[tmp].territoryName = d->m_territory;
244 d->m_place[tmp].cityName = d->m_cityName;
246 // Set the string list, we will use for the applet to display the available cities.
247 d->m_locations[tmp] = tmp;
252 return !d->m_xmlSetup.error();
255 WeatherData EnvCanadaIon::parseWeatherSite(WeatherData& data, QXmlStreamReader& xml)
257 while (!xml.atEnd()) {
258 xml.readNext();
260 if (xml.isStartElement()) {
261 if (xml.name() == "license") {
262 xml.readElementText();
263 } else if (xml.name() == "location") {
264 parseLocations(data, xml);
265 } else if (xml.name() == "warnings") {
266 // Cleanup warning list on update
267 data.warnings.clear();
268 parseWarnings(data, xml);
269 } else if (xml.name() == "currentConditions") {
270 parseConditions(data, xml);
271 } else if (xml.name() == "forecastGroup") {
272 // Clean up forecast list on update
273 data.forecasts.clear();
274 parseWeatherForecast(data, xml);
275 } else if (xml.name() == "yesterdayConditions") {
276 parseYesterdayWeather(data, xml);
277 } else if (xml.name() == "riseSet") {
278 parseAstronomicals(data, xml);
279 } else if (xml.name() == "almanac") {
280 parseWeatherRecords(data, xml);
281 } else {
282 parseUnknownElement(xml);
286 return data;
289 // Parse Weather data main loop, from here we have to decend into each tag pair
290 bool EnvCanadaIon::readXMLData(const QString& source, QXmlStreamReader& xml)
292 WeatherData data;
293 data.comforttemp = "N/A";
294 data.recordHigh = 0.0;
295 data.recordLow = 0.0;
296 data.shortTerritoryName = d->m_place[source].territoryName;
297 while (!xml.atEnd()) {
298 xml.readNext();
300 if (xml.isEndElement()) {
301 break;
304 if (xml.isStartElement()) {
305 if (xml.name() == "siteData") {
306 data = parseWeatherSite(data, xml);
307 } else {
308 parseUnknownElement(xml);
313 d->m_weatherData[source] = data;
314 updateWeather(source);
315 return !xml.error();
318 void EnvCanadaIon::parseDateTime(WeatherData& data, QXmlStreamReader& xml, WeatherData::WarningInfo *warning)
321 Q_ASSERT(xml.isStartElement() && xml.name() == "dateTime");
323 // What kind of date info is this?
324 QString dateType = xml.attributes().value("name").toString();
325 QString dateZone = xml.attributes().value("zone").toString();
328 while (!xml.atEnd()) {
329 xml.readNext();
331 if (xml.isEndElement()) {
332 break;
335 if (xml.isStartElement()) {
336 if (dateType == "xmlCreation") {
337 return;
339 if (xml.name() == "year") {
340 xml.readElementText();
341 } else if (xml.name() == "month") {
342 xml.readElementText();
343 } else if (xml.name() == "day") {
344 xml.readElementText();
345 } else if (xml.name() == "hour")
346 xml.readElementText();
347 else if (xml.name() == "minute")
348 xml.readElementText();
349 else if (xml.name() == "timeStamp")
350 xml.readElementText();
351 else if (xml.name() == "textSummary") {
352 if (timezone() && dateZone == "UTC") {
353 // Which timestamp are we for?
355 if (dateType == "eventIssue") {
356 if (warning) {
357 warning->timestamp = xml.readElementText();
359 } else if (dateType == "observation") {
360 data.obsTimestamp = xml.readElementText();
361 } else if (dateType == "forecastIssue") {
362 data.forecastTimestamp = xml.readElementText();
363 } else if (dateType == "sunrise") {
364 data.sunriseTimestamp = xml.readElementText();
365 } else if (dateType == "sunset") {
366 data.sunsetTimestamp = xml.readElementText();
367 } else if (dateType == "moonrise") {
368 data.moonriseTimestamp = xml.readElementText();
369 } else if (dateType == "moonset") {
370 data.moonsetTimestamp = xml.readElementText();
373 } else if (dateZone != "UTC") {
374 if (dateType == "eventIssue") {
375 if (warning) {
376 warning->timestamp = xml.readElementText();
378 } else if (dateType == "observation") {
379 data.obsTimestamp = xml.readElementText();
380 } else if (dateType == "forecastIssue") {
381 data.forecastTimestamp = xml.readElementText();
382 } else if (dateType == "sunrise") {
383 data.sunriseTimestamp = xml.readElementText();
384 } else if (dateType == "sunset") {
385 data.sunsetTimestamp = xml.readElementText();
386 } else if (dateType == "moonrise") {
387 data.moonriseTimestamp = xml.readElementText();
388 } else if (dateType == "moonset") {
389 data.moonsetTimestamp = xml.readElementText();
397 void EnvCanadaIon::parseLocations(WeatherData& data, QXmlStreamReader& xml)
399 Q_ASSERT(xml.isStartElement() && xml.name() == "location");
401 while (!xml.atEnd()) {
402 xml.readNext();
404 if (xml.isEndElement()) {
405 break;
408 if (xml.isStartElement()) {
409 if (xml.name() == "country") {
410 data.countryName = xml.readElementText();
411 } else if (xml.name() == "province" || xml.name() == "territory") {
412 data.longTerritoryName = xml.readElementText();
413 } else if (xml.name() == "name") {
414 data.cityName = xml.readElementText();
415 } else if (xml.name() == "region") {
416 data.regionName = xml.readElementText();
417 } else {
418 parseUnknownElement(xml);
424 void EnvCanadaIon::parseWindInfo(WeatherData& data, QXmlStreamReader& xml)
426 Q_ASSERT(xml.isStartElement() && xml.name() == "wind");
428 while (!xml.atEnd()) {
429 xml.readNext();
431 if (xml.isEndElement()) {
432 break;
435 if (xml.isStartElement()) {
436 if (xml.name() == "speed") {
437 data.windSpeed = xml.readElementText();
438 } else if (xml.name() == "gust") {
439 data.windGust = xml.readElementText();
440 } else if (xml.name() == "direction") {
441 data.windDirection = xml.readElementText();
442 } else {
443 parseUnknownElement(xml);
449 void EnvCanadaIon::parseConditions(WeatherData& data, QXmlStreamReader& xml)
452 Q_ASSERT(xml.isStartElement() && xml.name() == "currentConditions");
453 data.temperature = "N/A";
454 data.dewpoint = "N/A";
455 data.condition = "N/A";
456 data.comforttemp = "N/A";
457 data.stationID = "N/A";
458 data.pressure = 0.0;
459 data.pressureTendency = "N/A";
460 data.visibility = 0;
461 data.humidity = "N/A";
462 data.windSpeed = "N/A";
463 data.windGust = "N/A";
465 while (!xml.atEnd()) {
466 xml.readNext();
468 if (xml.isEndElement() && xml.name() == "currentConditions")
469 break;
471 if (xml.isStartElement()) {
472 if (xml.name() == "station") {
473 data.stationID = xml.attributes().value("code").toString();
474 } else if (xml.name() == "dateTime") {
475 parseDateTime(data, xml);
476 } else if (xml.name() == "condition") {
477 data.condition = xml.readElementText();
478 } else if (xml.name() == "temperature") {
479 data.temperature = xml.readElementText();;
480 } else if (xml.name() == "dewpoint") {
481 data.dewpoint = xml.readElementText();
482 } else if (xml.name() == "humidex" || xml.name() == "windChill") {
483 data.comforttemp = xml.readElementText();
484 } else if (xml.name() == "pressure") {
485 data.pressureTendency = xml.attributes().value("tendency").toString();
486 if (data.pressureTendency.isEmpty()) {
487 data.pressureTendency = "steady";
489 data.pressure = xml.readElementText().toFloat();
490 } else if (xml.name() == "visibility") {
491 data.visibility = xml.readElementText().toFloat();
492 } else if (xml.name() == "relativeHumidity") {
493 data.humidity = xml.readElementText();
494 } else if (xml.name() == "wind") {
495 parseWindInfo(data, xml);
497 //} else {
498 // parseUnknownElement(xml);
504 void EnvCanadaIon::parseWarnings(WeatherData &data, QXmlStreamReader& xml)
506 WeatherData::WarningInfo* warning = new WeatherData::WarningInfo;
508 Q_ASSERT(xml.isStartElement() && xml.name() == "warnings");
509 QString warningURL = xml.attributes().value("url").toString();
510 while (!xml.atEnd()) {
511 xml.readNext();
513 if (xml.isEndElement() && xml.name() == "warnings") {
514 break;
517 if (xml.isStartElement()) {
518 if (xml.name() == "dateTime") {
519 parseDateTime(data, xml, warning);
520 if (!warning->timestamp.isEmpty() && !warning->url.isEmpty()) {
521 data.warnings.append(warning);
522 warning = new WeatherData::WarningInfo;
524 } else if (xml.name() == "event") {
525 // Append new event to list.
526 warning->url = warningURL;
527 warning->type = xml.attributes().value("type").toString();
528 warning->priority = xml.attributes().value("priority").toString();
529 warning->description = xml.attributes().value("description").toString();
530 } else {
531 if (xml.name() != "dateTime") {
532 parseUnknownElement(xml);
537 delete warning;
541 void EnvCanadaIon::parseWeatherForecast(WeatherData& data, QXmlStreamReader& xml)
543 WeatherData::ForecastInfo* forecast = new WeatherData::ForecastInfo;
544 Q_ASSERT(xml.isStartElement() && xml.name() == "forecastGroup");
546 while (!xml.atEnd()) {
547 xml.readNext();
549 if (xml.isEndElement() && xml.name() == "forecastGroup") {
550 break;
553 if (xml.isStartElement()) {
554 if (xml.name() == "dateTime") {
555 parseDateTime(data, xml);
556 } else if (xml.name() == "regionalNormals") {
557 parseRegionalNormals(data, xml);
558 } else if (xml.name() == "forecast") {
559 parseForecast(data, xml, forecast);
560 forecast = new WeatherData::ForecastInfo;
561 } else {
562 parseUnknownElement(xml);
566 delete forecast;
569 void EnvCanadaIon::parseRegionalNormals(WeatherData& data, QXmlStreamReader& xml)
571 Q_ASSERT(xml.isStartElement() && xml.name() == "regionalNormals");
573 while (!xml.atEnd()) {
574 xml.readNext();
576 if (xml.isEndElement()) {
577 break;
580 if (xml.isStartElement()) {
581 if (xml.name() == "textSummary") {
582 xml.readElementText();
583 } else if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
584 data.normalHigh = xml.readElementText();
585 } else if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
586 data.normalLow = xml.readElementText();
592 void EnvCanadaIon::parseForecast(WeatherData& data, QXmlStreamReader& xml, WeatherData::ForecastInfo *forecast)
595 Q_ASSERT(xml.isStartElement() && xml.name() == "forecast");
597 while (!xml.atEnd()) {
598 xml.readNext();
600 if (xml.isEndElement() && xml.name() == "forecast") {
601 data.forecasts.append(forecast);
602 break;
605 if (xml.isStartElement()) {
606 if (xml.name() == "period") {
607 forecast->forecastPeriod = xml.readElementText();
608 } else if (xml.name() == "textSummary") {
609 forecast->forecastSummary = xml.readElementText();
610 } else if (xml.name() == "abbreviatedForecast") {
611 parseShortForecast(forecast, xml);
612 } else if (xml.name() == "temperatures") {
613 parseForecastTemperatures(forecast, xml);
614 } else if (xml.name() == "winds") {
615 parseWindForecast(forecast, xml);
616 } else if (xml.name() == "precipitation") {
617 parsePrecipitationForecast(forecast, xml);
618 } else if (xml.name() == "uv") {
619 data.UVRating = xml.attributes().value("category").toString();
620 parseUVIndex(data, xml);
621 // else if (xml.name() == "frost") { FIXME: Wait until winter to see what this looks like.
622 // parseFrost(xml, forecast);
623 } else {
624 if (xml.name() != "forecast") {
625 parseUnknownElement(xml);
632 void EnvCanadaIon::parseShortForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
634 Q_ASSERT(xml.isStartElement() && xml.name() == "abbreviatedForecast");
636 while (!xml.atEnd()) {
637 xml.readNext();
639 if (xml.isEndElement() && xml.name() == "abbreviatedForecast") {
640 break;
643 if (xml.isStartElement()) {
644 if (xml.name() == "pop") {
645 forecast->popPrecent = xml.readElementText();
647 if (xml.name() == "textSummary") {
648 forecast->shortForecast = xml.readElementText();
654 void EnvCanadaIon::parseUVIndex(WeatherData& data, QXmlStreamReader& xml)
656 Q_ASSERT(xml.isStartElement() && xml.name() == "uv");
658 while (!xml.atEnd()) {
659 xml.readNext();
661 if (xml.isEndElement() && xml.name() == "uv") {
662 break;
665 if (xml.isStartElement()) {
666 if (xml.name() == "index") {
667 data.UVIndex = xml.readElementText();
669 if (xml.name() == "textSummary") {
670 xml.readElementText();
676 void EnvCanadaIon::parseForecastTemperatures(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
678 Q_ASSERT(xml.isStartElement() && xml.name() == "temperatures");
680 while (!xml.atEnd()) {
681 xml.readNext();
683 if (xml.isEndElement() && xml.name() == "temperatures") {
684 break;
687 if (xml.isStartElement()) {
688 if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
689 forecast->forecastTempLow = xml.readElementText();
690 } else if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
691 forecast->forecastTempHigh = xml.readElementText();
692 } else if (xml.name() == "textSummary") {
693 xml.readElementText();
699 void EnvCanadaIon::parsePrecipitationForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
701 Q_ASSERT(xml.isStartElement() && xml.name() == "precipitation");
703 while (!xml.atEnd()) {
704 xml.readNext();
706 if (xml.isEndElement() && xml.name() == "precipitation") {
707 break;
710 if (xml.isStartElement()) {
711 //kDebug() << "parsePrecipitationForecast() ====> TAG: " << xml.name().toString();
712 if (xml.name() == "textSummary") {
713 forecast->precipForecast = xml.readElementText();
714 } else if (xml.name() == "precipType") {
715 forecast->precipType = xml.readElementText();
716 } else if (xml.name() == "accumulation") {
717 parsePrecipTotals(forecast, xml);
723 void EnvCanadaIon::parsePrecipTotals(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
725 Q_ASSERT(xml.isStartElement() && xml.name() == "accumulation");
727 while (!xml.atEnd()) {
728 xml.readNext();
730 if (xml.isEndElement() && xml.name() == "accumulation") {
731 break;
734 if (xml.name() == "name") {
735 xml.readElementText();
736 } else if (xml.name() == "amount") {
737 forecast->precipTotalExpected = xml.readElementText();
742 void EnvCanadaIon::parseWindForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
744 Q_ASSERT(xml.isStartElement() && xml.name() == "winds");
746 while (!xml.atEnd()) {
747 xml.readNext();
749 if (xml.isEndElement() && xml.name() == "winds") {
750 break;
753 if (xml.isStartElement()) {
754 if (xml.name() == "textSummary") {
755 forecast->windForecast = xml.readElementText();
756 } else {
757 if (xml.name() != "winds") {
758 parseUnknownElement(xml);
765 void EnvCanadaIon::parseYesterdayWeather(WeatherData& data, QXmlStreamReader& xml)
767 Q_ASSERT(xml.isStartElement() && xml.name() == "yesterdayConditions");
769 while (!xml.atEnd()) {
770 xml.readNext();
772 if (xml.isEndElement()) {
773 break;
776 if (xml.isStartElement()) {
777 if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
778 data.prevHigh = xml.readElementText();
779 } else if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
780 data.prevLow = xml.readElementText();
781 } else if (xml.name() == "precip") {
782 data.prevPrecipType = xml.attributes().value("units").toString();
783 if (data.prevPrecipType.isEmpty()) {
784 data.prevPrecipType = "N/A";
786 data.prevPrecipTotal = xml.readElementText();
792 void EnvCanadaIon::parseWeatherRecords(WeatherData& data, QXmlStreamReader& xml)
794 Q_ASSERT(xml.isStartElement() && xml.name() == "almanac");
796 while (!xml.atEnd()) {
797 xml.readNext();
799 if (xml.isEndElement() && xml.name() == "almanac") {
800 break;
803 if (xml.isStartElement()) {
804 if (xml.name() == "temperature" && xml.attributes().value("class") == "extremeMax") {
805 data.recordHigh = xml.readElementText().toFloat();
806 } else if (xml.name() == "temperature" && xml.attributes().value("class") == "extremeMin") {
807 data.recordLow = xml.readElementText().toFloat();
808 } else if (xml.name() == "precipitation" && xml.attributes().value("class") == "extremeRainfall") {
809 data.recordRain = xml.readElementText().toFloat();
810 } else if (xml.name() == "precipitation" && xml.attributes().value("class") == "extremeSnowfall") {
811 data.recordSnow = xml.readElementText().toFloat();
817 void EnvCanadaIon::parseAstronomicals(WeatherData& data, QXmlStreamReader& xml)
819 Q_ASSERT(xml.isStartElement() && xml.name() == "riseSet");
821 while (!xml.atEnd()) {
822 xml.readNext();
824 if (xml.isEndElement() && xml.name() == "riseSet") {
825 break;
828 if (xml.isStartElement()) {
829 if (xml.name() == "disclaimer") {
830 xml.readElementText();
831 } else if (xml.name() == "dateTime") {
832 parseDateTime(data, xml);
838 // handle when no XML tag is found
839 void EnvCanadaIon::parseUnknownElement(QXmlStreamReader& xml)
842 while (!xml.atEnd()) {
843 xml.readNext();
845 if (xml.isEndElement()) {
846 break;
849 if (xml.isStartElement()) {
850 parseUnknownElement(xml);
855 void EnvCanadaIon::setMeasureUnit(const QString& unitType)
857 d->m_measureType = unitType.toInt();
860 void EnvCanadaIon::setTimezoneFormat(const QString& tz)
862 d->m_timezoneType = tz.toInt(); // Boolean
865 bool EnvCanadaIon::metricUnit()
867 if (d->m_measureType == KLocale::Metric) {
868 return true;
871 // Imperial units
872 return false;
875 bool EnvCanadaIon::timezone()
877 if (d->m_timezoneType) {
878 return true;
881 // Not UTC, local time
882 return false;
885 void EnvCanadaIon::updateWeather(const QString& source)
887 QMap<QString, QString> dataFields;
888 QStringList fieldList;
889 QVector<QString> forecastList;
890 int i = 0;
892 QString weatherSource = source;
893 weatherSource.replace("envcan|", "envcan|weather|");
895 setData(weatherSource, "Country", country(source));
896 setData(weatherSource, "Place", QString("%1, %2").arg(city(source)).arg(territory(source)));
897 setData(weatherSource, "Region", region(source));
898 setData(weatherSource, "Station", station(source));
900 // Real weather - Current conditions
901 setData(weatherSource, "Observation Period", observationTime(source));
902 setData(weatherSource, "Current Conditions", condition(source));
903 dataFields = temperature(source);
904 setData(weatherSource, "Temperature", dataFields["temperature"]);
906 // Do we have a comfort temperature? if so display it
907 if (dataFields["comfortTemperature"] != "N/A" && !dataFields["comfortTemperature"].isEmpty()) {
908 if (dataFields["comfortTemperature"].toFloat() <= 0 || (dataFields["comfortTemperature"].toFloat() <= 32 && !metricUnit())) {
909 setData(weatherSource, "Windchill", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176)));
910 setData(weatherSource, "Humidex", "N/A");
911 } else {
912 setData(weatherSource, "Humidex", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176)));
913 setData(weatherSource, "Windchill", "N/A");
915 } else {
916 setData(weatherSource, "Windchill", "N/A");
917 setData(weatherSource, "Humidex", "N/A");
920 setData(weatherSource, "Temperature Unit", dataFields["temperatureUnit"]);
922 setData(weatherSource, "Dewpoint", dewpoint(source));
923 if (dewpoint(source) != "N/A") {
924 setData(weatherSource, "Dewpoint Unit", dataFields["temperatureUnit"]);
927 dataFields = pressure(source);
928 setData(weatherSource, "Pressure", dataFields["pressure"]);
930 if (dataFields["pressure"] != "N/A") {
931 setData(weatherSource, "Pressure Tendency", dataFields["pressureTendency"]);
932 setData(weatherSource, "Pressure Unit", dataFields["pressureUnit"]);
935 dataFields = visibility(source);
936 setData(weatherSource, "Visibility", dataFields["visibility"]);
937 if (dataFields["visibility"] != "N/A") {
938 setData(weatherSource, "Visibility Unit", dataFields["visibilityUnit"]);
941 setData(weatherSource, "Humidity", humidity(source));
943 dataFields = wind(source);
944 setData(weatherSource, "Wind Speed", dataFields["windSpeed"]);
945 if (dataFields["windSpeed"] != "N/A") {
946 setData(weatherSource, "Wind Speed Unit", dataFields["windUnit"]);
948 setData(weatherSource, "Wind Gust", dataFields["windGust"]);
949 setData(weatherSource, "Wind Direction", dataFields["windDirection"]);
950 setData(weatherSource, "Wind Gust Unit", dataFields["windGustUnit"]);
952 dataFields = regionalTemperatures(source);
953 setData(weatherSource, "Normal High", dataFields["normalHigh"]);
954 setData(weatherSource, "Normal Low", dataFields["normalLow"]);
955 if (dataFields["normalHigh"] != "N/A" && dataFields["normalLow"] != "N/A") {
956 setData(weatherSource, "Regional Temperature Unit", dataFields["regionalTempUnit"]);
959 // Check if UV index is available for the location
960 dataFields = uvIndex(source);
961 setData(weatherSource, "UV Index", dataFields["uvIndex"]);
962 if (dataFields["uvIndex"] != "N/A") {
963 setData(weatherSource, "UV Rating", dataFields["uvRating"]);
966 dataFields = warnings(source);
967 // Check if we have warnings or watches
969 for (int i = 0; i < EnvCanadaIon::MAX_WARNINGS; i++) {
970 if (!dataFields[QString("watch %1").arg(i)].isEmpty()) {
971 fieldList = dataFields[QString("watch %1").arg(i)].split('|');
972 setData(weatherSource, QString("Watch Priority %1").arg(i), fieldList[0]);
973 setData(weatherSource, QString("Watch Description %1").arg(i), fieldList[1]);
974 setData(weatherSource, QString("Watch Info %1").arg(i), fieldList[2]);
975 setData(weatherSource, QString("Watch Timestamp %1").arg(i), fieldList[3]);
977 if (!dataFields[QString("warning %1").arg(i)].isEmpty()) {
978 fieldList = dataFields[QString("warning %1").arg(i)].split('|');
979 setData(weatherSource, QString("Warning Priority %1").arg(i), fieldList[0]);
980 setData(weatherSource, QString("Warning Description %1").arg(i), fieldList[1]);
981 setData(weatherSource, QString("Warning Info %1").arg(i), fieldList[2]);
982 setData(weatherSource, QString("Warning Timestamp %1").arg(i), fieldList[3]);
986 forecastList = forecasts(source);
987 foreach(QString forecastItem, forecastList) {
988 fieldList = forecastItem.split('|');
990 // TODO: We don't convert the wind format (Knots, meteres per second, bft) for the Long Forecast yet. These are not used in the applet (for now).
991 if (metricUnit()) {
992 setData(weatherSource, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5") \
993 .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[5]));
995 setData(weatherSource, QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \
996 .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[6]) \
997 .arg(fieldList[7]).arg(fieldList[8]).arg(fieldList[9]));
998 } else {
999 setData(weatherSource, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5") \
1000 .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[3] == "N/A" ? "N/A" : \
1001 QString::number(WeatherFormula::celsiusToF(fieldList[3].toFloat()), 'd', 0)) \
1002 .arg(fieldList[4] == "N/A" ? "N/A" : QString::number(WeatherFormula::celsiusToF(fieldList[4].toFloat()), 'd', 0)).arg(fieldList[5]));
1004 setData(weatherSource, QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \
1005 .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3] == "N/A" ? "N/A" : \
1006 QString::number(WeatherFormula::celsiusToF(fieldList[3].toFloat()), 'd', 0)) \
1007 .arg(fieldList[4] == "N/A" ? "N/A" : QString::number(WeatherFormula::celsiusToF(fieldList[4].toFloat()), 'd', 0)).arg(fieldList[6]).arg(fieldList[7]) \
1008 .arg(fieldList[8]).arg(fieldList[9]));
1011 i++;
1014 dataFields = yesterdayWeather(source);
1015 setData(weatherSource, "Yesterday High", dataFields["prevHigh"]);
1016 setData(weatherSource, "Yesterday Low", dataFields["prevLow"]);
1018 if (dataFields["prevHigh"] != "N/A" && dataFields["prevLow"] != "N/A") {
1019 setData(weatherSource , "Yesterday Temperature Unit", dataFields["yesterdayTempUnit"]);
1022 setData(weatherSource, "Yesterday Precip Total", dataFields["prevPrecip"]);
1023 setData(weatherSource, "Yesterday Precip Unit", dataFields["prevPrecipUnit"]);
1025 dataFields = sunriseSet(source);
1026 setData(weatherSource, "Sunrise At", dataFields["sunrise"]);
1027 setData(weatherSource, "Sunset At", dataFields["sunset"]);
1029 dataFields = moonriseSet(source);
1030 setData(weatherSource, "Moonrise At", dataFields["moonrise"]);
1031 setData(weatherSource, "Moonset At", dataFields["moonset"]);
1033 dataFields = weatherRecords(source);
1034 setData(weatherSource, "Record High Temperature", dataFields["recordHigh"]);
1035 setData(weatherSource, "Record Low Temperature", dataFields["recordLow"]);
1036 if (dataFields["recordHigh"] != "N/A" && dataFields["recordLow"] != "N/A") {
1037 setData(weatherSource, "Record Temperature Unit", dataFields["recordTempUnit"]);
1040 setData(weatherSource, "Record Rainfall", dataFields["recordRain"]);
1041 setData(weatherSource, "Record Rainfall Unit", dataFields["recordRainUnit"]);
1042 setData(weatherSource, "Record Snowfall", dataFields["recordSnow"]);
1043 setData(weatherSource, "Record Snowfall Unit", dataFields["recordSnowUnit"]);
1045 setData(weatherSource, "Credit", "Meteorological data is provided by Environment Canada");
1048 QString EnvCanadaIon::country(const QString& source)
1050 return d->m_weatherData[source].countryName;
1052 QString EnvCanadaIon::territory(const QString& source)
1054 return d->m_weatherData[source].shortTerritoryName;
1056 QString EnvCanadaIon::city(const QString& source)
1058 return d->m_weatherData[source].cityName;
1060 QString EnvCanadaIon::region(const QString& source)
1062 return d->m_weatherData[source].regionName;
1064 QString EnvCanadaIon::station(const QString& source)
1066 if (!d->m_weatherData[source].stationID.isEmpty()) {
1067 return d->m_weatherData[source].stationID.toUpper();
1070 return QString("N/A");
1073 QString EnvCanadaIon::observationTime(const QString& source)
1075 return d->m_weatherData[source].obsTimestamp;
1077 QString EnvCanadaIon::condition(const QString& source)
1079 if (d->m_weatherData[source].condition.isEmpty()) {
1080 d->m_weatherData[source].condition = "N/A";
1082 return d->m_weatherData[source].condition;
1085 QString EnvCanadaIon::dewpoint(const QString& source)
1087 if (metricUnit()) {
1088 if (!d->m_weatherData[source].dewpoint.isEmpty()) {
1089 return QString::number(d->m_weatherData[source].dewpoint.toFloat(), 'f', 1);
1093 if (!d->m_weatherData[source].dewpoint.isEmpty()) {
1094 return QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].dewpoint.toFloat()), 'f', 1);
1097 return QString("N/A");
1100 QString EnvCanadaIon::humidity(const QString& source)
1102 if (!d->m_weatherData[source].humidity.isEmpty()) {
1103 return QString("%1%").arg(d->m_weatherData[source].humidity);
1105 return QString("N/A");
1108 QMap<QString, QString> EnvCanadaIon::visibility(const QString& source)
1110 QMap<QString, QString> visibilityInfo;
1112 if (!d->m_weatherData[source].visibility == 0) {
1113 if (metricUnit()) {
1114 visibilityInfo.insert("visibility", QString::number(d->m_weatherData[source].visibility, 'f', 1));
1115 visibilityInfo.insert("visibilityUnit", "km");
1116 } else {
1117 visibilityInfo.insert("visibility", QString::number(WeatherFormula::kilometersToMI(d->m_weatherData[source].visibility), 'f', 2));
1118 visibilityInfo.insert("visibilityUnit", "mi");
1120 } else {
1121 visibilityInfo.insert("visibility", "N/A");
1123 return visibilityInfo;
1126 QMap<QString, QString> EnvCanadaIon::temperature(const QString& source)
1128 QMap<QString, QString> temperatureInfo;
1129 if (metricUnit()) {
1130 if (!d->m_weatherData[source].temperature.isEmpty()) {
1131 temperatureInfo.insert("temperature", QString::number(d->m_weatherData[source].temperature.toFloat(), 'f', 1));
1133 temperatureInfo.insert("temperatureUnit", QString("%1C").arg(QChar(176)));
1134 } else {
1135 if (!d->m_weatherData[source].temperature.isEmpty()) {
1136 temperatureInfo.insert("temperature", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].temperature.toFloat()), 'f', 1));
1137 } else {
1138 temperatureInfo.insert("temperature", "N/A");
1140 temperatureInfo.insert("temperatureUnit", QString("%1F").arg(QChar(176)));
1142 temperatureInfo.insert("comfortTemperature", "N/A");
1144 if (d->m_weatherData[source].comforttemp != "N/A") {
1145 if (metricUnit()) {
1146 temperatureInfo.insert("comfortTemperature", d->m_weatherData[source].comforttemp);
1147 } else {
1148 if (!d->m_weatherData[source].comforttemp.isEmpty()) {
1149 temperatureInfo.insert("comfortTemperature", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].comforttemp.toFloat()), 'f', 1));
1153 return temperatureInfo;
1156 QMap<QString, QString> EnvCanadaIon::warnings(const QString& source)
1158 QMap<QString, QString> warningData;
1159 QString warnType;
1160 for (int i = 0; i < d->m_weatherData[source].warnings.size(); ++i) {
1161 if (d->m_weatherData[source].warnings[i]->type == "watch") {
1162 warnType = QString("watch %1").arg(i);
1163 } else {
1164 warnType = QString("warning %1").arg(i);
1166 warningData[warnType] = QString("%1|%2|%3|%4").arg(d->m_weatherData[source].warnings[i]->priority) \
1167 .arg(d->m_weatherData[source].warnings[i]->description) \
1168 .arg(d->m_weatherData[source].warnings[i]->url) \
1169 .arg(d->m_weatherData[source].warnings[i]->timestamp);
1171 return warningData;
1174 QVector<QString> EnvCanadaIon::forecasts(const QString& source)
1176 QVector<QString> forecastData;
1178 // Do some checks for empty data
1179 for (int i = 0; i < d->m_weatherData[source].forecasts.size(); ++i) {
1180 if (d->m_weatherData[source].forecasts[i]->forecastPeriod.isEmpty()) {
1181 d->m_weatherData[source].forecasts[i]->forecastPeriod = "N/A";
1183 if (d->m_weatherData[source].forecasts[i]->shortForecast.isEmpty()) {
1184 d->m_weatherData[source].forecasts[i]->shortForecast = "N/A";
1186 if (d->m_weatherData[source].forecasts[i]->forecastSummary.isEmpty()) {
1187 d->m_weatherData[source].forecasts[i]->forecastSummary = "N/A";
1189 if (d->m_weatherData[source].forecasts[i]->forecastTempHigh.isEmpty()) {
1190 d->m_weatherData[source].forecasts[i]->forecastTempHigh = "N/A";
1192 if (d->m_weatherData[source].forecasts[i]->forecastTempLow.isEmpty()) {
1193 d->m_weatherData[source].forecasts[i]->forecastTempLow = "N/A";
1195 if (d->m_weatherData[source].forecasts[i]->popPrecent.isEmpty()) {
1196 d->m_weatherData[source].forecasts[i]->popPrecent = "N/A";
1198 if (d->m_weatherData[source].forecasts[i]->windForecast.isEmpty()) {
1199 d->m_weatherData[source].forecasts[i]->windForecast = "N/A";
1201 if (d->m_weatherData[source].forecasts[i]->precipForecast.isEmpty()) {
1202 d->m_weatherData[source].forecasts[i]->precipForecast = "N/A";
1204 if (d->m_weatherData[source].forecasts[i]->precipType.isEmpty()) {
1205 d->m_weatherData[source].forecasts[i]->precipType = "N/A";
1207 if (d->m_weatherData[source].forecasts[i]->precipTotalExpected.isEmpty()) {
1208 d->m_weatherData[source].forecasts[i]->precipTotalExpected = "N/A";
1212 for (int i = 0; i < d->m_weatherData[source].forecasts.size(); ++i) {
1213 forecastData.append(QString("%1|%2|%3|%4|%5|%6|%7|%8|%9|%10") \
1214 .arg(d->m_weatherData[source].forecasts[i]->forecastPeriod) \
1215 .arg(d->m_weatherData[source].forecasts[i]->shortForecast) \
1216 .arg(d->m_weatherData[source].forecasts[i]->forecastSummary) \
1217 .arg(d->m_weatherData[source].forecasts[i]->forecastTempHigh) \
1218 .arg(d->m_weatherData[source].forecasts[i]->forecastTempLow) \
1219 .arg(d->m_weatherData[source].forecasts[i]->popPrecent) \
1220 .arg(d->m_weatherData[source].forecasts[i]->windForecast) \
1221 .arg(d->m_weatherData[source].forecasts[i]->precipForecast) \
1222 .arg(d->m_weatherData[source].forecasts[i]->precipType) \
1223 .arg(d->m_weatherData[source].forecasts[i]->precipTotalExpected));
1225 return forecastData;
1228 QMap<QString, QString> EnvCanadaIon::pressure(const QString& source)
1230 QMap<QString, QString> pressureInfo;
1232 if (d->m_weatherData[source].pressure == 0) {
1233 pressureInfo.insert("pressure", "N/A");
1234 return pressureInfo;
1235 } else {
1236 if (metricUnit()) {
1237 pressureInfo.insert("pressure", QString::number(d->m_weatherData[source].pressure, 'f', 1));
1238 pressureInfo.insert("pressureUnit", "kPa");
1239 } else {
1240 pressureInfo.insert("pressure", QString::number(WeatherFormula::kilopascalsToInches(d->m_weatherData[source].pressure), 'f', 2));
1241 pressureInfo.insert("pressureUnit", "in");
1243 pressureInfo.insert("pressureTendency", d->m_weatherData[source].pressureTendency);
1245 return pressureInfo;
1248 QMap<QString, QString> EnvCanadaIon::wind(const QString& source)
1250 QMap<QString, QString> windInfo;
1252 // May not have any winds
1253 if (d->m_weatherData[source].windSpeed.isEmpty()) {
1254 windInfo.insert("windSpeed", "N/A");
1255 windInfo.insert("windUnit", "N/A");
1256 } else if (d->m_weatherData[source].windSpeed.toInt() == 0) {
1257 windInfo.insert("windSpeed", "Calm");
1258 windInfo.insert("windUnit", "N/A");
1259 } else {
1260 if (metricUnit()) {
1261 windInfo.insert("windSpeed", QString::number(d->m_weatherData[source].windSpeed.toInt()));
1262 windInfo.insert("windUnit", "km/h");
1263 } else {
1264 windInfo.insert("windSpeed", QString::number(WeatherFormula::kilometersToMI(d->m_weatherData[source].windSpeed.toInt()), 'f', 1));
1265 windInfo.insert("windUnit", "mph");
1269 // May not always have gusty winds
1270 if (d->m_weatherData[source].windGust.isEmpty()) {
1271 windInfo.insert("windGust", "N/A");
1272 windInfo.insert("windGustUnit", "N/A");
1273 } else {
1274 if (metricUnit()) {
1275 windInfo.insert("windGust", QString::number(d->m_weatherData[source].windGust.toInt()));
1276 windInfo.insert("windGustUnit", "km/h");
1277 } else {
1278 windInfo.insert("windGust", QString::number(WeatherFormula::kilometersToMI(d->m_weatherData[source].windGust.toInt()), 'f', 1));
1279 windInfo.insert("windGustUnit", "mph");
1283 if (d->m_weatherData[source].windDirection.isEmpty() && d->m_weatherData[source].windSpeed.isEmpty()) {
1284 windInfo.insert("windDirection", "N/A");
1285 } else if (d->m_weatherData[source].windSpeed.toInt() == 0) {
1286 windInfo.insert("windDirection", "VR");
1287 } else {
1288 windInfo.insert("windDirection", d->m_weatherData[source].windDirection);
1290 return windInfo;
1293 QMap<QString, QString> EnvCanadaIon::uvIndex(const QString& source)
1295 QMap<QString, QString> uvInfo;
1297 if (d->m_weatherData[source].UVRating.isEmpty()) {
1298 uvInfo.insert("uvRating", "N/A");
1299 } else {
1300 uvInfo.insert("uvRating", d->m_weatherData[source].UVRating);
1303 if (d->m_weatherData[source].UVIndex.isEmpty()) {
1304 uvInfo.insert("uvIndex", "N/A");
1305 } else {
1306 uvInfo.insert("uvIndex", d->m_weatherData[source].UVIndex);
1309 return uvInfo;
1312 QMap<QString, QString> EnvCanadaIon::regionalTemperatures(const QString& source)
1314 QMap<QString, QString> regionalTempInfo;
1316 if (d->m_weatherData[source].normalHigh.isEmpty()) {
1317 regionalTempInfo.insert("normalHigh", "N/A");
1318 } else {
1319 if (metricUnit()) {
1320 regionalTempInfo.insert("normalHigh", d->m_weatherData[source].normalHigh);
1321 } else {
1322 regionalTempInfo.insert("normalHigh", QString("%1").arg(WeatherFormula::celsiusToF(d->m_weatherData[source].normalHigh.toFloat())));
1326 if (d->m_weatherData[source].normalLow.isEmpty()) {
1327 regionalTempInfo.insert("normalLow", "N/A");
1328 } else {
1329 if (metricUnit()) {
1330 regionalTempInfo.insert("normalLow", d->m_weatherData[source].normalLow);
1331 } else {
1332 regionalTempInfo.insert("normalLow", QString("%1").arg(WeatherFormula::celsiusToF(d->m_weatherData[source].normalLow.toFloat())));
1336 if (metricUnit()) {
1337 regionalTempInfo.insert("regionalTempUnit", QString("%1C").arg(QChar(176)));
1338 } else {
1339 regionalTempInfo.insert("regionalTempUnit", QString("%1F").arg(QChar(176)));
1342 return regionalTempInfo;
1345 QMap<QString, QString> EnvCanadaIon::yesterdayWeather(const QString& source)
1347 QMap<QString, QString> yesterdayInfo;
1349 if (d->m_weatherData[source].prevHigh.isEmpty()) {
1350 yesterdayInfo.insert("prevHigh", "N/A");
1351 } else {
1352 if (metricUnit()) {
1353 yesterdayInfo.insert("prevHigh", d->m_weatherData[source].prevHigh);
1354 } else {
1355 yesterdayInfo.insert("prevHigh", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].prevHigh.toFloat())));
1359 if (d->m_weatherData[source].prevLow.isEmpty()) {
1360 yesterdayInfo.insert("prevLow", "N/A");
1361 } else {
1362 if (metricUnit()) {
1363 yesterdayInfo.insert("prevLow", d->m_weatherData[source].prevLow);
1364 } else {
1365 yesterdayInfo.insert("prevLow", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].prevLow.toFloat()), 'f', 1));
1369 if (metricUnit()) {
1370 yesterdayInfo.insert("yesterdayTempUnit", QString("%1C").arg(QChar(176)));
1371 } else {
1372 yesterdayInfo.insert("yesterdayTempUnit", QString("%1F").arg(QChar(176)));
1375 if (d->m_weatherData[source].prevPrecipTotal == "Trace") {
1376 yesterdayInfo.insert("prevPrecip", "Trace");
1377 return yesterdayInfo;
1380 if (d->m_weatherData[source].prevPrecipTotal.isEmpty()) {
1381 yesterdayInfo.insert("prevPrecip", "N/A");
1382 } else {
1383 if (metricUnit()) {
1384 yesterdayInfo.insert("prevPrecipTotal", d->m_weatherData[source].prevPrecipTotal);
1385 yesterdayInfo.insert("prevPrecipUnit", d->m_weatherData[source].prevPrecipType);
1386 } else {
1387 yesterdayInfo.insert("prevPrecipTotal", QString::number(WeatherFormula::millimetersToIN(d->m_weatherData[source].prevPrecipTotal.toFloat()), 'f', 1));
1388 yesterdayInfo.insert("prevPrecipUnit", QString("in"));
1392 return yesterdayInfo;
1395 QMap<QString, QString> EnvCanadaIon::sunriseSet(const QString& source)
1397 QMap<QString, QString> sunInfo;
1399 if (d->m_weatherData[source].sunriseTimestamp.isEmpty()) {
1400 sunInfo.insert("sunrise", "N/A");
1401 } else {
1402 sunInfo.insert("sunrise", d->m_weatherData[source].sunriseTimestamp);
1405 if (d->m_weatherData[source].sunsetTimestamp.isEmpty()) {
1406 sunInfo.insert("sunset", "N/A");
1407 } else {
1408 sunInfo.insert("sunset", d->m_weatherData[source].sunsetTimestamp);
1411 return sunInfo;
1414 QMap<QString, QString> EnvCanadaIon::moonriseSet(const QString& source)
1416 QMap<QString, QString> moonInfo;
1418 if (d->m_weatherData[source].moonriseTimestamp.isEmpty()) {
1419 moonInfo.insert("moonrise", "N/A");
1420 } else {
1421 moonInfo.insert("moonrise", d->m_weatherData[source].moonriseTimestamp);
1424 if (d->m_weatherData[source].moonsetTimestamp.isEmpty()) {
1425 moonInfo.insert("moonset", "N/A");
1426 } else {
1427 moonInfo.insert("moonset", d->m_weatherData[source].moonsetTimestamp);
1430 return moonInfo;
1433 QMap<QString, QString> EnvCanadaIon::weatherRecords(const QString& source)
1435 QMap<QString, QString> recordInfo;
1437 if (d->m_weatherData[source].recordHigh == 0) {
1438 recordInfo.insert("recordHigh", "N/A");
1439 } else {
1440 if (metricUnit()) {
1441 recordInfo.insert("recordHigh", QString("%1").arg(d->m_weatherData[source].recordHigh));
1442 } else {
1443 recordInfo.insert("recordHigh", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].recordHigh), 'f', 1));
1447 if (d->m_weatherData[source].recordLow == 0) {
1448 recordInfo.insert("recordLow", "N/A");
1449 } else {
1450 if (metricUnit()) {
1451 recordInfo.insert("recordLow", QString("%1").arg(d->m_weatherData[source].recordLow));
1452 } else {
1453 recordInfo.insert("recordLow", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].recordLow), 'f', 1));
1458 if (metricUnit()) {
1459 recordInfo.insert("recordTempUnit", QString("%1C").arg(QChar(176)));
1460 } else {
1461 recordInfo.insert("recordTempUnit", QString("%1F").arg(QChar(176)));
1464 if (d->m_weatherData[source].recordRain == 0) {
1465 recordInfo.insert("recordRain", "N/A");
1466 } else {
1467 if (metricUnit()) {
1468 recordInfo.insert("recordRain", QString("%1").arg(d->m_weatherData[source].recordRain));
1469 recordInfo.insert("recordRainUnit", QString("mm"));
1470 } else {
1471 recordInfo.insert("recordRain", QString::number(WeatherFormula::millimetersToIN(d->m_weatherData[source].recordRain), 'f', 1));
1472 recordInfo.insert("recordRainUnit", QString("in"));
1476 if (d->m_weatherData[source].recordSnow == 0) {
1477 recordInfo.insert("recordSnow", "N/A");
1478 } else {
1479 if (metricUnit()) {
1480 recordInfo.insert("recordSnow", QString("%1").arg(d->m_weatherData[source].recordSnow));
1481 recordInfo.insert("recordSnowUnit", QString("cm"));
1482 } else {
1483 recordInfo.insert("recordSnow", QString::number(WeatherFormula::centimetersToIN(d->m_weatherData[source].recordSnow), 'f', 1));
1484 recordInfo.insert("recordSnowUnit", QString("in"));
1488 return recordInfo;
1491 #include "ion_envcan.moc"