File indexing completed on 2024-04-21 14:47:05
0001 /* 0002 SPDX-FileCopyrightText: 2001 Jason Harris <jharris@30doradus.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kstars.h" 0008 0009 #include "config-kstars.h" 0010 #include "version.h" 0011 0012 #include "fov.h" 0013 #include "kactionmenu.h" 0014 #include "kstarsadaptor.h" 0015 #include "kstarsdata.h" 0016 #include "kstarssplash.h" 0017 #include "observinglist.h" 0018 #include "Options.h" 0019 #include "skymap.h" 0020 #include "skyqpainter.h" 0021 #include "texturemanager.h" 0022 #include "dialogs/finddialog.h" 0023 #include "dialogs/exportimagedialog.h" 0024 #include "skycomponents/starblockfactory.h" 0025 #ifdef HAVE_INDI 0026 #include "ekos/manager.h" 0027 #include "indi/drivermanager.h" 0028 #include "indi/guimanager.h" 0029 #include "indi/indilistener.h" 0030 #endif 0031 0032 #ifdef HAVE_CFITSIO 0033 #include "fitsviewer/fitsviewer.h" 0034 #endif 0035 0036 #include <KActionCollection> 0037 #include <KToolBar> 0038 0039 #ifdef Q_OS_WIN 0040 #include <QProcess> 0041 #endif 0042 #include <QStatusBar> 0043 #include <QMenu> 0044 0045 #include <kstars_debug.h> 0046 0047 KStars *KStars::pinstance = nullptr; 0048 bool KStars::Closing = false; 0049 0050 KStars::KStars(bool doSplash, bool clockrun, const QString &startdate) 0051 : KXmlGuiWindow(), StartClockRunning(clockrun), StartDateString(startdate) 0052 { 0053 // FIXME Hack to set RTL direction for Arabic 0054 // This is not a solution. It seems qtbase_ar.qm needs to take care of this? 0055 // qttranslations5-l10n does not contain qtbase_ar.qm 0056 // It seems qtbase_ar.ts does not exist for Qt 5.9 at all and needs to be translated. 0057 // https://wiki.qt.io/Qt_Localization 0058 if (i18n("Sky") == "السماء") 0059 qApp->setLayoutDirection(Qt::RightToLeft); 0060 0061 setWindowTitle(i18nc("@title:window", "KStars")); 0062 0063 // Set thread stack size to 32MB 0064 QThreadPool::globalInstance()->setStackSize(33554432); 0065 0066 // Initialize logging settings 0067 if (Options::disableLogging()) 0068 KSUtils::Logging::Disable(); 0069 else if (Options::logToFile()) 0070 KSUtils::Logging::UseFile(); 0071 else 0072 KSUtils::Logging::UseDefault(); 0073 0074 KSUtils::Logging::SyncFilterRules(); 0075 0076 qCInfo(KSTARS) << "Welcome to KStars" << KSTARS_VERSION << KSTARS_BUILD_RELEASE; 0077 qCInfo(KSTARS) << "Build:" << KSTARS_BUILD_TS; 0078 qCInfo(KSTARS) << "OS:" << QSysInfo::productType(); 0079 qCInfo(KSTARS) << "API:" << QSysInfo::buildAbi(); 0080 qCInfo(KSTARS) << "Arch:" << QSysInfo::currentCpuArchitecture(); 0081 qCInfo(KSTARS) << "Kernel Type:" << QSysInfo::kernelType(); 0082 qCInfo(KSTARS) << "Kernel Version:" << QSysInfo::kernelVersion(); 0083 qCInfo(KSTARS) << "Qt Version:" << QT_VERSION_STR; 0084 0085 new KstarsAdaptor( 0086 this); // NOTE the weird case convention, which cannot be changed as the file is generated by the moc. 0087 0088 #ifdef Q_OS_OSX 0089 0090 QString vlcPlugins = QDir(QCoreApplication::applicationDirPath() + "/../PlugIns/vlc").absolutePath(); 0091 qputenv("VLC_PLUGIN_PATH", vlcPlugins.toLatin1()); 0092 QString phonon_backend_path = QDir(QCoreApplication::applicationDirPath() + 0093 "/../PlugIns/phonon4qt5_backend/phonon_vlc.so").absolutePath(); 0094 qputenv("PHONON_BACKEND", phonon_backend_path.toLatin1()); 0095 0096 QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); 0097 QString path = env.value("PATH", ""); 0098 env.insert("PATH", "/usr/bin:/usr/local/bin:\"" + QCoreApplication::applicationDirPath() + "\":" + path); 0099 0100 QProcess dbusCheck; 0101 dbusCheck.setProcessEnvironment(env); 0102 0103 QString pluginsDir = QDir(QCoreApplication::applicationDirPath() + "/../PlugIns").absolutePath(); 0104 QString dbusPlist = pluginsDir + "/dbus/org.freedesktop.dbus-kstars.plist"; 0105 QFile file(dbusPlist); 0106 if (file.open(QIODevice::ReadOnly)) 0107 { 0108 QTextStream in(&file); 0109 QString pListText = in.readAll(); 0110 file.close(); 0111 int programArgsLeft = pListText.indexOf("<key>ProgramArguments</key>"); 0112 int programArgsRight = pListText.indexOf("</array>", programArgsLeft) + 8 - programArgsLeft; 0113 QString currentProgramArgs = pListText.mid(programArgsLeft, programArgsRight); 0114 QString newProgramArguments = "" 0115 "<key>ProgramArguments</key>\n" 0116 " <array>\n" 0117 " <string>" + 0118 QCoreApplication::applicationDirPath() + 0119 "/dbus-daemon</string>\n" 0120 " <string>--nofork</string>\n" 0121 " <string>--config-file=" + 0122 pluginsDir + 0123 "/dbus/kstars.conf</string>\n" 0124 " </array>"; 0125 pListText.replace(currentProgramArgs, newProgramArguments); 0126 if (file.open(QIODevice::WriteOnly)) 0127 { 0128 QTextStream stream(&file); 0129 stream << pListText; 0130 file.close(); 0131 0132 dbusCheck.start("chmod 775 " + dbusPlist); 0133 dbusCheck.waitForFinished(); 0134 dbusCheck.start("launchctl load -w \"" + dbusPlist + "\""); 0135 dbusCheck.waitForFinished(); 0136 qDebug("Starting DBus"); 0137 } 0138 else 0139 { 0140 qDebug("DBus File Write Error"); 0141 } 0142 } 0143 else 0144 { 0145 qDebug("DBus File Read Error"); 0146 } 0147 #endif 0148 0149 QDBusConnection::sessionBus().registerObject("/KStars", this); 0150 QDBusConnection::sessionBus().registerService("org.kde.kstars"); 0151 0152 #ifdef HAVE_CFITSIO 0153 m_GenericFITSViewer.clear(); 0154 #endif 0155 0156 // Set pinstance to yourself 0157 pinstance = this; 0158 0159 connect(qApp, SIGNAL(aboutToQuit()), this, SLOT(slotAboutToQuit())); 0160 0161 //Initialize QActionGroups 0162 projectionGroup = new QActionGroup(this); 0163 cschemeGroup = new QActionGroup(this); 0164 hipsGroup = new QActionGroup(this); 0165 telescopeGroup = new QActionGroup(this); 0166 telescopeGroup->setExclusive(false); 0167 domeGroup = new QActionGroup(this); 0168 domeGroup->setExclusive(false); 0169 skymapOrientationGroup = new QActionGroup(this); 0170 0171 0172 m_KStarsData = KStarsData::Create(); 0173 Q_ASSERT(m_KStarsData); 0174 //Set Geographic Location from Options 0175 m_KStarsData->setLocationFromOptions(); 0176 0177 //Initialize Time and Date 0178 bool datetimeSet = false; 0179 if (StartDateString.isEmpty() == false) 0180 { 0181 KStarsDateTime startDate = KStarsDateTime::fromString(StartDateString); 0182 if (startDate.isValid()) 0183 data()->changeDateTime(data()->geo()->LTtoUT(startDate)); 0184 else 0185 data()->changeDateTime(KStarsDateTime::currentDateTimeUtc()); 0186 0187 datetimeSet = true; 0188 } 0189 // JM 2016-11-15: Not need to set it again as it was initialized in the ctor of SimClock 0190 /* 0191 else 0192 data()->changeDateTime( KStarsDateTime::currentDateTimeUtc() ); 0193 */ 0194 0195 // If we are starting paused (--paused is not in the command line) change datetime in data 0196 if (StartClockRunning == false) 0197 { 0198 qCInfo(KSTARS) << "KStars is started in paused state."; 0199 if (datetimeSet == false) 0200 data()->changeDateTime(KStarsDateTime::currentDateTimeUtc()); 0201 } 0202 0203 // Setup splash screen 0204 KStarsSplash *splash = nullptr; 0205 if (doSplash) 0206 { 0207 splash = new KStarsSplash(nullptr); 0208 connect(m_KStarsData, SIGNAL(progressText(QString)), splash, SLOT(setMessage(QString))); 0209 splash->show(); 0210 } 0211 else 0212 { 0213 connect(m_KStarsData, SIGNAL(progressText(QString)), m_KStarsData, SLOT(slotConsoleMessage(QString))); 0214 } 0215 0216 /* 0217 //set up Dark color scheme for application windows 0218 DarkPalette = QPalette(QColor("black"), QColor("black")); 0219 DarkPalette.setColor(QPalette::Inactive, QPalette::WindowText, QColor("red")); 0220 DarkPalette.setColor(QPalette::Normal, QPalette::WindowText, QColor("red")); 0221 DarkPalette.setColor(QPalette::Normal, QPalette::Base, QColor("black")); 0222 DarkPalette.setColor(QPalette::Normal, QPalette::Text, QColor(238, 0, 0)); 0223 DarkPalette.setColor(QPalette::Normal, QPalette::Highlight, QColor(238, 0, 0)); 0224 DarkPalette.setColor(QPalette::Normal, QPalette::HighlightedText, QColor("black")); 0225 DarkPalette.setColor(QPalette::Inactive, QPalette::Text, QColor(238, 0, 0)); 0226 DarkPalette.setColor(QPalette::Inactive, QPalette::Base, QColor(30, 10, 10)); 0227 //store original color scheme 0228 OriginalPalette = QApplication::palette(); 0229 */ 0230 0231 //Initialize data. When initialization is complete, it will run dataInitFinished() 0232 if (!m_KStarsData->initialize()) 0233 return; 0234 delete splash; 0235 datainitFinished(); 0236 } 0237 0238 KStars *KStars::createInstance(bool doSplash, bool clockrun, const QString &startdate) 0239 { 0240 delete pinstance; 0241 // pinstance is set directly in constructor. 0242 new KStars(doSplash, clockrun, startdate); 0243 Q_ASSERT(pinstance && "pinstance must be non NULL"); 0244 return pinstance; 0245 } 0246 0247 KStars::~KStars() 0248 { 0249 releaseResources(); 0250 Q_ASSERT(pinstance); 0251 pinstance = nullptr; 0252 #ifdef PROFILE_COORDINATE_CONVERSION 0253 qDebug() << Q_FUNC_INFO << "Spent " << SkyPoint::cpuTime_EqToHz << " seconds in " << SkyPoint::eqToHzCalls 0254 << " calls to SkyPoint::EquatorialToHorizontal, for an average of " 0255 << 1000. * (SkyPoint::cpuTime_EqToHz / SkyPoint::eqToHzCalls) << " ms per call"; 0256 #endif 0257 0258 #ifdef COUNT_DMS_SINCOS_CALLS 0259 qDebug() << Q_FUNC_INFO << "Constructed " << dms::dms_constructor_calls << " dms objects, of which " << 0260 dms::dms_with_sincos_called 0261 << " had trigonometric functions called on them = " 0262 << (float(dms::dms_with_sincos_called) / float(dms::dms_constructor_calls)) * 100. << "%"; 0263 qDebug() << Q_FUNC_INFO << "Of the " << dms::trig_function_calls << " calls to sin/cos/sincos on dms objects, " 0264 << dms::redundant_trig_function_calls << " were redundant = " 0265 << ((float(dms::redundant_trig_function_calls) / float(dms::trig_function_calls)) * 100.) << "%"; 0266 qDebug() << Q_FUNC_INFO << "We had " << CachingDms::cachingdms_bad_uses << " bad uses of CachingDms in all, compared to " 0267 << CachingDms::cachingdms_constructor_calls << " constructed CachingDms objects = " 0268 << (float(CachingDms::cachingdms_bad_uses) / float(CachingDms::cachingdms_constructor_calls)) * 100. 0269 << "% bad uses"; 0270 #endif 0271 } 0272 0273 void KStars::releaseResources() 0274 { 0275 delete m_KStarsData; 0276 m_KStarsData = nullptr; 0277 delete StarBlockFactory::Instance(); 0278 TextureManager::Release(); 0279 SkyQPainter::releaseImageCache(); 0280 FOVManager::releaseCache(); 0281 0282 #ifdef HAVE_INDI 0283 GUIManager::release(); 0284 Ekos::Manager::release(); 0285 DriverManager::release(); 0286 #endif 0287 0288 QSqlDatabase::removeDatabase("userdb"); 0289 QSqlDatabase::removeDatabase("skydb"); 0290 } 0291 0292 void KStars::clearCachedFindDialog() 0293 { 0294 #if 0 0295 if (m_FindDialog) // dialog is cached 0296 { 0297 /** Delete findDialog only if it is not opened */ 0298 if (m_FindDialog->isHidden()) 0299 { 0300 delete m_FindDialog; 0301 m_FindDialog = nullptr; 0302 DialogIsObsolete = false; 0303 } 0304 else 0305 DialogIsObsolete = true; // dialog was opened so it could not deleted 0306 } 0307 #endif 0308 } 0309 0310 void KStars::applyConfig(bool doApplyFocus) 0311 { 0312 if (Options::isTracking()) 0313 { 0314 actionCollection()->action("track_object")->setText(i18n("Stop &Tracking")); 0315 actionCollection() 0316 ->action("track_object") 0317 ->setIcon(QIcon::fromTheme("document-encrypt")); 0318 } 0319 0320 actionCollection() 0321 ->action("coordsys") 0322 ->setText(Options::useAltAz() ? i18n("Switch to Star Globe View (Equatorial &Coordinates)") : 0323 i18n("Switch to Horizontal View (Horizontal &Coordinates)")); 0324 0325 actionCollection()->action("show_time_box")->setChecked(Options::showTimeBox()); 0326 actionCollection()->action("show_location_box")->setChecked(Options::showGeoBox()); 0327 actionCollection()->action("show_focus_box")->setChecked(Options::showFocusBox()); 0328 actionCollection()->action("show_statusBar")->setChecked(Options::showStatusBar()); 0329 actionCollection()->action("show_sbAzAlt")->setChecked(Options::showAltAzField()); 0330 actionCollection()->action("show_sbRADec")->setChecked(Options::showRADecField()); 0331 actionCollection()->action("show_sbJ2000RADec")->setChecked(Options::showJ2000RADecField()); 0332 actionCollection()->action("show_stars")->setChecked(Options::showStars()); 0333 actionCollection()->action("show_deepsky")->setChecked(Options::showDeepSky()); 0334 actionCollection()->action("show_planets")->setChecked(Options::showSolarSystem()); 0335 actionCollection()->action("show_clines")->setChecked(Options::showCLines()); 0336 actionCollection()->action("show_constellationart")->setChecked(Options::showConstellationArt()); 0337 actionCollection()->action("show_cnames")->setChecked(Options::showCNames()); 0338 actionCollection()->action("show_cbounds")->setChecked(Options::showCBounds()); 0339 actionCollection()->action("show_mw")->setChecked(Options::showMilkyWay()); 0340 actionCollection()->action("show_equatorial_grid")->setChecked(Options::showEquatorialGrid()); 0341 actionCollection()->action("show_horizontal_grid")->setChecked(Options::showHorizontalGrid()); 0342 actionCollection()->action("show_horizon")->setChecked(Options::showGround()); 0343 actionCollection()->action("show_flags")->setChecked(Options::showFlags()); 0344 actionCollection()->action("show_supernovae")->setChecked(Options::showSupernovae()); 0345 actionCollection()->action("show_satellites")->setChecked(Options::showSatellites()); 0346 actionCollection()->action("erect_observer_correction")->setChecked(Options::erectObserverCorrection()); 0347 actionCollection()->action("erect_observer_correction")->setEnabled(Options::useAltAz()); 0348 statusBar()->setVisible(Options::showStatusBar()); 0349 0350 //color scheme 0351 m_KStarsData->colorScheme()->loadFromConfig(); 0352 //QApplication::setPalette(Options::darkAppColors() ? DarkPalette : OriginalPalette); 0353 /** 0354 //Note: This uses style sheets to set the dark colors, this should be cross platform. Palettes have a different behavior on OS X and Windows as opposed to Linux. 0355 //It might be a good idea to use stylesheets in the future instead of palettes but this will work for now for OS X. 0356 //This is also in KStarsDbus.cpp. If you change it, change it in BOTH places. 0357 @code 0358 #ifdef Q_OS_OSX 0359 if (Options::darkAppColors()) 0360 qApp->setStyleSheet( 0361 "QWidget { background-color: black; color:red; " 0362 "selection-background-color:rgb(30,30,30);selection-color:white}" 0363 "QToolBar { border:none }" 0364 "QTabBar::tab:selected { background-color:rgb(50,50,50) }" 0365 "QTabBar::tab:!selected { background-color:rgb(30,30,30) }" 0366 "QPushButton { background-color:rgb(50,50,50);border-width:1px; border-style:solid;border-color:black}" 0367 "QPushButton::disabled { background-color:rgb(10,10,10);border-width:1px; " 0368 "border-style:solid;border-color:black }" 0369 "QToolButton:Checked { background-color:rgb(30,30,30); border:none }" 0370 "QComboBox { background-color:rgb(30,30,30); }" 0371 "QComboBox::disabled { background-color:rgb(10,10,10) }" 0372 "QScrollBar::handle { background: rgb(30,30,30) }" 0373 "QSpinBox { border-width: 1px; border-style:solid; border-color:rgb(30,30,30) }" 0374 "QDoubleSpinBox { border-width:1px; border-style:solid; border-color:rgb(30,30,30) }" 0375 "QLineEdit { border-width: 1px; border-style: solid; border-color:rgb(30,30,30) }" 0376 "QCheckBox::indicator:unchecked { background-color:rgb(30,30,30);border-width:1px; " 0377 "border-style:solid;border-color:black }" 0378 "QCheckBox::indicator:checked { background-color:red;border-width:1px; " 0379 "border-style:solid;border-color:black }" 0380 "QRadioButton::indicator:unchecked { background-color:rgb(30,30,30) }" 0381 "QRadioButton::indicator:checked { background-color:red }" 0382 "QRoundProgressBar { alternate-background-color:black }" 0383 "QDateTimeEdit {background-color:rgb(30,30,30); border-width: 1px; border-style:solid; " 0384 "border-color:rgb(30,30,30) }" 0385 "QHeaderView { color:red;background-color:black }" 0386 "QHeaderView::Section { background-color:rgb(30,30,30) }" 0387 "QTableCornerButton::section{ background-color:rgb(30,30,30) }" 0388 ""); 0389 else 0390 qApp->setStyleSheet(""); 0391 #endif 0392 @endcode 0393 **/ 0394 0395 //Set toolbar options from config file 0396 toolBar("kstarsToolBar")->applySettings(KSharedConfig::openConfig()->group("MainToolBar")); 0397 toolBar("viewToolBar")->applySettings(KSharedConfig::openConfig()->group("ViewToolBar")); 0398 0399 //Geographic location 0400 data()->setLocationFromOptions(); 0401 0402 //Focus 0403 if (doApplyFocus) 0404 { 0405 SkyObject *fo = data()->objectNamed(Options::focusObject()); 0406 if (fo && fo != map()->focusObject()) 0407 { 0408 map()->setClickedObject(fo); 0409 map()->setClickedPoint(fo); 0410 map()->slotCenter(); 0411 } 0412 0413 if (!fo) 0414 { 0415 SkyPoint fp(Options::focusRA(), Options::focusDec()); 0416 if (fp.ra().Degrees() != map()->focus()->ra().Degrees() || 0417 fp.dec().Degrees() != map()->focus()->dec().Degrees()) 0418 { 0419 map()->setClickedPoint(&fp); 0420 map()->slotCenter(); 0421 } 0422 } 0423 } 0424 } 0425 0426 void KStars::showImgExportDialog() 0427 { 0428 if (m_ExportImageDialog) 0429 m_ExportImageDialog->show(); 0430 } 0431 0432 void KStars::syncFOVActions() 0433 { 0434 foreach (QAction *action, fovActionMenu->menu()->actions()) 0435 { 0436 if (action->text().isEmpty()) 0437 { 0438 continue; 0439 } 0440 0441 if (Options::fOVNames().contains(action->text().remove(0, 1))) 0442 { 0443 action->setChecked(true); 0444 } 0445 else 0446 { 0447 action->setChecked(false); 0448 } 0449 } 0450 } 0451 0452 void KStars::hideAllFovExceptFirst() 0453 { 0454 // When there is only one visible FOV symbol, we don't need to do anything 0455 // Also, don't do anything if there are no available FOV symbols. 0456 if (data()->visibleFOVs.size() == 1 || data()->availFOVs.isEmpty()) 0457 { 0458 return; 0459 } 0460 else 0461 { 0462 // If there are no visible FOVs, select first available 0463 if (data()->visibleFOVs.isEmpty()) 0464 { 0465 Q_ASSERT(!data()->availFOVs.isEmpty()); 0466 Options::setFOVNames(QStringList(data()->availFOVs.first()->name())); 0467 } 0468 else 0469 { 0470 Options::setFOVNames(QStringList(data()->visibleFOVs.first()->name())); 0471 } 0472 0473 // Sync FOV and update skymap 0474 data()->syncFOV(); 0475 syncFOVActions(); 0476 map()->update(); // SkyMap::forceUpdate() is not required, as FOVs are drawn as overlays 0477 } 0478 } 0479 0480 void KStars::selectNextFov() 0481 { 0482 if (data()->getVisibleFOVs().isEmpty()) 0483 return; 0484 0485 Q_ASSERT(!data() 0486 ->getAvailableFOVs() 0487 .isEmpty()); // The available FOVs had better not be empty if the visible ones are not. 0488 0489 FOV *currentFov = data()->getVisibleFOVs().first(); 0490 int currentIdx = data()->availFOVs.indexOf(currentFov); 0491 0492 // If current FOV is not the available FOV list or there is only 1 FOV available, then return 0493 if (currentIdx == -1 || data()->availFOVs.size() < 2) 0494 { 0495 return; 0496 } 0497 0498 QStringList nextFovName; 0499 if (currentIdx == data()->availFOVs.size() - 1) 0500 { 0501 nextFovName << data()->availFOVs.first()->name(); 0502 } 0503 else 0504 { 0505 nextFovName << data()->availFOVs.at(currentIdx + 1)->name(); 0506 } 0507 0508 Options::setFOVNames(nextFovName); 0509 data()->syncFOV(); 0510 syncFOVActions(); 0511 map()->update(); 0512 } 0513 0514 void KStars::selectPreviousFov() 0515 { 0516 if (data()->getVisibleFOVs().isEmpty()) 0517 return; 0518 0519 Q_ASSERT(!data() 0520 ->getAvailableFOVs() 0521 .isEmpty()); // The available FOVs had better not be empty if the visible ones are not. 0522 0523 FOV *currentFov = data()->getVisibleFOVs().first(); 0524 int currentIdx = data()->availFOVs.indexOf(currentFov); 0525 0526 // If current FOV is not the available FOV list or there is only 1 FOV available, then return 0527 if (currentIdx == -1 || data()->availFOVs.size() < 2) 0528 { 0529 return; 0530 } 0531 0532 QStringList prevFovName; 0533 if (currentIdx == 0) 0534 { 0535 prevFovName << data()->availFOVs.last()->name(); 0536 } 0537 else 0538 { 0539 prevFovName << data()->availFOVs.at(currentIdx - 1)->name(); 0540 } 0541 0542 Options::setFOVNames(prevFovName); 0543 data()->syncFOV(); 0544 syncFOVActions(); 0545 map()->update(); 0546 } 0547 0548 //FIXME Port to QML2 0549 //#if 0 0550 void KStars::showWISettingsUI() 0551 { 0552 slotWISettings(); 0553 } 0554 //#endif 0555 0556 void KStars::updateTime(const bool automaticDSTchange) 0557 { 0558 // Due to frequently use of this function save data and map pointers for speedup. 0559 // Save options and geo() to a pointer would not speedup because most of time options 0560 // and geo will accessed only one time. 0561 KStarsData *Data = data(); 0562 // dms oldLST( Data->lst()->Degrees() ); 0563 0564 Data->updateTime(Data->geo(), automaticDSTchange); 0565 0566 //We do this outside of kstarsdata just to get the coordinates 0567 //displayed in the infobox to update every second. 0568 // if ( !Options::isTracking() && LST()->Degrees() > oldLST.Degrees() ) { 0569 // int nSec = int( 3600.*( LST()->Hours() - oldLST.Hours() ) ); 0570 // Map->focus()->setRA( Map->focus()->ra().Hours() + double( nSec )/3600. ); 0571 // if ( Options::useAltAz() ) Map->focus()->EquatorialToHorizontal( LST(), geo()->lat() ); 0572 // Map->showFocusCoords(); 0573 // } 0574 0575 //If time is accelerated beyond slewTimescale, then the clock's timer is stopped, 0576 //so that it can be ticked manually after each update, in order to make each time 0577 //step exactly equal to the timeScale setting. 0578 //Wrap the call to manualTick() in a singleshot timer so that it doesn't get called until 0579 //the skymap has been completely updated. 0580 if (Data->clock()->isManualMode() && Data->clock()->isActive()) 0581 { 0582 // Jasem 2017-11-13: Time for each update varies. 0583 // Ideally we want to advance the simulation clock by 0584 // the current clock scale (e.g. 1 hour) every 1 second 0585 // of real time. However, the sky map update, depending on calculations and 0586 // drawing of objects, takes variable time to complete. 0587 //QTimer::singleShot(0, Data->clock(), SLOT(manualTick())); 0588 QTimer::singleShot(1000, Data->clock(), SLOT(manualTick())); 0589 } 0590 } 0591 0592 #ifdef HAVE_CFITSIO 0593 const QSharedPointer<FITSViewer> &KStars::createFITSViewer() 0594 { 0595 if (Options::singleWindowCapturedFITS()) 0596 return KStars::Instance()->genericFITSViewer(); 0597 else 0598 { 0599 QSharedPointer<FITSViewer> newFITSViewer(new FITSViewer(Options::independentWindowFITS() ? nullptr : KStars::Instance()), 0600 &QObject::deleteLater); 0601 m_FITSViewers.append(newFITSViewer); 0602 connect(newFITSViewer.get(), &FITSViewer::terminated, this, [this]() 0603 { 0604 auto rawPointer = dynamic_cast<FITSViewer*>(sender()); 0605 m_FITSViewers.erase(std::remove_if(m_FITSViewers.begin(), m_FITSViewers.end(), [rawPointer](auto & viewer) 0606 { 0607 return viewer.get() == rawPointer; 0608 })); 0609 }); 0610 return m_FITSViewers.constLast(); 0611 } 0612 } 0613 0614 const QSharedPointer<FITSViewer> &KStars::genericFITSViewer() 0615 { 0616 if (m_GenericFITSViewer.isNull()) 0617 { 0618 m_GenericFITSViewer.reset(new FITSViewer(Options::independentWindowFITS() ? nullptr : this), &QObject::deleteLater); 0619 connect(m_GenericFITSViewer.get(), &FITSViewer::terminated, this, [this]() 0620 { 0621 m_FITSViewers.removeOne(m_GenericFITSViewer); 0622 m_GenericFITSViewer.clear(); 0623 }); 0624 m_FITSViewers.append(m_GenericFITSViewer); 0625 } 0626 0627 return m_GenericFITSViewer; 0628 } 0629 0630 void KStars::clearAllViewers() 0631 { 0632 for (auto &fv : m_FITSViewers) 0633 fv->close(); 0634 0635 m_FITSViewers.clear(); 0636 } 0637 #endif 0638 0639 void KStars::closeEvent(QCloseEvent *event) 0640 { 0641 KStars::Closing = true; 0642 QWidget::closeEvent(event); 0643 slotAboutToQuit(); 0644 }