StelLocationMgr.cpp   StelLocationMgr.cpp 
skipping to change at line 24 skipping to change at line 24
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA. * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
*/ */
#include "StelApp.hpp" #include "StelApp.hpp"
#include "StelCore.hpp" #include "StelCore.hpp"
#include "StelFileMgr.hpp" #include "StelFileMgr.hpp"
#include "StelLocationMgr.hpp" #include "StelLocationMgr.hpp"
#include "StelUtils.hpp" #include "StelUtils.hpp"
#include "StelJsonParser.hpp"
#include <QStringListModel> #include <QStringListModel>
#include <QDebug> #include <QDebug>
#include <QFile> #include <QFile>
#include <QDir> #include <QDir>
#include <QtNetwork/QNetworkInterface> #include <QtNetwork/QNetworkInterface>
#include <QtNetwork/QNetworkAccessManager> #include <QtNetwork/QNetworkAccessManager>
#include <QNetworkRequest> #include <QNetworkRequest>
#include <QNetworkReply> #include <QNetworkReply>
#include <QUrl> #include <QUrl>
skipping to change at line 47 skipping to change at line 48
StelLocationMgr::StelLocationMgr() StelLocationMgr::StelLocationMgr()
{ {
QSettings* conf = StelApp::getInstance().getSettings(); QSettings* conf = StelApp::getInstance().getSettings();
// The line below allows to re-generate the location file, you still need to gunzip it manually afterward. // The line below allows to re-generate the location file, you still need to gunzip it manually afterward.
// generateBinaryLocationFile("data/base_locations.txt", false, "dat a/base_locations.bin"); // generateBinaryLocationFile("data/base_locations.txt", false, "dat a/base_locations.bin");
locations = loadCitiesBin("data/base_locations.bin.gz"); locations = loadCitiesBin("data/base_locations.bin.gz");
locations.unite(loadCities("data/user_locations.txt", true)); locations.unite(loadCities("data/user_locations.txt", true));
modelAllLocation = new QStringListModel(this); // Init to Paris France because it's the center of the world.
modelAllLocation->setStringList(locations.keys()); lastResortLocation = locationForString(conf->value("init_location/la
modelPickedLocation = new QStringListModel(this); // keep empty for st_location", "Paris, France").toString());
now. }
StelLocationMgr::StelLocationMgr(const LocationList &locations)
{
setLocations(locations);
QSettings* conf = StelApp::getInstance().getSettings();
// Init to Paris France because it's the center of the world. // Init to Paris France because it's the center of the world.
lastResortLocation = locationForString(conf->value("init_location/la st_location", "Paris, France").toString()); lastResortLocation = locationForString(conf->value("init_location/la st_location", "Paris, France").toString());
} }
void StelLocationMgr::setLocations(const LocationList &locations)
{
for(LocationList::const_iterator it = locations.constBegin();it!=loc
ations.constEnd();++it)
{
this->locations.insert(it->getID(),*it);
}
emit locationListChanged();
}
void StelLocationMgr::generateBinaryLocationFile(const QString& fileName, b ool isUserLocation, const QString& binFilePath) const void StelLocationMgr::generateBinaryLocationFile(const QString& fileName, b ool isUserLocation, const QString& binFilePath) const
{ {
const QMap<QString, StelLocation>& cities = loadCities(fileName, isU serLocation); const QMap<QString, StelLocation>& cities = loadCities(fileName, isU serLocation);
QFile binfile(binFilePath); QFile binfile(binFilePath);
if(binfile.open(QIODevice::WriteOnly)) if(binfile.open(QIODevice::WriteOnly))
{ {
QDataStream out(&binfile); QDataStream out(&binfile);
out.setVersion(QDataStream::Qt_4_6); out.setVersion(QDataStream::Qt_4_6);
out << cities; out << cities;
binfile.close(); binfile.close();
} }
} }
QMap<QString, StelLocation> StelLocationMgr::loadCitiesBin(const QString& f ileName) const LocationMap StelLocationMgr::loadCitiesBin(const QString& fileName)
{ {
QMap<QString, StelLocation> res; QMap<QString, StelLocation> res;
QString cityDataPath = StelFileMgr::findFile(fileName); QString cityDataPath = StelFileMgr::findFile(fileName);
if (cityDataPath.isEmpty()) if (cityDataPath.isEmpty())
return res; return res;
QFile sourcefile(cityDataPath); QFile sourcefile(cityDataPath);
if (!sourcefile.open(QIODevice::ReadOnly)) if (!sourcefile.open(QIODevice::ReadOnly))
{ {
qWarning() << "ERROR: Could not open location data file: " < < QDir::toNativeSeparators(cityDataPath); qWarning() << "ERROR: Could not open location data file: " < < QDir::toNativeSeparators(cityDataPath);
skipping to change at line 98 skipping to change at line 114
} }
else else
{ {
QDataStream in(&sourcefile); QDataStream in(&sourcefile);
in.setVersion(QDataStream::Qt_4_6); in.setVersion(QDataStream::Qt_4_6);
in >> res; in >> res;
return res; return res;
} }
} }
QMap<QString, StelLocation> StelLocationMgr::loadCities(const QString& file Name, bool isUserLocation) const LocationMap StelLocationMgr::loadCities(const QString& fileName, bool isUse rLocation)
{ {
// Load the cities from data file // Load the cities from data file
QMap<QString, StelLocation> locations; QMap<QString, StelLocation> locations;
QString cityDataPath = StelFileMgr::findFile(fileName); QString cityDataPath = StelFileMgr::findFile(fileName);
if (cityDataPath.isEmpty()) if (cityDataPath.isEmpty())
{ {
// Note it is quite normal not to have a user locations file (e.g. first run) // Note it is quite normal not to have a user locations file (e.g. first run)
if (!isUserLocation) if (!isUserLocation)
qWarning() << "WARNING: Failed to locate location da ta file: " << QDir::toNativeSeparators(fileName); qWarning() << "WARNING: Failed to locate location da ta file: " << QDir::toNativeSeparators(fileName);
return locations; return locations;
skipping to change at line 155 skipping to change at line 171
} }
else else
{ {
locations.insert(locId, loc); locations.insert(locId, loc);
} }
} }
sourcefile.close(); sourcefile.close();
return locations; return locations;
} }
StelLocationMgr::~StelLocationMgr()
{
delete modelPickedLocation;
modelPickedLocation=NULL;
delete modelAllLocation;
modelAllLocation=NULL;
}
static float parseAngle(const QString& s, bool* ok) static float parseAngle(const QString& s, bool* ok)
{ {
float ret; float ret;
// First try normal decimal value. // First try normal decimal value.
ret = s.toFloat(ok); ret = s.toFloat(ok);
if (*ok) return ret; if (*ok) return ret;
// Try GPS coordinate like +121°33'38.28" // Try GPS coordinate like +121°33'38.28"
QRegExp reg("([+-]?[\\d.]+)°(?:([\\d.]+)')?(?:([\\d.]+)\")?"); QRegExp reg("([+-]?[\\d.]+)°(?:([\\d.]+)')?(?:([\\d.]+)\")?");
if (reg.exactMatch(s)) if (reg.exactMatch(s))
{ {
skipping to change at line 243 skipping to change at line 251
// Add permanently a location to the list of user locations // Add permanently a location to the list of user locations
bool StelLocationMgr::saveUserLocation(const StelLocation& loc) bool StelLocationMgr::saveUserLocation(const StelLocation& loc)
{ {
if (!canSaveUserLocation(loc)) if (!canSaveUserLocation(loc))
return false; return false;
// Add in the program // Add in the program
locations[loc.getID()]=loc; locations[loc.getID()]=loc;
// Append in the Qt model //emit before saving the list
modelAllLocation->setStringList(locations.keys()); emit locationListChanged();
// Append to the user location file // Append to the user location file
QString cityDataPath = StelFileMgr::findFile("data/user_locations.tx t", StelFileMgr::Flags(StelFileMgr::Writable|StelFileMgr::File)); QString cityDataPath = StelFileMgr::findFile("data/user_locations.tx t", StelFileMgr::Flags(StelFileMgr::Writable|StelFileMgr::File));
if (cityDataPath.isEmpty()) if (cityDataPath.isEmpty())
{ {
if (!StelFileMgr::exists(StelFileMgr::getUserDir()+"/data")) if (!StelFileMgr::exists(StelFileMgr::getUserDir()+"/data"))
{ {
if (!StelFileMgr::mkDir(StelFileMgr::getUserDir()+"/ data")) if (!StelFileMgr::mkDir(StelFileMgr::getUserDir()+"/ data"))
{ {
qWarning() << "ERROR - cannot create non-exi stent data directory" << QDir::toNativeSeparators(StelFileMgr::getUserDir() +"/data"); qWarning() << "ERROR - cannot create non-exi stent data directory" << QDir::toNativeSeparators(StelFileMgr::getUserDir() +"/data");
skipping to change at line 300 skipping to change at line 308
} }
// Delete permanently the given location from the list of user locations // Delete permanently the given location from the list of user locations
// If the location comes from the base read only list, it cannot be deleted and false is returned // If the location comes from the base read only list, it cannot be deleted and false is returned
bool StelLocationMgr::deleteUserLocation(const QString& id) bool StelLocationMgr::deleteUserLocation(const QString& id)
{ {
if (!canDeleteUserLocation(id)) if (!canDeleteUserLocation(id))
return false; return false;
locations.remove(id); locations.remove(id);
// Remove in the Qt model file
modelAllLocation->setStringList(locations.keys()); //emit before saving the list
emit locationListChanged();
// Resave the whole remaining user locations file // Resave the whole remaining user locations file
QString cityDataPath = StelFileMgr::findFile("data/user_locations.tx t", StelFileMgr::Writable); QString cityDataPath = StelFileMgr::findFile("data/user_locations.tx t", StelFileMgr::Writable);
if (cityDataPath.isEmpty()) if (cityDataPath.isEmpty())
{ {
if (!StelFileMgr::exists(StelFileMgr::getUserDir()+"/data")) if (!StelFileMgr::exists(StelFileMgr::getUserDir()+"/data"))
{ {
if (!StelFileMgr::mkDir(StelFileMgr::getUserDir()+"/ data")) if (!StelFileMgr::mkDir(StelFileMgr::getUserDir()+"/ data"))
{ {
qWarning() << "ERROR - cannot create non-exi stent data directory" << QDir::toNativeSeparators(StelFileMgr::getUserDir() +"/data"); qWarning() << "ERROR - cannot create non-exi stent data directory" << QDir::toNativeSeparators(StelFileMgr::getUserDir() +"/data");
skipping to change at line 346 skipping to change at line 355
} }
} }
sourcefile.close(); sourcefile.close();
return true; return true;
} }
// lookup location from IP address. // lookup location from IP address.
void StelLocationMgr::locationFromIP() void StelLocationMgr::locationFromIP()
{ {
QNetworkRequest req( QUrl( QString("http://freegeoip.net/csv/") ) ); QNetworkRequest req( QUrl( QString("http://freegeoip.net/json/") ) )
;
req.setAttribute(QNetworkRequest::CacheLoadControlAttribute, QNetwor
kRequest::PreferCache);
req.setRawHeader("User-Agent", StelUtils::getApplicationName().toLat
in1());
QNetworkReply* networkReply=StelApp::getInstance().getNetworkAccessM anager()->get(req); QNetworkReply* networkReply=StelApp::getInstance().getNetworkAccessM anager()->get(req);
connect(networkReply, SIGNAL(finished()), this, SLOT(changeLocationF romNetworkLookup())); connect(networkReply, SIGNAL(finished()), this, SLOT(changeLocationF romNetworkLookup()));
} }
// slot that receives IP-based location data from the network. // slot that receives IP-based location data from the network.
void StelLocationMgr::changeLocationFromNetworkLookup() void StelLocationMgr::changeLocationFromNetworkLookup()
{ {
StelLocation location; StelLocation location;
StelCore *core=StelApp::getInstance().getCore(); StelCore *core=StelApp::getInstance().getCore();
QNetworkReply* networkReply = qobject_cast<QNetworkReply*>(sender()) ; QNetworkReply* networkReply = qobject_cast<QNetworkReply*>(sender()) ;
if (!networkReply) if (!networkReply)
return; return;
if (networkReply->error() == QNetworkReply::NoError) { if (networkReply->error() == QNetworkReply::NoError) {
//success //success
// Tested with and without working network connection. QVariantMap locMap = StelJsonParser::parse(networkReply->rea
QByteArray answer=networkReply->readAll(); dAll()).toMap();
qDebug() << "IP answer:" << answer; QString ipRegion = locMap.value("region_name").toString();
// answer/splitline example: "222.222.222.222","AT","Aus QString ipCity = locMap.value("city").toString();
tria","","","","","47.3333","13.3333","","" QString ipCountry = locMap.value("country_name").toString();
// The parts from freegeoip are: ip,country_code,country_nam // NOTE: Got a short name of country
e,region_code,region_name,city,zipcode,latitude,longitude,metro_code,area_c QString ipCountryCode = locMap.value("country_code").toStrin
ode g();
// Changed before 2014-11-21 to: 222.222.222.222,AT,Austria, QString ipTimeZone = locMap.value("time_zone").toString();
"","","","",Europe/Vienna,47.33,13.33,0<CR><LF> (i.e., only empty strings h float latitude=locMap.value("latitude").toFloat();
ave "") float longitude=locMap.value("longitude").toFloat();
// Now: ip,country_code,country_nam
e,region_code,region_name,city,zipcode,Timezone_name,latitude,longitude,met qDebug() << "Got location" << QString("%1, %2, %3 (%4, %5)")
ro_code .arg(ipCity).arg(ipRegion).arg(ipCountry).arg(latitude).arg(longitude) << "
// longitude and latitude should always be filled. for IP" << locMap.value("ip").toString();
// A few tests:
if (answer.count(',') != 10 )
{
qDebug() << "StelLocationMgr: Malformatted answer in
IP-based location lookup: \n\t" << answer;
qDebug() << "StelLocationMgr: Will not change locati
on.";
networkReply->deleteLater();
return;
}
const QStringList& splitline = QString(answer).split(",");
if (splitline.count() != 11 )
{
qDebug() << "StelLocationMgr: Unexpected answer in I
P-based location lookup: \n\t" << answer;
qDebug() << "StelLocationMgr: Will not change locati
on.";
networkReply->deleteLater();
return;
}
// KEEP FOR DEBUGGING:
//for (int i=0; i<splitline.count(); ++i)
// qDebug() << "Component" << i << "length:" << splitli
ne.at(i).length() << ":" << splitline.at(i);
if ((splitline.at(8)=="\"\"") || (splitline.at(9)=="\"\""))
// empty coordinates?
{
qDebug() << "StelLocationMgr: Invalid coordinates fr
om IP-based lookup. Ignoring: \n\t" << answer;
networkReply->deleteLater();
return;
}
float latitude=splitline.at(8).toFloat();
float longitude=splitline.at(9).toFloat();
QString locLine= // we re-pack into a new line that will be parsed back by StelLocation... QString locLine= // we re-pack into a new line that will be parsed back by StelLocation...
QString("%1\t%2\t%3\t%4\t%5\t%6\t%7\t0") QString("%1\t%2\t%3\tX\t0\t%4\t%5\t0\t\t%6")
.arg(splitline.at(5) == "\"\"" ? QString("%1 .arg(ipCity.isEmpty() ? QString("%1, %2").ar
, %2").arg(latitude).arg(longitude) : splitline.at(5)) g(latitude).arg(longitude) : ipCity)
.arg(splitline.at(4) == "\"\"" ? "IPregion" .arg(ipRegion.isEmpty() ? "IPregion" : ipRe
: splitline.at(4)) gion)
.arg(splitline.at(2) == "\"\"" ? "IPcountry" .arg(ipCountryCode.isEmpty() ? "" : ipCountr
: splitline.at(2)) // countryCode yCode.toLower())
.arg("X") // role: X=user-defined
.arg(0) // population: unknown
.arg(latitude<0 ? QString("%1S").arg(-latitu de, 0, 'f', 6) : QString("%1N").arg(latitude, 0, 'f', 6)) .arg(latitude<0 ? QString("%1S").arg(-latitu de, 0, 'f', 6) : QString("%1N").arg(latitude, 0, 'f', 6))
.arg(longitude<0 ? QString("%1W").arg(-longi .arg(longitude<0 ? QString("%1W").arg(-longi
tude, 0, 'f', 6) : QString("%1E").arg(longitude, 0, 'f', 6)); tude, 0, 'f', 6) : QString("%1E").arg(longitude, 0, 'f', 6))
.arg(ipTimeZone.isEmpty() ? "" : ipTimeZone)
;
location=StelLocation::createFromLine(locLine); // in lack o f a regular constructor ;-) location=StelLocation::createFromLine(locLine); // in lack o f a regular constructor ;-)
core->moveObserverTo(location, 0.0f, 0.0f); core->moveObserverTo(location, 0.0f, 0.0f);
QSettings* conf = StelApp::getInstance().getSettings(); QSettings* conf = StelApp::getInstance().getSettings();
conf->setValue("init_location/last_location", QString("%1,%2 ").arg(latitude).arg(longitude)); conf->setValue("init_location/last_location", QString("%1,%2 ").arg(latitude).arg(longitude));
} }
else else
{ {
qDebug() << "Failure getting IP-based location: \n\t" <<netw orkReply->errorString(); qDebug() << "Failure getting IP-based location: \n\t" <<netw orkReply->errorString();
// If there is a problem, this must not change to some other location! // If there is a problem, this must not change to some other location!
//core->moveObserverTo(lastResortLocation, 0.0f, 0.0f); //core->moveObserverTo(lastResortLocation, 0.0f, 0.0f);
} }
networkReply->deleteLater(); networkReply->deleteLater();
} }
void StelLocationMgr::pickLocationsNearby(const QString planetName, const f loat longitude, const float latitude, const float radiusDegrees) LocationMap StelLocationMgr::pickLocationsNearby(const QString planetName, const float longitude, const float latitude, const float radiusDegrees)
{ {
pickedLocations.clear(); QMap<QString, StelLocation> results;
QMapIterator<QString, StelLocation> iter(locations); QMapIterator<QString, StelLocation> iter(locations);
while (iter.hasNext()) while (iter.hasNext())
{ {
iter.next(); iter.next();
const StelLocation *loc=&iter.value(); const StelLocation *loc=&iter.value();
if ( (loc->planetName == planetName) && if ( (loc->planetName == planetName) &&
(StelLocation::distanceDegrees(longitude, la titude, loc->longitude, loc->latitude) <= radiusDegrees) ) (StelLocation::distanceDegrees(longitude, la titude, loc->longitude, loc->latitude) <= radiusDegrees) )
{ {
pickedLocations.insert(iter.key(), iter.value()); results.insert(iter.key(), iter.value());
} }
} }
modelPickedLocation->setStringList(pickedLocations.keys()); return results;
} }
void StelLocationMgr::pickLocationsInCountry(const QString country) LocationMap StelLocationMgr::pickLocationsInCountry(const QString country)
{ {
pickedLocations.clear(); QMap<QString, StelLocation> results;
QMapIterator<QString, StelLocation> iter(locations); QMapIterator<QString, StelLocation> iter(locations);
while (iter.hasNext()) while (iter.hasNext())
{ {
iter.next(); iter.next();
const StelLocation *loc=&iter.value(); const StelLocation *loc=&iter.value();
if (loc->country == country) if (loc->country == country)
{ {
pickedLocations.insert(iter.key(), iter.value()); results.insert(iter.key(), iter.value());
} }
} }
modelPickedLocation->setStringList(pickedLocations.keys()); return results;
} }
 End of changes. 21 change blocks. 
87 lines changed or deleted 69 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/