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

0001 /*
0002     SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "ksnumbers.h"
0008 #include "kspaths.h"
0009 #include "kstars_debug.h"
0010 #include "kstarsdata.h"
0011 #include "ksnotification.h"
0012 #include "kstarsdatetime.h"
0013 #include "catalogsdb.h"
0014 #if defined(KSTARS_LITE)
0015 #include "kstarslite.h"
0016 #endif
0017 #include "ksutils.h"
0018 #include "Options.h"
0019 #include "simclock.h"
0020 #include "version.h"
0021 #if !defined(KSTARS_LITE)
0022 #include "kstars.h"
0023 #include "skymap.h"
0024 #endif
0025 
0026 #if !defined(KSTARS_LITE)
0027 #include <KAboutData>
0028 #include <KCrash>
0029 #endif
0030 #include <KLocalizedString>
0031 
0032 #include <QApplication>
0033 #if !defined(KSTARS_LITE)
0034 #include <QCommandLineParser>
0035 #include <QCommandLineOption>
0036 #endif
0037 #include <QDebug>
0038 #include <QPixmap>
0039 #include <QScreen>
0040 #include <QtGlobal>
0041 #include <QTranslator>
0042 
0043 #if defined(Q_OS_LINUX) || defined(Q_OS_OSX)
0044 #include <signal.h>
0045 #endif
0046 
0047 #ifndef KSTARS_LITE
0048 static const char description[] = I18N_NOOP("Desktop Planetarium");
0049 static const char notice[]      = I18N_NOOP(
0050                                       "Some images in KStars are for non-commercial use only. See README.images.");
0051 #endif
0052 
0053 #if defined(Q_OS_ANDROID)
0054 // __attribute__ is needed because clang-based linking removes the main() symbol from the shared library on Android
0055 Q_DECL_EXPORT
0056 #endif
0057 int main(int argc, char *argv[])
0058 {
0059 #if defined(Q_OS_LINUX) || defined(Q_OS_OSX)
0060     // Ignore SIGPIPE
0061     signal(SIGPIPE, SIG_IGN);
0062 #endif
0063 
0064     QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
0065 
0066     QApplication app(argc, argv);
0067 
0068 #ifdef Q_OS_OSX
0069     //Note, this function will return true on OS X if the data directories are good to go.  If not, quit with error code 1!
0070     if (!KSUtils::setupMacKStarsIfNeeded())
0071     {
0072         KSNotification::sorry(i18n("Sorry, without a KStars Data Directory, KStars "
0073                                    "cannot operate. Exiting program now."));
0074         return 1;
0075     }
0076 #endif
0077     Options::setKStarsFirstRun(false);
0078     app.setApplicationVersion(KSTARS_VERSION);
0079     /**
0080     * enable high dpi support
0081     */
0082     app.setAttribute(Qt::AA_UseHighDpiPixmaps, true);
0083 
0084     KLocalizedString::setApplicationDomain("kstars");
0085 #if defined(KSTARS_LITE)
0086 #if defined(__ANDROID__)
0087     KLocalizedString::addDomainLocaleDir(
0088         "kstars", "/data/data/org.kde.kstars.lite/qt-reserved-files/share/kstars/locale");
0089 #else
0090     KLocalizedString::addDomainLocaleDir("kstars", "locale");
0091 #endif
0092 #endif
0093 
0094 #ifndef KSTARS_LITE
0095 
0096     // Create writable data dir if it does not exist
0097     QDir writableDir;
0098     writableDir.mkdir(KSPaths::writableLocation(QStandardPaths::GenericDataLocation));
0099     writableDir.mkdir(KSPaths::writableLocation(QStandardPaths::TempLocation));
0100 
0101     KCrash::initialize();
0102     QString versionString =
0103         QString("%1 %2").arg(KSTARS_VERSION).arg(KSTARS_BUILD_RELEASE);
0104     KAboutData aboutData(
0105         "kstars", i18n("KStars"), versionString, i18n(description), KAboutLicense::GPL,
0106         "2001-" + QString::number(QDate::currentDate().year()) +
0107         i18n(" (c), The KStars Team\n\nThe Gaussian Process Guider Algorithm: (c) "
0108              "2014-2017 Max Planck Society"),
0109         i18nc("Build number followed by copyright notice", "Build: %1\n\n%2\n\n%3",
0110               KSTARS_BUILD_TS,
0111               KSTARS_BUILD_RELEASE == QLatin1String("Beta") ?
0112               "Pre-release beta snapshot. Do not use in production." :
0113               "Stable release.",
0114               i18n(notice)),
0115         "https://edu.kde.org/kstars");
0116     aboutData.addAuthor(i18n("Jason Harris"), i18n("Original Author"),
0117                         "jharris@30doradus.org", "http://www.30doradus.org");
0118     aboutData.addAuthor(i18n("Jasem Mutlaq"), i18n("Current Maintainer"),
0119                         "mutlaqja@ikarustech.com", "https://www.indilib.org");
0120 
0121     // Active developers
0122     aboutData.addAuthor(i18n("Akarsh Simha"), QString(), "akarsh@kde.org",
0123                         "http://www.ph.utexas.edu/~asimha");
0124     aboutData.addAuthor(i18n("Robert Lancaster"),
0125                         i18n("FITSViewer & Ekos Improvements. KStars OSX Port"),
0126                         "rlancaste@gmail.com");
0127     aboutData.addAuthor(i18n("Eric Dejouhanet"), QString(), "eric.dejouhanet@gmail.com",
0128                         i18n("Ekos Scheduler Improvements"));
0129     aboutData.addAuthor(i18n("Wolfgang Reissenberger"), QString(),
0130                         "sterne-jaeger@t-online.de",
0131                         i18n("Ekos Scheduler & Observatory Improvements"));
0132     aboutData.addAuthor(i18n("Hy Murveit"), QString(), "murveit@gmail.com",
0133                         i18n("FITS, Focus, Guide Improvements"));
0134     aboutData.addAuthor(i18n("John Evans"), QString(), "john.e.evans.email@gmail.com",
0135                         i18n("Focus algorithms"));
0136 
0137     // Inactive developers
0138     aboutData.addAuthor(i18n("Csaba Kertesz"), QString(), "csaba.kertesz@gmail.com", "");
0139     aboutData.addAuthor("Valentin Boettcher", QString(), "hiro@protagon.space",
0140                         i18n("Binary Asteroid List, DSO Database & Catalogs"));
0141     aboutData.addAuthor(i18n("Artem Fedoskin"), i18n("KStars Lite"),
0142                         "afedoskin3@gmail.com");
0143     aboutData.addAuthor(i18n("James Bowlin"), QString(), "bowlin@mindspring.com");
0144     aboutData.addAuthor(i18n("Pablo de Vicente"), QString(), "pvicentea@wanadoo.es");
0145     aboutData.addAuthor(i18n("Thomas Kabelmann"), QString(), "tk78@gmx.de");
0146     aboutData.addAuthor(i18n("Heiko Evermann"), QString(), "heiko@evermann.de",
0147                         "https://www.evermann.de");
0148     aboutData.addAuthor(i18n("Carsten Niehaus"), QString(), "cniehaus@gmx.de");
0149     aboutData.addAuthor(i18n("Mark Hollomon"), QString(), "mhh@mindspring.com");
0150     aboutData.addAuthor(i18n("Alexey Khudyakov"), QString(), "alexey.skladnoy@gmail.com");
0151     aboutData.addAuthor(i18n("M&eacute;d&eacute;ric Boquien"), QString(),
0152                         "mboquien@free.fr");
0153     aboutData.addAuthor(i18n("J&eacute;r&ocirc;me Sonrier"), QString(),
0154                         "jsid@emor3j.fr.eu.org");
0155     aboutData.addAuthor(i18n("Prakash Mohan"), QString(), "prakash.mohan@kdemail.net");
0156     aboutData.addAuthor(i18n("Victor Cărbune"), QString(), "victor.carbune@kdemail.net");
0157     aboutData.addAuthor(i18n("Henry de Valence"), QString(), "hdevalence@gmail.com");
0158     aboutData.addAuthor(i18n("Samikshan Bairagya"), QString(),
0159                         "samikshan.bairagya@kdemail.net");
0160     aboutData.addAuthor(i18n("Rafał Kułaga"), QString(), "rl.kulaga@gmail.com");
0161     aboutData.addAuthor(i18n("Rishab Arora"), QString(), "ra.rishab@gmail.com");
0162 
0163     // Contributors
0164     aboutData.addCredit(
0165         i18n("Valery Kharitonov"),
0166         i18n("Converted labels containing technical terms to links to documentation"));
0167     aboutData.addCredit(i18n("Ana-Maria Constantin"),
0168                         i18n("Technical documentation on Astronomy and KStars"));
0169     aboutData.addCredit(i18n("Andrew Stepanenko"),
0170                         i18n("Guiding code based on lin_guider"));
0171     aboutData.addCredit(i18n("Nuno Pinheiro"), i18n("Artwork"));
0172     aboutData.addCredit(
0173         i18n("Utkarsh Simha"),
0174         i18n("Improvements to observation plan execution, star hopper etc."));
0175     aboutData.addCredit(i18n("Daniel Holler"),
0176                         i18n("Extensive testing and suggestions for Ekos/INDI."));
0177     aboutData.addCredit(
0178         i18n("Stephane Lucas"),
0179         i18n("Extensive testing and suggestions for Ekos Scheduler. KStars OSX Port"));
0180     aboutData.addCredit(i18n("Yuri Fabirovsky"),
0181                         i18n("Splash screen for both regular KStars and KStars Lite."));
0182     aboutData.addCredit(i18n("Jamie Smith"), i18n("KStars OSX Port."));
0183     aboutData.addCredit(i18n("Patrick Molenaar"), i18n("Bahtinov Focus Assistant."));
0184     aboutData.addCredit(i18n("Philipp Auersperg-Castell"), i18n("Supernovae daily updates"));
0185     aboutData.addCredit(i18n("Tony Schriber"), i18n("Rotator Dialog improvements"));
0186     aboutData.addCredit(i18n("Joseph McGee"), i18n("Sub-exposure calculator based on Dr Robin Glover's work"));
0187 
0188     KAboutData::setApplicationData(aboutData);
0189 
0190     QCommandLineParser parser;
0191     aboutData.setupCommandLine(&parser);
0192     parser.setApplicationDescription(aboutData.shortDescription());
0193 
0194     //parser.addHelpOption(INSERT_DESCRIPTION_HERE);
0195     parser.addOption(QCommandLineOption("dump", i18n("Dump sky image to file."), "file"));
0196     parser.addOption(QCommandLineOption("script", i18n("Script to execute."), "file"));
0197     parser.addOption(QCommandLineOption("width", i18n("Width of sky image."), "value"));
0198     parser.addOption(QCommandLineOption("height", i18n("Height of sky image."), "value"));
0199     parser.addOption(QCommandLineOption("date", i18n("Date and time."), "string"));
0200     parser.addOption(QCommandLineOption("paused", i18n("Start with clock paused.")));
0201 
0202     // urls to open
0203     parser.addPositionalArgument(QStringLiteral("urls"), i18n("FITS file(s) to open."),
0204                                  QStringLiteral("[urls...]"));
0205 
0206     parser.process(app);
0207     aboutData.processCommandLine(&parser);
0208 
0209     if (parser.isSet("dump"))
0210     {
0211         qCDebug(KSTARS) << "Dumping sky image";
0212 
0213         //parse filename and image format
0214         const char *format = "PNG";
0215         QString fname      = parser.value("dump");
0216         QString ext        = fname.mid(fname.lastIndexOf(".") + 1);
0217         if (ext.toLower() == "png")
0218         {
0219             format = "PNG";
0220         }
0221         else if (ext.toLower() == "jpg" || ext.toLower() == "jpeg")
0222         {
0223             format = "JPG";
0224         }
0225         else if (ext.toLower() == "gif")
0226         {
0227             format = "GIF";
0228         }
0229         else if (ext.toLower() == "pnm")
0230         {
0231             format = "PNM";
0232         }
0233         else if (ext.toLower() == "bmp")
0234         {
0235             format = "BMP";
0236         }
0237         else
0238         {
0239             qCWarning(KSTARS) << i18n("Could not parse image format of %1; assuming PNG.",
0240                                       fname);
0241         }
0242 
0243         //parse width and height
0244         bool ok(false);
0245         int w(0), h(0);
0246         w = parser.value("width").toInt(&ok);
0247         if (ok)
0248             h = parser.value("height").toInt(&ok);
0249         if (!ok)
0250         {
0251             qCWarning(KSTARS) << "Unable to parse arguments Width: "
0252                               << parser.value("width")
0253                               << "  Height: " << parser.value("height");
0254             return 1;
0255         }
0256 
0257         KStarsData *dat = KStarsData::Create();
0258         QObject::connect(dat, SIGNAL(progressText(QString)), dat,
0259                          SLOT(slotConsoleMessage(QString)));
0260         dat->initialize();
0261 
0262         //Set Geographic Location
0263         dat->setLocationFromOptions();
0264 
0265         //Set color scheme
0266         dat->colorScheme()->loadFromConfig();
0267 
0268         //set clock now that we have a location:
0269         //Check to see if user provided a date/time string.  If not, use current CPU time
0270         QString datestring = parser.value("date");
0271         KStarsDateTime kdt;
0272         if (!datestring.isEmpty())
0273         {
0274             if (datestring.contains("-")) //assume ISODate format
0275             {
0276                 if (datestring.contains(":")) //also includes time
0277                 {
0278                     //kdt = QDateTime::fromString( datestring, QDateTime::ISODate );
0279                     kdt = KStarsDateTime(QDateTime::fromString(datestring, Qt::ISODate));
0280                 }
0281                 else //string probably contains date only
0282                 {
0283                     //kdt.setDate( QDate::fromString( datestring, Qt::ISODate ) );
0284                     kdt.setDate(QDate::fromString(datestring, Qt::ISODate));
0285                     kdt.setTime(QTime(0, 0, 0));
0286                 }
0287             }
0288             else //assume Text format for date string
0289             {
0290                 kdt = dat->geo()->LTtoUT(
0291                           KStarsDateTime(QDateTime::fromString(datestring, Qt::TextDate)));
0292             }
0293 
0294             if (!kdt.isValid())
0295             {
0296                 qCWarning(KSTARS) << i18n(
0297                                       "Supplied date string is invalid: %1. Using CPU date/time instead.",
0298                                       datestring);
0299 
0300                 kdt = KStarsDateTime::currentDateTimeUtc();
0301             }
0302         }
0303         else
0304         {
0305             kdt = KStarsDateTime::currentDateTimeUtc();
0306         }
0307         dat->clock()->setUTC(kdt);
0308 
0309         SkyMap *map = SkyMap::Create();
0310         map->resize(w, h);
0311         QPixmap sky(w, h);
0312 
0313         dat->setFullTimeUpdate();
0314         dat->updateTime(dat->geo(), map != nullptr);
0315 
0316         SkyPoint dest(Options::focusRA(), Options::focusDec());
0317         map->setDestination(dest);
0318         map->destination()->EquatorialToHorizontal(dat->lst(), dat->geo()->lat());
0319         map->setFocus(map->destination());
0320         map->focus()->EquatorialToHorizontal(dat->lst(), dat->geo()->lat());
0321 
0322         //Execute the specified script
0323         QString scriptfile = parser.value("script");
0324         if (!scriptfile.isEmpty())
0325         {
0326             if (dat->executeScript(scriptfile, map))
0327             {
0328                 std::cout << i18n("Script executed.").toUtf8().data() << std::endl;
0329             }
0330             else
0331             {
0332                 qCWarning(KSTARS) << i18n("Could not execute script.");
0333             }
0334         }
0335 
0336         qApp->processEvents();
0337         map->setupProjector();
0338         map->exportSkyImage(&sky);
0339         qApp->processEvents();
0340 
0341         if (!sky.save(fname, format))
0342             qCWarning(KSTARS) << "Unable to save image: " << fname;
0343         else
0344             qCDebug(KSTARS) << "Saved to file: %1" << fname;
0345 
0346         delete map;
0347         //delete dat;
0348         return 0;
0349     }
0350 
0351     //Try to parse the given date string
0352     QString datestring = parser.value("date");
0353 
0354     if (!datestring.isEmpty() && !KStarsDateTime::fromString(datestring).isValid())
0355     {
0356         qWarning() << i18n("Using CPU date/time instead.");
0357         datestring.clear();
0358     }
0359 
0360 #endif
0361 
0362     // Create writable data dir if it does not exist
0363     QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).mkpath(".");
0364     QDir(KSPaths::writableLocation(QStandardPaths::AppConfigLocation)).mkpath(".");
0365     QDir(KSPaths::writableLocation(QStandardPaths::CacheLocation)).mkpath(".");
0366     QDir(KSPaths::writableLocation(QStandardPaths::TempLocation)).mkpath(qAppName());
0367 
0368 #ifndef KSTARS_LITE
0369     KStars::createInstance(true, !parser.isSet("paused"), datestring);
0370 
0371     // no session.. just start up normally
0372     const QStringList urls = parser.positionalArguments();
0373 
0374     // take arguments
0375     if (!urls.isEmpty())
0376     {
0377         foreach (const QString &url, urls)
0378         {
0379             const QUrl u = QUrl::fromUserInput(url, QDir::currentPath());
0380 
0381             KStars::Instance()->openFITS(u);
0382         }
0383     }
0384     QObject::connect(qApp, SIGNAL(lastWindowClosed()), qApp, SLOT(quit()));
0385 
0386     app.exec();
0387 #else
0388     KStarsLite::createInstance(true);
0389 
0390     app.exec();
0391 #endif
0392     return 0;
0393 }