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