You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1674 lines
72 KiB
1674 lines
72 KiB
/*************************************************************************** |
|
* Copyright (C) 2007-2011,2019 by Shawn Starr <shawn.starr@rogers.com> * |
|
* * |
|
* This program is free software; you can redistribute it and/or modify * |
|
* it under the terms of the GNU General Public License as published by * |
|
* the Free Software Foundation; either version 2 of the License, or * |
|
* (at your option) any later version. * |
|
* * |
|
* This program is distributed in the hope that it will be useful, * |
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of * |
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * |
|
* GNU General Public License for more details. * |
|
* * |
|
* You should have received a copy of the GNU General Public License * |
|
* along with this program; if not, write to the * |
|
* Free Software Foundation, Inc., * |
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * |
|
***************************************************************************/ |
|
|
|
/* Ion for Environment Canada XML data */ |
|
|
|
#include "ion_envcan.h" |
|
|
|
#include "ion_envcandebug.h" |
|
|
|
#include <KIO/Job> |
|
#include <KUnitConversion/Converter> |
|
#include <KLocalizedString> |
|
|
|
#include <QRegularExpression> |
|
#include <QTimeZone> |
|
|
|
WeatherData::WeatherData() |
|
: stationLatitude(qQNaN()) |
|
, stationLongitude(qQNaN()) |
|
, temperature(qQNaN()) |
|
, dewpoint(qQNaN()) |
|
, windchill(qQNaN()) |
|
, pressure(qQNaN()) |
|
, visibility(qQNaN()) |
|
, humidity(qQNaN()) |
|
, windSpeed(qQNaN()) |
|
, windGust(qQNaN()) |
|
, normalHigh(qQNaN()) |
|
, normalLow(qQNaN()) |
|
, prevHigh(qQNaN()) |
|
, prevLow(qQNaN()) |
|
, recordHigh(qQNaN()) |
|
, recordLow(qQNaN()) |
|
, recordRain(qQNaN()) |
|
, recordSnow(qQNaN()) |
|
{ |
|
} |
|
|
|
WeatherData::ForecastInfo::ForecastInfo() |
|
: tempHigh(qQNaN()) |
|
, tempLow(qQNaN()) |
|
, popPrecent(qQNaN()) |
|
{ |
|
} |
|
|
|
|
|
// ctor, dtor |
|
EnvCanadaIon::EnvCanadaIon(QObject *parent, const QVariantList &args) |
|
: IonInterface(parent, args) |
|
{ |
|
// Get the real city XML URL so we can parse this |
|
getXMLSetup(); |
|
} |
|
|
|
void EnvCanadaIon::deleteForecasts() |
|
{ |
|
QMutableHashIterator<QString, WeatherData> it(m_weatherData); |
|
while (it.hasNext()) { |
|
it.next(); |
|
WeatherData &item = it.value(); |
|
qDeleteAll(item.warnings); |
|
item.warnings.clear(); |
|
|
|
qDeleteAll(item.watches); |
|
item.watches.clear(); |
|
|
|
qDeleteAll(item.forecasts); |
|
item.forecasts.clear(); |
|
} |
|
} |
|
|
|
void EnvCanadaIon::reset() |
|
{ |
|
deleteForecasts(); |
|
emitWhenSetup = true; |
|
m_sourcesToReset = sources(); |
|
getXMLSetup(); |
|
} |
|
|
|
EnvCanadaIon::~EnvCanadaIon() |
|
{ |
|
// Destroy each watch/warning stored in a QVector |
|
deleteForecasts(); |
|
} |
|
|
|
QMap<QString, IonInterface::ConditionIcons> EnvCanadaIon::setupConditionIconMappings() const |
|
{ |
|
return QMap<QString, ConditionIcons> { |
|
|
|
// Explicit periods |
|
{ QStringLiteral("mainly sunny"), FewCloudsDay }, |
|
{ QStringLiteral("mainly clear"), FewCloudsNight }, |
|
{ QStringLiteral("sunny"), ClearDay }, |
|
{ QStringLiteral("clear"), ClearNight }, |
|
|
|
// Available conditions |
|
{ QStringLiteral("blowing snow"), Snow }, |
|
{ QStringLiteral("cloudy"), Overcast }, |
|
{ QStringLiteral("distant precipitation"), LightRain }, |
|
{ QStringLiteral("drifting snow"), Flurries }, |
|
{ QStringLiteral("drizzle"), LightRain }, |
|
{ QStringLiteral("dust"), NotAvailable }, |
|
{ QStringLiteral("dust devils"), NotAvailable }, |
|
{ QStringLiteral("fog"), Mist }, |
|
{ QStringLiteral("fog bank near station"), Mist }, |
|
{ QStringLiteral("fog depositing ice"), Mist }, |
|
{ QStringLiteral("fog patches"), Mist }, |
|
{ QStringLiteral("freezing drizzle"), FreezingDrizzle }, |
|
{ QStringLiteral("freezing rain"), FreezingRain }, |
|
{ QStringLiteral("funnel cloud"), NotAvailable }, |
|
{ QStringLiteral("hail"), Hail }, |
|
{ QStringLiteral("haze"), Haze }, |
|
{ QStringLiteral("heavy blowing snow"), Snow }, |
|
{ QStringLiteral("heavy drifting snow"), Snow }, |
|
{ QStringLiteral("heavy drizzle"), LightRain }, |
|
{ QStringLiteral("heavy hail"), Hail }, |
|
{ QStringLiteral("heavy mixed rain and drizzle"), LightRain }, |
|
{ QStringLiteral("heavy mixed rain and snow shower"), RainSnow }, |
|
{ QStringLiteral("heavy rain"), Rain }, |
|
{ QStringLiteral("heavy rain and snow"), RainSnow }, |
|
{ QStringLiteral("heavy rainshower"), Rain }, |
|
{ QStringLiteral("heavy snow"), Snow }, |
|
{ QStringLiteral("heavy snow pellets"), Snow }, |
|
{ QStringLiteral("heavy snowshower"), Snow }, |
|
{ QStringLiteral("heavy thunderstorm with hail"), Thunderstorm }, |
|
{ QStringLiteral("heavy thunderstorm with rain"), Thunderstorm }, |
|
{ QStringLiteral("ice crystals"), Flurries }, |
|
{ QStringLiteral("ice pellets"), Hail }, |
|
{ QStringLiteral("increasing cloud"), Overcast }, |
|
{ QStringLiteral("light drizzle"), LightRain }, |
|
{ QStringLiteral("light freezing drizzle"), FreezingRain }, |
|
{ QStringLiteral("light freezing rain"), FreezingRain }, |
|
{ QStringLiteral("light rain"), LightRain }, |
|
{ QStringLiteral("light rainshower"), LightRain }, |
|
{ QStringLiteral("light snow"), LightSnow }, |
|
{ QStringLiteral("light snow pellets"), LightSnow }, |
|
{ QStringLiteral("light snowshower"), Flurries }, |
|
{ QStringLiteral("lightning visible"), Thunderstorm }, |
|
{ QStringLiteral("mist"), Mist }, |
|
{ QStringLiteral("mixed rain and drizzle"), LightRain }, |
|
{ QStringLiteral("mixed rain and snow shower"), RainSnow }, |
|
{ QStringLiteral("not reported"), NotAvailable }, |
|
{ QStringLiteral("rain"), Rain }, |
|
{ QStringLiteral("rain and snow"), RainSnow }, |
|
{ QStringLiteral("rainshower"), LightRain }, |
|
{ QStringLiteral("recent drizzle"), LightRain }, |
|
{ QStringLiteral("recent dust or sand storm"), NotAvailable }, |
|
{ QStringLiteral("recent fog"), Mist }, |
|
{ QStringLiteral("recent freezing precipitation"), FreezingDrizzle }, |
|
{ QStringLiteral("recent hail"), Hail }, |
|
{ QStringLiteral("recent rain"), Rain }, |
|
{ QStringLiteral("recent rain and snow"), RainSnow }, |
|
{ QStringLiteral("recent rainshower"), Rain }, |
|
{ QStringLiteral("recent snow"), Snow }, |
|
{ QStringLiteral("recent snowshower"), Flurries }, |
|
{ QStringLiteral("recent thunderstorm"), Thunderstorm }, |
|
{ QStringLiteral("recent thunderstorm with hail"), Thunderstorm }, |
|
{ QStringLiteral("recent thunderstorm with heavy hail"), Thunderstorm }, |
|
{ QStringLiteral("recent thunderstorm with heavy rain"), Thunderstorm }, |
|
{ QStringLiteral("recent thunderstorm with rain"), Thunderstorm }, |
|
{ QStringLiteral("sand or dust storm"), NotAvailable }, |
|
{ QStringLiteral("severe sand or dust storm"), NotAvailable }, |
|
{ QStringLiteral("shallow fog"), Mist }, |
|
{ QStringLiteral("smoke"), NotAvailable }, |
|
{ QStringLiteral("snow"), Snow }, |
|
{ QStringLiteral("snow crystals"), Flurries }, |
|
{ QStringLiteral("snow grains"), Flurries }, |
|
{ QStringLiteral("squalls"), Snow }, |
|
{ QStringLiteral("thunderstorm"), Thunderstorm }, |
|
{ QStringLiteral("thunderstorm with hail"), Thunderstorm }, |
|
{ QStringLiteral("thunderstorm with rain"), Thunderstorm }, |
|
{ QStringLiteral("thunderstorm with light rainshowers"), Thunderstorm }, |
|
{ QStringLiteral("thunderstorm with heavy rainshowers"), Thunderstorm }, |
|
{ QStringLiteral("thunderstorm with sand or dust storm"), Thunderstorm }, |
|
{ QStringLiteral("thunderstorm without precipitation"), Thunderstorm }, |
|
{ QStringLiteral("tornado"), NotAvailable }, |
|
}; |
|
} |
|
|
|
|
|
QMap<QString, IonInterface::ConditionIcons> EnvCanadaIon::setupForecastIconMappings() const |
|
{ |
|
return QMap<QString, ConditionIcons> { |
|
|
|
// Abbreviated forecast descriptions |
|
{ QStringLiteral("a few flurries"), Flurries }, |
|
{ QStringLiteral("a few flurries mixed with ice pellets"), RainSnow }, |
|
{ QStringLiteral("a few flurries or rain showers"), RainSnow }, |
|
{ QStringLiteral("a few flurries or thundershowers"), RainSnow }, |
|
{ QStringLiteral("a few rain showers or flurries"), RainSnow }, |
|
{ QStringLiteral("a few rain showers or wet flurries"), RainSnow }, |
|
{ QStringLiteral("a few showers"), LightRain }, |
|
{ QStringLiteral("a few showers or drizzle"), LightRain }, |
|
{ QStringLiteral("a few showers or thundershowers"), Thunderstorm }, |
|
{ QStringLiteral("a few showers or thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("a few thundershowers"), Thunderstorm }, |
|
{ QStringLiteral("a few thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("a few wet flurries"), RainSnow }, |
|
{ QStringLiteral("a few wet flurries or rain showers"), RainSnow }, |
|
{ QStringLiteral("a mix of sun and cloud"), PartlyCloudyDay }, |
|
{ QStringLiteral("cloudy with sunny periods"), PartlyCloudyDay }, |
|
{ QStringLiteral("partly cloudy"), PartlyCloudyDay }, |
|
{ QStringLiteral("mainly cloudy"), PartlyCloudyDay }, |
|
{ QStringLiteral("mainly sunny"), FewCloudsDay }, |
|
{ QStringLiteral("sunny"), ClearDay }, |
|
{ QStringLiteral("blizzard"), Snow }, |
|
{ QStringLiteral("clear"), ClearNight }, |
|
{ QStringLiteral("cloudy"), Overcast }, |
|
{ QStringLiteral("drizzle"), LightRain }, |
|
{ QStringLiteral("drizzle mixed with freezing drizzle"), FreezingDrizzle }, |
|
{ QStringLiteral("drizzle mixed with rain"), LightRain }, |
|
{ QStringLiteral("drizzle or freezing drizzle"), LightRain }, |
|
{ QStringLiteral("drizzle or rain"), LightRain }, |
|
{ QStringLiteral("flurries"), Flurries }, |
|
{ QStringLiteral("flurries at times heavy"), Flurries }, |
|
{ QStringLiteral("flurries at times heavy or rain snowers"), RainSnow }, |
|
{ QStringLiteral("flurries mixed with ice pellets"), FreezingRain }, |
|
{ QStringLiteral("flurries or ice pellets"), FreezingRain }, |
|
{ QStringLiteral("flurries or rain showers"), RainSnow }, |
|
{ QStringLiteral("flurries or thundershowers"), Flurries }, |
|
{ QStringLiteral("fog"), Mist }, |
|
{ QStringLiteral("fog developing"), Mist }, |
|
{ QStringLiteral("fog dissipating"), Mist }, |
|
{ QStringLiteral("fog patches"), Mist }, |
|
{ QStringLiteral("freezing drizzle"), FreezingDrizzle }, |
|
{ QStringLiteral("freezing rain"), FreezingRain }, |
|
{ QStringLiteral("freezing rain mixed with rain"), FreezingRain }, |
|
{ QStringLiteral("freezing rain mixed with snow"), FreezingRain }, |
|
{ QStringLiteral("freezing rain or ice pellets"), FreezingRain }, |
|
{ QStringLiteral("freezing rain or rain"), FreezingRain }, |
|
{ QStringLiteral("freezing rain or snow"), FreezingRain }, |
|
{ QStringLiteral("ice fog"), Mist }, |
|
{ QStringLiteral("ice fog developing"), Mist }, |
|
{ QStringLiteral("ice fog dissipating"), Mist }, |
|
{ QStringLiteral("ice pellets"), Hail }, |
|
{ QStringLiteral("ice pellets mixed with freezing rain"), Hail }, |
|
{ QStringLiteral("ice pellets mixed with snow"), Hail }, |
|
{ QStringLiteral("ice pellets or snow"), RainSnow }, |
|
{ QStringLiteral("light snow"), LightSnow }, |
|
{ QStringLiteral("light snow and blizzard"), LightSnow }, |
|
{ QStringLiteral("light snow and blizzard and blowing snow"), Snow }, |
|
{ QStringLiteral("light snow and blowing snow"), LightSnow }, |
|
{ QStringLiteral("light snow mixed with freezing drizzle"), FreezingDrizzle }, |
|
{ QStringLiteral("light snow mixed with freezing rain"), FreezingRain }, |
|
{ QStringLiteral("light snow or ice pellets"), LightSnow }, |
|
{ QStringLiteral("light snow or rain"), RainSnow }, |
|
{ QStringLiteral("light wet snow"), RainSnow }, |
|
{ QStringLiteral("light wet snow or rain"), RainSnow }, |
|
{ QStringLiteral("local snow squalls"), Snow }, |
|
{ QStringLiteral("near blizzard"), Snow }, |
|
{ QStringLiteral("overcast"), Overcast }, |
|
{ QStringLiteral("increasing cloudiness"), Overcast }, |
|
{ QStringLiteral("increasing clouds"), Overcast }, |
|
{ QStringLiteral("periods of drizzle"), LightRain }, |
|
{ QStringLiteral("periods of drizzle mixed with freezing drizzle"), FreezingDrizzle }, |
|
{ QStringLiteral("periods of drizzle mixed with rain"), LightRain }, |
|
{ QStringLiteral("periods of drizzle or freezing drizzle"), FreezingDrizzle }, |
|
{ QStringLiteral("periods of drizzle or rain"), LightRain }, |
|
{ QStringLiteral("periods of freezing drizzle"), FreezingDrizzle }, |
|
{ QStringLiteral("periods of freezing drizzle or drizzle"), FreezingDrizzle }, |
|
{ QStringLiteral("periods of freezing drizzle or rain"), FreezingDrizzle }, |
|
{ QStringLiteral("periods of freezing rain"), FreezingRain }, |
|
{ QStringLiteral("periods of freezing rain mixed with ice pellets"), FreezingRain }, |
|
{ QStringLiteral("periods of freezing rain mixed with rain"), FreezingRain }, |
|
{ QStringLiteral("periods of freezing rain mixed with snow"), FreezingRain }, |
|
{ QStringLiteral("periods of freezing rain mixed with freezing drizzle"), FreezingRain }, |
|
{ QStringLiteral("periods of freezing rain or ice pellets"), FreezingRain }, |
|
{ QStringLiteral("periods of freezing rain or rain"), FreezingRain }, |
|
{ QStringLiteral("periods of freezing rain or snow"), FreezingRain }, |
|
{ QStringLiteral("periods of ice pellets"), Hail }, |
|
{ QStringLiteral("periods of ice pellets mixed with freezing rain"), Hail }, |
|
{ QStringLiteral("periods of ice pellets mixed with snow"), Hail }, |
|
{ QStringLiteral("periods of ice pellets or freezing rain"), Hail }, |
|
{ QStringLiteral("periods of ice pellets or snow"), Hail }, |
|
{ QStringLiteral("periods of light snow"), LightSnow }, |
|
{ QStringLiteral("periods of light snow and blizzard"), Snow }, |
|
{ QStringLiteral("periods of light snow and blizzard and blowing snow"), Snow }, |
|
{ QStringLiteral("periods of light snow and blowing snow"), LightSnow }, |
|
{ QStringLiteral("periods of light snow mixed with freezing drizzle"), RainSnow }, |
|
{ QStringLiteral("periods of light snow mixed with freezing rain"), RainSnow }, |
|
{ QStringLiteral("periods of light snow mixed with ice pellets"), LightSnow }, |
|
{ QStringLiteral("periods of light snow mixed with rain"), RainSnow }, |
|
{ QStringLiteral("periods of light snow or freezing drizzle"), RainSnow }, |
|
{ QStringLiteral("periods of light snow or freezing rain"), RainSnow }, |
|
{ QStringLiteral("periods of light snow or ice pellets"), LightSnow }, |
|
{ QStringLiteral("periods of light snow or rain"), RainSnow }, |
|
{ QStringLiteral("periods of light wet snow"), LightSnow }, |
|
{ QStringLiteral("periods of light wet snow mixed with rain"), RainSnow }, |
|
{ QStringLiteral("periods of light wet snow or rain"), RainSnow }, |
|
{ QStringLiteral("periods of rain"), Rain }, |
|
{ QStringLiteral("periods of rain mixed with freezing rain"), Rain }, |
|
{ QStringLiteral("periods of rain mixed with snow"), RainSnow }, |
|
{ QStringLiteral("periods of rain or drizzle"), Rain }, |
|
{ QStringLiteral("periods of rain or freezing rain"), Rain }, |
|
{ QStringLiteral("periods of rain or thundershowers"), Showers }, |
|
{ QStringLiteral("periods of rain or thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("periods of rain or snow"), RainSnow }, |
|
{ QStringLiteral("periods of snow"), Snow }, |
|
{ QStringLiteral("periods of snow and blizzard"), Snow }, |
|
{ QStringLiteral("periods of snow and blizzard and blowing snow"), Snow }, |
|
{ QStringLiteral("periods of snow and blowing snow"), Snow }, |
|
{ QStringLiteral("periods of snow mixed with freezing drizzle"), RainSnow }, |
|
{ QStringLiteral("periods of snow mixed with freezing rain"), RainSnow }, |
|
{ QStringLiteral("periods of snow mixed with ice pellets"), Snow }, |
|
{ QStringLiteral("periods of snow mixed with rain"), RainSnow }, |
|
{ QStringLiteral("periods of snow or freezing drizzle"), RainSnow }, |
|
{ QStringLiteral("periods of snow or freezing rain"), RainSnow }, |
|
{ QStringLiteral("periods of snow or ice pellets"), Snow }, |
|
{ QStringLiteral("periods of snow or rain"), RainSnow }, |
|
{ QStringLiteral("periods of rain or snow"), RainSnow }, |
|
{ QStringLiteral("periods of wet snow"), Snow }, |
|
{ QStringLiteral("periods of wet snow mixed with rain"), RainSnow }, |
|
{ QStringLiteral("periods of wet snow or rain"), RainSnow }, |
|
{ QStringLiteral("rain"), Rain }, |
|
{ QStringLiteral("rain at times heavy"), Rain }, |
|
{ QStringLiteral("rain at times heavy mixed with freezing rain"), FreezingRain }, |
|
{ QStringLiteral("rain at times heavy mixed with snow"), RainSnow }, |
|
{ QStringLiteral("rain at times heavy or drizzle"), Rain }, |
|
{ QStringLiteral("rain at times heavy or freezing rain"), Rain }, |
|
{ QStringLiteral("rain at times heavy or snow"), RainSnow }, |
|
{ QStringLiteral("rain at times heavy or thundershowers"), Showers }, |
|
{ QStringLiteral("rain at times heavy or thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("rain mixed with freezing rain"), FreezingRain }, |
|
{ QStringLiteral("rain mixed with snow"), RainSnow }, |
|
{ QStringLiteral("rain or drizzle"), Rain }, |
|
{ QStringLiteral("rain or freezing rain"), Rain }, |
|
{ QStringLiteral("rain or snow"), RainSnow }, |
|
{ QStringLiteral("rain or thundershowers"), Showers }, |
|
{ QStringLiteral("rain or thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("rain showers or flurries"), RainSnow }, |
|
{ QStringLiteral("rain showers or wet flurries"), RainSnow }, |
|
{ QStringLiteral("showers"), Showers }, |
|
{ QStringLiteral("showers at times heavy"), Showers }, |
|
{ QStringLiteral("showers at times heavy or thundershowers"), Showers }, |
|
{ QStringLiteral("showers at times heavy or thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("showers or drizzle"), Showers }, |
|
{ QStringLiteral("showers or thundershowers"), Thunderstorm }, |
|
{ QStringLiteral("showers or thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("smoke"), NotAvailable }, |
|
{ QStringLiteral("snow"), Snow }, |
|
{ QStringLiteral("snow and blizzard"), Snow }, |
|
{ QStringLiteral("snow and blizzard and blowing snow"), Snow }, |
|
{ QStringLiteral("snow and blowing snow"), Snow }, |
|
{ QStringLiteral("snow at times heavy"), Snow }, |
|
{ QStringLiteral("snow at times heavy and blizzard"), Snow }, |
|
{ QStringLiteral("snow at times heavy and blowing snow"), Snow }, |
|
{ QStringLiteral("snow at times heavy mixed with freezing drizzle"), RainSnow }, |
|
{ QStringLiteral("snow at times heavy mixed with freezing rain"), RainSnow }, |
|
{ QStringLiteral("snow at times heavy mixed with ice pellets"), Snow }, |
|
{ QStringLiteral("snow at times heavy mixed with rain"), RainSnow }, |
|
{ QStringLiteral("snow at times heavy or freezing rain"), RainSnow }, |
|
{ QStringLiteral("snow at times heavy or ice pellets"), Snow }, |
|
{ QStringLiteral("snow at times heavy or rain"), RainSnow }, |
|
{ QStringLiteral("snow mixed with freezing drizzle"), RainSnow }, |
|
{ QStringLiteral("snow mixed with freezing rain"), RainSnow }, |
|
{ QStringLiteral("snow mixed with ice pellets"), Snow }, |
|
{ QStringLiteral("snow mixed with rain"), RainSnow }, |
|
{ QStringLiteral("snow or freezing drizzle"), RainSnow }, |
|
{ QStringLiteral("snow or freezing rain"), RainSnow }, |
|
{ QStringLiteral("snow or ice pellets"), Snow }, |
|
{ QStringLiteral("snow or rain"), RainSnow }, |
|
{ QStringLiteral("snow squalls"), Snow }, |
|
{ QStringLiteral("sunny"), ClearDay }, |
|
{ QStringLiteral("sunny with cloudy periods"), PartlyCloudyDay }, |
|
{ QStringLiteral("thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("thunderstorms and possible hail"), Thunderstorm }, |
|
{ QStringLiteral("wet flurries"), Flurries }, |
|
{ QStringLiteral("wet flurries at times heavy"), Flurries }, |
|
{ QStringLiteral("wet flurries at times heavy or rain snowers"), RainSnow }, |
|
{ QStringLiteral("wet flurries or rain showers"), RainSnow }, |
|
{ QStringLiteral("wet snow"), Snow }, |
|
{ QStringLiteral("wet snow at times heavy"), Snow }, |
|
{ QStringLiteral("wet snow at times heavy mixed with rain"), RainSnow }, |
|
{ QStringLiteral("wet snow mixed with rain"), RainSnow }, |
|
{ QStringLiteral("wet snow or rain"), RainSnow }, |
|
{ QStringLiteral("windy"), NotAvailable }, |
|
|
|
{ QStringLiteral("chance of drizzle mixed with freezing drizzle"), LightRain }, |
|
{ QStringLiteral("chance of flurries mixed with ice pellets"), Flurries }, |
|
{ QStringLiteral("chance of flurries or ice pellets"), Flurries }, |
|
{ QStringLiteral("chance of flurries or rain showers"), RainSnow }, |
|
{ QStringLiteral("chance of flurries or thundershowers"), RainSnow }, |
|
{ QStringLiteral("chance of freezing drizzle"), FreezingDrizzle }, |
|
{ QStringLiteral("chance of freezing rain"), FreezingRain }, |
|
{ QStringLiteral("chance of freezing rain mixed with snow"), RainSnow }, |
|
{ QStringLiteral("chance of freezing rain or rain"), FreezingRain }, |
|
{ QStringLiteral("chance of freezing rain or snow"), RainSnow }, |
|
{ QStringLiteral("chance of light snow and blowing snow"), LightSnow }, |
|
{ QStringLiteral("chance of light snow mixed with freezing drizzle"), LightSnow }, |
|
{ QStringLiteral("chance of light snow mixed with ice pellets"), LightSnow }, |
|
{ QStringLiteral("chance of light snow mixed with rain"), RainSnow }, |
|
{ QStringLiteral("chance of light snow or freezing rain"), RainSnow }, |
|
{ QStringLiteral("chance of light snow or ice pellets"), LightSnow }, |
|
{ QStringLiteral("chance of light snow or rain"), RainSnow }, |
|
{ QStringLiteral("chance of light wet snow"), Snow }, |
|
{ QStringLiteral("chance of rain"), Rain }, |
|
{ QStringLiteral("chance of rain at times heavy"), Rain }, |
|
{ QStringLiteral("chance of rain mixed with snow"), RainSnow }, |
|
{ QStringLiteral("chance of rain or drizzle"), Rain }, |
|
{ QStringLiteral("chance of rain or freezing rain"), Rain }, |
|
{ QStringLiteral("chance of rain or snow"), RainSnow }, |
|
{ QStringLiteral("chance of rain showers or flurries"), RainSnow }, |
|
{ QStringLiteral("chance of rain showers or wet flurries"), RainSnow }, |
|
{ QStringLiteral("chance of severe thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("chance of showers at times heavy"), Rain }, |
|
{ QStringLiteral("chance of showers at times heavy or thundershowers"), Thunderstorm }, |
|
{ QStringLiteral("chance of showers at times heavy or thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("chance of showers or thundershowers"), Thunderstorm }, |
|
{ QStringLiteral("chance of showers or thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("chance of snow"), Snow }, |
|
{ QStringLiteral("chance of snow and blizzard"), Snow }, |
|
{ QStringLiteral("chance of snow mixed with freezing drizzle"), Snow }, |
|
{ QStringLiteral("chance of snow mixed with freezing rain"), RainSnow }, |
|
{ QStringLiteral("chance of snow mixed with rain"), RainSnow }, |
|
{ QStringLiteral("chance of snow or rain"), RainSnow }, |
|
{ QStringLiteral("chance of snow squalls"), Snow }, |
|
{ QStringLiteral("chance of thundershowers"), Showers }, |
|
{ QStringLiteral("chance of thunderstorms"), Thunderstorm }, |
|
{ QStringLiteral("chance of thunderstorms and possible hail"), Thunderstorm }, |
|
{ QStringLiteral("chance of wet flurries"), Flurries }, |
|
{ QStringLiteral("chance of wet flurries at times heavy"), Flurries }, |
|
{ QStringLiteral("chance of wet flurries or rain showers"), RainSnow }, |
|
{ QStringLiteral("chance of wet snow"), Snow }, |
|
{ QStringLiteral("chance of wet snow mixed with rain"), RainSnow }, |
|
{ QStringLiteral("chance of wet snow or rain"), RainSnow }, |
|
}; |
|
} |
|
|
|
QMap<QString, IonInterface::ConditionIcons> const& EnvCanadaIon::conditionIcons() const |
|
{ |
|
static QMap<QString, ConditionIcons> const condval = setupConditionIconMappings(); |
|
return condval; |
|
} |
|
|
|
QMap<QString, IonInterface::ConditionIcons> const& EnvCanadaIon::forecastIcons() const |
|
{ |
|
static QMap<QString, ConditionIcons> const foreval = setupForecastIconMappings(); |
|
return foreval; |
|
} |
|
|
|
QStringList EnvCanadaIon::validate(const QString& source) const |
|
{ |
|
QStringList placeList; |
|
|
|
QString sourceNormalized = source.toUpper(); |
|
QHash<QString, EnvCanadaIon::XMLMapInfo>::const_iterator it = m_places.constBegin(); |
|
while (it != m_places.constEnd()) { |
|
if (it.key().toUpper().contains(sourceNormalized)) { |
|
placeList.append(QStringLiteral("place|") + it.key()); |
|
} |
|
++it; |
|
} |
|
|
|
placeList.sort(); |
|
return placeList; |
|
} |
|
|
|
// Get a specific Ion's data |
|
bool EnvCanadaIon::updateIonSource(const QString& source) |
|
{ |
|
//qCDebug(IONENGINE_ENVCAN) << "updateIonSource()" << source; |
|
|
|
// We expect the applet to send the source in the following tokenization: |
|
// ionname|validate|place_name - Triggers validation of place |
|
// ionname|weather|place_name - Triggers receiving weather of place |
|
|
|
const QStringList sourceAction = source.split(QLatin1Char('|')); |
|
|
|
// Guard: if the size of array is not 2 then we have bad data, return an error |
|
if (sourceAction.size() < 2) { |
|
setData(source, QStringLiteral("validate"), QStringLiteral("envcan|malformed")); |
|
return true; |
|
} |
|
|
|
if (sourceAction[1] == QLatin1String("validate") && sourceAction.size() > 2) { |
|
const QStringList result = validate(sourceAction[2]); |
|
|
|
const QString reply = |
|
(result.size() == 1) ? QStringLiteral("envcan|valid|single|") + result[0] : |
|
(result.size() > 1) ? QStringLiteral("envcan|valid|multiple|") + result.join(QLatin1Char('|')) : |
|
/*else*/ QStringLiteral("envcan|invalid|single|") + sourceAction[2]; |
|
setData(source, QStringLiteral("validate"), reply); |
|
|
|
return true; |
|
|
|
} |
|
if (sourceAction[1] == QLatin1String("weather") && sourceAction.size() > 2) { |
|
getXMLData(source); |
|
return true; |
|
} |
|
setData(source, QStringLiteral("validate"), QStringLiteral("envcan|malformed")); |
|
return true; |
|
} |
|
|
|
// Parses city list and gets the correct city based on ID number |
|
void EnvCanadaIon::getXMLSetup() |
|
{ |
|
//qCDebug(IONENGINE_ENVCAN) << "getXMLSetup()"; |
|
|
|
// If network is down, we need to spin and wait |
|
|
|
const QUrl url(QStringLiteral("http://dd.weatheroffice.ec.gc.ca/citypage_weather/xml/siteList.xml")); |
|
|
|
KIO::TransferJob* getJob = KIO::get(url, KIO::NoReload, KIO::HideProgressInfo); |
|
|
|
m_xmlSetup.clear(); |
|
connect(getJob, &KIO::TransferJob::data, |
|
this, &EnvCanadaIon::setup_slotDataArrived); |
|
connect(getJob, &KJob::result, |
|
this, &EnvCanadaIon::setup_slotJobFinished); |
|
} |
|
|
|
// Gets specific city XML data |
|
void EnvCanadaIon::getXMLData(const QString& source) |
|
{ |
|
for (const QString& fetching : qAsConst(m_jobList)) { |
|
if (fetching == source) { |
|
// already getting this source and awaiting the data |
|
return; |
|
} |
|
} |
|
|
|
//qCDebug(IONENGINE_ENVCAN) << source; |
|
|
|
// Demunge source name for key only. |
|
QString dataKey = source; |
|
dataKey.remove(QStringLiteral("envcan|weather|")); |
|
const XMLMapInfo& place = m_places[dataKey]; |
|
|
|
const QUrl url(QLatin1String("http://dd.weatheroffice.ec.gc.ca/citypage_weather/xml/") + place.territoryName + QLatin1Char('/') + place.cityCode + QStringLiteral("_e.xml")); |
|
//url="file:///home/spstarr/Desktop/s0000649_e.xml"; |
|
//qCDebug(IONENGINE_ENVCAN) << "Will Try URL: " << url; |
|
|
|
if (place.territoryName.isEmpty() && place.cityCode.isEmpty()) { |
|
setData(source, QStringLiteral("validate"), QStringLiteral("envcan|malformed")); |
|
return; |
|
} |
|
|
|
KIO::TransferJob* getJob = KIO::get(url, KIO::Reload, KIO::HideProgressInfo); |
|
|
|
m_jobXml.insert(getJob, new QXmlStreamReader); |
|
m_jobList.insert(getJob, source); |
|
|
|
connect(getJob, &KIO::TransferJob::data, |
|
this, &EnvCanadaIon::slotDataArrived); |
|
connect(getJob, &KJob::result, |
|
this, &EnvCanadaIon::slotJobFinished); |
|
} |
|
|
|
void EnvCanadaIon::setup_slotDataArrived(KIO::Job *job, const QByteArray &data) |
|
{ |
|
Q_UNUSED(job) |
|
|
|
if (data.isEmpty()) { |
|
//qCDebug(IONENGINE_ENVCAN) << "done!"; |
|
return; |
|
} |
|
|
|
// Send to xml. |
|
//qCDebug(IONENGINE_ENVCAN) << data; |
|
m_xmlSetup.addData(data); |
|
} |
|
|
|
void EnvCanadaIon::slotDataArrived(KIO::Job *job, const QByteArray &data) |
|
{ |
|
|
|
if (data.isEmpty() || !m_jobXml.contains(job)) { |
|
return; |
|
} |
|
|
|
// Send to xml. |
|
m_jobXml[job]->addData(data); |
|
} |
|
|
|
void EnvCanadaIon::slotJobFinished(KJob *job) |
|
{ |
|
// Dual use method, if we're fetching location data to parse we need to do this first |
|
const QString source = m_jobList.value(job); |
|
//qCDebug(IONENGINE_ENVCAN) << source << m_sourcesToReset.contains(source); |
|
setData(source, Data()); |
|
QXmlStreamReader *reader = m_jobXml.value(job); |
|
if (reader) { |
|
readXMLData(m_jobList[job], *reader); |
|
} |
|
|
|
m_jobList.remove(job); |
|
delete m_jobXml[job]; |
|
m_jobXml.remove(job); |
|
|
|
if (m_sourcesToReset.contains(source)) { |
|
m_sourcesToReset.removeAll(source); |
|
|
|
// so the weather engine updates it's data |
|
forceImmediateUpdateOfAllVisualizations(); |
|
|
|
// update the clients of our engine |
|
emit forceUpdate(this, source); |
|
} |
|
} |
|
|
|
void EnvCanadaIon::setup_slotJobFinished(KJob *job) |
|
{ |
|
Q_UNUSED(job) |
|
const bool success = readXMLSetup(); |
|
m_xmlSetup.clear(); |
|
//qCDebug(IONENGINE_ENVCAN) << success << m_sourcesToReset; |
|
setInitialized(success); |
|
} |
|
|
|
// Parse the city list and store into a QMap |
|
bool EnvCanadaIon::readXMLSetup() |
|
{ |
|
bool success = false; |
|
QString territory; |
|
QString code; |
|
QString cityName; |
|
|
|
//qCDebug(IONENGINE_ENVCAN) << "readXMLSetup()"; |
|
|
|
while (!m_xmlSetup.atEnd()) { |
|
m_xmlSetup.readNext(); |
|
|
|
const QStringRef elementName = m_xmlSetup.name(); |
|
|
|
if (m_xmlSetup.isStartElement()) { |
|
|
|
// XML ID code to match filename |
|
if (elementName == QLatin1String("site")) { |
|
code = m_xmlSetup.attributes().value(QStringLiteral("code")).toString(); |
|
} |
|
|
|
if (elementName == QLatin1String("nameEn")) { |
|
cityName = m_xmlSetup.readElementText(); // Name of cities |
|
} |
|
|
|
if (elementName == QLatin1String("provinceCode")) { |
|
territory = m_xmlSetup.readElementText(); // Provinces/Territory list |
|
} |
|
} |
|
|
|
if (m_xmlSetup.isEndElement() && elementName == QLatin1String("site")) { |
|
EnvCanadaIon::XMLMapInfo info; |
|
QString tmp = cityName + QStringLiteral(", ") + territory; // Build the key name. |
|
|
|
// Set the mappings |
|
info.cityCode = code; |
|
info.territoryName = territory; |
|
info.cityName = cityName; |
|
|
|
// Set the string list, we will use for the applet to display the available cities. |
|
m_places[tmp] = info; |
|
success = true; |
|
} |
|
|
|
} |
|
|
|
return (success && !m_xmlSetup.error()); |
|
} |
|
|
|
void EnvCanadaIon::parseWeatherSite(WeatherData& data, QXmlStreamReader& xml) |
|
{ |
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("license")) { |
|
data.creditUrl = xml.readElementText(); |
|
} else if (elementName == QLatin1String("location")) { |
|
parseLocations(data, xml); |
|
} else if (elementName == QLatin1String("warnings")) { |
|
// Cleanup warning list on update |
|
data.warnings.clear(); |
|
data.watches.clear(); |
|
parseWarnings(data, xml); |
|
} else if (elementName == QLatin1String("currentConditions")) { |
|
parseConditions(data, xml); |
|
} else if (elementName == QLatin1String("forecastGroup")) { |
|
// Clean up forecast list on update |
|
data.forecasts.clear(); |
|
parseWeatherForecast(data, xml); |
|
} else if (elementName == QLatin1String("yesterdayConditions")) { |
|
parseYesterdayWeather(data, xml); |
|
} else if (elementName == QLatin1String("riseSet")) { |
|
parseAstronomicals(data, xml); |
|
} else if (elementName == QLatin1String("almanac")) { |
|
parseWeatherRecords(data, xml); |
|
} else { |
|
parseUnknownElement(xml); |
|
} |
|
} |
|
} |
|
} |
|
|
|
// Parse Weather data main loop, from here we have to descend into each tag pair |
|
bool EnvCanadaIon::readXMLData(const QString& source, QXmlStreamReader& xml) |
|
{ |
|
WeatherData data; |
|
|
|
//qCDebug(IONENGINE_ENVCAN) << "readXMLData()"; |
|
|
|
QString dataKey = source; |
|
dataKey.remove(QStringLiteral("envcan|weather|")); |
|
data.shortTerritoryName = m_places[dataKey].territoryName; |
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
if (xml.isEndElement()) { |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
if (xml.name() == QLatin1String("siteData")) { |
|
parseWeatherSite(data, xml); |
|
} else { |
|
parseUnknownElement(xml); |
|
} |
|
} |
|
} |
|
|
|
bool solarDataSourceNeedsConnect = false; |
|
Plasma::DataEngine* timeEngine = dataEngine(QStringLiteral("time")); |
|
if (timeEngine) { |
|
const bool canCalculateElevation = |
|
(data.observationDateTime.isValid() && |
|
(!qIsNaN(data.stationLatitude) && !qIsNaN(data.stationLongitude))); |
|
if (canCalculateElevation) { |
|
data.solarDataTimeEngineSourceName = QStringLiteral("%1|Solar|Latitude=%2|Longitude=%3|DateTime=%4") |
|
.arg(QString::fromUtf8(data.observationDateTime.timeZone().id())) |
|
.arg(data.stationLatitude) |
|
.arg(data.stationLongitude) |
|
.arg(data.observationDateTime.toString(Qt::ISODate)); |
|
solarDataSourceNeedsConnect = true; |
|
} |
|
|
|
// check any previous data |
|
const auto it = m_weatherData.constFind(source); |
|
if (it != m_weatherData.constEnd()) { |
|
const QString& oldSolarDataTimeEngineSource = it.value().solarDataTimeEngineSourceName; |
|
|
|
if (oldSolarDataTimeEngineSource == data.solarDataTimeEngineSourceName) { |
|
// can reuse elevation source (if any), copy over data |
|
data.isNight = it.value().isNight; |
|
solarDataSourceNeedsConnect = false; |
|
} else if (!oldSolarDataTimeEngineSource.isEmpty()) { |
|
// drop old elevation source |
|
timeEngine->disconnectSource(oldSolarDataTimeEngineSource, this); |
|
} |
|
} |
|
} |
|
|
|
m_weatherData[source] = data; |
|
|
|
// connect only after m_weatherData has the data, so the instant data push handling can see it |
|
if (solarDataSourceNeedsConnect) { |
|
timeEngine->connectSource(data.solarDataTimeEngineSourceName, this); |
|
} else { |
|
updateWeather(source); |
|
} |
|
|
|
return !xml.error(); |
|
} |
|
|
|
void EnvCanadaIon::parseFloat(float& value, QXmlStreamReader& xml) |
|
{ |
|
bool ok = false; |
|
const float result = xml.readElementText().toFloat(&ok); |
|
if (ok) { |
|
value = result; |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseDateTime(WeatherData& data, QXmlStreamReader& xml, WeatherData::WeatherEvent *event) |
|
{ |
|
|
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("dateTime")); |
|
|
|
// What kind of date info is this? |
|
const QString dateType = xml.attributes().value(QStringLiteral("name")).toString(); |
|
const QString dateZone = xml.attributes().value(QStringLiteral("zone")).toString(); |
|
const QString dateUtcOffset = xml.attributes().value(QStringLiteral("UTCOffset")).toString(); |
|
|
|
QString selectTimeStamp; |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
if (xml.isEndElement()) { |
|
break; |
|
} |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isStartElement()) { |
|
if (dateType == QLatin1String("xmlCreation")) { |
|
return; |
|
} |
|
if (dateZone == QLatin1String("UTC")) { |
|
return; |
|
} |
|
if (elementName == QLatin1String("year")) { |
|
xml.readElementText(); |
|
} else if (elementName == QLatin1String("month")) { |
|
xml.readElementText(); |
|
} else if (elementName == QLatin1String("day")) { |
|
xml.readElementText(); |
|
} else if (elementName == QLatin1String("hour")) |
|
xml.readElementText(); |
|
else if (elementName == QLatin1String("minute")) |
|
xml.readElementText(); |
|
else if (elementName == QLatin1String("timeStamp")) |
|
selectTimeStamp = xml.readElementText(); |
|
else if (elementName == QLatin1String("textSummary")) { |
|
if (dateType == QLatin1String("eventIssue")) { |
|
if (event) { |
|
event->timestamp = xml.readElementText(); |
|
} |
|
} else if (dateType == QLatin1String("observation")) { |
|
xml.readElementText(); |
|
QDateTime observationDateTime = QDateTime::fromString(selectTimeStamp, QStringLiteral("yyyyMMddHHmmss")); |
|
QTimeZone timeZone = QTimeZone(dateZone.toUtf8()); |
|
// if timezone id not recognized, fallback to utcoffset |
|
if (!timeZone.isValid()) { |
|
timeZone = QTimeZone(dateUtcOffset.toInt() * 3600); |
|
} |
|
if (observationDateTime.isValid() && timeZone.isValid()) { |
|
data.observationDateTime = observationDateTime; |
|
data.observationDateTime.setTimeZone(timeZone); |
|
} |
|
data.obsTimestamp = observationDateTime.toString(QStringLiteral("dd.MM.yyyy @ hh:mm")); |
|
} else if (dateType == QLatin1String("forecastIssue")) { |
|
data.forecastTimestamp = xml.readElementText(); |
|
} else if (dateType == QLatin1String("sunrise")) { |
|
data.sunriseTimestamp = xml.readElementText(); |
|
} else if (dateType == QLatin1String("sunset")) { |
|
data.sunsetTimestamp = xml.readElementText(); |
|
} else if (dateType == QLatin1String("moonrise")) { |
|
data.moonriseTimestamp = xml.readElementText(); |
|
} else if (dateType == QLatin1String("moonset")) { |
|
data.moonsetTimestamp = xml.readElementText(); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseLocations(WeatherData& data, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("location")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
if (xml.isEndElement()) { |
|
break; |
|
} |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("country")) { |
|
data.countryName = xml.readElementText(); |
|
} else if (elementName == QLatin1String("province") || elementName == QLatin1String("territory")) { |
|
data.longTerritoryName = xml.readElementText(); |
|
} else if (elementName == QLatin1String("name")) { |
|
data.cityName = xml.readElementText(); |
|
} else if (elementName == QLatin1String("region")) { |
|
data.regionName = xml.readElementText(); |
|
} else { |
|
parseUnknownElement(xml); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseWindInfo(WeatherData& data, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("wind")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
if (xml.isEndElement()) { |
|
break; |
|
} |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("speed")) { |
|
parseFloat(data.windSpeed, xml); |
|
} else if (elementName == QLatin1String("gust")) { |
|
parseFloat(data.windGust, xml); |
|
} else if (elementName == QLatin1String("direction")) { |
|
data.windDirection = xml.readElementText(); |
|
} else if (elementName == QLatin1String("bearing")) { |
|
data.windDegrees = xml.attributes().value(QStringLiteral("degrees")).toString(); |
|
} else { |
|
parseUnknownElement(xml); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseConditions(WeatherData& data, QXmlStreamReader& xml) |
|
{ |
|
|
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("currentConditions")); |
|
data.temperature = qQNaN(); |
|
data.dewpoint = qQNaN(); |
|
data.condition = i18n("N/A"); |
|
data.humidex.clear(); |
|
data.stationID = i18n("N/A"); |
|
data.stationLatitude = qQNaN(); |
|
data.stationLongitude = qQNaN(); |
|
data.pressure = qQNaN(); |
|
data.visibility = qQNaN(); |
|
data.humidity = qQNaN(); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("currentConditions")) |
|
break; |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("station")) { |
|
data.stationID = xml.attributes().value(QStringLiteral("code")).toString(); |
|
QRegularExpression dumpDirection(QStringLiteral("[^0-9.]")); |
|
data.stationLatitude = xml.attributes().value(QStringLiteral("lat")).toString().remove(dumpDirection).toDouble(); |
|
data.stationLongitude = xml.attributes().value(QStringLiteral("lon")).toString().remove(dumpDirection).toDouble(); |
|
} else if (elementName == QLatin1String("dateTime")) { |
|
parseDateTime(data, xml); |
|
} else if (elementName == QLatin1String("condition")) { |
|
data.condition = xml.readElementText().trimmed(); |
|
} else if (elementName == QLatin1String("temperature")) { |
|
// prevent N/A text to result in 0.0 value |
|
parseFloat(data.temperature, xml); |
|
} else if (elementName == QLatin1String("dewpoint")) { |
|
// prevent N/A text to result in 0.0 value |
|
parseFloat(data.dewpoint, xml); |
|
} else if (elementName == QLatin1String("humidex")) { |
|
data.humidex = xml.readElementText(); |
|
} else if (elementName == QLatin1String("windChill")) { |
|
// prevent N/A text to result in 0.0 value |
|
parseFloat(data.windchill, xml); |
|
} else if (elementName == QLatin1String("pressure")) { |
|
data.pressureTendency = xml.attributes().value(QStringLiteral("tendency")).toString(); |
|
if (data.pressureTendency.isEmpty()) { |
|
data.pressureTendency = QStringLiteral("steady"); |
|
} |
|
parseFloat(data.pressure, xml); |
|
} else if (elementName == QLatin1String("visibility")) { |
|
parseFloat(data.visibility, xml); |
|
} else if (elementName == QLatin1String("relativeHumidity")) { |
|
parseFloat(data.humidity, xml); |
|
} else if (elementName == QLatin1String("wind")) { |
|
parseWindInfo(data, xml); |
|
} |
|
//} else { |
|
// parseUnknownElement(xml); |
|
//} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseWarnings(WeatherData &data, QXmlStreamReader& xml) |
|
{ |
|
WeatherData::WeatherEvent *watch = new WeatherData::WeatherEvent; |
|
WeatherData::WeatherEvent *warning = new WeatherData::WeatherEvent; |
|
|
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("warnings")); |
|
QString eventURL = xml.attributes().value(QStringLiteral("url")).toString(); |
|
int flag = 0; |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("warnings")) { |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("dateTime")) { |
|
if (flag == 1) { |
|
parseDateTime(data, xml, watch); |
|
} |
|
if (flag == 2) { |
|
parseDateTime(data, xml, warning); |
|
} |
|
|
|
if (!warning->timestamp.isEmpty() && !warning->url.isEmpty()) { |
|
data.warnings.append(warning); |
|
warning = new WeatherData::WeatherEvent; |
|
} |
|
if (!watch->timestamp.isEmpty() && !watch->url.isEmpty()) { |
|
data.watches.append(watch); |
|
watch = new WeatherData::WeatherEvent; |
|
} |
|
|
|
} else if (elementName == QLatin1String("event")) { |
|
// Append new event to list. |
|
QString eventType = xml.attributes().value(QStringLiteral("type")).toString(); |
|
if (eventType == QLatin1String("watch")) { |
|
watch->url = eventURL; |
|
watch->type = eventType; |
|
watch->priority = xml.attributes().value(QStringLiteral("priority")).toString(); |
|
watch->description = xml.attributes().value(QStringLiteral("description")).toString(); |
|
flag = 1; |
|
} |
|
|
|
if (eventType == QLatin1String("warning")) { |
|
warning->url = eventURL; |
|
warning->type = eventType; |
|
warning->priority = xml.attributes().value(QStringLiteral("priority")).toString(); |
|
warning->description = xml.attributes().value(QStringLiteral("description")).toString(); |
|
flag = 2; |
|
} |
|
} else { |
|
if (xml.name() != QLatin1String("dateTime")) { |
|
parseUnknownElement(xml); |
|
} |
|
} |
|
} |
|
} |
|
delete watch; |
|
delete warning; |
|
} |
|
|
|
|
|
void EnvCanadaIon::parseWeatherForecast(WeatherData& data, QXmlStreamReader& xml) |
|
{ |
|
WeatherData::ForecastInfo* forecast = new WeatherData::ForecastInfo; |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("forecastGroup")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("forecastGroup")) { |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("dateTime")) { |
|
parseDateTime(data, xml); |
|
} else if (elementName == QLatin1String("regionalNormals")) { |
|
parseRegionalNormals(data, xml); |
|
} else if (elementName == QLatin1String("forecast")) { |
|
parseForecast(data, xml, forecast); |
|
forecast = new WeatherData::ForecastInfo; |
|
} else { |
|
parseUnknownElement(xml); |
|
} |
|
} |
|
} |
|
delete forecast; |
|
} |
|
|
|
void EnvCanadaIon::parseRegionalNormals(WeatherData& data, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("regionalNormals")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
if (xml.isEndElement()) { |
|
break; |
|
} |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("textSummary")) { |
|
xml.readElementText(); |
|
} else if (elementName == QLatin1String("temperature") && xml.attributes().value(QStringLiteral("class")) == QLatin1String("high")) { |
|
// prevent N/A text to result in 0.0 value |
|
parseFloat(data.normalHigh, xml); |
|
} else if (elementName == QLatin1String("temperature") && xml.attributes().value(QStringLiteral("class")) == QLatin1String("low")) { |
|
// prevent N/A text to result in 0.0 value |
|
parseFloat(data.normalLow, xml); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseForecast(WeatherData& data, QXmlStreamReader& xml, WeatherData::ForecastInfo *forecast) |
|
{ |
|
|
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("forecast")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("forecast")) { |
|
data.forecasts.append(forecast); |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("period")) { |
|
forecast->forecastPeriod = xml.attributes().value(QStringLiteral("textForecastName")).toString(); |
|
} else if (elementName == QLatin1String("textSummary")) { |
|
forecast->forecastSummary = xml.readElementText(); |
|
} else if (elementName == QLatin1String("abbreviatedForecast")) { |
|
parseShortForecast(forecast, xml); |
|
} else if (elementName == QLatin1String("temperatures")) { |
|
parseForecastTemperatures(forecast, xml); |
|
} else if (elementName == QLatin1String("winds")) { |
|
parseWindForecast(forecast, xml); |
|
} else if (elementName == QLatin1String("precipitation")) { |
|
parsePrecipitationForecast(forecast, xml); |
|
} else if (elementName == QLatin1String("uv")) { |
|
data.UVRating = xml.attributes().value(QStringLiteral("category")).toString(); |
|
parseUVIndex(data, xml); |
|
// else if (elementName == QLatin1String("frost")) { FIXME: Wait until winter to see what this looks like. |
|
// parseFrost(xml, forecast); |
|
} else { |
|
if (elementName != QLatin1String("forecast")) { |
|
parseUnknownElement(xml); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseShortForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("abbreviatedForecast")); |
|
|
|
QString shortText; |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("abbreviatedForecast")) { |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("pop")) { |
|
parseFloat(forecast->popPrecent, xml); |
|
} |
|
if (elementName == QLatin1String("textSummary")) { |
|
shortText = xml.readElementText(); |
|
QMap<QString, ConditionIcons> forecastList = forecastIcons(); |
|
if ((forecast->forecastPeriod == QLatin1String("tonight")) || |
|
(forecast->forecastPeriod.contains(QLatin1String("night")))) { |
|
forecastList.insert(QStringLiteral("a few clouds"), FewCloudsNight); |
|
forecastList.insert(QStringLiteral("cloudy periods"), PartlyCloudyNight); |
|
forecastList.insert(QStringLiteral("chance of drizzle mixed with rain"), ChanceShowersNight); |
|
forecastList.insert(QStringLiteral("chance of drizzle"), ChanceShowersNight); |
|
forecastList.insert(QStringLiteral("chance of drizzle or rain"), ChanceShowersNight); |
|
forecastList.insert(QStringLiteral("chance of flurries"), ChanceSnowNight); |
|
forecastList.insert(QStringLiteral("chance of light snow"), ChanceSnowNight); |
|
forecastList.insert(QStringLiteral("chance of flurries at times heavy"), ChanceSnowNight); |
|
forecastList.insert(QStringLiteral("chance of showers or drizzle"), ChanceShowersNight); |
|
forecastList.insert(QStringLiteral("chance of showers"), ChanceShowersNight); |
|
forecastList.insert(QStringLiteral("clearing"), ClearNight); |
|
} else { |
|
forecastList.insert(QStringLiteral("a few clouds"), FewCloudsDay); |
|
forecastList.insert(QStringLiteral("cloudy periods"), PartlyCloudyDay); |
|
forecastList.insert(QStringLiteral("chance of drizzle mixed with rain"), ChanceShowersDay); |
|
forecastList.insert(QStringLiteral("chance of drizzle"), ChanceShowersDay); |
|
forecastList.insert(QStringLiteral("chance of drizzle or rain"), ChanceShowersDay); |
|
forecastList.insert(QStringLiteral("chance of flurries"), ChanceSnowDay); |
|
forecastList.insert(QStringLiteral("chance of light snow"), ChanceSnowDay); |
|
forecastList.insert(QStringLiteral("chance of flurries at times heavy"), ChanceSnowDay); |
|
forecastList.insert(QStringLiteral("chance of showers or drizzle"), ChanceShowersDay); |
|
forecastList.insert(QStringLiteral("chance of showers"), ChanceShowersDay); |
|
forecastList.insert(QStringLiteral("clearing"), ClearDay); |
|
} |
|
forecast->shortForecast = shortText; |
|
forecast->iconName = getWeatherIcon(forecastList, shortText.toLower()); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseUVIndex(WeatherData& data, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("uv")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("uv")) { |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("index")) { |
|
data.UVIndex = xml.readElementText(); |
|
} |
|
if (elementName == QLatin1String("textSummary")) { |
|
xml.readElementText(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseForecastTemperatures(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("temperatures")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("temperatures")) { |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("temperature") && xml.attributes().value(QStringLiteral("class")) == QLatin1String("low")) { |
|
parseFloat(forecast->tempLow, xml); |
|
} else if (elementName == QLatin1String("temperature") && xml.attributes().value(QStringLiteral("class")) == QLatin1String("high")) { |
|
parseFloat(forecast->tempHigh, xml); |
|
} else if (elementName == QLatin1String("textSummary")) { |
|
xml.readElementText(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parsePrecipitationForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("precipitation")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("precipitation")) { |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("textSummary")) { |
|
forecast->precipForecast = xml.readElementText(); |
|
} else if (elementName == QLatin1String("precipType")) { |
|
forecast->precipType = xml.readElementText(); |
|
} else if (elementName == QLatin1String("accumulation")) { |
|
parsePrecipTotals(forecast, xml); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parsePrecipTotals(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("accumulation")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("accumulation")) { |
|
break; |
|
} |
|
|
|
if (elementName == QLatin1String("name")) { |
|
xml.readElementText(); |
|
} else if (elementName == QLatin1String("amount")) { |
|
forecast->precipTotalExpected = xml.readElementText(); |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseWindForecast(WeatherData::ForecastInfo *forecast, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("winds")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("winds")) { |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("textSummary")) { |
|
forecast->windForecast = xml.readElementText(); |
|
} else { |
|
if (xml.name() != QLatin1String("winds")) { |
|
parseUnknownElement(xml); |
|
} |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseYesterdayWeather(WeatherData& data, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("yesterdayConditions")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
if (xml.isEndElement()) { |
|
break; |
|
} |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("temperature") && xml.attributes().value(QStringLiteral("class")) == QLatin1String("high")) { |
|
parseFloat(data.prevHigh, xml); |
|
} else if (elementName == QLatin1String("temperature") && xml.attributes().value(QStringLiteral("class")) == QLatin1String("low")) { |
|
parseFloat(data.prevLow, xml); |
|
} else if (elementName == QLatin1String("precip")) { |
|
data.prevPrecipType = xml.attributes().value(QStringLiteral("units")).toString(); |
|
if (data.prevPrecipType.isEmpty()) { |
|
data.prevPrecipType = QString::number(KUnitConversion::NoUnit); |
|
} |
|
data.prevPrecipTotal = xml.readElementText(); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseWeatherRecords(WeatherData& data, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("almanac")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("almanac")) { |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("temperature") && xml.attributes().value(QStringLiteral("class")) == QLatin1String("extremeMax")) { |
|
parseFloat(data.recordHigh, xml); |
|
} else if (elementName == QLatin1String("temperature") && xml.attributes().value(QStringLiteral("class")) == QLatin1String("extremeMin")) { |
|
parseFloat(data.recordLow, xml); |
|
} else if (elementName == QLatin1String("precipitation") && xml.attributes().value(QStringLiteral("class")) == QLatin1String("extremeRainfall")) { |
|
parseFloat(data.recordRain, xml); |
|
} else if (elementName == QLatin1String("precipitation") && xml.attributes().value(QStringLiteral("class")) == QLatin1String("extremeSnowfall")) { |
|
parseFloat(data.recordSnow, xml); |
|
} |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::parseAstronomicals(WeatherData& data, QXmlStreamReader& xml) |
|
{ |
|
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("riseSet")); |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
const QStringRef elementName = xml.name(); |
|
|
|
if (xml.isEndElement() && elementName == QLatin1String("riseSet")) { |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
if (elementName == QLatin1String("disclaimer")) { |
|
xml.readElementText(); |
|
} else if (elementName == QLatin1String("dateTime")) { |
|
parseDateTime(data, xml); |
|
} |
|
} |
|
} |
|
} |
|
|
|
// handle when no XML tag is found |
|
void EnvCanadaIon::parseUnknownElement(QXmlStreamReader& xml) const |
|
{ |
|
|
|
while (!xml.atEnd()) { |
|
xml.readNext(); |
|
|
|
if (xml.isEndElement()) { |
|
break; |
|
} |
|
|
|
if (xml.isStartElement()) { |
|
parseUnknownElement(xml); |
|
} |
|
} |
|
} |
|
|
|
void EnvCanadaIon::updateWeather(const QString& source) |
|
{ |
|
//qCDebug(IONENGINE_ENVCAN) << "updateWeather()"; |
|
|
|
const WeatherData& weatherData = m_weatherData[source]; |
|
|
|
Plasma::DataEngine::Data data; |
|
|
|
data.insert(QStringLiteral("Country"), weatherData.countryName); |
|
data.insert(QStringLiteral("Place"), QVariant(weatherData.cityName + QStringLiteral(", ") + weatherData.shortTerritoryName)); |
|
data.insert(QStringLiteral("Region"), weatherData.regionName); |
|
|
|
data.insert(QStringLiteral("Station"), weatherData.stationID.isEmpty() ? i18n("N/A") : weatherData.stationID.toUpper()); |
|
|
|
const bool stationCoordValid = (!qIsNaN(weatherData.stationLatitude) && !qIsNaN(weatherData.stationLongitude)); |
|
|
|
if (stationCoordValid) { |
|
data.insert(QStringLiteral("Latitude"), weatherData.stationLatitude); |
|
data.insert(QStringLiteral("Longitude"), weatherData.stationLongitude); |
|
} |
|
|
|
// Real weather - Current conditions |
|
if (weatherData.observationDateTime.isValid()) { |
|
data.insert(QStringLiteral("Observation Timestamp"), weatherData.observationDateTime); |
|
} |
|
|
|
data.insert(QStringLiteral("Observation Period"), weatherData.obsTimestamp); |
|
|
|
if (!weatherData.condition.isEmpty()) { |
|
data.insert(QStringLiteral("Current Conditions"), i18nc("weather condition", weatherData.condition.toUtf8().data())); |
|
} |
|
//qCDebug(IONENGINE_ENVCAN) << "i18n condition string: " << qPrintable(condition(source)); |
|
|
|
QMap<QString, ConditionIcons> conditionList = conditionIcons(); |
|
|
|
if (weatherData.isNight) { |
|
conditionList.insert(QStringLiteral("decreasing cloud"), FewCloudsNight); |
|
conditionList.insert(QStringLiteral("mostly cloudy"), PartlyCloudyNight); |
|
conditionList.insert(QStringLiteral("partly cloudy"), PartlyCloudyNight); |
|
conditionList.insert(QStringLiteral("fair"), FewCloudsNight); |
|
} else { |
|
conditionList.insert(QStringLiteral("decreasing cloud"), FewCloudsDay); |
|
conditionList.insert(QStringLiteral("mostly cloudy"), PartlyCloudyDay); |
|
conditionList.insert(QStringLiteral("partly cloudy"), PartlyCloudyDay); |
|
conditionList.insert(QStringLiteral("fair"), FewCloudsDay); |
|
} |
|
|
|
data.insert(QStringLiteral("Condition Icon"), getWeatherIcon(conditionList, weatherData.condition)); |
|
|
|
if (!qIsNaN(weatherData.temperature)) { |
|
data.insert(QStringLiteral("Temperature"), weatherData.temperature); |
|
} |
|
if (!qIsNaN(weatherData.windchill)) { |
|
data.insert(QStringLiteral("Windchill"), weatherData.windchill); |
|
} |
|
if (!weatherData.humidex.isEmpty()) { |
|
data.insert(QStringLiteral("Humidex"), weatherData.humidex); |
|
} |
|
|
|
// Used for all temperatures |
|
data.insert(QStringLiteral("Temperature Unit"), KUnitConversion::Celsius); |
|
|
|
if (!qIsNaN(weatherData.dewpoint)) { |
|
data.insert(QStringLiteral("Dewpoint"), weatherData.dewpoint); |
|
} |
|
|
|
if (!qIsNaN(weatherData.pressure)) { |
|
data.insert(QStringLiteral("Pressure"), weatherData.pressure); |
|
data.insert(QStringLiteral("Pressure Unit"), KUnitConversion::Kilopascal); |
|
data.insert(QStringLiteral("Pressure Tendency"), weatherData.pressureTendency); |
|
} |
|
|
|
if (!qIsNaN(weatherData.visibility)) { |
|
data.insert(QStringLiteral("Visibility"), weatherData.visibility); |
|
data.insert(QStringLiteral("Visibility Unit"), KUnitConversion::Kilometer); |
|
} |
|
|
|
if (!qIsNaN(weatherData.humidity)) { |
|
data.insert(QStringLiteral("Humidity"), weatherData.humidity); |
|
data.insert(QStringLiteral("Humidity Unit"), KUnitConversion::Percent); |
|
} |
|
|
|
if (!qIsNaN(weatherData.windSpeed)) { |
|
data.insert(QStringLiteral("Wind Speed"), weatherData.windSpeed); |
|
} |
|
if (!qIsNaN(weatherData.windGust)) { |
|
data.insert(QStringLiteral("Wind Gust"), weatherData.windGust); |
|
} |
|
|
|
if (!qIsNaN(weatherData.windSpeed) || !qIsNaN(weatherData.windGust)) { |
|
data.insert(QStringLiteral("Wind Speed Unit"), KUnitConversion::KilometerPerHour); |
|
} |
|
|
|
if (!qIsNaN(weatherData.windSpeed) && static_cast<int>(weatherData.windSpeed) == 0) { |
|
data.insert(QStringLiteral("Wind Direction"), QStringLiteral("VR")); // Variable/calm |
|
} else if (!weatherData.windDirection.isEmpty()) { |
|
data.insert(QStringLiteral("Wind Direction"), weatherData.windDirection); |
|
} |
|
|
|
if (!qIsNaN(weatherData.normalHigh)) { |
|
data.insert(QStringLiteral("Normal High"), weatherData.normalHigh); |
|
} |
|
if (!qIsNaN(weatherData.normalLow)) { |
|
data.insert(QStringLiteral("Normal Low"), weatherData.normalLow); |
|
} |
|
|
|
// Check if UV index is available for the location |
|
if (!weatherData.UVIndex.isEmpty()) { |
|
data.insert(QStringLiteral("UV Index"), weatherData.UVIndex); |
|
} |
|
if (!weatherData.UVRating.isEmpty()) { |
|
data.insert(QStringLiteral("UV Rating"), weatherData.UVRating); |
|
} |
|
|
|
const QVector<WeatherData::WeatherEvent*>& watches = weatherData.watches; |
|
|
|
// Set number of forecasts per day/night supported |
|
data.insert(QStringLiteral("Total Watches Issued"), watches.size()); |
|
|
|
// Check if we have warnings or watches |
|
for (int i = 0; i < watches.size(); ++i) { |
|
const WeatherData::WeatherEvent* watch = watches.at(i); |
|
const QString number = QString::number(i); |
|
|
|
data.insert(QStringLiteral("Watch Priority ") + number, watch->priority); |
|
data.insert(QStringLiteral("Watch Description ") + number, watch->description); |
|
data.insert(QStringLiteral("Watch Info ") + number, watch->url); |
|
data.insert(QStringLiteral("Watch Timestamp ") + number, watch->timestamp); |
|
} |
|
|
|
const QVector<WeatherData::WeatherEvent*>& warnings = weatherData.warnings; |
|
|
|
data.insert(QStringLiteral("Total Warnings Issued"), warnings.size()); |
|
|
|
for (int k = 0; k < warnings.size(); ++k) { |
|
const WeatherData::WeatherEvent* warning = warnings.at(k); |
|
const QString number = QString::number(k); |
|
|
|
data.insert(QStringLiteral("Warning Priority ") + number, warning->priority); |
|
data.insert(QStringLiteral("Warning Description ") + number, warning->description); |
|
data.insert(QStringLiteral("Warning Info ") + number, warning->url); |
|
data.insert(QStringLiteral("Warning Timestamp ") + number, warning->timestamp); |
|
} |
|
|
|
const QVector <WeatherData::ForecastInfo *>& forecasts = weatherData.forecasts; |
|
|
|
// Set number of forecasts per day/night supported |
|
data.insert(QStringLiteral("Total Weather Days"), forecasts.size()); |
|
|
|
int i = 0; |
|
for (const WeatherData::ForecastInfo* forecastInfo : forecasts) { |
|
|
|
QString forecastPeriod = forecastInfo->forecastPeriod; |
|
if (forecastPeriod.isEmpty()) { |
|
forecastPeriod = i18n("N/A"); |
|
} else { |
|
// We need to shortform the day/night strings. |
|
|
|
forecastPeriod.replace(QStringLiteral("Today"), i18n("day")); |
|
forecastPeriod.replace(QStringLiteral("Tonight"), i18nc("Short for tonight", "nite")); |
|
forecastPeriod.replace(QStringLiteral("night"), i18nc("Short for night, appended to the end of the weekday", "nt")); |
|
forecastPeriod.replace(QStringLiteral("Saturday"), i18nc("Short for Saturday", "Sat")); |
|
forecastPeriod.replace(QStringLiteral("Sunday"), i18nc("Short for Sunday", "Sun")); |
|
forecastPeriod.replace(QStringLiteral("Monday"), i18nc("Short for Monday", "Mon")); |
|
forecastPeriod.replace(QStringLiteral("Tuesday"), i18nc("Short for Tuesday", "Tue")); |
|
forecastPeriod.replace(QStringLiteral("Wednesday"), i18nc("Short for Wednesday", "Wed")); |
|
forecastPeriod.replace(QStringLiteral("Thursday"), i18nc("Short for Thursday", "Thu")); |
|
forecastPeriod.replace(QStringLiteral("Friday"), i18nc("Short for Friday", "Fri")); |
|
} |
|
const QString shortForecast = forecastInfo->shortForecast.isEmpty() ? i18n("N/A") : |
|
i18nc("weather forecast", forecastInfo->shortForecast.toUtf8().data()); |
|
|
|
const QString tempHigh = qIsNaN(forecastInfo->tempHigh) ? QString() : QString::number(forecastInfo->tempHigh); |
|
const QString tempLow = qIsNaN(forecastInfo->tempLow) ? QString() : QString::number(forecastInfo->tempLow); |
|
const QString popPrecent = qIsNaN(forecastInfo->popPrecent) ? QString() : QString::number(forecastInfo->popPrecent); |
|
|
|
data.insert(QStringLiteral("Short Forecast Day %1").arg(i), |
|
QStringLiteral("%1|%2|%3|%4|%5|%6").arg( |
|
forecastPeriod, |
|
forecastInfo->iconName, |
|
shortForecast, |
|
tempHigh, |
|
tempLow, |
|
popPrecent)); |
|
//qCDebug(IONENGINE_ENVCAN) << "i18n summary string: " << qPrintable(i18n(forecastInfo->shortForecast.toUtf8())); |
|
|
|
/* |
|
data.insert(QString("Long Forecast Day %1").arg(i), QString("%1|%2|%3|%4|%5|%6|%7|%8") \ |
|
.arg(fieldList[0]).arg(fieldList[2]).arg(fieldList[3]).arg(fieldList[4]).arg(fieldList[6]) \ |
|
.arg(fieldList[7]).arg(fieldList[8]).arg(fieldList[9])); |
|
*/ |
|
++i; |
|
} |
|
|
|
// yesterday |
|
if (!qIsNaN(weatherData.prevHigh)) { |
|
data.insert(QStringLiteral("Yesterday High"), weatherData.prevHigh); |
|
} |
|
if (!qIsNaN(weatherData.prevLow)) { |
|
data.insert(QStringLiteral("Yesterday Low"), weatherData.prevLow); |
|
} |
|
|
|
const QString& prevPrecipTotal = weatherData.prevPrecipTotal; |
|
if (prevPrecipTotal == QLatin1String("Trace")) { |
|
data.insert(QStringLiteral("Yesterday Precip Total"), i18nc("precipitation total, very little", "Trace")); |
|
} else if (!prevPrecipTotal.isEmpty()) { |
|
data.insert(QStringLiteral("Yesterday Precip Total"), prevPrecipTotal); |
|
const QString& prevPrecipType = weatherData.prevPrecipType; |
|
const KUnitConversion::UnitId unit = |
|
(prevPrecipType == QLatin1String("mm")) ? KUnitConversion::Millimeter : |
|
(prevPrecipType == QLatin1String("cm")) ? KUnitConversion::Centimeter : |
|
/*else*/ KUnitConversion::NoUnit; |
|
data.insert(QStringLiteral("Yesterday Precip Unit"), unit); |
|
} |
|
|
|
// records |
|
if (!qIsNaN(weatherData.recordHigh)) { |
|
data.insert(QStringLiteral("Record High Temperature"), weatherData.recordHigh); |
|
} |
|
if (!qIsNaN(weatherData.recordLow)) { |
|
data.insert(QStringLiteral("Record Low Temperature"), weatherData.recordLow); |
|
} |
|
if (!qIsNaN(weatherData.recordRain)) { |
|
data.insert(QStringLiteral("Record Rainfall"), weatherData.recordRain); |
|
data.insert(QStringLiteral("Record Rainfall Unit"), KUnitConversion::Millimeter); |
|
} |
|
if (!qIsNaN(weatherData.recordSnow)) { |
|
data.insert(QStringLiteral("Record Snowfall"), weatherData.recordSnow); |
|
data.insert(QStringLiteral("Record Snowfall Unit"), KUnitConversion::Centimeter); |
|
} |
|
|
|
data.insert(QStringLiteral("Credit"), i18nc("credit line, keep string short", "Data from Environment and Climate Change\302\240Canada")); |
|
data.insert(QStringLiteral("Credit Url"), weatherData.creditUrl); |
|
setData(source, data); |
|
} |
|
|
|
void EnvCanadaIon::dataUpdated(const QString& sourceName, const Plasma::DataEngine::Data& data) |
|
{ |
|
const bool isNight = (data.value(QStringLiteral("Corrected Elevation")).toDouble() < 0.0); |
|
|
|
for (auto end = m_weatherData.end(), it = m_weatherData.begin(); it != end; ++it) { |
|
auto& weatherData = it.value(); |
|
if (weatherData.solarDataTimeEngineSourceName == sourceName) { |
|
weatherData.isNight = isNight; |
|
updateWeather(it.key()); |
|
} |
|
} |
|
} |
|
|
|
|
|
K_EXPORT_PLASMA_DATAENGINE_WITH_JSON(envcan, EnvCanadaIon, "ion-envcan.json") |
|
|
|
#include "ion_envcan.moc"
|
|
|