Warning, file /education/kstars/kstars/kstarsactions.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2002 Jason Harris <jharris@30doradus.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 // This file contains function definitions for Actions declared in kstars.h
0008 
0009 #include "kstars.h"
0010 
0011 #include "imageexporter.h"
0012 #include "kstarsdata.h"
0013 #include "kstars_debug.h"
0014 #include "ksnotification.h"
0015 #include "kswizard.h"
0016 #include "Options.h"
0017 #include "skymap.h"
0018 #include "texturemanager.h"
0019 #include "dialogs/exportimagedialog.h"
0020 #include "dialogs/finddialog.h"
0021 #include "dialogs/focusdialog.h"
0022 #include "dialogs/fovdialog.h"
0023 #include "dialogs/locationdialog.h"
0024 #include "dialogs/timedialog.h"
0025 #include "dialogs/catalogsdbui.h"
0026 #include "oal/execute.h"
0027 #include "oal/equipmentwriter.h"
0028 #include "oal/observeradd.h"
0029 #include "options/opsadvanced.h"
0030 #include "options/opscatalog.h"
0031 #include "options/opscolors.h"
0032 #include "options/opsguides.h"
0033 #include "options/opsterrain.h"
0034 #include "options/opsdeveloper.h"
0035 #include "options/opssatellites.h"
0036 #include "options/opssolarsystem.h"
0037 #include "options/opssupernovae.h"
0038 #include "printing/printingwizard.h"
0039 #include "projections/projector.h"
0040 #include "skycomponents/asteroidscomponent.h"
0041 #include "skycomponents/cometscomponent.h"
0042 #include "skycomponents/satellitescomponent.h"
0043 #include "skycomponents/skymapcomposite.h"
0044 #include "skycomponents/solarsystemcomposite.h"
0045 #include "skycomponents/supernovaecomponent.h"
0046 #include "skycomponents/catalogscomponent.h"
0047 #include "skycomponents/mosaiccomponent.h"
0048 #ifdef HAVE_INDI
0049 #include "skyobjects/mosaictiles.h"
0050 #endif
0051 #include "tools/altvstime.h"
0052 #include "tools/astrocalc.h"
0053 #include "tools/eyepiecefield.h"
0054 #include "tools/flagmanager.h"
0055 #include "tools/horizonmanager.h"
0056 #include "tools/observinglist.h"
0057 #include "tools/planetviewer.h"
0058 #include "tools/jmoontool.h"
0059 #include "tools/scriptbuilder.h"
0060 #include "tools/skycalendar.h"
0061 #include "tools/wutdialog.h"
0062 #include "tools/polarishourangle.h"
0063 #include "tools/whatsinteresting/wiequipsettings.h"
0064 #include "tools/whatsinteresting/wilpsettings.h"
0065 #include "tools/whatsinteresting/wiview.h"
0066 #include "hips/hipsmanager.h"
0067 #include "catalogsdb.h"
0068 #ifdef HAVE_INDI
0069 #include <basedevice.h>
0070 //#include "indi/telescopewizardprocess.h"
0071 #include "indi/opsindi.h"
0072 #include "indi/drivermanager.h"
0073 #include "indi/guimanager.h"
0074 #include "indi/indilistener.h"
0075 #endif
0076 
0077 #ifdef HAVE_CFITSIO
0078 #include "fitsviewer/fitsviewer.h"
0079 #include "fitsviewer/opsfits.h"
0080 #ifdef HAVE_INDI
0081 #include "ekos/manager.h"
0082 #include "ekos/scheduler/framingassistantui.h"
0083 #include "ekos/opsekos.h"
0084 #endif
0085 #endif
0086 
0087 #include "xplanet/opsxplanet.h"
0088 
0089 #ifdef HAVE_NOTIFYCONFIG
0090 #include <KNotifyConfigWidget>
0091 #endif
0092 #include <KActionCollection>
0093 #include <KActionMenu>
0094 #include <KTipDialog>
0095 #include <KToggleAction>
0096 #include <kns3/downloaddialog.h>
0097 
0098 #include <QQuickWindow>
0099 #include <QQuickView>
0100 
0101 #ifdef _WIN32
0102 #include <windows.h>
0103 #undef interface
0104 #endif
0105 #include <sys/stat.h>
0106 
0107 /** ViewToolBar Action.  All of the viewToolBar buttons are connected to this slot. **/
0108 
0109 void KStars::slotViewToolBar()
0110 {
0111     KToggleAction *a   = (KToggleAction *)sender();
0112     KConfigDialog *kcd = KConfigDialog::exists("settings");
0113 
0114     if (a == actionCollection()->action("show_stars"))
0115     {
0116         Options::setShowStars(a->isChecked());
0117         if (kcd)
0118         {
0119             opcatalog->kcfg_ShowStars->setChecked(a->isChecked());
0120         }
0121     }
0122     else if (a == actionCollection()->action("show_deepsky"))
0123     {
0124         Options::setShowDeepSky(a->isChecked());
0125         if (kcd)
0126         {
0127             opcatalog->kcfg_ShowDeepSky->setChecked(a->isChecked());
0128         }
0129     }
0130     else if (a == actionCollection()->action("show_planets"))
0131     {
0132         Options::setShowSolarSystem(a->isChecked());
0133         if (kcd)
0134         {
0135             opsolsys->kcfg_ShowSolarSystem->setChecked(a->isChecked());
0136         }
0137     }
0138     else if (a == actionCollection()->action("show_clines"))
0139     {
0140         Options::setShowCLines(a->isChecked());
0141         if (kcd)
0142         {
0143             opguides->kcfg_ShowCLines->setChecked(a->isChecked());
0144         }
0145     }
0146     else if (a == actionCollection()->action("show_cnames"))
0147     {
0148         Options::setShowCNames(a->isChecked());
0149         if (kcd)
0150         {
0151             opguides->kcfg_ShowCNames->setChecked(a->isChecked());
0152         }
0153     }
0154     else if (a == actionCollection()->action("show_cbounds"))
0155     {
0156         Options::setShowCBounds(a->isChecked());
0157         if (kcd)
0158         {
0159             opguides->kcfg_ShowCBounds->setChecked(a->isChecked());
0160         }
0161     }
0162     else if (a == actionCollection()->action("show_constellationart"))
0163     {
0164         Options::setShowConstellationArt(a->isChecked());
0165         if (kcd)
0166         {
0167             opguides->kcfg_ShowConstellationArt->setChecked(a->isChecked());
0168         }
0169     }
0170     else if (a == actionCollection()->action("show_mw"))
0171     {
0172         Options::setShowMilkyWay(a->isChecked());
0173         if (kcd)
0174         {
0175             opguides->kcfg_ShowMilkyWay->setChecked(a->isChecked());
0176         }
0177     }
0178     else if (a == actionCollection()->action("show_equatorial_grid"))
0179     {
0180         // if autoSelectGrid is selected and the user clicked the
0181         // show_equatorial_grid button, he probably wants us to disable
0182         // the autoSelectGrid and display the equatorial grid.
0183         Options::setAutoSelectGrid(false);
0184         Options::setShowEquatorialGrid(a->isChecked());
0185         if (kcd)
0186         {
0187             opguides->kcfg_ShowEquatorialGrid->setChecked(a->isChecked());
0188             opguides->kcfg_AutoSelectGrid->setChecked(false);
0189         }
0190     }
0191     else if (a == actionCollection()->action("show_horizontal_grid"))
0192     {
0193         Options::setAutoSelectGrid(false);
0194         Options::setShowHorizontalGrid(a->isChecked());
0195         if (kcd)
0196         {
0197             opguides->kcfg_ShowHorizontalGrid->setChecked(a->isChecked());
0198             opguides->kcfg_AutoSelectGrid->setChecked(false);
0199         }
0200     }
0201     else if (a == actionCollection()->action("show_horizon"))
0202     {
0203         Options::setShowGround(a->isChecked());
0204         if (!a->isChecked() && Options::useRefraction())
0205         {
0206             QString caption = i18n("Refraction effects disabled");
0207             QString message = i18n("When the horizon is switched off, refraction effects "
0208                                    "are temporarily disabled.");
0209 
0210             KMessageBox::information(this, message, caption, "dag_refract_hide_ground");
0211         }
0212         if (kcd)
0213         {
0214             opguides->kcfg_ShowGround->setChecked(a->isChecked());
0215         }
0216     }
0217     else if (a == actionCollection()->action("show_flags"))
0218     {
0219         Options::setShowFlags(a->isChecked());
0220         if (kcd)
0221         {
0222             opguides->kcfg_ShowFlags->setChecked(a->isChecked());
0223         }
0224     }
0225     else if (a == actionCollection()->action("show_satellites"))
0226     {
0227         Options::setShowSatellites(a->isChecked());
0228         if (kcd)
0229         {
0230             opssatellites->kcfg_ShowSatellites->setChecked(a->isChecked());
0231         }
0232     }
0233     else if (a == actionCollection()->action("show_supernovae"))
0234     {
0235         Options::setShowSupernovae(a->isChecked());
0236         if (kcd)
0237         {
0238             opssupernovae->kcfg_ShowSupernovae->setChecked(a->isChecked());
0239         }
0240     }
0241 
0242     // update time for all objects because they might be not initialized
0243     // it's needed when using horizontal coordinates
0244     data()->setFullTimeUpdate();
0245     updateTime();
0246 
0247     map()->forceUpdate();
0248 }
0249 
0250 void KStars::slotINDIToolBar()
0251 {
0252 #ifdef HAVE_INDI
0253     KToggleAction *a = qobject_cast<KToggleAction *>(sender());
0254 
0255     if (a == actionCollection()->action("show_control_panel"))
0256     {
0257         if (a->isChecked())
0258         {
0259             GUIManager::Instance()->raise();
0260             GUIManager::Instance()->activateWindow();
0261             GUIManager::Instance()->showNormal();
0262         }
0263         else
0264             GUIManager::Instance()->hide();
0265     }
0266     else if (a == actionCollection()->action("show_ekos"))
0267     {
0268         if (a->isChecked())
0269         {
0270             Ekos::Manager::Instance()->raise();
0271             Ekos::Manager::Instance()->activateWindow();
0272             Ekos::Manager::Instance()->showNormal();
0273         }
0274         else
0275             Ekos::Manager::Instance()->hide();
0276     }
0277     else if (a == actionCollection()->action("lock_telescope"))
0278     {
0279         for (auto &oneDevice : INDIListener::devices())
0280         {
0281             if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
0282                 continue;
0283 
0284             if (oneDevice->isConnected() == false)
0285             {
0286                 KSNotification::error(i18n("Mount %1 is offline. Please connect and retry again.", oneDevice->getDeviceName()));
0287                 return;
0288             }
0289 
0290             auto mount = oneDevice->getMount();
0291             if (!mount)
0292                 continue;
0293 
0294             if (a->isChecked())
0295                 mount->centerLock();
0296             else
0297                 mount->centerUnlock();
0298             return;
0299         }
0300 
0301         KSNotification::sorry(i18n("No connected mounts found."));
0302         return;
0303     }
0304     else if (a == actionCollection()->action("show_fits_viewer"))
0305     {
0306         if (m_FITSViewers.isEmpty())
0307         {
0308             a->setEnabled(false);
0309             return;
0310         }
0311 
0312         if (a->isChecked())
0313         {
0314             for (auto &view : m_FITSViewers)
0315             {
0316                 if (view->getTabs().empty() == false)
0317                 {
0318                     view->raise();
0319                     view->activateWindow();
0320                     view->showNormal();
0321                 }
0322             }
0323         }
0324         else
0325         {
0326             for (auto &view : m_FITSViewers)
0327             {
0328                 view->hide();
0329             }
0330         }
0331     }
0332     else if (a == actionCollection()->action("show_mount_box"))
0333     {
0334         Ekos::Manager::Instance()->mountModule()->toggleMountToolBox();
0335     }
0336     else if (a == actionCollection()->action("show_sensor_fov"))
0337     {
0338         Options::setShowSensorFOV(a->isChecked());
0339         for (auto &oneFOV : data()->getTransientFOVs())
0340         {
0341             if (oneFOV->objectName() == "sensor_fov")
0342                 oneFOV->setProperty("visible", a->isChecked());
0343         }
0344     }
0345     else if (a == actionCollection()->action("show_mosaic_panel"))
0346     {
0347         Options::setShowMosaicPanel(a->isChecked());
0348         // TODO
0349         // If scheduler is not running, then we should also show the Mosaic Planner dialog.
0350         auto scheduler = Ekos::Manager::Instance()->schedulerModule();
0351         if (a->isChecked() && scheduler && scheduler->status() != Ekos::SCHEDULER_RUNNING)
0352         {
0353             // Only create if we don't have an instance already
0354             if (findChild<Ekos::FramingAssistantUI *>("FramingAssistant") == nullptr)
0355             {
0356                 Ekos::FramingAssistantUI *assistant = new Ekos::FramingAssistantUI();
0357                 assistant->setAttribute(Qt::WA_DeleteOnClose, true);
0358                 assistant->show();
0359             }
0360         }
0361     }
0362 
0363 #endif
0364 }
0365 
0366 void KStars::slotSetTelescopeEnabled(bool enable)
0367 {
0368     telescopeGroup->setEnabled(enable);
0369     if (enable == false)
0370     {
0371         for (QAction *a : telescopeGroup->actions())
0372         {
0373             a->setChecked(false);
0374         }
0375     }
0376 }
0377 
0378 void KStars::slotSetDomeEnabled(bool enable)
0379 {
0380     domeGroup->setEnabled(enable);
0381     if (enable == false)
0382     {
0383         for (QAction *a : domeGroup->actions())
0384         {
0385             a->setChecked(false);
0386         }
0387     }
0388 }
0389 
0390 /** Major Dialog Window Actions **/
0391 
0392 void KStars::slotCalculator()
0393 {
0394     if (!m_AstroCalc)
0395         m_AstroCalc = new AstroCalc(this);
0396     m_AstroCalc->show();
0397 }
0398 
0399 void KStars::slotWizard()
0400 {
0401     QPointer<KSWizard> wizard = new KSWizard(this);
0402     if (wizard->exec() == QDialog::Accepted)
0403     {
0404         Options::setRunStartupWizard(false); //don't run on startup next time
0405         if (wizard->geo())
0406             updateLocationFromWizard(*(wizard->geo()));
0407     }
0408 }
0409 
0410 void KStars::updateLocationFromWizard(const GeoLocation &geo)
0411 {
0412     data()->setLocation(geo);
0413     // adjust local time to keep UT the same.
0414     // create new LT without DST offset
0415     KStarsDateTime ltime = data()->geo()->UTtoLT(data()->ut());
0416 
0417     // reset timezonerule to compute next dst change
0418     data()->geo()->tzrule()->reset_with_ltime(ltime, data()->geo()->TZ0(),
0419             data()->isTimeRunningForward());
0420 
0421     // reset next dst change time
0422     data()->setNextDSTChange(data()->geo()->tzrule()->nextDSTChange());
0423 
0424     // reset local sideral time
0425     data()->syncLST();
0426 
0427     // Make sure Numbers, Moon, planets, and sky objects are updated immediately
0428     data()->setFullTimeUpdate();
0429 
0430     // If the sky is in Horizontal mode and not tracking, reset focus such that
0431     // Alt/Az remain constant.
0432     if (!Options::isTracking() && Options::useAltAz())
0433     {
0434         map()->focus()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
0435     }
0436 
0437     // recalculate new times and objects
0438     data()->setSnapNextFocus();
0439     updateTime();
0440 }
0441 
0442 void KStars::slotDownload()
0443 {
0444     KSNotification::event(
0445         QLatin1String("KnownIssue"),
0446         i18n("Due to a known issue in the kde frameworks, "
0447              "updating already downloaded items is currently not possible. <br> "
0448              "Please uninstall and reinstall them to update."));
0449 
0450     // 2017-07-04: Explicitly load kstars.knsrc from resources file
0451     auto dlg = std::make_unique<KNS3::DownloadDialog>(":/kconfig/kstars.knsrc", this);
0452 
0453     if (!dlg)
0454         return;
0455 
0456     dlg->exec();
0457 
0458     // Get the list of all the installed entries.
0459     const auto changed_entries = dlg->changedEntries();
0460 
0461     CatalogsDB::DBManager manager{ CatalogsDB::dso_db_path() };
0462     for (const KNS3::Entry &entry : changed_entries)
0463     {
0464         if (entry.category() != "dso")
0465             continue;
0466         const auto id = entry.id().toInt();
0467 
0468         if (entry.status() == KNS3::Entry::Installed)
0469             for (const QString &name : entry.installedFiles())
0470             {
0471                 if (name.endsWith(CatalogsDB::db_file_extension))
0472                 {
0473                     const auto meta{ CatalogsDB::read_catalog_meta_from_file(name) };
0474 
0475                     if (!meta.first)
0476                     {
0477                         QMessageBox::critical(
0478                             this, i18n("Error"),
0479                             i18n("The catalog \"%1\" is corrupt.", entry.name()));
0480                         continue;
0481                     }
0482 
0483                     if (meta.second.id != id)
0484                     {
0485                         QMessageBox::critical(
0486                             this, i18n("Error"),
0487                             i18n("The catalog \"%1\" is corrupt.<br>Expected id=%2 but "
0488                                  "got id=%3",
0489                                  entry.name(), id, meta.second.id));
0490                         continue;
0491                     }
0492 
0493                     const auto success{ manager.import_catalog(name, true) };
0494                     if (!success.first)
0495                         QMessageBox::critical(
0496                             this, i18n("Error"),
0497                             i18n("Could not import the catalog \"%1\"<br>%2",
0498                                  entry.name(), success.second));
0499                 }
0500             }
0501 
0502         if (entry.status() == KNS3::Entry::Deleted)
0503         {
0504             manager.remove_catalog(id);
0505         }
0506     }
0507 
0508     TextureManager::discoverTextureDirs();
0509     KStars::Instance()->data()->skyComposite()->reloadDeepSky();
0510     KStars::Instance()->data()->setFullTimeUpdate();
0511     KStars::Instance()->updateTime();
0512     KStars::Instance()->map()->forceUpdate();
0513 }
0514 
0515 void KStars::slotAVT()
0516 {
0517     if (!m_AltVsTime)
0518         m_AltVsTime = new AltVsTime(this);
0519     m_AltVsTime->show();
0520 }
0521 
0522 void KStars::slotWUT()
0523 {
0524     if (!m_WUTDialog)
0525         m_WUTDialog = new WUTDialog(this);
0526     m_WUTDialog->show();
0527 }
0528 
0529 //FIXME Port to QML2
0530 //#if 0
0531 void KStars::slotWISettings()
0532 {
0533     if (!m_WIView)
0534         slotToggleWIView();
0535     if (m_WIView && !m_wiDock->isVisible())
0536         slotToggleWIView();
0537 
0538     if (KConfigDialog::showDialog("wisettings"))
0539     {
0540         m_WIEquipmentSettings->populateScopeListWidget();
0541         return;
0542     }
0543 
0544     KConfigDialog *dialog = new KConfigDialog(this, "wisettings", Options::self());
0545 
0546     connect(dialog, SIGNAL(settingsChanged(QString)), this,
0547             SLOT(slotApplyWIConfigChanges()));
0548 
0549     m_WISettings          = new WILPSettings(this);
0550     m_WIEquipmentSettings = new WIEquipSettings();
0551     dialog->addPage(m_WISettings, i18n("Light Pollution Settings"));
0552     dialog->addPage(m_WIEquipmentSettings,
0553                     i18n("Equipment Settings - Equipment Type and Parameters"));
0554     dialog->exec();
0555     if (m_WIEquipmentSettings)
0556         m_WIEquipmentSettings->setAperture(); //Something isn't working with this!
0557 }
0558 
0559 void KStars::slotToggleWIView()
0560 {
0561     if (KStars::Closing)
0562         return;
0563 
0564     if (!m_WIView)
0565     {
0566         m_WIView = new WIView(nullptr);
0567         m_wiDock = new QDockWidget(this);
0568         m_wiDock->setStyleSheet("QDockWidget::title{background-color:black;}");
0569         m_wiDock->setObjectName("What's Interesting");
0570         m_wiDock->setAllowedAreas(Qt::RightDockWidgetArea);
0571         QWidget *container = QWidget::createWindowContainer(m_WIView->getWIBaseView());
0572         m_wiDock->setWidget(container);
0573         m_wiDock->setMinimumWidth(400);
0574         addDockWidget(Qt::RightDockWidgetArea, m_wiDock);
0575         connect(m_wiDock, SIGNAL(visibilityChanged(bool)),
0576                 actionCollection()->action("show_whatsinteresting"),
0577                 SLOT(setChecked(bool)));
0578         m_wiDock->setVisible(true);
0579     }
0580     else
0581     {
0582         m_wiDock->setVisible(!m_wiDock->isVisible());
0583     }
0584 }
0585 
0586 void KStars::slotCalendar()
0587 {
0588     if (!m_SkyCalendar)
0589         m_SkyCalendar = new SkyCalendar(this);
0590     m_SkyCalendar->show();
0591 }
0592 
0593 void KStars::slotGlossary()
0594 {
0595     //  GlossaryDialog *dlg = new GlossaryDialog( this, true );
0596     //  QString glossaryfile =data()->stdDirs->findResource( "data", "kstars/glossary.xml" );
0597     //  QUrl u = glossaryfile;
0598     //  Glossary *g = new Glossary( u );
0599     //  g->setName( i18n( "Knowledge" ) );
0600     //  dlg->addGlossary( g );
0601     //  dlg->show();
0602 }
0603 
0604 void KStars::slotScriptBuilder()
0605 {
0606     if (!m_ScriptBuilder)
0607         m_ScriptBuilder = new ScriptBuilder(this);
0608     m_ScriptBuilder->show();
0609 }
0610 
0611 void KStars::slotSolarSystem()
0612 {
0613     if (!m_PlanetViewer)
0614         m_PlanetViewer = new PlanetViewer(this);
0615     m_PlanetViewer->show();
0616 }
0617 
0618 void KStars::slotJMoonTool()
0619 {
0620     if (!m_JMoonTool)
0621         m_JMoonTool = new JMoonTool(this);
0622     m_JMoonTool->show();
0623 }
0624 
0625 void KStars::slotMoonPhaseTool()
0626 {
0627     //FIXME Port to KF5
0628     //if( ! mpt ) mpt = new MoonPhaseTool( this );
0629     //mpt->show();
0630 }
0631 
0632 void KStars::slotFlagManager()
0633 {
0634     if (!m_FlagManager)
0635         m_FlagManager = new FlagManager(this);
0636     m_FlagManager->show();
0637 }
0638 
0639 #if 0
0640 void KStars::slotTelescopeWizard()
0641 {
0642 #ifdef HAVE_INDI
0643 #ifndef Q_OS_WIN
0644 
0645     QString indiServerDir = Options::indiServer();
0646 
0647 #ifdef Q_OS_OSX
0648     if (Options::indiServerIsInternal())
0649         indiServerDir = QCoreApplication::applicationDirPath();
0650     else
0651         indiServerDir = QFileInfo(Options::indiServer()).dir().path();
0652 #endif
0653 
0654     QStringList paths;
0655     paths << "/usr/bin"
0656           << "/usr/local/bin" << indiServerDir;
0657 
0658     if (QStandardPaths::findExecutable("indiserver").isEmpty())
0659     {
0660         if (QStandardPaths::findExecutable("indiserver", paths).isEmpty())
0661         {
0662             KSNotification::error(i18n("Unable to find INDI server. Please make sure the package that provides "
0663                                        "the 'indiserver' binary is installed."));
0664             return;
0665         }
0666     }
0667 #endif
0668 
0669     QPointer<telescopeWizardProcess> twiz = new telescopeWizardProcess(this);
0670     twiz->exec();
0671     delete twiz;
0672 #endif
0673 }
0674 #endif
0675 
0676 void KStars::slotINDIPanel()
0677 {
0678 #ifdef HAVE_INDI
0679 #ifndef Q_OS_WIN
0680 
0681     QString indiServerDir = Options::indiServer();
0682 
0683 #ifdef Q_OS_OSX
0684     if (Options::indiServerIsInternal())
0685         indiServerDir = QCoreApplication::applicationDirPath();
0686     else
0687         indiServerDir = QFileInfo(Options::indiServer()).dir().path();
0688 #endif
0689 
0690     QStringList paths;
0691     paths << "/usr/bin"
0692           << "/usr/local/bin" << indiServerDir;
0693 
0694     if (QStandardPaths::findExecutable("indiserver").isEmpty())
0695     {
0696         if (QStandardPaths::findExecutable("indiserver", paths).isEmpty())
0697         {
0698             KSNotification::error(i18n(
0699                                       "Unable to find INDI server. Please make sure the package that provides "
0700                                       "the 'indiserver' binary is installed."));
0701             return;
0702         }
0703     }
0704 #endif
0705     GUIManager::Instance()->updateStatus(true);
0706 #endif
0707 }
0708 
0709 void KStars::slotINDIDriver()
0710 {
0711 #ifdef HAVE_INDI
0712 #ifndef Q_OS_WIN
0713 
0714     if (KMessageBox::warningContinueCancel(
0715                 nullptr,
0716                 i18n("INDI Device Manager should only be used by advanced technical users. "
0717                      "It cannot be used with Ekos. Do you still want to open INDI device "
0718                      "manager?"),
0719                 i18n("INDI Device Manager"), KStandardGuiItem::cont(),
0720                 KStandardGuiItem::cancel(),
0721                 "indi_device_manager_warning") == KMessageBox::Cancel)
0722         return;
0723 
0724     QString indiServerDir = Options::indiServer();
0725 
0726 #ifdef Q_OS_OSX
0727     if (Options::indiServerIsInternal())
0728         indiServerDir = QCoreApplication::applicationDirPath();
0729     else
0730         indiServerDir = QFileInfo(Options::indiServer()).dir().path();
0731 #endif
0732 
0733     QStringList paths;
0734     paths << "/usr/bin"
0735           << "/usr/local/bin" << indiServerDir;
0736 
0737     if (QStandardPaths::findExecutable("indiserver").isEmpty())
0738     {
0739         if (QStandardPaths::findExecutable("indiserver", paths).isEmpty())
0740         {
0741             KSNotification::error(i18n(
0742                                       "Unable to find INDI server. Please make sure the package that provides "
0743                                       "the 'indiserver' binary is installed."));
0744             return;
0745         }
0746     }
0747 #endif
0748 
0749     DriverManager::Instance()->raise();
0750     DriverManager::Instance()->activateWindow();
0751     DriverManager::Instance()->showNormal();
0752 
0753 #endif
0754 }
0755 
0756 void KStars::slotEkos()
0757 {
0758 #ifdef HAVE_CFITSIO
0759 #ifdef HAVE_INDI
0760 
0761 #ifndef Q_OS_WIN
0762 
0763     QString indiServerDir = Options::indiServer();
0764 
0765 #ifdef Q_OS_OSX
0766     if (Options::indiServerIsInternal())
0767         indiServerDir = QCoreApplication::applicationDirPath();
0768     else
0769         indiServerDir = QFileInfo(Options::indiServer()).dir().path();
0770 #endif
0771 
0772     QStringList paths;
0773     paths << "/usr/bin"
0774           << "/usr/local/bin" << indiServerDir;
0775 
0776     if (QStandardPaths::findExecutable("indiserver").isEmpty())
0777     {
0778         if (QStandardPaths::findExecutable("indiserver", paths).isEmpty())
0779         {
0780             KSNotification::error(i18n(
0781                                       "Unable to find INDI server. Please make sure the package that provides "
0782                                       "the 'indiserver' binary is installed."));
0783             return;
0784         }
0785     }
0786 #endif
0787 
0788     if (Ekos::Manager::Instance()->isVisible() &&
0789             Ekos::Manager::Instance()->isActiveWindow())
0790     {
0791         Ekos::Manager::Instance()->hide();
0792     }
0793     else
0794     {
0795         Ekos::Manager::Instance()->raise();
0796         Ekos::Manager::Instance()->activateWindow();
0797         Ekos::Manager::Instance()->showNormal();
0798     }
0799 
0800 #endif
0801 #endif
0802 }
0803 
0804 void KStars::slotINDITelescopeTrack()
0805 {
0806 #ifdef HAVE_INDI
0807     if (m_KStarsData == nullptr || INDIListener::Instance() == nullptr)
0808         return;
0809 
0810     for (auto &oneDevice : INDIListener::devices())
0811     {
0812         if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
0813             continue;
0814 
0815         auto mount = oneDevice->getMount();
0816         if (!mount || mount->isConnected() == false)
0817             continue;
0818 
0819         KToggleAction *a = qobject_cast<KToggleAction *>(sender());
0820 
0821         if (a != nullptr)
0822         {
0823             mount->setTrackEnabled(a->isChecked());
0824             return;
0825         }
0826     }
0827 #endif
0828 }
0829 
0830 void KStars::slotINDITelescopeSlew(bool focused_object)
0831 {
0832 #ifdef HAVE_INDI
0833     if (m_KStarsData == nullptr || INDIListener::Instance() == nullptr)
0834         return;
0835 
0836     for (auto &oneDevice : INDIListener::devices())
0837     {
0838         if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
0839             continue;
0840 
0841         auto mount = oneDevice->getMount();
0842         if (!mount || mount->isConnected() == false)
0843             continue;
0844         if (focused_object)
0845         {
0846             if (m_SkyMap->focusObject() != nullptr)
0847                 mount->Slew(m_SkyMap->focusObject());
0848         }
0849         else
0850             mount->Slew(m_SkyMap->mousePoint());
0851 
0852         return;
0853     }
0854 #else
0855     Q_UNUSED(focused_object)
0856 #endif
0857 }
0858 
0859 void KStars::slotINDITelescopeSlewMousePointer()
0860 {
0861 #ifdef HAVE_INDI
0862     slotINDITelescopeSlew(false);
0863 #endif
0864 }
0865 
0866 void KStars::slotINDITelescopeSync(bool focused_object)
0867 {
0868 #ifdef HAVE_INDI
0869     if (m_KStarsData == nullptr || INDIListener::Instance() == nullptr)
0870         return;
0871 
0872     for (auto &oneDevice : INDIListener::devices())
0873     {
0874         if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
0875             continue;
0876 
0877         auto mount = oneDevice->getMount();
0878         if (!mount || mount->isConnected() == false)
0879             continue;
0880 
0881         if (focused_object)
0882         {
0883             if (m_SkyMap->focusObject() != nullptr)
0884                 mount->Sync(m_SkyMap->focusObject());
0885         }
0886         else
0887             mount->Sync(m_SkyMap->mousePoint());
0888 
0889         return;
0890     }
0891 #else
0892     Q_UNUSED(focused_object)
0893 #endif
0894 }
0895 
0896 void KStars::slotINDITelescopeSyncMousePointer()
0897 {
0898 #ifdef HAVE_INDI
0899     slotINDITelescopeSync(false);
0900 #endif
0901 }
0902 
0903 void KStars::slotINDITelescopeAbort()
0904 {
0905 #ifdef HAVE_INDI
0906     if (m_KStarsData == nullptr || INDIListener::Instance() == nullptr)
0907         return;
0908 
0909     for (auto &oneDevice : INDIListener::devices())
0910     {
0911         if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
0912             continue;
0913 
0914         auto mount = oneDevice->getMount();
0915         if (!mount || mount->isConnected() == false)
0916             continue;
0917 
0918         mount->abort();
0919         return;
0920     }
0921 #endif
0922 }
0923 
0924 void KStars::slotINDITelescopePark()
0925 {
0926 #ifdef HAVE_INDI
0927     if (m_KStarsData == nullptr || INDIListener::Instance() == nullptr)
0928         return;
0929 
0930     for (auto &oneDevice : INDIListener::devices())
0931     {
0932         if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
0933             continue;
0934 
0935         auto mount = oneDevice->getMount();
0936         if (!mount || mount->isConnected() == false || mount->canPark() == false)
0937             continue;
0938 
0939         mount->park();
0940         return;
0941     }
0942 #endif
0943 }
0944 
0945 void KStars::slotINDITelescopeUnpark()
0946 {
0947 #ifdef HAVE_INDI
0948     if (m_KStarsData == nullptr || INDIListener::Instance() == nullptr)
0949         return;
0950 
0951     for (auto &oneDevice : INDIListener::devices())
0952     {
0953         if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
0954             continue;
0955 
0956         auto mount = oneDevice->getMount();
0957         if (!mount || mount->isConnected() == false || mount->canPark() == false)
0958             continue;
0959 
0960         mount->unpark();
0961         return;
0962     }
0963 #endif
0964 }
0965 
0966 void KStars::slotINDIDomePark()
0967 {
0968 #ifdef HAVE_INDI
0969     if (m_KStarsData == nullptr || INDIListener::Instance() == nullptr)
0970         return;
0971 
0972     for (auto &oneDevice : INDIListener::devices())
0973     {
0974         if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::DOME_INTERFACE))
0975             continue;
0976 
0977         auto dome = oneDevice->getDome();
0978         if (!dome || dome->isConnected() == false)
0979             continue;
0980         if (dome->canPark())
0981         {
0982             dome->park();
0983             return;
0984         }
0985     }
0986 #endif
0987 }
0988 
0989 void KStars::slotINDIDomeUnpark()
0990 {
0991 #ifdef HAVE_INDI
0992     if (m_KStarsData == nullptr || INDIListener::Instance() == nullptr)
0993         return;
0994 
0995     for (auto &oneDevice : INDIListener::devices())
0996     {
0997         if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::DOME_INTERFACE))
0998             continue;
0999 
1000         auto dome = oneDevice->getDome();
1001         if (!dome || dome->isConnected() == false)
1002             continue;
1003         if (dome->canPark())
1004         {
1005             dome->unpark();
1006             return;
1007         }
1008     }
1009 #endif
1010 }
1011 
1012 void KStars::slotGeoLocator()
1013 {
1014     QPointer<LocationDialog> locationdialog = new LocationDialog(this);
1015     if (locationdialog->exec() == QDialog::Accepted)
1016     {
1017         GeoLocation *newLocation = locationdialog->selectedCity();
1018         if (newLocation)
1019         {
1020             // set new location in options
1021             data()->setLocation(*newLocation);
1022 
1023             // adjust local time to keep UT the same.
1024             // create new LT without DST offset
1025             KStarsDateTime ltime = newLocation->UTtoLT(data()->ut());
1026 
1027             // reset timezonerule to compute next dst change
1028             newLocation->tzrule()->reset_with_ltime(ltime, newLocation->TZ0(),
1029                                                     data()->isTimeRunningForward());
1030 
1031             // reset next dst change time
1032             data()->setNextDSTChange(newLocation->tzrule()->nextDSTChange());
1033 
1034             // reset local sideral time
1035             data()->syncLST();
1036 
1037             // Make sure Numbers, Moon, planets, and sky objects are updated immediately
1038             data()->setFullTimeUpdate();
1039 
1040             // If the sky is in Horizontal mode and not tracking, reset focus such that
1041             // Alt/Az remain constant.
1042             if (!Options::isTracking() && Options::useAltAz())
1043             {
1044                 map()->focus()->HorizontalToEquatorial(data()->lst(),
1045                                                        data()->geo()->lat());
1046             }
1047 
1048             // recalculate new times and objects
1049             data()->setSnapNextFocus();
1050             updateTime();
1051         }
1052     }
1053     delete locationdialog;
1054 }
1055 
1056 void KStars::slotViewOps()
1057 {
1058     // An instance of your dialog could be already created and could be cached,
1059     // in which case you want to display the cached dialog instead of creating
1060     // another one
1061     auto ops = prepareOps();
1062     ops->show();
1063     // Bring to the front.
1064     ops->raise();  // for MacOS
1065     ops->activateWindow(); // for Windows
1066 }
1067 
1068 KConfigDialog *KStars::prepareOps()
1069 {
1070     KConfigDialog *dialog = KConfigDialog::exists("settings");
1071     if (nullptr != dialog)
1072         return dialog;
1073 
1074     // KConfigDialog didn't find an instance of this dialog, so lets create it :
1075     dialog = new KConfigDialog(this, "settings", Options::self());
1076 
1077     // For some reason the dialog does not resize to contents
1078     // so we set initial 'resonable' size here. Any better way to do this?
1079     dialog->resize(800, 600);
1080 #ifdef Q_OS_OSX
1081     dialog->setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
1082 #endif
1083 
1084     connect(dialog, SIGNAL(settingsChanged(QString)), this,
1085             SLOT(slotApplyConfigChanges()));
1086 
1087     opcatalog     = new OpsCatalog();
1088     opguides      = new OpsGuides();
1089     opterrain     = new OpsTerrain();
1090     opsdeveloper     = new OpsDeveloper();
1091     opsolsys      = new OpsSolarSystem();
1092     opssatellites = new OpsSatellites();
1093     opssupernovae = new OpsSupernovae();
1094     opcolors      = new OpsColors();
1095     opadvanced    = new OpsAdvanced();
1096 
1097     KPageWidgetItem *page;
1098 
1099     page = dialog->addPage(opcatalog, i18n("Catalogs"), "kstars_catalog");
1100     page->setIcon(QIcon::fromTheme("kstars_catalog"));
1101 
1102     page = dialog->addPage(opsolsys, i18n("Solar System"), "kstars_solarsystem");
1103     page->setIcon(QIcon::fromTheme("kstars_solarsystem"));
1104 
1105     page = dialog->addPage(opssatellites, i18n("Satellites"), "kstars_satellites");
1106     page->setIcon(QIcon::fromTheme("kstars_satellites"));
1107 
1108     page = dialog->addPage(opssupernovae, i18n("Supernovae"), "kstars_supernovae");
1109     page->setIcon(QIcon::fromTheme("kstars_supernovae"));
1110 
1111     page = dialog->addPage(opguides, i18n("Guides"), "kstars_guides");
1112     page->setIcon(QIcon::fromTheme("kstars_guides"));
1113 
1114     page = dialog->addPage(opterrain, i18n("Terrain"), "kstars_terrain");
1115     page->setIcon(QIcon::fromTheme("kstars_terrain", QIcon(":/icons/kstars_terrain.png")));
1116 
1117 
1118     page = dialog->addPage(opcolors, i18n("Colors"), "kstars_colors");
1119     page->setIcon(QIcon::fromTheme("kstars_colors"));
1120 
1121 #ifdef HAVE_CFITSIO
1122     opsfits = new OpsFITS();
1123     page    = dialog->addPage(opsfits, i18n("FITS"), "kstars_fitsviewer");
1124     page->setIcon(QIcon::fromTheme("kstars_fitsviewer"));
1125 #endif
1126 
1127 #ifdef HAVE_INDI
1128     opsindi = new OpsINDI();
1129     page    = dialog->addPage(opsindi, i18n("INDI"), "kstars_indi");
1130     page->setIcon(QIcon::fromTheme("kstars_indi"));
1131 #ifdef HAVE_CFITSIO
1132     opsekos                     = new OpsEkos();
1133     KPageWidgetItem *ekosOption = dialog->addPage(opsekos, i18n("Ekos"), "kstars_ekos");
1134     ekosOption->setIcon(QIcon::fromTheme("kstars_ekos"));
1135     if (Ekos::Manager::Instance())
1136         Ekos::Manager::Instance()->setOptionsWidget(ekosOption, opsekos);
1137 #endif
1138 
1139 #endif
1140 
1141     opsxplanet = new OpsXplanet(this);
1142     page       = dialog->addPage(opsxplanet, i18n("Xplanet"), "kstars_xplanet");
1143     page->setIcon(QIcon::fromTheme("kstars_xplanet"));
1144 
1145     page = dialog->addPage(opadvanced, i18n("Advanced"), "kstars_advanced");
1146     page->setIcon(QIcon::fromTheme("kstars_advanced"));
1147 
1148     page = dialog->addPage(opsdeveloper, i18n("Developer"), "kstars_developer");
1149     page->setIcon(QIcon::fromTheme("kstars_developer", QIcon(":/icons/kstars_developer.png")));
1150 
1151 #ifdef Q_OS_OSX // This is because KHelpClient doesn't seem to be working right on MacOS
1152     dialog->button(QDialogButtonBox::Help)->disconnect();
1153     connect(dialog->button(QDialogButtonBox::Help), &QPushButton::clicked, this, []()
1154     {
1155         KStars::Instance()->appHelpActivated();
1156     });
1157 #endif
1158 
1159     return dialog;
1160 }
1161 
1162 void KStars::syncOps()
1163 {
1164     opterrain->syncOptions();
1165     actionCollection()->action("toggle_terrain")
1166     ->setText(Options::showTerrain() ? i18n("Hide Terrain") : i18n("Show Terrain"));
1167 }
1168 
1169 void KStars::slotApplyConfigChanges()
1170 {
1171     Options::self()->save();
1172 
1173     applyConfig();
1174 
1175     //data()->setFullTimeUpdate();
1176     //map()->forceUpdate();
1177 }
1178 
1179 void KStars::slotApplyWIConfigChanges()
1180 {
1181     Options::self()->save();
1182     applyConfig();
1183     m_WIView->updateObservingConditions();
1184     m_WIView->onReloadIconClicked();
1185 }
1186 
1187 void KStars::slotSetTime()
1188 {
1189     QPointer<TimeDialog> timedialog = new TimeDialog(data()->lt(), data()->geo(), this);
1190 
1191     if (timedialog->exec() == QDialog::Accepted)
1192     {
1193         data()->changeDateTime(data()->geo()->LTtoUT(timedialog->selectedDateTime()));
1194 
1195         if (Options::useAltAz())
1196         {
1197             if (map()->focusObject())
1198             {
1199                 map()->focusObject()->EquatorialToHorizontal(data()->lst(),
1200                         data()->geo()->lat());
1201                 map()->setFocus(map()->focusObject());
1202             }
1203             else
1204                 map()->focus()->HorizontalToEquatorial(data()->lst(),
1205                                                        data()->geo()->lat());
1206         }
1207 
1208         map()->forceUpdateNow();
1209 
1210         //If focusObject has a Planet Trail, clear it and start anew.
1211         KSPlanetBase *planet = dynamic_cast<KSPlanetBase *>(map()->focusObject());
1212         if (planet && planet->hasTrail())
1213         {
1214             planet->clearTrail();
1215             planet->addToTrail();
1216         }
1217     }
1218     delete timedialog;
1219 }
1220 
1221 //Set Time to CPU clock
1222 void KStars::slotSetTimeToNow()
1223 {
1224     data()->changeDateTime(KStarsDateTime::currentDateTimeUtc());
1225 
1226     if (Options::useAltAz())
1227     {
1228         if (map()->focusObject())
1229         {
1230             map()->focusObject()->EquatorialToHorizontal(data()->lst(),
1231                     data()->geo()->lat());
1232             map()->setFocus(map()->focusObject());
1233         }
1234         else
1235             map()->focus()->HorizontalToEquatorial(data()->lst(), data()->geo()->lat());
1236     }
1237 
1238     map()->forceUpdateNow();
1239 
1240     //If focusObject has a Planet Trail, clear it and start anew.
1241     KSPlanetBase *planet = dynamic_cast<KSPlanetBase *>(map()->focusObject());
1242     if (planet && planet->hasTrail())
1243     {
1244         planet->clearTrail();
1245         planet->addToTrail();
1246     }
1247 }
1248 
1249 void KStars::slotFind()
1250 {
1251     //clearCachedFindDialog();
1252     SkyObject *targetObject = nullptr;
1253     if (FindDialog::Instance()->exec() == QDialog::Accepted &&
1254             (targetObject = FindDialog::Instance()->targetObject()))
1255     {
1256         map()->setClickedObject(targetObject);
1257         map()->setClickedPoint(map()->clickedObject());
1258         map()->slotCenter();
1259     }
1260 
1261     // check if data has changed while dialog was open
1262     //if (DialogIsObsolete)
1263     //    clearCachedFindDialog();
1264 }
1265 
1266 void KStars::slotOpenFITS()
1267 {
1268 #ifdef HAVE_CFITSIO
1269 
1270     static QUrl path = QUrl::fromLocalFile(QDir::homePath());
1271     QUrl fileURL =
1272         QFileDialog::getOpenFileUrl(KStars::Instance(), i18nc("@title:window", "Open Image"), path,
1273                                     "Images (*.fits *.fits.fz *.fit *.fts "
1274                                     "*.jpg *.jpeg *.png *.gif *.bmp "
1275                                     "*.cr2 *.cr3 *.crw *.nef *.raf *.dng *.arw *.orf)");
1276     if (fileURL.isEmpty())
1277         return;
1278 
1279     // Remember last directory
1280     path.setUrl(fileURL.url(QUrl::RemoveFilename));
1281 
1282     QPointer<FITSViewer> fv = createFITSViewer();
1283     connect(fv, &FITSViewer::failed, [ &, fv](const QString & errorMessage)
1284     {
1285         KSNotification::error(errorMessage, i18n("Open FITS"), 10);
1286         fv->close();
1287     });
1288 
1289     fv->loadFile(fileURL, FITS_NORMAL, FITS_NONE, QString());
1290 #endif
1291 }
1292 
1293 void KStars::slotExportImage()
1294 {
1295     //TODO Check this
1296     //For remote files, this returns
1297     //QFileInfo::absolutePath: QFileInfo::absolutePath: Constructed with empty filename
1298     //As of 2014-07-19
1299     //QUrl fileURL = KFileDialog::getSaveUrl( QDir::homePath(), "image/png image/jpeg image/gif image/x-portable-pixmap image/bmp image/svg+xml" );
1300     QUrl fileURL =
1301         QFileDialog::getSaveFileUrl(KStars::Instance(), i18nc("@title:window", "Export Image"), QUrl(),
1302                                     "Images (*.png *.jpeg *.gif *.bmp *.svg)");
1303 
1304     //User cancelled file selection dialog - abort image export
1305     if (fileURL.isEmpty())
1306     {
1307         return;
1308     }
1309 
1310     //Warn user if file exists!
1311     if (QFile::exists(fileURL.toLocalFile()))
1312     {
1313         int r = KMessageBox::warningContinueCancel(
1314                     parentWidget(),
1315                     i18n("A file named \"%1\" already exists. Overwrite it?", fileURL.fileName()),
1316                     i18n("Overwrite File?"), KStandardGuiItem::overwrite());
1317         if (r == KMessageBox::Cancel)
1318             return;
1319     }
1320 
1321     // execute image export dialog
1322 
1323     // Note: We don't let ExportImageDialog create its own ImageExporter because we want legend settings etc to be remembered between UI use and DBus scripting interface use.
1324     //if ( !m_ImageExporter )
1325     //m_ImageExporter = new ImageExporter( this );
1326 
1327     if (!m_ExportImageDialog)
1328     {
1329         m_ExportImageDialog = new ExportImageDialog(
1330             fileURL.toLocalFile(), QSize(map()->width(), map()->height()),
1331             KStarsData::Instance()->imageExporter());
1332     }
1333     else
1334     {
1335         m_ExportImageDialog->setOutputUrl(fileURL.toLocalFile());
1336         m_ExportImageDialog->setOutputSize(QSize(map()->width(), map()->height()));
1337     }
1338 
1339     m_ExportImageDialog->show();
1340 }
1341 
1342 void KStars::slotRunScript()
1343 {
1344     QUrl fileURL = QFileDialog::getOpenFileUrl(
1345                        KStars::Instance(), QString(), QUrl(QDir::homePath()),
1346                        "*.kstars|" +
1347                        i18nc("Filter by file type: KStars Scripts.", "KStars Scripts (*.kstars)"));
1348     QFile f;
1349     //QString fname;
1350 
1351     if (fileURL.isValid())
1352     {
1353         if (fileURL.isLocalFile() == false)
1354         {
1355             KSNotification::sorry(i18n("Executing remote scripts is not supported."));
1356             return;
1357         }
1358 
1359         f.setFileName(fileURL.toLocalFile());
1360 
1361         if (!f.open(QIODevice::ReadOnly))
1362         {
1363             QString message = i18n("Could not open file %1", f.fileName());
1364             KSNotification::sorry(message, i18n("Could Not Open File"));
1365             return;
1366         }
1367 
1368         QTextStream istream(&f);
1369         QString line;
1370         bool fileOK(true);
1371 
1372         while (!istream.atEnd())
1373         {
1374             line = istream.readLine();
1375             if (line.at(0) != '#' && line.left(9) != "dbus-send")
1376             {
1377                 fileOK = false;
1378                 break;
1379             }
1380         }
1381 
1382         if (!fileOK)
1383         {
1384             int answer;
1385             answer = KMessageBox::warningContinueCancel(
1386                          nullptr,
1387                          i18n(
1388                              "The selected script contains unrecognized elements, "
1389                              "indicating that it was not created using the KStars script builder. "
1390                              "This script may not function properly, and it may even contain "
1391                              "malicious code. "
1392                              "Would you like to execute it anyway?"),
1393                          i18n("Script Validation Failed"), KGuiItem(i18n("Run Nevertheless")),
1394                          KStandardGuiItem::cancel(), "daExecuteScript");
1395             if (answer == KMessageBox::Cancel)
1396                 return;
1397         }
1398 
1399         //Add statusbar message that script is running
1400         statusBar()->showMessage(i18n("Running script: %1", fileURL.fileName()));
1401 
1402         // 2017-09-19: Jasem
1403         // FIXME This is a hack and does not work on non-Linux systems
1404         // The Script Builder should generate files that can run cross-platform
1405         QProcess p;
1406         QStringList arguments;
1407         p.start(f.fileName(), arguments);
1408         if (!p.waitForStarted())
1409             return;
1410 
1411         while (!p.waitForFinished(10))
1412         {
1413             qApp->processEvents(); //otherwise tempfile may get deleted before script completes.
1414             if (p.state() != QProcess::Running)
1415                 break;
1416         }
1417 
1418         statusBar()->showMessage(i18n("Script finished."), 0);
1419     }
1420 }
1421 
1422 void KStars::slotPrint()
1423 {
1424     bool switchColors(false);
1425 
1426     //Suggest Chart color scheme
1427     if (data()->colorScheme()->colorNamed("SkyColor") != QColor(255, 255, 255))
1428     {
1429         QString message =
1430             i18n("You can save printer ink by using the \"Star Chart\" "
1431                  "color scheme, which uses a white background. Would you like to "
1432                  "temporarily switch to the Star Chart color scheme for printing?");
1433 
1434         int answer = KMessageBox::questionYesNoCancel(
1435                          nullptr, message, i18n("Switch to Star Chart Colors?"),
1436                          KGuiItem(i18n("Switch Color Scheme")), KGuiItem(i18n("Do Not Switch")),
1437                          KStandardGuiItem::cancel(), "askAgainPrintColors");
1438 
1439         if (answer == KMessageBox::Cancel)
1440             return;
1441         if (answer == KMessageBox::Yes)
1442             switchColors = true;
1443     }
1444 
1445     printImage(true, switchColors);
1446 }
1447 
1448 void KStars::slotPrintingWizard()
1449 {
1450     if (m_PrintingWizard)
1451     {
1452         delete m_PrintingWizard;
1453     }
1454 
1455     m_PrintingWizard = new PrintingWizard(this);
1456     m_PrintingWizard->show();
1457 }
1458 
1459 void KStars::slotToggleTimer()
1460 {
1461     if (data()->clock()->isActive())
1462     {
1463         data()->clock()->stop();
1464         updateTime();
1465     }
1466     else
1467     {
1468         if (fabs(data()->clock()->scale()) > Options::slewTimeScale())
1469             data()->clock()->setManualMode(true);
1470         data()->clock()->start();
1471         if (data()->clock()->isManualMode())
1472             map()->forceUpdate();
1473     }
1474 
1475     // Update clock state in options
1476     Options::setRunClock(data()->clock()->isActive());
1477 }
1478 
1479 void KStars::slotStepForward()
1480 {
1481     if (data()->clock()->isActive())
1482         data()->clock()->stop();
1483     data()->clock()->manualTick(true);
1484     map()->forceUpdate();
1485 }
1486 
1487 void KStars::slotStepBackward()
1488 {
1489     if (data()->clock()->isActive())
1490         data()->clock()->stop();
1491     data()->clock()->manualTick(true, true);
1492     map()->forceUpdate();
1493 }
1494 
1495 //Pointing
1496 void KStars::slotPointFocus()
1497 {
1498     // In the following cases, we set slewing=true in order to disengage tracking
1499     map()->stopTracking();
1500 
1501     if (sender() == actionCollection()->action("zenith"))
1502         map()->setDestinationAltAz(dms(90.0), map()->focus()->az(),
1503                                    Options::useRefraction());
1504     else if (sender() == actionCollection()->action("north"))
1505         map()->setDestinationAltAz(dms(15.0), dms(0.0001), Options::useRefraction());
1506     else if (sender() == actionCollection()->action("east"))
1507         map()->setDestinationAltAz(dms(15.0), dms(90.0), Options::useRefraction());
1508     else if (sender() == actionCollection()->action("south"))
1509         map()->setDestinationAltAz(dms(15.0), dms(180.0), Options::useRefraction());
1510     else if (sender() == actionCollection()->action("west"))
1511         map()->setDestinationAltAz(dms(15.0), dms(270.0), Options::useRefraction());
1512 }
1513 
1514 void KStars::slotTrack()
1515 {
1516     if (Options::isTracking())
1517     {
1518         Options::setIsTracking(false);
1519         actionCollection()->action("track_object")->setText(i18n("Engage &Tracking"));
1520         actionCollection()
1521         ->action("track_object")
1522         ->setIcon(QIcon::fromTheme("document-decrypt"));
1523 
1524         KSPlanetBase *planet = dynamic_cast<KSPlanetBase *>(map()->focusObject());
1525         if (planet && data()->temporaryTrail)
1526         {
1527             planet->clearTrail();
1528             data()->temporaryTrail = false;
1529         }
1530 
1531         map()->setClickedObject(nullptr);
1532         map()->setFocusObject(nullptr); //no longer tracking focusObject
1533         map()->setFocusPoint(nullptr);
1534     }
1535     else
1536     {
1537         map()->setClickedPoint(map()->focus());
1538         map()->setClickedObject(nullptr);
1539         map()->setFocusObject(nullptr); //no longer tracking focusObject
1540         map()->setFocusPoint(map()->clickedPoint());
1541         Options::setIsTracking(true);
1542         actionCollection()->action("track_object")->setText(i18n("Stop &Tracking"));
1543         actionCollection()
1544         ->action("track_object")
1545         ->setIcon(QIcon::fromTheme("document-encrypt"));
1546     }
1547 
1548     map()->forceUpdate();
1549 }
1550 
1551 void KStars::slotManualFocus()
1552 {
1553     QPointer<FocusDialog> focusDialog = new FocusDialog();
1554 
1555     // JM 2019-09-04: Should default to RA/DE always
1556     //    if (Options::useAltAz())
1557     //        focusDialog->activateAzAltPage();
1558 
1559     if (focusDialog->exec() == QDialog::Accepted)
1560     {
1561         //If the requested position is very near the pole, we need to point first
1562         //to an intermediate location just below the pole in order to get the longitudinal
1563         //position (RA/Az) right.
1564 
1565         // Do not access (RA0, Dec0) of focusDialog->point() as it can be of unknown epoch.
1566         // (RA, Dec) should be synced to JNow
1567         // -- asimha (2020-07-06)
1568         double realAlt(focusDialog->point()->alt().Degrees());
1569         double realDec(focusDialog->point()->dec().Degrees());
1570         if (Options::useAltAz() && realAlt > 89.0)
1571         {
1572             focusDialog->point()->setAlt(89.0);
1573             focusDialog->point()->HorizontalToEquatorial(data()->lst(),
1574                     data()->geo()->lat());
1575         }
1576         if (!Options::useAltAz() && realDec > 89.0)
1577         {
1578             focusDialog->point()->setDec(89.0);
1579             focusDialog->point()->EquatorialToHorizontal(data()->lst(),
1580                     data()->geo()->lat());
1581         }
1582 
1583         map()->setClickedPoint(focusDialog->point());
1584 
1585         if (Options::isTracking())
1586             slotTrack();
1587 
1588         map()->slotCenter();
1589 
1590         //The slew takes some time to complete, and this often causes the final focus point to be slightly
1591         //offset from the user's requested coordinates (because EquatorialToHorizontal() is called
1592         //throughout the process, which depends on the sidereal time).  So we now "polish" the final
1593         //position by resetting the final focus to the focusDialog point.
1594         //
1595         //Also, if the requested position was within 1 degree of the coordinate pole, this will
1596         //automatically correct the final pointing from the intermediate offset position to the final position
1597         data()->setSnapNextFocus();
1598         if (Options::useAltAz())
1599         {
1600             // N.B. We have applied unrefract() in focusDialog
1601             map()->setDestinationAltAz(focusDialog->point()->alt(),
1602                                        focusDialog->point()->az(), false);
1603         }
1604         else
1605         {
1606             map()->setDestination(focusDialog->point()->ra(),
1607                                   focusDialog->point()->dec());
1608         }
1609 
1610         //Now, if the requested point was near a pole, we need to reset the Alt/Dec of the focus.
1611         if (Options::useAltAz() && realAlt > 89.0)
1612             map()->focus()->setAlt(realAlt);
1613         if (!Options::useAltAz() && realDec > 89.0)
1614             map()->focus()->setDec(realAlt);
1615 
1616         //Don't track if we set Alt/Az coordinates.  This way, Alt/Az remain constant.
1617         if (focusDialog->usedAltAz())
1618             map()->stopTracking();
1619     }
1620     delete focusDialog;
1621 }
1622 
1623 void KStars::slotZoomChanged()
1624 {
1625     // Enable/disable actions
1626     actionCollection()->action("zoom_out")->setEnabled(Options::zoomFactor() > MINZOOM);
1627     actionCollection()->action("zoom_in")->setEnabled(Options::zoomFactor() < MAXZOOM);
1628     // Update status bar
1629     map()
1630     ->setupProjector(); // this needs to be run redundantly, so that the FOV returned below is up-to-date.
1631     float fov                      = map()->projector()->fov();
1632     KLocalizedString fovi18nstring =
1633         ki18nc("approximate field of view", "Approximate FOV: %1 degrees");
1634     if (fov < 1.0)
1635     {
1636         fov           = fov * 60.0;
1637         fovi18nstring =
1638             ki18nc("approximate field of view", "Approximate FOV: %1 arcminutes");
1639     }
1640     if (fov < 1.0)
1641     {
1642         fov           = fov * 60.0;
1643         fovi18nstring =
1644             ki18nc("approximate field of view", "Approximate FOV: %1 arcseconds");
1645     }
1646     QString fovstring = fovi18nstring.subs(QString::number(fov, 'f', 1)).toString();
1647 
1648     statusBar()->showMessage(fovstring, 0);
1649 }
1650 
1651 void KStars::slotSetZoom()
1652 {
1653     bool ok;
1654     double currentAngle = map()->width() / (Options::zoomFactor() * dms::DegToRad);
1655     double minAngle     = map()->width() / (MAXZOOM * dms::DegToRad);
1656     double maxAngle     = map()->width() / (MINZOOM * dms::DegToRad);
1657 
1658     double angSize = QInputDialog::getDouble(
1659                          nullptr,
1660                          i18nc("The user should enter an angle for the field-of-view of the display",
1661                                "Enter Desired Field-of-View Angle"),
1662                          i18n("Enter a field-of-view angle in degrees: "), currentAngle, minAngle,
1663                          maxAngle, 1, &ok);
1664 
1665     if (ok)
1666     {
1667         map()->setZoomFactor(map()->width() / (angSize * dms::DegToRad));
1668     }
1669 }
1670 
1671 void KStars::slotCoordSys()
1672 {
1673     if (Options::useAltAz())
1674     {
1675         Options::setUseAltAz(false);
1676         if (Options::useRefraction())
1677         {
1678             if (map()->focusObject()) //simply update focus to focusObject's position
1679                 map()->setFocus(map()->focusObject());
1680             else //need to recompute focus for unrefracted position
1681             {
1682                 // FIXME: Changed focus()->alt() to be unrefracted by convention; is this still necessary? -- asimha 2020/07/05
1683                 map()->setFocusAltAz(map()->focus()->alt(), map()->focus()->az());
1684                 map()->focus()->HorizontalToEquatorial(data()->lst(),
1685                                                        data()->geo()->lat());
1686             }
1687         }
1688         actionCollection()
1689         ->action("coordsys")
1690         ->setText(i18n("Switch to Horizonal View (Horizontal &Coordinates)"));
1691     }
1692     else
1693     {
1694         Options::setUseAltAz(true);
1695         if (Options::useRefraction())
1696         {
1697             // FIXME: Changed focus()->alt() to be unrefracted by convention; is this still necessary? -- asimha 2020/07/05
1698             map()->setFocusAltAz(map()->focus()->alt(), map()->focus()->az());
1699         }
1700         actionCollection()
1701         ->action("coordsys")
1702         ->setText(i18n("Switch to Star Globe View (Equatorial &Coordinates)"));
1703     }
1704     map()->forceUpdate();
1705 }
1706 
1707 void KStars::slotMapProjection()
1708 {
1709     if (sender() == actionCollection()->action("project_lambert"))
1710         Options::setProjection(Projector::Lambert);
1711     if (sender() == actionCollection()->action("project_azequidistant"))
1712         Options::setProjection(Projector::AzimuthalEquidistant);
1713     if (sender() == actionCollection()->action("project_orthographic"))
1714         Options::setProjection(Projector::Orthographic);
1715     if (sender() == actionCollection()->action("project_equirectangular"))
1716         Options::setProjection(Projector::Equirectangular);
1717     if (sender() == actionCollection()->action("project_stereographic"))
1718         Options::setProjection(Projector::Stereographic);
1719     if (sender() == actionCollection()->action("project_gnomonic"))
1720         Options::setProjection(Projector::Gnomonic);
1721 
1722     //DEBUG
1723     qCDebug(KSTARS) << "Projection system: " << Options::projection();
1724 
1725     m_SkyMap->forceUpdate();
1726 }
1727 
1728 //Settings Menu:
1729 void KStars::slotColorScheme()
1730 {
1731     loadColorScheme(sender()->objectName());
1732 }
1733 
1734 void KStars::slotTargetSymbol(bool flag)
1735 {
1736     qDebug() << Q_FUNC_INFO << QString("slotTargetSymbol: %1 %2").arg(sender()->objectName()).arg(flag);
1737 
1738     QStringList names = Options::fOVNames();
1739     if (flag)
1740     {
1741         // Add FOV to list
1742         names.append(sender()->objectName());
1743     }
1744     else
1745     {
1746         // Remove FOV from list
1747         int ix = names.indexOf(sender()->objectName());
1748         if (ix >= 0)
1749             names.removeAt(ix);
1750     }
1751     Options::setFOVNames(names);
1752 
1753     // Sync visibleFOVs with fovNames
1754     data()->syncFOV();
1755 
1756     map()->forceUpdate();
1757 }
1758 
1759 void KStars::slotHIPSSource()
1760 {
1761     QAction *selectedAction = qobject_cast<QAction *>(sender());
1762     Q_ASSERT(selectedAction != nullptr);
1763 
1764     QString selectedSource = selectedAction->text().remove('&');
1765 
1766     // selectedSource could be translated, while we need to send only Latin "None"
1767     // to Hips manager.
1768     if (selectedSource == i18n("None"))
1769         HIPSManager::Instance()->setCurrentSource("None");
1770     else
1771         HIPSManager::Instance()->setCurrentSource(selectedSource);
1772 
1773     map()->forceUpdate();
1774 }
1775 
1776 void KStars::slotFOVEdit()
1777 {
1778     QPointer<FOVDialog> fovdlg = new FOVDialog(this);
1779     if (fovdlg->exec() == QDialog::Accepted)
1780     {
1781         FOVManager::save();
1782         repopulateFOV();
1783     }
1784     delete fovdlg;
1785 }
1786 
1787 void KStars::slotObsList()
1788 {
1789     m_KStarsData->observingList()->show();
1790 }
1791 
1792 void KStars::slotEquipmentWriter()
1793 {
1794     QPointer<EquipmentWriter> equipmentdlg = new EquipmentWriter();
1795     equipmentdlg->loadEquipment();
1796     equipmentdlg->exec();
1797     delete equipmentdlg;
1798 }
1799 
1800 void KStars::slotObserverManager()
1801 {
1802     QPointer<ObserverAdd> m_observerAdd = new ObserverAdd();
1803     m_observerAdd->exec();
1804     delete m_observerAdd;
1805 }
1806 
1807 void KStars::slotHorizonManager()
1808 {
1809     if (!m_HorizonManager)
1810     {
1811         m_HorizonManager = new HorizonManager(this);
1812         connect(m_SkyMap, SIGNAL(positionClicked(SkyPoint *)), m_HorizonManager,
1813                 SLOT(addSkyPoint(SkyPoint *)));
1814     }
1815 
1816     m_HorizonManager->show();
1817 }
1818 
1819 void KStars::slotEyepieceView(SkyPoint *sp, const QString &imagePath)
1820 {
1821     if (!m_EyepieceView)
1822         m_EyepieceView = new EyepieceField(this);
1823 
1824     // FIXME: Move FOV choice into the Eyepiece View tool itself.
1825     bool ok        = true;
1826     const FOV *fov = nullptr;
1827     if (!data()->getAvailableFOVs().isEmpty())
1828     {
1829         // Ask the user to choose from a list of available FOVs.
1830         //int index;
1831         const FOV *f;
1832         QMap<QString, const FOV *> nameToFovMap;
1833         foreach (f, data()->getAvailableFOVs())
1834         {
1835             nameToFovMap.insert(f->name(), f);
1836         }
1837         nameToFovMap.insert(i18n("Attempt to determine from image"), nullptr);
1838         fov = nameToFovMap[QInputDialog::getItem(
1839                                this, i18n("Eyepiece View: Choose a field-of-view"),
1840                                i18n("FOV to render eyepiece view for:"), nameToFovMap.keys(), 0, false,
1841                                &ok)];
1842     }
1843     if (ok)
1844         m_EyepieceView->showEyepieceField(sp, fov, imagePath);
1845 }
1846 
1847 void KStars::slotExecute()
1848 {
1849     KStarsData::Instance()->executeSession()->init();
1850     KStarsData::Instance()->executeSession()->show();
1851 }
1852 
1853 void KStars::slotPolarisHourAngle()
1854 {
1855     QPointer<PolarisHourAngle> pHourAngle = new PolarisHourAngle(this);
1856     pHourAngle->exec();
1857 }
1858 
1859 //Help Menu
1860 void KStars::slotTipOfDay()
1861 {
1862     KTipDialog::showTip(this, "kstars/tips", true);
1863 }
1864 
1865 // Toggle to and from full screen mode
1866 void KStars::slotFullScreen()
1867 {
1868     if (topLevelWidget()->isFullScreen())
1869     {
1870         topLevelWidget()->setWindowState(topLevelWidget()->windowState() &
1871                                          ~Qt::WindowFullScreen); // reset
1872     }
1873     else
1874     {
1875         topLevelWidget()->setWindowState(topLevelWidget()->windowState() |
1876                                          Qt::WindowFullScreen); // set
1877     }
1878 }
1879 
1880 // Toggle to and from full screen mode
1881 void KStars::slotTerrain()
1882 {
1883     Options::setShowTerrain(!Options::showTerrain());
1884     actionCollection()->action("toggle_terrain")
1885     ->setText(Options::showTerrain() ? i18n("Hide Terrain") : i18n("Show Terrain"));
1886     KStars::Instance()->map()->forceUpdate();
1887 }
1888 
1889 void KStars::slotClearAllTrails()
1890 {
1891     //Exclude object with temporary trail
1892     SkyObject *exOb(nullptr);
1893     if (map()->focusObject() && map()->focusObject()->isSolarSystem() &&
1894             data()->temporaryTrail)
1895     {
1896         exOb = map()->focusObject();
1897     }
1898 
1899     TrailObject::clearTrailsExcept(exOb);
1900 
1901     map()->forceUpdate();
1902 }
1903 
1904 //toggle display of GUI Items on/off
1905 void KStars::slotShowGUIItem(bool show)
1906 {
1907     //Toolbars
1908     if (sender() == actionCollection()->action("show_statusBar"))
1909     {
1910         Options::setShowStatusBar(show);
1911         statusBar()->setVisible(show);
1912     }
1913 
1914     if (sender() == actionCollection()->action("show_sbAzAlt"))
1915     {
1916         Options::setShowAltAzField(show);
1917         AltAzField.setHidden(!show);
1918     }
1919 
1920     if (sender() == actionCollection()->action("show_sbRADec"))
1921     {
1922         Options::setShowRADecField(show);
1923         RADecField.setHidden(!show);
1924     }
1925 
1926     if (sender() == actionCollection()->action("show_sbJ2000RADec"))
1927     {
1928         Options::setShowJ2000RADecField(show);
1929         J2000RADecField.setHidden(!show);
1930     }
1931 }
1932 void KStars::addColorMenuItem(QString name, const QString &actionName)
1933 {
1934     KToggleAction *kta     = actionCollection()->add<KToggleAction>(actionName);
1935     const QString filename = QString(actionName).mid(3) + ".colors";
1936     kta->setText(name);
1937     kta->setObjectName(filename);
1938     kta->setActionGroup(cschemeGroup);
1939 
1940     colorActionMenu->addAction(kta);
1941 
1942     KConfigGroup cg = KSharedConfig::openConfig()->group("Colors");
1943     if (actionName.mid(3) ==
1944             cg.readEntry("ColorSchemeFile", "moonless-night.colors").remove(".colors"))
1945     {
1946         kta->setChecked(true);
1947     }
1948 
1949     //use mid(3) to exclude the leading "cs_" prefix from the action name
1950     data()->add_color_scheme(filename, name.replace("&", ""));
1951     connect(kta, SIGNAL(toggled(bool)), this, SLOT(slotColorScheme()));
1952 }
1953 
1954 void KStars::removeColorMenuItem(const QString &actionName)
1955 {
1956     qCDebug(KSTARS) << "removing " << actionName;
1957     colorActionMenu->removeAction(actionCollection()->action(actionName));
1958 }
1959 
1960 void KStars::slotAboutToQuit()
1961 {
1962     if (m_SkyMap == nullptr)
1963         return;
1964 
1965 #ifdef HAVE_INDI
1966     DriverManager::Instance()->disconnectClients();
1967     INDIListener::Instance()->disconnect();
1968     GUIManager::Instance()->disconnect();
1969 #endif
1970 
1971     // Delete skymap. This required to run destructors and save
1972     // current state in the option.
1973     delete m_SkyMap;
1974     m_SkyMap = nullptr;
1975 
1976     //Store Window geometry in Options object
1977     Options::setWindowWidth(width());
1978     Options::setWindowHeight(height());
1979 
1980     //explicitly save the colorscheme data to the config file
1981     data()->colorScheme()->saveToConfig();
1982 
1983     //synch the config file with the Config object
1984     writeConfig();
1985 
1986     //Terminate Child Processes if on OS X
1987 #ifdef Q_OS_OSX
1988     QProcess *quit = new QProcess(this);
1989     quit->start("killall kdeinit5");
1990     quit->waitForFinished(1000);
1991     quit->start("killall klauncher");
1992     quit->waitForFinished(1000);
1993     quit->start("killall kioslave");
1994     quit->waitForFinished(1000);
1995     quit->start("killall kio_http_cache_cleaner");
1996     quit->waitForFinished(1000);
1997     delete quit;
1998 #endif
1999 }
2000 
2001 void KStars::slotShowPositionBar(SkyPoint *p)
2002 {
2003     if (Options::showAltAzField())
2004     {
2005         dms a = p->alt();
2006         if (Options::useAltAz())
2007             a = p->altRefracted();
2008         QString s =
2009             QString("%1, %2").arg(p->az().toDMSString(true), //true: force +/- symbol
2010                                   a.toDMSString(true));      //true: force +/- symbol
2011         //statusBar()->changeItem( s, 1 );
2012         AltAzField.setText(s);
2013     }
2014     if (Options::showRADecField())
2015     {
2016         KStarsDateTime lastUpdate;
2017         lastUpdate.setDJD(KStarsData::Instance()->updateNum()->getJD());
2018         QString sEpoch = QString::number(lastUpdate.epoch(), 'f', 1);
2019         QString s      = QString("%1, %2 (J%3)")
2020                          .arg(p->ra().toHMSString(), p->dec().toDMSString(true),
2021                               sEpoch); //true: force +/- symbol
2022         //statusBar()->changeItem( s, 2 );
2023         RADecField.setText(s);
2024     }
2025 
2026     if (Options::showJ2000RADecField())
2027     {
2028         SkyPoint p0;
2029         //p0        = p->deprecess(KStarsData::Instance()->updateNum()); // deprecess to update RA0/Dec0 from RA/Dec
2030         p0 = p->catalogueCoord(KStarsData::Instance()->updateNum()->julianDay());
2031         QString s = QString("%1, %2 (J2000)")
2032                     .arg(p0.ra().toHMSString(),
2033                          p0.dec().toDMSString(true)); //true: force +/- symbol
2034         //statusBar()->changeItem( s, 2 );
2035         J2000RADecField.setText(s);
2036     }
2037 }
2038 
2039 void KStars::slotUpdateComets(bool isAutoUpdate)
2040 {
2041     data()->skyComposite()->solarSystemComposite()->cometsComponent()->updateDataFile(
2042         isAutoUpdate);
2043 }
2044 
2045 void KStars::slotUpdateAsteroids(bool isAutoUpdate)
2046 {
2047     data()->skyComposite()->solarSystemComposite()->asteroidsComponent()->updateDataFile(
2048         isAutoUpdate);
2049 }
2050 
2051 void KStars::slotUpdateSupernovae()
2052 {
2053     data()->skyComposite()->supernovaeComponent()->slotTriggerDataFileUpdate();
2054 }
2055 
2056 void KStars::slotUpdateSatellites()
2057 {
2058     data()->skyComposite()->satellites()->updateTLEs();
2059 }
2060 
2061 void KStars::slotConfigureNotifications()
2062 {
2063 #ifdef HAVE_NOTIFYCONFIG
2064     KNotifyConfigWidget::configure(this);
2065 #endif
2066 }
2067 void KStars::slotDSOCatalogGUI()
2068 {
2069     auto *ui = new CatalogsDBUI{ this, CatalogsDB::dso_db_path() };
2070     ui->show();
2071     connect(ui, &QDialog::finished, this, [&](const auto)
2072     {
2073         KStars::Instance()->data()->skyComposite()->catalogsComponent()->dropCache();
2074     });
2075 }