Satellites.cpp   Satellites.cpp 
skipping to change at line 32 skipping to change at line 32
#include "StelGui.hpp" #include "StelGui.hpp"
#include "StelGuiItems.hpp" #include "StelGuiItems.hpp"
#include "StelLocation.hpp" #include "StelLocation.hpp"
#include "StelObjectMgr.hpp" #include "StelObjectMgr.hpp"
#include "StelModuleMgr.hpp" #include "StelModuleMgr.hpp"
#include "StelLocaleMgr.hpp" #include "StelLocaleMgr.hpp"
#include "StelFileMgr.hpp" #include "StelFileMgr.hpp"
#include "StelIniParser.hpp" #include "StelIniParser.hpp"
#include "Satellites.hpp" #include "Satellites.hpp"
#include "Satellite.hpp" #include "Satellite.hpp"
#include "SatellitesListModel.hpp"
#include "Planet.hpp" #include "Planet.hpp"
#include "SolarSystem.hpp" #include "SolarSystem.hpp"
#include "StelJsonParser.hpp" #include "StelJsonParser.hpp"
#include "SatellitesDialog.hpp" #include "SatellitesDialog.hpp"
#include "LabelMgr.hpp" #include "LabelMgr.hpp"
#include "StelTranslator.hpp" #include "StelTranslator.hpp"
#include "renderer/StelRenderer.hpp" #include "renderer/StelRenderer.hpp"
#include <QNetworkAccessManager> #include <QNetworkAccessManager>
#include <QNetworkReply> #include <QNetworkReply>
#include <QKeyEvent> #include <QKeyEvent>
#include <QAction> #include <QAction>
#include <QProgressBar> #include <QProgressBar>
#include <QDebug> #include <QDebug>
#include <QFileInfo> #include <QFileInfo>
#include <QFile> #include <QFile>
#include <QTimer> #include <QTimer>
#include <QVariantMap> #include <QVariantMap>
#include <QVariant> #include <QVariant>
#include <QDir>
StelModule* SatellitesStelPluginInterface::getStelModule() const StelModule* SatellitesStelPluginInterface::getStelModule() const
{ {
return new Satellites(); return new Satellites();
} }
StelPluginInfo SatellitesStelPluginInterface::getPluginInfo() const StelPluginInfo SatellitesStelPluginInterface::getPluginInfo() const
{ {
// Allow to load the resources when used as a static plugin // Allow to load the resources when used as a static plugin
Q_INIT_RESOURCE(Satellites); Q_INIT_RESOURCE(Satellites);
StelPluginInfo info; StelPluginInfo info;
info.id = "Satellites"; info.id = "Satellites";
info.displayedName = N_("Satellites"); info.displayedName = N_("Satellites");
info.authors = "Matthew Gates, Jose Luis Canales"; info.authors = "Matthew Gates, Jose Luis Canales, Bogdan Marinov";
info.contact = "http://stellarium.org/"; info.contact = "http://stellarium.org/";
info.description = N_("Prediction of artificial satellite positions in Earth orbit based on NORAD TLE data"); info.description = N_("Prediction of artificial satellite positions in Earth orbit based on NORAD TLE data");
return info; return info;
} }
Q_EXPORT_PLUGIN2(Satellites, SatellitesStelPluginInterface) Q_EXPORT_PLUGIN2(Satellites, SatellitesStelPluginInterface)
Satellites::Satellites() Satellites::Satellites()
: hintTexture(NULL) : satelliteListModel(0),
hintTexture(NULL)
, texPointer(NULL) , texPointer(NULL)
, pxmapGlow(NULL) , pxmapGlow(NULL)
, pxmapOnIcon(NULL) , pxmapOnIcon(NULL)
, pxmapOffIcon(NULL) , pxmapOffIcon(NULL)
, toolbarButton(NULL) , toolbarButton(NULL)
, earth(NULL) , earth(NULL)
, defaultHintColor(0.0, 0.4, 0.6) , defaultHintColor(0.0, 0.4, 0.6)
, defaultOrbitColor(0.0, 0.3, 0.6) , defaultOrbitColor(0.0, 0.3, 0.6)
, progressBar(NULL) , progressBar(NULL)
{ {
skipping to change at line 119 skipping to change at line 122
if (pxmapOffIcon) if (pxmapOffIcon)
delete pxmapOffIcon; delete pxmapOffIcon;
} }
void Satellites::init() void Satellites::init()
{ {
QSettings* conf = StelApp::getInstance().getSettings(); QSettings* conf = StelApp::getInstance().getSettings();
try try
{ {
StelFileMgr::makeSureDirExistsAndIsWritable(StelFileMgr::get // TODO: Compatibility with installation-dir modules? --BM
UserDir()+"/modules/Satellites"); // It seems that the original code couldn't handle them eith
er.
QString dirPath = StelFileMgr::getUserDir() + "/modules/Sate
llites";
// TODO: Ideally, this should return a QDir object
StelFileMgr::makeSureDirExistsAndIsWritable(dirPath);
dataDir.setPath(dirPath);
// If no settings in the main config file, create with defau lts // If no settings in the main config file, create with defau lts
if (!conf->childGroups().contains("Satellites")) if (!conf->childGroups().contains("Satellites"))
{ {
qDebug() << "Stellites::init no Satellites section e //qDebug() << "Stellites: created section in config
xists in main config file - creating with defaults"; file.";
restoreDefaultConfigIni(); restoreDefaultSettings();
} }
// populate settings from main config file. // populate settings from main config file.
readSettingsFromConfig(); loadSettings();
satellitesJsonPath = StelFileMgr::findFile("modules/Satellit es", (StelFileMgr::Flags)(StelFileMgr::Directory|StelFileMgr::Writable)) + "/satellites.json"; catalogPath = dataDir.absoluteFilePath("satellites.json");
// Load and find resources used in the plugin // Load and find resources used in the plugin
// key bindings and other actions // key bindings and other actions
StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance() .getGui()); StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance() .getGui());
gui->getGuiAction("actionShow_Satellite_Hints")->setChecked( getFlagHints()); gui->getGuiAction("actionShow_Satellite_Hints")->setChecked( getFlagHints());
gui->getGuiAction("actionShow_Satellite_Labels")->setChecked (Satellite::showLabels); gui->getGuiAction("actionShow_Satellite_Labels")->setChecked (Satellite::showLabels);
// Gui toolbar button // Gui toolbar button
pxmapGlow = new QPixmap(":/graphicGui/glow32x32.png"); pxmapGlow = new QPixmap(":/graphicGui/glow32x32.png");
skipping to change at line 164 skipping to change at line 172
{ {
qWarning() << "Satellites::init error: " << e.what(); qWarning() << "Satellites::init error: " << e.what();
return; return;
} }
// A timer for hiding alert messages // A timer for hiding alert messages
messageTimer = new QTimer(this); messageTimer = new QTimer(this);
messageTimer->setSingleShot(true); // recurring check for update messageTimer->setSingleShot(true); // recurring check for update
messageTimer->setInterval(9000); // 6 seconds should be enough time messageTimer->setInterval(9000); // 6 seconds should be enough time
messageTimer->stop(); messageTimer->stop();
connect(messageTimer, SIGNAL(timeout()), this, SLOT(messageTimeout() )); connect(messageTimer, SIGNAL(timeout()), this, SLOT(hideMessages())) ;
// If the json file does not already exist, create it from the resou rce in the QT resource // If the json file does not already exist, create it from the resou rce in the QT resource
if(QFileInfo(satellitesJsonPath).exists()) if(QFileInfo(catalogPath).exists())
{ {
if (getJsonFileVersion() != SATELLITES_PLUGIN_VERSION) if (readCatalogVersion() != SATELLITES_PLUGIN_VERSION)
{ {
displayMessage(q_("The old satellites.json file is n o longer compatible - using default file"), "#bb0000"); displayMessage(q_("The old satellites.json file is n o longer compatible - using default file"), "#bb0000");
restoreDefaultJsonFile(); restoreDefaultCatalog();
} }
} }
else else
{ {
qDebug() << "Satellites::init satellites.json does not exist qDebug() << "Satellites::init satellites.json does not exist
- copying default file to " << satellitesJsonPath; - copying default file to " << QDir::toNativeSeparators(catalogPath);
restoreDefaultJsonFile(); restoreDefaultCatalog();
} }
qDebug() << "Satellites::init using satellite.json file: " << satell itesJsonPath; qDebug() << "Satellites: loading catalog file:" << QDir::toNativeSep arators(catalogPath);
// create satellites according to content os satellites.json file // create satellites according to content os satellites.json file
readJsonFile(); loadCatalog();
// Set up download manager and the update schedule // Set up download manager and the update schedule
downloadMgr = new QNetworkAccessManager(this); downloadMgr = new QNetworkAccessManager(this);
connect(downloadMgr, SIGNAL(finished(QNetworkReply*)), this, SLOT(up connect(downloadMgr, SIGNAL(finished(QNetworkReply*)),
dateDownloadComplete(QNetworkReply*))); this, SLOT(saveDownloadedUpdate(QNetworkReply*)));
updateState = CompleteNoUpdates; updateState = CompleteNoUpdates;
updateTimer = new QTimer(this); updateTimer = new QTimer(this);
updateTimer->setSingleShot(false); // recurring check for update updateTimer->setSingleShot(false); // recurring check for update
updateTimer->setInterval(13000); // check once every 13 seconds to see if it is time for an update updateTimer->setInterval(13000); // check once every 13 seconds to see if it is time for an update
connect(updateTimer, SIGNAL(timeout()), this, SLOT(checkForUpdate()) ); connect(updateTimer, SIGNAL(timeout()), this, SLOT(checkForUpdate()) );
updateTimer->start(); updateTimer->start();
earth = GETSTELMODULE(SolarSystem)->getEarth(); earth = GETSTELMODULE(SolarSystem)->getEarth();
GETSTELMODULE(StelObjectMgr)->registerStelObjectMgr(this); GETSTELMODULE(StelObjectMgr)->registerStelObjectMgr(this);
// Handle changes to the observer location: // Handle changes to the observer location:
connect(StelApp::getInstance().getCore(), SIGNAL(locationChanged(Ste connect(StelApp::getInstance().getCore(),
lLocation)), this, SLOT(observerLocationChanged(StelLocation))); SIGNAL(locationChanged(StelLocation)),
this,
SLOT(updateObserverLocation(StelLocation)));
//Load the module's custom style sheets //Load the module's custom style sheets
QFile styleSheetFile; QFile styleSheetFile;
styleSheetFile.setFileName(":/satellites/normalStyle.css"); styleSheetFile.setFileName(":/satellites/normalStyle.css");
if(styleSheetFile.open(QFile::ReadOnly|QFile::Text)) if(styleSheetFile.open(QFile::ReadOnly|QFile::Text))
{ {
normalStyleSheet = styleSheetFile.readAll(); normalStyleSheet = styleSheetFile.readAll();
} }
styleSheetFile.close(); styleSheetFile.close();
styleSheetFile.setFileName(":/satellites/nightStyle.css"); styleSheetFile.setFileName(":/satellites/nightStyle.css");
if(styleSheetFile.open(QFile::ReadOnly|QFile::Text)) if(styleSheetFile.open(QFile::ReadOnly|QFile::Text))
{ {
nightStyleSheet = styleSheetFile.readAll(); nightStyleSheet = styleSheetFile.readAll();
} }
styleSheetFile.close(); styleSheetFile.close();
connect(&StelApp::getInstance(), SIGNAL(colorSchemeChanged(const QSt ring&)), this, SLOT(setStelStyle(const QString&))); connect(&StelApp::getInstance(), SIGNAL(colorSchemeChanged(const QSt ring&)), this, SLOT(setStelStyle(const QString&)));
} }
bool Satellites::backupJsonFile(bool deleteOriginal) bool Satellites::backupCatalog(bool deleteOriginal)
{ {
QFile old(satellitesJsonPath); QFile old(catalogPath);
if (!old.exists()) if (!old.exists())
{ {
qWarning() << "Satellites::backupJsonFile no file to backup" ; qWarning() << "Satellites::backupJsonFile no file to backup" ;
return false; return false;
} }
QString backupPath = satellitesJsonPath + ".old"; QString backupPath = catalogPath + ".old";
if (QFileInfo(backupPath).exists()) if (QFileInfo(backupPath).exists())
QFile(backupPath).remove(); QFile(backupPath).remove();
if (old.copy(backupPath)) if (old.copy(backupPath))
{ {
if (deleteOriginal) if (deleteOriginal)
{ {
if (!old.remove()) if (!old.remove())
{ {
qWarning() << "Satellites::backupJsonFile WA RNING - could not remove old satellites.json file"; qWarning() << "Satellites: WARNING: unable t o remove old catalog file!";
return false; return false;
} }
} }
} }
else else
{ {
qWarning() << "Satellites::backupJsonFile WARNING - failed t qWarning() << "Satellites: WARNING: failed to back up catalo
o copy satellites.json to satellites.json.old"; g file as"
<< QDir::toNativeSeparators(backupPath);
return false; return false;
} }
return true; return true;
} }
void Satellites::setStelStyle(const QString& mode) void Satellites::setStelStyle(const QString& mode)
{ {
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
skipping to change at line 298 skipping to change at line 311
if (!hintFader || StelApp::getInstance().getCore()->getCurrentLocati on().planetName != earth->getEnglishName()) if (!hintFader || StelApp::getInstance().getCore()->getCurrentLocati on().planetName != earth->getEnglishName())
return result; return result;
Vec3d v(av); Vec3d v(av);
v.normalize(); v.normalize();
double cosLimFov = cos(limitFov * M_PI/180.); double cosLimFov = cos(limitFov * M_PI/180.);
Vec3d equPos; Vec3d equPos;
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
if (sat->initialized && sat->visible) if (sat->initialized && sat->displayed)
{ {
equPos = sat->XYZ; equPos = sat->XYZ;
equPos.normalize(); equPos.normalize();
if (equPos[0]*v[0] + equPos[1]*v[1] + equPos[2]*v[2] >=cosLimFov) if (equPos[0]*v[0] + equPos[1]*v[1] + equPos[2]*v[2] >=cosLimFov)
{ {
result.append(qSharedPointerCast<StelObject> (sat)); result.append(qSharedPointerCast<StelObject> (sat));
} }
} }
} }
return result; return result;
skipping to change at line 324 skipping to change at line 337
return NULL; return NULL;
QString objw = nameI18n.toUpper(); QString objw = nameI18n.toUpper();
StelObjectP result = searchByNoradNumber(objw); StelObjectP result = searchByNoradNumber(objw);
if (result) if (result)
return result; return result;
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
if (sat->initialized && sat->visible) if (sat->initialized && sat->displayed)
{ {
if (sat->getNameI18n().toUpper() == nameI18n) if (sat->getNameI18n().toUpper() == nameI18n)
return qSharedPointerCast<StelObject>(sat); return qSharedPointerCast<StelObject>(sat);
} }
} }
return NULL; return NULL;
} }
StelObjectP Satellites::searchByName(const QString& englishName) const StelObjectP Satellites::searchByName(const QString& englishName) const
skipping to change at line 347 skipping to change at line 360
return NULL; return NULL;
QString objw = englishName.toUpper(); QString objw = englishName.toUpper();
StelObjectP result = searchByNoradNumber(objw); StelObjectP result = searchByNoradNumber(objw);
if (result) if (result)
return result; return result;
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
if (sat->initialized && sat->visible) if (sat->initialized && sat->displayed)
{ {
if (sat->getEnglishName().toUpper() == englishName) if (sat->getEnglishName().toUpper() == englishName)
return qSharedPointerCast<StelObject>(sat); return qSharedPointerCast<StelObject>(sat);
} }
} }
return NULL; return NULL;
} }
StelObjectP Satellites::searchByNoradNumber(const QString &noradNumber) con st StelObjectP Satellites::searchByNoradNumber(const QString &noradNumber) con st
skipping to change at line 374 skipping to change at line 387
if (regExp.exactMatch(noradNumber)) if (regExp.exactMatch(noradNumber))
{ {
QString numberString = regExp.capturedTexts().at(2); QString numberString = regExp.capturedTexts().at(2);
bool ok; bool ok;
/* int number = */ numberString.toInt(&ok); /* int number = */ numberString.toInt(&ok);
if (!ok) if (!ok)
return StelObjectP(); return StelObjectP();
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
if (sat->initialized && sat->visible) if (sat->initialized && sat->displayed)
{ {
if (sat->getCatalogNumberString() == numberS tring) if (sat->getCatalogNumberString() == numberS tring)
return qSharedPointerCast<StelObject >(sat); return qSharedPointerCast<StelObject >(sat);
} }
} }
} }
return StelObjectP(); return StelObjectP();
} }
skipping to change at line 406 skipping to change at line 419
if (regExp.exactMatch(objw)) if (regExp.exactMatch(objw))
{ {
QString numberString = regExp.capturedTexts().at(2); QString numberString = regExp.capturedTexts().at(2);
bool ok; bool ok;
/* int number = */ numberString.toInt(&ok); /* int number = */ numberString.toInt(&ok);
if (ok) if (ok)
numberPrefix = numberString; numberPrefix = numberString;
} }
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
if (sat->initialized && sat->visible) if (sat->initialized && sat->displayed)
{ {
if (sat->getNameI18n().toUpper().left(objw.length()) == objw) if (sat->getNameI18n().toUpper().contains(objw, Qt:: CaseInsensitive))
{ {
result << sat->getNameI18n().toUpper(); result << sat->getNameI18n().toUpper();
} }
else if (!numberPrefix.isEmpty() && sat->getCatalogN umberString().left(numberPrefix.length()) == numberPrefix) else if (!numberPrefix.isEmpty() && sat->getCatalogN umberString().left(numberPrefix.length()) == numberPrefix)
{ {
result << QString("NORAD %1").arg(sat->getCa talogNumberString()); result << QString("NORAD %1").arg(sat->getCa talogNumberString());
} }
} }
} }
skipping to change at line 446 skipping to change at line 459
if (regExp.exactMatch(objw)) if (regExp.exactMatch(objw))
{ {
QString numberString = regExp.capturedTexts().at(2); QString numberString = regExp.capturedTexts().at(2);
bool ok; bool ok;
/* int number = */ numberString.toInt(&ok); /* int number = */ numberString.toInt(&ok);
if (ok) if (ok)
numberPrefix = numberString; numberPrefix = numberString;
} }
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
if (sat->initialized && sat->visible) if (sat->initialized && sat->displayed)
{ {
if (sat->getEnglishName().toUpper().left(objw.length ()) == objw) if (sat->getEnglishName().toUpper().contains(objw, Q t::CaseInsensitive))
{ {
result << sat->getEnglishName().toUpper(); result << sat->getEnglishName().toUpper();
} }
else if (!numberPrefix.isEmpty() && sat->getCatalogN umberString().left(numberPrefix.length()) == numberPrefix) else if (!numberPrefix.isEmpty() && sat->getCatalogN umberString().left(numberPrefix.length()) == numberPrefix)
{ {
result << QString("NORAD %1").arg(sat->getCa talogNumberString()); result << QString("NORAD %1").arg(sat->getCa talogNumberString());
} }
} }
} }
skipping to change at line 498 skipping to change at line 511
{ {
StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance() .getGui()); StelGui* gui = dynamic_cast<StelGui*>(StelApp::getInstance() .getGui());
gui->getGuiAction("actionShow_Satellite_ConfigDialog_Global" )->setChecked(true); gui->getGuiAction("actionShow_Satellite_ConfigDialog_Global" )->setChecked(true);
} }
return true; return true;
} }
void Satellites::restoreDefaults(void) void Satellites::restoreDefaults(void)
{ {
restoreDefaultConfigIni(); restoreDefaultSettings();
restoreDefaultJsonFile(); restoreDefaultCatalog();
readJsonFile(); loadCatalog();
readSettingsFromConfig(); loadSettings();
} }
void Satellites::restoreDefaultConfigIni(void) void Satellites::restoreDefaultSettings()
{ {
QSettings* conf = StelApp::getInstance().getSettings(); QSettings* conf = StelApp::getInstance().getSettings();
conf->beginGroup("Satellites"); conf->beginGroup("Satellites");
// delete all existing Satellite settings... // delete all existing Satellite settings...
conf->remove(""); conf->remove("");
conf->setValue("show_satellite_hints", false); conf->setValue("show_satellite_hints", false);
conf->setValue("show_satellite_labels", true); conf->setValue("show_satellite_labels", true);
conf->setValue("updates_enabled", true); conf->setValue("updates_enabled", true);
conf->setValue("auto_add_enabled", true);
conf->setValue("auto_remove_enabled", true);
conf->setValue("hint_color", "0.0,0.4,0.6"); conf->setValue("hint_color", "0.0,0.4,0.6");
conf->setValue("hint_font_size", 10); conf->setValue("hint_font_size", 10);
conf->setValue("tle_url0", "http://celestrak.com/NORAD/elements/noaa
.txt");
conf->setValue("tle_url1", "http://celestrak.com/NORAD/elements/goes
.txt");
conf->setValue("tle_url2", "http://celestrak.com/NORAD/elements/gps-
ops.txt");
conf->setValue("tle_url3", "http://celestrak.com/NORAD/elements/gali
leo.txt");
conf->setValue("tle_url4", "http://celestrak.com/NORAD/elements/visu
al.txt");
conf->setValue("tle_url5", "http://celestrak.com/NORAD/elements/amat
eur.txt");
conf->setValue("tle_url6", "http://celestrak.com/NORAD/elements/irid
ium.txt");
conf->setValue("tle_url7", "http://celestrak.com/NORAD/elements/geo.
txt");
conf->setValue("tle_url8", "http://celestrak.com/NORAD/elements/tle-
new.txt");
conf->setValue("tle_url9", "http://celestrak.com/NORAD/elements/scie
nce.txt");
//TODO: Better? See http://doc.qt.nokia.com/4.7/qsettings.html#begin
WriteArray --BM
conf->setValue("update_frequency_hours", 72); conf->setValue("update_frequency_hours", 72);
conf->setValue("orbit_line_flag", true); conf->setValue("orbit_line_flag", true);
conf->setValue("orbit_line_segments", 90); conf->setValue("orbit_line_segments", 90);
conf->setValue("orbit_fade_segments", 5); conf->setValue("orbit_fade_segments", 5);
conf->setValue("orbit_segment_duration", 20); conf->setValue("orbit_segment_duration", 20);
conf->endGroup();
conf->endGroup(); // saveTleSources() opens it for itself
// TLE update sources
QStringList urls;
urls << "1,http://celestrak.com/NORAD/elements/visual.txt" // Auto-a
dd ON!
<< "http://celestrak.com/NORAD/elements/tle-new.txt"
<< "http://celestrak.com/NORAD/elements/science.txt"
<< "http://celestrak.com/NORAD/elements/noaa.txt"
<< "http://celestrak.com/NORAD/elements/goes.txt"
<< "http://celestrak.com/NORAD/elements/amateur.txt"
<< "http://celestrak.com/NORAD/elements/gps-ops.txt"
<< "http://celestrak.com/NORAD/elements/galileo.txt"
<< "http://celestrak.com/NORAD/elements/iridium.txt"
<< "http://celestrak.com/NORAD/elements/geo.txt";
saveTleSources(urls);
} }
void Satellites::restoreDefaultJsonFile(void) void Satellites::restoreDefaultCatalog()
{ {
if (QFileInfo(satellitesJsonPath).exists()) if (QFileInfo(catalogPath).exists())
backupJsonFile(true); backupCatalog(true);
QFile src(":/satellites/satellites.json"); QFile src(":/satellites/satellites.json");
if (!src.copy(satellitesJsonPath)) if (!src.copy(catalogPath))
{ {
qWarning() << "Satellites::restoreDefaultJsonFile cannot cop y json resource to " + satellitesJsonPath; qWarning() << "Satellites::restoreDefaultJsonFile cannot cop y json resource to " + QDir::toNativeSeparators(catalogPath);
} }
else else
{ {
qDebug() << "Satellites::init copied default satellites.json to " << satellitesJsonPath; qDebug() << "Satellites::init copied default satellites.json to " << QDir::toNativeSeparators(catalogPath);
// The resource is read only, and the new file inherits this ... make sure the new file // The resource is read only, and the new file inherits this ... make sure the new file
// is writable by the Stellarium process so that updates can be done. // is writable by the Stellarium process so that updates can be done.
QFile dest(satellitesJsonPath); QFile dest(catalogPath);
dest.setPermissions(dest.permissions() | QFile::WriteOwner); dest.setPermissions(dest.permissions() | QFile::WriteOwner);
// Make sure that in the case where an online update has pre viously been done, but // Make sure that in the case where an online update has pre viously been done, but
// the json file has been manually removed, that an update i s schreduled in a timely // the json file has been manually removed, that an update i s schreduled in a timely
// manner // manner
StelApp::getInstance().getSettings()->remove("Satellites/las t_update"); StelApp::getInstance().getSettings()->remove("Satellites/las t_update");
lastUpdate = QDateTime::fromString("2001-05-25T12:00:00", Qt ::ISODate); lastUpdate = QDateTime::fromString("2001-05-25T12:00:00", Qt ::ISODate);
} }
} }
void Satellites::readSettingsFromConfig(void) void Satellites::loadSettings()
{ {
QSettings* conf = StelApp::getInstance().getSettings(); QSettings* conf = StelApp::getInstance().getSettings();
conf->beginGroup("Satellites"); conf->beginGroup("Satellites");
// populate updateUrls from tle_url? keys // Load update sources list...
QRegExp keyRE("^tle_url\\d+$");
updateUrls.clear(); updateUrls.clear();
// Backward compatibility: try to detect and read an old-stlye array
.
// TODO: Assume that the user hasn't modified their conf in a stupid
way?
// if (conf->contains("tle_url0")) // This can skip some operations...
QRegExp keyRE("^tle_url\\d+$");
QStringList urls;
foreach(const QString& key, conf->childKeys()) foreach(const QString& key, conf->childKeys())
{ {
if (keyRE.exactMatch(key)) if (keyRE.exactMatch(key))
{ {
QString s = conf->value(key, "").toString(); QString url = conf->value(key).toString();
if (!s.isEmpty() && s!="") conf->remove(key); // Delete old-style keys
updateUrls << s; if (url.isEmpty())
continue;
// NOTE: This URL is also hardcoded in restoreDefaul
tSettings().
if (url == "http://celestrak.com/NORAD/elements/visu
al.txt")
url.prepend("1,"); // Same as in the new def
ault configuration
urls << url;
}
}
// If any have been read, save them in the new format.
if (!urls.isEmpty())
{
conf->endGroup();
setTleSources(urls);
conf->beginGroup("Satellites");
}
else
{
int size = conf->beginReadArray("tle_sources");
for (int i = 0; i < size; i++)
{
conf->setArrayIndex(i);
QString url = conf->value("url").toString();
if (!url.isEmpty())
{
if (conf->value("add_new").toBool())
url.prepend("1,");
updateUrls.append(url);
}
} }
conf->endArray();
} }
// NOTE: Providing default values AND using restoreDefaultSettings()
to create the section seems redundant. --BM
// updater related settings... // updater related settings...
updateFrequencyHours = conf->value("update_frequency_hours", 72).toI nt(); updateFrequencyHours = conf->value("update_frequency_hours", 72).toI nt();
// last update default is the first Towell Day. <3 DA // last update default is the first Towell Day. <3 DA
lastUpdate = QDateTime::fromString(conf->value("last_update", "2001- 05-25T12:00:00").toString(), Qt::ISODate); lastUpdate = QDateTime::fromString(conf->value("last_update", "2001- 05-25T12:00:00").toString(), Qt::ISODate);
setFlagHints(conf->value("show_satellite_hints", false).toBool()); setFlagHints(conf->value("show_satellite_hints", false).toBool());
Satellite::showLabels = conf->value("show_satellite_labels", true).t oBool(); Satellite::showLabels = conf->value("show_satellite_labels", true).t oBool();
updatesEnabled = conf->value("updates_enabled", true).toBool(); updatesEnabled = conf->value("updates_enabled", true).toBool();
autoAddEnabled = conf->value("auto_add_enabled", true).toBool();
autoRemoveEnabled = conf->value("auto_remove_enabled", true).toBool(
);
// Get a font for labels // Get a font for labels
labelFont.setPixelSize(conf->value("hint_font_size", 10).toInt()); labelFont.setPixelSize(conf->value("hint_font_size", 10).toInt());
// orbit drawing params // orbit drawing params
Satellite::orbitLinesFlag = conf->value("orbit_line_flag", true).toB ool(); Satellite::orbitLinesFlag = conf->value("orbit_line_flag", true).toB ool();
Satellite::orbitLineSegments = conf->value("orbit_line_segments", 90 ).toInt(); Satellite::orbitLineSegments = conf->value("orbit_line_segments", 90 ).toInt();
Satellite::orbitLineFadeSegments = conf->value("orbit_fade_segments" , 5).toInt(); Satellite::orbitLineFadeSegments = conf->value("orbit_fade_segments" , 5).toInt();
Satellite::orbitLineSegmentDuration = conf->value("orbit_segment_dur ation", 20).toInt(); Satellite::orbitLineSegmentDuration = conf->value("orbit_segment_dur ation", 20).toInt();
conf->endGroup(); conf->endGroup();
} }
void Satellites::saveSettingsToConfig(void) void Satellites::saveSettings()
{ {
QSettings* conf = StelApp::getInstance().getSettings(); QSettings* conf = StelApp::getInstance().getSettings();
conf->beginGroup("Satellites"); conf->beginGroup("Satellites");
// update tle urls... first clear the existing ones in the file
QRegExp keyRE("^tle_url\\d+$");
foreach(const QString& key, conf->childKeys())
{
if (keyRE.exactMatch(key))
conf->remove(key);
}
// populate updateUrls from tle_url? keys
int n=0;
foreach(const QString& url, updateUrls)
{
QString key = QString("tle_url%1").arg(n++);
conf->setValue(key, url);
}
// updater related settings... // updater related settings...
conf->setValue("update_frequency_hours", updateFrequencyHours); conf->setValue("update_frequency_hours", updateFrequencyHours);
conf->setValue("show_satellite_hints", getFlagHints()); conf->setValue("show_satellite_hints", getFlagHints());
conf->setValue("show_satellite_labels", Satellite::showLabels); conf->setValue("show_satellite_labels", Satellite::showLabels);
conf->setValue("updates_enabled", updatesEnabled ); conf->setValue("updates_enabled", updatesEnabled );
conf->setValue("auto_add_enabled", autoAddEnabled);
conf->setValue("auto_remove_enabled", autoRemoveEnabled);
// Get a font for labels // Get a font for labels
conf->setValue("hint_font_size", labelFont.pixelSize()); conf->setValue("hint_font_size", labelFont.pixelSize());
// orbit drawing params // orbit drawing params
conf->setValue("orbit_line_flag", Satellite::orbitLinesFlag); conf->setValue("orbit_line_flag", Satellite::orbitLinesFlag);
conf->setValue("orbit_line_segments", Satellite::orbitLineSegments); conf->setValue("orbit_line_segments", Satellite::orbitLineSegments);
conf->setValue("orbit_fade_segments", Satellite::orbitLineFadeSegmen ts); conf->setValue("orbit_fade_segments", Satellite::orbitLineFadeSegmen ts);
conf->setValue("orbit_segment_duration", Satellite::orbitLineSegment Duration); conf->setValue("orbit_segment_duration", Satellite::orbitLineSegment Duration);
conf->endGroup(); conf->endGroup();
// Update sources...
saveTleSources(updateUrls);
} }
void Satellites::readJsonFile(void) void Satellites::loadCatalog()
{ {
setTleMap(loadTleMap()); setDataMap(loadDataMap());
} }
const QString Satellites::getJsonFileVersion(void) const QString Satellites::readCatalogVersion()
{ {
QString jsonVersion("unknown"); QString jsonVersion("unknown");
QFile satelliteJsonFile(satellitesJsonPath); QFile satelliteJsonFile(catalogPath);
if (!satelliteJsonFile.open(QIODevice::ReadOnly)) if (!satelliteJsonFile.open(QIODevice::ReadOnly))
{ {
qWarning() << "Satellites::init cannot open " << satellitesJ sonPath; qWarning() << "Satellites::init cannot open " << QDir::toNat iveSeparators(catalogPath);
return jsonVersion; return jsonVersion;
} }
QVariantMap map; QVariantMap map;
map = StelJsonParser::parse(&satelliteJsonFile).toMap(); map = StelJsonParser::parse(&satelliteJsonFile).toMap();
if (map.contains("creator")) if (map.contains("creator"))
{ {
QString creator = map.value("creator").toString(); QString creator = map.value("creator").toString();
QRegExp vRx(".*(\\d+\\.\\d+\\.\\d+).*"); QRegExp vRx(".*(\\d+\\.\\d+\\.\\d+).*");
if (vRx.exactMatch(creator)) if (vRx.exactMatch(creator))
{ {
jsonVersion = vRx.capturedTexts().at(1); jsonVersion = vRx.capturedTexts().at(1);
} }
} }
satelliteJsonFile.close(); satelliteJsonFile.close();
qDebug() << "Satellites::getJsonFileVersion() version from file:" << jsonVersion; //qDebug() << "Satellites: catalog version from file:" << jsonVersio n;
return jsonVersion; return jsonVersion;
} }
bool Satellites::saveTleMap(const QVariantMap& map, QString path) bool Satellites::saveDataMap(const QVariantMap& map, QString path)
{ {
if (path.isEmpty()) if (path.isEmpty())
path = satellitesJsonPath; path = catalogPath;
QFile jsonFile(path); QFile jsonFile(path);
StelJsonParser parser; StelJsonParser parser;
if (jsonFile.exists()) if (jsonFile.exists())
jsonFile.remove(); jsonFile.remove();
if (!jsonFile.open(QIODevice::WriteOnly)) if (!jsonFile.open(QIODevice::WriteOnly))
{ {
qWarning() << "Satellites::saveTleMap() cannot open for writ ing:" << path; qWarning() << "Satellites::saveTleMap() cannot open for writ ing:" << QDir::toNativeSeparators(path);
return false; return false;
} }
else else
{ {
qDebug() << "Satellites::saveTleMap() writing to:" << path; qDebug() << "Satellites::saveTleMap() writing to:" << QDir:: toNativeSeparators(path);
parser.write(map, &jsonFile); parser.write(map, &jsonFile);
jsonFile.close(); jsonFile.close();
return true; return true;
} }
} }
QVariantMap Satellites::loadTleMap(QString path) QVariantMap Satellites::loadDataMap(QString path)
{ {
if (path.isEmpty()) if (path.isEmpty())
path = satellitesJsonPath; path = catalogPath;
QVariantMap map; QVariantMap map;
QFile jsonFile(path); QFile jsonFile(path);
if (!jsonFile.open(QIODevice::ReadOnly)) if (!jsonFile.open(QIODevice::ReadOnly))
qWarning() << "Satellites::loadTleMap cannot open " << path; qWarning() << "Satellites::loadTleMap cannot open " << QDir: :toNativeSeparators(path);
else else
map = StelJsonParser::parse(&jsonFile).toMap(); map = StelJsonParser::parse(&jsonFile).toMap();
jsonFile.close(); jsonFile.close();
return map; return map;
} }
void Satellites::setTleMap(const QVariantMap& map) void Satellites::setDataMap(const QVariantMap& map)
{ {
int numReadOk = 0; int numReadOk = 0;
QVariantList defaultHintColorMap; QVariantList defaultHintColorMap;
defaultHintColorMap << defaultHintColor[0] << defaultHintColor[1] << defaultHintColor[2]; defaultHintColorMap << defaultHintColor[0] << defaultHintColor[1] << defaultHintColor[2];
if (map.contains("hintColor")) if (map.contains("hintColor"))
{ {
defaultHintColorMap = map.value("hintColor").toList(); defaultHintColorMap = map.value("hintColor").toList();
defaultHintColor.set(defaultHintColorMap.at(0).toDouble(), d efaultHintColorMap.at(1).toDouble(), defaultHintColorMap.at(2).toDouble()); defaultHintColor.set(defaultHintColorMap.at(0).toDouble(), d efaultHintColorMap.at(1).toDouble(), defaultHintColorMap.at(2).toDouble());
} }
if (satelliteListModel)
satelliteListModel->beginSatellitesChange();
satellites.clear(); satellites.clear();
groups.clear();
QVariantMap satMap = map.value("satellites").toMap(); QVariantMap satMap = map.value("satellites").toMap();
foreach(const QString& satId, satMap.keys()) foreach(const QString& satId, satMap.keys())
{ {
QVariantMap satData = satMap.value(satId).toMap(); QVariantMap satData = satMap.value(satId).toMap();
if (!satData.contains("hintColor")) if (!satData.contains("hintColor"))
satData["hintColor"] = defaultHintColorMap; satData["hintColor"] = defaultHintColorMap;
if (!satData.contains("orbitColor")) if (!satData.contains("orbitColor"))
satData["orbitColor"] = satData["hintColor"]; satData["orbitColor"] = satData["hintColor"];
SatelliteP sat(new Satellite(satId, satData)); SatelliteP sat(new Satellite(satId, satData));
if (sat->initialized) if (sat->initialized)
{ {
satellites.append(sat); satellites.append(sat);
groups.unite(sat->groups);
numReadOk++; numReadOk++;
} }
} }
qSort(satellites);
if (satelliteListModel)
satelliteListModel->endSatellitesChange();
} }
QVariantMap Satellites::getTleMap(void) QVariantMap Satellites::createDataMap(void)
{ {
QVariantMap map; QVariantMap map;
QVariantList defHintCol; QVariantList defHintCol;
defHintCol << Satellite::roundToDp(defaultHintColor[0],3) defHintCol << Satellite::roundToDp(defaultHintColor[0],3)
<< Satellite::roundToDp(def aultHintColor[1],3) << Satellite::roundToDp(def aultHintColor[1],3)
<< Satellite::roundToDp(def aultHintColor[2],3); << Satellite::roundToDp(def aultHintColor[2],3);
map["creator"] = QString("Satellites plugin version %1 (updated)").a rg(SATELLITES_PLUGIN_VERSION); map["creator"] = QString("Satellites plugin version %1 (updated)").a rg(SATELLITES_PLUGIN_VERSION);
map["hintColor"] = defHintCol; map["hintColor"] = defHintCol;
map["shortName"] = "satellite orbital data"; map["shortName"] = "satellite orbital data";
skipping to change at line 774 skipping to change at line 828
if (satMap["hintColor"].toList() == defHintCol) if (satMap["hintColor"].toList() == defHintCol)
satMap.remove("hintColor"); satMap.remove("hintColor");
sats[sat->id] = satMap; sats[sat->id] = satMap;
} }
map["satellites"] = sats; map["satellites"] = sats;
return map; return map;
} }
QStringList Satellites::getGroups(void) const void Satellites::markLastUpdate()
{
lastUpdate = QDateTime::currentDateTime();
QSettings* conf = StelApp::getInstance().getSettings();
conf->setValue("Satellites/last_update",
lastUpdate.toString(Qt::ISODate));
}
QSet<QString> Satellites::getGroups() const
{ {
QStringList groups;
foreach (const SatelliteP& sat, satellites)
{
if (sat->initialized)
{
foreach(const QString& group, sat->groupIDs)
{
if (!groups.contains(group))
groups << group;
}
}
}
return groups; return groups;
} }
QStringList Satellites::getGroupIdList() const
{
QStringList groupList(groups.values());
groupList.sort();
return groupList;
}
void Satellites::addGroup(const QString& groupId)
{
if (groupId.isEmpty())
return;
groups.insert(groupId);
}
QHash<QString,QString> Satellites::getSatellites(const QString& group, Stat us vis) QHash<QString,QString> Satellites::getSatellites(const QString& group, Stat us vis)
{ {
QHash<QString,QString> result; QHash<QString,QString> result;
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
if (sat->initialized) if (sat->initialized)
{ {
if ((group.isEmpty() || sat->groupIDs.contains(group )) && ! result.contains(sat->id)) if ((group.isEmpty() || sat->groups.contains(group)) && ! result.contains(sat->id))
{ {
if (vis==Both || if (vis==Both ||
(vis==Visible && sat->visibl (vis==Visible && sat->displa
e) || yed) ||
(vis==NotVisible && !sat->vi (vis==NotVisible && !sat->di
sible) || splayed) ||
(vis==OrbitError && !sat->or bitValid) || (vis==OrbitError && !sat->or bitValid) ||
(vis==NewlyAdded && sat->isN ew())) (vis==NewlyAdded && sat->isN ew()))
result.insert(sat->id, sat->name); result.insert(sat->id, sat->name);
} }
} }
} }
return result; return result;
} }
SatelliteP Satellites::getByID(const QString& id) SatellitesListModel* Satellites::getSatellitesListModel()
{
if (!satelliteListModel)
satelliteListModel = new SatellitesListModel(&satellites, th
is);
return satelliteListModel;
}
SatelliteP Satellites::getById(const QString& id)
{ {
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
if (sat->initialized && sat->id == id) if (sat->initialized && sat->id == id)
return sat; return sat;
} }
return SatelliteP(); return SatelliteP();
} }
QStringList Satellites::getAllIDs() QStringList Satellites::listAllIds()
{ {
QStringList result; QStringList result;
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
if (sat->initialized) if (sat->initialized)
result.append(sat->id); result.append(sat->id);
} }
return result; return result;
} }
void Satellites::add(const TleDataList& newSatellites) bool Satellites::add(const TleData& tleData)
{ {
int numAdded = 0; //TODO: Duplicates check!!! --BM
QVariantList defaultHintColorMap;
defaultHintColorMap << defaultHintColor[0] << defaultHintColor[1]
<< defaultHintColor[2];
foreach (const TleData& tleSet, newSatellites) // More validation?
{ if (tleData.id.isEmpty() ||
//TODO: Duplicates check? --BM tleData.name.isEmpty() ||
tleData.first.isEmpty() ||
tleData.second.isEmpty())
return false;
if (tleSet.id.isEmpty() || QVariantList hintColor;
tleSet.name.isEmpty() || hintColor << defaultHintColor[0]
tleSet.first.isEmpty() || << defaultHintColor[1]
tleSet.second.isEmpty()) << defaultHintColor[2];
continue;
QVariantMap satProperties;
satProperties.insert("name", tleData.name);
satProperties.insert("tle1", tleData.first);
satProperties.insert("tle2", tleData.second);
satProperties.insert("hintColor", hintColor);
//TODO: Decide if newly added satellites are visible by default --BM
satProperties.insert("visible", true);
satProperties.insert("orbitVisible", false);
SatelliteP sat(new Satellite(tleData.id, satProperties));
if (sat->initialized)
{
qDebug() << "Satellite added:" << tleData.id << tleData.name
;
satellites.append(sat);
sat->setNew();
return true;
}
return false;
}
QVariantMap satProperties; void Satellites::add(const TleDataList& newSatellites)
satProperties.insert("name", tleSet.name); {
satProperties.insert("tle1", tleSet.first); if (satelliteListModel)
satProperties.insert("tle2", tleSet.second); satelliteListModel->beginSatellitesChange();
satProperties.insert("hintColor", defaultHintColorMap);
//TODO: Decide if newly added satellites are visible by defa
ult --BM
satProperties.insert("visible", true);
satProperties.insert("orbitVisible", false);
SatelliteP sat(new Satellite(tleSet.id, satProperties)); int numAdded = 0;
if (sat->initialized) foreach (const TleData& tleSet, newSatellites)
{
if (add(tleSet))
{ {
qDebug() << "Satellites: added" << tleSet.id << tleS
et.name;
satellites.append(sat);
sat->setNew();
numAdded++; numAdded++;
} }
} }
if (numAdded > 0)
qSort(satellites);
if (satelliteListModel)
satelliteListModel->endSatellitesChange();
qDebug() << "Satellites: " qDebug() << "Satellites: "
<< newSatellites.count() << "satell ites proposed for addition, " << newSatellites.count() << "satell ites proposed for addition, "
<< numAdded << " added, " << numAdded << " added, "
<< satellites.count() << " total af ter the operation."; << satellites.count() << " total af ter the operation.";
} }
void Satellites::remove(const QStringList& idList) void Satellites::remove(const QStringList& idList)
{ {
if (satelliteListModel)
satelliteListModel->beginSatellitesChange();
StelObjectMgr* objMgr = GETSTELMODULE(StelObjectMgr); StelObjectMgr* objMgr = GETSTELMODULE(StelObjectMgr);
int numRemoved = 0; int numRemoved = 0;
for (int i = 0; i < satellites.size(); i++) for (int i = 0; i < satellites.size(); i++)
{ {
const SatelliteP& sat = satellites.at(i); const SatelliteP& sat = satellites.at(i);
if (idList.contains(sat->id)) if (idList.contains(sat->id))
{ {
QList<StelObjectP> selected = objMgr->getSelectedObj ect("Satellite"); QList<StelObjectP> selected = objMgr->getSelectedObj ect("Satellite");
if (selected.contains(sat.staticCast<StelObject>())) if (selected.contains(sat.staticCast<StelObject>()))
objMgr->unSelect(); objMgr->unSelect();
qDebug() << "Satellite removed:" << sat->id << sat-> name; qDebug() << "Satellite removed:" << sat->id << sat-> name;
satellites.removeAt(i); satellites.removeAt(i);
i--; //Compensate for the change in the array's inde xing i--; //Compensate for the change in the array's inde xing
numRemoved++; numRemoved++;
} }
} }
// As the satellite list is kept sorted, no need for re-sorting.
if (satelliteListModel)
satelliteListModel->endSatellitesChange();
qDebug() << "Satellites: " qDebug() << "Satellites: "
<< idList.count() << "satellites pr oposed for removal, " << idList.count() << "satellites pr oposed for removal, "
<< numRemoved << " removed, " << numRemoved << " removed, "
<< satellites.count() << " remain." ; << satellites.count() << " remain." ;
} }
int Satellites::getSecondsToUpdate(void) int Satellites::getSecondsToUpdate(void)
{ {
QDateTime nextUpdate = lastUpdate.addSecs(updateFrequencyHours * 360 0); QDateTime nextUpdate = lastUpdate.addSecs(updateFrequencyHours * 360 0);
return QDateTime::currentDateTime().secsTo(nextUpdate); return QDateTime::currentDateTime().secsTo(nextUpdate);
} }
void Satellites::setTleSources(QStringList tleSources) void Satellites::setTleSources(QStringList tleSources)
{ {
updateUrls = tleSources; updateUrls = tleSources;
saveTleSources(updateUrls);
}
void Satellites::saveTleSources(const QStringList& urls)
{
QSettings* conf = StelApp::getInstance().getSettings(); QSettings* conf = StelApp::getInstance().getSettings();
conf->beginGroup("Satellites"); conf->beginGroup("Satellites");
// clear old source list // clear old source list
QRegExp keyRE("^tle_url\\d+$"); conf->remove("tle_sources");
foreach(const QString& key, conf->childKeys())
{
if (keyRE.exactMatch(key))
conf->remove(key);
}
// set the new sources list int index = 0;
int i=0; conf->beginWriteArray("tle_sources");
foreach (const QString& url, updateUrls) foreach (QString url, urls)
{ {
conf->setValue(QString("tle_url%1").arg(i++), url); conf->setArrayIndex(index++);
if (url.startsWith("1,"))
{
conf->setValue("add_new", true);
url.remove(0, 2);
}
else if (url.startsWith("0,"))
url.remove(0, 2);
conf->setValue("url", url);
} }
conf->endArray();
conf->endGroup(); conf->endGroup();
} }
bool Satellites::getFlagLabels(void) bool Satellites::getFlagLabels()
{ {
return Satellite::showLabels; return Satellite::showLabels;
} }
void Satellites::enableInternetUpdates(bool enabled)
{
if (enabled != updatesEnabled)
{
updatesEnabled = enabled;
emit settingsChanged();
}
}
void Satellites::enableAutoAdd(bool enabled)
{
if (autoAddEnabled != enabled)
{
autoAddEnabled = enabled;
emit settingsChanged();
}
}
void Satellites::enableAutoRemove(bool enabled)
{
if (autoRemoveEnabled != enabled)
{
autoRemoveEnabled = enabled;
emit settingsChanged();
}
}
void Satellites::setFlagHints(bool b)
{
if (hintFader != b)
{
hintFader = b;
emit settingsChanged();
}
}
void Satellites::setFlagLabels(bool b) void Satellites::setFlagLabels(bool b)
{ {
Satellite::showLabels = b; if (Satellite::showLabels != b)
{
Satellite::showLabels = b;
emit settingsChanged();
}
}
void Satellites::setLabelFontSize(int size)
{
if (labelFont.pixelSize() != size)
{
labelFont.setPixelSize(size);
emit settingsChanged();
}
}
void Satellites::setUpdateFrequencyHours(int hours)
{
if (updateFrequencyHours != hours)
{
updateFrequencyHours = hours;
emit settingsChanged();
}
} }
void Satellites::checkForUpdate(void) void Satellites::checkForUpdate(void)
{ {
if (updatesEnabled && lastUpdate.addSecs(updateFrequencyHours * 3600 if (updatesEnabled && updateState != Updating
) <= QDateTime::currentDateTime()) && lastUpdate.addSecs(updateFrequencyHours * 3600) <= QDateTime:
updateTLEs(); :currentDateTime())
updateFromOnlineSources();
} }
void Satellites::updateTLEs(void) void Satellites::updateFromOnlineSources()
{ {
if (updateState==Satellites::Updating) if (updateState==Satellites::Updating)
{ {
qWarning() << "Satellites: already updating... will not sta rt again current update is complete."; qWarning() << "Satellites: Internet update already in progre ss!";
return; return;
} }
else else
{ {
qDebug() << "Satellites: starting update..."; qDebug() << "Satellites: starting Internet update...";
} }
lastUpdate = QDateTime::currentDateTime(); // Setting lastUpdate should be done only when the update is finishe
QSettings* conf = StelApp::getInstance().getSettings(); d. -BM
conf->setValue("Satellites/last_update", lastUpdate.toString(Qt::ISO
Date));
if (updateUrls.size() == 0) // TODO: Perhaps tie the emptyness of updateUrls to updatesEnabled..
. --BM
if (updateUrls.isEmpty())
{ {
qWarning() << "Satellites::updateTLEs no update URLs are def qWarning() << "Satellites: update failed."
ined... nothing to do."; << "No update sources are defined!";
emit(tleUpdateComplete(0,satellites.count(),satellites.count
())); // Prevent from re-entering this method on the next check:
markLastUpdate();
// TODO: Do something saner, such as disabling internet upda
tes,
// or stopping the timer. --BM
emit updateStateChanged(OtherError);
emit tleUpdateComplete(0, satellites.count(), 0, 0);
return; return;
} }
updateState = Satellites::Updating; updateState = Satellites::Updating;
emit(updateStateChanged(updateState)); emit(updateStateChanged(updateState));
updateFiles.clear(); updateSources.clear();
numberDownloadsComplete = 0; numberDownloadsComplete = 0;
if (progressBar==NULL) if (progressBar==NULL)
progressBar = StelApp::getInstance().getGui()->addProgressBa r(); progressBar = StelApp::getInstance().getGui()->addProgressBa r();
progressBar->setValue(0); progressBar->setValue(0);
progressBar->setMaximum(updateUrls.size()); progressBar->setMaximum(updateUrls.size());
progressBar->setVisible(true); progressBar->setVisible(true);
progressBar->setFormat("TLE download %v/%m"); progressBar->setFormat("TLE download %v/%m");
// set off the downloads foreach (QString url, updateUrls)
for(int i=0; i<updateUrls.size(); i++)
{ {
downloadMgr->get(QNetworkRequest(QUrl(updateUrls.at(i)))); TleSource source;
source.file = 0;
source.addNew = false;
if (url.startsWith("1,"))
{
// Also prevents inconsistent behavior if the user t
oggles the flag
// while an update is in progress.
source.addNew = autoAddEnabled;
url.remove(0, 2);
}
else if (url.startsWith("0,"))
url.remove(0, 2);
source.url.setUrl(url);
if (source.url.isValid())
{
updateSources.append(source);
downloadMgr->get(QNetworkRequest(source.url));
}
} }
} }
void Satellites::updateDownloadComplete(QNetworkReply* reply) void Satellites::saveDownloadedUpdate(QNetworkReply* reply)
{ {
// check the download worked, and save the data to file if this is t he case. // check the download worked, and save the data to file if this is t he case.
if (reply->error() != QNetworkReply::NoError) if (reply->error() != QNetworkReply::NoError)
{ {
qWarning() << "Satellites::updateDownloadComplete FAILED to qWarning() << "Satellites: FAILED to download"
download" << reply->url() << " Error: " << reply->errorString(); << reply->url().toString(QUrl::RemoveUserInfo)
<< "Error:" << reply->errorString();
} }
else else
{ {
// download completed successfully. // download completed successfully.
try QString name = QString("tle%1.txt").arg(numberDownloadsCompl
{ ete);
QString partialName = QString("tle%1.txt").arg(numbe QString path = dataDir.absoluteFilePath(name);
rDownloadsComplete); // QFile as a child object to the plugin to ease memory mana
QString tleTmpFilePath = StelFileMgr::findFile("modu gement
les/Satellites", StelFileMgr::Flags(StelFileMgr::Writable|StelFileMgr::Dire QFile* tmpFile = new QFile(path, this);
ctory)) + "/" + partialName; if (tmpFile->exists())
QFile tmpFile(tleTmpFilePath); tmpFile->remove();
if (tmpFile.exists())
tmpFile.remove(); if (tmpFile->open(QIODevice::WriteOnly | QIODevice::Text))
{
tmpFile.open(QIODevice::WriteOnly | QIODevice::Text) tmpFile->write(reply->readAll());
; tmpFile->close();
tmpFile.write(reply->readAll());
tmpFile.close(); // The reply URL can be different form the requested
updateFiles << tleTmpFilePath; one...
QUrl url = reply->request().url();
for (int i = 0; i < updateSources.count(); i++)
{
if (updateSources[i].url == url)
{
updateSources[i].file = tmpFile;
tmpFile = 0;
break;
}
}
if (tmpFile) // Something strange just happened...
delete tmpFile; // ...so we have to clean.
} }
catch (std::runtime_error &e) else
{ {
qWarning() << "Satellites::updateDownloadComplete: c qWarning() << "Satellites: cannot save update file:"
annot write TLE data to file:" << e.what(); << tmpFile->error()
<< tmpFile->errorString();
} }
} }
numberDownloadsComplete++; numberDownloadsComplete++;
if (progressBar) if (progressBar)
progressBar->setValue(numberDownloadsComplete); progressBar->setValue(numberDownloadsComplete);
// all downloads are complete... do the update. // Check if all files have been downloaded.
if (numberDownloadsComplete >= updateUrls.size()) // TODO: It's better to keep track of the network requests themselve
s. --BM
if (numberDownloadsComplete < updateSources.size())
return;
if (progressBar)
{ {
updateFromFiles(updateFiles, true); delete progressBar;
progressBar = 0;
} }
// All files have been downloaded, finish the update
TleDataHash newData;
for (int i = 0; i < updateSources.count(); i++)
{
if (!updateSources[i].file)
continue;
if (updateSources[i].file->open(QFile::ReadOnly|QFile::Text)
)
{
parseTleFile(*updateSources[i].file,
newData,
updateSources[i].addNew);
updateSources[i].file->close();
delete updateSources[i].file;
updateSources[i].file = 0;
}
}
updateSources.clear();
updateSatellites(newData);
} }
void Satellites::observerLocationChanged(StelLocation) void Satellites::updateObserverLocation(StelLocation)
{ {
recalculateOrbitLines(); recalculateOrbitLines();
} }
void Satellites::setOrbitLinesFlag(bool b) void Satellites::setOrbitLinesFlag(bool b)
{ {
Satellite::orbitLinesFlag = b; Satellite::orbitLinesFlag = b;
} }
bool Satellites::getOrbitLinesFlag(void) bool Satellites::getOrbitLinesFlag()
{ {
return Satellite::orbitLinesFlag; return Satellite::orbitLinesFlag;
} }
void Satellites::recalculateOrbitLines(void) void Satellites::recalculateOrbitLines(void)
{ {
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
if (sat->initialized && sat->visible && sat->orbitVisible) if (sat->initialized && sat->displayed && sat->orbitDisplaye d)
sat->recalculateOrbitLines(); sat->recalculateOrbitLines();
} }
} }
void Satellites::displayMessage(const QString& message, const QString hexCo lor) void Satellites::displayMessage(const QString& message, const QString hexCo lor)
{ {
messageIDs << GETSTELMODULE(LabelMgr)->labelScreen(message, 30, 30 + (20*messageIDs.count()), true, 16, hexColor); messageIDs << GETSTELMODULE(LabelMgr)->labelScreen(message, 30, 30 + (20*messageIDs.count()), true, 16, hexColor);
messageTimer->start(); messageTimer->start();
} }
void Satellites::messageTimeout(void) void Satellites::hideMessages()
{ {
foreach(const int& id, messageIDs) foreach(const int& id, messageIDs)
{ {
GETSTELMODULE(LabelMgr)->deleteLabel(id); GETSTELMODULE(LabelMgr)->deleteLabel(id);
} }
} }
void Satellites::saveTleData(QString path) void Satellites::saveCatalog(QString path)
{ {
saveTleMap(getTleMap(), path); saveDataMap(createDataMap(), path);
} }
void Satellites::updateFromFiles(QStringList paths, bool deleteFiles) void Satellites::updateFromFiles(QStringList paths, bool deleteFiles)
{ {
// Container for the new data. // Container for the new data.
TleDataHash newTleSets; TleDataHash newTleSets;
if (progressBar)
{
progressBar->setValue(0);
progressBar->setMaximum(paths.size() + 1);
progressBar->setFormat("TLE updating %v/%m");
}
foreach(const QString& tleFilePath, paths) foreach(const QString& tleFilePath, paths)
{ {
QFile tleFile(tleFilePath); QFile tleFile(tleFilePath);
if (tleFile.open(QIODevice::ReadOnly|QIODevice::Text)) if (tleFile.open(QIODevice::ReadOnly|QIODevice::Text))
{ {
parseTleFile(tleFile, newTleSets); parseTleFile(tleFile, newTleSets);
tleFile.close(); tleFile.close();
if (deleteFiles) if (deleteFiles)
tleFile.remove(); tleFile.remove();
if (progressBar)
progressBar->setValue(progressBar->value() +
1);
} }
} }
updateSatellites(newTleSets);
}
void Satellites::updateSatellites(TleDataHash& newTleSets)
{
// Save the update time.
// One of the reasons it's here is that lastUpdate is used below.
markLastUpdate();
if (newTleSets.isEmpty())
{
qWarning() << "Satellites: update files contain no TLE sets!
";
updateState = OtherError;
emit(updateStateChanged(updateState));
return;
}
if (satelliteListModel)
satelliteListModel->beginSatellitesChange();
// Right, we should now have a map of all the elements we downloaded . For each satellite // Right, we should now have a map of all the elements we downloaded . For each satellite
// which this module is managing, see if it exists with an updated e lement, and update it if so... // which this module is managing, see if it exists with an updated e lement, and update it if so...
int numUpdated = 0; int sourceCount = newTleSets.count(); // newTleSets is modified belo
int totalSats = 0; w
int numMissing = 0; int updatedCount = 0;
int totalCount = 0;
int addedCount = 0;
int missingCount = 0; // Also the number of removed sats, if any.
QStringList toBeRemoved;
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
totalSats++; totalCount++;
// Satellites marked as "user-defined" are protected from up
dates and
// removal.
if (sat->userDefined)
{
qDebug() << "Satellite ignored (user-protected):"
<< sat->id << sat->name;
continue;
}
QString id = sat->id; QString id = sat->id;
if (newTleSets.contains(id)) TleData newTle = newTleSets.take(id);
if (!newTle.name.isEmpty())
{ {
TleData newTle = newTleSets.value(id); if (sat->tleElements.first != newTle.first ||
if (sat->tleElements.first != newTle.first || sat->tleElements.second != newTle.second ||
sat->tleElements.second != newTle.se sat->name != newTle.name)
cond ||
sat->name != newTle.name)
{ {
// We have updated TLE elements for this sat ellite // We have updated TLE elements for this sat ellite
sat->setNewTleElements(newTle.first, newTle. second); sat->setNewTleElements(newTle.first, newTle. second);
// Update the name if it has been changed in the source list // Update the name if it has been changed in the source list
sat->name = newTle.name; sat->name = newTle.name;
// we reset this to "now" when we started th e update. // we reset this to "now" when we started th e update.
sat->lastUpdated = lastUpdate; sat->lastUpdated = lastUpdate;
numUpdated++; updatedCount++;
} }
} }
else else
{ {
qWarning() << "Satellites: could not update orbital if (autoRemoveEnabled)
elements for" toBeRemoved.append(sat->id);
<< sat->nam else
e qWarning() << "Satellites:" << sat->id << sa
<< sat->id t->name
<< ": no en << "is missing in the update list
try found in the source TLE lists."; s.";
numMissing++; missingCount++;
} }
} }
if (numUpdated>0) // Only those not in the loaded collection have remained
// (autoAddEnabled is not checked, because it's already in the flags
)
QHash<QString, TleData>::const_iterator i;
for (i = newTleSets.begin(); i != newTleSets.end(); ++i)
{ {
saveTleMap(getTleMap()); if (i.value().addThis)
{
// Add the satellite...
if (add(i.value()))
addedCount++;
}
} }
if (addedCount)
qSort(satellites);
delete progressBar; if (autoRemoveEnabled && !toBeRemoved.isEmpty())
progressBar = NULL; {
qWarning() << "Satellites: purging objects that were not upd
qDebug() << "Satellites: updated" << numUpdated << "/" << totalSats ated...";
<< "satellites. Update URLs contai remove(toBeRemoved);
ned" << newTleSets.size() << "objects. " }
<< "There were" << numMissing << "s
atellies missing from the update URLs";
if (numUpdated==0) if (updatedCount > 0 ||
updateState = CompleteNoUpdates; (autoRemoveEnabled && missingCount > 0))
else {
saveDataMap(createDataMap());
updateState = CompleteUpdates; updateState = CompleteUpdates;
}
else
updateState = CompleteNoUpdates;
if (satelliteListModel)
satelliteListModel->endSatellitesChange();
qDebug() << "Satellites: update finished."
<< updatedCount << "/" << totalCount << "updated,"
<< addedCount << "added,"
<< missingCount << "missing or removed."
<< sourceCount << "source entries parsed.";
emit(updateStateChanged(updateState)); emit(updateStateChanged(updateState));
emit(tleUpdateComplete(numUpdated, totalSats, numMissing)); emit(tleUpdateComplete(updatedCount, totalCount, addedCount, missing Count));
} }
void Satellites::parseTleFile(QFile& openFile, TleDataHash& tleList) void Satellites::parseTleFile(QFile& openFile,
TleDataHash& tleList,
bool addFlagValue)
{ {
if (!openFile.isOpen() || !openFile.isReadable()) if (!openFile.isOpen() || !openFile.isReadable())
return; return;
// Code mostly re-used from updateFromFiles() // Code mostly re-used from updateFromFiles()
int lineNumber = 0; int lineNumber = 0;
TleData lastData; TleData lastData;
while (!openFile.atEnd()) while (!openFile.atEnd())
{ {
QString line = QString(openFile.readLine()).trimmed(); QString line = QString(openFile.readLine()).trimmed();
if (line.length() < 65) // this is title line if (line.length() < 65) // this is title line
{ {
// New entry in the list, so reset all fields // New entry in the list, so reset all fields
lastData = TleData(); lastData = TleData();
lastData.addThis = addFlagValue;
//TODO: We need to think of some kind of ecaping the se //TODO: We need to think of some kind of ecaping the se
//characters in the JSON parser. --BM //characters in the JSON parser. --BM
// The thing in square brackets after the name is ac
tually
// Celestrak's "status code". Parse automatically? -
-BM
line.replace(QRegExp("\\s*\\[([^\\]])*\\]\\s*$"),"") ; // remove things in square brackets line.replace(QRegExp("\\s*\\[([^\\]])*\\]\\s*$"),"") ; // remove things in square brackets
lastData.name = line; lastData.name = line;
} }
else else
{ {
// TODO: Yet another place suitable for a standard T LE regex. --BM
if (QRegExp("^1 .*").exactMatch(line)) if (QRegExp("^1 .*").exactMatch(line))
lastData.first = line; lastData.first = line;
else if (QRegExp("^2 .*").exactMatch(line)) else if (QRegExp("^2 .*").exactMatch(line))
{ {
lastData.second = line; lastData.second = line;
// The Satellite Catalog Number is the secon d number // The Satellite Catalog Number is the secon d number
// on the second line. // on the second line.
QString id = line.split(' ').at(1).trimmed() ; QString id = line.split(' ').at(1).trimmed() ;
if (id.isEmpty()) if (id.isEmpty())
continue; continue;
lastData.id = id; lastData.id = id;
// This is the second line and there will be no more, // This is the second line and there will be no more,
// so if everything is OK, save the elements . // so if everything is OK, save the elements .
if (!lastData.name.isEmpty() && if (!lastData.name.isEmpty() &&
!lastData.first.isEmpty()) !lastData.first.isEmpty())
{ {
//TODO: This overwrites duplicates. // Some satellites can be listed in
Display warning? --BM multiple files,
tleList.insert(id, lastData); // and only some of those files may
be marked for adding,
// so try to preserve the flag - if
it's set,
// feel free to overwrite the existi
ng value.
// If not, overwrite only if it's no
t in the list already.
// NOTE: Second case overwrite may n
eed to check which TLE set is newer.
if (lastData.addThis || !tleList.con
tains(id))
tleList.insert(id, lastData)
; // Overwrite if necessary
} }
//TODO: Error warnings? --BM //TODO: Error warnings? --BM
} }
else else
qDebug() << "Satellites: unprocessed line " << lineNumber << " in file " << openFile.fileName(); qDebug() << "Satellites: unprocessed line " << lineNumber << " in file " << QDir::toNativeSeparators(openFile.fileName ());
} }
} }
} }
void Satellites::update(double deltaTime) void Satellites::update(double deltaTime)
{ {
if (StelApp::getInstance().getCore()->getCurrentLocation().planetNam e != earth->getEnglishName() || (!hintFader && hintFader.getInterstate() <= 0.)) if (StelApp::getInstance().getCore()->getCurrentLocation().planetNam e != earth->getEnglishName() || (!hintFader && hintFader.getInterstate() <= 0.))
return; return;
hintFader.update((int)(deltaTime*1000)); hintFader.update((int)(deltaTime*1000));
foreach(const SatelliteP& sat, satellites) foreach(const SatelliteP& sat, satellites)
{ {
if (sat->initialized && sat->visible) if (sat->initialized && sat->displayed)
sat->update(deltaTime); sat->update(deltaTime);
} }
} }
void Satellites::draw(StelCore* core, StelRenderer* renderer) void Satellites::draw(StelCore* core, StelRenderer* renderer)
{ {
if (core->getCurrentLocation().planetName != earth->getEnglishName() || if (core->getCurrentLocation().planetName != earth->getEnglishName() ||
(core->getJDay()<2436116.3115) || // do not draw anything before Oct 4, 1957, 19:28:34GMT ;-) (core->getJDay()<2436116.3115) || // do not draw anything before Oct 4, 1957, 19:28:34GMT ;-)
(!hintFader && hintFader.getInterstate() <= 0.)) (!hintFader && hintFader.getInterstate() <= 0.))
return; return;
skipping to change at line 1245 skipping to change at line 1532
renderer->setBlendMode(BlendMode_Alpha); renderer->setBlendMode(BlendMode_Alpha);
if(NULL == hintTexture) if(NULL == hintTexture)
{ {
hintTexture = renderer->createTexture(":/satellites/hint.png "); hintTexture = renderer->createTexture(":/satellites/hint.png ");
} }
hintTexture->bind(); hintTexture->bind();
Satellite::viewportHalfspace = prj->getBoundingCap(); Satellite::viewportHalfspace = prj->getBoundingCap();
foreach (const SatelliteP& sat, satellites) foreach (const SatelliteP& sat, satellites)
{ {
if (sat && sat->initialized && sat->visible) if (sat && sat->initialized && sat->displayed)
{ {
sat->draw(core, renderer, prj, hintTexture); sat->draw(core, renderer, prj, hintTexture);
} }
} }
if (GETSTELMODULE(StelObjectMgr)->getFlagSelectedObjectPointer()) if (GETSTELMODULE(StelObjectMgr)->getFlagSelectedObjectPointer())
{ {
drawPointer(core, renderer); drawPointer(core, renderer);
} }
} }
skipping to change at line 1299 skipping to change at line 1586
const float left = screenpos[0] - halfSize - 20; const float left = screenpos[0] - halfSize - 20;
const float right = screenpos[0] + halfSize - 20; const float right = screenpos[0] + halfSize - 20;
const float top = screenpos[1] - halfSize - 20; const float top = screenpos[1] - halfSize - 20;
const float bottom = screenpos[1] + halfSize - 20; const float bottom = screenpos[1] + halfSize - 20;
renderer->drawTexturedRect(left, top, 40, 40, 90); renderer->drawTexturedRect(left, top, 40, 40, 90);
renderer->drawTexturedRect(left, bottom, 40, 40, 0); renderer->drawTexturedRect(left, bottom, 40, 40, 0);
renderer->drawTexturedRect(right, bottom, 40, 40, -90); renderer->drawTexturedRect(right, bottom, 40, 40, -90);
renderer->drawTexturedRect(right, top, 40, 40, -180); renderer->drawTexturedRect(right, top, 40, 40, -180);
} }
} }
void Satellites::translations()
{
#if 0
// Satellite groups
// TRANSLATORS: Satellite group: Bright/naked-eye-visible satellites
N_("visual");
// TRANSLATORS: Satellite group: Scientific satellites
N_("scientific");
// TRANSLATORS: Satellite group: Communication satellites
N_("communications");
// TRANSLATORS: Satellite group: Navigation satellites
N_("navigation");
// TRANSLATORS: Satellite group: Amateur radio (ham) satellites
N_("amateur");
// TRANSLATORS: Satellite group: Weather (meteorological) satellites
N_("weather");
// TRANSLATORS: Satellite group: Satellites in geostationary orbit
N_("geostationary");
// TRANSLATORS: Satellite group: Satellites that are no longer funct
ioning
N_("non-operational");
// TRANSLATORS: Satellite group: Satellites belonging to the GPS con
stellation (the Global Positioning System)
N_("gps");
// TRANSLATORS: Satellite group: Satellites belonging to the Iridium
constellation (Iridium is a proper name)
N_("iridium");
/* For copy/paste:
// TRANSLATORS: Satellite group:
N_("");
*/
// Satellite descriptions - bright and/or famous objects
// Just A FEW objects please! (I'm looking at you, Alex!)
// TRANSLATORS: Satellite description. "Hubble" is a person's name.
N_("The Hubble Space Telescope");
// TRANSLATORS: Satellite description.
N_("The International Space Station");
#endif
}
 End of changes. 145 change blocks. 
272 lines changed or deleted 563 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/