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 "kspopupmenu.h"
0008 
0009 #include "config-kstars.h"
0010 
0011 #include "kstars.h"
0012 #include "kstarsdata.h"
0013 #include "skymap.h"
0014 #include "skyobjects/skyobject.h"
0015 #include "skyobjects/starobject.h"
0016 #include "skyobjects/trailobject.h"
0017 #include "skyobjects/catalogobject.h"
0018 #include "skyobjects/ksmoon.h"
0019 #include "skyobjects/satellite.h"
0020 #include "skyobjects/supernova.h"
0021 #include "skycomponents/constellationboundarylines.h"
0022 #include "skycomponents/flagcomponent.h"
0023 #include "skycomponents/skymapcomposite.h"
0024 #include "skyobjectuserdata.h"
0025 #include "tools/whatsinteresting/wiview.h"
0026 #include "catalogsdb.h"
0027 #include "observinglist.h"
0028 
0029 #ifdef HAVE_INDI
0030 #include "indi/indilistener.h"
0031 #include "indi/guimanager.h"
0032 #include "indi/driverinfo.h"
0033 #include "indi/indistd.h"
0034 #include "indi/indidevice.h"
0035 #include "indi/indigroup.h"
0036 #include "indi/indiproperty.h"
0037 #include "indi/indielement.h"
0038 #include "indi/indimount.h"
0039 #include <basedevice.h>
0040 #endif
0041 
0042 #include <KLocalizedString>
0043 
0044 #include <QWidgetAction>
0045 
0046 namespace
0047 {
0048 // Convert magnitude to string representation for QLabel
0049 QString magToStr(double m)
0050 {
0051     if (m > -30 && m < 90)
0052         return QString("%1<sup>m</sup>").arg(m, 0, 'f', 2);
0053     else
0054         return QString();
0055 }
0056 
0057 // Return object name
0058 QString getObjectName(SkyObject *obj)
0059 {
0060     // FIXME: make logic less convoluted.
0061     if (obj->longname() != obj->name()) // Object has proper name
0062     {
0063         return obj->translatedLongName() + ", " + obj->translatedName();
0064     }
0065     else
0066     {
0067         if (!obj->translatedName2().isEmpty())
0068             return obj->translatedName() + ", " + obj->translatedName2();
0069         else
0070             return obj->translatedName();
0071     }
0072 }
0073 
0074 // String representation for rise/set time of object. If object
0075 // doesn't rise/set returns descriptive string.
0076 //
0077 // Second parameter choose between raise and set. 'true' for
0078 // raise, 'false' for set.
0079 QString riseSetTimeLabel(SkyObject *o, bool isRaise)
0080 {
0081     KStarsData *data = KStarsData::Instance();
0082     QTime t          = o->riseSetTime(data->ut(), data->geo(), isRaise);
0083     if (t.isValid())
0084     {
0085         //We can round to the nearest minute by simply adding 30 seconds to the time.
0086         QString time = QLocale().toString(t.addSecs(30), QLocale::ShortFormat);
0087         return isRaise ? i18n("Rise time: %1", time) :
0088                i18nc("the time at which an object falls below the horizon",
0089                      "Set time: %1", time);
0090     }
0091     if (o->alt().Degrees() > 0)
0092         return isRaise ? i18n("No rise time: Circumpolar") :
0093                i18n("No set time: Circumpolar");
0094     else
0095         return isRaise ? i18n("No rise time: Never rises") :
0096                i18n("No set time: Never rises");
0097 }
0098 
0099 // String representation for transit time for object
0100 QString transitTimeLabel(SkyObject *o)
0101 {
0102     KStarsData *data = KStarsData::Instance();
0103     QTime t          = o->transitTime(data->ut(), data->geo());
0104     if (t.isValid())
0105         //We can round to the nearest minute by simply adding 30 seconds to the time.
0106         return i18n("Transit time: %1",
0107                     QLocale().toString(t.addSecs(30), QLocale::ShortFormat));
0108     else
0109         return "--:--";
0110 }
0111 } // namespace
0112 
0113 KSPopupMenu::KSPopupMenu()
0114     : QMenu(KStars::Instance()), m_CurrentFlagIdx(-1), m_EditActionMapping(nullptr),
0115       m_DeleteActionMapping(nullptr)
0116 {
0117 }
0118 
0119 KSPopupMenu::~KSPopupMenu()
0120 {
0121     if (m_EditActionMapping)
0122     {
0123         delete m_EditActionMapping;
0124     }
0125 
0126     if (m_DeleteActionMapping)
0127     {
0128         delete m_DeleteActionMapping;
0129     }
0130 }
0131 
0132 void KSPopupMenu::createEmptyMenu(SkyPoint *nullObj)
0133 {
0134     KStars *ks = KStars::Instance();
0135     SkyObject o(SkyObject::TYPE_UNKNOWN, nullObj->ra(), nullObj->dec());
0136     o.setAlt(nullObj->alt());
0137     o.setAz(nullObj->az());
0138     initPopupMenu(&o, i18n("Empty sky"), QString(), QString(), false, false);
0139     addAction(i18nc("Sloan Digital Sky Survey", "Show SDSS Image"), ks->map(),
0140               SLOT(slotSDSS()));
0141     addAction(i18nc("Digitized Sky Survey", "Show DSS Image"), ks->map(),
0142               SLOT(slotDSS()));
0143 }
0144 
0145 void KSPopupMenu::slotEditFlag()
0146 {
0147     if (m_CurrentFlagIdx != -1)
0148     {
0149         KStars::Instance()->map()->slotEditFlag(m_CurrentFlagIdx);
0150     }
0151 }
0152 
0153 void KSPopupMenu::slotDeleteFlag()
0154 {
0155     if (m_CurrentFlagIdx != -1)
0156     {
0157         KStars::Instance()->map()->slotDeleteFlag(m_CurrentFlagIdx);
0158     }
0159 }
0160 
0161 void KSPopupMenu::slotEditFlag(QAction *action)
0162 {
0163     int idx = m_EditActionMapping->value(action, -1);
0164 
0165     if (idx == -1)
0166     {
0167         return;
0168     }
0169 
0170     else
0171     {
0172         KStars::Instance()->map()->slotEditFlag(idx);
0173     }
0174 }
0175 
0176 void KSPopupMenu::slotDeleteFlag(QAction *action)
0177 {
0178     int idx = m_DeleteActionMapping->value(action, -1);
0179 
0180     if (idx == -1)
0181     {
0182         return;
0183     }
0184 
0185     else
0186     {
0187         KStars::Instance()->map()->slotDeleteFlag(idx);
0188     }
0189 }
0190 
0191 void KSPopupMenu::createStarMenu(StarObject *star)
0192 {
0193     KStars *ks = KStars::Instance();
0194     //Add name, rise/set time, center/track, and detail-window items
0195     QString name;
0196     if (star->name() != "star")
0197     {
0198         name = star->translatedLongName();
0199     }
0200     else
0201     {
0202         if (star->getHDIndex())
0203         {
0204             name = QString("HD%1").arg(QString::number(star->getHDIndex()));
0205         }
0206         else
0207         {
0208             // FIXME: this should be some catalog name too
0209             name = "Star";
0210         }
0211     }
0212     initPopupMenu(star, name, i18n("star"),
0213                   i18n("%1<sup>m</sup>, %2", star->mag(), star->sptype()));
0214     //If the star is named, add custom items to popup menu based on object's ImageList and InfoList
0215     if (star->name() != "star")
0216     {
0217         addLinksToMenu(star);
0218     }
0219     else
0220     {
0221         addAction(i18nc("Sloan Digital Sky Survey", "Show SDSS Image"), ks->map(),
0222                   SLOT(slotSDSS()));
0223         addAction(i18nc("Digitized Sky Survey", "Show DSS Image"), ks->map(),
0224                   SLOT(slotDSS()));
0225     }
0226 }
0227 
0228 void KSPopupMenu::createCatalogObjectMenu(CatalogObject *obj)
0229 {
0230     QString name     = getObjectName(obj);
0231     QString typeName = obj->typeName();
0232 
0233     QString info = QString("%1<br>Catalog: %2")
0234                    .arg(magToStr(obj->mag()))
0235                    .arg(obj->getCatalog().name);
0236 
0237     if (obj->a() > 0)
0238     {
0239         float a = obj->a();
0240         float b = obj->b() > 0 ? obj->b() : obj->a(); // Assume circular if a != 0 but b == 0
0241         info += QString("<br>%1′×%2′").arg(a).arg(b);
0242     }
0243 
0244     initPopupMenu(obj, name, typeName, info);
0245     addLinksToMenu(obj);
0246 }
0247 
0248 void KSPopupMenu::createPlanetMenu(SkyObject *p)
0249 {
0250     QString info = magToStr(p->mag());
0251     QString type = i18n("Solar system object");
0252     initPopupMenu(p, p->translatedName(), type, info);
0253     addLinksToMenu(p, false); //don't offer DSS images for planets
0254 }
0255 
0256 void KSPopupMenu::createMoonMenu(KSMoon *moon)
0257 {
0258     QString info = QString("%1, %2").arg(magToStr(moon->mag()), moon->phaseName());
0259     initPopupMenu(moon, moon->translatedName(), QString(), info);
0260     addLinksToMenu(moon, false); //don't offer DSS images for planets
0261 }
0262 
0263 void KSPopupMenu::createSatelliteMenu(Satellite *satellite)
0264 {
0265     KStars *ks = KStars::Instance();
0266     QString velocity, altitude, range;
0267     velocity.setNum(satellite->velocity());
0268     altitude.setNum(satellite->altitude());
0269     range.setNum(satellite->range());
0270 
0271     clear();
0272 
0273     addFancyLabel(satellite->name());
0274     addFancyLabel(satellite->id());
0275     addFancyLabel(i18n("satellite"));
0276     addFancyLabel(KStarsData::Instance()
0277                   ->skyComposite()
0278                   ->constellationBoundary()
0279                   ->constellationName(satellite));
0280 
0281     addSeparator();
0282 
0283     addFancyLabel(i18n("Velocity: %1 km/s", velocity), -2);
0284     addFancyLabel(i18n("Altitude: %1 km", altitude), -2);
0285     addFancyLabel(i18n("Range: %1 km", range), -2);
0286 
0287     addSeparator();
0288 
0289     //Insert item for centering on object
0290     addAction(QIcon::fromTheme("snap-nodes-center"), i18n("Center && Track"), ks->map(),
0291               SLOT(slotCenter()));
0292     //Insert item for measuring distances
0293     //FIXME: add key shortcut to menu items properly!
0294     addAction(QIcon::fromTheme("kruler-east"),
0295               i18n("Angular Distance To...            ["), ks->map(),
0296               SLOT(slotBeginAngularDistance()));
0297     addAction(QIcon::fromTheme("show-path-outline"),
0298               i18n("Starhop from here to...            "), ks->map(),
0299               SLOT(slotBeginStarHop()));
0300     addAction(QIcon::fromTheme("edit-copy"), i18n("Copy TLE to Clipboard"), ks->map(),
0301               SLOT(slotCopyTLE()));
0302 
0303     //Insert "Add/Remove Label" item
0304     if (ks->map()->isObjectLabeled(satellite))
0305         addAction(QIcon::fromTheme("list-remove"), i18n("Remove Label"), ks->map(),
0306                   SLOT(slotRemoveObjectLabel()));
0307     else
0308         addAction(QIcon::fromTheme("label"), i18n("Attach Label"), ks->map(),
0309                   SLOT(slotAddObjectLabel()));
0310 
0311     addSeparator();
0312     addINDI();
0313 }
0314 
0315 void KSPopupMenu::createSupernovaMenu(Supernova *supernova)
0316 {
0317     QString name = supernova->name();
0318     float mag    = supernova->mag();
0319     float z      = supernova->getRedShift();
0320     QString type = supernova->getType();
0321 
0322     QString info;
0323 
0324     if (mag < 99)
0325         info += QString("%1<sup>m</sup> ").arg(mag);
0326     info += type;
0327     if (z < 99)
0328         info += QString(" z: %1").arg(QString::number(z, 'f', 2));
0329 
0330     initPopupMenu(supernova, name, i18n("supernova"), info);
0331 }
0332 
0333 void KSPopupMenu::initPopupMenu(SkyObject *obj, const QString &name, const QString &type,
0334                                 QString info, bool showDetails, bool showObsList,
0335                                 bool showFlags)
0336 {
0337     KStarsData *data = KStarsData::Instance();
0338     SkyMap *map      = SkyMap::Instance();
0339 
0340     clear();
0341     bool showLabel = (name != i18n("star") && !name.isEmpty());
0342     QString Name   = name;
0343 
0344     if (Name.isEmpty())
0345         Name = i18n("Empty sky");
0346 
0347     addFancyLabel(Name);
0348     addFancyLabel(type);
0349     addFancyLabel(info);
0350     addFancyLabel(KStarsData::Instance()
0351                   ->skyComposite()
0352                   ->constellationBoundary()
0353                   ->constellationName(obj));
0354 
0355     //Insert Rise/Set/Transit labels
0356     SkyObject *o = obj->clone();
0357     addSeparator();
0358     addFancyLabel(riseSetTimeLabel(o, true), -2);
0359     addFancyLabel(riseSetTimeLabel(o, false), -2);
0360     addFancyLabel(transitTimeLabel(o), -2);
0361     addSeparator();
0362     delete o;
0363 
0364     // Show 'Select this object' item when in object pointing mode and when obj is not empty sky
0365     if (map->isInObjectPointingMode() && obj->type() != 21)
0366     {
0367         addAction(i18n("Select this object"), map, SLOT(slotObjectSelected()));
0368     }
0369 
0370     //Insert item for centering on object
0371     addAction(QIcon::fromTheme("snap-nodes-center"), i18n("Center && Track"), map,
0372               SLOT(slotCenter()));
0373 
0374     if (showFlags)
0375     {
0376         //Insert actions for flag operations
0377         initFlagActions(obj);
0378     }
0379 
0380     //Insert item for measuring distances
0381     //FIXME: add key shortcut to menu items properly!
0382     addAction(QIcon::fromTheme("kruler-east"),
0383               i18n("Angular Distance To...            ["), map,
0384               SLOT(slotBeginAngularDistance()));
0385     addAction(QIcon::fromTheme("show-path-outline"),
0386               i18n("Starhop from here to...            "), map, SLOT(slotBeginStarHop()));
0387 
0388     //Insert item for Showing details dialog
0389     if (showDetails)
0390         addAction(QIcon::fromTheme("view-list-details"),
0391                   i18nc("Show Detailed Information Dialog", "Details"), map,
0392                   SLOT(slotDetail()));
0393 
0394     addAction(QIcon::fromTheme("edit-copy"), i18n("Copy Coordinates"), map,
0395               SLOT(slotCopyCoordinates()));
0396 
0397     //Insert "Add/Remove Label" item
0398     if (showLabel)
0399     {
0400         if (map->isObjectLabeled(obj))
0401         {
0402             addAction(QIcon::fromTheme("list-remove"), i18n("Remove Label"), map,
0403                       SLOT(slotRemoveObjectLabel()));
0404         }
0405         else
0406         {
0407             addAction(QIcon::fromTheme("label"), i18n("Attach Label"), map,
0408                       SLOT(slotAddObjectLabel()));
0409         }
0410     }
0411     // Should show observing list
0412     if (showObsList)
0413     {
0414         if (data->observingList()->contains(obj))
0415             addAction(QIcon::fromTheme("list-remove"),
0416                       i18n("Remove From Observing WishList"), data->observingList(),
0417                       SLOT(slotRemoveObject()));
0418         else
0419             addAction(QIcon::fromTheme("bookmarks"), i18n("Add to Observing WishList"),
0420                       data->observingList(), SLOT(slotAddObject()));
0421     }
0422     // Should we show trail actions
0423     TrailObject *t = dynamic_cast<TrailObject *>(obj);
0424     if (t)
0425     {
0426         if (t->hasTrail())
0427             addAction(i18n("Remove Trail"), map, SLOT(slotRemovePlanetTrail()));
0428         else
0429             addAction(i18n("Add Trail"), map, SLOT(slotAddPlanetTrail()));
0430     }
0431 
0432     addAction(QIcon::fromTheme("redeyes"), i18n("Simulate Eyepiece View"), map,
0433               SLOT(slotEyepieceView()));
0434 
0435     addSeparator();
0436     if (obj->isSolarSystem() &&
0437             obj->type() !=
0438             SkyObject::
0439             COMET) // FIXME: We now have asteroids -- so should this not be isMajorPlanet() || Pluto?
0440     {
0441         addAction(i18n("View in XPlanet"), map, SLOT(slotStartXplanetViewer()));
0442     }
0443     addSeparator();
0444     addINDI();
0445 
0446     addAction(QIcon::fromTheme("view-list-details"), i18n("View in What's Interesting"),
0447               this, SLOT(slotViewInWI()));
0448 }
0449 
0450 void KSPopupMenu::initFlagActions(SkyObject *obj)
0451 {
0452     KStars *ks = KStars::Instance();
0453 
0454     QList<int> flags = ks->data()->skyComposite()->flags()->getFlagsNearPix(obj, 5);
0455 
0456     if (flags.isEmpty())
0457     {
0458         // There is no flag around clicked SkyObject
0459         addAction(QIcon::fromTheme("flag"), i18n("Add Flag..."), ks->map(),
0460                   SLOT(slotAddFlag()));
0461     }
0462 
0463     else if (flags.size() == 1)
0464     {
0465         // There is only one flag around clicked SkyObject
0466         addAction(QIcon::fromTheme("document-edit"), i18n("Edit Flag"), this,
0467                   SLOT(slotEditFlag()));
0468         addAction(QIcon::fromTheme("delete"), i18n("Delete Flag"), this,
0469                   SLOT(slotDeleteFlag()));
0470 
0471         m_CurrentFlagIdx = flags.first();
0472     }
0473 
0474     else
0475     {
0476         // There are more than one flags around clicked SkyObject - we need to create submenus
0477         QMenu *editMenu = new QMenu(i18n("Edit Flag..."), KStars::Instance());
0478         editMenu->setIcon(QIcon::fromTheme("document-edit"));
0479         QMenu *deleteMenu = new QMenu(i18n("Delete Flag..."), KStars::Instance());
0480         deleteMenu->setIcon(QIcon::fromTheme("delete"));
0481 
0482         connect(editMenu, SIGNAL(triggered(QAction *)), this,
0483                 SLOT(slotEditFlag(QAction *)));
0484         connect(deleteMenu, SIGNAL(triggered(QAction *)), this,
0485                 SLOT(slotDeleteFlag(QAction *)));
0486 
0487         if (m_EditActionMapping)
0488         {
0489             delete m_EditActionMapping;
0490         }
0491 
0492         if (m_DeleteActionMapping)
0493         {
0494             delete m_DeleteActionMapping;
0495         }
0496 
0497         m_EditActionMapping   = new QHash<QAction *, int>;
0498         m_DeleteActionMapping = new QHash<QAction *, int>;
0499 
0500         foreach (int idx, flags)
0501         {
0502             QIcon flagIcon(
0503                 QPixmap::fromImage(ks->data()->skyComposite()->flags()->image(idx)));
0504 
0505             QString flagLabel = ks->data()->skyComposite()->flags()->label(idx);
0506             if (flagLabel.size() > 35)
0507             {
0508                 flagLabel = flagLabel.left(35);
0509                 flagLabel.append("...");
0510             }
0511 
0512             QAction *editAction = new QAction(flagIcon, flagLabel, ks);
0513             editAction->setIconVisibleInMenu(true);
0514             editMenu->addAction(editAction);
0515             m_EditActionMapping->insert(editAction, idx);
0516 
0517             QAction *deleteAction = new QAction(flagIcon, flagLabel, ks);
0518             deleteAction->setIconVisibleInMenu(true);
0519             deleteMenu->addAction(deleteAction);
0520             m_DeleteActionMapping->insert(deleteAction, idx);
0521         }
0522 
0523         addMenu(editMenu);
0524         addMenu(deleteMenu);
0525     }
0526 }
0527 
0528 void KSPopupMenu::addLinksToMenu(SkyObject *obj, bool showDSS)
0529 {
0530     KStars *ks = KStars::Instance();
0531 
0532     const auto &user_data    = KStarsData::Instance()->getUserData(obj->name());
0533     const auto &image_list   = user_data.images();
0534     const auto &website_list = user_data.websites();
0535     for (const auto &res : std::list <
0536             std::tuple<QString, SkyObjectUserdata::LinkList, SkyObjectUserdata::Type >>
0537 {
0538     { i18n("Image Resources"), image_list, SkyObjectUserdata::Type::image },
0539         { i18n("Web Links"), website_list, SkyObjectUserdata::Type::website }
0540     })
0541     {
0542         const auto &title = std::get<0>(res);
0543         const auto &list  = std::get<1>(res);
0544         const auto &type  = std::get<2>(res);
0545 
0546         if (!list.empty())
0547         {
0548             QMenu *LinkSubMenu = new QMenu();
0549             LinkSubMenu->setTitle(title);
0550             for (const auto &entry : list)
0551             {
0552                 QString t = QString(entry.title);
0553                 QAction *action;
0554                 if (type == SkyObjectUserdata::Type::website)
0555                     action = LinkSubMenu->addAction(
0556                         i18nc("Image/info menu item (should be translated)",
0557                               t.toLocal8Bit()),
0558                         ks->map(), SLOT(slotInfo()));
0559                 else
0560                     action = LinkSubMenu->addAction(
0561                         i18nc("Image/info menu item (should be translated)",
0562                               t.toLocal8Bit()),
0563                         ks->map(), SLOT(slotImage()));
0564 
0565                 action->setData(entry.url);
0566             }
0567             addMenu(LinkSubMenu);
0568         }
0569     }
0570 
0571     // Look for a custom object
0572     {
0573         auto *object = dynamic_cast<CatalogObject *>(obj);
0574         if (object)
0575         {
0576             CatalogsDB::DBManager manager{ CatalogsDB::dso_db_path() };
0577 
0578             if (object->getCatalog().mut &&
0579                     manager.get_object(object->getObjectId()).first)
0580             {
0581                 addAction(i18n("Remove From Local Catalog"), ks->map(),
0582                           SLOT(slotRemoveCustomObject()));
0583             }
0584         }
0585     }
0586 
0587     if (showDSS)
0588     {
0589         addAction(i18nc("Sloan Digital Sky Survey", "Show SDSS Image"), ks->map(),
0590                   SLOT(slotSDSS()));
0591         addAction(i18nc("Digitized Sky Survey", "Show DSS Image"), ks->map(),
0592                   SLOT(slotDSS()));
0593     }
0594 
0595     if (showDSS)
0596         addSeparator();
0597 }
0598 
0599 void KSPopupMenu::addINDI()
0600 {
0601 #ifdef HAVE_INDI
0602     if (INDIListener::Instance()->size() == 0)
0603         return;
0604 
0605     for (auto &oneDevice : INDIListener::devices())
0606     {
0607         if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
0608             continue;
0609 
0610 
0611         auto mount = oneDevice->getMount();
0612         if (!mount)
0613             continue;
0614 
0615         QMenu *mountMenu = new QMenu(mount->getDeviceName());
0616         mountMenu->setIcon(QIcon::fromTheme("kstars"));
0617         addMenu(mountMenu);
0618 
0619         if (mount->canGoto() || mount->canSync())
0620         {
0621             if (mount->canGoto())
0622             {
0623                 QAction *a = mountMenu->addAction(QIcon::fromTheme("object-rotate-right"),
0624                                                   i18nc("Move mount to target", "Goto"));
0625                 a->setEnabled(!mount->isParked());
0626                 connect(a, &QAction::triggered,
0627                         [mount] { mount->Slew(SkyMap::Instance()->clickedPoint()); });
0628             }
0629             if (mount->canSync())
0630             {
0631                 QAction *a =
0632                     mountMenu->addAction(QIcon::fromTheme("media-record"),
0633                                          i18nc("Synchronize mount to target", "Sync"));
0634                 a->setEnabled(!mount->isParked());
0635                 connect(a, &QAction::triggered,
0636                         [mount] { mount->Sync(SkyMap::Instance()->clickedPoint()); });
0637             }
0638 
0639             mountMenu->addSeparator();
0640         }
0641 
0642         if (mount->canAbort())
0643         {
0644             QAction *a =
0645                 mountMenu->addAction(QIcon::fromTheme("process-stop"), i18n("Abort"));
0646             a->setEnabled(!mount->isParked());
0647             connect(a, &QAction::triggered, [mount] { mount->abort(); });
0648             mountMenu->addSeparator();
0649         }
0650 
0651         if (mount->canPark())
0652         {
0653             QAction *park =
0654                 mountMenu->addAction(QIcon::fromTheme("flag-red"), i18n("Park"));
0655             park->setEnabled(!mount->isParked());
0656             connect(park, &QAction::triggered, [mount] { mount->park(); });
0657 
0658             QAction *unpark =
0659                 mountMenu->addAction(QIcon::fromTheme("flag-green"), i18n("UnPark"));
0660             unpark->setEnabled(mount->isParked());
0661             connect(unpark, &QAction::triggered, [mount] { mount->unpark(); });
0662 
0663             mountMenu->addSeparator();
0664         }
0665 
0666         const SkyObject *clickedObject = KStars::Instance()->map()->clickedObject();
0667         if (clickedObject && clickedObject->type() == SkyObject::SATELLITE &&
0668                 (mount->canTrackSatellite()))
0669         {
0670             const Satellite *sat = dynamic_cast<const Satellite *>(clickedObject);
0671             const KStarsDateTime currentTime        = KStarsData::Instance()->ut();
0672             const KStarsDateTime currentTimePlusOne = currentTime.addSecs(60);
0673             QAction *a =
0674                 mountMenu->addAction(QIcon::fromTheme("arrow"), i18n("Track satellite"));
0675             a->setEnabled(!mount->isParked());
0676             connect(a, &QAction::triggered,
0677                     [mount, sat, currentTime, currentTimePlusOne]
0678             {
0679                 mount->setSatelliteTLEandTrack(sat->tle(), currentTime,
0680                                                currentTimePlusOne);
0681             });
0682             mountMenu->addSeparator();
0683         }
0684 
0685         if (mount->canCustomPark())
0686         {
0687             QAction *a = mountMenu->addAction(QIcon::fromTheme("go-jump-declaration"),
0688                                               i18n("Goto && Set As Parking Position"));
0689             a->setEnabled(!mount->isParked());
0690             connect(a, &QAction::triggered,
0691                     [mount] { mount->setCustomParking(); });
0692         }
0693 
0694         QAction *a =
0695             mountMenu->addAction(QIcon::fromTheme("edit-find"), i18n("Find Telescope"));
0696         connect(a, &QAction::triggered,
0697                 [mount] { mount->find(); });
0698     }
0699 #endif
0700 }
0701 
0702 void KSPopupMenu::addFancyLabel(const QString &name, int deltaFontSize)
0703 {
0704     if (name.isEmpty())
0705         return;
0706     QLabel *label = new QLabel("<b>" + name + "</b>", this);
0707     label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
0708     if (deltaFontSize != 0)
0709     {
0710         QFont font = label->font();
0711         font.setPointSize(font.pointSize() + deltaFontSize);
0712         label->setFont(font);
0713     }
0714     QWidgetAction *act = new QWidgetAction(this);
0715     act->setDefaultWidget(label);
0716     addAction(act);
0717 }
0718 
0719 void KSPopupMenu::slotViewInWI()
0720 {
0721     if (!KStars::Instance()->map()->clickedObject())
0722         return;
0723     if (!KStars::Instance()->isWIVisible())
0724         KStars::Instance()->slotToggleWIView();
0725     KStars::Instance()->wiView()->inspectSkyObject(
0726         KStars::Instance()->map()->clickedObject());
0727 }