File indexing completed on 2025-04-20 03:29:58
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