Commit 879abee0 authored by Friedrich W. H. Kossebau's avatar Friedrich W. H. Kossebau
Browse files

[weather applet] Port away from libplasmaweather

parent f28640fc
......@@ -8,8 +8,8 @@ add_library(plasma_applet_weather MODULE ${weatherapplet_SRCS})
kcoreaddons_desktop_to_json(plasma_applet_weather package/metadata.desktop SERVICE_TYPES plasma-applet.desktop)
target_link_libraries(plasma_applet_weather
plasmaweather
KF5::Plasma
KF5::Notifications
KF5::UnitConversion
KF5::IconThemes
KF5::I18n
......@@ -32,7 +32,7 @@ set(weather_SRCS
add_library(weatherplugin SHARED ${weather_SRCS})
target_link_libraries(weatherplugin
plasmaweather
KF5::Plasma
KF5::UnitConversion
KF5::I18n
Qt5::Qml
......
/*
* Copyright 2009 Petri Damstén <damu@iki.fi>
* Copyright 2016 Friedrich W. H. Kossebau <kossebau@kde.org>
* Copyright 2016, 2018 Friedrich W. H. Kossebau <kossebau@kde.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
......@@ -18,8 +18,6 @@
#include "locationlistmodel.h"
#include <plasmaweather/weathervalidator.h>
#include <Plasma/DataContainer>
#include <Plasma/DataEngine>
......@@ -27,6 +25,68 @@
#include <QDebug>
WeatherValidator::WeatherValidator(Plasma::DataEngine* weatherDataengine, const QString& ionName,
QObject* parent)
: QObject(parent)
, m_weatherDataEngine(weatherDataengine)
, m_ionName(ionName)
{
}
WeatherValidator::~WeatherValidator() = default;
void WeatherValidator::validate(const QString& location)
{
const QString validationSource = m_ionName + QLatin1String("|validate|") + location;
m_weatherDataEngine->connectSource(validationSource, this);
}
void WeatherValidator::dataUpdated(const QString& source, const Plasma::DataEngine::Data& data)
{
QMap<QString, QString> locationSources;
m_weatherDataEngine->disconnectSource(source, this);
const auto validationResult = data[QStringLiteral("validate")].toString().split(QLatin1Char('|'));
if (validationResult.size() < 2) {
emit error(i18n("Cannot find '%1' using %2.", source, m_ionName));
} else if (validationResult[1] == QLatin1String("valid") && validationResult.size() > 2) {
const QString weatherSourcePrefix = validationResult[0] + QLatin1String("|weather|");
int i = 3;
const int lastFieldIndex = validationResult.size() - 1;
while (i < lastFieldIndex) {
if (validationResult[i] == QLatin1String("place")) {
const QString& name = validationResult[i + 1];
QString locationSource;
if (i + 2 < lastFieldIndex && validationResult[i + 2] == QLatin1String("extra")) {
const QString& id = validationResult[i + 3];
locationSource = weatherSourcePrefix + name + QLatin1Char('|') + id;
i += 4;
} else {
locationSource = weatherSourcePrefix + name;
i += 2;
}
locationSources.insert(name, locationSource);
} else {
++i;
}
}
} else if (validationResult[1] == QLatin1String("timeout")) {
emit error(i18n("Connection to %1 weather server timed out.", m_ionName));
} else {
const QString searchTerm = validationResult.size() > 3 ? validationResult[3] : source;
emit error(i18n("Cannot find '%1' using %2.", searchTerm, m_ionName));
}
emit finished(locationSources);
}
LocationListModel::LocationListModel(QObject *parent)
: QAbstractListModel(parent)
, m_validatingInput(false)
......@@ -120,18 +180,16 @@ void LocationListModel::searchLocations(const QString &searchString, const QStri
//qDebug() << "ion: " << pluginInfo[0] << pluginInfo[1];
//d->ions.insert(pluginInfo[1], pluginInfo[0]);
auto* validator = new Plasma::WeatherValidator(this);
connect(validator, &Plasma::WeatherValidator::error, this, &LocationListModel::validatorError);
connect(validator, &Plasma::WeatherValidator::finished, this, &LocationListModel::addSources);
validator->setDataEngine(dataengine);
validator->setIon(ionId);
auto* validator = new WeatherValidator(dataengine, ionId, this);
connect(validator, &WeatherValidator::error, this, &LocationListModel::validatorError);
connect(validator, &WeatherValidator::finished, this, &LocationListModel::addSources);
m_validators.append(validator);
}
}
for (auto* validator : qAsConst(m_validators)) {
validator->validate(m_searchString, true);
validator->validate(m_searchString);
}
}
......
......@@ -19,14 +19,44 @@
#define LOCATIONLISTMODEL_H
#include <Plasma/DataEngineConsumer>
#include <Plasma/DataEngine>
#include <QAbstractListModel>
#include <QVector>
#include <QMap>
namespace Plasma {
class WeatherValidator;
}
class WeatherValidator : public QObject
{
Q_OBJECT
public:
WeatherValidator(Plasma::DataEngine* weatherDataengine, const QString& ionName, QObject* parent = nullptr);
~WeatherValidator() override;
/**
* @param location the name of the location to find
*/
void validate(const QString& location);
Q_SIGNALS:
/**
* Emitted when an error in validation occurs
**/
void error(const QString& message);
/**
* Emitted when validation is done
* @param sources a mapping of user-friendly names to the DataEngine source
**/
void finished(const QMap<QString, QString>& sources);
public Q_SLOTS: // callback for the weather dataengine
void dataUpdated(const QString& source, const Plasma::DataEngine::Data& data);
private:
Plasma::DataEngine* m_weatherDataEngine;
QString m_ionName;
};
class LocationItem
{
......@@ -82,7 +112,7 @@ private:
bool m_validatingInput;
QString m_searchString;
int m_checkedInCount;
QVector<Plasma::WeatherValidator*> m_validators;
QVector<WeatherValidator*> m_validators;
};
#endif // LOCATIONLISTMODEL_H
......@@ -2,6 +2,7 @@
* Copyright (C) 2007-2009 by Shawn Starr <shawn.starr@rogers.com> *
* Copyright (C) 2008 by Marco Martin <notmart@gmail.com> *
* Copyright (C) 2012 by Luís Gabriel Lima <lampih@gmail.com> *
* Copyright (C) 2017-2018 Friedrich W. H. Kossebau <kossebau@kde.org> *
* *
* 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 *
......@@ -21,15 +22,21 @@
#include "weatherapplet.h"
// KF
#include <KLocalizedString>
#include <KIconLoader>
#include <KConfigGroup>
#include <KUnitConversion/Value>
#include <KNotification>
#include <Plasma/Package>
// Qt
#include <QTimer>
// Std
#include <cmath>
using namespace KUnitConversion;
template <typename T>
T clampValue(T value, int decimals)
{
......@@ -41,10 +48,22 @@ namespace {
namespace AppletConfigKeys {
inline QString services() { return QStringLiteral("services"); }
inline QString showTemperatureInCompactMode() { return QStringLiteral("showTemperatureInCompactMode"); }
inline QString temperatureUnitId() { return QStringLiteral("temperatureUnitId"); }
inline QString windSpeedUnitId() { return QStringLiteral("windSpeedUnitId"); }
inline QString pressureUnitId() { return QStringLiteral("pressureUnitId"); }
inline QString visibilityUnitId() { return QStringLiteral("visibilityUnitId"); }
inline QString updateInterval() { return QStringLiteral("updateInterval"); }
inline QString source() { return QStringLiteral("source"); }
}
namespace StorageConfigKeys {
const char weatherServiceProviders[] = "weatherServiceProviders";
const char showTemperatureInCompactMode[] = "showTemperatureInCompactMode";
const char temperatureUnit[] = "temperatureUnit";
const char speedUnit[] = "speedUnit";
const char pressureUnit[] = "pressureUnit";
const char visibilityUnit[] = "visibilityUnit";
const char updateInterval[] = "updateInterval";
const char source[] = "source";
}
namespace PanelModelKeys {
inline QString location() { return QStringLiteral("location"); }
......@@ -61,6 +80,9 @@ namespace NoticesKeys {
inline QString description() { return QStringLiteral("description"); }
inline QString info() { return QStringLiteral("info"); }
}
namespace DataEngineIds {
inline QString weather() { return QStringLiteral("weather"); }
}
}
/**
......@@ -77,23 +99,45 @@ QString existingWeatherIconName(const QString &iconName)
WeatherApplet::WeatherApplet(QObject *parent, const QVariantList &args)
: Plasma::WeatherPopupApplet(parent, args)
: Plasma::Applet(parent, args)
{
m_busyTimer = new QTimer(this);
m_busyTimer->setInterval(2*60*1000); // 2 min
m_busyTimer->setSingleShot(true);
connect(m_busyTimer, &QTimer::timeout,
this, &WeatherApplet::giveUpBeingBusy);
}
void WeatherApplet::init()
{
resetPanelModel();
Plasma::WeatherPopupApplet::init();
configChanged();
}
void WeatherApplet::configChanged()
{
Plasma::WeatherPopupApplet::WeatherPopupApplet::configChanged();
if (!m_source.isEmpty()) {
Plasma::DataEngine* weatherDataEngine = dataEngine(DataEngineIds::weather());
weatherDataEngine->disconnectSource(m_source, this);
}
KConfigGroup cfg = config();
const bool useMetric = (QLocale().measurementSystem() == QLocale::MetricSystem);
m_displayTemperatureUnit = unit(cfg.readEntry(StorageConfigKeys::temperatureUnit, (useMetric ? "C" : "F")));
m_displaySpeedUnit = unit(cfg.readEntry(StorageConfigKeys::speedUnit, (useMetric ? "m/s" : "mph")));
m_displayPressureUnit = unit(cfg.readEntry(StorageConfigKeys::pressureUnit, (useMetric ? "hPa" : "inHg")));
m_displayVisibilityUnit = unit(cfg.readEntry(StorageConfigKeys::visibilityUnit, (useMetric ? "km" : "ml")));
m_updateInterval = cfg.readEntry(StorageConfigKeys::updateInterval, 30);
m_source = cfg.readEntry(StorageConfigKeys::source, QString());
setConfigurationRequired(m_source.isEmpty());
connectToEngine();
m_configuration.insert(AppletConfigKeys::showTemperatureInCompactMode(),
cfg.readEntry(StorageConfigKeys::showTemperatureInCompactMode, false));
emit configurationChanged();
......@@ -156,7 +200,6 @@ void WeatherApplet::updatePanelModel(const Plasma::DataEngine::Data &data)
m_panelModel[PanelModelKeys::location()] = data[QStringLiteral("Place")].toString();
const int reportTemperatureUnit = data[QStringLiteral("Temperature Unit")].toInt();
const KUnitConversion::Unit displayTemperatureUnit = temperatureUnit();
// Get current time period of day
const QStringList fiveDayTokens = data[QStringLiteral("Short Forecast Day 0")].toString().split(QLatin1Char('|'));
......@@ -166,13 +209,13 @@ void WeatherApplet::updatePanelModel(const Plasma::DataEngine::Data &data)
const QString& reportLowString = fiveDayTokens[4];
if (reportLowString != QLatin1String("N/A") && !reportLowString.isEmpty()) {
m_panelModel[PanelModelKeys::currentDayLowTemperature()] =
convertTemperature(displayTemperatureUnit, reportLowString, reportTemperatureUnit, true);
convertTemperature(m_displayTemperatureUnit, reportLowString, reportTemperatureUnit, true);
}
const QString& reportHighString = fiveDayTokens[3];
if (reportHighString != QLatin1String("N/A") && !reportHighString.isEmpty()) {
m_panelModel[PanelModelKeys::currentDayHighTemperature()] =
convertTemperature(displayTemperatureUnit, reportHighString, reportTemperatureUnit, true);
convertTemperature(m_displayTemperatureUnit, reportHighString, reportTemperatureUnit, true);
}
}
......@@ -180,7 +223,7 @@ void WeatherApplet::updatePanelModel(const Plasma::DataEngine::Data &data)
const QVariant temperature = data[QStringLiteral("Temperature")];
if (isValidData(temperature)) {
m_panelModel[PanelModelKeys::currentTemperature()] = convertTemperature(displayTemperatureUnit, temperature, reportTemperatureUnit);
m_panelModel[PanelModelKeys::currentTemperature()] = convertTemperature(m_displayTemperatureUnit, temperature, reportTemperatureUnit);
}
const QString conditionIconName = data[QStringLiteral("Condition Icon")].toString();
......@@ -217,7 +260,6 @@ void WeatherApplet::updateForecastModel(const Plasma::DataEngine::Data &data)
m_forecastModel.clear();
const int reportTemperatureUnit = data[QStringLiteral("Temperature Unit")].toInt();
const KUnitConversion::Unit displayTemperatureUnit = temperatureUnit();
QStringList dayItems;
QStringList conditionItems; // Icon
......@@ -260,7 +302,7 @@ void WeatherApplet::updateForecastModel(const Plasma::DataEngine::Data &data)
if (tempHigh == QLatin1String("N/A") || tempHigh.isEmpty()) {
hiItems << i18nc("Short for no data available", "-");
} else {
hiItems << convertTemperature(displayTemperatureUnit,
hiItems << convertTemperature(m_displayTemperatureUnit,
tempHigh,
reportTemperatureUnit,
true);
......@@ -272,7 +314,7 @@ void WeatherApplet::updateForecastModel(const Plasma::DataEngine::Data &data)
if (tempLow == QLatin1String("N/A") || tempLow.isEmpty()) {
lowItems << i18nc("Short for no data available", "-");
} else {
lowItems << convertTemperature(displayTemperatureUnit,
lowItems << convertTemperature(m_displayTemperatureUnit,
tempLow,
reportTemperatureUnit,
true);
......@@ -311,13 +353,12 @@ void WeatherApplet::updateDetailsModel(const Plasma::DataEngine::Data &data)
row.insert(textId, QString());
const int reportTemperatureUnit = data[QStringLiteral("Temperature Unit")].toInt();
const KUnitConversion::Unit displayTemperatureUnit = temperatureUnit();
const QVariant windChill = data[QStringLiteral("Windchill")];
if (isValidData(windChill)) {
// Use temperature unit to convert windchill temperature
// we only show degrees symbol not actual temperature unit
const QString temp = convertTemperature(displayTemperatureUnit, windChill, reportTemperatureUnit, false, true);
const QString temp = convertTemperature(m_displayTemperatureUnit, windChill, reportTemperatureUnit, false, true);
row[textId] = i18nc("windchill, unit", "Windchill: %1", temp);
m_detailsModel << row;
......@@ -328,7 +369,7 @@ void WeatherApplet::updateDetailsModel(const Plasma::DataEngine::Data &data)
// TODO: this seems wrong, does the humidex have temperature as units?
// Use temperature unit to convert humidex temperature
// we only show degrees symbol not actual temperature unit
QString temp = convertTemperature(displayTemperatureUnit, humidex, reportTemperatureUnit, false, true);
QString temp = convertTemperature(m_displayTemperatureUnit, humidex, reportTemperatureUnit, false, true);
row[textId] = i18nc("humidex, unit","Humidex: %1", temp);
m_detailsModel << row;
......@@ -336,7 +377,7 @@ void WeatherApplet::updateDetailsModel(const Plasma::DataEngine::Data &data)
const QVariant dewpoint = data[QStringLiteral("Dewpoint")];
if (isValidData(dewpoint)) {
QString temp = convertTemperature(displayTemperatureUnit, dewpoint, reportTemperatureUnit);
QString temp = convertTemperature(m_displayTemperatureUnit, dewpoint, reportTemperatureUnit);
row[textId] = i18nc("ground temperature, unit", "Dewpoint: %1", temp);
m_detailsModel << row;
......@@ -346,7 +387,7 @@ void WeatherApplet::updateDetailsModel(const Plasma::DataEngine::Data &data)
if (isValidData(pressure)) {
KUnitConversion::Value v(pressure.toDouble(),
static_cast<KUnitConversion::UnitId>(data[QStringLiteral("Pressure Unit")].toInt()));
v = v.convertTo(pressureUnit());
v = v.convertTo(m_displayPressureUnit);
row[textId] = i18nc("pressure, unit","Pressure: %1 %2",
locale.toString(clampValue(v.number(), 2), 'f', 2), v.unit().symbol());
......@@ -367,7 +408,7 @@ void WeatherApplet::updateDetailsModel(const Plasma::DataEngine::Data &data)
const KUnitConversion::UnitId unitId = static_cast<KUnitConversion::UnitId>(data[QStringLiteral("Visibility Unit")].toInt());
if (unitId != KUnitConversion::NoUnit) {
KUnitConversion::Value v(visibility.toDouble(), unitId);
v = v.convertTo(visibilityUnit());
v = v.convertTo(m_displayVisibilityUnit);
row[textId] = i18nc("distance, unit","Visibility: %1 %2",
locale.toString(clampValue(v.number(), 1), 'f', 1), v.unit().symbol());
} else {
......@@ -397,7 +438,7 @@ void WeatherApplet::updateDetailsModel(const Plasma::DataEngine::Data &data)
if (windSpeedNumeric != 0) {
KUnitConversion::Value v(windSpeedNumeric,
static_cast<KUnitConversion::UnitId>(data[QStringLiteral("Wind Speed Unit")].toInt()));
v = v.convertTo(speedUnit());
v = v.convertTo(m_displaySpeedUnit);
const QString i18nWindDirection = i18nc("wind direction", windDirection.toUtf8().data());
row[textId] = i18nc("wind direction, speed","%1 %2 %3", i18nWindDirection,
locale.toString(clampValue(v.number(), 1), 'f', 1), v.unit().symbol());
......@@ -417,7 +458,7 @@ void WeatherApplet::updateDetailsModel(const Plasma::DataEngine::Data &data)
// Convert the wind format for nonstandard types
KUnitConversion::Value v(windGust.toDouble(),
static_cast<KUnitConversion::UnitId>(data[QStringLiteral("Wind Speed Unit")].toInt()));
v = v.convertTo(speedUnit());
v = v.convertTo(m_displaySpeedUnit);
row[textId] = i18nc("winds exceeding wind speed briefly", "Wind Gust: %1 %2",
locale.toString(clampValue(v.number(), 1), 'f', 1), v.unit().symbol());
......@@ -454,6 +495,8 @@ void WeatherApplet::updateNoticesModel(const Plasma::DataEngine::Data &data)
void WeatherApplet::dataUpdated(const QString &source, const Plasma::DataEngine::Data &data)
{
Q_UNUSED(source);
if (data.isEmpty()) {
return;
}
......@@ -462,20 +505,42 @@ void WeatherApplet::dataUpdated(const QString &source, const Plasma::DataEngine:
updateForecastModel(data);
updateDetailsModel(data);
updateNoticesModel(data);
WeatherPopupApplet::dataUpdated(source, data);
const QString creditUrl = data[QStringLiteral("Credit Url")].toString();
QList<QUrl> associatedApplicationUrls;
if (!creditUrl.isEmpty()) {
associatedApplicationUrls << QUrl(creditUrl);
}
setAssociatedApplicationUrls(associatedApplicationUrls);
m_busyTimer->stop();
if (m_timeoutNotification) {
m_timeoutNotification->close();
}
setBusy(false);
emit modelUpdated();
}
QVariantMap WeatherApplet::configValues() const
{
QVariantMap config = WeatherPopupApplet::configValues();
KConfigGroup cfg = this->config();
config.insert(AppletConfigKeys::services(), cfg.readEntry(StorageConfigKeys::weatherServiceProviders, QStringList()));
config.insert(AppletConfigKeys::showTemperatureInCompactMode(), cfg.readEntry(StorageConfigKeys::showTemperatureInCompactMode, false));
return config;
return QVariantMap {
// UI settings
{ AppletConfigKeys::services(), cfg.readEntry(StorageConfigKeys::weatherServiceProviders, QStringList()) },
{ AppletConfigKeys::showTemperatureInCompactMode(), cfg.readEntry(StorageConfigKeys::showTemperatureInCompactMode, false) },
// units
{ AppletConfigKeys::temperatureUnitId(), m_displayTemperatureUnit.id() },
{ AppletConfigKeys::windSpeedUnitId(), m_displaySpeedUnit.id() },
{ AppletConfigKeys::pressureUnitId(), m_displayPressureUnit.id() },
{ AppletConfigKeys::visibilityUnitId(), m_displayVisibilityUnit.id() },
// data source
{ AppletConfigKeys::updateInterval(), m_updateInterval },
{ AppletConfigKeys::source(), m_source },
};
}
void WeatherApplet::saveConfig(const QVariantMap& configChanges)
......@@ -489,6 +554,7 @@ void WeatherApplet::saveConfig(const QVariantMap& configChanges)
KConfigGroup cfg = config();
// UI settings
auto it = configChanges.find(AppletConfigKeys::services());
if (it != configChanges.end()) {
cfg.writeEntry(StorageConfigKeys::weatherServiceProviders, it.value().toStringList());
......@@ -498,7 +564,90 @@ void WeatherApplet::saveConfig(const QVariantMap& configChanges)
cfg.writeEntry(StorageConfigKeys::showTemperatureInCompactMode, it.value().toBool());
}
WeatherPopupApplet::saveConfig(configChanges);
// units
it = configChanges.find(AppletConfigKeys::temperatureUnitId());
if (it != configChanges.end()) {
cfg.writeEntry(StorageConfigKeys::temperatureUnit, it.value().toInt());
}
it = configChanges.find(AppletConfigKeys::windSpeedUnitId());
if (it != configChanges.end()) {
cfg.writeEntry(StorageConfigKeys::speedUnit, it.value().toInt());
}
it = configChanges.find(AppletConfigKeys::pressureUnitId());
if (it != configChanges.end()) {
cfg.writeEntry(StorageConfigKeys::pressureUnit, it.value().toInt());
}
it = configChanges.find(AppletConfigKeys::visibilityUnitId());
if (it != configChanges.end()) {
cfg.writeEntry(StorageConfigKeys::visibilityUnit, it.value().toInt());
}
// data source
it = configChanges.find(AppletConfigKeys::updateInterval());
if (it != configChanges.end()) {
cfg.writeEntry(StorageConfigKeys::updateInterval, it.value().toInt());
}
it = configChanges.find(AppletConfigKeys::source());
if (it != configChanges.end()) {
cfg.writeEntry(StorageConfigKeys::source, it.value().toString());
}
emit configNeedsSaving();
}
void WeatherApplet::connectToEngine()
{
if (m_timeoutNotification) {
QObject::disconnect(m_timeoutNotificationConnection);
m_timeoutNotification = nullptr;
}
const bool missingLocation = m_source.isEmpty();
if (missingLocation) {
setBusy(false);
m_busyTimer->stop();
setConfigurationRequired(true);
} else {
setBusy(true);
m_busyTimer->start();
Plasma::DataEngine* weatherDataEngine = dataEngine(DataEngineIds::weather());
weatherDataEngine->connectSource(m_source, this, m_updateInterval * 60 * 1000);
}
}
void WeatherApplet::giveUpBeingBusy()
{
setBusy(false);
const QStringList sourceDetails = m_source.split(QLatin1Char( '|' ), QString::SkipEmptyParts);
if (sourceDetails.size() < 3) {
setConfigurationRequired(true);
} else {
m_timeoutNotification =
KNotification::event(KNotification::Error, QString(), // TODO: some title?
i18n("Weather information retrieval for %1 timed out.", sourceDetails.value(2)),
QStringLiteral("dialog-error"));
// seems global disconnect with wildcard does not cover lambdas, so remembering manually for disconnect
m_timeoutNotificationConnection =
connect(m_timeoutNotification, &KNotification::closed,
this, &WeatherApplet::onTimeoutNotificationClosed);
}
}
void WeatherApplet::onTimeoutNotificationClosed()
{
m_timeoutNotification = nullptr;
}
Unit WeatherApplet::unit(const QString& unit)
{
if (!unit.isEmpty() && unit[0].isDigit()) {
return m_converter.unit(static_cast<UnitId>(unit.toInt()));
}
// Support < 4.4 config values
return m_converter.unit(unit);
}
K_EXPORT_PLASMA_APPLET_WITH_JSON(weather, WeatherApplet, "metadata.json")
......
/***************************************************************************
* Copyright (C) 2007-2009 by Shawn Starr <shawn.starr@rogers.com> *
* Copyright (C) 2012 by Luís Gabriel Lima <lampih@gmail.com> *
* Copyright (C) 2017-2018 Friedrich W. H. Kossebau <kossebau@kde.org> *
* *
* 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 *
......@@ -21,9 +22,17 @@
#ifndef WEATHERAPPLET_H
#define WEATHERAPPLET_H
#include <plasmaweather/weatherpopupapplet.h>
#include <KUnitConversion/Unit>
#include <KUnitConversion/Converter>
class WeatherApplet : public Plasma::WeatherPopupApplet
#include <Plasma/DataEngine>
#include <Plasma/DataEngineConsumer>
#include <Plasma/Applet>
class KNotification;
class QTimer;
class WeatherApplet : public Plasma::Applet, public Plasma::DataEngineConsumer
{
Q_OBJECT
Q_PROPERTY(QVariantMap panelModel READ panelModel NOTIFY modelUpdated)
......@@ -43,6 +52,17 @@ public: // Plasma::Applet API
void init() override;
void configChanged() override;
public: // QML config control API
/**
* @return currently used config values
*/