File indexing completed on 2024-04-28 03:50:24

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2011 Guillaume Martres <smarter@ubuntu.com>
0004 // SPDX-FileCopyrightText: 2012 Rene Kuettner <rene@bitkanal.net>
0005 //
0006 
0007 #include "SatellitesPlugin.h"
0008 
0009 #include "MarbleDebug.h"
0010 #include "MarbleWidget.h"
0011 #include "MarbleWidgetPopupMenu.h"
0012 #include "MarbleModel.h"
0013 #include "GeoDataPlacemark.h"
0014 #include "SatellitesMSCItem.h"
0015 #include "SatellitesTLEItem.h"
0016 #include "SatellitesConfigLeafItem.h"
0017 #include "SatellitesConfigNodeItem.h"
0018 #include "SatellitesConfigModel.h"
0019 #include "ViewportParams.h"
0020 
0021 #include "ui_SatellitesConfigDialog.h"
0022 
0023 #include <QAction>
0024 #include <QUrl>
0025 #include <QMouseEvent>
0026 
0027 namespace Marble
0028 {
0029 
0030 SatellitesPlugin::SatellitesPlugin( const MarbleModel *marbleModel )
0031     : RenderPlugin( marbleModel ),
0032      m_satModel( nullptr ),
0033      m_isInitialized( false ),
0034      m_configDialog(nullptr)
0035 {
0036     connect( this, SIGNAL(settingsChanged(QString)), SLOT(updateSettings()) );
0037     connect( this, SIGNAL(enabledChanged(bool)), SLOT(enableModel(bool)) );
0038     connect( this, SIGNAL(visibilityChanged(bool,QString)), SLOT(visibleModel(bool)) );
0039 
0040     setVisible( false );
0041     setSettings(QHash<QString, QVariant>());
0042 
0043     m_showOrbitAction = new QAction( tr( "Display orbit" ), this );
0044     m_showOrbitAction->setCheckable( true );
0045     m_showOrbitAction->setData( 0 );
0046 
0047     m_trackPlacemarkAction = new QAction( tr( "Keep centered" ), this );
0048     m_trackPlacemarkAction->setData( 0 );
0049     connect( m_showOrbitAction, SIGNAL(triggered(bool)), SLOT(showOrbit(bool)) );
0050     connect( m_trackPlacemarkAction, SIGNAL(triggered(bool)), SLOT(trackPlacemark()) );
0051 }
0052 
0053 SatellitesPlugin::~SatellitesPlugin()
0054 {
0055     delete m_satModel;
0056 
0057     delete m_configDialog;
0058     delete m_showOrbitAction;
0059     delete m_trackPlacemarkAction;
0060 }
0061 
0062 QStringList SatellitesPlugin::backendTypes() const
0063 {
0064     return QStringList(QStringLiteral("satellites"));
0065 }
0066 
0067 QString SatellitesPlugin::renderPolicy() const
0068 {
0069     return QStringLiteral("ALWAYS");
0070 }
0071 
0072 QStringList SatellitesPlugin::renderPosition() const
0073 {
0074     return QStringList(QStringLiteral("ORBIT"));
0075 }
0076 
0077 QString SatellitesPlugin::name() const
0078 {
0079     return tr( "Satellites" );
0080 }
0081 
0082 QString SatellitesPlugin::nameId() const
0083 {
0084     return QStringLiteral("satellites");
0085 }
0086 
0087 QString SatellitesPlugin::guiString() const
0088 {
0089     return tr( "&Satellites" );
0090 }
0091 
0092 QString SatellitesPlugin::version() const
0093 {
0094     return QStringLiteral("2.0");
0095 }
0096 
0097 QString SatellitesPlugin::description() const
0098 {
0099     return tr( "This plugin displays satellites and their orbits." );
0100 }
0101 
0102 QString SatellitesPlugin::copyrightYears() const
0103 {
0104     return QStringLiteral("2012");
0105 }
0106 
0107 QVector<PluginAuthor> SatellitesPlugin::pluginAuthors() const
0108 {
0109     return QVector<PluginAuthor>()
0110             << PluginAuthor(QStringLiteral("Guillaume Martres"), QStringLiteral("smarter@ubuntu.com"))
0111             << PluginAuthor(QStringLiteral("Rene Kuettner"), QStringLiteral("rene@bitkanal.net"))
0112             << PluginAuthor(QStringLiteral("Gerhard Holtkamp"), QString());
0113 }
0114 
0115 QString SatellitesPlugin::aboutDataText() const
0116 {
0117     return tr(
0118         "Earth-Satellites orbital elements from <ul><li>"
0119         "<a href=\"https://www.celestrak.com\">https://www.celestrak.com</a>"
0120         "</li></ul>"
0121         "Planetary-Satellites orbital elements from <ul><li>"
0122         "<a href=\"https://ssd.jpl.nasa.gov/?horizons\">"
0123         "JPL Horizons</a></li></ul>" );
0124 }
0125 
0126 QIcon SatellitesPlugin::icon() const
0127 {
0128     return QIcon(QStringLiteral(":/data/bitmaps/satellite.png"));
0129 }
0130 
0131 RenderPlugin::RenderType SatellitesPlugin::renderType() const
0132 {
0133     return OnlineRenderType;
0134 }
0135 
0136 void SatellitesPlugin::initialize()
0137 {
0138     // FIXME: remove the const_cast, it may be best to create a new type of
0139     // plugins where marbleModel() is not const, since traditional
0140     // RenderPlugins do not require that
0141     m_satModel = new SatellitesModel(
0142         const_cast<MarbleModel *>( marbleModel() )->treeModel(),
0143         marbleModel()->clock() );
0144 
0145     m_configModel = new SatellitesConfigModel( this );
0146 
0147     delete m_configDialog;
0148     m_configDialog = new SatellitesConfigDialog();
0149     connect( m_configDialog, SIGNAL(activatePluginClicked()), this, SLOT(activate()) );
0150     connect( this, SIGNAL(visibilityChanged(bool,QString)),
0151              m_configDialog, SLOT(setDialogActive(bool)) );
0152     m_configDialog->configWidget()->treeView->setModel( m_configModel );
0153 
0154     connect( m_satModel, SIGNAL(fileParsed(QString)),
0155         SLOT(dataSourceParsed(QString)) );
0156     connect( m_satModel, SIGNAL(fileParsed(QString)),
0157         SLOT(updateDataSourceConfig(QString)) );
0158     connect( m_configDialog, SIGNAL(dataSourcesReloadRequested()),
0159         SLOT(updateSettings()) );
0160     connect( m_configDialog, SIGNAL(accepted()), SLOT(writeSettings()) );
0161     connect( m_configDialog, SIGNAL(rejected()), SLOT(readSettings()) );
0162     connect( m_configDialog->configWidget()->buttonBox->button(
0163         QDialogButtonBox::Reset ),
0164         SIGNAL(clicked()), SLOT(restoreDefaultSettings()) );
0165     connect( m_configDialog, SIGNAL(userDataSourcesChanged()),
0166         SLOT(writeSettings()) );
0167     connect( m_configDialog, SIGNAL(userDataSourceAdded(QString)),
0168         SLOT(userDataSourceAdded(QString)) );
0169 
0170     m_isInitialized = true;
0171     readSettings();
0172     updateSettings();
0173     enableModel( enabled() );
0174 }
0175 
0176 bool SatellitesPlugin::isInitialized() const
0177 {
0178     return m_isInitialized;
0179 }
0180 
0181 bool SatellitesPlugin::render( GeoPainter *painter, ViewportParams *viewport,
0182     const QString &renderPos, GeoSceneLayer *layer )
0183 {
0184     Q_UNUSED( painter );
0185     Q_UNUSED( viewport );
0186     Q_UNUSED( renderPos );
0187     Q_UNUSED( layer );
0188 
0189     enableModel( enabled() );
0190 
0191     return true;
0192 }
0193 
0194 bool SatellitesPlugin::eventFilter( QObject *object, QEvent *event )
0195 {
0196     // only if active plugin
0197     if( !enabled() || !visible() ) {
0198         return false;
0199     }
0200 
0201     if( event->type() != QEvent::MouseButtonPress )
0202     {
0203         return false;
0204     }
0205 
0206     MarbleWidget *widget = qobject_cast<MarbleWidget*> ( object );
0207     Q_ASSERT ( widget );
0208 
0209     QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>(event);
0210     Q_ASSERT( mouseEvent );
0211 
0212     if( mouseEvent->button() == Qt::LeftButton ) {
0213         m_trackerList.clear();
0214         QVector<const GeoDataFeature*> vector = widget->whichFeatureAt( mouseEvent->pos() );
0215         for (const GeoDataFeature *feature: vector) {
0216             const GeoDataPlacemark* placemark = dynamic_cast<const GeoDataPlacemark*>(feature);
0217             if ( placemark ) {
0218                 for (TrackerPluginItem *obj: m_satModel->items() ) {
0219                     if( obj->placemark() == placemark ) {
0220                         m_showOrbitAction->data() = m_trackerList.size();
0221                         m_showOrbitAction->setChecked( obj->isTrackVisible() );
0222                         widget->popupMenu()->addAction( Qt::LeftButton, m_showOrbitAction );
0223 
0224                         m_trackPlacemarkAction->data() = m_trackerList.size();
0225                         widget->popupMenu()->addAction( Qt::LeftButton, m_trackPlacemarkAction );
0226 
0227                         m_trackerList.append( obj );
0228                     }
0229                 }
0230             }
0231         }
0232     }
0233     return false;
0234 }
0235 
0236 void SatellitesPlugin::showOrbit(bool show)
0237 {
0238     QAction *action = qobject_cast<QAction *>( sender() );
0239     Q_ASSERT( action );
0240 
0241     int actionIndex = action->data().toInt();
0242     TrackerPluginItem *item = m_trackerList.at( actionIndex );
0243     item->setTrackVisible( show );
0244     m_satModel->updateVisibility();
0245 }
0246 
0247 void SatellitesPlugin::trackPlacemark()
0248 {
0249     QAction *action = qobject_cast<QAction *>( sender() );
0250     Q_ASSERT( action );
0251 
0252     int actionIndex = action->data().toInt();
0253     TrackerPluginItem *item = m_trackerList.at( actionIndex );
0254     const_cast<MarbleModel *>( marbleModel() )->setTrackedPlacemark( item->placemark() );
0255 }
0256 
0257 QHash<QString, QVariant> SatellitesPlugin::settings() const
0258 {
0259     QHash<QString, QVariant> result = RenderPlugin::settings();
0260 
0261     typedef QHash<QString, QVariant>::ConstIterator Iterator;
0262     Iterator end = m_settings.constEnd();
0263     for ( Iterator iter = m_settings.constBegin(); iter != end; ++iter ) {
0264         result.insert( iter.key(), iter.value() );
0265     }
0266 
0267     return result;
0268 }
0269 
0270 void SatellitesPlugin::setSettings( const QHash<QString, QVariant> &settings )
0271 {
0272     RenderPlugin::setSettings( settings );
0273 
0274     // reset
0275     m_newDataSources.clear();
0276     // TODO: cancel also all on-going downloads
0277 
0278     // add default data sources
0279     if (!settings.contains(QStringLiteral("dataSources"))) {
0280         QStringList dsList;
0281         dsList << QStringLiteral("https://www.celestrak.com/NORAD/elements/visual.txt");
0282         m_settings.insert(QStringLiteral("dataSources"), dsList);
0283         m_settings.insert(QStringLiteral("idList"), dsList);
0284     }
0285     else {
0286         // HACK: KConfig can't guess the type of the settings, when we use
0287         // KConfigGroup::readEntry() in marble_part it returns a QString which
0288         // is then wrapped into a QVariant when added to the settings hash.
0289         // QVariant can handle the conversion for some types, like toDateTime()
0290         // but when calling toStringList() on a QVariant::String, it will
0291         // return a one element list
0292         if (settings.value(QStringLiteral("dataSources")).type() == QVariant::String) {
0293             m_settings.insert(QStringLiteral("dataSources"),
0294                 settings.value(QStringLiteral("dataSources")).toString().split(QLatin1Char(',')));
0295         }
0296         if (settings.value(QStringLiteral("idList")).type() == QVariant::String) {
0297             m_settings.insert(QStringLiteral("idList"),
0298                 settings.value(QStringLiteral("idList")).toString().split(QLatin1Char(',')));
0299         }
0300     }
0301 
0302     // add default user data source
0303     if (!settings.contains(QStringLiteral("userDataSources"))) {
0304         QStringList udsList;
0305         udsList << QStringLiteral("http://files.kde.org/marble/satellites/PlanetarySatellites.msc");
0306         m_settings.insert(QStringLiteral("userDataSources"), udsList);
0307         userDataSourceAdded( udsList[0] );
0308     }
0309     else if (settings.value(QStringLiteral("userDataSources")).type() == QVariant::String) {
0310         // same HACK as above
0311         m_settings.insert(QStringLiteral("userDataSources"),
0312             settings.value(QStringLiteral("userDataSources")).toString().split(QLatin1Char(',')));
0313     }
0314 
0315     emit settingsChanged( nameId() );
0316 }
0317 
0318 void SatellitesPlugin::readSettings()
0319 {
0320     m_configDialog->setUserDataSources(
0321         m_settings.value(QStringLiteral("userDataSources")).toStringList());
0322     m_configModel->loadSettings( m_settings );
0323     m_satModel->loadSettings( m_settings );
0324 }
0325 
0326 void SatellitesPlugin::writeSettings()
0327 {
0328     m_settings.insert(QStringLiteral("userDataSources"), m_configDialog->userDataSources());
0329     m_settings.insert(QStringLiteral("dataSources"), m_configModel->urlList());
0330     m_settings.insert(QStringLiteral("idList"), m_configModel->idList());
0331 
0332     emit settingsChanged( nameId() );
0333 }
0334 
0335 void SatellitesPlugin::updateSettings()
0336 {
0337     if (!isInitialized()) {
0338         return;
0339     }
0340 
0341     // TODO: cancel also all on-going downloads
0342     m_satModel->clear();
0343     
0344     m_configModel->clear();
0345     addBuiltInDataSources();
0346 
0347     // (re)load data sources
0348     QStringList dsList = m_settings[QStringLiteral("dataSources")].toStringList();
0349     dsList << m_settings[QStringLiteral("userDataSources")].toStringList();
0350     dsList.removeDuplicates();
0351     for( const QString &ds: dsList ) {
0352         mDebug() << "Loading satellite data from:" << ds;
0353         m_satModel->downloadFile( QUrl( ds ), ds );
0354     }
0355 }
0356 
0357 void SatellitesPlugin::dataSourceParsed( const QString &source )
0358 {
0359     m_configDialog->setUserDataSourceLoaded( source, true );
0360 }
0361 
0362 void SatellitesPlugin::userDataSourceAdded( const QString &source )
0363 {
0364     // items contained in catalog data sources are not known before
0365     // the catalog has been parsed. so we store new data sources in
0366     // order to activate them later (new datasources are enabled by
0367     // default)
0368     if( !m_newDataSources.contains( source ) ) {
0369         m_newDataSources.append( source );
0370     }
0371 }
0372 
0373 SatellitesConfigDialog *SatellitesPlugin::configDialog()
0374 {
0375     return m_configDialog;
0376 }
0377 
0378 void SatellitesPlugin::activate()
0379 {
0380     action()->trigger();
0381 }
0382 
0383 void SatellitesPlugin::enableModel( bool enabled )
0384 {
0385     if ( !m_isInitialized ) {
0386         return;
0387     }
0388 
0389     m_satModel->setPlanet( marbleModel()->planetId() );
0390     m_satModel->enable( enabled && visible() );
0391 }
0392 
0393 void SatellitesPlugin::visibleModel( bool visible )
0394 {
0395     if ( !m_isInitialized ) {
0396         return;
0397     }
0398 
0399     m_satModel->setPlanet( marbleModel()->planetId() );
0400     m_satModel->enable( enabled() && visible );
0401 }
0402 
0403 void SatellitesPlugin::updateDataSourceConfig( const QString &source )
0404 {
0405     mDebug() << "Updating orbiter configuration";
0406 
0407     for( TrackerPluginItem *obj: m_satModel->items() ) {
0408         // catalog items
0409         SatellitesMSCItem *item = dynamic_cast<SatellitesMSCItem*>( obj );
0410         if( ( item != nullptr ) && ( item->catalog() == source ) ) {
0411             m_configDialog->addSatelliteItem(
0412                 item->relatedBody(),
0413                 item->category(),
0414                 item->name(),
0415                 item->id() );
0416         }
0417     }
0418 
0419     // activate new datasources by default
0420     if( m_newDataSources.contains( source ) ) {
0421         m_newDataSources.removeAll( source );
0422         activateDataSource( source );
0423     }
0424 
0425     readSettings();
0426     m_configDialog->update();
0427 }
0428 
0429 void SatellitesPlugin::activateDataSource( const QString &source )
0430 {
0431     // activate the given data source (select it)
0432     mDebug() << "Activating Data Source:" << source;
0433     QStringList list = m_configModel->fullIdList().filter( source );
0434     QStringList idList = m_settings[QStringLiteral("idList")].toStringList();
0435     idList << list;
0436     m_settings.insert(QStringLiteral("idList"), idList);
0437 }
0438 
0439 void SatellitesPlugin::addBuiltInDataSources()
0440 {
0441     QString currentCategory;
0442 
0443     currentCategory = tr("Special-Interest Satellites" );
0444     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Last 30 Days' Launches", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/tle-new.txt" );
0445     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Space Stations", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/stations.txt" );
0446     m_configDialog->addTLESatelliteItem( currentCategory, tr( "100 (or so) Brightest", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/visual.txt" );
0447     m_configDialog->addTLESatelliteItem( currentCategory, tr( "FENGYUN 1C Debris", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/1999-025.txt" );
0448     m_configDialog->addTLESatelliteItem( currentCategory, tr( "IRIDIUM 33 Debris", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/iridium-33-debris.txt" );
0449     m_configDialog->addTLESatelliteItem( currentCategory, tr( "COSMOS 2251 Debris", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/cosmos-2251-debris.txt" );
0450 
0451     currentCategory = tr( "Weather & Earth Resources Satellites" );
0452     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Weather", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/weather.txt" );
0453     m_configDialog->addTLESatelliteItem( currentCategory, tr( "NOAA", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/noaa.txt" );
0454     m_configDialog->addTLESatelliteItem( currentCategory, tr( "GOES", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/goes.txt" );
0455     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Earth Resources", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/resource.txt" );
0456     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Search & Rescue (SARSAT)", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/sarsat.txt" );
0457     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Disaster Monitoring", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/dmc.txt" );
0458     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Tracking and Data Relay Satellite System (TDRSS)", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/tdrss.txt" );
0459 
0460     currentCategory = tr( "Communications Satellites" );
0461     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Geostationary", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/geo.txt" );
0462     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Intelsat", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/intelsat.txt" );
0463     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Gorizont", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/gorizont.txt" );
0464     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Raduga", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/raduga.txt" );
0465     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Molniya", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/molniya.txt" );
0466     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Iridium", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/iridium.txt" );
0467     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Orbcomm", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/orbcomm.txt" );
0468     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Globalstar", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/globalstar.txt" );
0469     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Amateur radio", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/amateur.txt" );
0470     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Experimental", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/x-comm.txt" );
0471     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Other", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/other-comm.txt" );
0472 
0473     currentCategory = tr( "Navigation Satellites" );
0474     m_configDialog->addTLESatelliteItem( currentCategory, tr( "GPS Operational", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/gps-ops.txt" );
0475     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Glonass Operational", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/glo-ops.txt" );
0476     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Galileo", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/galileo.txt" );
0477     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Satellite-Based Augmentation System (WAAS/EGNOS/MSAS)", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/sbas.txt" );
0478     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Navy Navigation Satellite System (NNSS)", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/nnss.txt" );
0479     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Russian LEO Navigation", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/musson.txt" );
0480 
0481     currentCategory = tr( "Scientific Satellites" );
0482     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Space & Earth Science", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/science.txt" );
0483     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Geodetic", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/geodetic.txt" );
0484     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Engineering", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/engineering.txt" );
0485     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Education", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/education.txt" );
0486 
0487     currentCategory = tr( "Miscellaneous Satellites" );
0488     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Miscellaneous Military", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/military.txt" );
0489     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Radar Calibration", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/radar.txt" );
0490     m_configDialog->addTLESatelliteItem( currentCategory, tr( "CubeSats", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/cubesat.txt" );
0491     m_configDialog->addTLESatelliteItem( currentCategory, tr( "Other", "Name of a satellite group" ), "https://www.celestrak.com/NORAD/elements/other.txt" );
0492 
0493     readSettings();
0494     m_configDialog->update();
0495 }
0496 
0497 } // namespace Marble
0498 
0499 #include "moc_SatellitesPlugin.cpp"
0500