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

Engines

ion_bbcukmet.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002  *   Copyright (C) 2007-2008 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 BBC's Weather from the UK Met Office */
00021 
00022 #include "ion_bbcukmet.h"
00023 
00024 class UKMETIon::Private : public QObject
00025 {
00026 public:
00027     Private() {
00028         m_url = 0;
00029     }
00030     ~Private() {
00031         delete m_url;
00032     }
00033 
00034 private:
00035     struct XMLMapInfo {
00036         QString place;
00037         QString XMLurl;
00038         QString XMLforecastURL;
00039         bool ukPlace;
00040         QString sourceOptions;
00041     };
00042 
00043 public:
00044     // Key dicts
00045     QHash<QString, UKMETIon::Private::XMLMapInfo> m_place;
00046     QVector<QString> m_locations;
00047     QStringList m_matchLocations;
00048 
00049 public:
00050     // Weather information
00051     QHash<QString, WeatherData> m_weatherData;
00052 
00053     // Store KIO jobs - Search list
00054     QMap<KJob *, QXmlStreamReader*> m_jobXml;
00055     QMap<KJob *, QString> m_jobList;
00056 
00057     QMap<KJob *, QXmlStreamReader*> m_obsJobXml;
00058     QMap<KJob *, QString> m_obsJobList;
00059 
00060     QMap<KJob *, QXmlStreamReader *> m_forecastJobXml;
00061     QMap<KJob *, QString> m_forecastJobList;
00062 
00063     KUrl *m_url;
00064     KIO::TransferJob *m_job;
00065 
00066     QDateTime m_dateFormat;
00067 };
00068 
00069 
00070 // ctor, dtor
00071 UKMETIon::UKMETIon(QObject *parent, const QVariantList &args)
00072         : IonInterface(parent, args), d(new Private())
00073 
00074 {
00075     Q_UNUSED(args)
00076 }
00077 
00078 UKMETIon::~UKMETIon()
00079 {
00080     // Destroy each forecast stored in a QVector
00081     foreach(const WeatherData &item, d->m_weatherData) {
00082         foreach(WeatherData::ForecastInfo *forecast, item.forecasts) {
00083             if (forecast) {
00084                 delete forecast;
00085             }
00086         }
00087     }
00088 
00089     // Destroy dptr
00090     delete d;
00091 }
00092 
00093 // Get the master list of locations to be parsed
00094 void UKMETIon::init()
00095 {
00096     setInitialized(true);
00097 }
00098 
00099 QMap<QString, IonInterface::ConditionIcons> UKMETIon::setupDayIconMappings(void)
00100 {
00101 //    ClearDay, FewCloudsDay, PartlyCloudyDay, Overcast,
00102 //    Showers, ScatteredShowers, Thunderstorm, Snow,
00103 //    FewCloudsNight, PartlyCloudyNight, ClearNight,
00104 //    Mist, NotAvailable
00105 
00106     QMap<QString, ConditionIcons> dayList;
00107     dayList["sunny"] = ClearDay;
00108     //dayList["sunny night"] = ClearNight;
00109     dayList["clear"] = ClearDay;
00110     dayList["sunny intervals"] = PartlyCloudyDay;
00111     //dayList["sunny intervals night"] = ClearNight;
00112     dayList["partly cloudy"] = PartlyCloudyDay;
00113     dayList["cloudy"] = Overcast;
00114     //dayList["low level cloud"] = NotAvailable;
00115     //dayList["medium level cloud"] = NotAvailable;
00116     //dayList["sandstorm"] = NotAvailable;
00117     dayList["drizzle"] = LightRain;
00118     dayList["misty"] = Mist;
00119     dayList["mist"] = Mist;
00120     dayList["fog"] = Mist;
00121     dayList["foggy"] = Mist;
00122     dayList["tropical storm"] = Thunderstorm;
00123     dayList["hazy"] = NotAvailable;
00124     dayList["light shower"] = Showers;
00125     dayList["light rain shower"] = Showers;
00126     dayList["light showers"] = Showers;
00127     dayList["light rain"] = Showers;
00128     dayList["heavy rain"] = Rain;
00129     dayList["heavy showers"] = Rain;
00130     dayList["heavy shower"] = Rain;
00131     dayList["thundery shower"] = Thunderstorm;
00132     dayList["thunderstorm"] = Thunderstorm;
00133     dayList["cloudy with sleet"] = RainSnow;
00134     dayList["sleet shower"] = RainSnow;
00135     dayList["sleet showers"] = RainSnow;
00136     dayList["sleet"] = RainSnow;
00137     dayList["cloudy with hail"] = Hail;
00138     dayList["hail shower"] = Hail;
00139     dayList["hail showers"] = Hail;
00140     dayList["hail"] = Hail;
00141     dayList["light snow"] = LightSnow;
00142     dayList["light snow shower"] = Flurries;
00143     dayList["light snow showers"] = Flurries;
00144     dayList["cloudy with light snow"] = LightSnow;
00145     dayList["heavy snow"] = Snow;
00146     dayList["heavy snow shower"] = Snow;
00147     dayList["heavy snow showers"] = Snow;
00148     dayList["cloudy with heavy snow"] = Snow;
00149     dayList["na"] = NotAvailable;
00150     return dayList;
00151 }
00152 
00153 QMap<QString, IonInterface::ConditionIcons> UKMETIon::setupNightIconMappings(void)
00154 {
00155     QMap<QString, ConditionIcons> nightList;
00156     nightList["clear"] = ClearNight;
00157     nightList["clear intervals"] = PartlyCloudyNight;
00158     nightList["sunny intervals"] = PartlyCloudyDay; // it's not really sunny
00159     nightList["sunny"] = ClearDay;
00160     nightList["cloudy"] = Overcast;
00161     nightList["partly cloudy"] = PartlyCloudyNight;
00162     nightList["drizzle"] = LightRain;
00163     nightList["misty"] = Mist;
00164     nightList["mist"] = Mist;
00165     nightList["fog"] = Mist;
00166     nightList["foggy"] = Mist;
00167     nightList["tropical storm"] = Thunderstorm;
00168     nightList["hazy"] = NotAvailable;
00169     nightList["light shower"] = Showers;
00170     nightList["light rain shower"] = Showers;
00171     nightList["light showers"] = Showers;
00172     nightList["light rain"] = Showers;
00173     nightList["heavy rain"] = Rain;
00174     nightList["heavy showers"] = Rain;
00175     nightList["heavy shower"] = Rain;
00176     nightList["thundery shower"] = Thunderstorm;
00177     nightList["thunderstorm"] = Thunderstorm;
00178     nightList["cloudy with sleet"] = NotAvailable;
00179     nightList["sleet shower"] = NotAvailable;
00180     nightList["sleet showers"] = NotAvailable;
00181     nightList["sleet"] = NotAvailable;
00182     nightList["cloudy with hail"] = Hail;
00183     nightList["hail shower"] = Hail;
00184     nightList["hail showers"] = Hail;
00185     nightList["hail"] = Hail;
00186     nightList["light snow"] = LightSnow;
00187     nightList["light snow shower"] = Flurries;
00188     nightList["light snow showers"] = Flurries;
00189     nightList["cloudy with light snow"] = LightSnow;
00190     nightList["heavy snow"] = Snow;
00191     nightList["heavy snow shower"] = Snow;
00192     nightList["heavy snow showers"] = Snow;
00193     nightList["cloudy with heavy snow"] = Snow;
00194     nightList["na"] = NotAvailable;
00195 
00196     return nightList;
00197 }
00198 
00199 QMap<QString, IonInterface::ConditionIcons> const& UKMETIon::dayIcons(void)
00200 {
00201     static QMap<QString, ConditionIcons> const dval = setupDayIconMappings();
00202     return dval;
00203 }
00204 
00205 QMap<QString, IonInterface::ConditionIcons> const& UKMETIon::nightIcons(void)
00206 {
00207     static QMap<QString, ConditionIcons> const nval = setupNightIconMappings();
00208     return nval;
00209 }
00210 
00211 // Get a specific Ion's data
00212 bool UKMETIon::updateIonSource(const QString& source)
00213 {
00214     // We expect the applet to send the source in the following tokenization:
00215     // ionname|validate|place_name - Triggers validation of place
00216     // ionname|weather|place_name - Triggers receiving weather of place
00217 
00218     QStringList sourceAction = source.split('|');
00219 
00220     if (sourceAction[1] == QString("validate")) {
00221         // Look for places to match
00222         findPlace(sourceAction[2], source);
00223         return true;
00224 
00225     } else if (sourceAction[1] == QString("weather")) {
00226         if (sourceAction.count() >= 3) {
00227             d->m_place[QString("bbcukmet|%1").arg(sourceAction[2])].XMLurl = sourceAction[3];
00228             getXMLData(QString("%1|%2").arg(sourceAction[0]).arg(sourceAction[2]));
00229             return true;
00230         } else {
00231             return false;
00232         }
00233     }
00234     return false;
00235 }
00236 
00237 // Gets specific city XML data
00238 void UKMETIon::getXMLData(const QString& source)
00239 {
00240     KUrl url;
00241     url = d->m_place[source].XMLurl;
00242 
00243     d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
00244     d->m_job->addMetaData("cookies", "none"); // Disable displaying cookies
00245     d->m_obsJobXml.insert(d->m_job, new QXmlStreamReader);
00246     d->m_obsJobList.insert(d->m_job, source);
00247 
00248     if (d->m_job) {
00249         connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
00250                 SLOT(observation_slotDataArrived(KIO::Job *, const QByteArray &)));
00251         connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(observation_slotJobFinished(KJob *)));
00252     }
00253 }
00254 
00255 // Parses city list and gets the correct city based on ID number
00256 void UKMETIon::findPlace(const QString& place, const QString& source)
00257 {
00258     KUrl url;
00259     url = "http://www.bbc.co.uk/cgi-perl/weather/search/new_search.pl?x=0&y=0&=Submit&search_query=" + place + "&tmpl=wap";
00260 
00261     d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
00262     d->m_job->addMetaData("cookies", "none"); // Disable displaying cookies
00263     d->m_jobXml.insert(d->m_job, new QXmlStreamReader);
00264     d->m_jobList.insert(d->m_job, source);
00265 
00266     if (d->m_job) {
00267         connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
00268                 SLOT(setup_slotDataArrived(KIO::Job *, const QByteArray &)));
00269         connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(setup_slotJobFinished(KJob *)));
00270 
00271         // Handle redirects for direct hit places.
00272         connect(d->m_job, SIGNAL(redirection(KIO::Job *, const KUrl &)), this,
00273                 SLOT(setup_slotRedirected(KIO::Job *, const KUrl &)));
00274     }
00275 }
00276 
00277 void UKMETIon::getFiveDayForecast(const QString& source)
00278 {
00279     KUrl url;
00280     url = d->m_place[source].XMLforecastURL;
00281     QString xmlMap = d->m_place[source].XMLforecastURL;
00282     xmlMap.replace("weather/5day.shtml", "weather/mobile/5day.wml");
00283     url = xmlMap;
00284 
00285     d->m_job = KIO::get(url.url(), KIO::Reload, KIO::HideProgressInfo);
00286     d->m_job->addMetaData("cookies", "none"); // Disable displaying cookies
00287     d->m_forecastJobXml.insert(d->m_job, new QXmlStreamReader);
00288     d->m_forecastJobList.insert(d->m_job, source);
00289 
00290     if (d->m_job) {
00291         connect(d->m_job, SIGNAL(data(KIO::Job *, const QByteArray &)), this,
00292                 SLOT(forecast_slotDataArrived(KIO::Job *, const QByteArray &)));
00293         connect(d->m_job, SIGNAL(result(KJob *)), this, SLOT(forecast_slotJobFinished(KJob *)));
00294     }
00295 }
00296 
00297 bool UKMETIon::readSearchXMLData(const QString& key, QXmlStreamReader& xml)
00298 {
00299 
00300     while (!xml.atEnd()) {
00301         xml.readNext();
00302 
00303         if (xml.isEndElement()) {
00304             break;
00305         }
00306 
00307         if (xml.isStartElement()) {
00308             if (xml.name() == "wml") {
00309                 parseSearchLocations(key, xml);
00310             } else {
00311                 parseUnknownElement(xml);
00312             }
00313         }
00314     }
00315 
00316     return !xml.error();
00317 }
00318 
00319 void UKMETIon::parseSearchLocations(const QString& source, QXmlStreamReader& xml)
00320 {
00321     int flag = 0;
00322     QString url;
00323     QString place;
00324     QStringList tokens;
00325     QString tmp;
00326     int counter = 2;
00327     int currentParagraph = 0;
00328 
00329     Q_ASSERT(xml.isStartElement() && xml.name() == "wml");
00330 
00331     while (!xml.atEnd()) {
00332         xml.readNext();
00333 
00334         if (xml.isEndElement() && xml.name() == "wml") {
00335             break;
00336         }
00337 
00338         if (xml.isStartElement() && xml.name() == "p") {
00339             currentParagraph++;
00340         }
00341 
00342         if (currentParagraph == 2) {
00343             if (xml.isCharacters() && !xml.isWhitespace())  {
00344                 QString dataText = xml.text().toString().trimmed();
00345                 if (dataText.contains("No locations")) {
00346                     break;
00347                 }
00348             }
00349         }
00350 
00351         if (xml.isStartElement()) {
00352             if (xml.name() == "a" && !xml.attributes().value("href").isEmpty()) {
00353                 if (xml.attributes().value("href").toString().contains("5day.wml")) {
00354 
00355                     // Split URL to determine station ID number
00356                     tokens = xml.attributes().value("href").toString().split('=');
00357                     if (xml.attributes().value("href").toString().contains("world")) {
00358                         url = "http://feeds.bbc.co.uk/weather/feeds/obs/world/" + tokens[1] + ".xml";
00359                         flag = 0;
00360                     } else {
00361                         url = "http://feeds.bbc.co.uk/weather/feeds/obs/id/" + tokens[1] + ".xml";
00362                         flag = 1;
00363                     }
00364                     place = xml.readElementText();
00365                     tmp = QString("bbcukmet|%1").arg(place);
00366 
00367                     // Duplicate places can exist
00368                     if (d->m_locations.contains(tmp)) {
00369 
00370                         QString dupePlace = place;
00371                         tmp = QString("bbcukmet|%1").arg(QString("%1 (#%2)").arg(dupePlace).arg(counter));
00372                         place = QString("%1 (#%2)").arg(dupePlace).arg(counter);
00373                         counter++;
00374                     }
00375 
00376                     if (flag) {  // This is a UK specific location
00377                         d->m_place[tmp].XMLurl = url;
00378                         d->m_place[tmp].place = place;
00379                         d->m_place[tmp].ukPlace = true;
00380                     } else {
00381                         d->m_place[tmp].XMLurl = url;
00382                         d->m_place[tmp].place = place;
00383                         d->m_place[tmp].ukPlace = false;
00384                     }
00385                     d->m_locations.append(tmp);
00386                 }
00387             }
00388         }
00389     }
00390     validate(source);
00391 }
00392 
00393 // handle when no XML tag is found
00394 void UKMETIon::parseUnknownElement(QXmlStreamReader& xml)
00395 {
00396     while (!xml.atEnd()) {
00397         xml.readNext();
00398 
00399         if (xml.isEndElement()) {
00400             break;
00401         }
00402 
00403         if (xml.isStartElement()) {
00404             parseUnknownElement(xml);
00405         }
00406     }
00407 }
00408 
00409 void UKMETIon::setup_slotRedirected(KIO::Job *job, const KUrl &url)
00410 {
00411     QString obsUrl;
00412     QString place;
00413     QString tmp;
00414     bool flag = false;
00415     QStringList tokens = url.url().split('=');
00416     if (url.url().contains("xhtml")) { // We don't care about the first redirection (there is two)
00417         if (url.url().contains("world")) {
00418             obsUrl = "http://feeds.bbc.co.uk/weather/feeds/obs/world/" + tokens[2] + ".xml";
00419             flag = false;
00420         } else {
00421             obsUrl = "http://feeds.bbc.co.uk/weather/feeds/obs/id/" + tokens[2] + ".xml";
00422             flag = true;
00423         }
00424         place = d->m_jobList[job].split('|')[2]; // Contains the source name (place in this case)
00425         tmp = QString("bbcukmet|%1").arg(place);
00426         place[0] = place[0].toUpper();
00427 
00428         if (flag) { // This is a UK specific location
00429             d->m_place[tmp].XMLurl = obsUrl;
00430             d->m_place[tmp].place = place;
00431             d->m_place[tmp].ukPlace = true;
00432         } else {
00433             d->m_place[tmp].XMLurl = obsUrl;
00434             d->m_place[tmp].place = place;
00435             d->m_place[tmp].ukPlace = false;
00436         }
00437         d->m_locations.append(tmp);
00438         validate(d->m_jobList[job]);
00439     }
00440 }
00441 
00442 void UKMETIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data)
00443 {
00444     QByteArray local = data;
00445     if (data.isEmpty() || !d->m_jobXml.contains(job)) {
00446         return;
00447     }
00448 
00449     // XXX: BBC doesn't convert unicode strings so this breaks XML formatting. Not pretty.
00450     if (local.startsWith("<?xml version")) {
00451         local.replace("<?xml version=\"1.0\"?>", "<?xml version=\"1.0\" encoding=\"cp1252\" ?>");
00452     }
00453 
00454     // Send to xml.
00455     d->m_jobXml[job]->addData(local);
00456 }
00457 
00458 void UKMETIon::setup_slotJobFinished(KJob *job)
00459 {
00460     if (job->error() == 149) {
00461         setData(d->m_jobList[job], "validate", QString("bbcukmet|timeout"));
00462         disconnectSource(d->m_jobList[job], this);
00463         d->m_jobList.remove(job);
00464         delete d->m_jobXml[job];
00465         d->m_jobXml.remove(job);
00466         return;
00467     }
00468     // If Redirected, don't go to this routine
00469     if (!d->m_locations.contains(QString("bbcukmet|%1").arg(d->m_jobList[job]))) {
00470         readSearchXMLData(d->m_jobList[job], *d->m_jobXml[job]);
00471     }
00472     d->m_jobList.remove(job);
00473     delete d->m_jobXml[job];
00474     d->m_jobXml.remove(job);
00475 }
00476 
00477 void UKMETIon::observation_slotDataArrived(KIO::Job *job, const QByteArray &data)
00478 {
00479     QByteArray local = data;
00480     if (data.isEmpty() || !d->m_obsJobXml.contains(job)) {
00481         return;
00482     }
00483 
00484     // XXX: I don't know what to say about this. But horrible. We can't really do much about this :/
00485     // No, it's not UTF-8, it really lies.
00486     if (local.startsWith("<?xml version")) {
00487         local.replace("encoding=\"UTF-8\"?>", "encoding=\"cp1252\" ?>");
00488     }
00489 
00490     // Send to xml.
00491     d->m_obsJobXml[job]->addData(local);
00492 }
00493 
00494 void UKMETIon::observation_slotJobFinished(KJob *job)
00495 {
00496     setData(d->m_obsJobList[job], Data());
00497     readObservationXMLData(d->m_obsJobList[job], *d->m_obsJobXml[job]);
00498     d->m_obsJobList.remove(job);
00499     delete d->m_obsJobXml[job];
00500     d->m_obsJobXml.remove(job);
00501 }
00502 
00503 void UKMETIon::forecast_slotDataArrived(KIO::Job *job, const QByteArray &data)
00504 {
00505     QByteArray local = data;
00506     if (data.isEmpty() || !d->m_forecastJobXml.contains(job)) {
00507         return;
00508     }
00509 
00510     // XXX: BBC doesn't convert unicode strings so this breaks XML formatting. Not pretty.
00511     // No, it's not UTF-8, it really lies.
00512     if (local.startsWith("<?xml version")) {
00513         local.replace("<?xml version=\"1.0\"?>", "<?xml version=\"1.0\" encoding=\"cp1252\" ?>");
00514     }
00515     // Send to xml.
00516     d->m_forecastJobXml[job]->addData(local);
00517 }
00518 
00519 void UKMETIon::forecast_slotJobFinished(KJob *job)
00520 {
00521     setData(d->m_forecastJobList[job], Data());
00522     readFiveDayForecastXMLData(d->m_forecastJobList[job], *d->m_forecastJobXml[job]);
00523     d->m_forecastJobList.remove(job);
00524     delete d->m_forecastJobXml[job];
00525     d->m_forecastJobXml.remove(job);
00526 }
00527 
00528 void UKMETIon::parsePlaceObservation(const QString &source, WeatherData& data, QXmlStreamReader& xml)
00529 {
00530     Q_ASSERT(xml.isStartElement() && xml.name() == "rss");
00531 
00532     while (!xml.atEnd()) {
00533         xml.readNext();
00534 
00535         if (xml.isEndElement() && xml.name() == "rss") {
00536             break;
00537         }
00538 
00539         if (xml.isStartElement()) {
00540             if (xml.name() == "channel") {
00541                 parseWeatherChannel(source, data, xml);
00542             }
00543         }
00544     }
00545 }
00546 
00547 void UKMETIon::parseWeatherChannel(const QString& source, WeatherData& data, QXmlStreamReader& xml)
00548 {
00549     Q_ASSERT(xml.isStartElement() && xml.name() == "channel");
00550 
00551     while (!xml.atEnd()) {
00552         xml.readNext();
00553 
00554         if (xml.isEndElement() && xml.name() == "channel") {
00555             break;
00556         }
00557 
00558         if (xml.isStartElement()) {
00559             if (xml.name() == "title") {
00560                 data.stationName = xml.readElementText().split("Observations for")[1].trimmed();
00561 
00562                 data.stationName.replace("United Kingdom", "UK");
00563                 data.stationName.replace("United States of America", "USA");
00564 
00565             } else if (xml.name() == "item") {
00566                 parseWeatherObservation(source, data, xml);
00567             } else {
00568                 parseUnknownElement(xml);
00569             }
00570         }
00571     }
00572 }
00573 
00574 void UKMETIon::parseWeatherObservation(const QString& source, WeatherData& data, QXmlStreamReader& xml)
00575 {
00576     Q_UNUSED(data)
00577     Q_ASSERT(xml.isStartElement() && xml.name() == "item");
00578 
00579     while (!xml.atEnd()) {
00580         xml.readNext();
00581 
00582         if (xml.isEndElement() && xml.name() == "item") {
00583             break;
00584         }
00585 
00586         if (xml.isStartElement()) {
00587             if (xml.name() == "title") {
00588                 QString conditionString = xml.readElementText();
00589 
00590                 // Get the observation time.
00591                 QStringList conditionData = conditionString.split(':');
00592 
00593                 data.obsTime = conditionData[0];
00594                 // Friday at 0200 GMT
00595                 d->m_dateFormat =  QDateTime::fromString(data.obsTime.split("at")[1].trimmed(), "hhmm 'GMT'");
00596                 data.iconPeriodHour = d->m_dateFormat.toString("HH").toInt();
00597                 //data.iconPeriodAP = d->m_dateFormat.toString("ap");
00598 
00599                 data.condition = conditionData[1].split('.')[0].trimmed();
00600 
00601             } else if (xml.name() == "link") {
00602                 d->m_place[source].XMLforecastURL = xml.readElementText();
00603             } else if (xml.name() == "description") {
00604                 QString observeString = xml.readElementText();
00605                 QStringList observeData = observeString.split(':');
00606 
00607                 data.temperature_C = observeData[1].split(QChar(176))[0].trimmed();
00608                 data.temperature_F = observeData[1].split('(')[1].split(QChar(176))[0];
00609 
00610                 data.windDirection = observeData[2].split(',')[0].trimmed();
00611                 data.windSpeed_miles = observeData[3].split(',')[0].split(' ')[1];
00612 
00613                 data.humidity = observeData[4].split(',')[0].split(' ')[1];
00614 
00615                 data.pressure = observeData[5].split(',')[0].split(' ')[1].split("mB")[0];
00616 
00617                 data.pressureTendency = observeData[5].split(',')[1].trimmed();
00618 
00619                 data.visibilityStr = observeData[6].trimmed();
00620 
00621             } else {
00622                 parseUnknownElement(xml);
00623             }
00624         }
00625     }
00626 }
00627 
00628 bool UKMETIon::readObservationXMLData(const QString& source, QXmlStreamReader& xml)
00629 {
00630     WeatherData data;
00631 
00632     while (!xml.atEnd()) {
00633         xml.readNext();
00634 
00635         if (xml.isEndElement()) {
00636             break;
00637         }
00638 
00639         if (xml.isStartElement()) {
00640             if (xml.name() == "rss") {
00641                 parsePlaceObservation(source, data, xml);
00642             } else {
00643                 parseUnknownElement(xml);
00644             }
00645         }
00646 
00647     }
00648 
00649     d->m_weatherData[source] = data;
00650 
00651     // Get the 5 day forecast info next.
00652     getFiveDayForecast(source);
00653 
00654     return !xml.error();
00655 }
00656 
00657 bool UKMETIon::readFiveDayForecastXMLData(const QString& source, QXmlStreamReader& xml)
00658 {
00659     while (!xml.atEnd()) {
00660         xml.readNext();
00661 
00662         if (xml.isEndElement()) {
00663             break;
00664         }
00665 
00666         if (xml.isStartElement()) {
00667             if (xml.name() == "wml") {
00668                 parseFiveDayForecast(source, xml);
00669             } else {
00670                 parseUnknownElement(xml);
00671             }
00672         }
00673     }
00674     updateWeather(source);
00675     return !xml.error();
00676 }
00677 
00678 void UKMETIon::parseFiveDayForecast(const QString& source, QXmlStreamReader& xml)
00679 {
00680     Q_ASSERT(xml.isStartElement() && xml.name() == "wml");
00681     bool validNumber = false;
00682     int currentParagraph = 0;
00683     bool skipPlace = false;
00684     int dataItem = 0;
00685 
00686     enum DataItem {
00687         Day,
00688         Summary,
00689         MaxTemp,
00690         MinTemp,
00691         WindSpeed
00692     };
00693 
00694     // Flush out the old forecasts when updating.
00695     d->m_weatherData[source].forecasts.clear();
00696 
00697     WeatherData::ForecastInfo *forecast = new WeatherData::ForecastInfo;
00698 
00699     QRegExp numParser("(Max|Min|Wind)\\s+-*([0-9]+)");
00700     while (!xml.atEnd()) {
00701         xml.readNext();
00702 
00703         if (xml.isStartElement() && xml.name() == "p") {
00704             currentParagraph++;
00705         }
00706 
00707         if (currentParagraph == 3) {
00708             if (xml.isCharacters() && !xml.isWhitespace())  {
00709                 QString dataText = xml.text().toString().trimmed();
00710                 if (!skipPlace) {
00711                     skipPlace = true;
00712                 } else {
00713                     if (numParser.indexIn(dataText) != -1 && numParser.capturedTexts().count() >= 3) {
00714                         validNumber = true;
00715                     }
00716                     switch (dataItem) {
00717                     case Day:
00718                         forecast->period = dataText;
00719                         dataItem++;
00720                         break;
00721                     case Summary:
00722                         forecast->summary = dataText;
00723                         forecast->iconName = getWeatherIcon(dayIcons(), forecast->summary.toLower());
00724                         dataItem++;
00725                         break;
00726                     case MaxTemp:
00727                         forecast->tempHigh = numParser.capturedTexts()[0].remove("Max").toInt();
00728                         dataItem++;
00729                         validNumber = false;
00730                         break;
00731                     case MinTemp:
00732                         forecast->tempLow = numParser.capturedTexts()[0].remove("Min").toInt();
00733                         dataItem++;
00734                         validNumber = false;
00735                         break;
00736                     case WindSpeed:
00737                         forecast->windSpeed = numParser.capturedTexts()[0].remove("Wind").toInt();
00738                         forecast->windDirection = dataText.split('(')[1].split(')')[0];
00739                         dataItem = 0;
00740                         d->m_weatherData[source].forecasts.append(forecast);
00741                         forecast = new WeatherData::ForecastInfo;
00742                         validNumber = false;
00743                         break;
00744                     };
00745                 }
00746             }
00747         }
00748     }
00749 
00750     delete forecast;
00751 }
00752 
00753 void UKMETIon::validate(const QString& source)
00754 {
00755     bool beginflag = true;
00756 
00757     if (!d->m_locations.count()) {
00758         QStringList invalidPlace = source.split('|');
00759         if (d->m_place[QString("bbcukmet|%1").arg(invalidPlace[2])].place.isEmpty()) {
00760             setData(source, "validate", QString("bbcukmet|invalid|multiple|%1").arg(invalidPlace[2]));
00761         }
00762         d->m_locations.clear();
00763         return;
00764     } else {
00765         QString placeList;
00766         foreach(const QString &place, d->m_locations) {
00767             if (beginflag) {
00768                 placeList.append(QString("%1|extra|%2").arg(place.split('|')[1]).arg(d->m_place[place].XMLurl));
00769                 beginflag = false;
00770             } else {
00771                 placeList.append(QString("|place|%1|extra|%2").arg(place.split('|')[1]).arg(d->m_place[place].XMLurl));
00772             }
00773         }
00774         if (d->m_locations.count() > 1) {
00775             setData(source, "validate", QString("bbcukmet|valid|multiple|place|%1").arg(placeList));
00776         } else {
00777             placeList[0] = placeList[0].toUpper();
00778             setData(source, "validate", QString("bbcukmet|valid|single|place|%1").arg(placeList));
00779         }
00780     }
00781     d->m_locations.clear();
00782 }
00783 
00784 void UKMETIon::updateWeather(const QString& source)
00785 {
00786     QString weatherSource = source;
00787     weatherSource.replace("bbcukmet|", "bbcukmet|weather|");
00788     weatherSource.append(QString("|%1").arg(d->m_place[source].XMLurl));
00789 
00790     QMap<QString, QString> dataFields;
00791     QStringList fieldList;
00792     QVector<QString> forecastList;
00793     int i = 0;
00794 
00795     setData(weatherSource, "Place", place(source));
00796     setData(weatherSource, "Station", station(source));
00797     setData(weatherSource, "Observation Period", observationTime(source));
00798     setData(weatherSource, "Current Conditions", condition(source));
00799 
00800     // Tell applet which icon to use for conditions and provide mapping for condition type to the icons to display
00801     if (periodHour(source) >= 0 && periodHour(source) < 6) {
00802         setData(weatherSource, "Condition Icon", getWeatherIcon(nightIcons(), condition(source)));
00803     } else if (periodHour(source) >= 18) {
00804         setData(weatherSource, "Condition Icon", getWeatherIcon(nightIcons(), condition(source)));
00805     } else {
00806         setData(weatherSource, "Condition Icon", getWeatherIcon(dayIcons(), condition(source)));
00807     }
00808 
00809     setData(weatherSource, "Humidity", humidity(source));
00810     setData(weatherSource, "Visibility", visibility(source));
00811 
00812     dataFields = temperature(source);
00813     setData(weatherSource, "Temperature", dataFields["temperature"]);
00814     setData(weatherSource, "Temperature Unit", dataFields["temperatureUnit"]);
00815 
00816     dataFields = pressure(source);
00817     setData(weatherSource, "Pressure", dataFields["pressure"]);
00818     setData(weatherSource, "Pressure Unit", dataFields["pressureUnit"]);
00819     setData(weatherSource, "Pressure Tendency", dataFields["pressureTendency"]);
00820 
00821     dataFields = wind(source);
00822     setData(weatherSource, "Wind Speed", dataFields["windSpeed"]);
00823     setData(weatherSource, "Wind Speed Unit", dataFields["windUnit"]);
00824     setData(weatherSource, "Wind Direction", dataFields["windDirection"]);
00825 
00826     // 5 Day forecast info
00827     forecastList = forecasts(source);
00828 
00829     // Set number of forecasts per day/night supported
00830     setData(weatherSource, QString("Total Weather Days"), d->m_weatherData[source].forecasts.size());
00831 
00832     foreach(const QString &forecastItem, forecastList) {
00833         fieldList = forecastItem.split('|');
00834 
00835         setData(weatherSource, QString("Short Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6") \
00836                 .arg(fieldList[0]).arg(fieldList[1]).arg(fieldList[2]).arg(fieldList[3]) \
00837                 .arg(fieldList[4]).arg(fieldList[5]));
00838         i++;
00839     }
00840 
00841     setData(weatherSource, "Credit", "Supported by backstage.bbc.co.uk / Data from UK MET Office");
00842     setData(weatherSource, "Credit Url", d->m_place[source].XMLforecastURL);
00843 }
00844 
00845 QString UKMETIon::place(const QString& source)
00846 {
00847     return d->m_weatherData[source].stationName;
00848 }
00849 
00850 QString UKMETIon::station(const QString& source)
00851 {
00852     return d->m_weatherData[source].stationName;
00853 }
00854 
00855 QString UKMETIon::observationTime(const QString& source)
00856 {
00857     return d->m_weatherData[source].obsTime;
00858 }
00859 
00860 /*
00861 bool UKMETIon::night(const QString& source)
00862 {
00863     if (d->m_weatherData[source].iconPeriodAP == "pm") {
00864         return true;
00865     }
00866     return false;
00867 } */
00868 
00869 int UKMETIon::periodHour(const QString& source)
00870 {
00871     return d->m_weatherData[source].iconPeriodHour;
00872 }
00873 
00874 QString UKMETIon::condition(const QString& source)
00875 {
00876     return d->m_weatherData[source].condition;
00877 }
00878 
00879 QMap<QString, QString> UKMETIon::temperature(const QString& source)
00880 {
00881     QMap<QString, QString> temperatureInfo;
00882 
00883     temperatureInfo.insert("temperature", QString(d->m_weatherData[source].temperature_C));
00884     temperatureInfo.insert("temperatureUnit", QString::number(WeatherUtils::Celsius));
00885     return temperatureInfo;
00886 }
00887 
00888 QMap<QString, QString> UKMETIon::wind(const QString& source)
00889 {
00890     QMap<QString, QString> windInfo;
00891     if (d->m_weatherData[source].windSpeed_miles == "N/A") {
00892         windInfo.insert("windSpeed", "N/A");
00893         windInfo.insert("windUnit", QString::number(WeatherUtils::NoUnit));
00894     } else {
00895         windInfo.insert("windSpeed", QString(d->m_weatherData[source].windSpeed_miles));
00896         windInfo.insert("windUnit", QString::number(WeatherUtils::MilesAnHour));
00897     }
00898     windInfo.insert("windDirection", d->m_weatherData[source].windDirection);
00899     return windInfo;
00900 }
00901 
00902 QString UKMETIon::humidity(const QString& source)
00903 {
00904     if (d->m_weatherData[source].humidity == "N/A%") {
00905         return "N/A";
00906     }
00907     return d->m_weatherData[source].humidity;
00908 }
00909 
00910 QString UKMETIon::visibility(const QString& source)
00911 {
00912     return d->m_weatherData[source].visibilityStr;
00913 }
00914 
00915 QMap<QString, QString> UKMETIon::pressure(const QString& source)
00916 {
00917     QMap<QString, QString> pressureInfo;
00918     if (d->m_weatherData[source].pressure == "N/A") {
00919         pressureInfo.insert("pressure", "N/A");
00920         return pressureInfo;
00921     }
00922 
00923     pressureInfo.insert("pressure", QString(d->m_weatherData[source].pressure));
00924     pressureInfo.insert("pressureUnit", QString::number(WeatherUtils::Millibars));
00925 
00926     pressureInfo.insert("pressureTendency", d->m_weatherData[source].pressureTendency);
00927     return pressureInfo;
00928 }
00929 
00930 QVector<QString> UKMETIon::forecasts(const QString& source)
00931 {
00932     QVector<QString> forecastData;
00933 
00934     for (int i = 0; i < d->m_weatherData[source].forecasts.size(); ++i) {
00935 
00936         if (d->m_weatherData[source].forecasts[i]->period.contains("Saturday")) {
00937             d->m_weatherData[source].forecasts[i]->period.replace("Saturday", "Sat");
00938         }
00939 
00940         if (d->m_weatherData[source].forecasts[i]->period.contains("Sunday")) {
00941             d->m_weatherData[source].forecasts[i]->period.replace("Sunday", "Sun");
00942         }
00943 
00944         if (d->m_weatherData[source].forecasts[i]->period.contains("Monday")) {
00945             d->m_weatherData[source].forecasts[i]->period.replace("Monday", "Mon");
00946         }
00947 
00948         if (d->m_weatherData[source].forecasts[i]->period.contains("Tuesday")) {
00949             d->m_weatherData[source].forecasts[i]->period.replace("Tuesday", "Tue");
00950         }
00951 
00952         if (d->m_weatherData[source].forecasts[i]->period.contains("Wednesday")) {
00953             d->m_weatherData[source].forecasts[i]->period.replace("Wednesday", "Wed");
00954         }
00955 
00956         if (d->m_weatherData[source].forecasts[i]->period.contains("Thursday")) {
00957             d->m_weatherData[source].forecasts[i]->period.replace("Thursday", "Thu");
00958         }
00959         if (d->m_weatherData[source].forecasts[i]->period.contains("Friday")) {
00960             d->m_weatherData[source].forecasts[i]->period.replace("Friday", "Fri");
00961         }
00962 
00963         forecastData.append(QString("%1|%2|%3|%4|%5|%6") \
00964                             .arg(d->m_weatherData[source].forecasts[i]->period) \
00965                             .arg(d->m_weatherData[source].forecasts[i]->iconName) \
00966                             .arg(d->m_weatherData[source].forecasts[i]->summary) \
00967                             .arg(d->m_weatherData[source].forecasts[i]->tempHigh) \
00968                             .arg(d->m_weatherData[source].forecasts[i]->tempLow) \
00969                             .arg("N/U"));
00970         //.arg(d->m_weatherData[source].forecasts[i]->windSpeed)
00971         //arg(d->m_weatherData[source].forecasts[i]->windDirection));
00972     }
00973 
00974     return forecastData;
00975 }
00976 
00977 #include "ion_bbcukmet.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
  •   libsolidcontrol
  •   libtaskmanager
  • Plasma
  •   Animators
  •   Applets
  •   Engines
  • Solid Modules
Generated for API Reference by doxygen 1.5.7
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