[weather] Use night icons for observation data where possible

As the time dataengine can no longer be queried sync in Plasma5 days,
do the needed async stateful dance.
parent e3db65d7
......@@ -701,6 +701,7 @@ void UKMETIon::parseWeatherObservation(const QString& source, WeatherData& data,
bool UKMETIon::readObservationXMLData(const QString& source, QXmlStreamReader& xml)
{
WeatherData data;
data.isForecastsDataPending = true;
bool haveObservation = false;
while (!xml.atEnd()) {
xml.readNext();
......@@ -723,8 +724,45 @@ bool UKMETIon::readObservationXMLData(const QString& source, QXmlStreamReader& x
if (!haveObservation) {
return false;
}
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("Local|Solar|Latitude=%1|Longitude=%2|DateTime=%3")
.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) {
data.isSolarDataPending = true;
timeEngine->connectSource(data.solarDataTimeEngineSourceName, this);
}
// Get the 5 day forecast info next.
getFiveDayForecast(source);
......@@ -759,7 +797,8 @@ void UKMETIon::parseFiveDayForecast(const QString& source, QXmlStreamReader& xml
{
Q_ASSERT(xml.isStartElement() && xml.name() == QLatin1String("item"));
QVector<WeatherData::ForecastInfo*>& forecasts = m_weatherData[source].forecasts;
WeatherData& weatherData = m_weatherData[source];
QVector<WeatherData::ForecastInfo*>& forecasts = weatherData.forecasts;
// Flush out the old forecasts when updating.
forecasts.clear();
......@@ -802,6 +841,9 @@ void UKMETIon::parseFiveDayForecast(const QString& source, QXmlStreamReader& xml
forecast = new WeatherData::ForecastInfo;
}
}
weatherData.isForecastsDataPending = false;
// remove unused
delete forecast;
}
......@@ -844,6 +886,12 @@ void UKMETIon::validate(const QString& source)
void UKMETIon::updateWeather(const QString& source)
{
const WeatherData& weatherData = m_weatherData[source];
if (weatherData.isForecastsDataPending || weatherData.isSolarDataPending) {
return;
}
const XMLMapInfo& place = m_place[source];
QString weatherSource = source;
......@@ -851,8 +899,6 @@ void UKMETIon::updateWeather(const QString& source)
weatherSource.replace(QStringLiteral("bbcukmet|"), QStringLiteral("bbcukmet|weather|"));
weatherSource.append(QLatin1Char('|') + place.XMLurl);
const WeatherData& weatherData = m_weatherData[source];
Plasma::DataEngine::Data data;
data.insert(QStringLiteral("Place"), weatherData.stationName);
......@@ -876,21 +922,7 @@ void UKMETIon::updateWeather(const QString& source)
data.insert(QStringLiteral("Longitude"), weatherData.stationLongitude);
}
bool useDayIcon = true;
// TODO: get timeengine's solarsystem code to use directly
#if 0
if (weatherData.observationDateTime.isValid() && stationCoordsValid) {
PlasmaWeather::Sun sun;
sun.setPosition(weatherData.stationLatitude, weatherData.stationLongitude);
const int offset = weatherData.observationDateTime.timeZone().offsetFromUtc(weatherData.observationDateTime);
sun.calcForDateTime(weatherData.observationDateTime, offset);
const auto elevation = sun.calcElevation();
// Tell applet which icon to use for conditions and provide mapping for condition type to the icons to display
useDayIcon = (elevation >= 0.0);
}
#endif
data.insert(QStringLiteral("Condition Icon"), getWeatherIcon(useDayIcon ? dayIcons() : nightIcons(), weatherData.condition));
data.insert(QStringLiteral("Condition Icon"), getWeatherIcon(weatherData.isNight ? nightIcons() : dayIcons(), weatherData.condition));
if (!qIsNaN(weatherData.humidity)) {
data.insert(QStringLiteral("Humidity"), weatherData.humidity);
......@@ -966,6 +998,19 @@ void UKMETIon::updateWeather(const QString& source)
setData(weatherSource, data);
}
void UKMETIon::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;
weatherData.isSolarDataPending = false;
updateWeather(it.key());
}
}
}
K_EXPORT_PLASMA_DATAENGINE_WITH_JSON(bbcukmet, UKMETIon, "ion-bbcukmet.json")
......
......@@ -61,6 +61,10 @@ public:
QString pressureTendency;
QString visibilityStr;
QString solarDataTimeEngineSourceName;
bool isNight = false;
bool isSolarDataPending = false;
// Five day forecast
struct ForecastInfo {
ForecastInfo();
......@@ -75,6 +79,8 @@ public:
// 5 day Forecast
QVector <WeatherData::ForecastInfo *> forecasts;
bool isForecastsDataPending = false;
};
Q_DECLARE_TYPEINFO(WeatherData::ForecastInfo, Q_MOVABLE_TYPE);
......@@ -92,6 +98,10 @@ public:
public: // IonInterface API
bool updateIonSource(const QString& source) override;
public Q_SLOTS:
// for solar data pushes from the time engine
void dataUpdated(const QString& sourceName, const Plasma::DataEngine::Data& data);
protected: // IonInterface API
void reset() override;
......
......@@ -731,8 +731,45 @@ bool EnvCanadaIon::readXMLData(const QString& source, QXmlStreamReader& 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("Local|Solar|Latitude=%1|Longitude=%2|DateTime=%3")
.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;
updateWeather(source);
// 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();
}
......@@ -1405,23 +1442,9 @@ void EnvCanadaIon::updateWeather(const QString& source)
}
//qCDebug(IONENGINE_ENVCAN) << "i18n condition string: " << qPrintable(condition(source));
bool useDayIcon = true;
// TODO: get timeengine's solarsystem code to use directly
#if 0
if (weatherData.observationDateTime.isValid() && stationCoordValid) {
PlasmaWeather::Sun sun;
sun.setPosition(weatherData.stationLatitude, weatherData.stationLongitude);
const int offset = weatherData.observationDateTime.timeZone().offsetFromUtc(weatherData.observationDateTime);
sun.calcForDateTime(weatherData.observationDateTime, offset);
const auto elevation = sun.calcElevation();
// Tell applet which icon to use for conditions and provide mapping for condition type to the icons to display
useDayIcon = (elevation >= 0.0);
}
#endif
QMap<QString, ConditionIcons> conditionList = conditionIcons();
if (!useDayIcon) {
if (weatherData.isNight) {
conditionList.insert(QStringLiteral("decreasing cloud"), FewCloudsNight);
conditionList.insert(QStringLiteral("mostly cloudy"), PartlyCloudyNight);
conditionList.insert(QStringLiteral("partly cloudy"), PartlyCloudyNight);
......@@ -1622,6 +1645,19 @@ void EnvCanadaIon::updateWeather(const QString& source)
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")
......
......@@ -133,6 +133,9 @@ public:
float recordLow;
float recordRain;
float recordSnow;
QString solarDataTimeEngineSourceName;
bool isNight = false;
};
Q_DECLARE_TYPEINFO(WeatherData::WeatherEvent, Q_MOVABLE_TYPE);
......@@ -153,6 +156,10 @@ public:
public: // IonInterface API
bool updateIonSource(const QString& source) override;
public Q_SLOTS:
// for solar data pushes from the time engine
void dataUpdated(const QString& sourceName, const Plasma::DataEngine::Data& data);
protected: // IonInterface API
void reset() override;
......
......@@ -466,6 +466,7 @@ void NOAAIon::parseWeatherSite(WeatherData& data, QXmlStreamReader& xml)
bool NOAAIon::readXMLData(const QString& source, QXmlStreamReader& xml)
{
WeatherData data;
data.isForecastsDataPending = true;
while (!xml.atEnd()) {
xml.readNext();
......@@ -483,7 +484,44 @@ bool NOAAIon::readXMLData(const QString& source, QXmlStreamReader& 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("Local|Solar|Latitude=%1|Longitude=%2|DateTime=%3")
.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) {
data.isSolarDataPending = true;
timeEngine->connectSource(data.solarDataTimeEngineSourceName, this);
}
return !xml.error();
}
......@@ -508,6 +546,10 @@ void NOAAIon::updateWeather(const QString& source)
{
const WeatherData& weatherData = m_weatherData[source];
if (weatherData.isForecastsDataPending || weatherData.isSolarDataPending) {
return;
}
Plasma::DataEngine::Data data;
data.insert(QStringLiteral("Country"), QStringLiteral("USA"));
......@@ -528,23 +570,8 @@ void NOAAIon::updateWeather(const QString& source)
data.insert(QStringLiteral("Current Conditions"), conditionI18n);
qCDebug(IONENGINE_NOAA) << "i18n condition string: " << qPrintable(conditionI18n);
bool useDayIcon = true;
// TODO: get timeengine's solarsystem code to use directly
#if 0
if (weatherData.observationDateTime.isValid() && stationCoordValid) {
PlasmaWeather::Sun sun;
sun.setPosition(weatherData.stationLatitude, weatherData.stationLongitude);
const int offset = weatherData.observationDateTime.timeZone().offsetFromUtc(weatherData.observationDateTime);
sun.calcForDateTime(weatherData.observationDateTime, offset);
const auto elevation = sun.calcElevation();
// Tell applet which icon to use for conditions and provide mapping for condition type to the icons to display
useDayIcon = (elevation >= 0.0);
}
#endif
const QString weather = weatherData.weather.toLower();
ConditionIcons condition = getConditionIcon(weather, useDayIcon);
ConditionIcons condition = getConditionIcon(weather, !weatherData.isNight);
data.insert(QStringLiteral("Condition Icon"), getWeatherIcon(condition));
if (!qIsNaN(weatherData.temperature_F)) {
......@@ -792,7 +819,8 @@ void NOAAIon::forecast_slotJobFinished(KJob *job)
void NOAAIon::readForecast(const QString& source, QXmlStreamReader& xml)
{
QVector<WeatherData::Forecast>& forecasts = m_weatherData[source].forecasts;
WeatherData& weatherData = m_weatherData[source];
QVector<WeatherData::Forecast>& forecasts = weatherData.forecasts;
// Clear the current forecasts
forecasts.clear();
......@@ -875,8 +903,25 @@ void NOAAIon::readForecast(const QString& source, QXmlStreamReader& xml)
}
}
}
weatherData.isForecastsDataPending = false;
}
void NOAAIon::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;
weatherData.isSolarDataPending = false;
updateWeather(it.key());
}
}
}
K_EXPORT_PLASMA_DATAENGINE_WITH_JSON(noaa, NOAAIon, "ion-noaa.json")
#include "ion_noaa.moc"
......@@ -78,6 +78,12 @@ public:
QString high;
};
QVector<Forecast> forecasts;
bool isForecastsDataPending = false;
QString solarDataTimeEngineSourceName;
bool isNight = false;
bool isSolarDataPending = false;
};
Q_DECLARE_TYPEINFO(WeatherData::Forecast, Q_MOVABLE_TYPE);
......@@ -95,6 +101,10 @@ public:
public: // IonInterface API
bool updateIonSource(const QString& source) override;
public Q_SLOTS:
// for solar data pushes from the time engine
void dataUpdated(const QString& sourceName, const Plasma::DataEngine::Data& data);
protected: // IonInterface API
void reset() override;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment