• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

Engines

ion_envcan.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2007 by Shawn Starr <shawn.starr@rogers.com>            *
00003  *                                                                         *
00004  *   This program is free software; you can redistribute it and/or modify  *
00005  *   it under the terms of the GNU General Public License as published by  *
00006  *   the Free Software Foundation; either version 2 of the License, or     *
00007  *   (at your option) any later version.                                   *
00008  *                                                                         *
00009  *   This program is distributed in the hope that it will be useful,       *
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00012  *   GNU General Public License for more details.                          *
00013  *                                                                         *
00014  *   You should have received a copy of the GNU General Public License     *
00015  *   along with this program; if not, write to the                         *
00016  *   Free Software Foundation, Inc.,                                       *
00017  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA          *
00018  ***************************************************************************/
00019 
00020 /* Ion for Environment Canada XML data */
00021 
00022 #include "ion_envcan.h"
00023 
00024 class EnvCanadaIon::Private : public QObject
00025 {
00026 public:
00027     Private() { m_url = 0; }
00028     ~Private() { delete m_url; }
00029 
00030 private:
00031     struct XMLMapInfo {
00032         QString cityName;
00033         QString territoryName;
00034         QString cityCode;
00035         QString sourceOptions;
00036     };
00037 
00038 public:
00039     // Key dicts
00040     QHash<QString, EnvCanadaIon::Private::XMLMapInfo> m_place;
00041     QHash<QString, QString> m_locations;
00042     QString m_code;
00043     QString m_territory;
00044     QString m_cityName;
00045 
00046     // Weather information
00047     QHash<QString, WeatherData> m_weatherData;
00048 
00049     // Store KIO jobs
00050     QMap<KJob *, QXmlStreamReader*> m_jobXml;
00051     QMap<KJob *, QString> m_jobList;
00052     QXmlStreamReader m_xmlSetup;
00053     KUrl *m_url;
00054     KIO::TransferJob *m_job;
00055 
00056     int m_timezoneType;  // Ion option: Timezone may be local time or UTC time
00057     int m_measureType; // Ion option: Units may be Metric or Imperial
00058 };
00059 
00060 
00061 // ctor, dtor
00062 EnvCanadaIon::EnvCanadaIon(QObject *parent, const QVariantList &args)
00063         : IonInterface(parent, args), d(new Private())
00064 {
00065 }
00066 
00067 EnvCanadaIon::~EnvCanadaIon()
00068 {
00069     // Destroy each warning stored in a QVector
00070     foreach(const WeatherData &item, d->m_weatherData) {
00071         foreach(WeatherData::WarningInfo *warning, item.warnings) {
00072             if (warning) {
00073                 delete warning;
00074             }
00075         }
00076         foreach(WeatherData::ForecastInfo *forecast, item.forecasts) {
00077             if (forecast) {
00078                 delete forecast;
00079             }
00080         }
00081     }
00082 
00083     // Destroy dptr
00084     delete d;
00085 }
00086 
00087 // Get the master list of locations to be parsed
00088 void EnvCanadaIon::init()
00089 {
00090     // Get the real city XML URL so we can parse this
00091     getXMLSetup();
00092 }
00093 
00094 QStringList EnvCanadaIon::validate(const QString& source) const
00095 {
00096     QStringList placeList;
00097     QHash<QString, QString>::const_iterator it = d->m_locations.constBegin();
00098     while (it != d->m_locations.constEnd()) {
00099         if (it.value().toLower().contains(source.toLower())) {
00100             placeList.append(QString("place|%1").arg(it.value().split("|")[1]));
00101         }
00102         ++it;
00103     }
00104 
00105     // Check if placeList is empty if so, return nothing.
00106     if (placeList.isEmpty()) {
00107         return QStringList();
00108     }
00109     placeList.sort();
00110     return placeList;
00111 }
00112 
00113 // Get a specific Ion's data
00114 bool EnvCanadaIon::updateIonSource(const QString& source)
00115 {
00116     kDebug() << "updateIonSource() SOURCE: " << source;
00117     // We expect the applet to send the source in the following tokenization:
00118     // ionname|validate|place_name - Triggers validation of place
00119     // ionname|weather|place_name - Triggers receiving weather of place
00120 
00121     QStringList sourceAction = source.split('|');
00122     if (sourceAction[1] == QString("validate")) {
00123         kDebug() << "Initiate Validating of place: " << sourceAction[2];
00124 
00125         QStringList result = validate(QString("%1|%2").arg(sourceAction[0]).arg(sourceAction[2]));
00126 
00127         if (result.size() == 1) {
00128             setData(source, "validate", QString("envcan|valid|single|%1").arg(result.join("|")));
00129             return true;
00130         } else if (result.size() > 1) {
00131             setData(source, "validate", QString("envcan|valid|multiple|%1").arg(result.join("|")));
00132             return true;
00133         } else if (result.size() == 0) {
00134             setData(source, "validate", QString("envcan|invalid|single|%1").arg(sourceAction[2]));
00135             return true;
00136         }
00137 
00138     } else if (sourceAction[1] == QString("weather")) {
00139         getXMLData(source);
00140         return true;
00141     }
00142     return false;
00143 }
00144 
00145 // Parses city list and gets the correct city based on ID number
00146 void EnvCanadaIon::getXMLSetup()
00147 {
00148 
00149     d->m_url = new KUrl("http://dd.weatheroffice.ec.gc.ca/EC_sites/xml/siteList.xml");
00150 
00151     KIO::TransferJob *job = KIO::get(d->m_url->url(), KIO::NoReload, KIO::HideProgressInfo);
00152 
00153     if (job) {
00154         connect(job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
00155                 SLOT(setup_slotDataArrived(KIO::Job *, const QByteArray &)));
00156         connect(job, SIGNAL(result(KJob *)), this, SLOT(setup_slotJobFinished(KJob *)));
00157     }
00158 }
00159 
00160 // Gets specific city XML data
00161 void EnvCanadaIon::getXMLData(const QString& source)
00162 {
00163     KUrl url;
00164     
00165     // Demunge source name for key only.
00166     QString dataKey = source;
00167     dataKey.replace("|weather", "");
00168     kDebug() << "DATA KEY: " << dataKey;
00169 
00170     url = "http://dd.weatheroffice.ec.gc.ca/EC_sites/xml/" + d->m_place[dataKey].territoryName + "/" + d->m_place[dataKey].cityCode + "_e.xml";
00171 
00172     kDebug() << "URL Location: " << url.url();
00173 
00174     d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
00175     d->m_jobXml.insert(d->m_job, new QXmlStreamReader);
00176     d->m_jobList.insert(d->m_job, source);
00177 
00178     if (d->m_job) {
00179         connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
00180                 SLOT(slotDataArrived(KIO::Job *, const QByteArray &)));
00181         connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(slotJobFinished(KJob *)));
00182     }
00183 }
00184 
00185 void EnvCanadaIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data)
00186 {
00187     Q_UNUSED(job)
00188 
00189     if (data.isEmpty()) {
00190         return;
00191     }
00192 
00193     // Send to xml.
00194     d->m_xmlSetup.addData(data);
00195 }
00196 
00197 void EnvCanadaIon::slotDataArrived(KIO::Job *job, const QByteArray &data)
00198 {
00199 
00200     if (data.isEmpty() || !d->m_jobXml.contains(job)) {
00201         return;
00202     }
00203 
00204     // Send to xml.
00205     d->m_jobXml[job]->addData(data);
00206 }
00207 
00208 void EnvCanadaIon::slotJobFinished(KJob *job)
00209 {
00210     // Dual use method, if we're fetching location data to parse we need to do this first
00211     kDebug() << "WE FINISHED JOB!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!";
00212     setData(d->m_jobList[job], Data());
00213     readXMLData(d->m_jobList[job], *d->m_jobXml[job]);
00214     d->m_jobList.remove(job);
00215     delete d->m_jobXml[job];
00216     d->m_jobXml.remove(job);
00217 }
00218 
00219 void EnvCanadaIon::setup_slotJobFinished(KJob *job)
00220 {
00221     Q_UNUSED(job)
00222     readXMLSetup();
00223     setInitialized(true);
00224     kDebug() << "We're INITIALIZED... GO!";
00225 }
00226 
00227 // Parse the city list and store into a QMap
00228 bool EnvCanadaIon::readXMLSetup()
00229 {
00230     QString tmp;
00231     kDebug() << "readXMLSetup()";
00232     while (!d->m_xmlSetup.atEnd()) {
00233         d->m_xmlSetup.readNext();
00234 
00235         if (d->m_xmlSetup.isStartElement()) {
00236 
00237             // XML ID code to match filename
00238             if (d->m_xmlSetup.name() == "site") {
00239                 d->m_code = d->m_xmlSetup.attributes().value("code").toString();
00240             }
00241 
00242             if (d->m_xmlSetup.name() == "nameEn") {
00243                 d->m_cityName = d->m_xmlSetup.readElementText(); // Name of cities
00244             }
00245 
00246             if (d->m_xmlSetup.name() == "provinceCode") {
00247                 d->m_territory = d->m_xmlSetup.readElementText(); // Provinces/Territory list
00248                 tmp = "envcan|" + d->m_cityName + ", " + d->m_territory; // Build the key name.
00249 
00250                 // Set the mappings
00251                 d->m_place[tmp].cityCode = d->m_code;
00252                 d->m_place[tmp].territoryName = d->m_territory;
00253                 d->m_place[tmp].cityName = d->m_cityName;
00254 
00255                 // Set the string list, we will use for the applet to display the available cities.
00256                 kDebug() << "KEY NAME: " << tmp;
00257                 d->m_locations[tmp] = tmp;
00258             }
00259         }
00260 
00261     }
00262     return !d->m_xmlSetup.error();
00263 }
00264 
00265 WeatherData EnvCanadaIon::parseWeatherSite(WeatherData& data, QXmlStreamReader& xml)
00266 {
00267     while (!xml.atEnd()) {
00268         xml.readNext();
00269 
00270         if (xml.isStartElement()) {
00271             if (xml.name() == "license") {
00272                 xml.readElementText();
00273             } else if (xml.name() == "location") {
00274                 parseLocations(data, xml);
00275             } else if (xml.name() == "warnings") {
00276                 // Cleanup warning list on update
00277                 data.warnings.clear();
00278                 parseWarnings(data, xml);
00279             } else if (xml.name() == "currentConditions") {
00280                 parseConditions(data, xml);
00281             } else if (xml.name() == "forecastGroup") {
00282                 // Clean up forecast list on update
00283                 data.forecasts.clear();
00284                 parseWeatherForecast(data, xml);
00285             } else if (xml.name() == "yesterdayConditions") {
00286                 parseYesterdayWeather(data, xml);
00287             } else if (xml.name() == "riseSet") {
00288                 parseAstronomicals(data, xml);
00289             } else if (xml.name() == "almanac") {
00290                 parseWeatherRecords(data, xml);
00291             } else {
00292                 parseUnknownElement(xml);
00293             }
00294         }
00295     }
00296     return data;
00297 }
00298 
00299 // Parse Weather data main loop, from here we have to decend into each tag pair
00300 bool EnvCanadaIon::readXMLData(const QString& source, QXmlStreamReader& xml)
00301 {
00302     WeatherData data;
00303     data.comforttemp = "N/A";
00304     data.recordHigh = 0.0;
00305     data.recordLow = 0.0;
00306    
00307     QString dataKey = source;
00308     dataKey.replace("|weather", "");
00309     data.shortTerritoryName = d->m_place[dataKey].territoryName;
00310     while (!xml.atEnd()) {
00311         xml.readNext();
00312 
00313         if (xml.isEndElement()) {
00314             break;
00315         }
00316 
00317         if (xml.isStartElement()) {
00318             if (xml.name() == "siteData") {
00319                 data = parseWeatherSite(data, xml);
00320             } else {
00321                 parseUnknownElement(xml);
00322             }
00323         }
00324     }
00325 
00326     d->m_weatherData[source] = data;
00327     updateWeather(source);
00328     return !xml.error();
00329 }
00330 
00331 void EnvCanadaIon::parseDateTime(WeatherData& data, QXmlStreamReader& xml, WeatherData::WarningInfo *warning)
00332 {
00333 
00334     Q_ASSERT(xml.isStartElement() && xml.name() == "dateTime");
00335 
00336     // What kind of date info is this?
00337     QString dateType = xml.attributes().value("name").toString();
00338     QString dateZone = xml.attributes().value("zone").toString();
00339 
00340 
00341     while (!xml.atEnd()) {
00342         xml.readNext();
00343 
00344         if (xml.isEndElement()) {
00345             break;
00346         }
00347 
00348         if (xml.isStartElement()) {
00349             if (dateType == "xmlCreation") {
00350                 return;
00351             }
00352             if (xml.name() == "year") {
00353                 xml.readElementText();
00354             } else if (xml.name() == "month") {
00355                 xml.readElementText();
00356             } else if (xml.name() == "day") {
00357                 xml.readElementText();
00358             } else if (xml.name() == "hour")
00359                 xml.readElementText();
00360             else if (xml.name() == "minute")
00361                 xml.readElementText();
00362             else if (xml.name() == "timeStamp")
00363                 xml.readElementText();
00364             else if (xml.name() == "textSummary") {
00365                 if (timezone() && dateZone == "UTC") {
00366                     // Which timestamp are we for?
00367 
00368                     if (dateType == "eventIssue") {
00369                         if (warning) {
00370                             warning->timestamp = xml.readElementText();
00371                         }
00372                     } else if (dateType == "observation") {
00373                         data.obsTimestamp = xml.readElementText();
00374                     } else if (dateType == "forecastIssue") {
00375                         data.forecastTimestamp = xml.readElementText();
00376                     } else if (dateType == "sunrise") {
00377                         data.sunriseTimestamp = xml.readElementText();
00378                     } else if (dateType == "sunset") {
00379                         data.sunsetTimestamp = xml.readElementText();
00380                     } else if (dateType == "moonrise") {
00381                         data.moonriseTimestamp = xml.readElementText();
00382                     } else if (dateType == "moonset") {
00383                         data.moonsetTimestamp = xml.readElementText();
00384                     }
00385 
00386                 } else if (dateZone != "UTC") {
00387                     if (dateType == "eventIssue") {
00388                         if (warning) {
00389                             warning->timestamp = xml.readElementText();
00390                         }
00391                     } else if (dateType == "observation") {
00392                         data.obsTimestamp = xml.readElementText();
00393                     } else if (dateType == "forecastIssue") {
00394                         data.forecastTimestamp = xml.readElementText();
00395                     } else if (dateType == "sunrise") {
00396                         data.sunriseTimestamp = xml.readElementText();
00397                     } else if (dateType == "sunset") {
00398                         data.sunsetTimestamp = xml.readElementText();
00399                     } else if (dateType == "moonrise") {
00400                         data.moonriseTimestamp = xml.readElementText();
00401                     } else if (dateType == "moonset") {
00402                         data.moonsetTimestamp = xml.readElementText();
00403                     }
00404                 }
00405             }
00406         }
00407     }
00408 }
00409 
00410 void EnvCanadaIon::parseLocations(WeatherData& data, QXmlStreamReader& xml)
00411 {
00412     Q_ASSERT(xml.isStartElement() && xml.name() == "location");
00413 
00414     while (!xml.atEnd()) {
00415         xml.readNext();
00416 
00417         if (xml.isEndElement()) {
00418             break;
00419         }
00420 
00421         if (xml.isStartElement()) {
00422             if (xml.name() == "country") {
00423                 data.countryName = xml.readElementText();
00424             } else if (xml.name() == "province" || xml.name() == "territory") {
00425                 data.longTerritoryName = xml.readElementText();
00426             } else if (xml.name() == "name") {
00427                 data.cityName = xml.readElementText();
00428             } else if (xml.name() == "region") {
00429                 data.regionName = xml.readElementText();
00430             } else {
00431                 parseUnknownElement(xml);
00432             }
00433         }
00434     }
00435 }
00436 
00437 void EnvCanadaIon::parseWindInfo(WeatherData& data, QXmlStreamReader& xml)
00438 {
00439     Q_ASSERT(xml.isStartElement() && xml.name() == "wind");
00440 
00441     while (!xml.atEnd()) {
00442         xml.readNext();
00443 
00444         if (xml.isEndElement()) {
00445             break;
00446         }
00447 
00448         if (xml.isStartElement()) {
00449             if (xml.name() == "speed") {
00450                 data.windSpeed = xml.readElementText();
00451             } else if (xml.name() == "gust") {
00452                 data.windGust = xml.readElementText();
00453             } else if (xml.name() == "direction") {
00454                 data.windDirection = xml.readElementText();
00455             } else {
00456                 parseUnknownElement(xml);
00457             }
00458         }
00459     }
00460 }
00461 
00462 void EnvCanadaIon::parseConditions(WeatherData& data, QXmlStreamReader& xml)
00463 {
00464 
00465     Q_ASSERT(xml.isStartElement() && xml.name() == "currentConditions");
00466     data.temperature = "N/A";
00467     data.dewpoint = "N/A";
00468     data.condition = "N/A";
00469     data.comforttemp = "N/A";
00470     data.stationID = "N/A";
00471     data.pressure = 0.0;
00472     data.pressureTendency = "N/A";
00473     data.visibility = 0;
00474     data.humidity = "N/A";
00475     data.windSpeed = "N/A";
00476     data.windGust = "N/A";
00477 
00478     while (!xml.atEnd()) {
00479         xml.readNext();
00480 
00481         if (xml.isEndElement() && xml.name() == "currentConditions")
00482             break;
00483 
00484         if (xml.isStartElement()) {
00485             if (xml.name() == "station") {
00486                 data.stationID = xml.attributes().value("code").toString();
00487             } else if (xml.name() == "dateTime") {
00488                 parseDateTime(data, xml);
00489             } else if (xml.name() == "condition") {
00490                 data.condition = xml.readElementText();
00491             } else if (xml.name() == "temperature") {
00492                 data.temperature = xml.readElementText();;
00493             } else if (xml.name() == "dewpoint") {
00494                 data.dewpoint = xml.readElementText();
00495             } else if (xml.name() == "humidex" || xml.name() == "windChill") {
00496                 data.comforttemp = xml.readElementText();
00497             } else if (xml.name() == "pressure") {
00498                 data.pressureTendency = xml.attributes().value("tendency").toString();
00499                 if (data.pressureTendency.isEmpty()) {
00500                     data.pressureTendency = "steady";
00501                 }
00502                 data.pressure = xml.readElementText().toFloat();
00503             } else if (xml.name() == "visibility") {
00504                 data.visibility = xml.readElementText().toFloat();
00505             } else if (xml.name() == "relativeHumidity") {
00506                 data.humidity = xml.readElementText();
00507             } else if (xml.name() == "wind") {
00508                 parseWindInfo(data, xml);
00509             }
00510             //} else {
00511             //    parseUnknownElement(xml);
00512             //}
00513         }
00514     }
00515 }
00516 
00517 void EnvCanadaIon::parseWarnings(WeatherData &data, QXmlStreamReader& xml)
00518 {
00519     WeatherData::WarningInfo* warning = new WeatherData::WarningInfo;
00520 
00521     Q_ASSERT(xml.isStartElement() && xml.name() == "warnings");
00522     QString warningURL = xml.attributes().value("url").toString();
00523     while (!xml.atEnd()) {
00524         xml.readNext();
00525 
00526         if (xml.isEndElement() && xml.name() == "warnings") {
00527             break;
00528         }
00529 
00530         if (xml.isStartElement()) {
00531             if (xml.name() == "dateTime") {
00532                 parseDateTime(data, xml, warning);
00533                 if (!warning->timestamp.isEmpty() && !warning->url.isEmpty())  {
00534                     data.warnings.append(warning);
00535                     warning = new WeatherData::WarningInfo;
00536                 }
00537             } else if (xml.name() == "event") {
00538                 // Append new event to list.
00539                 warning->url = warningURL;
00540                 warning->type = xml.attributes().value("type").toString();
00541                 warning->priority = xml.attributes().value("priority").toString();
00542                 warning->description = xml.attributes().value("description").toString();
00543             } else {
00544                 if (xml.name() != "dateTime") {
00545                     parseUnknownElement(xml);
00546                 }
00547             }
00548         }
00549     }
00550     delete warning;
00551 }
00552 
00553 
00554 void EnvCanadaIon::parseWeatherForecast(WeatherData& data, QXmlStreamReader& xml)
00555 {
00556     WeatherData::ForecastInfo* forecast = new WeatherData::ForecastInfo;
00557     Q_ASSERT(xml.isStartElement() && xml.name() == "forecastGroup");
00558 
00559     while (!xml.atEnd()) {
00560         xml.readNext();
00561 
00562         if (xml.isEndElement() && xml.name() == "forecastGroup") {
00563             break;
00564         }
00565 
00566         if (xml.isStartElement()) {
00567             if (xml.name() == "dateTime") {
00568                 parseDateTime(data, xml);
00569             } else if (xml.name() == "regionalNormals") {
00570                 parseRegionalNormals(data, xml);
00571             } else if (xml.name() == "forecast") {
00572                 parseForecast(data, xml, forecast);
00573                 forecast = new WeatherData::ForecastInfo;
00574             } else {
00575                 parseUnknownElement(xml);
00576             }
00577         }
00578     }
00579     delete forecast;
00580 }
00581 
00582 void EnvCanadaIon::parseRegionalNormals(WeatherData& data, QXmlStreamReader& xml)
00583 {
00584     Q_ASSERT(xml.isStartElement() && xml.name() == "regionalNormals");
00585 
00586     while (!xml.atEnd()) {
00587         xml.readNext();
00588 
00589         if (xml.isEndElement()) {
00590             break;
00591         }
00592 
00593         if (xml.isStartElement()) {
00594             if (xml.name() == "textSummary") {
00595                 xml.readElementText();
00596             } else if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
00597                 data.normalHigh = xml.readElementText();
00598             } else if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
00599                 data.normalLow = xml.readElementText();
00600             }
00601         }
00602     }
00603 }
00604 
00605 void EnvCanadaIon::parseForecast(WeatherData& data, QXmlStreamReader& xml, WeatherData::ForecastInfo *forecast)
00606 {
00607 
00608     Q_ASSERT(xml.isStartElement() && xml.name() == "forecast");
00609 
00610     while (!xml.atEnd()) {
00611         xml.readNext();
00612 
00613         if (xml.isEndElement() && xml.name() == "forecast") {
00614             data.forecasts.append(forecast);
00615             break;
00616         }
00617 
00618         if (xml.isStartElement()) {
00619             if (xml.name() == "period") {
00620                 forecast->forecastPeriod = xml.readElementText();
00621             } else if (xml.name() == "textSummary") {
00622                 forecast->forecastSummary = xml.readElementText();
00623             } else if (xml.name() == "abbreviatedForecast") {
00624                 parseShortForecast(forecast, xml);
00625             } else if (xml.name() == "temperatures") {
00626                 parseForecastTemperatures(forecast, xml);
00627             } else if (xml.name() == "winds") {
00628                 parseWindForecast(forecast, xml);
00629             } else if (xml.name() == "precipitation") {
00630                 parsePrecipitationForecast(forecast, xml);
00631             } else if (xml.name() == "uv") {
00632                 data.UVRating = xml.attributes().value("category").toString();
00633                 parseUVIndex(data, xml);
00634                 // else if (xml.name() == "frost") { FIXME: Wait until winter to see what this looks like.
00635                 //  parseFrost(xml, forecast);
00636             } else {
00637                 if (xml.name() != "forecast") {
00638                     parseUnknownElement(xml);
00639                 }
00640             }
00641         }
00642     }
00643 }
00644 
00645 void EnvCanadaIon::parseShortForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
00646 {
00647     Q_ASSERT(xml.isStartElement() && xml.name() == "abbreviatedForecast");
00648 
00649     while (!xml.atEnd()) {
00650         xml.readNext();
00651 
00652         if (xml.isEndElement() && xml.name() == "abbreviatedForecast") {
00653             break;
00654         }
00655 
00656         if (xml.isStartElement()) {
00657             if (xml.name() == "pop") {
00658                 forecast->popPrecent = xml.readElementText();
00659             }
00660             if (xml.name() == "textSummary") {
00661                 forecast->shortForecast = xml.readElementText();
00662             }
00663         }
00664     }
00665 }
00666 
00667 void EnvCanadaIon::parseUVIndex(WeatherData& data, QXmlStreamReader& xml)
00668 {
00669     Q_ASSERT(xml.isStartElement() && xml.name() == "uv");
00670 
00671     while (!xml.atEnd()) {
00672         xml.readNext();
00673 
00674         if (xml.isEndElement() && xml.name() == "uv") {
00675             break;
00676         }
00677 
00678         if (xml.isStartElement()) {
00679             if (xml.name() == "index") {
00680                 data.UVIndex = xml.readElementText();
00681             }
00682             if (xml.name() == "textSummary") {
00683                 xml.readElementText();
00684             }
00685         }
00686     }
00687 }
00688 
00689 void EnvCanadaIon::parseForecastTemperatures(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
00690 {
00691     Q_ASSERT(xml.isStartElement() && xml.name() == "temperatures");
00692 
00693     while (!xml.atEnd()) {
00694         xml.readNext();
00695 
00696         if (xml.isEndElement() && xml.name() == "temperatures") {
00697             break;
00698         }
00699 
00700         if (xml.isStartElement()) {
00701             if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
00702                 forecast->forecastTempLow = xml.readElementText();
00703             } else if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
00704                 forecast->forecastTempHigh = xml.readElementText();
00705             } else if (xml.name() == "textSummary") {
00706                 xml.readElementText();
00707             }
00708         }
00709     }
00710 }
00711 
00712 void EnvCanadaIon::parsePrecipitationForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
00713 {
00714     Q_ASSERT(xml.isStartElement() && xml.name() == "precipitation");
00715 
00716     while (!xml.atEnd()) {
00717         xml.readNext();
00718 
00719         if (xml.isEndElement() && xml.name() == "precipitation") {
00720             break;
00721         }
00722 
00723         if (xml.isStartElement()) {
00724             //kDebug() << "parsePrecipitationForecast() ====> TAG: " << xml.name().toString();
00725             if (xml.name() == "textSummary") {
00726                 forecast->precipForecast = xml.readElementText();
00727             } else if (xml.name() == "precipType") {
00728                 forecast->precipType = xml.readElementText();
00729             } else if (xml.name() == "accumulation") {
00730                 parsePrecipTotals(forecast, xml);
00731             }
00732         }
00733     }
00734 }
00735 
00736 void EnvCanadaIon::parsePrecipTotals(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
00737 {
00738     Q_ASSERT(xml.isStartElement() && xml.name() == "accumulation");
00739 
00740     while (!xml.atEnd()) {
00741         xml.readNext();
00742 
00743         if (xml.isEndElement() && xml.name() == "accumulation") {
00744             break;
00745         }
00746 
00747         if (xml.name() == "name") {
00748             xml.readElementText();
00749         } else if (xml.name() == "amount") {
00750             forecast->precipTotalExpected = xml.readElementText();
00751         }
00752     }
00753 }
00754 
00755 void EnvCanadaIon::parseWindForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml)
00756 {
00757     Q_ASSERT(xml.isStartElement() && xml.name() == "winds");
00758 
00759     while (!xml.atEnd()) {
00760         xml.readNext();
00761 
00762         if (xml.isEndElement() && xml.name() == "winds") {
00763             break;
00764         }
00765 
00766         if (xml.isStartElement()) {
00767             if (xml.name() == "textSummary") {
00768                 forecast->windForecast = xml.readElementText();
00769             } else {
00770                 if (xml.name() != "winds") {
00771                     parseUnknownElement(xml);
00772                 }
00773             }
00774         }
00775     }
00776 }
00777 
00778 void EnvCanadaIon::parseYesterdayWeather(WeatherData& data, QXmlStreamReader& xml)
00779 {
00780     Q_ASSERT(xml.isStartElement() && xml.name() == "yesterdayConditions");
00781 
00782     while (!xml.atEnd()) {
00783         xml.readNext();
00784 
00785         if (xml.isEndElement()) {
00786             break;
00787         }
00788 
00789         if (xml.isStartElement()) {
00790             if (xml.name() == "temperature" && xml.attributes().value("class") == "high") {
00791                 data.prevHigh = xml.readElementText();
00792             } else if (xml.name() == "temperature" && xml.attributes().value("class") == "low") {
00793                 data.prevLow = xml.readElementText();
00794             } else if (xml.name() == "precip") {
00795                 data.prevPrecipType = xml.attributes().value("units").toString();
00796                 if (data.prevPrecipType.isEmpty()) {
00797                     data.prevPrecipType = "N/A";
00798                 }
00799                 data.prevPrecipTotal = xml.readElementText();
00800             }
00801         }
00802     }
00803 }
00804 
00805 void EnvCanadaIon::parseWeatherRecords(WeatherData& data, QXmlStreamReader& xml)
00806 {
00807     Q_ASSERT(xml.isStartElement() && xml.name() == "almanac");
00808 
00809     while (!xml.atEnd()) {
00810         xml.readNext();
00811 
00812         if (xml.isEndElement() && xml.name() == "almanac") {
00813             break;
00814         }
00815 
00816         if (xml.isStartElement()) {
00817             if (xml.name() == "temperature" && xml.attributes().value("class") == "extremeMax") {
00818                 data.recordHigh = xml.readElementText().toFloat();
00819             } else if (xml.name() == "temperature" && xml.attributes().value("class") == "extremeMin") {
00820                 data.recordLow = xml.readElementText().toFloat();
00821             } else if (xml.name() == "precipitation" && xml.attributes().value("class") == "extremeRainfall") {
00822                 data.recordRain = xml.readElementText().toFloat();
00823             } else if (xml.name() == "precipitation" && xml.attributes().value("class") == "extremeSnowfall") {
00824                 data.recordSnow = xml.readElementText().toFloat();
00825             }
00826         }
00827     }
00828 }
00829 
00830 void EnvCanadaIon::parseAstronomicals(WeatherData& data, QXmlStreamReader& xml)
00831 {
00832     Q_ASSERT(xml.isStartElement() && xml.name() == "riseSet");
00833 
00834     while (!xml.atEnd()) {
00835         xml.readNext();
00836 
00837         if (xml.isEndElement() && xml.name() == "riseSet") {
00838             break;
00839         }
00840 
00841         if (xml.isStartElement()) {
00842             if (xml.name() == "disclaimer") {
00843                 xml.readElementText();
00844             } else if (xml.name() == "dateTime") {
00845                 parseDateTime(data, xml);
00846             }
00847         }
00848     }
00849 }
00850 
00851 // handle when no XML tag is found
00852 void EnvCanadaIon::parseUnknownElement(QXmlStreamReader& xml)
00853 {
00854 
00855     while (!xml.atEnd()) {
00856         xml.readNext();
00857 
00858         if (xml.isEndElement()) {
00859             break;
00860         }
00861 
00862         if (xml.isStartElement()) {
00863             parseUnknownElement(xml);
00864         }
00865     }
00866 }
00867 
00868 void EnvCanadaIon::setMeasureUnit(const QString& unitType)
00869 {
00870     d->m_measureType = unitType.toInt();
00871 }
00872 
00873 void EnvCanadaIon::setTimezoneFormat(const QString& tz)
00874 {
00875     d->m_timezoneType = tz.toInt(); // Boolean
00876 }
00877 
00878 bool EnvCanadaIon::metricUnit()
00879 {
00880     if (d->m_measureType == KLocale::Metric) {
00881         return true;
00882     }
00883 
00884     // Imperial units
00885     return false;
00886 }
00887 
00888 bool EnvCanadaIon::timezone()
00889 {
00890     if (d->m_timezoneType) {
00891         return true;
00892     }
00893 
00894     // Not UTC, local time
00895     return false;
00896 }
00897 
00898 void EnvCanadaIon::updateWeather(const QString& source)
00899 {
00900     QMap<QString, QString> dataFields;
00901     QStringList fieldList;
00902     QVector<QString> forecastList;
00903     int i = 0;
00904 
00905     kDebug() << "updateWeather() BEGIN";
00906     setData(source, "Country", country(source));
00907     kDebug() << "SOURCE = " << source;
00908     setData(source, "Place", QString("%1, %2").arg(city(source)).arg(territory(source)));
00909     kDebug() << "KEEP GOING" << source;
00910     setData(source, "Region", region(source));
00911     setData(source, "Station", station(source));
00912 
00913     // Real weather - Current conditions
00914     setData(source, "Observation Period", observationTime(source));
00915     setData(source, "Current Conditions", condition(source));
00916     dataFields = temperature(source);
00917     setData(source, "Temperature", dataFields["temperature"]);
00918 
00919     // Do we have a comfort temperature? if so display it
00920     if (dataFields["comfortTemperature"] != "N/A" && !dataFields["comfortTemperature"].isEmpty()) {
00921         if (dataFields["comfortTemperature"].toFloat() <= 0 || (dataFields["comfortTemperature"].toFloat() <= 32 && !metricUnit())) {
00922             setData(source, "Windchill", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176)));
00923             setData(source, "Humidex", "N/A");
00924         } else {
00925             setData(source, "Humidex", QString("%1%2").arg(dataFields["comfortTemperature"]).arg(QChar(176)));
00926             setData(source, "Windchill", "N/A");
00927         }
00928     } else {
00929         setData(source, "Windchill", "N/A");
00930         setData(source, "Humidex", "N/A");
00931     }
00932 
00933     setData(source, "Temperature Unit", dataFields["temperatureUnit"]);
00934 
00935     setData(source, "Dewpoint", dewpoint(source));
00936     if (dewpoint(source) != "N/A") {
00937         setData(source, "Dewpoint Unit", dataFields["temperatureUnit"]);
00938     }
00939 
00940     dataFields = pressure(source);
00941     setData(source, "Pressure", dataFields["pressure"]);
00942 
00943     if (dataFields["pressure"] != "N/A") {
00944         setData(source, "Pressure Tendency", dataFields["pressureTendency"]);
00945         setData(source, "Pressure Unit", dataFields["pressureUnit"]);
00946     }
00947 
00948     dataFields = visibility(source);
00949     setData(source, "Visibility", dataFields["visibility"]);
00950     if (dataFields["visibility"] != "N/A") {
00951         setData(source, "Visibility Unit", dataFields["visibilityUnit"]);
00952     }
00953 
00954     setData(source, "Humidity", humidity(source));
00955 
00956     dataFields = wind(source);
00957     setData(source, "Wind Speed", dataFields["windSpeed"]);
00958     if (dataFields["windSpeed"] != "N/A") {
00959         setData(source, "Wind Speed Unit", dataFields["windUnit"]);
00960     }
00961     setData(source, "Wind Gust", dataFields["windGust"]);
00962     setData(source, "Wind Direction", dataFields["windDirection"]);
00963     setData(source, "Wind Gust Unit", dataFields["windGustUnit"]);
00964 
00965     dataFields = regionalTemperatures(source);
00966     setData(source, "Normal High", dataFields["normalHigh"]);
00967     setData(source, "Normal Low", dataFields["normalLow"]);
00968     if (dataFields["normalHigh"] != "N/A" && dataFields["normalLow"] != "N/A") {
00969         setData(source, "Regional Temperature Unit", dataFields["regionalTempUnit"]);
00970     }
00971 
00972     // Check if UV index is available for the location
00973     dataFields = uvIndex(source);
00974     setData(source, "UV Index", dataFields["uvIndex"]);
00975     if (dataFields["uvIndex"] != "N/A") {
00976         setData(source, "UV Rating", dataFields["uvRating"]);
00977     }
00978 
00979     dataFields = warnings(source);
00980     // Check if we have warnings or watches
00981 
00982     for (int i = 0; i < EnvCanadaIon::MAX_WARNINGS; i++) {
00983         if (!dataFields[QString("watch %1").arg(i)].isEmpty()) {
00984             fieldList = dataFields[QString("watch %1").arg(i)].split('|');
00985             setData(source, QString("Watch Priority %1").arg(i), fieldList[0]);
00986             setData(source, QString("Watch Description %1").arg(i), fieldList[1]);
00987             setData(source, QString("Watch Info %1").arg(i), fieldList[2]);
00988             setData(source, QString("Watch Timestamp %1").arg(i), fieldList[3]);
00989         }
00990         if (!dataFields[QString("warning %1").arg(i)].isEmpty()) {
00991             fieldList = dataFields[QString("warning %1").arg(i)].split('|');
00992             setData(source, QString("Warning Priority %1").arg(i), fieldList[0]);
00993             setData(source, QString("Warning Description %1").arg(i), fieldList[1]);
00994             setData(source, QString("Warning Info %1").arg(i), fieldList[2]);
00995             setData(source, QString("Warning Timestamp %1").arg(i), fieldList[3]);
00996         }
00997     }
00998 
00999     forecastList = forecasts(source);
01000     foreach(const QString &forecastItem, forecastList) {
01001         fieldList = forecastItem.split('|');
01002 
01003         // 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).
01004         if (metricUnit()) {
01005             setData(source, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5") \
01006                     .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[5]));
01007 
01008             setData(source, QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \
01009                     .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[6]) \
01010                     .arg(fieldList[7]).arg(fieldList[8]).arg(fieldList[9]));
01011         } else {
01012             setData(source, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5") \
01013                     .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[3] == "N/A" ? "N/A" : \
01014                             QString::number(WeatherFormula::celsiusToF(fieldList[3].toFloat()), 'd', 0)) \
01015                     .arg(fieldList[4] == "N/A" ? "N/A" : QString::number(WeatherFormula::celsiusToF(fieldList[4].toFloat()), 'd', 0)).arg(fieldList[5]));
01016 
01017             setData(source, QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \
01018                     .arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3] == "N/A" ? "N/A" : \
01019                             QString::number(WeatherFormula::celsiusToF(fieldList[3].toFloat()), 'd', 0)) \
01020                     .arg(fieldList[4] == "N/A" ? "N/A" : QString::number(WeatherFormula::celsiusToF(fieldList[4].toFloat()), 'd', 0)).arg(fieldList[6]).arg(fieldList[7]) \
01021                     .arg(fieldList[8]).arg(fieldList[9]));
01022         }
01023 
01024         i++;
01025     }
01026 
01027     dataFields = yesterdayWeather(source);
01028     setData(source, "Yesterday High", dataFields["prevHigh"]);
01029     setData(source, "Yesterday Low", dataFields["prevLow"]);
01030 
01031     if (dataFields["prevHigh"] != "N/A" && dataFields["prevLow"] != "N/A") {
01032         setData(source , "Yesterday Temperature Unit", dataFields["yesterdayTempUnit"]);
01033     }
01034 
01035     setData(source, "Yesterday Precip Total", dataFields["prevPrecip"]);
01036     setData(source, "Yesterday Precip Unit", dataFields["prevPrecipUnit"]);
01037 
01038     dataFields = sunriseSet(source);
01039     setData(source, "Sunrise At", dataFields["sunrise"]);
01040     setData(source, "Sunset At", dataFields["sunset"]);
01041 
01042     dataFields = moonriseSet(source);
01043     setData(source, "Moonrise At", dataFields["moonrise"]);
01044     setData(source, "Moonset At", dataFields["moonset"]);
01045 
01046     dataFields = weatherRecords(source);
01047     setData(source, "Record High Temperature", dataFields["recordHigh"]);
01048     setData(source, "Record Low Temperature", dataFields["recordLow"]);
01049     if (dataFields["recordHigh"] != "N/A" && dataFields["recordLow"] != "N/A") {
01050         setData(source, "Record Temperature Unit", dataFields["recordTempUnit"]);
01051     }
01052 
01053     setData(source, "Record Rainfall", dataFields["recordRain"]);
01054     setData(source, "Record Rainfall Unit", dataFields["recordRainUnit"]);
01055     setData(source, "Record Snowfall", dataFields["recordSnow"]);
01056     setData(source, "Record Snowfall Unit", dataFields["recordSnowUnit"]);
01057 
01058     setData(source, "Credit", "Meteorological data is provided by Environment Canada");
01059     kDebug() << "updateWeather FINISH Send it out!";
01060 }
01061 
01062 QString EnvCanadaIon::country(const QString& source)
01063 {
01064     return d->m_weatherData[source].countryName;
01065 }
01066 QString EnvCanadaIon::territory(const QString& source)
01067 {
01068     return d->m_weatherData[source].shortTerritoryName;
01069 }
01070 QString EnvCanadaIon::city(const QString& source)
01071 {
01072     return d->m_weatherData[source].cityName;
01073 }
01074 QString EnvCanadaIon::region(const QString& source)
01075 {
01076     return d->m_weatherData[source].regionName;
01077 }
01078 QString EnvCanadaIon::station(const QString& source)
01079 {
01080     if (!d->m_weatherData[source].stationID.isEmpty()) {
01081         return d->m_weatherData[source].stationID.toUpper();
01082     }
01083 
01084     return QString("N/A");
01085 }
01086 
01087 QString EnvCanadaIon::observationTime(const QString& source)
01088 {
01089     return d->m_weatherData[source].obsTimestamp;
01090 }
01091 QString EnvCanadaIon::condition(const QString& source)
01092 {
01093     if (d->m_weatherData[source].condition.isEmpty()) {
01094         d->m_weatherData[source].condition = "N/A";
01095     }
01096     return d->m_weatherData[source].condition;
01097 }
01098 
01099 QString EnvCanadaIon::dewpoint(const QString& source)
01100 {
01101     if (metricUnit()) {
01102         if (!d->m_weatherData[source].dewpoint.isEmpty()) {
01103             return QString::number(d->m_weatherData[source].dewpoint.toFloat(), 'f', 1);
01104         }
01105     }
01106 
01107     if (!d->m_weatherData[source].dewpoint.isEmpty()) {
01108         return QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].dewpoint.toFloat()), 'f', 1);
01109     }
01110 
01111     return QString("N/A");
01112 }
01113 
01114 QString EnvCanadaIon::humidity(const QString& source)
01115 {
01116     if (!d->m_weatherData[source].humidity.isEmpty()) {
01117         return QString("%1%").arg(d->m_weatherData[source].humidity);
01118     }
01119     return QString("N/A");
01120 }
01121 
01122 QMap<QString, QString> EnvCanadaIon::visibility(const QString& source)
01123 {
01124     QMap<QString, QString> visibilityInfo;
01125 
01126     if (!d->m_weatherData[source].visibility == 0) {
01127         if (metricUnit()) {
01128             visibilityInfo.insert("visibility", QString::number(d->m_weatherData[source].visibility, 'f', 1));
01129             visibilityInfo.insert("visibilityUnit", "km");
01130         } else {
01131             visibilityInfo.insert("visibility", QString::number(WeatherFormula::kilometersToMI(d->m_weatherData[source].visibility), 'f', 2));
01132             visibilityInfo.insert("visibilityUnit", "mi");
01133         }
01134     } else {
01135         visibilityInfo.insert("visibility", "N/A");
01136     }
01137     return visibilityInfo;
01138 }
01139 
01140 QMap<QString, QString> EnvCanadaIon::temperature(const QString& source)
01141 {
01142     QMap<QString, QString> temperatureInfo;
01143     if (metricUnit()) {
01144         if (!d->m_weatherData[source].temperature.isEmpty()) {
01145             temperatureInfo.insert("temperature", QString::number(d->m_weatherData[source].temperature.toFloat(), 'f', 1));
01146         }
01147         temperatureInfo.insert("temperatureUnit", QString("%1C").arg(QChar(176)));
01148     } else {
01149         if (!d->m_weatherData[source].temperature.isEmpty()) {
01150             temperatureInfo.insert("temperature", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].temperature.toFloat()), 'f', 1));
01151         } else {
01152             temperatureInfo.insert("temperature", "N/A");
01153         }
01154         temperatureInfo.insert("temperatureUnit", QString("%1F").arg(QChar(176)));
01155     }
01156     temperatureInfo.insert("comfortTemperature", "N/A");
01157 
01158     if (d->m_weatherData[source].comforttemp != "N/A") {
01159         if (metricUnit()) {
01160             temperatureInfo.insert("comfortTemperature", d->m_weatherData[source].comforttemp);
01161         } else {
01162             if (!d->m_weatherData[source].comforttemp.isEmpty()) {
01163                 temperatureInfo.insert("comfortTemperature", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].comforttemp.toFloat()), 'f', 1));
01164             }
01165         }
01166     }
01167     return temperatureInfo;
01168 }
01169 
01170 QMap<QString, QString> EnvCanadaIon::warnings(const QString& source)
01171 {
01172     QMap<QString, QString> warningData;
01173     QString warnType;
01174     for (int i = 0; i < d->m_weatherData[source].warnings.size(); ++i) {
01175         if (d->m_weatherData[source].warnings[i]->type == "watch") {
01176             warnType = QString("watch %1").arg(i);
01177         } else {
01178             warnType = QString("warning %1").arg(i);
01179         }
01180         warningData[warnType] = QString("%1|%2|%3|%4").arg(d->m_weatherData[source].warnings[i]->priority) \
01181                                 .arg(d->m_weatherData[source].warnings[i]->description) \
01182                                 .arg(d->m_weatherData[source].warnings[i]->url) \
01183                                 .arg(d->m_weatherData[source].warnings[i]->timestamp);
01184     }
01185     return warningData;
01186 }
01187 
01188 QVector<QString> EnvCanadaIon::forecasts(const QString& source)
01189 {
01190     QVector<QString> forecastData;
01191 
01192     // Do some checks for empty data
01193     for (int i = 0; i < d->m_weatherData[source].forecasts.size(); ++i) {
01194         if (d->m_weatherData[source].forecasts[i]->forecastPeriod.isEmpty()) {
01195             d->m_weatherData[source].forecasts[i]->forecastPeriod = "N/A";
01196         }
01197         if (d->m_weatherData[source].forecasts[i]->shortForecast.isEmpty()) {
01198             d->m_weatherData[source].forecasts[i]->shortForecast = "N/A";
01199         }
01200         if (d->m_weatherData[source].forecasts[i]->forecastSummary.isEmpty()) {
01201             d->m_weatherData[source].forecasts[i]->forecastSummary = "N/A";
01202         }
01203         if (d->m_weatherData[source].forecasts[i]->forecastTempHigh.isEmpty()) {
01204             d->m_weatherData[source].forecasts[i]->forecastTempHigh = "N/A";
01205         }
01206         if (d->m_weatherData[source].forecasts[i]->forecastTempLow.isEmpty()) {
01207             d->m_weatherData[source].forecasts[i]->forecastTempLow = "N/A";
01208         }
01209         if (d->m_weatherData[source].forecasts[i]->popPrecent.isEmpty()) {
01210             d->m_weatherData[source].forecasts[i]->popPrecent = "N/A";
01211         }
01212         if (d->m_weatherData[source].forecasts[i]->windForecast.isEmpty()) {
01213             d->m_weatherData[source].forecasts[i]->windForecast = "N/A";
01214         }
01215         if (d->m_weatherData[source].forecasts[i]->precipForecast.isEmpty()) {
01216             d->m_weatherData[source].forecasts[i]->precipForecast = "N/A";
01217         }
01218         if (d->m_weatherData[source].forecasts[i]->precipType.isEmpty()) {
01219             d->m_weatherData[source].forecasts[i]->precipType = "N/A";
01220         }
01221         if (d->m_weatherData[source].forecasts[i]->precipTotalExpected.isEmpty()) {
01222             d->m_weatherData[source].forecasts[i]->precipTotalExpected = "N/A";
01223         }
01224     }
01225 
01226     for (int i = 0; i < d->m_weatherData[source].forecasts.size(); ++i) {
01227         forecastData.append(QString("%1|%2|%3|%4|%5|%6|%7|%8|%9|%10") \
01228                             .arg(d->m_weatherData[source].forecasts[i]->forecastPeriod) \
01229                             .arg(d->m_weatherData[source].forecasts[i]->shortForecast) \
01230                             .arg(d->m_weatherData[source].forecasts[i]->forecastSummary) \
01231                             .arg(d->m_weatherData[source].forecasts[i]->forecastTempHigh) \
01232                             .arg(d->m_weatherData[source].forecasts[i]->forecastTempLow) \
01233                             .arg(d->m_weatherData[source].forecasts[i]->popPrecent) \
01234                             .arg(d->m_weatherData[source].forecasts[i]->windForecast) \
01235                             .arg(d->m_weatherData[source].forecasts[i]->precipForecast) \
01236                             .arg(d->m_weatherData[source].forecasts[i]->precipType) \
01237                             .arg(d->m_weatherData[source].forecasts[i]->precipTotalExpected));
01238     }
01239     return forecastData;
01240 }
01241 
01242 QMap<QString, QString> EnvCanadaIon::pressure(const QString& source)
01243 {
01244     QMap<QString, QString> pressureInfo;
01245 
01246     if (d->m_weatherData[source].pressure == 0) {
01247         pressureInfo.insert("pressure", "N/A");
01248         return pressureInfo;
01249     } else {
01250         if (metricUnit()) {
01251             pressureInfo.insert("pressure", QString::number(d->m_weatherData[source].pressure, 'f', 1));
01252             pressureInfo.insert("pressureUnit", "kPa");
01253         } else {
01254             pressureInfo.insert("pressure", QString::number(WeatherFormula::kilopascalsToInches(d->m_weatherData[source].pressure), 'f', 2));
01255             pressureInfo.insert("pressureUnit", "in");
01256         }
01257         pressureInfo.insert("pressureTendency", d->m_weatherData[source].pressureTendency);
01258     }
01259     return pressureInfo;
01260 }
01261 
01262 QMap<QString, QString> EnvCanadaIon::wind(const QString& source)
01263 {
01264     QMap<QString, QString> windInfo;
01265 
01266     // May not have any winds
01267     if (d->m_weatherData[source].windSpeed.isEmpty()) {
01268         windInfo.insert("windSpeed", "N/A");
01269         windInfo.insert("windUnit", "N/A");
01270     } else if (d->m_weatherData[source].windSpeed.toInt() == 0) {
01271         windInfo.insert("windSpeed", "Calm");
01272         windInfo.insert("windUnit", "N/A");
01273     } else {
01274         if (metricUnit()) {
01275                 windInfo.insert("windSpeed", QString::number(d->m_weatherData[source].windSpeed.toInt()));
01276                 windInfo.insert("windUnit", "km/h");
01277         } else {
01278                 windInfo.insert("windSpeed", QString::number(WeatherFormula::kilometersToMI(d->m_weatherData[source].windSpeed.toInt()), 'f', 1));
01279                 windInfo.insert("windUnit", "mph");
01280         }
01281     }
01282 
01283     // May not always have gusty winds
01284     if (d->m_weatherData[source].windGust.isEmpty()) {
01285         windInfo.insert("windGust", "N/A");
01286         windInfo.insert("windGustUnit", "N/A");
01287     } else {
01288         if (metricUnit()) {
01289                 windInfo.insert("windGust", QString::number(d->m_weatherData[source].windGust.toInt()));
01290                 windInfo.insert("windGustUnit", "km/h");
01291         } else {
01292                 windInfo.insert("windGust", QString::number(WeatherFormula::kilometersToMI(d->m_weatherData[source].windGust.toInt()), 'f', 1));
01293                 windInfo.insert("windGustUnit", "mph");
01294         }
01295     }
01296 
01297     if (d->m_weatherData[source].windDirection.isEmpty() && d->m_weatherData[source].windSpeed.isEmpty()) {
01298         windInfo.insert("windDirection", "N/A");
01299     } else if (d->m_weatherData[source].windSpeed.toInt() == 0) {
01300         windInfo.insert("windDirection", "VR");
01301     } else {
01302         windInfo.insert("windDirection", d->m_weatherData[source].windDirection);
01303     }
01304     return windInfo;
01305 }
01306 
01307 QMap<QString, QString> EnvCanadaIon::uvIndex(const QString& source)
01308 {
01309     QMap<QString, QString> uvInfo;
01310 
01311     if (d->m_weatherData[source].UVRating.isEmpty()) {
01312         uvInfo.insert("uvRating", "N/A");
01313     } else {
01314         uvInfo.insert("uvRating", d->m_weatherData[source].UVRating);
01315     }
01316 
01317     if (d->m_weatherData[source].UVIndex.isEmpty()) {
01318         uvInfo.insert("uvIndex", "N/A");
01319     } else {
01320         uvInfo.insert("uvIndex", d->m_weatherData[source].UVIndex);
01321     }
01322 
01323     return uvInfo;
01324 }
01325 
01326 QMap<QString, QString> EnvCanadaIon::regionalTemperatures(const QString& source)
01327 {
01328     QMap<QString, QString> regionalTempInfo;
01329 
01330     if (d->m_weatherData[source].normalHigh.isEmpty()) {
01331         regionalTempInfo.insert("normalHigh", "N/A");
01332     } else {
01333         if (metricUnit()) {
01334             regionalTempInfo.insert("normalHigh", d->m_weatherData[source].normalHigh);
01335         } else {
01336             regionalTempInfo.insert("normalHigh", QString("%1").arg(WeatherFormula::celsiusToF(d->m_weatherData[source].normalHigh.toFloat())));
01337         }
01338     }
01339 
01340     if (d->m_weatherData[source].normalLow.isEmpty()) {
01341         regionalTempInfo.insert("normalLow", "N/A");
01342     } else {
01343         if (metricUnit()) {
01344             regionalTempInfo.insert("normalLow", d->m_weatherData[source].normalLow);
01345         } else {
01346             regionalTempInfo.insert("normalLow", QString("%1").arg(WeatherFormula::celsiusToF(d->m_weatherData[source].normalLow.toFloat())));
01347         }
01348     }
01349 
01350     if (metricUnit()) {
01351         regionalTempInfo.insert("regionalTempUnit", QString("%1C").arg(QChar(176)));
01352     } else {
01353         regionalTempInfo.insert("regionalTempUnit", QString("%1F").arg(QChar(176)));
01354     }
01355 
01356     return regionalTempInfo;
01357 }
01358 
01359 QMap<QString, QString> EnvCanadaIon::yesterdayWeather(const QString& source)
01360 {
01361     QMap<QString, QString> yesterdayInfo;
01362 
01363     if (d->m_weatherData[source].prevHigh.isEmpty()) {
01364         yesterdayInfo.insert("prevHigh", "N/A");
01365     } else {
01366         if (metricUnit()) {
01367             yesterdayInfo.insert("prevHigh", d->m_weatherData[source].prevHigh);
01368         } else {
01369             yesterdayInfo.insert("prevHigh", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].prevHigh.toFloat())));
01370         }
01371     }
01372 
01373     if (d->m_weatherData[source].prevLow.isEmpty()) {
01374         yesterdayInfo.insert("prevLow", "N/A");
01375     } else {
01376         if (metricUnit()) {
01377             yesterdayInfo.insert("prevLow", d->m_weatherData[source].prevLow);
01378         } else {
01379             yesterdayInfo.insert("prevLow", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].prevLow.toFloat()), 'f', 1));
01380         }
01381     }
01382 
01383     if (metricUnit()) {
01384         yesterdayInfo.insert("yesterdayTempUnit", QString("%1C").arg(QChar(176)));
01385     } else {
01386         yesterdayInfo.insert("yesterdayTempUnit", QString("%1F").arg(QChar(176)));
01387     }
01388 
01389     if (d->m_weatherData[source].prevPrecipTotal == "Trace") {
01390         yesterdayInfo.insert("prevPrecip", "Trace");
01391         return yesterdayInfo;
01392     }
01393 
01394     if (d->m_weatherData[source].prevPrecipTotal.isEmpty()) {
01395         yesterdayInfo.insert("prevPrecip", "N/A");
01396     } else {
01397         if (metricUnit()) {
01398             yesterdayInfo.insert("prevPrecipTotal", d->m_weatherData[source].prevPrecipTotal);
01399             yesterdayInfo.insert("prevPrecipUnit", d->m_weatherData[source].prevPrecipType);
01400         } else {
01401             yesterdayInfo.insert("prevPrecipTotal", QString::number(WeatherFormula::millimetersToIN(d->m_weatherData[source].prevPrecipTotal.toFloat()), 'f', 1));
01402             yesterdayInfo.insert("prevPrecipUnit", QString("in"));
01403         }
01404     }
01405 
01406     return yesterdayInfo;
01407 }
01408 
01409 QMap<QString, QString> EnvCanadaIon::sunriseSet(const QString& source)
01410 {
01411     QMap<QString, QString> sunInfo;
01412 
01413     if (d->m_weatherData[source].sunriseTimestamp.isEmpty()) {
01414         sunInfo.insert("sunrise", "N/A");
01415     } else {
01416         sunInfo.insert("sunrise", d->m_weatherData[source].sunriseTimestamp);
01417     }
01418 
01419     if (d->m_weatherData[source].sunsetTimestamp.isEmpty()) {
01420         sunInfo.insert("sunset", "N/A");
01421     } else {
01422         sunInfo.insert("sunset", d->m_weatherData[source].sunsetTimestamp);
01423     }
01424 
01425     return sunInfo;
01426 }
01427 
01428 QMap<QString, QString> EnvCanadaIon::moonriseSet(const QString& source)
01429 {
01430     QMap<QString, QString> moonInfo;
01431 
01432     if (d->m_weatherData[source].moonriseTimestamp.isEmpty()) {
01433         moonInfo.insert("moonrise", "N/A");
01434     } else {
01435         moonInfo.insert("moonrise", d->m_weatherData[source].moonriseTimestamp);
01436     }
01437 
01438     if (d->m_weatherData[source].moonsetTimestamp.isEmpty()) {
01439         moonInfo.insert("moonset", "N/A");
01440     } else {
01441         moonInfo.insert("moonset", d->m_weatherData[source].moonsetTimestamp);
01442     }
01443 
01444     return moonInfo;
01445 }
01446 
01447 QMap<QString, QString> EnvCanadaIon::weatherRecords(const QString& source)
01448 {
01449     QMap<QString, QString> recordInfo;
01450 
01451     if (d->m_weatherData[source].recordHigh == 0) {
01452         recordInfo.insert("recordHigh", "N/A");
01453     } else {
01454         if (metricUnit()) {
01455             recordInfo.insert("recordHigh", QString("%1").arg(d->m_weatherData[source].recordHigh));
01456         } else {
01457             recordInfo.insert("recordHigh", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].recordHigh), 'f', 1));
01458         }
01459     }
01460 
01461     if (d->m_weatherData[source].recordLow == 0) {
01462         recordInfo.insert("recordLow", "N/A");
01463     } else {
01464         if (metricUnit()) {
01465             recordInfo.insert("recordLow", QString("%1").arg(d->m_weatherData[source].recordLow));
01466         } else {
01467             recordInfo.insert("recordLow", QString::number(WeatherFormula::celsiusToF(d->m_weatherData[source].recordLow), 'f', 1));
01468         }
01469 
01470     }
01471 
01472     if (metricUnit()) {
01473         recordInfo.insert("recordTempUnit", QString("%1C").arg(QChar(176)));
01474     } else {
01475         recordInfo.insert("recordTempUnit", QString("%1F").arg(QChar(176)));
01476     }
01477 
01478     if (d->m_weatherData[source].recordRain == 0) {
01479         recordInfo.insert("recordRain", "N/A");
01480     } else {
01481         if (metricUnit()) {
01482             recordInfo.insert("recordRain", QString("%1").arg(d->m_weatherData[source].recordRain));
01483             recordInfo.insert("recordRainUnit", QString("mm"));
01484         } else {
01485             recordInfo.insert("recordRain", QString::number(WeatherFormula::millimetersToIN(d->m_weatherData[source].recordRain), 'f', 1));
01486             recordInfo.insert("recordRainUnit", QString("in"));
01487         }
01488     }
01489 
01490     if (d->m_weatherData[source].recordSnow == 0) {
01491         recordInfo.insert("recordSnow", "N/A");
01492     } else {
01493         if (metricUnit()) {
01494             recordInfo.insert("recordSnow", QString("%1").arg(d->m_weatherData[source].recordSnow));
01495             recordInfo.insert("recordSnowUnit", QString("cm"));
01496         } else {
01497             recordInfo.insert("recordSnow", QString::number(WeatherFormula::centimetersToIN(d->m_weatherData[source].recordSnow), 'f', 1));
01498             recordInfo.insert("recordSnowUnit", QString("in"));
01499         }
01500     }
01501 
01502     return recordInfo;
01503 }
01504 
01505 #include "ion_envcan.moc"

Engines

Skip menu "Engines"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

API Reference

Skip menu "API Reference"
  • KWin
  •   KWin Libraries
  • Libraries
  •   libkworkspace
  •   libplasma
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal