1 /*
2     SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org>
3 
4     SPDX-License-Identifier: GPL-2.0-or-later
5 */
6 
7 #pragma once
8 
9 #include "geolocation.h"
10 #include "ui_locationdialog.h"
11 
12 #include <QPointer>
13 #ifdef HAVE_GEOCLUE2
14 #include <QGeoPositionInfo>
15 #include <QGeoPositionInfoSource>
16 #endif
17 #include <QDialog>
18 #include <QList>
19 
20 class QTimer;
21 class QNetworkAccessManager;
22 class QNetworkReply;
23 
24 class LocationDialogUI : public QFrame, public Ui::LocationDialog
25 {
26     Q_OBJECT
27   public:
28     explicit LocationDialogUI(QWidget *parent = nullptr);
29 };
30 
31 /**
32  * @class LocationDialog
33  * Dialog for changing the geographic location of the observer.  The
34  * dialog is divided into two sections.
35  *
36  * The top section allows the location to be selected from a database
37  * of 2000 cities.  It contains a MapCanvas (showing map of the globe
38  * with cities overlaid, with a handler for mouse clicks), a QListBox
39  * containing the names of cities in the database, and three QLineEdit
40  * widgets, which allow the user to filter the List by the name of the
41  * City, Province, and Country.  In addition, the List
42  * can be filtered by location, by clicking anywhere in the MapCanvas.
43  * Doing so will display cities within 2 degrees of the clicked position.
44  *
45  * The bottom section allows the location to be specified manually.
46  * The Longitude, Latitude, City name, Province/State name, and Country name
47  * are entered into KLineEdits.  There is also a QPushButton for adding the
48  * location to the custom Cities database.  If the user selects "Add" without
49  * filling in all of the manual entry fields, an error message is displayed.
50  *
51  * The user can fetch current geographic location from QtPosition system. The actual
52  * underlying location source depends on the OS and what modules are currently available, if any.
53  *
54  * @short Geographic Location dialog
55  * @author Jason Harris
56  * @author Jasem Mutlaq
57  * @author Artem Fedoskin
58  * @version 1.1
59  */
60 class LocationDialog : public QDialog
61 {
62     Q_OBJECT
63 
64   public:
65     typedef enum { CITY_ADD, CITY_UPDATE, CITY_REMOVE } CityOperation;
66 
67     /**
68      * Constructor.  Create all widgets, and pack them into QLayouts.
69      * Connect Signals to Slots.  Run initCityList().
70      */
71     explicit LocationDialog(QWidget *parent);
72 
73     /**
74      * Initialize list of cities.  Note that the database is not read in here,
75      * that is done in the KStars constructor.  This simply loads the local QListBox
76      * with the names of the cities from the kstarsData object.
77      */
78     void initCityList(void);
79 
80     /** @return pointer to the highlighted city in the List. */
selectedCity()81     GeoLocation *selectedCity() const { return SelectedCity; }
82 
83     /** @return pointer to the List of filtered city pointers. */
filteredList()84     QList<GeoLocation *> filteredList() { return filteredCityList; }
85 
86     /**
87      * @short Show only cities within 3 degrees of point specified by arguments
88      * @param longitude the longitude of the search point (int)
89      * @param latitude the latitude of the search point (int)
90      */
91     void findCitiesNear(int longitude, int latitude);
92 
93     /** @return the city name of the selected location. */
selectedCityName()94     QString selectedCityName() const { return SelectedCity->translatedName(); }
95 
96     /** @return the province name of the selected location. */
selectedProvinceName()97     QString selectedProvinceName() const { return SelectedCity->translatedProvince(); }
98 
99     /** @return the country name of the selected location. */
selectedCountryName()100     QString selectedCountryName() const { return SelectedCity->translatedCountry(); }
101 
102   public slots:
103     /**
104      * When text is entered in the City/Province/Country Filter KLineEdits, the List of cities is
105      * trimmed to show only cities beginning with the entered text.  Also, the QMemArray of ID
106      * numbers is kept in sync with the filtered list.
107      */
108     void filterCity();
109 
110     /**
111      * @short Filter by city / province / country only after a few milliseconds
112      */
113     void enqueueFilterCity();
114 
115     /**
116      * When the selected city in the QListBox changes, repaint the MapCanvas
117      * so that the crosshairs icon appears on the newly selected city.
118      */
119     void changeCity();
120 
121     /**
122      * When the "Add new city" QPushButton is clicked, add the manually-entered
123      * city information to the user's custom city database.
124      * @return true on success
125      */
126     bool addCity();
127 
128     /**
129      * When the "Update City" QPushButton is clicked, update the city
130      * information in the user's custom city database.
131      * @return true on success
132      */
133     bool updateCity();
134 
135     /**
136      * When the "Remove City" QPushButton is clicked, remove the
137      * city information from the user's custom city database.
138      * @return true on success
139      */
140     bool removeCity();
141 
142     /**
143      * @brief updateCity Adds, updates, or removes a city from the user's database.
144      * @param operation Add, update, or remove city
145      * @return true on success
146      */
147     bool updateCity(LocationDialog::CityOperation operation);
148 
149     // FIXME Disable this until Qt5 works with Geoclue2
150     #ifdef HAVE_GEOCLUE_2
151     /**
152      * @brief getNameFromCoordinates Given the current latitude and longitude, use Google Location API services to reverse lookup
153      * the city, province, and country located at the requested position.
154      * @param latitude Latitude in degrees
155      * @param longitude Longitude is degrees
156      */
157     void getNameFromCoordinates(double latitude, double longitude);
158     #endif
159 
160     void clearFields();
161     void showTZRules();
162     void nameChanged();
163     void dataChanged();
164     void slotOk();
165 
166 protected slots:
167     // FIXME Disable this until Qt5 works with Geoclue2
168     #ifdef HAVE_GEOCLUE_2
169     void processLocationNameData(QNetworkReply *rep);
170     void requestUpdate();
171     void positionUpdated(const QGeoPositionInfo &info);
172     void positionUpdateError(QGeoPositionInfoSource::Error error);
173     void positionUpdateTimeout();
174     #endif
175 
176   private:
177     /** Make sure Longitude and Latitude values are valid. */
178     bool checkLongLat();
179 
180     bool dataModified { false };
181     bool nameModified { false };
182 
183     LocationDialogUI *ld { nullptr };
184     GeoLocation *SelectedCity { nullptr };
185     QList<GeoLocation *> filteredCityList;
186     QTimer *timer { nullptr };
187     //Retrieve the name of city
188 
189     #ifdef HAVE_GEOCLUE_2
190     QNetworkAccessManager *nam { nullptr };
191     QPointer<QGeoPositionInfoSource> source;
192     #endif
193 };
194