File indexing completed on 2024-04-14 03:41:23

0001 /*
0002     SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "locationdialog.h"
0008 
0009 #include "kspaths.h"
0010 #include "kstarsdata.h"
0011 #include "Options.h"
0012 #include "ksnotification.h"
0013 #include "kstars_debug.h"
0014 #include "ksutils.h"
0015 
0016 #include <QSqlQuery>
0017 
0018 #ifdef HAVE_GEOCLUE2
0019 #include <QGeoPositionInfoSource>
0020 #endif
0021 #include <QJsonArray>
0022 #include <QJsonDocument>
0023 #include <QJsonObject>
0024 #include <QJsonValue>
0025 #include <QNetworkAccessManager>
0026 #include <QNetworkConfigurationManager>
0027 #include <QNetworkReply>
0028 #include <QNetworkSession>
0029 #include <QQmlContext>
0030 #include <QUrlQuery>
0031 #include <QPlainTextEdit>
0032 
0033 
0034 LocationDialogUI::LocationDialogUI(QWidget *parent) : QFrame(parent)
0035 {
0036     setupUi(this);
0037 }
0038 
0039 LocationDialog::LocationDialog(QWidget *parent) : QDialog(parent), timer(nullptr)
0040 {
0041 #ifdef Q_OS_OSX
0042     setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
0043 #endif
0044     KStarsData *data = KStarsData::Instance();
0045 
0046     SelectedCity = nullptr;
0047     ld           = new LocationDialogUI(this);
0048 
0049     QVBoxLayout *mainLayout = new QVBoxLayout;
0050     mainLayout->addWidget(ld);
0051     setLayout(mainLayout);
0052 
0053     ld->MapView->setLocationDialog(this);
0054 
0055     setWindowTitle(i18nc("@title:window", "Set Geographic Location"));
0056 
0057     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
0058     mainLayout->addWidget(buttonBox);
0059     connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotOk()));
0060     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
0061 
0062     for (int i = 0; i < 25; ++i)
0063         ld->TZBox->addItem(QLocale().toString(static_cast<double>(i - 12)));
0064 
0065     //Populate DSTRuleBox
0066     foreach (const QString &key, data->getRulebook().keys())
0067     {
0068         if (!key.isEmpty())
0069             ld->DSTRuleBox->addItem(key);
0070     }
0071 
0072     connect(ld->CityFilter, SIGNAL(textChanged(QString)), this, SLOT(enqueueFilterCity()));
0073     connect(ld->ProvinceFilter, SIGNAL(textChanged(QString)), this, SLOT(enqueueFilterCity()));
0074     connect(ld->CountryFilter, SIGNAL(textChanged(QString)), this, SLOT(enqueueFilterCity()));
0075     connect(ld->NewCityName, SIGNAL(textChanged(QString)), this, SLOT(nameChanged()));
0076     connect(ld->NewProvinceName, SIGNAL(textChanged(QString)), this, SLOT(nameChanged()));
0077     connect(ld->NewCountryName, SIGNAL(textChanged(QString)), this, SLOT(nameChanged()));
0078     connect(ld->NewLong, SIGNAL(textChanged(QString)), this, SLOT(dataChanged()));
0079     connect(ld->NewLat, SIGNAL(textChanged(QString)), this, SLOT(dataChanged()));
0080     connect(ld->NewElev, SIGNAL(valueChanged(double)), this, SLOT(dataChanged()));
0081 
0082     connect(ld->TZBox, SIGNAL(activated(int)), this, SLOT(dataChanged()));
0083     connect(ld->DSTRuleBox, SIGNAL(activated(int)), this, SLOT(dataChanged()));
0084     connect(ld->GeoBox, SIGNAL(itemSelectionChanged()), this, SLOT(changeCity()));
0085     connect(ld->AddCityButton, SIGNAL(clicked()), this, SLOT(addCity()));
0086     connect(ld->ClearFieldsButton, SIGNAL(clicked()), this, SLOT(clearFields()));
0087     connect(ld->RemoveButton, SIGNAL(clicked()), this, SLOT(removeCity()));
0088     connect(ld->UpdateButton, SIGNAL(clicked()), this, SLOT(updateCity()));
0089 
0090     // FIXME Disable this until Qt5 works with Geoclue2
0091 #ifdef HAVE_GEOCLUE_2
0092     source = QGeoPositionInfoSource::createDefaultSource(this);
0093     source->setPreferredPositioningMethods(QGeoPositionInfoSource::SatellitePositioningMethods);
0094     qDebug() << Q_FUNC_INFO << "Last known position" << source->lastKnownPosition().coordinate();
0095 
0096     connect(source, SIGNAL(positionUpdated(QGeoPositionInfo)), this, SLOT(positionUpdated(QGeoPositionInfo)));
0097     connect(source, SIGNAL(error(QGeoPositionInfoSource::Error)), this, SLOT(positionUpdateError(QGeoPositionInfoSource::Error)));
0098     connect(source, SIGNAL(updateTimeout()), this, SLOT(positionUpdateTimeout()));
0099 
0100     connect(ld->GetLocationButton, SIGNAL(clicked()), this, SLOT(requestUpdate()));
0101 #endif
0102 
0103     ld->DSTLabel->setText("<a href=\"showrules\">" + i18n("DST rule:") + "</a>");
0104     connect(ld->DSTLabel, SIGNAL(linkActivated(QString)), this, SLOT(showTZRules()));
0105 
0106     dataModified = false;
0107     nameModified = false;
0108     ld->AddCityButton->setEnabled(false);
0109 
0110     ld->errorLabel->setText(QString());
0111 
0112     // FIXME Disable this until Qt5 works with Geoclue2
0113 #ifdef HAVE_GEOCLUE_2
0114     nam = new QNetworkAccessManager(this);
0115     connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(processLocationNameData(QNetworkReply*)));
0116 #endif
0117 
0118     initCityList();
0119     resize(640, 480);
0120 }
0121 
0122 void LocationDialog::initCityList()
0123 {
0124     KStarsData *data = KStarsData::Instance();
0125     foreach (GeoLocation *loc, data->getGeoList())
0126     {
0127         ld->GeoBox->addItem(loc->fullName());
0128         filteredCityList.append(loc);
0129 
0130         //If TZ is not an even integer value, add it to listbox
0131         if (loc->TZ0() - int(loc->TZ0()) && ld->TZBox->findText(QLocale().toString(loc->TZ0())) != -1)
0132         {
0133             for (int i = 0; i < ld->TZBox->count(); ++i)
0134             {
0135                 if (ld->TZBox->itemText(i).toDouble() > loc->TZ0())
0136                 {
0137                     ld->TZBox->addItem(QLocale().toString(loc->TZ0()), i - 1);
0138                     break;
0139                 }
0140             }
0141         }
0142     }
0143 
0144     //Sort the list of Cities alphabetically...note that filteredCityList may now have a different ordering!
0145     ld->GeoBox->sortItems();
0146 
0147     ld->CountLabel->setText(
0148         i18np("One city matches search criteria", "%1 cities match search criteria", ld->GeoBox->count()));
0149 
0150     // attempt to highlight the current kstars location in the GeoBox
0151     ld->GeoBox->setCurrentItem(nullptr);
0152     for (int i = 0; i < ld->GeoBox->count(); i++)
0153     {
0154         if (ld->GeoBox->item(i)->text() == data->geo()->fullName())
0155         {
0156             ld->GeoBox->setCurrentRow(i);
0157             break;
0158         }
0159     }
0160 }
0161 
0162 void LocationDialog::enqueueFilterCity()
0163 {
0164     if (timer)
0165         timer->stop();
0166     else
0167     {
0168         timer = new QTimer(this);
0169         timer->setSingleShot(true);
0170         connect(timer, SIGNAL(timeout()), this, SLOT(filterCity()));
0171     }
0172     timer->start(500);
0173 }
0174 
0175 void LocationDialog::filterCity()
0176 {
0177     KStarsData *data = KStarsData::Instance();
0178     ld->GeoBox->clear();
0179     //Do NOT delete members of filteredCityList!
0180     while (!filteredCityList.isEmpty())
0181         filteredCityList.takeFirst();
0182 
0183     nameModified = false;
0184     dataModified = false;
0185     ld->AddCityButton->setEnabled(false);
0186     ld->UpdateButton->setEnabled(false);
0187 
0188     foreach (GeoLocation *loc, data->getGeoList())
0189     {
0190         QString sc(loc->translatedName());
0191         QString ss(loc->translatedCountry());
0192         QString sp = "";
0193         if (!loc->province().isEmpty())
0194             sp = loc->translatedProvince();
0195 
0196         if (sc.startsWith(ld->CityFilter->text(), Qt::CaseInsensitive) &&
0197                 sp.startsWith(ld->ProvinceFilter->text(), Qt::CaseInsensitive) &&
0198                 ss.startsWith(ld->CountryFilter->text(), Qt::CaseInsensitive))
0199         {
0200             ld->GeoBox->addItem(loc->fullName());
0201             filteredCityList.append(loc);
0202         }
0203     }
0204 
0205     ld->GeoBox->sortItems();
0206 
0207     ld->CountLabel->setText(
0208         i18np("One city matches search criteria", "%1 cities match search criteria", ld->GeoBox->count()));
0209 
0210     if (ld->GeoBox->count() > 0) // set first item in list as selected
0211         ld->GeoBox->setCurrentItem(ld->GeoBox->item(0));
0212 
0213     ld->MapView->repaint();
0214 }
0215 
0216 void LocationDialog::changeCity()
0217 {
0218     KStarsData *data = KStarsData::Instance();
0219 
0220     //when the selected city changes, set newCity, and redraw map
0221     SelectedCity = nullptr;
0222     if (ld->GeoBox->currentItem())
0223     {
0224         for (auto &loc : filteredCityList)
0225         {
0226             if (loc->fullName() == ld->GeoBox->currentItem()->text())
0227             {
0228                 SelectedCity = loc;
0229                 break;
0230             }
0231         }
0232     }
0233 
0234     ld->MapView->repaint();
0235 
0236     //Fill the fields at the bottom of the window with the selected city's data.
0237     if (SelectedCity)
0238     {
0239         ld->NewCityName->setText(SelectedCity->translatedName());
0240         if (SelectedCity->province().isEmpty())
0241             ld->NewProvinceName->setText(QString());
0242         else
0243             ld->NewProvinceName->setText(SelectedCity->translatedProvince());
0244 
0245         ld->NewCountryName->setText(SelectedCity->translatedCountry());
0246         ld->NewLong->show(SelectedCity->lng());
0247         ld->NewLat->show(SelectedCity->lat());
0248         ld->TZBox->setEditText(QLocale().toString(SelectedCity->TZ0()));
0249         ld->NewElev->setValue(SelectedCity->elevation());
0250 
0251         //Pick the City's rule from the rulebook
0252         for (int i = 0; i < ld->DSTRuleBox->count(); ++i)
0253         {
0254             TimeZoneRule tzr = data->getRulebook().value(ld->DSTRuleBox->itemText(i));
0255             if (tzr.equals(SelectedCity->tzrule()))
0256             {
0257                 ld->DSTRuleBox->setCurrentIndex(i);
0258                 break;
0259             }
0260         }
0261 
0262         ld->RemoveButton->setEnabled(SelectedCity->isReadOnly() == false);
0263     }
0264 
0265     nameModified = false;
0266     dataModified = false;
0267     ld->AddCityButton->setEnabled(false);
0268     ld->UpdateButton->setEnabled(false);
0269 }
0270 
0271 bool LocationDialog::addCity()
0272 {
0273     return updateCity(CITY_ADD);
0274 }
0275 
0276 bool LocationDialog::updateCity()
0277 {
0278     if (SelectedCity == nullptr)
0279         return false;
0280 
0281     return updateCity(CITY_UPDATE);
0282 }
0283 
0284 bool LocationDialog::removeCity()
0285 {
0286     if (SelectedCity == nullptr)
0287         return false;
0288 
0289     return updateCity(CITY_REMOVE);
0290 }
0291 
0292 bool LocationDialog::updateCity(CityOperation operation)
0293 {
0294     if (operation == CITY_REMOVE)
0295     {
0296         QString message = i18n("Are you sure you want to remove %1?", selectedCityName());
0297         if (KMessageBox::questionYesNo(nullptr, message, i18n("Remove City?")) == KMessageBox::No)
0298             return false; //user answered No.
0299     }
0300     else if (!nameModified && !dataModified)
0301     {
0302         QString message = i18n("This city already exists in the database.");
0303         KSNotification::sorry(message, i18n("Error: Duplicate Entry"));
0304         return false;
0305     }
0306 
0307     bool latOk(false), lngOk(false), tzOk(false);
0308     dms lat                = ld->NewLat->createDms(&latOk);
0309     dms lng                = ld->NewLong->createDms(&lngOk);
0310     QString TimeZoneString = ld->TZBox->lineEdit()->text();
0311     TimeZoneString.replace(QLocale().decimalPoint(), ".");
0312     double TZ = TimeZoneString.toDouble(&tzOk);
0313     double height          = ld->NewElev->value();
0314 
0315     if (ld->NewCityName->text().isEmpty() || ld->NewCountryName->text().isEmpty())
0316     {
0317         QString message = i18n("All fields (except province) must be filled to add this location.");
0318         KSNotification::sorry(message, i18n("Fields are Empty"));
0319         return false;
0320     }
0321     else if (!latOk || !lngOk)
0322     {
0323         QString message = i18n("Could not parse the Latitude/Longitude.");
0324         KSNotification::sorry(message, i18n("Bad Coordinates"));
0325         return false;
0326     }
0327     else if (!tzOk)
0328     {
0329         QString message = i18n("UTC Offset must be selected.");
0330         KSNotification::sorry(message, i18n("UTC Offset"));
0331         return false;
0332     }
0333 
0334     // If name is still the same then it's an update operation
0335     if (operation == CITY_ADD && !nameModified)
0336         operation = CITY_UPDATE;
0337 
0338     /*if ( !nameModified )
0339     {
0340         QString message = i18n( "Really override original data for this city?" );
0341         if ( KMessageBox::questionYesNo( 0, message, i18n( "Override Existing Data?" ), KGuiItem(i18n("Override Data")), KGuiItem(i18n("Do Not Override"))) == KMessageBox::No )
0342             return false; //user answered No.
0343     }*/
0344 
0345     QSqlDatabase mycitydb = QSqlDatabase::database("mycitydb");
0346     QString dbfile        = QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath("mycitydb.sqlite");
0347 
0348     // If it doesn't exist, create it
0349     if (QFile::exists(dbfile) == false)
0350     {
0351         mycitydb.setDatabaseName(dbfile);
0352         mycitydb.open();
0353         QSqlQuery create_query(mycitydb);
0354         QString query("CREATE TABLE city ( "
0355                       "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
0356                       "Name TEXT DEFAULT NULL, "
0357                       "Province TEXT DEFAULT NULL, "
0358                       "Country TEXT DEFAULT NULL, "
0359                       "Latitude TEXT DEFAULT NULL, "
0360                       "Longitude TEXT DEFAULT NULL, "
0361                       "TZ REAL DEFAULT NULL, "
0362                       "TZRule TEXT DEFAULT NULL,"
0363                       "Elevation REAL NOT NULL DEFAULT -10 )");
0364 
0365         if (create_query.exec(query) == false)
0366         {
0367             qCWarning(KSTARS) << create_query.lastError();
0368             return false;
0369         }
0370     }
0371     else if (mycitydb.open() == false)
0372     {
0373         qCWarning(KSTARS) << mycitydb.lastError();
0374         return false;
0375     }
0376 
0377     //Strip off white space
0378     QString name     = ld->NewCityName->text().trimmed();
0379     QString province = ld->NewProvinceName->text().trimmed();
0380     QString country  = ld->NewCountryName->text().trimmed();
0381     QString TZrule   = ld->DSTRuleBox->currentText();
0382     double Elevation = ld->NewElev->value();
0383     GeoLocation *g   = nullptr;
0384 
0385     switch (operation)
0386     {
0387         case CITY_ADD:
0388         {
0389             QSqlQuery add_query(mycitydb);
0390             add_query.prepare("INSERT INTO city(Name, Province, Country, Latitude, Longitude, TZ, TZRule, Elevation) "
0391                               "VALUES(:Name, :Province, :Country, :Latitude, :Longitude, :TZ, :TZRule, :Elevation)");
0392             add_query.bindValue(":Name", name);
0393             add_query.bindValue(":Province", province);
0394             add_query.bindValue(":Country", country);
0395             add_query.bindValue(":Latitude", lat.toDMSString());
0396             add_query.bindValue(":Longitude", lng.toDMSString());
0397             add_query.bindValue(":TZ", TZ);
0398             add_query.bindValue(":TZRule", TZrule);
0399             add_query.bindValue(":Elevation", Elevation);
0400             if (add_query.exec() == false)
0401             {
0402                 qCWarning(KSTARS) << add_query.lastError();
0403                 return false;
0404             }
0405 
0406             //Add city to geoList...don't need to insert it alphabetically, since we always sort GeoList
0407             g = new GeoLocation(lng, lat, name, province, country, TZ, &KStarsData::Instance()->Rulebook[TZrule], Elevation);
0408             KStarsData::Instance()->getGeoList().append(g);
0409         }
0410         break;
0411 
0412         case CITY_UPDATE:
0413         {
0414             g = SelectedCity;
0415 
0416             QSqlQuery update_query(mycitydb);
0417             update_query.prepare("UPDATE city SET Name = :newName, Province = :newProvince, Country = :newCountry, "
0418                                  "Latitude = :Latitude, Longitude = :Longitude, TZ = :TZ, TZRule = :TZRule, Elevation = :Elevation WHERE "
0419                                  "Name = :Name AND Province = :Province AND Country = :Country");
0420             update_query.bindValue(":newName", name);
0421             update_query.bindValue(":newProvince", province);
0422             update_query.bindValue(":newCountry", country);
0423             update_query.bindValue(":Name", SelectedCity->name());
0424             update_query.bindValue(":Province", SelectedCity->province());
0425             update_query.bindValue(":Country", SelectedCity->country());
0426             update_query.bindValue(":Latitude", lat.toDMSString());
0427             update_query.bindValue(":Longitude", lng.toDMSString());
0428             update_query.bindValue(":TZ", TZ);
0429             update_query.bindValue(":TZRule", TZrule);
0430             update_query.bindValue(":Elevation", Elevation);
0431             if (update_query.exec() == false)
0432             {
0433                 qCWarning(KSTARS) << update_query.lastError();
0434                 return false;
0435             }
0436 
0437             g->setName(name);
0438             g->setProvince(province);
0439             g->setCountry(country);
0440             g->setLat(lat);
0441             g->setLong(lng);
0442             g->setTZ0(TZ);
0443             g->setTZRule(&KStarsData::Instance()->Rulebook[TZrule]);
0444             g->setElevation(height);
0445 
0446         }
0447         break;
0448 
0449         case CITY_REMOVE:
0450         {
0451             g = SelectedCity;
0452             QSqlQuery delete_query(mycitydb);
0453             delete_query.prepare("DELETE FROM city WHERE Name = :Name AND Province = :Province AND Country = :Country");
0454             delete_query.bindValue(":Name", name);
0455             delete_query.bindValue(":Province", province);
0456             delete_query.bindValue(":Country", country);
0457             if (delete_query.exec() == false)
0458             {
0459                 qCWarning(KSTARS) << delete_query.lastError();
0460                 return false;
0461             }
0462 
0463             filteredCityList.removeOne(g);
0464             KStarsData::Instance()->getGeoList().removeOne(g);
0465             delete g;
0466             g = nullptr;
0467         }
0468         break;
0469     }
0470 
0471     //(possibly) insert new city into GeoBox by running filterCity()
0472     filterCity();
0473 
0474     //Attempt to highlight new city in list
0475     ld->GeoBox->setCurrentItem(nullptr);
0476     if (g && ld->GeoBox->count())
0477     {
0478         for (int i = 0; i < ld->GeoBox->count(); i++)
0479         {
0480             if (ld->GeoBox->item(i)->text() == g->fullName())
0481             {
0482                 ld->GeoBox->setCurrentRow(i);
0483                 break;
0484             }
0485         }
0486     }
0487 
0488     mycitydb.commit();
0489     mycitydb.close();
0490 
0491     return true;
0492 }
0493 
0494 void LocationDialog::findCitiesNear(int lng, int lat)
0495 {
0496     KStarsData *data = KStarsData::Instance();
0497     //find all cities within 3 degrees of (lng, lat); list them in GeoBox
0498     ld->GeoBox->clear();
0499     //Remember, do NOT delete members of filteredCityList
0500     while (!filteredCityList.isEmpty())
0501         filteredCityList.takeFirst();
0502 
0503     foreach (GeoLocation *loc, data->getGeoList())
0504     {
0505         if ((abs(lng - int(loc->lng()->Degrees())) < 3) && (abs(lat - int(loc->lat()->Degrees())) < 3))
0506         {
0507             ld->GeoBox->addItem(loc->fullName());
0508             filteredCityList.append(loc);
0509         }
0510     }
0511 
0512     ld->GeoBox->sortItems();
0513     ld->CountLabel->setText(
0514         i18np("One city matches search criteria", "%1 cities match search criteria", ld->GeoBox->count()));
0515 
0516     if (ld->GeoBox->count() > 0) // set first item in list as selected
0517         ld->GeoBox->setCurrentItem(ld->GeoBox->item(0));
0518 
0519     repaint();
0520 }
0521 
0522 bool LocationDialog::checkLongLat()
0523 {
0524     if (ld->NewLong->text().isEmpty() || ld->NewLat->text().isEmpty())
0525         return false;
0526 
0527     bool ok;
0528     double lng = ld->NewLong->createDms(&ok).Degrees();
0529     if (!ok)
0530         return false;
0531     double lat = ld->NewLat->createDms(&ok).Degrees();
0532     if (!ok)
0533         return false;
0534 
0535     if (fabs(lng) > 180 || fabs(lat) > 90)
0536         return false;
0537 
0538     return true;
0539 }
0540 
0541 void LocationDialog::clearFields()
0542 {
0543     ld->CityFilter->clear();
0544     ld->ProvinceFilter->clear();
0545     ld->CountryFilter->clear();
0546     ld->NewCityName->clear();
0547     ld->NewProvinceName->clear();
0548     ld->NewCountryName->clear();
0549     ld->NewLong->clearFields();
0550     ld->NewLat->clearFields();
0551     ld->NewElev->setValue(-10);
0552     ld->TZBox->setCurrentIndex(-1);
0553     // JM 2017-09-16: No, let's not assume it is 0. User have to explicitly set TZ so avoid mistakes.
0554     //ld->TZBox->lineEdit()->setText(QLocale().toString(0.0));
0555     ld->DSTRuleBox->setCurrentIndex(0);
0556     nameModified = true;
0557     dataModified = false;
0558 
0559     ld->AddCityButton->setEnabled(false);
0560     ld->UpdateButton->setEnabled(false);
0561     ld->NewCityName->setFocus();
0562 }
0563 
0564 void LocationDialog::showTZRules()
0565 {
0566     QFile file;
0567 
0568     if (KSUtils::openDataFile(file, "TZrules.dat") == false)
0569         return;
0570 
0571     QTextStream stream(&file);
0572 
0573     QString message = i18n("Daylight Saving Time Rules");
0574 
0575     QPointer<QDialog> tzd = new QDialog(this);
0576     tzd->setWindowTitle(message);
0577 
0578     QPlainTextEdit *textEdit = new QPlainTextEdit(tzd);
0579     textEdit->setReadOnly(true);
0580     while (stream.atEnd() == false)
0581     {
0582         QString line = stream.readLine();
0583         if (line.startsWith('#'))
0584             textEdit->appendPlainText(line);
0585     }
0586     textEdit->moveCursor(QTextCursor::Start);
0587     textEdit->ensureCursorVisible();
0588 
0589     QVBoxLayout *mainLayout = new QVBoxLayout;
0590     mainLayout->addWidget(textEdit);
0591 
0592     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
0593     mainLayout->addWidget(buttonBox);
0594     connect(buttonBox, SIGNAL(rejected()), tzd, SLOT(reject()));
0595 
0596     tzd->setLayout(mainLayout);
0597 
0598     tzd->exec();
0599 
0600     delete tzd;
0601 }
0602 
0603 void LocationDialog::nameChanged()
0604 {
0605     nameModified = true;
0606     dataChanged();
0607 }
0608 
0609 //do not enable Add button until all data are present and valid.
0610 void LocationDialog::dataChanged()
0611 {
0612     dataModified = true;
0613     ld->AddCityButton->setEnabled(nameModified && !ld->NewCityName->text().isEmpty() &&
0614                                   !ld->NewCountryName->text().isEmpty() && checkLongLat() && ld->TZBox->currentIndex() != -1);
0615     if (SelectedCity)
0616         ld->UpdateButton->setEnabled(SelectedCity->isReadOnly() == false && !ld->NewCityName->text().isEmpty() &&
0617                                      !ld->NewCountryName->text().isEmpty() && checkLongLat() && ld->TZBox->currentIndex() != -1);
0618 
0619     if (ld->AddCityButton->isEnabled() == false && ld->UpdateButton->isEnabled() == false)
0620     {
0621         if (ld->NewCityName->text().isEmpty())
0622         {
0623             ld->errorLabel->setText(i18n("Cannot add new location -- city name blank"));
0624         }
0625         else if (ld->NewCountryName->text().isEmpty())
0626         {
0627             ld->errorLabel->setText(i18n("Cannot add new location -- country name blank"));
0628         }
0629         else if (!checkLongLat())
0630         {
0631             ld->errorLabel->setText(i18n("Cannot add new location -- invalid latitude / longitude"));
0632         }
0633         else if (ld->TZBox->currentIndex() == -1)
0634         {
0635             ld->errorLabel->setText(i18n("Cannot add new location -- missing UTC Offset"));
0636         }
0637         else if (SelectedCity && SelectedCity->isReadOnly())
0638         {
0639             ld->errorLabel->setText(i18n("City is Read Only. Change name to add new city."));
0640         }
0641     }
0642     else
0643     {
0644         ld->errorLabel->setText(QString());
0645     }
0646 }
0647 
0648 void LocationDialog::slotOk()
0649 {
0650     if (ld->AddCityButton->isEnabled())
0651     {
0652         if (addCity())
0653             accept();
0654     }
0655     else
0656         accept();
0657 }
0658 
0659 // FIXME Disable this until Qt5 works with Geoclue2
0660 #ifdef HAVE_GEOCLUE_2
0661 void LocationDialog::getNameFromCoordinates(double latitude, double longitude)
0662 {
0663     QString lat = QString::number(latitude);
0664     QString lon = QString::number(longitude);
0665     QString latlng(lat + ", " + lon);
0666 
0667     QUrl url("http://maps.googleapis.com/maps/api/geocode/json");
0668     QUrlQuery query;
0669     query.addQueryItem("latlng", latlng);
0670     url.setQuery(query);
0671     qDebug() << Q_FUNC_INFO << "submitting request";
0672 
0673     nam->get(QNetworkRequest(url));
0674     connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(processLocationNameData(QNetworkReply*)));
0675 }
0676 
0677 void LocationDialog::processLocationNameData(QNetworkReply *networkReply)
0678 {
0679     if (!networkReply)
0680         return;
0681 
0682     if (!networkReply->error())
0683     {
0684         QJsonDocument document = QJsonDocument::fromJson(networkReply->readAll());
0685 
0686         if (document.isObject())
0687         {
0688             QJsonObject obj = document.object();
0689             QJsonValue val;
0690 
0691             if (obj.contains(QStringLiteral("results")))
0692             {
0693                 val = obj["results"];
0694 
0695                 QString city =
0696                     val.toArray()[0].toObject()["address_components"].toArray()[2].toObject()["long_name"].toString();
0697                 QString region =
0698                     val.toArray()[0].toObject()["address_components"].toArray()[3].toObject()["long_name"].toString();
0699                 QString country =
0700                     val.toArray()[0].toObject()["address_components"].toArray()[4].toObject()["long_name"].toString();
0701 
0702                 //emit newNameFromCoordinates(city, region, country);
0703             }
0704             else
0705             {
0706             }
0707         }
0708     }
0709     networkReply->deleteLater();
0710 }
0711 
0712 void LocationDialog::requestUpdate()
0713 {
0714     source->requestUpdate(15000);
0715 }
0716 
0717 void LocationDialog::positionUpdated(const QGeoPositionInfo &info)
0718 {
0719     qDebug() << Q_FUNC_INFO << "Position updated:" << info;
0720 }
0721 
0722 void LocationDialog::positionUpdateError(QGeoPositionInfoSource::Error error)
0723 {
0724     qDebug() << Q_FUNC_INFO << "Position update error: " << error;
0725 }
0726 
0727 void LocationDialog::positionUpdateTimeout()
0728 {
0729     qDebug() << Q_FUNC_INFO << "Timed out!";
0730     qDebug() << Q_FUNC_INFO << source->error();
0731 }
0732 #endif