File indexing completed on 2024-04-21 14:44:35

0001 /*
0002     SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "geolocation.h"
0010 #include "ui_locationdialog.h"
0011 
0012 #include <QPointer>
0013 #ifdef HAVE_GEOCLUE2
0014 #include <QGeoPositionInfo>
0015 #include <QGeoPositionInfoSource>
0016 #endif
0017 #include <QDialog>
0018 #include <QList>
0019 
0020 class QTimer;
0021 class QNetworkAccessManager;
0022 class QNetworkReply;
0023 
0024 class LocationDialogUI : public QFrame, public Ui::LocationDialog
0025 {
0026     Q_OBJECT
0027   public:
0028     explicit LocationDialogUI(QWidget *parent = nullptr);
0029 };
0030 
0031 /**
0032  * @class LocationDialog
0033  * Dialog for changing the geographic location of the observer.  The
0034  * dialog is divided into two sections.
0035  *
0036  * The top section allows the location to be selected from a database
0037  * of 2000 cities.  It contains a MapCanvas (showing map of the globe
0038  * with cities overlaid, with a handler for mouse clicks), a QListBox
0039  * containing the names of cities in the database, and three QLineEdit
0040  * widgets, which allow the user to filter the List by the name of the
0041  * City, Province, and Country.  In addition, the List
0042  * can be filtered by location, by clicking anywhere in the MapCanvas.
0043  * Doing so will display cities within 2 degrees of the clicked position.
0044  *
0045  * The bottom section allows the location to be specified manually.
0046  * The Longitude, Latitude, City name, Province/State name, and Country name
0047  * are entered into KLineEdits.  There is also a QPushButton for adding the
0048  * location to the custom Cities database.  If the user selects "Add" without
0049  * filling in all of the manual entry fields, an error message is displayed.
0050  *
0051  * The user can fetch current geographic location from QtPosition system. The actual
0052  * underlying location source depends on the OS and what modules are currently available, if any.
0053  *
0054  * @short Geographic Location dialog
0055  * @author Jason Harris
0056  * @author Jasem Mutlaq
0057  * @author Artem Fedoskin
0058  * @version 1.1
0059  */
0060 class LocationDialog : public QDialog
0061 {
0062     Q_OBJECT
0063 
0064   public:
0065     typedef enum { CITY_ADD, CITY_UPDATE, CITY_REMOVE } CityOperation;
0066 
0067     /**
0068      * Constructor.  Create all widgets, and pack them into QLayouts.
0069      * Connect Signals to Slots.  Run initCityList().
0070      */
0071     explicit LocationDialog(QWidget *parent);
0072 
0073     /**
0074      * Initialize list of cities.  Note that the database is not read in here,
0075      * that is done in the KStars constructor.  This simply loads the local QListBox
0076      * with the names of the cities from the kstarsData object.
0077      */
0078     void initCityList(void);
0079 
0080     /** @return pointer to the highlighted city in the List. */
0081     GeoLocation *selectedCity() const { return SelectedCity; }
0082 
0083     /** @return pointer to the List of filtered city pointers. */
0084     QList<GeoLocation *> filteredList() { return filteredCityList; }
0085 
0086     /**
0087      * @short Show only cities within 3 degrees of point specified by arguments
0088      * @param longitude the longitude of the search point (int)
0089      * @param latitude the latitude of the search point (int)
0090      */
0091     void findCitiesNear(int longitude, int latitude);
0092 
0093     /** @return the city name of the selected location. */
0094     QString selectedCityName() const { return SelectedCity->translatedName(); }
0095 
0096     /** @return the province name of the selected location. */
0097     QString selectedProvinceName() const { return SelectedCity->translatedProvince(); }
0098 
0099     /** @return the country name of the selected location. */
0100     QString selectedCountryName() const { return SelectedCity->translatedCountry(); }
0101 
0102   public slots:
0103     /**
0104      * When text is entered in the City/Province/Country Filter KLineEdits, the List of cities is
0105      * trimmed to show only cities beginning with the entered text.  Also, the QMemArray of ID
0106      * numbers is kept in sync with the filtered list.
0107      */
0108     void filterCity();
0109 
0110     /**
0111      * @short Filter by city / province / country only after a few milliseconds
0112      */
0113     void enqueueFilterCity();
0114 
0115     /**
0116      * When the selected city in the QListBox changes, repaint the MapCanvas
0117      * so that the crosshairs icon appears on the newly selected city.
0118      */
0119     void changeCity();
0120 
0121     /**
0122      * When the "Add new city" QPushButton is clicked, add the manually-entered
0123      * city information to the user's custom city database.
0124      * @return true on success
0125      */
0126     bool addCity();
0127 
0128     /**
0129      * When the "Update City" QPushButton is clicked, update the city
0130      * information in the user's custom city database.
0131      * @return true on success
0132      */
0133     bool updateCity();
0134 
0135     /**
0136      * When the "Remove City" QPushButton is clicked, remove the
0137      * city information from the user's custom city database.
0138      * @return true on success
0139      */
0140     bool removeCity();
0141 
0142     /**
0143      * @brief updateCity Adds, updates, or removes a city from the user's database.
0144      * @param operation Add, update, or remove city
0145      * @return true on success
0146      */
0147     bool updateCity(LocationDialog::CityOperation operation);
0148 
0149     // FIXME Disable this until Qt5 works with Geoclue2
0150     #ifdef HAVE_GEOCLUE_2
0151     /**
0152      * @brief getNameFromCoordinates Given the current latitude and longitude, use Google Location API services to reverse lookup
0153      * the city, province, and country located at the requested position.
0154      * @param latitude Latitude in degrees
0155      * @param longitude Longitude is degrees
0156      */
0157     void getNameFromCoordinates(double latitude, double longitude);
0158     #endif
0159 
0160     void clearFields();
0161     void showTZRules();
0162     void nameChanged();
0163     void dataChanged();
0164     void slotOk();
0165 
0166 protected slots:
0167     // FIXME Disable this until Qt5 works with Geoclue2
0168     #ifdef HAVE_GEOCLUE_2
0169     void processLocationNameData(QNetworkReply *rep);
0170     void requestUpdate();
0171     void positionUpdated(const QGeoPositionInfo &info);
0172     void positionUpdateError(QGeoPositionInfoSource::Error error);
0173     void positionUpdateTimeout();
0174     #endif
0175 
0176   private:
0177     /** Make sure Longitude and Latitude values are valid. */
0178     bool checkLongLat();
0179 
0180     bool dataModified { false };
0181     bool nameModified { false };
0182 
0183     LocationDialogUI *ld { nullptr };
0184     GeoLocation *SelectedCity { nullptr };
0185     QList<GeoLocation *> filteredCityList;
0186     QTimer *timer { nullptr };
0187     //Retrieve the name of city
0188 
0189     #ifdef HAVE_GEOCLUE_2
0190     QNetworkAccessManager *nam { nullptr };
0191     QPointer<QGeoPositionInfoSource> source;
0192     #endif
0193 };