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édéric Boquien"), QString(), 0152 "mboquien@free.fr"); 0153 aboutData.addAuthor(i18n("Jérô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 }