Warning, file /plasma/kdeplasma-addons/applets/weather/plugin/locationlistmodel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * SPDX-FileCopyrightText: 2009 Petri Damstén <damu@iki.fi>
0003  * SPDX-FileCopyrightText: 2016, 2018 Friedrich W. H. Kossebau <kossebau@kde.org>
0004  *
0005  * SPDX-License-Identifier: GPL-2.0-or-later
0006  */
0007 
0008 #include "locationlistmodel.h"
0009 
0010 #include <Plasma/DataContainer>
0011 
0012 #include <KLocalizedString>
0013 
0014 #include <QDebug>
0015 
0016 WeatherValidator::WeatherValidator(Plasma::DataEngine *weatherDataengine, const QString &ionName, QObject *parent)
0017     : QObject(parent)
0018     , m_weatherDataEngine(weatherDataengine)
0019     , m_ionName(ionName)
0020 {
0021 }
0022 
0023 WeatherValidator::~WeatherValidator() = default;
0024 
0025 void WeatherValidator::validate(const QString &location)
0026 {
0027     const QString validationSource = m_ionName + QLatin1String("|validate|") + location;
0028 
0029     m_weatherDataEngine->connectSource(validationSource, this);
0030 }
0031 
0032 void WeatherValidator::dataUpdated(const QString &source, const Plasma::DataEngine::Data &data)
0033 {
0034     QMap<QString, QString> locationSources;
0035 
0036     m_weatherDataEngine->disconnectSource(source, this);
0037 
0038     const auto validationResult = data[QStringLiteral("validate")].toString().split(QLatin1Char('|'));
0039 
0040     if (validationResult.size() < 2) {
0041         Q_EMIT error(i18n("Cannot find '%1' using %2.", source, m_ionName));
0042     } else if (validationResult[1] == QLatin1String("valid") && validationResult.size() > 2) {
0043         const QString weatherSourcePrefix = validationResult[0] + QLatin1String("|weather|");
0044         int i = 3;
0045 
0046         const int lastFieldIndex = validationResult.size() - 1;
0047         while (i < lastFieldIndex) {
0048             if (validationResult[i] == QLatin1String("place")) {
0049                 const QString &name = validationResult[i + 1];
0050                 QString locationSource;
0051                 if (i + 2 < lastFieldIndex && validationResult[i + 2] == QLatin1String("extra")) {
0052                     const QString &id = validationResult[i + 3];
0053                     locationSource = weatherSourcePrefix + name + QLatin1Char('|') + id;
0054                     i += 4;
0055                 } else {
0056                     locationSource = weatherSourcePrefix + name;
0057                     i += 2;
0058                 }
0059                 locationSources.insert(name, locationSource);
0060             } else {
0061                 ++i;
0062             }
0063         }
0064 
0065     } else if (validationResult[1] == QLatin1String("timeout")) {
0066         Q_EMIT error(i18n("Connection to %1 weather server timed out.", m_ionName));
0067     } else {
0068         const QString searchTerm = validationResult.size() > 3 ? validationResult[3] : source;
0069         Q_EMIT error(i18n("Cannot find '%1' using %2.", searchTerm, m_ionName));
0070     }
0071 
0072     Q_EMIT finished(locationSources);
0073 }
0074 
0075 LocationListModel::LocationListModel(QObject *parent)
0076     : QAbstractListModel(parent)
0077     , m_validatingInput(false)
0078     , m_checkedInCount(0)
0079 {
0080 }
0081 
0082 QVariant LocationListModel::data(const QModelIndex &index, int role) const
0083 {
0084     if (!index.isValid() || index.row() >= m_locations.size()) {
0085         return QVariant();
0086     }
0087 
0088     switch (role) {
0089     case Qt::DisplayRole:
0090         return nameForListIndex(index.row());
0091     }
0092 
0093     return QVariant();
0094 }
0095 
0096 int LocationListModel::rowCount(const QModelIndex &index) const
0097 {
0098     if (!index.isValid()) {
0099         return m_locations.size();
0100     }
0101 
0102     return 0;
0103 }
0104 
0105 bool LocationListModel::isValidatingInput() const
0106 {
0107     return m_validatingInput;
0108 }
0109 
0110 QString LocationListModel::valueForListIndex(int listIndex) const
0111 {
0112     if (0 <= listIndex && listIndex < m_locations.count()) {
0113         return m_locations.at(listIndex).value;
0114     }
0115 
0116     return QString();
0117 }
0118 
0119 QString LocationListModel::nameForListIndex(int listIndex) const
0120 {
0121     if (0 <= listIndex && listIndex < m_locations.count()) {
0122         const LocationItem &item = m_locations.at(listIndex);
0123         if (!item.weatherService.isEmpty()) {
0124             return i18nc("A weather station location and the weather service it comes from",
0125                          "%1 (%2)",
0126                          item.weatherStation,
0127                          m_serviceCodeToDisplayName.value(item.weatherService, item.weatherService));
0128         }
0129     }
0130 
0131     return QString();
0132 }
0133 
0134 void LocationListModel::searchLocations(const QString &searchString, const QStringList &services)
0135 {
0136     m_checkedInCount = 0;
0137 
0138     // reset current validators
0139     qDeleteAll(m_validators);
0140     m_validators.clear();
0141 
0142     m_searchString = searchString;
0143 
0144     if (!m_validatingInput) {
0145         m_validatingInput = true;
0146         Q_EMIT validatingInputChanged(true);
0147     }
0148 
0149     beginResetModel();
0150     m_locations.clear();
0151     endResetModel();
0152 
0153     if (searchString.isEmpty()) {
0154         completeSearch();
0155         return;
0156     }
0157 
0158     Plasma::DataEngine *dataengine = dataEngine(QStringLiteral("weather"));
0159 
0160     const QVariantList plugins = dataengine->containerForSource(QStringLiteral("ions"))->data().values();
0161     for (const QVariant &plugin : plugins) {
0162         const QStringList pluginInfo = plugin.toString().split(QLatin1Char('|'));
0163         if (pluginInfo.count() > 1) {
0164             const QString &ionId = pluginInfo[1];
0165             if (!services.contains(ionId)) {
0166                 continue;
0167             }
0168 
0169             m_serviceCodeToDisplayName[pluginInfo[1]] = pluginInfo[0];
0170 
0171             // qDebug() << "ion: " << pluginInfo[0] << pluginInfo[1];
0172             // d->ions.insert(pluginInfo[1], pluginInfo[0]);
0173 
0174             auto *validator = new WeatherValidator(dataengine, ionId, this);
0175             connect(validator, &WeatherValidator::error, this, &LocationListModel::validatorError);
0176             connect(validator, &WeatherValidator::finished, this, &LocationListModel::addSources);
0177 
0178             m_validators.append(validator);
0179         }
0180     }
0181 
0182     for (auto *validator : std::as_const(m_validators)) {
0183         validator->validate(m_searchString);
0184     }
0185 }
0186 
0187 void LocationListModel::validatorError(const QString &error)
0188 {
0189     qDebug() << error;
0190 }
0191 
0192 void LocationListModel::addSources(const QMap<QString, QString> &sources)
0193 {
0194     QMapIterator<QString, QString> it(sources);
0195 
0196     // TODO: be more elaborate and use beginInsertRows() & endInsertRows()
0197     beginResetModel();
0198 
0199     while (it.hasNext()) {
0200         it.next();
0201         const QStringList list = it.value().split(QLatin1Char('|'), Qt::SkipEmptyParts);
0202         if (list.count() > 2) {
0203             qDebug() << list;
0204             m_locations.append(LocationItem(list[2], list[0], it.value()));
0205         }
0206     }
0207 
0208     endResetModel();
0209 
0210     ++m_checkedInCount;
0211     if (m_checkedInCount >= m_validators.count()) {
0212         completeSearch();
0213     }
0214 }
0215 
0216 void LocationListModel::completeSearch()
0217 {
0218     m_validatingInput = false;
0219     const bool success = !m_locations.empty();
0220     Q_EMIT locationSearchDone(success, m_searchString);
0221     Q_EMIT validatingInputChanged(false);
0222 }
0223 
0224 void LocationListModel::clear()
0225 {
0226     beginResetModel();
0227     m_locations.clear();
0228     endResetModel();
0229 
0230     m_checkedInCount = 0;
0231     m_validatingInput = false;
0232     Q_EMIT validatingInputChanged(false);
0233 }