1 /*
2  * Copyright (C) 2008 Fabien Chereau
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA  02110-1335, USA.
17  */
18 
19 #ifndef STELLOCATIONMGR_HPP
20 #define STELLOCATIONMGR_HPP
21 
22 #include "StelLocation.hpp"
23 #include <QString>
24 #include <QObject>
25 #include <QMetaType>
26 #include <QMap>
27 
28 typedef QList<StelLocation> LocationList;
29 typedef QMap<QString,StelLocation> LocationMap;
30 typedef QMap<QByteArray,QByteArray> TimezoneNameMap;
31 
32 typedef struct
33 {
34 	int code;
35 	QString regionName;
36 	QString countries;
37 	QString planet;
38 } GeoRegion;
39 
40 class GPSLookupHelper;
41 
42 //! @class StelLocationMgr
43 //! Manage the list of available location.
44 class StelLocationMgr : public QObject
45 {
46 	Q_OBJECT
47 
48 public:
49 	//! Default constructor which loads the list of locations from the base and user location files.
50 	StelLocationMgr();
51 	~StelLocationMgr();
52 
53 	//! Construct a StelLocationMgr which uses the locations given instead of loading them from the files.
54 	StelLocationMgr(const LocationList& locations);
55 
56 	//! Replaces the loaded location list
57 	void setLocations(const LocationList& locations);
58 
59 	//! Return the list of all loaded locations
getAll() const60 	LocationList getAll() const {return locations.values();}
61 
62 	//! Returns a map of all loaded locations. The key is the location ID, suitable for a list view.
getAllMap() const63 	LocationMap getAllMap() const { return locations; }
64 
65 	//! Return the StelLocation from a CLI
66 	const StelLocation locationFromCLI() const;
67 
68 	//! Return a valid location when no valid one was found.
getLastResortLocation() const69 	const StelLocation& getLastResortLocation() const {return lastResortLocation;}
70 
71 	//! Get whether a location can be permanently added to the list of user locations
72 	//! The main constraint is that the small string must be unique
73 	bool canSaveUserLocation(const StelLocation& loc) const;
74 
75 	//! Add permanently a location to the list of user locations
76 	//! It is later identified by its small string
77 	bool saveUserLocation(const StelLocation& loc);
78 
79 	//! Get whether a location can be deleted from the list of user locations
80 	//! If the location comes from the base read only list, it cannot be deleted
81 	//! @param id the location ID
82 	bool canDeleteUserLocation(const QString& id) const;
83 
84 	//! Delete permanently the given location from the list of user locations
85 	//! If the location comes from the base read only list, it cannot be deleted and false is returned
86 	//! @param id the location ID
87 	bool deleteUserLocation(const QString& id);
88 
89 	//! Find list of locations within @param radiusDegrees of selected (usually screen-clicked) coordinates.
90 	LocationMap pickLocationsNearby(const QString planetName, const float longitude, const float latitude, const float radiusDegrees);
91 	//! Find list of locations in a particular region only.
92 	LocationMap pickLocationsInRegion(const QString region);
93 
94 	//! return a QStringList of region names by planet (return all list of regions if planet name is empty)
95 	QStringList getRegionNames(const QString& planet = "") const;
96 
97 	//! Pick region name from ISO 3166-1 two-letter country codes
98 	static QString pickRegionFromCountryCode(const QString countryCode);
99 	//! Pick region name from country English name
100 	static QString pickRegionFromCountry(const QString country);
101 	//! Pick region name from region code
102 	static QString pickRegionFromCode(int regionCode);
103 
104 public slots:
105 	//! Return the StelLocation for a given string
106 	//! Can match location name, or coordinates
107 	const StelLocation locationForString(const QString& s) const;
108 
109 	//! Find location via online lookup of IP address
110 	void locationFromIP();
111 
112 	//! return a QStringList of valid timezone names in Stellarium's location database.
113 	QStringList getAllTimezoneNames() const;
114 
115 #ifdef ENABLE_GPS
116 	//! Try to get a location from GPS lookup.
117 	//! This prefers GPSD on non-Windows platforms, and uses Qt positioning with a NMEA serial device otherwise
118 	//! Use the gpsResult() signal to determine if the location was set successfully.
119 	//! With argument 0, this always signals true.
120 	//! @note When using GPSD not on localhost, don't forget the -G switch when starting gpsd there!
121 	//! @param interval set negative to just fetch one position, mseconds to start periodic query, or 0 to stop those.
122 	//! It may be better to leave it running to observe incoming data, then switch off when fix seems good.
123 	//! When disabled, the NMEA device and its serial connection is released.
124 	void locationFromGPS(int interval=-1);
125 #endif
126 
127 	//! Check timezone string and return either the same or one that we use in the Stellarium location database.
128 	//! If timezone name starts with "UTC", always return unchanged.
129 	//! This is required to store timezone names exactly as we know them, and not mix ours and current-IANA spelling flavour.
130 	static QString sanitizeTimezoneStringForLocationDB(QString tzString);
131 	//! Attempt to translate a timezone name from those used in Stellarium's location database to a name which is known
132 	//! to Qt at runtime as result of QTimeZone::availableTimeZoneIds(). That list may be updated by OS anytime and is known to differ
133 	//! between OSes. Some spellings may be different, or in some cases some names get simply translated to "UTC+HH:MM" style.
134 	//! The empty string gets translated to "UTC".
135 	static QString sanitizeTimezoneStringFromLocationDB(QString dbString);
136 
137 signals:
138 	//! Can be used to detect changes to the full location list
139 	//! i.e. when the user added or removed locations
140 	void locationListChanged();
141 
142 #ifdef ENABLE_GPS
143 	//! emitted when GPS location query and setting location either succeed or fail.
144 	//! @param success true if successful, false in case of any error (no device, timeout, bad fix, ...).
145 	void gpsQueryFinished(bool success);
146 #endif
147 private slots:
148 	//! Process answer from online lookup of IP address
149 	void changeLocationFromNetworkLookup();
150 #ifdef ENABLE_GPS
151 	void changeLocationFromGPSQuery(const StelLocation& loc);
152 	void gpsQueryError(const QString& err);
153 #endif
154 private:
155 	void loadRegions();
156 	void loadCountries();
157 	void generateBinaryLocationFile(const QString& txtFile, bool isUserLocation, const QString& binFile) const;
158 
159 	//! Load cities from a file
160 	static LocationMap loadCities(const QString& fileName, bool isUserLocation);
161 	static LocationMap loadCitiesBin(const QString& fileName);
162 
163 	//! The list of all loaded locations
164 	LocationMap locations;
165 	//! A Map which has to be used to replace, system- and Qt-version dependent,
166 	//! timezone names from our location database to the code names currently used by Qt.
167 	//! Required to avoid https://bugs.launchpad.net/stellarium/+bug/1662132,
168 	//! details on IANA names with Qt at http://doc.qt.io/qt-5/qtimezone.html.
169 	//! This has nothing to do with the Windows timezone names!
170 	//! Key: TZ name as used in our database.
171 	//! Value: TZ name as may be available instead in the currently running version of Qt.
172 	//! The list has to be maintained based on empirical observations.
173 	//! @todo Make it load from a configurable external file.
174 	static TimezoneNameMap locationDBToIANAtranslations;
175 
176 	static QList<GeoRegion> regions;
177 	static QMap<QString, QString> countryCodeToRegionMap;
178 	static QMap<QString, QString> countryNameToCodeMap;
179 
180 	StelLocation lastResortLocation;
181 
182 	GPSLookupHelper *nmeaHelper,*libGpsHelper;
183 };
184 
185 #endif // STELLOCATIONMGR_HPP
186