1 /***************************************************************************
2 * Copyright (C) 2007 by Shawn Starr <shawn.starr@rogers.com> *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
18 ***************************************************************************/
20 /* Ion for BBC's Weather from the UK Met Office */
22 #include "ion_bbcukmet.h"
24 class UKMETIon::Private
: public QObject
34 QString XMLforecastURL
;
36 QString sourceOptions
;
41 QHash
<QString
, UKMETIon::Private::XMLMapInfo
> m_place
;
42 QVector
<QString
> m_locations
;
43 QStringList m_matchLocations
;
47 // Weather information
48 QHash
<QString
, WeatherData
> m_weatherData
;
50 // Store KIO jobs - Search list
51 QMap
<KJob
*, QXmlStreamReader
*> m_jobXml
;
52 QMap
<KJob
*, QString
> m_jobList
;
54 QMap
<KJob
*, QXmlStreamReader
*> m_obsJobXml
;
55 QMap
<KJob
*, QString
> m_obsJobList
;
57 QMap
<KJob
*, QXmlStreamReader
*> m_forecastJobXml
;
58 QMap
<KJob
*, QString
> m_forecastJobList
;
61 KIO::TransferJob
*m_job
;
63 int m_timezoneType
; // Ion option: Timezone may be local time or UTC time
64 int m_measureType
; // Ion option: Units may be Metric or Imperial
69 UKMETIon::UKMETIon(QObject
*parent
, const QVariantList
&args
)
70 : IonInterface(parent
), d(new Private())
78 // Destroy each forecast stored in a QVector
79 foreach(WeatherData item
, d
->m_weatherData
) {
80 foreach(WeatherData::ForecastInfo
*forecast
, item
.forecasts
) {
91 // Get the master list of locations to be parsed
97 // Get a specific Ion's data
98 bool UKMETIon::updateIonSource(const QString
& source
)
100 // We expect the applet to send the source in the following tokenization:
101 // ionname|validate|place_name - Triggers validation of place
102 // ionname|weather|place_name - Triggers receiving weather of place
104 QStringList sourceAction
= source
.split('|');
106 if (sourceAction
[1] == QString("validate")) {
107 // Look for places to match
108 findPlace(sourceAction
[2], source
);
111 } else if (sourceAction
[1] == QString("weather")) {
112 if (sourceAction
.count() >= 3) {
113 d
->m_place
[QString("bbcukmet|%1").arg(sourceAction
[2])].XMLurl
= sourceAction
[3];
114 getXMLData(QString("%1|%2").arg(sourceAction
[0]).arg(sourceAction
[2]));
123 // Gets specific city XML data
124 void UKMETIon::getXMLData(const QString
& source
)
127 url
= d
->m_place
[source
].XMLurl
;
129 d
->m_job
= KIO::get(url
.url(), KIO::Reload
, KIO::HideProgressInfo
);
130 d
->m_job
->addMetaData("cookies", "none"); // Disable displaying cookies
131 d
->m_obsJobXml
.insert(d
->m_job
, new QXmlStreamReader
);
132 d
->m_obsJobList
.insert(d
->m_job
, source
);
135 connect(d
->m_job
, SIGNAL(data(KIO::Job
*, const QByteArray
&)), this,
136 SLOT(observation_slotDataArrived(KIO::Job
*, const QByteArray
&)));
137 connect(d
->m_job
, SIGNAL(result(KJob
*)), this, SLOT(observation_slotJobFinished(KJob
*)));
141 // Parses city list and gets the correct city based on ID number
142 void UKMETIon::findPlace(const QString
& place
, const QString
& source
)
145 url
= "http://www.bbc.co.uk/cgi-perl/weather/search/new_search.pl?x=0&y=0&=Submit&search_query=" + place
+ "&tmpl=wap";
147 d
->m_job
= KIO::get(url
.url(), KIO::Reload
, KIO::HideProgressInfo
);
148 d
->m_job
->addMetaData("cookies", "none"); // Disable displaying cookies
149 d
->m_jobXml
.insert(d
->m_job
, new QXmlStreamReader
);
150 d
->m_jobList
.insert(d
->m_job
, source
);
153 connect(d
->m_job
, SIGNAL(data(KIO::Job
*, const QByteArray
&)), this,
154 SLOT(setup_slotDataArrived(KIO::Job
*, const QByteArray
&)));
155 connect(d
->m_job
, SIGNAL(result(KJob
*)), this, SLOT(setup_slotJobFinished(KJob
*)));
157 // Handle redirects for direct hit places.
158 connect(d
->m_job
, SIGNAL(redirection(KIO::Job
*, const KUrl
&)), this,
159 SLOT(setup_slotRedirected(KIO::Job
*, const KUrl
&)));
163 void UKMETIon::getFiveDayForecast(const QString
& source
)
166 url
= d
->m_place
[source
].XMLforecastURL
.replace("weather/5day.shtml", "weather/mobile/5day.wml");
168 d
->m_job
= KIO::get(url
.url(), KIO::Reload
, KIO::HideProgressInfo
);
169 d
->m_job
->addMetaData("cookies", "none"); // Disable displaying cookies
170 d
->m_forecastJobXml
.insert(d
->m_job
, new QXmlStreamReader
);
171 d
->m_forecastJobList
.insert(d
->m_job
, source
);
174 connect(d
->m_job
, SIGNAL(data(KIO::Job
*, const QByteArray
&)), this,
175 SLOT(forecast_slotDataArrived(KIO::Job
*, const QByteArray
&)));
176 connect(d
->m_job
, SIGNAL(result(KJob
*)), this, SLOT(forecast_slotJobFinished(KJob
*)));
180 bool UKMETIon::readSearchXMLData(const QString
& key
, QXmlStreamReader
& xml
)
183 while (!xml
.atEnd()) {
186 if (xml
.isEndElement()) {
190 if (xml
.isStartElement()) {
191 if (xml
.name() == "wml") {
192 parseSearchLocations(key
, xml
);
194 parseUnknownElement(xml
);
202 void UKMETIon::parseSearchLocations(const QString
& source
, QXmlStreamReader
& xml
)
210 int currentParagraph
= 0;
212 Q_ASSERT(xml
.isStartElement() && xml
.name() == "wml");
214 while (!xml
.atEnd()) {
217 if (xml
.isEndElement() && xml
.name() == "wml") {
221 if (xml
.isStartElement() && xml
.name() == "p") {
225 if (currentParagraph
== 2) {
226 if (xml
.isCharacters() && !xml
.isWhitespace()) {
227 QString dataText
= xml
.text().toString().trimmed();
228 if (dataText
.contains("No locations")) {
234 if (xml
.isStartElement()) {
235 if (xml
.name() == "a" && !xml
.attributes().value("href").isEmpty()) {
236 if (xml
.attributes().value("href").toString().contains("5day.wml")) {
238 // Split URL to determine station ID number
239 tokens
= xml
.attributes().value("href").toString().split("=");
240 if (xml
.attributes().value("href").toString().contains("world")) {
241 url
= "http://feeds.bbc.co.uk/weather/feeds/obs/world/" + tokens
[1] + ".xml";
244 url
= "http://feeds.bbc.co.uk/weather/feeds/obs/id/" + tokens
[1] + ".xml";
247 place
= xml
.readElementText();
248 tmp
= QString("bbcukmet|%1").arg(place
);
250 // Duplicate places can exist
251 if (d
->m_locations
.contains(tmp
)) {
253 QString dupePlace
= place
;
254 tmp
= QString("bbcukmet|%1").arg(QString("%1 (#%2)").arg(dupePlace
).arg(counter
));
255 place
= QString("%1 (#%2)").arg(dupePlace
).arg(counter
);
259 if (flag
) { // This is a UK specific location
260 d
->m_place
[tmp
].XMLurl
= url
;
261 d
->m_place
[tmp
].place
= place
;
262 d
->m_place
[tmp
].ukPlace
= true;
264 d
->m_place
[tmp
].XMLurl
= url
;
265 d
->m_place
[tmp
].place
= place
;
266 d
->m_place
[tmp
].ukPlace
= false;
268 d
->m_locations
.append(tmp
);
276 // handle when no XML tag is found
277 void UKMETIon::parseUnknownElement(QXmlStreamReader
& xml
)
279 while (!xml
.atEnd()) {
282 if (xml
.isEndElement()) {
286 if (xml
.isStartElement()) {
287 parseUnknownElement(xml
);
292 void UKMETIon::setup_slotRedirected(KIO::Job
*job
, const KUrl
&url
)
298 QStringList tokens
= url
.url().split("=");
299 if (url
.url().contains("xhtml")) { // We dont care about the first redirection (there is two)
300 if (url
.url().contains("world")) {
301 obsUrl
= "http://feeds.bbc.co.uk/weather/feeds/obs/world/" + tokens
[2] + ".xml";
304 obsUrl
= "http://feeds.bbc.co.uk/weather/feeds/obs/id/" + tokens
[2] + ".xml";
307 place
= d
->m_jobList
[job
].split("|")[2]; // Contains the source name (place in this case)
308 tmp
= QString("bbcukmet|%1").arg(place
);
309 place
[0] = place
[0].toUpper();
311 if (flag
) { // This is a UK specific location
312 d
->m_place
[tmp
].XMLurl
= obsUrl
;
313 d
->m_place
[tmp
].place
= place
;
314 d
->m_place
[tmp
].ukPlace
= true;
316 d
->m_place
[tmp
].XMLurl
= obsUrl
;
317 d
->m_place
[tmp
].place
= place
;
318 d
->m_place
[tmp
].ukPlace
= false;
320 d
->m_locations
.append(tmp
);
321 validate(d
->m_jobList
[job
]);
325 void UKMETIon::setup_slotDataArrived(KIO::Job
*job
, const QByteArray
&data
)
327 QByteArray local
= data
;
328 if (data
.isEmpty() || !d
->m_jobXml
.contains(job
)) {
332 // XXX: BBC doesn't convert unicode strings so this breaks XML formatting. Not pretty.
333 if (local
.startsWith("<?xml version")) {
334 local
.replace("<?xml version=\"1.0\"?>", "<?xml version=\"1.0\" encoding=\"cp1252\" ?>");
338 d
->m_jobXml
[job
]->addData(local
);
341 void UKMETIon::setup_slotJobFinished(KJob
*job
)
343 if (job
->error() == 149) {
344 setData(d
->m_jobList
[job
], "validate", QString("bbcukmet|timeout"));
345 disconnectSource(d
->m_jobList
[job
], this);
346 d
->m_jobList
.remove(job
);
347 delete d
->m_jobXml
[job
];
348 d
->m_jobXml
.remove(job
);
351 // If Redirected, dont go to this routine
352 if (!d
->m_locations
.contains(QString("bbcukmet|%1").arg(d
->m_jobList
[job
]))) {
353 readSearchXMLData(d
->m_jobList
[job
], *d
->m_jobXml
[job
]);
355 d
->m_jobList
.remove(job
);
356 delete d
->m_jobXml
[job
];
357 d
->m_jobXml
.remove(job
);
360 void UKMETIon::observation_slotDataArrived(KIO::Job
*job
, const QByteArray
&data
)
362 QByteArray local
= data
;
363 if (data
.isEmpty() || !d
->m_obsJobXml
.contains(job
)) {
367 // XXX: I don't know what to say about this. But horrible. We can't really do much about this :/
368 // No, it's not UTF-8, it really lies.
369 if (local
.startsWith("<?xml version")) {
370 local
.replace("encoding=\"UTF-8\"?>", "encoding=\"cp1252\" ?>");
374 d
->m_obsJobXml
[job
]->addData(local
);
377 void UKMETIon::observation_slotJobFinished(KJob
*job
)
379 readObservationXMLData(d
->m_obsJobList
[job
], *d
->m_obsJobXml
[job
]);
380 d
->m_obsJobList
.remove(job
);
381 delete d
->m_obsJobXml
[job
];
382 d
->m_obsJobXml
.remove(job
);
385 void UKMETIon::forecast_slotDataArrived(KIO::Job
*job
, const QByteArray
&data
)
387 QByteArray local
= data
;
388 if (data
.isEmpty() || !d
->m_forecastJobXml
.contains(job
)) {
392 // XXX: BBC doesn't convert unicode strings so this breaks XML formatting. Not pretty.
393 // No, it's not UTF-8, it really lies.
394 if (local
.startsWith("<?xml version")) {
395 local
.replace("<?xml version=\"1.0\"?>", "<?xml version=\"1.0\" encoding=\"cp1252\" ?>");
398 d
->m_forecastJobXml
[job
]->addData(local
);
401 void UKMETIon::forecast_slotJobFinished(KJob
*job
)
403 readFiveDayForecastXMLData(d
->m_forecastJobList
[job
], *d
->m_forecastJobXml
[job
]);
404 d
->m_forecastJobList
.remove(job
);
405 delete d
->m_forecastJobXml
[job
];
406 d
->m_forecastJobXml
.remove(job
);
409 void UKMETIon::parsePlaceObservation(const QString
&source
, WeatherData
& data
, QXmlStreamReader
& xml
)
411 Q_ASSERT(xml
.isStartElement() && xml
.name() == "rss");
413 while (!xml
.atEnd()) {
416 if (xml
.isEndElement() && xml
.name() == "rss") {
420 if (xml
.isStartElement()) {
421 if (xml
.name() == "channel") {
422 parseWeatherChannel(source
, data
, xml
);
428 void UKMETIon::parseWeatherChannel(const QString
& source
, WeatherData
& data
, QXmlStreamReader
& xml
)
430 Q_ASSERT(xml
.isStartElement() && xml
.name() == "channel");
432 while (!xml
.atEnd()) {
435 if (xml
.isEndElement() && xml
.name() == "channel") {
439 if (xml
.isStartElement()) {
440 if (xml
.name() == "title") {
441 data
.stationName
= xml
.readElementText().split("Observations for")[1].trimmed();
442 } else if (xml
.name() == "item") {
443 parseWeatherObservation(source
, data
, xml
);
445 parseUnknownElement(xml
);
451 void UKMETIon::parseWeatherObservation(const QString
& source
, WeatherData
& data
, QXmlStreamReader
& xml
)
454 Q_ASSERT(xml
.isStartElement() && xml
.name() == "item");
456 while (!xml
.atEnd()) {
459 if (xml
.isEndElement() && xml
.name() == "item") {
463 if (xml
.isStartElement()) {
464 if (xml
.name() == "title") {
465 QString conditionString
= xml
.readElementText();
467 // Get the observation time.
468 QStringList conditionData
= conditionString
.split(":");
470 data
.obsTime
= conditionData
[0];
471 data
.condition
= conditionData
[1].split(".")[0].trimmed();
472 } else if (xml
.name() == "link") {
473 d
->m_place
[source
].XMLforecastURL
= xml
.readElementText();
474 } else if (xml
.name() == "description") {
475 QString observeString
= xml
.readElementText();
476 QStringList observeData
= observeString
.split(":");
478 data
.temperature_C
= observeData
[1].split(QChar(176))[0].trimmed();
479 data
.temperature_F
= observeData
[1].split("(")[1].split(QChar(176))[0];
481 data
.windDirection
= observeData
[2].split(",")[0].trimmed();
482 data
.windSpeed_miles
= observeData
[3].split(",")[0].split(" ")[1];
484 data
.humidity
= observeData
[4].split(",")[0].split(" ")[1];
486 data
.pressure
= observeData
[5].split(",")[0].split(" ")[1].split("mB")[0];
488 data
.pressureTendency
= observeData
[5].split(",")[1].trimmed();
490 data
.visibilityStr
= observeData
[6].trimmed();
493 parseUnknownElement(xml
);
499 bool UKMETIon::readObservationXMLData(const QString
& source
, QXmlStreamReader
& xml
)
503 while (!xml
.atEnd()) {
506 if (xml
.isEndElement()) {
510 if (xml
.isStartElement()) {
511 if (xml
.name() == "rss") {
512 parsePlaceObservation(source
, data
, xml
);
514 parseUnknownElement(xml
);
520 d
->m_weatherData
[source
] = data
;
522 // Get the 5 day forecast info next.
523 getFiveDayForecast(source
);
528 bool UKMETIon::readFiveDayForecastXMLData(const QString
& source
, QXmlStreamReader
& xml
)
530 while (!xml
.atEnd()) {
533 if (xml
.isEndElement()) {
537 if (xml
.isStartElement()) {
538 if (xml
.name() == "wml") {
539 parseFiveDayForecast(source
, xml
);
541 parseUnknownElement(xml
);
545 updateWeather(source
);
549 void UKMETIon::parseFiveDayForecast(const QString
& source
, QXmlStreamReader
& xml
)
551 Q_ASSERT(xml
.isStartElement() && xml
.name() == "wml");
553 int currentParagraph
= 0;
554 bool skipPlace
= false;
566 // Flush out the old forecasts when updating.
567 d
->m_weatherData
[source
].forecasts
.clear();
569 WeatherData::ForecastInfo
*forecast
= new WeatherData::ForecastInfo
;
571 QRegExp
numParser("(Max|Min|Wind)\\s+-*([0-9]+)");
572 while (!xml
.atEnd()) {
575 if (xml
.isStartElement() && xml
.name() == "p") {
579 if (currentParagraph
== 3) {
580 if (xml
.isCharacters() && !xml
.isWhitespace()) {
581 QString dataText
= xml
.text().toString().trimmed();
585 if (numParser
.indexIn(dataText
) != -1 && numParser
.capturedTexts().count() >= 3) {
586 numberValue
= numParser
.capturedTexts()[2].toInt();
590 forecast
->period
= dataText
;
594 forecast
->summary
= dataText
;
598 forecast
->tempHigh
= numberValue
;
602 forecast
->tempLow
= numberValue
;
606 forecast
->windSpeed
= numberValue
;
607 forecast
->windDirection
= dataText
.split("(")[1].split(")")[0];
609 d
->m_weatherData
[source
].forecasts
.append(forecast
);
610 forecast
= new WeatherData::ForecastInfo
;
621 void UKMETIon::setMeasureUnit(const QString
& unitType
)
623 d
->m_measureType
= unitType
.toInt();
626 // Not used in this ion yet.
627 void UKMETIon::setTimezoneFormat(const QString
& tz
)
629 d
->m_timezoneType
= tz
.toInt(); // Boolean
632 bool UKMETIon::metricUnit()
634 if (d
->m_measureType
== KLocale::Metric
) {
642 // Not used in this ion yet.
643 bool UKMETIon::timezone()
645 if (d
->m_timezoneType
) {
649 // Not UTC, local time
653 void UKMETIon::validate(const QString
& source
)
655 bool beginflag
= true;
657 if (!d
->m_locations
.count()) {
658 QStringList invalidPlace
= source
.split('|');
659 if (d
->m_place
[QString("bbcukmet|%1").arg(invalidPlace
[2])].place
.isEmpty()) {
660 setData(source
, "validate", QString("bbcukmet|invalid|multiple|%1").arg(invalidPlace
[2]));
662 d
->m_locations
.clear();
666 foreach(QString place
, d
->m_locations
) {
668 placeList
.append(QString("%1|extra|%2").arg(place
.split("|")[1]).arg(d
->m_place
[place
].XMLurl
));
671 placeList
.append(QString("|place|%1|extra|%2").arg(place
.split("|")[1]).arg(d
->m_place
[place
].XMLurl
));
674 if (d
->m_locations
.count() > 1) {
675 setData(source
, "validate", QString("bbcukmet|valid|multiple|place|%1").arg(placeList
));
677 placeList
[0] = placeList
[0].toUpper();
678 setData(source
, "validate", QString("bbcukmet|valid|single|place|%1").arg(placeList
));
681 d
->m_locations
.clear();
684 void UKMETIon::updateWeather(const QString
& source
)
686 QString weatherSource
= source
;
687 weatherSource
.replace("bbcukmet|", "bbcukmet|weather|");
688 weatherSource
.append(QString("|%1").arg(d
->m_place
[source
].XMLurl
));
690 QMap
<QString
, QString
> dataFields
;
691 QStringList fieldList
;
692 QVector
<QString
> forecastList
;
695 setData(weatherSource
, "Place", place(source
));
696 setData(weatherSource
, "Station", station(source
));
697 setData(weatherSource
, "Observation Period", observationTime(source
));
698 setData(weatherSource
, "Current Conditions", condition(source
));
700 setData(weatherSource
, "Humidity", humidity(source
));
701 setData(weatherSource
, "Visibility", visibility(source
));
703 dataFields
= temperature(source
);
704 setData(weatherSource
, "Temperature", dataFields
["temperature"]);
705 setData(weatherSource
, "Temperature Unit", dataFields
["temperatureUnit"]);
707 dataFields
= pressure(source
);
708 setData(weatherSource
, "Pressure", dataFields
["pressure"]);
709 setData(weatherSource
, "Pressure Unit", dataFields
["pressureUnit"]);
710 setData(weatherSource
, "Pressure Tendency", dataFields
["pressureTendency"]);
712 dataFields
= wind(source
);
713 setData(weatherSource
, "Wind Speed", dataFields
["windSpeed"]);
714 setData(weatherSource
, "Wind Speed Unit", dataFields
["windUnit"]);
715 setData(weatherSource
, "Wind Direction", dataFields
["windDirection"]);
717 // 5 Day forecast info
718 forecastList
= forecasts(source
);
722 foreach(QString forecastItem
, forecastList
) {
723 fieldList
= forecastItem
.split('|');
725 windSpeed
= QString::number(WeatherFormula::milesToKM(fieldList
[4].toFloat()), 'f', 1);
728 windSpeed
= fieldList
[4];
732 setData(weatherSource
, QString("Short Forecast Day %1").arg(i
), QString("%1|%2|%3|%4|%5|%6|%7") \
733 .arg(fieldList
[0]).arg(fieldList
[1]).arg(fieldList
[2]).arg(fieldList
[3]) \
734 .arg(windSpeed
).arg(windUnit
).arg(fieldList
[5]));
738 setData(weatherSource
, "Credit", "Supported by backstage.bbc.co.uk / Data from UK MET Office");
741 QString
UKMETIon::place(const QString
& source
)
743 return d
->m_weatherData
[source
].stationName
;
746 QString
UKMETIon::station(const QString
& source
)
748 return d
->m_weatherData
[source
].stationName
;
751 QString
UKMETIon::observationTime(const QString
& source
)
753 return d
->m_weatherData
[source
].obsTime
;
756 QString
UKMETIon::condition(const QString
& source
)
758 return d
->m_weatherData
[source
].condition
;
761 QMap
<QString
, QString
> UKMETIon::temperature(const QString
& source
)
763 QMap
<QString
, QString
> temperatureInfo
;
766 temperatureInfo
.insert("temperature", QString("%1").arg(d
->m_weatherData
[source
].temperature_C
));
767 temperatureInfo
.insert("temperatureUnit", QString("%1C").arg(QChar(176)));
769 temperatureInfo
.insert("temperature", QString("%1").arg(d
->m_weatherData
[source
].temperature_F
));
770 temperatureInfo
.insert("temperatureUnit", QString("%1F").arg(QChar(176)));
772 return temperatureInfo
;
775 QMap
<QString
, QString
> UKMETIon::wind(const QString
& source
)
777 QMap
<QString
, QString
> windInfo
;
778 if (d
->m_weatherData
[source
].windSpeed_miles
== "N/A") {
779 windInfo
.insert("windSpeed", "N/A");
780 windInfo
.insert("windUnit", "N/A");
783 windInfo
.insert("windSpeed", QString::number(WeatherFormula::milesToKM(d
->m_weatherData
[source
].windSpeed_miles
.toFloat()), 'f', 1));
784 windInfo
.insert("windUnit", "km/h");
786 windInfo
.insert("windSpeed", QString(d
->m_weatherData
[source
].windSpeed_miles
));
787 windInfo
.insert("windUnit", "mph");
790 windInfo
.insert("windDirection", d
->m_weatherData
[source
].windDirection
);
794 QString
UKMETIon::humidity(const QString
& source
)
796 if (d
->m_weatherData
[source
].humidity
== "N/A%") {
799 return d
->m_weatherData
[source
].humidity
;
802 QString
UKMETIon::visibility(const QString
& source
)
804 return d
->m_weatherData
[source
].visibilityStr
;
807 QMap
<QString
, QString
> UKMETIon::pressure(const QString
& source
)
809 QMap
<QString
, QString
> pressureInfo
;
810 if (d
->m_weatherData
[source
].pressure
== "N/A") {
811 pressureInfo
.insert("pressure", "N/A");
816 pressureInfo
.insert("pressure", QString::number(WeatherFormula::millibarsToKilopascals(d
->m_weatherData
[source
].pressure
.toFloat()), 'f', 1));
817 pressureInfo
.insert("pressureUnit", "kPa");
819 pressureInfo
.insert("pressure", QString::number(WeatherFormula::millibarsToInches(d
->m_weatherData
[source
].pressure
.toFloat()), 'f', 2));
820 pressureInfo
.insert("pressureUnit", "in");
823 pressureInfo
.insert("pressureTendency", d
->m_weatherData
[source
].pressureTendency
);
827 QVector
<QString
> UKMETIon::forecasts(const QString
& source
)
829 QVector
<QString
> forecastData
;
831 for (int i
= 0; i
< d
->m_weatherData
[source
].forecasts
.size(); ++i
) {
832 forecastData
.append(QString("%1|%2|%3|%4|%5|%6") \
833 .arg(d
->m_weatherData
[source
].forecasts
[i
]->period
) \
834 .arg(d
->m_weatherData
[source
].forecasts
[i
]->summary
) \
835 .arg(d
->m_weatherData
[source
].forecasts
[i
]->tempHigh
) \
836 .arg(d
->m_weatherData
[source
].forecasts
[i
]->tempLow
) \
837 .arg(d
->m_weatherData
[source
].forecasts
[i
]->windSpeed
) \
838 .arg(d
->m_weatherData
[source
].forecasts
[i
]->windDirection
));
844 #include "ion_bbcukmet.moc"