File indexing completed on 2024-04-14 15:49:50

0001 // SPDX-License-Identifier: GPL-3.0-or-later
0002 /*
0003   Copyright 2017 Martin Koller, kollix@aon.at
0004 
0005   This file is part of liquidshell.
0006 
0007   liquidshell is free software: you can redistribute it and/or modify
0008   it under the terms of the GNU General Public License as published by
0009   the Free Software Foundation, either version 3 of the License, or
0010   (at your option) any later version.
0011 
0012   liquidshell is distributed in the hope that it will be useful,
0013   but WITHOUT ANY WARRANTY; without even the implied warranty of
0014   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0015   GNU General Public License for more details.
0016 
0017   You should have received a copy of the GNU General Public License
0018   along with liquidshell.  If not, see <http://www.gnu.org/licenses/>.
0019 */
0020 
0021 #include <WeatherAppletConfigureDialog.hxx>
0022 #include <WeatherApplet.hxx>
0023 
0024 #include <QUrl>
0025 #include <QStandardPaths>
0026 #include <QFile>
0027 #include <QMessageBox>
0028 #include <QJsonDocument>
0029 #include <QJsonArray>
0030 #include <QJsonObject>
0031 #include <QDebug>
0032 #include <QElapsedTimer>
0033 #include <QTimer>
0034 #include <QDir>
0035 
0036 #include <KRun>
0037 #include <KFilterDev>
0038 
0039 //--------------------------------------------------------------------------------
0040 
0041 WeatherAppletConfigureDialog::WeatherAppletConfigureDialog(WeatherApplet *parent)
0042   : QDialog(parent), applet(parent)
0043 {
0044   ui.setupUi(this);
0045   connect(ui.city, &QLineEdit::textEdited, [this](const QString &txt)
0046           { auto found = ui.cityList->findItems(txt, Qt::MatchStartsWith);
0047             if ( found.count() ) ui.cityList->setCurrentItem(found[0]); });
0048 
0049   connect(ui.cityList, &QTreeWidget::itemClicked,
0050           [this](QTreeWidgetItem *current) { ui.city->setText(current->text(0)); });
0051 
0052   ui.apiKey->setText(applet->apiKey);
0053   if ( applet->units == "metric" )
0054     ui.metric->setChecked(true);
0055   else
0056     ui.imperial->setChecked(true);
0057 
0058   connect(ui.getApiKey, &QPushButton::clicked, []() { new KRun(QUrl("http://openweathermap.org/appid"), nullptr); });
0059 
0060   ui.textColor->setColor(applet->palette().color(applet->foregroundRole()));
0061   ui.backgroundColor->setColor(applet->palette().color(applet->backgroundRole()));
0062 
0063   // for city selection, we need the json file
0064   QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) +
0065                      "/api.openweathermap.org/";
0066 
0067   QDir dir;
0068   dir.mkpath(cacheDir);
0069   QString filePath = cacheDir + "city.list.json.gz";
0070 
0071   if ( QFile::exists(filePath) )
0072     QTimer::singleShot(0, [this, filePath]() { readJsonFile(filePath); });
0073   else
0074   {
0075     KIO::CopyJob *job = KIO::copy(QUrl("http://bulk.openweathermap.org/sample/city.list.json.gz"),
0076                                   QUrl::fromLocalFile(filePath));
0077 
0078     connect(job, &KIO::Job::result, this, &WeatherAppletConfigureDialog::gotJsonFile);
0079 
0080     ui.city->setText(i18n("Downloading city list..."));
0081     ui.city->setReadOnly(true);
0082   }
0083 }
0084 
0085 //--------------------------------------------------------------------------------
0086 
0087 void WeatherAppletConfigureDialog::gotJsonFile(KJob *job)
0088 {
0089   ui.city->setText(QString());
0090   ui.city->setReadOnly(false);
0091 
0092   if ( job->error() )
0093   {
0094     QMessageBox::warning(this, i18n("Download Error"),
0095                          i18n("Error on downloading city list: %1").arg(job->errorString()));
0096     return;
0097   }
0098   readJsonFile(static_cast<KIO::CopyJob *>(job)->destUrl().toLocalFile());
0099 }
0100 
0101 //--------------------------------------------------------------------------------
0102 
0103 void WeatherAppletConfigureDialog::readJsonFile(const QString &filePath)
0104 {
0105   ui.city->setFocus();
0106 
0107   KFilterDev jsonFile(filePath);
0108   if ( !jsonFile.open(QIODevice::ReadOnly) )
0109     return;
0110 
0111   QJsonArray array = QJsonDocument::fromJson(jsonFile.readAll()).array();
0112 
0113   QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
0114 
0115   int i = 0;
0116   for (const QJsonValue &value : array)
0117   {
0118     if ( value.isObject() )
0119     {
0120       QJsonObject obj = value.toObject();
0121       QString city = obj["name"].toString();
0122       QString country = obj["country"].toString();
0123 
0124       if ( !city.isEmpty() && (city != "-") && !country.isEmpty() )
0125       {
0126         QTreeWidgetItem *item = new QTreeWidgetItem(ui.cityList);
0127         item->setText(0, city);
0128         item->setText(1, country);
0129         item->setData(0, Qt::UserRole, obj["id"].toInt());
0130       }
0131     }
0132     if ( (i++ % 40000) == 0 )
0133       QApplication::processEvents();
0134   }
0135 
0136   ui.cityList->setSortingEnabled(true);
0137   ui.cityList->sortByColumn(0, Qt::AscendingOrder);
0138   ui.cityList->header()->resizeSections(QHeaderView::ResizeToContents);
0139 
0140   for (int i = 0; i < ui.cityList->topLevelItemCount(); i++)
0141   {
0142     if ( ui.cityList->topLevelItem(i)->data(0, Qt::UserRole).toString() == applet->cityId )
0143     {
0144       ui.cityList->setCurrentItem(ui.cityList->topLevelItem(i));
0145       ui.city->setText(ui.cityList->topLevelItem(i)->text(0));
0146       break;
0147     }
0148   }
0149 
0150    QApplication::restoreOverrideCursor();
0151 }
0152 
0153 //--------------------------------------------------------------------------------
0154 
0155 void WeatherAppletConfigureDialog::accept()
0156 {
0157   applet->apiKey = ui.apiKey->text();
0158 
0159   auto selected = ui.cityList->selectedItems();
0160   if ( selected.count() )
0161     applet->cityId = selected[0]->data(0, Qt::UserRole).toString();
0162 
0163   if ( ui.metric->isChecked() )
0164     applet->units = "metric";
0165   else
0166     applet->units = "imperial";
0167 
0168   QPalette pal = applet->palette();
0169   pal.setColor(applet->foregroundRole(), ui.textColor->color());
0170   pal.setColor(applet->backgroundRole(), ui.backgroundColor->color());
0171   applet->setPalette(pal);
0172 
0173   QDialog::accept();
0174 }
0175 
0176 //--------------------------------------------------------------------------------