1 /*
2 SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "locationdialog.h"
8
9 #include "kspaths.h"
10 #include "kstarsdata.h"
11 #include "Options.h"
12 #include "ksnotification.h"
13 #include "kstars_debug.h"
14 #include "ksutils.h"
15
16 #include <QSqlQuery>
17
18 #ifdef HAVE_GEOCLUE2
19 #include <QGeoPositionInfoSource>
20 #endif
21 #include <QJsonArray>
22 #include <QJsonDocument>
23 #include <QJsonObject>
24 #include <QJsonValue>
25 #include <QNetworkAccessManager>
26 #include <QNetworkConfigurationManager>
27 #include <QNetworkReply>
28 #include <QNetworkSession>
29 #include <QQmlContext>
30 #include <QUrlQuery>
31 #include <QPlainTextEdit>
32
33
LocationDialogUI(QWidget * parent)34 LocationDialogUI::LocationDialogUI(QWidget *parent) : QFrame(parent)
35 {
36 setupUi(this);
37 }
38
LocationDialog(QWidget * parent)39 LocationDialog::LocationDialog(QWidget *parent) : QDialog(parent), timer(nullptr)
40 {
41 #ifdef Q_OS_OSX
42 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
43 #endif
44 KStarsData *data = KStarsData::Instance();
45
46 SelectedCity = nullptr;
47 ld = new LocationDialogUI(this);
48
49 QVBoxLayout *mainLayout = new QVBoxLayout;
50 mainLayout->addWidget(ld);
51 setLayout(mainLayout);
52
53 ld->MapView->setLocationDialog(this);
54
55 setWindowTitle(i18nc("@title:window", "Set Geographic Location"));
56
57 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
58 mainLayout->addWidget(buttonBox);
59 connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotOk()));
60 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
61
62 for (int i = 0; i < 25; ++i)
63 ld->TZBox->addItem(QLocale().toString(static_cast<double>(i - 12)));
64
65 //Populate DSTRuleBox
66 foreach (const QString &key, data->getRulebook().keys())
67 {
68 if (!key.isEmpty())
69 ld->DSTRuleBox->addItem(key);
70 }
71
72 connect(ld->CityFilter, SIGNAL(textChanged(QString)), this, SLOT(enqueueFilterCity()));
73 connect(ld->ProvinceFilter, SIGNAL(textChanged(QString)), this, SLOT(enqueueFilterCity()));
74 connect(ld->CountryFilter, SIGNAL(textChanged(QString)), this, SLOT(enqueueFilterCity()));
75 connect(ld->NewCityName, SIGNAL(textChanged(QString)), this, SLOT(nameChanged()));
76 connect(ld->NewProvinceName, SIGNAL(textChanged(QString)), this, SLOT(nameChanged()));
77 connect(ld->NewCountryName, SIGNAL(textChanged(QString)), this, SLOT(nameChanged()));
78 connect(ld->NewLong, SIGNAL(textChanged(QString)), this, SLOT(dataChanged()));
79 connect(ld->NewLat, SIGNAL(textChanged(QString)), this, SLOT(dataChanged()));
80 connect(ld->NewElev, SIGNAL(valueChanged(double)), this, SLOT(dataChanged()));
81
82 connect(ld->TZBox, SIGNAL(activated(int)), this, SLOT(dataChanged()));
83 connect(ld->DSTRuleBox, SIGNAL(activated(int)), this, SLOT(dataChanged()));
84 connect(ld->GeoBox, SIGNAL(itemSelectionChanged()), this, SLOT(changeCity()));
85 connect(ld->AddCityButton, SIGNAL(clicked()), this, SLOT(addCity()));
86 connect(ld->ClearFieldsButton, SIGNAL(clicked()), this, SLOT(clearFields()));
87 connect(ld->RemoveButton, SIGNAL(clicked()), this, SLOT(removeCity()));
88 connect(ld->UpdateButton, SIGNAL(clicked()), this, SLOT(updateCity()));
89
90 // FIXME Disable this until Qt5 works with Geoclue2
91 #ifdef HAVE_GEOCLUE_2
92 source = QGeoPositionInfoSource::createDefaultSource(this);
93 source->setPreferredPositioningMethods(QGeoPositionInfoSource::SatellitePositioningMethods);
94 qDebug() << "Last known position" << source->lastKnownPosition().coordinate();
95
96 connect(source, SIGNAL(positionUpdated(QGeoPositionInfo)), this, SLOT(positionUpdated(QGeoPositionInfo)));
97 connect(source, SIGNAL(error(QGeoPositionInfoSource::Error)), this, SLOT(positionUpdateError(QGeoPositionInfoSource::Error)));
98 connect(source, SIGNAL(updateTimeout()), this, SLOT(positionUpdateTimeout()));
99
100 connect(ld->GetLocationButton, SIGNAL(clicked()), this, SLOT(requestUpdate()));
101 #endif
102
103 ld->DSTLabel->setText("<a href=\"showrules\">" + i18n("DST rule:") + "</a>");
104 connect(ld->DSTLabel, SIGNAL(linkActivated(QString)), this, SLOT(showTZRules()));
105
106 dataModified = false;
107 nameModified = false;
108 ld->AddCityButton->setEnabled(false);
109
110 ld->errorLabel->setText(QString());
111
112 // FIXME Disable this until Qt5 works with Geoclue2
113 #ifdef HAVE_GEOCLUE_2
114 nam = new QNetworkAccessManager(this);
115 connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(processLocationNameData(QNetworkReply*)));
116 #endif
117
118 initCityList();
119 resize(640, 480);
120 }
121
initCityList()122 void LocationDialog::initCityList()
123 {
124 KStarsData *data = KStarsData::Instance();
125 foreach (GeoLocation *loc, data->getGeoList())
126 {
127 ld->GeoBox->addItem(loc->fullName());
128 filteredCityList.append(loc);
129
130 //If TZ is not an even integer value, add it to listbox
131 if (loc->TZ0() - int(loc->TZ0()) && ld->TZBox->findText(QLocale().toString(loc->TZ0())) != -1)
132 {
133 for (int i = 0; i < ld->TZBox->count(); ++i)
134 {
135 if (ld->TZBox->itemText(i).toDouble() > loc->TZ0())
136 {
137 ld->TZBox->addItem(QLocale().toString(loc->TZ0()), i - 1);
138 break;
139 }
140 }
141 }
142 }
143
144 //Sort the list of Cities alphabetically...note that filteredCityList may now have a different ordering!
145 ld->GeoBox->sortItems();
146
147 ld->CountLabel->setText(
148 i18np("One city matches search criteria", "%1 cities match search criteria", ld->GeoBox->count()));
149
150 // attempt to highlight the current kstars location in the GeoBox
151 ld->GeoBox->setCurrentItem(nullptr);
152 for (int i = 0; i < ld->GeoBox->count(); i++)
153 {
154 if (ld->GeoBox->item(i)->text() == data->geo()->fullName())
155 {
156 ld->GeoBox->setCurrentRow(i);
157 break;
158 }
159 }
160 }
161
enqueueFilterCity()162 void LocationDialog::enqueueFilterCity()
163 {
164 if (timer)
165 timer->stop();
166 else
167 {
168 timer = new QTimer(this);
169 timer->setSingleShot(true);
170 connect(timer, SIGNAL(timeout()), this, SLOT(filterCity()));
171 }
172 timer->start(500);
173 }
174
filterCity()175 void LocationDialog::filterCity()
176 {
177 KStarsData *data = KStarsData::Instance();
178 ld->GeoBox->clear();
179 //Do NOT delete members of filteredCityList!
180 while (!filteredCityList.isEmpty())
181 filteredCityList.takeFirst();
182
183 nameModified = false;
184 dataModified = false;
185 ld->AddCityButton->setEnabled(false);
186 ld->UpdateButton->setEnabled(false);
187
188 foreach (GeoLocation *loc, data->getGeoList())
189 {
190 QString sc(loc->translatedName());
191 QString ss(loc->translatedCountry());
192 QString sp = "";
193 if (!loc->province().isEmpty())
194 sp = loc->translatedProvince();
195
196 if (sc.startsWith(ld->CityFilter->text(), Qt::CaseInsensitive) &&
197 sp.startsWith(ld->ProvinceFilter->text(), Qt::CaseInsensitive) &&
198 ss.startsWith(ld->CountryFilter->text(), Qt::CaseInsensitive))
199 {
200 ld->GeoBox->addItem(loc->fullName());
201 filteredCityList.append(loc);
202 }
203 }
204
205 ld->GeoBox->sortItems();
206
207 ld->CountLabel->setText(
208 i18np("One city matches search criteria", "%1 cities match search criteria", ld->GeoBox->count()));
209
210 if (ld->GeoBox->count() > 0) // set first item in list as selected
211 ld->GeoBox->setCurrentItem(ld->GeoBox->item(0));
212
213 ld->MapView->repaint();
214 }
215
changeCity()216 void LocationDialog::changeCity()
217 {
218 KStarsData *data = KStarsData::Instance();
219
220 //when the selected city changes, set newCity, and redraw map
221 SelectedCity = nullptr;
222 if (ld->GeoBox->currentItem())
223 {
224 for (auto &loc : filteredCityList)
225 {
226 if (loc->fullName() == ld->GeoBox->currentItem()->text())
227 {
228 SelectedCity = loc;
229 break;
230 }
231 }
232 }
233
234 ld->MapView->repaint();
235
236 //Fill the fields at the bottom of the window with the selected city's data.
237 if (SelectedCity)
238 {
239 ld->NewCityName->setText(SelectedCity->translatedName());
240 if (SelectedCity->province().isEmpty())
241 ld->NewProvinceName->setText(QString());
242 else
243 ld->NewProvinceName->setText(SelectedCity->translatedProvince());
244
245 ld->NewCountryName->setText(SelectedCity->translatedCountry());
246 ld->NewLong->showInDegrees(SelectedCity->lng());
247 ld->NewLat->showInDegrees(SelectedCity->lat());
248 ld->TZBox->setEditText(QLocale().toString(SelectedCity->TZ0()));
249 ld->NewElev->setValue(SelectedCity->elevation());
250
251 //Pick the City's rule from the rulebook
252 for (int i = 0; i < ld->DSTRuleBox->count(); ++i)
253 {
254 TimeZoneRule tzr = data->getRulebook().value(ld->DSTRuleBox->itemText(i));
255 if (tzr.equals(SelectedCity->tzrule()))
256 {
257 ld->DSTRuleBox->setCurrentIndex(i);
258 break;
259 }
260 }
261
262 ld->RemoveButton->setEnabled(SelectedCity->isReadOnly() == false);
263 }
264
265 nameModified = false;
266 dataModified = false;
267 ld->AddCityButton->setEnabled(false);
268 ld->UpdateButton->setEnabled(false);
269 }
270
addCity()271 bool LocationDialog::addCity()
272 {
273 return updateCity(CITY_ADD);
274 }
275
updateCity()276 bool LocationDialog::updateCity()
277 {
278 if (SelectedCity == nullptr)
279 return false;
280
281 return updateCity(CITY_UPDATE);
282 }
283
removeCity()284 bool LocationDialog::removeCity()
285 {
286 if (SelectedCity == nullptr)
287 return false;
288
289 return updateCity(CITY_REMOVE);
290 }
291
updateCity(CityOperation operation)292 bool LocationDialog::updateCity(CityOperation operation)
293 {
294 if (operation == CITY_REMOVE)
295 {
296 QString message = i18n("Are you sure you want to remove %1?", selectedCityName());
297 if (KMessageBox::questionYesNo(nullptr, message, i18n("Remove City?")) == KMessageBox::No)
298 return false; //user answered No.
299 }
300 else if (!nameModified && !dataModified)
301 {
302 QString message = i18n("This city already exists in the database.");
303 KSNotification::sorry(message, i18n("Error: Duplicate Entry"));
304 return false;
305 }
306
307 bool latOk(false), lngOk(false), tzOk(false);
308 dms lat = ld->NewLat->createDms(true, &latOk);
309 dms lng = ld->NewLong->createDms(true, &lngOk);
310 QString TimeZoneString = ld->TZBox->lineEdit()->text();
311 TimeZoneString.replace(QLocale().decimalPoint(), ".");
312 double TZ = TimeZoneString.toDouble(&tzOk);
313 double height = ld->NewElev->value();
314
315 if (ld->NewCityName->text().isEmpty() || ld->NewCountryName->text().isEmpty())
316 {
317 QString message = i18n("All fields (except province) must be filled to add this location.");
318 KSNotification::sorry(message, i18n("Fields are Empty"));
319 return false;
320 }
321 else if (!latOk || !lngOk)
322 {
323 QString message = i18n("Could not parse the Latitude/Longitude.");
324 KSNotification::sorry(message, i18n("Bad Coordinates"));
325 return false;
326 }
327 else if (!tzOk)
328 {
329 QString message = i18n("UTC Offset must be selected.");
330 KSNotification::sorry(message, i18n("UTC Offset"));
331 return false;
332 }
333
334 // If name is still the same then it's an update operation
335 if (operation == CITY_ADD && !nameModified)
336 operation = CITY_UPDATE;
337
338 /*if ( !nameModified )
339 {
340 QString message = i18n( "Really override original data for this city?" );
341 if ( KMessageBox::questionYesNo( 0, message, i18n( "Override Existing Data?" ), KGuiItem(i18n("Override Data")), KGuiItem(i18n("Do Not Override"))) == KMessageBox::No )
342 return false; //user answered No.
343 }*/
344
345 QSqlDatabase mycitydb = QSqlDatabase::database("mycitydb");
346 QString dbfile = QDir(KSPaths::writableLocation(QStandardPaths::AppDataLocation)).filePath("mycitydb.sqlite");
347
348 // If it doesn't exist, create it
349 if (QFile::exists(dbfile) == false)
350 {
351 mycitydb.setDatabaseName(dbfile);
352 mycitydb.open();
353 QSqlQuery create_query(mycitydb);
354 QString query("CREATE TABLE city ( "
355 "id INTEGER DEFAULT NULL PRIMARY KEY AUTOINCREMENT, "
356 "Name TEXT DEFAULT NULL, "
357 "Province TEXT DEFAULT NULL, "
358 "Country TEXT DEFAULT NULL, "
359 "Latitude TEXT DEFAULT NULL, "
360 "Longitude TEXT DEFAULT NULL, "
361 "TZ REAL DEFAULT NULL, "
362 "TZRule TEXT DEFAULT NULL,"
363 "Elevation REAL NOT NULL DEFAULT -10 )");
364
365 if (create_query.exec(query) == false)
366 {
367 qCWarning(KSTARS) << create_query.lastError();
368 return false;
369 }
370 }
371 else if (mycitydb.open() == false)
372 {
373 qCWarning(KSTARS) << mycitydb.lastError();
374 return false;
375 }
376
377 //Strip off white space
378 QString name = ld->NewCityName->text().trimmed();
379 QString province = ld->NewProvinceName->text().trimmed();
380 QString country = ld->NewCountryName->text().trimmed();
381 QString TZrule = ld->DSTRuleBox->currentText();
382 double Elevation = ld->NewElev->value();
383 GeoLocation *g = nullptr;
384
385 switch (operation)
386 {
387 case CITY_ADD:
388 {
389 QSqlQuery add_query(mycitydb);
390 add_query.prepare("INSERT INTO city(Name, Province, Country, Latitude, Longitude, TZ, TZRule, Elevation) "
391 "VALUES(:Name, :Province, :Country, :Latitude, :Longitude, :TZ, :TZRule, :Elevation)");
392 add_query.bindValue(":Name", name);
393 add_query.bindValue(":Province", province);
394 add_query.bindValue(":Country", country);
395 add_query.bindValue(":Latitude", lat.toDMSString());
396 add_query.bindValue(":Longitude", lng.toDMSString());
397 add_query.bindValue(":TZ", TZ);
398 add_query.bindValue(":TZRule", TZrule);
399 add_query.bindValue(":Elevation", Elevation);
400 if (add_query.exec() == false)
401 {
402 qCWarning(KSTARS) << add_query.lastError();
403 return false;
404 }
405
406 //Add city to geoList...don't need to insert it alphabetically, since we always sort GeoList
407 g = new GeoLocation(lng, lat, name, province, country, TZ, &KStarsData::Instance()->Rulebook[TZrule], Elevation);
408 KStarsData::Instance()->getGeoList().append(g);
409 }
410 break;
411
412 case CITY_UPDATE:
413 {
414 g = SelectedCity;
415
416 QSqlQuery update_query(mycitydb);
417 update_query.prepare("UPDATE city SET Name = :newName, Province = :newProvince, Country = :newCountry, "
418 "Latitude = :Latitude, Longitude = :Longitude, TZ = :TZ, TZRule = :TZRule, Elevation = :Elevation WHERE "
419 "Name = :Name AND Province = :Province AND Country = :Country");
420 update_query.bindValue(":newName", name);
421 update_query.bindValue(":newProvince", province);
422 update_query.bindValue(":newCountry", country);
423 update_query.bindValue(":Name", SelectedCity->name());
424 update_query.bindValue(":Province", SelectedCity->province());
425 update_query.bindValue(":Country", SelectedCity->country());
426 update_query.bindValue(":Latitude", lat.toDMSString());
427 update_query.bindValue(":Longitude", lng.toDMSString());
428 update_query.bindValue(":TZ", TZ);
429 update_query.bindValue(":TZRule", TZrule);
430 update_query.bindValue(":Elevation", Elevation);
431 if (update_query.exec() == false)
432 {
433 qCWarning(KSTARS) << update_query.lastError();
434 return false;
435 }
436
437 g->setName(name);
438 g->setProvince(province);
439 g->setCountry(country);
440 g->setLat(lat);
441 g->setLong(lng);
442 g->setTZ0(TZ);
443 g->setTZRule(&KStarsData::Instance()->Rulebook[TZrule]);
444 g->setElevation(height);
445
446 }
447 break;
448
449 case CITY_REMOVE:
450 {
451 g = SelectedCity;
452 QSqlQuery delete_query(mycitydb);
453 delete_query.prepare("DELETE FROM city WHERE Name = :Name AND Province = :Province AND Country = :Country");
454 delete_query.bindValue(":Name", name);
455 delete_query.bindValue(":Province", province);
456 delete_query.bindValue(":Country", country);
457 if (delete_query.exec() == false)
458 {
459 qCWarning(KSTARS) << delete_query.lastError();
460 return false;
461 }
462
463 filteredCityList.removeOne(g);
464 KStarsData::Instance()->getGeoList().removeOne(g);
465 delete g;
466 g = nullptr;
467 }
468 break;
469 }
470
471 //(possibly) insert new city into GeoBox by running filterCity()
472 filterCity();
473
474 //Attempt to highlight new city in list
475 ld->GeoBox->setCurrentItem(nullptr);
476 if (g && ld->GeoBox->count())
477 {
478 for (int i = 0; i < ld->GeoBox->count(); i++)
479 {
480 if (ld->GeoBox->item(i)->text() == g->fullName())
481 {
482 ld->GeoBox->setCurrentRow(i);
483 break;
484 }
485 }
486 }
487
488 mycitydb.commit();
489 mycitydb.close();
490
491 return true;
492 }
493
findCitiesNear(int lng,int lat)494 void LocationDialog::findCitiesNear(int lng, int lat)
495 {
496 KStarsData *data = KStarsData::Instance();
497 //find all cities within 3 degrees of (lng, lat); list them in GeoBox
498 ld->GeoBox->clear();
499 //Remember, do NOT delete members of filteredCityList
500 while (!filteredCityList.isEmpty())
501 filteredCityList.takeFirst();
502
503 foreach (GeoLocation *loc, data->getGeoList())
504 {
505 if ((abs(lng - int(loc->lng()->Degrees())) < 3) && (abs(lat - int(loc->lat()->Degrees())) < 3))
506 {
507 ld->GeoBox->addItem(loc->fullName());
508 filteredCityList.append(loc);
509 }
510 }
511
512 ld->GeoBox->sortItems();
513 ld->CountLabel->setText(
514 i18np("One city matches search criteria", "%1 cities match search criteria", ld->GeoBox->count()));
515
516 if (ld->GeoBox->count() > 0) // set first item in list as selected
517 ld->GeoBox->setCurrentItem(ld->GeoBox->item(0));
518
519 repaint();
520 }
521
checkLongLat()522 bool LocationDialog::checkLongLat()
523 {
524 if (ld->NewLong->text().isEmpty() || ld->NewLat->text().isEmpty())
525 return false;
526
527 bool ok;
528 double lng = ld->NewLong->createDms(true, &ok).Degrees();
529 if (!ok)
530 return false;
531 double lat = ld->NewLat->createDms(true, &ok).Degrees();
532 if (!ok)
533 return false;
534
535 if (fabs(lng) > 180 || fabs(lat) > 90)
536 return false;
537
538 return true;
539 }
540
clearFields()541 void LocationDialog::clearFields()
542 {
543 ld->CityFilter->clear();
544 ld->ProvinceFilter->clear();
545 ld->CountryFilter->clear();
546 ld->NewCityName->clear();
547 ld->NewProvinceName->clear();
548 ld->NewCountryName->clear();
549 ld->NewLong->clearFields();
550 ld->NewLat->clearFields();
551 ld->NewElev->setValue(-10);
552 ld->TZBox->setCurrentIndex(-1);
553 // JM 2017-09-16: No, let's not assume it is 0. User have to explicitly set TZ so avoid mistakes.
554 //ld->TZBox->lineEdit()->setText(QLocale().toString(0.0));
555 ld->DSTRuleBox->setCurrentIndex(0);
556 nameModified = true;
557 dataModified = false;
558
559 ld->AddCityButton->setEnabled(false);
560 ld->UpdateButton->setEnabled(false);
561 ld->NewCityName->setFocus();
562 }
563
showTZRules()564 void LocationDialog::showTZRules()
565 {
566 QFile file;
567
568 if (KSUtils::openDataFile(file, "TZrules.dat") == false)
569 return;
570
571 QTextStream stream(&file);
572
573 QString message = i18n("Daylight Saving Time Rules");
574
575 QPointer<QDialog> tzd = new QDialog(this);
576 tzd->setWindowTitle(message);
577
578 QPlainTextEdit *textEdit = new QPlainTextEdit(tzd);
579 textEdit->setReadOnly(true);
580 while (stream.atEnd() == false)
581 {
582 QString line = stream.readLine();
583 if (line.startsWith('#'))
584 textEdit->appendPlainText(line);
585 }
586 textEdit->moveCursor(QTextCursor::Start);
587 textEdit->ensureCursorVisible();
588
589 QVBoxLayout *mainLayout = new QVBoxLayout;
590 mainLayout->addWidget(textEdit);
591
592 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
593 mainLayout->addWidget(buttonBox);
594 connect(buttonBox, SIGNAL(rejected()), tzd, SLOT(reject()));
595
596 tzd->setLayout(mainLayout);
597
598 tzd->exec();
599
600 delete tzd;
601 }
602
nameChanged()603 void LocationDialog::nameChanged()
604 {
605 nameModified = true;
606 dataChanged();
607 }
608
609 //do not enable Add button until all data are present and valid.
dataChanged()610 void LocationDialog::dataChanged()
611 {
612 dataModified = true;
613 ld->AddCityButton->setEnabled(nameModified && !ld->NewCityName->text().isEmpty() &&
614 !ld->NewCountryName->text().isEmpty() && checkLongLat() && ld->TZBox->currentIndex() != -1);
615 if (SelectedCity)
616 ld->UpdateButton->setEnabled(SelectedCity->isReadOnly() == false && !ld->NewCityName->text().isEmpty() &&
617 !ld->NewCountryName->text().isEmpty() && checkLongLat() && ld->TZBox->currentIndex() != -1);
618
619 if (ld->AddCityButton->isEnabled() == false && ld->UpdateButton->isEnabled() == false)
620 {
621 if (ld->NewCityName->text().isEmpty())
622 {
623 ld->errorLabel->setText(i18n("Cannot add new location -- city name blank"));
624 }
625 else if (ld->NewCountryName->text().isEmpty())
626 {
627 ld->errorLabel->setText(i18n("Cannot add new location -- country name blank"));
628 }
629 else if (!checkLongLat())
630 {
631 ld->errorLabel->setText(i18n("Cannot add new location -- invalid latitude / longitude"));
632 }
633 else if (ld->TZBox->currentIndex() == -1)
634 {
635 ld->errorLabel->setText(i18n("Cannot add new location -- missing UTC Offset"));
636 }
637 else if (SelectedCity && SelectedCity->isReadOnly())
638 {
639 ld->errorLabel->setText(i18n("City is Read Only. Change name to add new city."));
640 }
641 }
642 else
643 {
644 ld->errorLabel->setText(QString());
645 }
646 }
647
slotOk()648 void LocationDialog::slotOk()
649 {
650 if (ld->AddCityButton->isEnabled())
651 {
652 if (addCity())
653 accept();
654 }
655 else
656 accept();
657 }
658
659 // FIXME Disable this until Qt5 works with Geoclue2
660 #ifdef HAVE_GEOCLUE_2
getNameFromCoordinates(double latitude,double longitude)661 void LocationDialog::getNameFromCoordinates(double latitude, double longitude)
662 {
663 QString lat = QString::number(latitude);
664 QString lon = QString::number(longitude);
665 QString latlng(lat + ", " + lon);
666
667 QUrl url("http://maps.googleapis.com/maps/api/geocode/json");
668 QUrlQuery query;
669 query.addQueryItem("latlng", latlng);
670 url.setQuery(query);
671 qDebug() << "submitting request";
672
673 nam->get(QNetworkRequest(url));
674 connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(processLocationNameData(QNetworkReply*)));
675 }
676
processLocationNameData(QNetworkReply * networkReply)677 void LocationDialog::processLocationNameData(QNetworkReply *networkReply)
678 {
679 if (!networkReply)
680 return;
681
682 if (!networkReply->error())
683 {
684 QJsonDocument document = QJsonDocument::fromJson(networkReply->readAll());
685
686 if (document.isObject())
687 {
688 QJsonObject obj = document.object();
689 QJsonValue val;
690
691 if (obj.contains(QStringLiteral("results")))
692 {
693 val = obj["results"];
694
695 QString city =
696 val.toArray()[0].toObject()["address_components"].toArray()[2].toObject()["long_name"].toString();
697 QString region =
698 val.toArray()[0].toObject()["address_components"].toArray()[3].toObject()["long_name"].toString();
699 QString country =
700 val.toArray()[0].toObject()["address_components"].toArray()[4].toObject()["long_name"].toString();
701
702 //emit newNameFromCoordinates(city, region, country);
703 }
704 else
705 {
706 }
707 }
708 }
709 networkReply->deleteLater();
710 }
711
requestUpdate()712 void LocationDialog::requestUpdate()
713 {
714 source->requestUpdate(15000);
715 }
716
positionUpdated(const QGeoPositionInfo & info)717 void LocationDialog::positionUpdated(const QGeoPositionInfo &info)
718 {
719 qDebug() << "Position updated:" << info;
720 }
721
positionUpdateError(QGeoPositionInfoSource::Error error)722 void LocationDialog::positionUpdateError(QGeoPositionInfoSource::Error error)
723 {
724 qDebug() << "Position update error: " << error;
725 }
726
positionUpdateTimeout()727 void LocationDialog::positionUpdateTimeout()
728 {
729 qDebug() << "Timed out!";
730 qDebug() << source->error();
731 }
732 #endif
733