Kstars

locationdialog.cpp
1 /*
2  SPDX-FileCopyrightText: 2001 Jason Harris <[email protected]>
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 
34 LocationDialogUI::LocationDialogUI(QWidget *parent) : QFrame(parent)
35 {
36  setupUi(this);
37 }
38 
39 LocationDialog::LocationDialog(QWidget *parent) : QDialog(parent), timer(nullptr)
40 {
41 #ifdef Q_OS_OSX
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 
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
93  source->setPreferredPositioningMethods(QGeoPositionInfoSource::SatellitePositioningMethods);
94  qDebug() << Q_FUNC_INFO << "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 
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 
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 
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 
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->show(SelectedCity->lng());
247  ld->NewLat->show(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 
272 {
273  return updateCity(CITY_ADD);
274 }
275 
277 {
278  if (SelectedCity == nullptr)
279  return false;
280 
281  return updateCity(CITY_UPDATE);
282 }
283 
285 {
286  if (SelectedCity == nullptr)
287  return false;
288 
289  return updateCity(CITY_REMOVE);
290 }
291 
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(&latOk);
309  dms lng = ld->NewLong->createDms(&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::AppLocalDataLocation)).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 
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 
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(&ok).Degrees();
529  if (!ok)
530  return false;
531  double lat = ld->NewLat->createDms(&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 
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 
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 
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 
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.
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 
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
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");
669  query.addQueryItem("latlng", latlng);
670  url.setQuery(query);
671  qDebug() << Q_FUNC_INFO << "submitting request";
672 
673  nam->get(QNetworkRequest(url));
674  connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(processLocationNameData(QNetworkReply*)));
675 }
676 
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 
712 void LocationDialog::requestUpdate()
713 {
714  source->requestUpdate(15000);
715 }
716 
717 void LocationDialog::positionUpdated(const QGeoPositionInfo &info)
718 {
719  qDebug() << Q_FUNC_INFO << "Position updated:" << info;
720 }
721 
722 void LocationDialog::positionUpdateError(QGeoPositionInfoSource::Error error)
723 {
724  qDebug() << Q_FUNC_INFO << "Position update error: " << error;
725 }
726 
727 void LocationDialog::positionUpdateTimeout()
728 {
729  qDebug() << Q_FUNC_INFO << "Timed out!";
730  qDebug() << Q_FUNC_INFO << source->error();
731 }
732 #endif
void append(const T &value)
void changeCity()
When the selected city in the QListBox changes, repaint the MapCanvas so that the crosshairs icon app...
QJsonObject object() const const
QStringView country(QStringView ifopt)
void setTZ0(double value)
Set Time zone.
Definition: geolocation.h:157
LocationDialog(QWidget *parent)
Constructor.
QList< GeoLocation * > & getGeoList()
Definition: kstarsdata.h:235
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
QString number(int n, int base)
QString fullName() const
Definition: geolocation.cpp:46
virtual void reject()
CaseInsensitive
void setCountry(const QString &n)
Set Country name according to argument.
Definition: geolocation.h:245
const T value(const Key &key, const T &defaultValue) const const
void moveCursor(QTextCursor::MoveOperation operation, QTextCursor::MoveMode mode)
QNetworkReply::NetworkError error() const const
double TZ0() const
Definition: geolocation.h:136
const CachingDms * lng() const
Definition: geolocation.h:64
bool updateCity()
When the "Update City" QPushButton is clicked, update the city information in the user's custom city ...
void setName(const QString &n)
Set City name according to argument.
Definition: geolocation.h:229
bool exists() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
bool contains(const QString &key) const const
void setReadOnly(bool ro)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
KSERVICE_EXPORT KService::List query(FilterFunc filterFunc)
void deleteLater()
void appendPlainText(const QString &text)
void rejected()
QString i18n(const char *text, const TYPE &arg...)
const QString toDMSString(const bool forceSign=false, const bool machineReadable=false, const bool highPrecision=false) const
Definition: dms.cpp:279
void setWindowFlags(Qt::WindowFlags type)
const CachingDms * lat() const
Definition: geolocation.h:70
void filterCity()
When text is entered in the City/Province/Country Filter KLineEdits, the List of cities is trimmed to...
void setDatabaseName(const QString &name)
bool removeOne(const T &value)
bool isEmpty() const const
GeoLocation * geo()
Definition: kstarsdata.h:229
QString translatedName() const
Definition: geolocation.cpp:76
void setWindowTitle(const QString &)
bool addCity()
When the "Add new city" QPushButton is clicked, add the manually-entered city information to the user...
QString translatedCountry() const
Definition: geolocation.cpp:97
QString translatedProvince() const
Definition: geolocation.cpp:90
bool isObject() const const
void setTZRule(TimeZoneRule *value)
Set Time zone rule.
Definition: geolocation.h:164
void initCityList(void)
Initialize list of cities.
double toDouble(bool *ok) const const
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QJsonArray toArray() const const
QString & replace(int position, int n, QChar after)
void findCitiesNear(int longitude, int latitude)
Show only cities within 3 degrees of point specified by arguments.
QString province() const
Definition: geolocation.h:115
QString i18np(const char *singular, const char *plural, const TYPE &arg...)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
const QMap< QString, TimeZoneRule > & getRulebook() const
Return map for daylight saving rules.
Definition: kstarsdata.h:261
An angle, stored as degrees, but expressible in many ways.
Definition: dms.h:37
void resize(int w, int h)
void ensureCursorVisible()
void enqueueFilterCity()
Filter by city / province / country only after a few milliseconds.
QList< Key > keys() const const
void setProvince(const QString &n)
Set Province name according to argument.
Definition: geolocation.h:237
const double & Degrees() const
Definition: dms.h:141
QString name(StandardShortcut id)
bool equals(TimeZoneRule *r)
QString filePath(const QString &fileName) const const
bool removeCity()
When the "Remove City" QPushButton is clicked, remove the city information from the user's custom cit...
QString i18nc(const char *context, const char *text, const TYPE &arg...)
void setLong(const dms &l)
Set longitude according to dms argument.
Definition: geolocation.h:171
QGeoPositionInfoSource * createDefaultSource(QObject *parent)
QByteArray readAll()
QSqlDatabase database(const QString &connectionName, bool open)
void setLayout(QLayout *layout)
QSqlError lastError() const const
ButtonCode questionYesNo(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonYes=KStandardGuiItem::yes(), const KGuiItem &buttonNo=KStandardGuiItem::no(), const QString &dontAskAgainName=QString(), Options options=Notify)
QString message
void finished(int result)
void setLat(const dms &l)
Set latitude according to dms argument.
Definition: geolocation.h:180
Relevant data about an observing location on Earth.
Definition: geolocation.h:27
void accepted()
void setElevation(double hg)
Set elevation above sea level.
Definition: geolocation.h:189
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sun Aug 14 2022 04:13:58 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.