File indexing completed on 2024-04-14 14:11:51

0001 /*
0002     SPDX-FileCopyrightText: 2001 Heiko Evermann <heiko@evermann.de>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "colorscheme.h"
0010 #include "geolocation.h"
0011 #include "ksnumbers.h"
0012 #include "kstarsdatetime.h"
0013 #include "ksuserdb.h"
0014 #include "simclock.h"
0015 #include "skyobjectuserdata.h"
0016 #include <qobject.h>
0017 #ifndef KSTARS_LITE
0018 #include "oal/oal.h"
0019 #include "oal/log.h"
0020 #include "polyfills/qstring_hash.h"
0021 #endif
0022 
0023 #include <QList>
0024 #include <QMap>
0025 #include <QKeySequence>
0026 #include <QMutex>
0027 
0028 #include <iostream>
0029 #include <memory>
0030 #include <unordered_map>
0031 
0032 #define MINZOOM     250.
0033 #define MAXZOOM     5000000.
0034 #define DEFAULTZOOM 2000.
0035 #define DZOOM       1.189207115 // 2^(1/4)
0036 #define AU_KM       1.49605e8   //km in one AU
0037 
0038 class QFile;
0039 
0040 class Execute;
0041 class FOV;
0042 class ImageExporter;
0043 class SkyMap;
0044 class SkyMapComposite;
0045 class SkyObject;
0046 class ObservingList;
0047 class TimeZoneRule;
0048 
0049 #ifdef KSTARS_LITE
0050 //Will go away when details window will be implemented in KStars Lite
0051 struct ADVTreeData
0052 {
0053     QString Name;
0054     QString Link;
0055     int Type;
0056 };
0057 #else
0058 struct ADVTreeData;
0059 #endif
0060 
0061 /**
0062  * @class KStarsData
0063  * KStarsData is the backbone of KStars.  It contains all the data used by KStars,
0064  * including the SkyMapComposite that contains all items in the skymap
0065  * (stars, deep-sky objects, planets, constellations, etc).  Other kinds of data
0066  * are stored here as well: the geographic locations, the timezone rules, etc.
0067  *
0068  * @author Heiko Evermann
0069  * @version 1.0
0070  */
0071 class KStarsData : public QObject
0072 {
0073         Q_OBJECT
0074 
0075     protected:
0076         /** Constructor. */
0077         KStarsData();
0078 
0079     public:
0080         // FIXME: It uses temporary trail. There must be way to
0081         //        this better. And resumeKey in DBUS code
0082         friend class KStars;
0083         // FIXME: it uses temporary trail and resumeKey
0084         friend class SkyMap;
0085         // FIXME: uses geoList and changes it.
0086         friend class LocationDialog;
0087         friend class LocationDialogLite;
0088 
0089         static KStarsData *Create();
0090 
0091         static inline KStarsData *Instance()
0092         {
0093             return pinstance;
0094         }
0095 
0096         /**
0097          * Initialize KStarsData while running splash screen.
0098          * @return true on success.
0099          */
0100         bool initialize();
0101 
0102         /** Destructor.  Delete data objects. */
0103         ~KStarsData() override;
0104 
0105         /**
0106          * Set the NextDSTChange member.
0107          *  Need this accessor because I could not make KStars::privatedata a friend
0108          *  class for some reason...:/
0109          */
0110         void setNextDSTChange(const KStarsDateTime &dt)
0111         {
0112             NextDSTChange = dt;
0113         }
0114 
0115         /**
0116          * Returns true if time is running forward else false. Used by KStars to prevent
0117          *  double calculations of daylight saving change time.
0118          */
0119         bool isTimeRunningForward() const
0120         {
0121             return TimeRunsForward;
0122         }
0123 
0124         /** @return pointer to the localization (KLocale) object */
0125         //KLocale *getLocale() { return locale; }
0126 
0127         /**
0128          * @short Find object by name.
0129          * @param name Object name to find
0130          * @return pointer to SkyObject matching this name
0131          */
0132         SkyObject *objectNamed(const QString &name);
0133 
0134         /**
0135          * The Sky is updated more frequently than the moon, which is updated more frequently
0136          * than the planets.  The date of the last update for each category is recorded so we
0137          * know when we need to do it again (see KStars::updateTime()).
0138          * Initializing these to -1000000.0 ensures they will be updated immediately
0139          * on the first call to KStars::updateTime().
0140          */
0141         void setFullTimeUpdate();
0142 
0143         /**
0144          * Change the current simulation date/time to the KStarsDateTime argument.
0145          * Specified DateTime is always universal time.
0146          * @param newDate the DateTime to set.
0147          */
0148         void changeDateTime(const KStarsDateTime &newDate);
0149 
0150         /** @return pointer to the current simulation local time */
0151         const KStarsDateTime &lt() const
0152         {
0153             return LTime;
0154         }
0155 
0156         /** @return reference to the current simulation universal time */
0157         const KStarsDateTime &ut() const
0158         {
0159             return Clock.utc();
0160         }
0161 
0162         /** Sync the LST with the simulation clock. */
0163         void syncLST();
0164 
0165         /** @return pointer to SkyComposite */
0166         SkyMapComposite *skyComposite()
0167         {
0168             return m_SkyComposite.get();
0169         }
0170 
0171         /** @return pointer to the ColorScheme object */
0172         ColorScheme *colorScheme()
0173         {
0174             return &CScheme;
0175         }
0176 
0177         /** @return file name of current color scheme **/
0178         Q_INVOKABLE QString colorSchemeFileName() { return CScheme.fileName(); }
0179 
0180         /** @return file name of the color scheme with the name \p name **/
0181         QString colorSchemeFileName(const QString &name)
0182         {
0183             return m_color_schemes.count(name) > 0 ? m_color_schemes.at(name) : "";
0184         }
0185 
0186         /** @return file name of the current color scheme **/
0187         Q_INVOKABLE QString colorSchemeName()
0188         {
0189             return colorSchemeName(CScheme.fileName());
0190         }
0191 
0192         /** @return the name of the color scheme with the name \p name **/
0193         QString colorSchemeName(const QString &fileName)
0194         {
0195             return m_color_scheme_names.count(fileName) > 0 ? m_color_scheme_names.at(fileName) : "";
0196         }
0197 
0198         /** @return if the color scheme with the name or filename \p scheme is loaded **/
0199         bool hasColorScheme(const QString &scheme)
0200         {
0201             return m_color_scheme_names.count(scheme) || m_color_schemes.count(scheme);
0202         }
0203 
0204         /** Register a color scheme with \p filename and \p name. */
0205         void add_color_scheme(const QString &filename, const QString &name)
0206         {
0207             m_color_schemes[name] = filename;
0208             m_color_scheme_names[filename] = name;
0209         };
0210 
0211         /** \return a map of color scheme names and filenames */
0212         const std::map<QString, QString> color_schemes() { return m_color_schemes; };
0213 
0214         /** @return pointer to the KSUserDB object */
0215         KSUserDB *userdb() { return &m_ksuserdb; }
0216 
0217         /** @return pointer to the simulation Clock object */
0218         Q_INVOKABLE SimClock *clock()
0219         {
0220             return &Clock;
0221         }
0222 
0223         /** @return pointer to the local sidereal time: a dms object */
0224         CachingDms *lst()
0225         {
0226             return &LST;
0227         }
0228 
0229         /** @return pointer to the GeoLocation object*/
0230         GeoLocation *geo()
0231         {
0232             return &m_Geo;
0233         }
0234 
0235         /** @return list of all geographic locations */
0236         QList<GeoLocation *> &getGeoList()
0237         {
0238             return geoList;
0239         }
0240 
0241         GeoLocation *locationNamed(const QString &city, const QString &province = QString(),
0242                                    const QString &country = QString());
0243 
0244         /**
0245          * @brief nearestLocation Return nearest location to the given longitude and latitude coordinates
0246          * @param longitude Longitude (-180 to +180)
0247          * @param latitude Latitude (-90 to +90)
0248          * @return nearest geographical location to the parameters above.
0249          */
0250         GeoLocation *nearestLocation(double longitude, double latitude);
0251 
0252         /**
0253          * Set the GeoLocation according to the argument.
0254          * @param l reference to the new GeoLocation
0255          */
0256         void setLocation(const GeoLocation &l);
0257 
0258         /** Set the GeoLocation according to the values stored in the configuration file. */
0259         void setLocationFromOptions();
0260 
0261         /** Return map for daylight saving rules. */
0262         const QMap<QString, TimeZoneRule> &getRulebook() const
0263         {
0264             return Rulebook;
0265         }
0266 
0267         /** @return whether the next Focus change will omit the slewing animation. */
0268         bool snapNextFocus() const
0269         {
0270             return snapToFocus;
0271         }
0272 
0273         /**
0274          * Disable or re-enable the slewing animation for the next Focus change.
0275          * @note If the user has turned off all animated slewing, setSnapNextFocus(false)
0276          * will *NOT* enable animation on the next slew.  A false argument would only
0277          * be used if you have previously called setSnapNextFocus(true), but then decided
0278          * you didn't want that after all.  In other words, it's extremely unlikely you'd
0279          * ever want to use setSnapNextFocus(false).
0280          * @param b when true (the default), the next Focus change will omit the slewing
0281          * animation.
0282          */
0283         void setSnapNextFocus(bool b = true)
0284         {
0285             snapToFocus = b;
0286         }
0287 
0288         /**
0289          * Execute a script.  This function actually duplicates the DCOP functionality
0290          * for those cases when invoking DCOP is not practical (i.e., when preparing
0291          * a sky image in command-line dump mode).
0292          * @param name the filename of the script to "execute".
0293          * @param map pointer to the SkyMap object.
0294          * @return true if the script was successfully parsed.
0295          */
0296         bool executeScript(const QString &name, SkyMap *map);
0297 
0298         /** Synchronize list of visible FOVs and list of selected FOVs in Options */
0299 #ifndef KSTARS_LITE
0300         void syncFOV();
0301 #endif
0302 
0303         /**
0304          * @return the list of visible FOVs
0305          */
0306         inline const QList<FOV *> getVisibleFOVs() const
0307         {
0308             return visibleFOVs;
0309         }
0310 
0311         /**
0312          * @return the list of available FOVs
0313          */
0314         inline const QList<FOV *> getAvailableFOVs() const
0315         {
0316             return availFOVs;
0317         }
0318 
0319         /**
0320          * @brief addTransientFOV Adds a new FOV to the list.
0321          * @param newFOV pointer to FOV object.
0322          */
0323         inline void addTransientFOV(std::shared_ptr<FOV> newFOV)
0324         {
0325             transientFOVs.append(newFOV);
0326         }
0327         inline void clearTransientFOVs()
0328         {
0329             transientFOVs.clear();
0330         }
0331 
0332         /**
0333          * @return the list of transient FOVs
0334          */
0335         inline const QList<std::shared_ptr<FOV>> getTransientFOVs() const
0336         {
0337             return transientFOVs;
0338         }
0339 #ifndef KSTARS_LITE
0340         /** Return log object */
0341         OAL::Log *logObject()
0342         {
0343             return m_LogObject.get();
0344         }
0345 
0346         /** Return ADV Tree */
0347         QList<ADVTreeData *> avdTree()
0348         {
0349             return ADVtreeList;
0350         }
0351 
0352         inline ObservingList *observingList() const
0353         {
0354             return m_ObservingList;
0355         }
0356 
0357         ImageExporter *imageExporter();
0358 
0359         Execute *executeSession();
0360 #endif
0361         /*@short Increments the updateID, forcing a recomputation of star positions as well */
0362         unsigned int incUpdateID();
0363 
0364         unsigned int updateID() const
0365         {
0366             return m_updateID;
0367         }
0368         unsigned int updateNumID() const
0369         {
0370             return m_updateNumID;
0371         }
0372         KSNumbers *updateNum()
0373         {
0374             return &m_updateNum;
0375         }
0376         void syncUpdateIDs();
0377 
0378     signals:
0379         /** Signal that specifies the text that should be drawn in the KStarsSplash window. */
0380         void progressText(const QString &text);
0381 
0382         /** Should be used to refresh skymap. */
0383         void skyUpdate(bool);
0384 
0385         /** If data changed, emit clearCache signal. */
0386         void clearCache();
0387 
0388         /** Emitted when geo location changed */
0389         void geoChanged();
0390 
0391     public slots:
0392         /** @short send a message to the console*/
0393         void slotConsoleMessage(QString s)
0394         {
0395             std::cout << (const char *)(s.toLocal8Bit()) << std::endl;
0396         }
0397 
0398         /**
0399          * Update the Simulation Clock.  Update positions of Planets.  Update
0400          * Alt/Az coordinates of objects.  Update precession.
0401          * emit the skyUpdate() signal so that SkyMap / whatever draws the sky can update itself
0402          *
0403          * This is ugly.
0404          * It _will_ change!
0405          * (JH:)hey, it's much less ugly now...can we lose the comment yet? :p
0406          */
0407         void updateTime(GeoLocation *geo, const bool automaticDSTchange = true);
0408 
0409         /**
0410          * Sets the direction of time and stores it in bool TimeRunForwards. If scale >= 0
0411          * time is running forward else time runs backward. We need this to calculate just
0412          * one daylight saving change time (previous or next DST change).
0413          */
0414         void setTimeDirection(float scale);
0415 
0416         // What follows is mostly a port of Arkashs auxdata stuff to a
0417         // more centralized approach that does not store the data in
0418         // the skyobjects as they are ephemeral in the new DSO implementation
0419         //
0420         // I've tried to reuse as much code as possible and maintain
0421         // compatibility with peoples data.
0422         //
0423         // -- Valentin Boettcher
0424 
0425         /**
0426          * Get a reference to the user data of an object with the name \p name.
0427          */
0428         const SkyObjectUserdata::Data &getUserData(const QString &name);
0429 
0430         /**
0431          * Adds a link \p data to the user data for the object with \p
0432          * name, both in memory and on disk.
0433          *
0434          * @returns {success, error_message}
0435          */
0436         std::pair<bool, QString> addToUserData(const QString &name,
0437                                                const SkyObjectUserdata::LinkData &data);
0438 
0439         /**
0440          * Replace \p data in the user data at \p index for the object with \p
0441          * name, both in memory and on disk.
0442          *
0443          * @returns {success, error_message}
0444          */
0445         std::pair<bool, QString> editUserData(const QString &name,
0446                                               const unsigned int index,
0447                                               const SkyObjectUserdata::LinkData &data);
0448 
0449         /**
0450          * Remove data of \p type from the user data at \p index for
0451          * the object with \p name, both in memory and on disk.
0452          *
0453          * @returns {success, error_message}
0454          */
0455         std::pair<bool, QString> deleteUserData(const QString &name,
0456                                                 const unsigned int index,
0457                                                 SkyObjectUserdata::Type type);
0458         /**
0459          * Update the user log of the object with the \p name to
0460          * contain \p newLog (find and replace).
0461          *
0462          * @returns {success, error_message}
0463          */
0464         std::pair<bool, QString> updateUserLog(const QString &name,
0465                                                const QString &newLog);
0466 
0467       private:
0468         /**
0469          * Populate list of geographic locations from "citydb.sqlite" database. Also check for custom
0470          * locations file "mycitydb.sqlite" database, but don't require it.  Each line in the file
0471          * provides the information required to create one GeoLocation object.
0472          * @short Fill list of geographic locations from file(s)
0473          * @return true if at least one city read successfully.
0474          * @see KStarsData::processCity()
0475          */
0476         bool readCityData();
0477 
0478         /** Read the data file that contains daylight savings time rules. */
0479         bool readTimeZoneRulebook();
0480 
0481         //TODO JM: ADV tree should use XML instead
0482         /**
0483          * Read Advanced interface structure to be used later to construct the list view in
0484          * the advanced tab in the Detail Dialog.
0485          * @li KSLABEL designates a top-level parent label
0486          * @li KSINTERFACE designates a common URL interface for several objects
0487          * @li END designates the end of a sub tree structure
0488          * @short read online database lookup structure.
0489          * @return true if data is successfully read.
0490          */
0491         bool readADVTreeData();
0492 
0493         /** Read INDI hosts from an XML file */
0494         bool readINDIHosts();
0495 
0496         //TODO JM: Use XML instead; The logger should have more features
0497         // that allow users to enter details about their observation logs
0498         // objects observed, eye pieces, telescope, conditions, mag..etc
0499         /**
0500          * @short read user logs.
0501          *
0502          * Read user logs. The log file is formatted as following:
0503          * @li KSLABEL designates the beginning of a log
0504          * @li KSLogEnd designates the end of a log.
0505          *
0506          * @return true if data is successfully read.
0507          */
0508         bool readUserLog();
0509 
0510         /**
0511          * Read in URLs to be attached to a named object's right-click popup menu.  At this
0512          * point, there is no way to attach URLs to unnamed objects.  There are two
0513          * kinds of URLs, each with its own data file: image links and webpage links.  In addition,
0514          * there may be user-specific versions with custom URLs.  Each line contains 3 fields
0515          * separated by colons (":").  Note that the last field is the URL, and as such it will
0516          * generally contain a colon itself.  Only the first two colons encountered are treated
0517          * as field separators.  The fields are:
0518          *
0519          * @li Object name.  This must be the "primary" name of the object (the name at the top of the popup menu).
0520          * @li Menu text.  The string that should appear in the popup menu to activate the link.
0521          * @li URL.
0522          * @short Read in image and information URLs.
0523          * @return true if data files were successfully read.
0524          */
0525         bool readURLData(const QString &url,
0526                          SkyObjectUserdata::Type type = SkyObjectUserdata::Type::website);
0527 
0528         /**
0529          * @short open a file containing URL links.
0530          * @param urlfile string representation of the filename to open
0531          * @param file reference to the QFile object which will be opened to this file.
0532          * @return true if file successfully opened.
0533          */
0534         bool openUrlFile(const QString &urlfile, QFile &file);
0535 
0536         /**
0537          * Reset local time to new daylight saving time. Use this function if DST has changed.
0538          * Used by updateTime().
0539          */
0540         void resetToNewDST(GeoLocation *geo, const bool automaticDSTchange);
0541 
0542         /**
0543          * As KStarsData::getUserData just non-const.
0544          * @warning This method is not thread safe :) so take care of that when you use it.
0545          */
0546         SkyObjectUserdata::Data &findUserData(const QString &name);
0547 
0548         QList<ADVTreeData *> ADVtreeList;
0549         std::unique_ptr<SkyMapComposite> m_SkyComposite;
0550 
0551         GeoLocation m_Geo;
0552         SimClock Clock;
0553         KStarsDateTime LTime;
0554         KSUserDB m_ksuserdb;
0555         ColorScheme CScheme;
0556         std::map<QString, QString> m_color_schemes; // name: filename
0557         std::map<QString, QString> m_color_scheme_names; // filename: name
0558 
0559 #ifndef KSTARS_LITE
0560         ObservingList* m_ObservingList { nullptr };
0561         std::unique_ptr<OAL::Log> m_LogObject;
0562         std::unique_ptr<Execute> m_Execute;
0563         std::unique_ptr<ImageExporter> m_ImageExporter;
0564 #endif
0565 
0566         //EquipmentWriter *m_equipmentWriter;
0567 
0568         bool TimeRunsForward { false };
0569         bool temporaryTrail { false };
0570         // FIXME: Used in SkyMap only. Check!
0571         bool snapToFocus { false };
0572 
0573         //KLocale *locale;
0574 
0575         CachingDms LST;
0576 
0577         QKeySequence resumeKey;
0578 
0579         QList<FOV *> availFOVs;         // List of all available FOVs
0580         QList<FOV *> visibleFOVs;       // List of visible FOVs. Cached from Options::FOVNames
0581         QList<std::shared_ptr<FOV>> transientFOVs;     // List of non-permenant transient FOVs.
0582 
0583         KStarsDateTime LastNumUpdate, LastSkyUpdate, LastPlanetUpdate, LastMoonUpdate;
0584         KStarsDateTime NextDSTChange;
0585         // FIXME: Used in kstarsdcop.cpp only
0586         KStarsDateTime StoredDate;
0587 
0588         QList<GeoLocation *> geoList;
0589         QMap<QString, TimeZoneRule> Rulebook;
0590 
0591         quint32 m_preUpdateID, m_updateID;
0592         quint32 m_preUpdateNumID, m_updateNumID;
0593         KSNumbers m_preUpdateNum, m_updateNum;
0594 
0595         static KStarsData *pinstance;
0596 
0597         std::unordered_map<QString, SkyObjectUserdata::Data> m_user_data;
0598         QMutex m_user_data_mutex; // for m_user_data
0599 };