diff --git a/kstars/kstarsdata.cpp b/kstars/kstarsdata.cpp index 99db5eaa2..d55940cc3 100644 --- a/kstars/kstarsdata.cpp +++ b/kstars/kstarsdata.cpp @@ -1,1506 +1,1507 @@ /*************************************************************************** kstarsdata.cpp - K Desktop Planetarium ------------------- begin : Sun Jul 29 2001 copyright : (C) 2001 by Heiko Evermann email : heiko@evermann.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "kstarsdata.h" -#include "fov.h" #include "ksutils.h" #include "Options.h" #include "auxiliary/kspaths.h" #include "skycomponents/supernovaecomponent.h" #include "skycomponents/skymapcomposite.h" #ifndef KSTARS_LITE +#include "fov.h" #include "imageexporter.h" #include "kstars.h" #include "observinglist.h" #include "skymap.h" #include "dialogs/detaildialog.h" #include "oal/execute.h" #endif #ifndef KSTARS_LITE #include #endif #include #include #include #include "kstars_debug.h" namespace { // Report fatal error during data loading to user // Calls QApplication::exit void fatalErrorMessage(QString fname) { #ifndef KSTARS_LITE KMessageBox::sorry(nullptr, i18n("The file %1 could not be found. " "KStars cannot run properly without this file. " "KStars searches for this file in following locations:\n\n\t" "%2\n\n" "It appears that your setup is broken.", fname, QStandardPaths::standardLocations(QStandardPaths::DataLocation).join("\n\t")), i18n("Critical File Not Found: %1", fname)); // FIXME: Must list locations depending on file type #endif qDebug() << i18n("Critical File Not Found: %1", fname); qApp->exit(1); } // Report non-fatal error during data loading to user and ask // whether he wants to continue. // Calls QApplication::exit if he don't #if 1 bool nonFatalErrorMessage(QString fname) { #ifdef KSTARS_LITE Q_UNUSED(fname) #else int res = KMessageBox::warningContinueCancel(0, i18n("The file %1 could not be found. " "KStars can still run without this file. " "KStars search for this file in following locations:\n\n\t" "%2\n\n" "It appears that you setup is broken. Press Continue to run KStars without this file ", fname, QStandardPaths::standardLocations( QStandardPaths::DataLocation ).join("\n\t") ), i18n( "Non-Critical File Not Found: %1", fname )); // FIXME: Must list locations depending on file type if( res != KMessageBox::Continue ) qApp->exit(1); return res == KMessageBox::Continue; #endif return true; } #endif } KStarsData *KStarsData::pinstance = nullptr; KStarsData *KStarsData::Create() { // This method should never be called twice within a run, since a // lot of the code assumes that KStarsData, once created, is never // destroyed. They maintain local copies of KStarsData::Instance() // for efficiency (maybe this should change, but it is not // required to delete and reinstantiate KStarsData). Thus, when we // call this method, pinstance MUST be zero, i.e. this must be the // first (and last) time we are calling it. -- asimha Q_ASSERT(!pinstance); delete pinstance; pinstance = new KStarsData(); return pinstance; } KStarsData::KStarsData() : m_Geo(dms(0), dms(0)), m_ksuserdb(), m_catalogdb(), temporaryTrail(false), //locale( new KLocale( "kstars" ) ), m_preUpdateID(0), m_updateID(0), m_preUpdateNumID(0), m_updateNumID(0), m_preUpdateNum(J2000), m_updateNum(J2000) { #ifndef KSTARS_LITE m_LogObject.reset(new OAL::Log); #endif // at startup times run forward setTimeDirection(0.0); } KStarsData::~KStarsData() { Q_ASSERT(pinstance); //delete locale; qDeleteAll(geoList); geoList.clear(); qDeleteAll(ADVtreeList); ADVtreeList.clear(); pinstance = nullptr; } bool KStarsData::initialize() { //Initialize CatalogDB// catalogdb()->Initialize(); //Load Time Zone Rules// emit progressText(i18n("Reading time zone rules")); if (!readTimeZoneRulebook()) { fatalErrorMessage("TZrules.dat"); return false; } emit progressText(i18n("Upgrade existing user city db to support geographic elevation.")); QString dbfile = KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + QDir::separator() + "mycitydb.sqlite"; /// This code to add Height column to table city in mycitydb.sqlite is a transitional measure to support a meaningful /// geographic elevation. if (QFile::exists(dbfile)) { QSqlDatabase fixcitydb = QSqlDatabase::addDatabase("QSQLITE", "fixcitydb"); fixcitydb.setDatabaseName(dbfile); fixcitydb.open(); if (fixcitydb.tables().contains("city",Qt::CaseInsensitive)) { QSqlRecord r = fixcitydb.record("city"); if (!r.contains("Elevation")) { emit progressText(i18n("Adding \"Elevation\" column to city table.")); QSqlQuery query(fixcitydb); if (query.exec("alter table city add column Elevation real default -10;") == false) { emit progressText(QString("failed to add Elevation column to city table in mycitydb.sqlite: &1").arg(query.lastError().text())); } } else { emit progressText(i18n("City table already contains \"Elevation\".")); } } else { emit progressText(i18n("City table missing from database.")); } fixcitydb.close(); } //Load Cities// emit progressText(i18n("Loading city data")); if (!readCityData()) { fatalErrorMessage("citydb.sqlite"); return false; } //Initialize User Database// emit progressText(i18n("Loading User Information")); m_ksuserdb.Initialize(); //Initialize SkyMapComposite// emit progressText(i18n("Loading sky objects")); m_SkyComposite.reset(new SkyMapComposite()); //Load Image URLs// //#ifndef Q_OS_ANDROID //On Android these 2 calls produce segfault. WARNING emit progressText(i18n("Loading Image URLs")); if( !readURLData( "image_url.dat", 0 ) && !nonFatalErrorMessage( "image_url.dat" ) ) return false; //QtConcurrent::run(this, &KStarsData::readURLData, QString("image_url.dat"), 0, false); //Load Information URLs// //emit progressText(i18n("Loading Information URLs")); if( !readURLData( "info_url.dat", 1 ) && !nonFatalErrorMessage( "info_url.dat" ) ) return false; QtConcurrent::run(this, &KStarsData::readURLData, QString("info_url.dat"), 1, false); //#endif //emit progressText( i18n("Loading Variable Stars" ) ); #ifndef KSTARS_LITE //Initialize Observing List m_ObservingList = new ObservingList(); #endif readUserLog(); #ifndef KSTARS_LITE readADVTreeData(); #endif return true; } void KStarsData::updateTime(GeoLocation *geo, const bool automaticDSTchange) { // sync LTime with the simulation clock LTime = geo->UTtoLT(ut()); syncLST(); //Only check DST if (1) TZrule is not the empty rule, and (2) if we have crossed //the DST change date/time. if (!geo->tzrule()->isEmptyRule()) { if (TimeRunsForward) { // timedirection is forward // DST change happens if current date is bigger than next calculated dst change if (ut() > NextDSTChange) resetToNewDST(geo, automaticDSTchange); } else { // timedirection is backward // DST change happens if current date is smaller than next calculated dst change if (ut() < NextDSTChange) resetToNewDST(geo, automaticDSTchange); } } KSNumbers num(ut().djd()); if (std::abs(ut().djd() - LastNumUpdate.djd()) > 1.0) { LastNumUpdate = KStarsDateTime(ut().djd()); m_preUpdateNumID++; m_preUpdateNum = KSNumbers(num); skyComposite()->update(&num); } if (std::abs(ut().djd() - LastPlanetUpdate.djd()) > 0.01) { LastPlanetUpdate = KStarsDateTime(ut().djd()); skyComposite()->updateSolarSystemBodies(&num); } // Moon moves ~30 arcmin/hr, so update its position every minute. if (std::abs(ut().djd() - LastMoonUpdate.djd()) > 0.00069444) { LastMoonUpdate = ut(); skyComposite()->updateMoons(&num); } //Update Alt/Az coordinates. Timescale varies with zoom level //If Clock is in Manual Mode, always update. (?) if (std::abs(ut().djd() - LastSkyUpdate.djd()) > 0.1 / Options::zoomFactor() || clock()->isManualMode()) { LastSkyUpdate = ut(); m_preUpdateID++; //omit KSNumbers arg == just update Alt/Az coords // <-- Eh? -- asimha. Looks like this behavior / ideology has changed drastically. skyComposite()->update(&num); emit skyUpdate(clock()->isManualMode()); } } void KStarsData::syncUpdateIDs() { m_updateID = m_preUpdateID; if (m_updateNumID == m_preUpdateNumID) return; m_updateNumID = m_preUpdateNumID; m_updateNum = KSNumbers(m_preUpdateNum); } unsigned int KStarsData::incUpdateID() { m_preUpdateID++; m_preUpdateNumID++; syncUpdateIDs(); return m_updateID; } void KStarsData::setFullTimeUpdate() { //Set the update markers to invalid dates to trigger updates in each category LastSkyUpdate = KStarsDateTime(QDateTime()); LastPlanetUpdate = KStarsDateTime(QDateTime()); LastMoonUpdate = KStarsDateTime(QDateTime()); LastNumUpdate = KStarsDateTime(QDateTime()); } void KStarsData::syncLST() { LST = geo()->GSTtoLST(ut().gst()); } void KStarsData::changeDateTime(const KStarsDateTime &newDate) { //Turn off animated slews for the next time step. setSnapNextFocus(); clock()->setUTC(newDate); LTime = geo()->UTtoLT(ut()); //set local sideral time syncLST(); //Make sure Numbers, Moon, planets, and sky objects are updated immediately setFullTimeUpdate(); // reset tzrules data with new local time and time direction (forward or backward) geo()->tzrule()->reset_with_ltime(LTime, geo()->TZ0(), isTimeRunningForward()); // reset next dst change time setNextDSTChange(geo()->tzrule()->nextDSTChange()); } void KStarsData::resetToNewDST(GeoLocation *geo, const bool automaticDSTchange) { // reset tzrules data with local time, timezone offset and time direction (forward or backward) // force a DST change with option true for 3. parameter geo->tzrule()->reset_with_ltime(LTime, geo->TZ0(), TimeRunsForward, automaticDSTchange); // reset next DST change time setNextDSTChange(geo->tzrule()->nextDSTChange()); //reset LTime, because TZoffset has changed LTime = geo->UTtoLT(ut()); } void KStarsData::setTimeDirection(float scale) { TimeRunsForward = scale >= 0; } GeoLocation *KStarsData::locationNamed(const QString &city, const QString &province, const QString &country) { foreach (GeoLocation *loc, geoList) { if (loc->translatedName() == city && (province.isEmpty() || loc->translatedProvince() == province) && (country.isEmpty() || loc->translatedCountry() == country)) { return loc; } } return nullptr; } void KStarsData::setLocationFromOptions() { setLocation(GeoLocation(dms(Options::longitude()), dms(Options::latitude()), Options::cityName(), Options::provinceName(), Options::countryName(), Options::timeZone(), &(Rulebook[Options::dST()]), Options::elevation(), false, 4)); } void KStarsData::setLocation(const GeoLocation &l) { m_Geo = GeoLocation(l); if (m_Geo.lat()->Degrees() >= 90.0) m_Geo.setLat(dms(89.99)); if (m_Geo.lat()->Degrees() <= -90.0) m_Geo.setLat(dms(-89.99)); //store data in the Options objects Options::setCityName(m_Geo.name()); Options::setProvinceName(m_Geo.province()); Options::setCountryName(m_Geo.country()); Options::setTimeZone(m_Geo.TZ0()); Options::setElevation(m_Geo.elevation()); Options::setLongitude(m_Geo.lng()->Degrees()); Options::setLatitude(m_Geo.lat()->Degrees()); // set the rule from rulebook foreach (const QString &key, Rulebook.keys()) { if (!key.isEmpty() && m_Geo.tzrule()->equals(&Rulebook[key])) Options::setDST(key); } emit geoChanged(); } SkyObject *KStarsData::objectNamed(const QString &name) { if ((name == "star") || (name == "nothing") || name.isEmpty()) return nullptr; return skyComposite()->findByName(name); } bool KStarsData::readCityData() { QSqlDatabase citydb = QSqlDatabase::addDatabase("QSQLITE", "citydb"); QString dbfile = KSPaths::locate(QStandardPaths::GenericDataLocation, "citydb.sqlite"); citydb.setDatabaseName(dbfile); if (citydb.open() == false) { qCCritical(KSTARS) << "Unable to open city database file " << dbfile << citydb.lastError().text(); return false; } QSqlQuery get_query(citydb); //get_query.prepare("SELECT * FROM city"); if (!get_query.exec("SELECT * FROM city")) { qCCritical(KSTARS) << get_query.lastError(); return false; } bool citiesFound = false; // get_query.size() always returns -1 so we set citiesFound if at least one city is found while (get_query.next()) { citiesFound = true; QString name = get_query.value(1).toString(); QString province = get_query.value(2).toString(); QString country = get_query.value(3).toString(); dms lat = dms(get_query.value(4).toString()); dms lng = dms(get_query.value(5).toString()); double TZ = get_query.value(6).toDouble(); TimeZoneRule *TZrule = &(Rulebook[get_query.value(7).toString()]); double elevation = get_query.value(8).toDouble(); // appends city names to list geoList.append(new GeoLocation(lng, lat, name, province, country, TZ, TZrule, elevation, true,4)); } citydb.close(); // Reading local database QSqlDatabase mycitydb = QSqlDatabase::addDatabase("QSQLITE", "mycitydb"); dbfile = KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + QDir::separator() + "mycitydb.sqlite"; if (QFile::exists(dbfile)) { mycitydb.setDatabaseName(dbfile); if (mycitydb.open()) { QSqlQuery get_query(mycitydb); if (!get_query.exec("SELECT * FROM city")) { qDebug() << get_query.lastError(); return false; } while (get_query.next()) { QString name = get_query.value(1).toString(); QString province = get_query.value(2).toString(); QString country = get_query.value(3).toString(); dms lat = dms(get_query.value(4).toString()); dms lng = dms(get_query.value(5).toString()); double TZ = get_query.value(6).toDouble(); TimeZoneRule *TZrule = &(Rulebook[get_query.value(7).toString()]); double elevation = get_query.value(8).toDouble(); // appends city names to list geoList.append(new GeoLocation(lng, lat, name, province, country, TZ, TZrule, elevation, false,4)); } mycitydb.close(); } } return citiesFound; } bool KStarsData::readTimeZoneRulebook() { QFile file; if (KSUtils::openDataFile(file, "TZrules.dat")) { QTextStream stream(&file); while (!stream.atEnd()) { QString line = stream.readLine().trimmed(); if (line.length() && !line.startsWith('#')) //ignore commented and blank lines { QStringList fields = line.split(' ', QString::SkipEmptyParts); QString id = fields[0]; QTime stime = QTime(fields[3].leftRef(fields[3].indexOf(':')).toInt(), fields[3].midRef(fields[3].indexOf(':') + 1, fields[3].length()).toInt()); QTime rtime = QTime(fields[6].leftRef(fields[6].indexOf(':')).toInt(), fields[6].midRef(fields[6].indexOf(':') + 1, fields[6].length()).toInt()); Rulebook[id] = TimeZoneRule(fields[1], fields[2], stime, fields[4], fields[5], rtime); } } return true; } else { return false; } } bool KStarsData::openUrlFile(const QString &urlfile, QFile &file) { //QFile file; QString localFile; bool fileFound = false; QFile localeFile; //if ( locale->language() != "en_US" ) if (QLocale().language() != QLocale::English) //localFile = locale->language() + '/' + urlfile; localFile = QLocale().languageToString(QLocale().language()) + '/' + urlfile; if (!localFile.isEmpty() && KSUtils::openDataFile(file, localFile)) { fileFound = true; } else { // Try to load locale file, if not successful, load regular urlfile and then copy it to locale. file.setFileName(KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + urlfile); if (file.open(QIODevice::ReadOnly)) { //local file found. Now, if global file has newer timestamp, then merge the two files. //First load local file into QStringList bool newDataFound(false); QStringList urlData; QTextStream lStream(&file); while (!lStream.atEnd()) urlData.append(lStream.readLine()); //Find global file(s) in findAllResources() list. QFileInfo fi_local(file.fileName()); QStringList flist = KSPaths::locateAll(QStandardPaths::DataLocation, urlfile); for (int i = 0; i < flist.size(); i++) { if (flist[i] != file.fileName()) { QFileInfo fi_global(flist[i]); //Is this global file newer than the local file? if (fi_global.lastModified() > fi_local.lastModified()) { //Global file has newer timestamp than local. Add lines in global file that don't already exist in local file. //be smart about this; in some cases the URL is updated but the image is probably the same if its //label string is the same. So only check strings up to last ":" QFile globalFile(flist[i]); if (globalFile.open(QIODevice::ReadOnly)) { QTextStream gStream(&globalFile); while (!gStream.atEnd()) { QString line = gStream.readLine(); //If global-file line begins with "XXX:" then this line should be removed from the local file. if (line.startsWith(QLatin1String("XXX:")) && urlData.contains(line.mid(4))) { urlData.removeAt(urlData.indexOf(line.mid(4))); } else { //does local file contain the current global file line, up to second ':' ? bool linefound(false); for (int j = 0; j < urlData.size(); ++j) { if (urlData[j].contains(line.left(line.indexOf(':', line.indexOf(':') + 1)))) { //replace line in urlData with its equivalent in the newer global file. urlData.replace(j, line); if (!newDataFound) newDataFound = true; linefound = true; break; } } if (!linefound) { urlData.append(line); if (!newDataFound) newDataFound = true; } } } } } } } file.close(); //(possibly) write appended local file if (newDataFound) { if (file.open(QIODevice::WriteOnly)) { QTextStream outStream(&file); for (int i = 0; i < urlData.size(); i++) { outStream << urlData[i] << endl; } file.close(); } } if (file.open(QIODevice::ReadOnly)) fileFound = true; } else { if (KSUtils::openDataFile(file, urlfile)) { if (QLocale().language() != QLocale::English) qDebug() << "No localized URL file; using default English file."; // we found urlfile, we need to copy it to locale localeFile.setFileName(KSPaths::writableLocation(QStandardPaths::GenericDataLocation) + urlfile); if (localeFile.open(QIODevice::WriteOnly)) { QTextStream readStream(&file); QTextStream writeStream(&localeFile); while (!readStream.atEnd()) { QString line = readStream.readLine(); if (!line.startsWith(QLatin1String("XXX:"))) //do not write "deleted" lines writeStream << line << endl; } localeFile.close(); file.reset(); } else { qDebug() << "Failed to copy default URL file to locale folder, modifying default object links is " "not possible"; } fileFound = true; } } } return fileFound; } // FIXME: This is a significant contributor to KStars start-up time bool KStarsData::readURLData(const QString &urlfile, int type, bool deepOnly) { #ifndef KSTARS_LITE if (KStars::Closing) return true; #endif QFile file; if (!openUrlFile(urlfile, file)) return false; QTextStream stream(&file); while (!stream.atEnd()) { QString line = stream.readLine(); //ignore comment lines if (!line.startsWith('#')) { #ifndef KSTARS_LITE if (KStars::Closing) { file.close(); return true; } #endif int idx = line.indexOf(':'); QString name = line.left(idx); if (name == "XXX") continue; QString sub = line.mid(idx + 1); idx = sub.indexOf(':'); QString title = sub.left(idx); QString url = sub.mid(idx + 1); // Dirty hack to fix things up for planets SkyObject *o; if (name == "Mercury" || name == "Venus" || name == "Mars" || name == "Jupiter" || name == "Saturn" || name == "Uranus" || name == "Neptune" /* || name == "Pluto" */) o = skyComposite()->findByName(i18n(name.toLocal8Bit().data())); else o = skyComposite()->findByName(name); if (!o) { qCWarning(KSTARS) << i18n("Object named %1 not found", name); } else { if (!deepOnly || (o->type() > 2 && o->type() < 9)) { if (type == 0) //image URL { o->ImageList().append(url); o->ImageTitle().append(title); } else if (type == 1) //info URL { o->InfoList().append(url); o->InfoTitle().append(title); } } } } } file.close(); return true; } // FIXME: Improve the user log system // Note: It might be very nice to keep the log in plaintext files, for // portability, human-readability, and greppability. However, it takes // a lot of time to parse and look up, is very messy from the // reliability and programming point of view, needs to be parsed at // start, can become corrupt easily because of a missing bracket... // An SQLite database is a good compromise. A user can easily view it // using an SQLite browser. There is no need to read at start-up, one // can read the log when required. Easy to edit logs / update logs // etc. Will not become corrupt. Needn't be parsed. // However, IMHO, it is best to put these kinds of things in separate // databases, instead of unifying them as a table under the user // database. This ensures portability and a certain robustness that if // a user opens it, they cannot incorrectly edit a part of the DB they // did not intend to edit. // --asimha 2016 Aug 17 // FIXME: This is a significant contributor to KStars startup time. bool KStarsData::readUserLog() { QFile file; QString buffer; QString sub, name, data; if (!KSUtils::openDataFile(file, "userlog.dat")) return false; QTextStream stream(&file); if (!stream.atEnd()) buffer = stream.readAll(); while (!buffer.isEmpty()) { int startIndex, endIndex; startIndex = buffer.indexOf(QLatin1String("[KSLABEL:")); sub = buffer.mid(startIndex); // FIXME: This is inefficient because we are making a copy of a huge string! endIndex = sub.indexOf(QLatin1String("[KSLogEnd]")); // Read name after KSLABEL identifier name = sub.mid(startIndex + 9, sub.indexOf(']') - (startIndex + 9)); // Read data and skip new line data = sub.mid(sub.indexOf(']') + 2, endIndex - (sub.indexOf(']') + 2)); buffer = buffer.mid(endIndex + 11); //Find the sky object named 'name'. //Note that ObjectNameList::find() looks for the ascii representation //of star genetive names, so stars are identified that way in the user log. SkyObject *o = skyComposite()->findByName(name); if (!o) { qWarning() << name << " not found"; } else { o->userLog() = data; } } // end while file.close(); return true; } bool KStarsData::readADVTreeData() { QFile file; QString Interface; QString Name, Link, subName; if (!KSUtils::openDataFile(file, "advinterface.dat")) return false; QTextStream stream(&file); QString Line; while (!stream.atEnd()) { int Type, interfaceIndex; Line = stream.readLine(); if (Line.startsWith(QLatin1String("[KSLABEL]"))) { Name = Line.mid(9); Type = 0; } else if (Line.startsWith(QLatin1String("[END]"))) Type = 1; else if (Line.startsWith(QLatin1String("[KSINTERFACE]"))) { Interface = Line.mid(13); continue; } else { int idx = Line.indexOf(':'); Name = Line.left(idx); Link = Line.mid(idx + 1); // Link is empty, using Interface instead if (Link.isEmpty()) { Link = Interface; subName = Name; interfaceIndex = Link.indexOf(QLatin1String("KSINTERFACE")); Link.remove(interfaceIndex, 11); Link = Link.insert(interfaceIndex, subName.replace(' ', '+')); } Type = 2; } ADVTreeData *ADVData = new ADVTreeData; ADVData->Name = Name; ADVData->Link = Link; ADVData->Type = Type; ADVtreeList.append(ADVData); } return true; } //There's a lot of code duplication here, but it's not avoidable because //this function is only called from main.cpp when the user is using //"dump" mode to produce an image from the command line. In this mode, //there is no KStars object, so none of the DBus functions can be called //directly. bool KStarsData::executeScript(const QString &scriptname, SkyMap *map) { #ifndef KSTARS_LITE int cmdCount(0); QFile f(scriptname); if (!f.open(QIODevice::ReadOnly)) { qDebug() << "Could not open file " << f.fileName(); return false; } QTextStream istream(&f); while (!istream.atEnd()) { QString line = istream.readLine(); line.remove("string:"); line.remove("int:"); line.remove("double:"); line.remove("bool:"); //find a dbus line and extract the function name and its arguments //The function name starts after the last occurrence of "org.kde.kstars." //or perhaps "org.kde.kstars.SimClock.". if (line.startsWith(QString("dbus-send"))) { QString funcprefix = "org.kde.kstars.SimClock."; int i = line.lastIndexOf(funcprefix); if (i >= 0) { i += funcprefix.length(); } else { funcprefix = "org.kde.kstars."; i = line.lastIndexOf(funcprefix); if (i >= 0) { i += funcprefix.length(); } } if (i < 0) { qWarning() << "Could not parse line: " << line; return false; } QStringList fn = line.mid(i).split(' '); //DEBUG //qDebug() << fn << endl; if (fn[0] == "lookTowards" && fn.size() >= 2) { double az(-1.0); QString arg = fn[1].toLower(); if (arg == "n" || arg == "north") az = 0.0; if (arg == "ne" || arg == "northeast") az = 45.0; if (arg == "e" || arg == "east") az = 90.0; if (arg == "se" || arg == "southeast") az = 135.0; if (arg == "s" || arg == "south") az = 180.0; if (arg == "sw" || arg == "southwest") az = 225.0; if (arg == "w" || arg == "west") az = 270.0; if (arg == "nw" || arg == "northwest") az = 335.0; if (az >= 0.0) { map->setFocusAltAz(dms(90.0), map->focus()->az()); map->focus()->HorizontalToEquatorial(&LST, geo()->lat()); map->setDestination(*map->focus()); cmdCount++; } if (arg == "z" || arg == "zenith") { map->setFocusAltAz(dms(90.0), map->focus()->az()); map->focus()->HorizontalToEquatorial(&LST, geo()->lat()); map->setDestination(*map->focus()); cmdCount++; } //try a named object. The name is everything after fn[0], //concatenated with spaces. fn.removeAll(fn.first()); QString objname = fn.join(" "); SkyObject *target = objectNamed(objname); if (target) { map->setFocus(target); map->focus()->EquatorialToHorizontal(&LST, geo()->lat()); map->setDestination(*map->focus()); cmdCount++; } } else if (fn[0] == "setRaDec" && fn.size() == 3) { bool ok(false); dms r(0.0), d(0.0); ok = r.setFromString(fn[1], false); //assume angle in hours if (ok) ok = d.setFromString(fn[2], true); //assume angle in degrees if (ok) { map->setFocus(r, d); map->focus()->EquatorialToHorizontal(&LST, geo()->lat()); cmdCount++; } } else if (fn[0] == "setAltAz" && fn.size() == 3) { bool ok(false); dms az(0.0), alt(0.0); ok = alt.setFromString(fn[1]); if (ok) ok = az.setFromString(fn[2]); if (ok) { map->setFocusAltAz(alt, az); map->focus()->HorizontalToEquatorial(&LST, geo()->lat()); cmdCount++; } } else if (fn[0] == "loadColorScheme") { fn.removeAll(fn.first()); QString csName = fn.join(" ").remove('\"'); qCDebug(KSTARS) << "Loading Color scheme: " << csName; QString filename = csName.toLower().trimmed(); bool ok(false); //Parse default names which don't follow the regular file-naming scheme if (csName == i18nc("use default color scheme", "Default Colors")) filename = "classic.colors"; if (csName == i18nc("use 'star chart' color scheme", "Star Chart")) filename = "chart.colors"; if (csName == i18nc("use 'night vision' color scheme", "Night Vision")) filename = "night.colors"; //Try the filename if it ends with ".colors" if (filename.endsWith(QLatin1String(".colors"))) ok = colorScheme()->load(filename); //If that didn't work, try assuming that 'name' is the color scheme name //convert it to a filename exactly as ColorScheme::save() does if (!ok) { if (!filename.isEmpty()) { for (int i = 0; i < filename.length(); ++i) if (filename.at(i) == ' ') filename.replace(i, 1, "-"); filename = filename.append(".colors"); ok = colorScheme()->load(filename); } if (!ok) qDebug() << QString("Unable to load color scheme named %1. Also tried %2.") .arg(csName, filename); } } else if (fn[0] == "zoom" && fn.size() == 2) { bool ok(false); double z = fn[1].toDouble(&ok); if (ok) { if (z > MAXZOOM) z = MAXZOOM; if (z < MINZOOM) z = MINZOOM; Options::setZoomFactor(z); cmdCount++; } } else if (fn[0] == "zoomIn") { if (Options::zoomFactor() < MAXZOOM) { Options::setZoomFactor(Options::zoomFactor() * DZOOM); cmdCount++; } } else if (fn[0] == "zoomOut") { if (Options::zoomFactor() > MINZOOM) { Options::setZoomFactor(Options::zoomFactor() / DZOOM); cmdCount++; } } else if (fn[0] == "defaultZoom") { Options::setZoomFactor(DEFAULTZOOM); cmdCount++; } else if (fn[0] == "setLocalTime" && fn.size() == 7) { bool ok(false); // min is a macro - use mnt int yr(0), mth(0), day(0), hr(0), mnt(0), sec(0); yr = fn[1].toInt(&ok); if (ok) mth = fn[2].toInt(&ok); if (ok) day = fn[3].toInt(&ok); if (ok) hr = fn[4].toInt(&ok); if (ok) mnt = fn[5].toInt(&ok); if (ok) sec = fn[6].toInt(&ok); if (ok) { changeDateTime(geo()->LTtoUT(KStarsDateTime(QDate(yr, mth, day), QTime(hr, mnt, sec)))); cmdCount++; } else { qWarning() << ki18n("Could not set time: %1 / %2 / %3 ; %4:%5:%6") .subs(day) .subs(mth) .subs(yr) .subs(hr) .subs(mnt) .subs(sec) .toString() << endl; } } else if (fn[0] == "changeViewOption" && fn.size() == 3) { bool bOk(false), dOk(false); //parse bool value bool bVal(false); if (fn[2].toLower() == "true") { bOk = true; bVal = true; } if (fn[2].toLower() == "false") { bOk = true; bVal = false; } if (fn[2] == "1") { bOk = true; bVal = true; } if (fn[2] == "0") { bOk = true; bVal = false; } //parse double value double dVal = fn[2].toDouble(&dOk); // FIXME: REGRESSION // if ( fn[1] == "FOVName" ) { Options::setFOVName( fn[2] ); cmdCount++; } // if ( fn[1] == "FOVSizeX" && dOk ) { Options::setFOVSizeX( (float)dVal ); cmdCount++; } // if ( fn[1] == "FOVSizeY" && dOk ) { Options::setFOVSizeY( (float)dVal ); cmdCount++; } // if ( fn[1] == "FOVShape" && nOk ) { Options::setFOVShape( nVal ); cmdCount++; } // if ( fn[1] == "FOVColor" ) { Options::setFOVColor( fn[2] ); cmdCount++; } if (fn[1] == "ShowStars" && bOk) { Options::setShowStars(bVal); cmdCount++; } if (fn[1] == "ShowMessier" && bOk) { Options::setShowMessier(bVal); cmdCount++; } if (fn[1] == "ShowMessierImages" && bOk) { Options::setShowMessierImages(bVal); cmdCount++; } if (fn[1] == "ShowCLines" && bOk) { Options::setShowCLines(bVal); cmdCount++; } if (fn[1] == "ShowCNames" && bOk) { Options::setShowCNames(bVal); cmdCount++; } if (fn[1] == "ShowNGC" && bOk) { Options::setShowNGC(bVal); cmdCount++; } if (fn[1] == "ShowIC" && bOk) { Options::setShowIC(bVal); cmdCount++; } if (fn[1] == "ShowMilkyWay" && bOk) { Options::setShowMilkyWay(bVal); cmdCount++; } if (fn[1] == "ShowEquatorialGrid" && bOk) { Options::setShowEquatorialGrid(bVal); cmdCount++; } if (fn[1] == "ShowHorizontalGrid" && bOk) { Options::setShowHorizontalGrid(bVal); cmdCount++; } if (fn[1] == "ShowEquator" && bOk) { Options::setShowEquator(bVal); cmdCount++; } if (fn[1] == "ShowEcliptic" && bOk) { Options::setShowEcliptic(bVal); cmdCount++; } if (fn[1] == "ShowHorizon" && bOk) { Options::setShowHorizon(bVal); cmdCount++; } if (fn[1] == "ShowGround" && bOk) { Options::setShowGround(bVal); cmdCount++; } if (fn[1] == "ShowSun" && bOk) { Options::setShowSun(bVal); cmdCount++; } if (fn[1] == "ShowMoon" && bOk) { Options::setShowMoon(bVal); cmdCount++; } if (fn[1] == "ShowMercury" && bOk) { Options::setShowMercury(bVal); cmdCount++; } if (fn[1] == "ShowVenus" && bOk) { Options::setShowVenus(bVal); cmdCount++; } if (fn[1] == "ShowMars" && bOk) { Options::setShowMars(bVal); cmdCount++; } if (fn[1] == "ShowJupiter" && bOk) { Options::setShowJupiter(bVal); cmdCount++; } if (fn[1] == "ShowSaturn" && bOk) { Options::setShowSaturn(bVal); cmdCount++; } if (fn[1] == "ShowUranus" && bOk) { Options::setShowUranus(bVal); cmdCount++; } if (fn[1] == "ShowNeptune" && bOk) { Options::setShowNeptune(bVal); cmdCount++; } //if ( fn[1] == "ShowPluto" && bOk ) { Options::setShowPluto( bVal ); cmdCount++; } if (fn[1] == "ShowAsteroids" && bOk) { Options::setShowAsteroids(bVal); cmdCount++; } if (fn[1] == "ShowComets" && bOk) { Options::setShowComets(bVal); cmdCount++; } if (fn[1] == "ShowSolarSystem" && bOk) { Options::setShowSolarSystem(bVal); cmdCount++; } if (fn[1] == "ShowDeepSky" && bOk) { Options::setShowDeepSky(bVal); cmdCount++; } if (fn[1] == "ShowSupernovae" && bOk) { Options::setShowSupernovae(bVal); cmdCount++; } if (fn[1] == "ShowStarNames" && bOk) { Options::setShowStarNames(bVal); cmdCount++; } if (fn[1] == "ShowStarMagnitudes" && bOk) { Options::setShowStarMagnitudes(bVal); cmdCount++; } if (fn[1] == "ShowAsteroidNames" && bOk) { Options::setShowAsteroidNames(bVal); cmdCount++; } if (fn[1] == "ShowCometNames" && bOk) { Options::setShowCometNames(bVal); cmdCount++; } if (fn[1] == "ShowPlanetNames" && bOk) { Options::setShowPlanetNames(bVal); cmdCount++; } if (fn[1] == "ShowPlanetImages" && bOk) { Options::setShowPlanetImages(bVal); cmdCount++; } if (fn[1] == "UseAltAz" && bOk) { Options::setUseAltAz(bVal); cmdCount++; } if (fn[1] == "UseRefraction" && bOk) { Options::setUseRefraction(bVal); cmdCount++; } if (fn[1] == "UseAutoLabel" && bOk) { Options::setUseAutoLabel(bVal); cmdCount++; } if (fn[1] == "UseAutoTrail" && bOk) { Options::setUseAutoTrail(bVal); cmdCount++; } if (fn[1] == "UseAnimatedSlewing" && bOk) { Options::setUseAnimatedSlewing(bVal); cmdCount++; } if (fn[1] == "FadePlanetTrails" && bOk) { Options::setFadePlanetTrails(bVal); cmdCount++; } if (fn[1] == "SlewTimeScale" && dOk) { Options::setSlewTimeScale(dVal); cmdCount++; } if (fn[1] == "ZoomFactor" && dOk) { Options::setZoomFactor(dVal); cmdCount++; } // if ( fn[1] == "MagLimitDrawStar" && dOk ) { Options::setMagLimitDrawStar( dVal ); cmdCount++; } if (fn[1] == "StarDensity" && dOk) { Options::setStarDensity(dVal); cmdCount++; } // if ( fn[1] == "MagLimitDrawStarZoomOut" && dOk ) { Options::setMagLimitDrawStarZoomOut( dVal ); cmdCount++; } if (fn[1] == "MagLimitDrawDeepSky" && dOk) { Options::setMagLimitDrawDeepSky(dVal); cmdCount++; } if (fn[1] == "MagLimitDrawDeepSkyZoomOut" && dOk) { Options::setMagLimitDrawDeepSkyZoomOut(dVal); cmdCount++; } if (fn[1] == "StarLabelDensity" && dOk) { Options::setStarLabelDensity(dVal); cmdCount++; } if (fn[1] == "MagLimitHideStar" && dOk) { Options::setMagLimitHideStar(dVal); cmdCount++; } if (fn[1] == "MagLimitAsteroid" && dOk) { Options::setMagLimitAsteroid(dVal); cmdCount++; } if (fn[1] == "AsteroidLabelDensity" && dOk) { Options::setAsteroidLabelDensity(dVal); cmdCount++; } if (fn[1] == "MaxRadCometName" && dOk) { Options::setMaxRadCometName(dVal); cmdCount++; } //these three are a "radio group" if (fn[1] == "UseLatinConstellationNames" && bOk) { Options::setUseLatinConstellNames(true); Options::setUseLocalConstellNames(false); Options::setUseAbbrevConstellNames(false); cmdCount++; } if (fn[1] == "UseLocalConstellationNames" && bOk) { Options::setUseLatinConstellNames(false); Options::setUseLocalConstellNames(true); Options::setUseAbbrevConstellNames(false); cmdCount++; } if (fn[1] == "UseAbbrevConstellationNames" && bOk) { Options::setUseLatinConstellNames(false); Options::setUseLocalConstellNames(false); Options::setUseAbbrevConstellNames(true); cmdCount++; } } else if (fn[0] == "setGeoLocation" && (fn.size() == 3 || fn.size() == 4)) { QString city(fn[1]), province, country(fn[2]); province.clear(); if (fn.size() == 4) { province = fn[2]; country = fn[3]; } bool cityFound(false); foreach (GeoLocation *loc, geoList) { if (loc->translatedName() == city && (province.isEmpty() || loc->translatedProvince() == province) && loc->translatedCountry() == country) { cityFound = true; setLocation(*loc); cmdCount++; break; } } if (!cityFound) qWarning() << i18n("Could not set location named %1, %2, %3", city, province, country); } } } //end while if (cmdCount) return true; #else Q_UNUSED(map) Q_UNUSED(scriptname) #endif return false; } +#ifndef KSTARS_LITE void KStarsData::syncFOV() { visibleFOVs.clear(); // Add visible FOVs foreach (FOV *fov, availFOVs) { if (Options::fOVNames().contains(fov->name())) visibleFOVs.append(fov); } // Remove unavailable FOVs QSet names = QSet::fromList(Options::fOVNames()); QSet all; foreach (FOV *fov, visibleFOVs) { all.insert(fov->name()); } Options::setFOVNames(all.intersect(names).toList()); } -#ifndef KSTARS_LITE + // FIXME: Why does KStarsData store the Execute instance??? -- asimha Execute *KStarsData::executeSession() { if (!m_Execute.get()) m_Execute.reset(new Execute()); return m_Execute.get(); } // FIXME: Why does KStarsData store the ImageExporer instance??? KStarsData is supposed to work with no reference to KStars -- asimha ImageExporter *KStarsData::imageExporter() { if (!m_ImageExporter.get()) m_ImageExporter.reset(new ImageExporter(KStars::Instance())); return m_ImageExporter.get(); } #endif diff --git a/kstars/kstarsdata.h b/kstars/kstarsdata.h index b60f5092b..2940e28b1 100644 --- a/kstars/kstarsdata.h +++ b/kstars/kstarsdata.h @@ -1,411 +1,413 @@ /*************************************************************************** kstarsdata.h - K Desktop Planetarium ------------------- begin : Sun Jul 29 2001 copyright : (C) 2001 by Heiko Evermann email : heiko@evermann.de ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #pragma once #include "catalogdb.h" #include "colorscheme.h" #include "geolocation.h" #include "ksnumbers.h" #include "kstarsdatetime.h" #include "ksuserdb.h" #include "simclock.h" #ifndef KSTARS_LITE #include "oal/oal.h" #include "oal/log.h" #endif #include #include #include #include #include #define MINZOOM 250. #define MAXZOOM 5000000. #define DEFAULTZOOM 2000. #define DZOOM 1.189207115 // 2^(1/4) #define AU_KM 1.49605e8 //km in one AU class QFile; class Execute; class FOV; class ImageExporter; class SkyMap; class SkyMapComposite; class SkyObject; class ObservingList; class TimeZoneRule; #ifdef KSTARS_LITE //Will go away when details window will be implemented in KStars Lite struct ADVTreeData { QString Name; QString Link; int Type; }; #else struct ADVTreeData; #endif /** * @class KStarsData * KStarsData is the backbone of KStars. It contains all the data used by KStars, * including the SkyMapComposite that contains all items in the skymap * (stars, deep-sky objects, planets, constellations, etc). Other kinds of data * are stored here as well: the geographic locations, the timezone rules, etc. * * @author Heiko Evermann * @version 1.0 */ class KStarsData : public QObject { Q_OBJECT protected: /** Constructor. */ KStarsData(); public: // FIXME: It uses temporary trail. There must be way to // this better. And resumeKey in DBUS code friend class KStars; // FIXME: it uses temporary trail and resumeKey friend class SkyMap; // FIXME: uses geoList and changes it. friend class LocationDialog; friend class LocationDialogLite; static KStarsData *Create(); static inline KStarsData *Instance() { return pinstance; } /** * Initialize KStarsData while running splash screen. * @return true on success. */ bool initialize(); /** Destructor. Delete data objects. */ ~KStarsData() override; /** * Set the NextDSTChange member. * Need this accessor because I could not make KStars::privatedata a friend * class for some reason...:/ */ void setNextDSTChange(const KStarsDateTime &dt) { NextDSTChange = dt; } /** * Returns true if time is running forward else false. Used by KStars to prevent * double calculations of daylight saving change time. */ bool isTimeRunningForward() const { return TimeRunsForward; } /** @return pointer to the localization (KLocale) object */ //KLocale *getLocale() { return locale; } /** * @short Find object by name. * @param name Object name to find * @return pointer to SkyObject matching this name */ SkyObject *objectNamed(const QString &name); /** * The Sky is updated more frequently than the moon, which is updated more frequently * than the planets. The date of the last update for each category is recorded so we * know when we need to do it again (see KStars::updateTime()). * Initializing these to -1000000.0 ensures they will be updated immediately * on the first call to KStars::updateTime(). */ void setFullTimeUpdate(); /** * Change the current simulation date/time to the KStarsDateTime argument. * Specified DateTime is always universal time. * @param newDate the DateTime to set. */ void changeDateTime(const KStarsDateTime &newDate); /** @return pointer to the current simulation local time */ const KStarsDateTime <() const { return LTime; } /** @return reference to the current simulation universal time */ const KStarsDateTime &ut() const { return Clock.utc(); } /** Sync the LST with the simulation clock. */ void syncLST(); /** @return pointer to SkyComposite */ SkyMapComposite *skyComposite() { return m_SkyComposite.get(); } /** @return pointer to the ColorScheme object */ ColorScheme *colorScheme() { return &CScheme; } /** @return name of current color scheme **/ Q_INVOKABLE QString colorSchemeName() { return CScheme.fileName(); } /** @return pointer to the KSUserDB object */ KSUserDB *userdb() { return &m_ksuserdb; } /** @return pointer to the Catalog DB object */ CatalogDB *catalogdb() { return &m_catalogdb; } /** @return pointer to the simulation Clock object */ Q_INVOKABLE SimClock *clock() { return &Clock; } /** @return pointer to the local sidereal time: a dms object */ CachingDms *lst() { return &LST; } /** @return pointer to the GeoLocation object*/ GeoLocation *geo() { return &m_Geo; } /** @return list of all geographic locations */ QList &getGeoList() { return geoList; } GeoLocation *locationNamed(const QString &city, const QString &province = QString(), const QString &country = QString()); /** * Set the GeoLocation according to the argument. * @param l reference to the new GeoLocation */ void setLocation(const GeoLocation &l); /** Set the GeoLocation according to the values stored in the configuration file. */ void setLocationFromOptions(); /** Return map for daylight saving rules. */ const QMap &getRulebook() const { return Rulebook; } /** @return whether the next Focus change will omit the slewing animation. */ bool snapNextFocus() const { return snapToFocus; } /** * Disable or re-enable the slewing animation for the next Focus change. * @note If the user has turned off all animated slewing, setSnapNextFocus(false) * will *NOT* enable animation on the next slew. A false argument would only * be used if you have previously called setSnapNextFocus(true), but then decided * you didn't want that after all. In other words, it's extremely unlikely you'd * ever want to use setSnapNextFocus(false). * @param b when true (the default), the next Focus change will omit the slewing * animation. */ void setSnapNextFocus(bool b = true) { snapToFocus = b; } /** * Execute a script. This function actually duplicates the DCOP functionality * for those cases when invoking DCOP is not practical (i.e., when preparing * a sky image in command-line dump mode). * @param name the filename of the script to "execute". * @param map pointer to the SkyMap object. * @return true if the script was successfully parsed. */ bool executeScript(const QString &name, SkyMap *map); /** Synchronize list of visible FOVs and list of selected FOVs in Options */ + #ifndef KSTARS_LITE void syncFOV(); + #endif /** * @return the list of visible FOVs */ inline const QList getVisibleFOVs() const { return visibleFOVs; } /** * @return the list of available FOVs */ inline const QList getAvailableFOVs() const { return availFOVs; } #ifndef KSTARS_LITE /** Return log object */ OAL::Log *logObject() { return m_LogObject.get(); } /** Return ADV Tree */ QList avdTree() { return ADVtreeList; } inline ObservingList *observingList() const { return m_ObservingList; } ImageExporter *imageExporter(); Execute *executeSession(); #endif /*@short Increments the updateID, forcing a recomputation of star positions as well */ unsigned int incUpdateID(); unsigned int updateID() const { return m_updateID; } unsigned int updateNumID() const { return m_updateNumID; } KSNumbers *updateNum() { return &m_updateNum; } void syncUpdateIDs(); signals: /** Signal that specifies the text that should be drawn in the KStarsSplash window. */ void progressText(const QString &text); /** Should be used to refresh skymap. */ void skyUpdate(bool); /** If data changed, emit clearCache signal. */ void clearCache(); /** Emitted when geo location changed */ void geoChanged(); public slots: /** @short send a message to the console*/ void slotConsoleMessage(QString s) { std::cout << (const char *)(s.toLocal8Bit()) << std::endl; } /** * Update the Simulation Clock. Update positions of Planets. Update * Alt/Az coordinates of objects. Update precession. * emit the skyUpdate() signal so that SkyMap / whatever draws the sky can update itself * * This is ugly. * It _will_ change! * (JH:)hey, it's much less ugly now...can we lose the comment yet? :p */ void updateTime(GeoLocation *geo, const bool automaticDSTchange = true); /** * Sets the direction of time and stores it in bool TimeRunForwards. If scale >= 0 * time is running forward else time runs backward. We need this to calculate just * one daylight saving change time (previous or next DST change). */ void setTimeDirection(float scale); private: /** * Populate list of geographic locations from "citydb.sqlite" database. Also check for custom * locations file "mycitydb.sqlite" database, but don't require it. Each line in the file * provides the information required to create one GeoLocation object. * @short Fill list of geographic locations from file(s) * @return true if at least one city read successfully. * @see KStarsData::processCity() */ bool readCityData(); /** Read the data file that contains daylight savings time rules. */ bool readTimeZoneRulebook(); //TODO JM: ADV tree should use XML instead /** * Read Advanced interface structure to be used later to construct the list view in * the advanced tab in the Detail Dialog. * @li KSLABEL designates a top-level parent label * @li KSINTERFACE designates a common URL interface for several objects * @li END designates the end of a sub tree structure * @short read online database lookup structure. * @return true if data is successfully read. */ bool readADVTreeData(); /** Read INDI hosts from an XML file */ bool readINDIHosts(); //TODO JM: Use XML instead; The logger should have more features // that allow users to enter details about their observation logs // objects observed, eye pieces, telescope, conditions, mag..etc /** * @short read user logs. * * Read user logs. The log file is formatted as following: * @li KSLABEL designates the beginning of a log * @li KSLogEnd designates the end of a log. * * @return true if data is successfully read. */ bool readUserLog(); /** * Read in URLs to be attached to a named object's right-click popup menu. At this * point, there is no way to attach URLs to unnamed objects. There are two * kinds of URLs, each with its own data file: image links and webpage links. In addition, * there may be user-specific versions with custom URLs. Each line contains 3 fields * separated by colons (":"). Note that the last field is the URL, and as such it will * generally contain a colon itself. Only the first two colons encountered are treated * as field separators. The fields are: * * @li Object name. This must be the "primary" name of the object (the name at the top of the popup menu). * @li Menu text. The string that should appear in the popup menu to activate the link. * @li URL. * @short Read in image and information URLs. * @return true if data files were successfully read. */ bool readURLData(const QString &url, int type = 0, bool deepOnly = false); /** * @short open a file containing URL links. * @param urlfile string representation of the filename to open * @param file reference to the QFile object which will be opened to this file. * @return true if file successfully opened. */ bool openUrlFile(const QString &urlfile, QFile &file); /** * Reset local time to new daylight saving time. Use this function if DST has changed. * Used by updateTime(). */ void resetToNewDST(GeoLocation *geo, const bool automaticDSTchange); QList ADVtreeList; std::unique_ptr m_SkyComposite; GeoLocation m_Geo; SimClock Clock; KStarsDateTime LTime; KSUserDB m_ksuserdb; CatalogDB m_catalogdb; ColorScheme CScheme; #ifndef KSTARS_LITE ObservingList* m_ObservingList { nullptr }; std::unique_ptr m_LogObject; std::unique_ptr m_Execute; std::unique_ptr m_ImageExporter; #endif //EquipmentWriter *m_equipmentWriter; bool TimeRunsForward { false }; bool temporaryTrail { false }; // FIXME: Used in SkyMap only. Check! bool snapToFocus { false }; //KLocale *locale; CachingDms LST; QKeySequence resumeKey; QList availFOVs; // List of all available FOVs QList visibleFOVs; // List of visible FOVs. Cached from Options::FOVNames KStarsDateTime LastNumUpdate, LastSkyUpdate, LastPlanetUpdate, LastMoonUpdate; KStarsDateTime NextDSTChange; // FIXME: Used in kstarsdcop.cpp only KStarsDateTime StoredDate; QList geoList; QMap Rulebook; quint32 m_preUpdateID, m_updateID; quint32 m_preUpdateNumID, m_updateNumID; KSNumbers m_preUpdateNum, m_updateNum; static KStarsData *pinstance; };