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

0001 // SPDX-License-Identifier: LGPL-2.1-or-later
0002 //
0003 // SPDX-FileCopyrightText: 2012 Rene Kuettner <rene@bitkanal.net>
0004 //
0005 
0006 #include "SatellitesConfigDialog.h"
0007 
0008 #include <QMessageBox>
0009 #include <QInputDialog>
0010 #include <QFileDialog>
0011 #include <QDateTime>
0012 #include <QUrl>
0013 
0014 #include "MarbleGlobal.h"
0015 #include "MarbleDebug.h"
0016 #include "SatellitesConfigNodeItem.h"
0017 #include "SatellitesConfigLeafItem.h"
0018 #include "SatellitesConfigModel.h"
0019 
0020 #include "ui_SatellitesConfigDialog.h"
0021 
0022 namespace Marble {
0023 
0024 SatellitesConfigDialog::SatellitesConfigDialog( QWidget *parent )
0025     : QDialog( parent )
0026 {
0027     initialize();
0028 
0029     // allow translation for catalog items
0030     // + categories
0031     m_translations["Comets"]        = tr( "Comets" );
0032     m_translations["Moons"]         = tr( "Moons" );
0033     m_translations["Other"]         = tr( "Other" );
0034     m_translations["Spacecrafts"]   = tr( "Spacecrafts" );
0035     m_translations["Spaceprobes"]  = tr( "Spaceprobes" );
0036     // + bodies
0037     m_translations["Moon"]          = tr( "Moon" );
0038     m_translations["Sun"]           = tr( "Sun" );
0039     m_translations["Mercury"]       = tr( "Mercury" );
0040     m_translations["Venus"]         = tr( "Venus" );
0041     m_translations["Earth"]         = tr( "Earth" );
0042     m_translations["Mars"]          = tr( "Mars" );
0043     m_translations["Jupiter"]       = tr( "Jupiter" );
0044     m_translations["Saturn"]        = tr( "Saturn" );
0045     m_translations["Uranus"]        = tr( "Uranus" );
0046     m_translations["Neptune"]       = tr( "Neptune" );
0047 }
0048 
0049 SatellitesConfigDialog::~SatellitesConfigDialog()
0050 {
0051 }
0052 
0053 void SatellitesConfigDialog::setUserDataSources( const QStringList &sources )
0054 {
0055     m_userDataSources = sources;
0056 
0057     // keep the first item
0058     for( int i = m_configWidget->listDataSources->count(); i > 1; --i ) {
0059         delete m_configWidget->listDataSources->takeItem( i-1 );
0060     }
0061 
0062     m_configWidget->listDataSources->addItems( m_userDataSources );
0063 }
0064 
0065 QStringList SatellitesConfigDialog::userDataSources() const
0066 {
0067     return m_userDataSources;
0068 }
0069 
0070 void SatellitesConfigDialog::setUserDataSourceLoaded( const QString &source,
0071                                                       bool loaded )
0072 {
0073     QList<QListWidgetItem*> list;
0074     list = m_configWidget->listDataSources->findItems( source,
0075                                                        Qt::MatchFixedString );
0076     if( list.count() > 0 ) {
0077         list[0]->setData( IsLoadedRole, QVariant( loaded ) );
0078     }
0079 
0080     QString date( QDateTime::currentDateTime().toString() );
0081     m_configWidget->labelLastUpdated->setText( date );
0082 }
0083 
0084 void SatellitesConfigDialog::update()
0085 {
0086     expandTreeView();
0087 
0088     QDialog::update();
0089 }
0090 
0091 SatellitesConfigAbstractItem*
0092 SatellitesConfigDialog::addSatelliteItem( const QString &body,
0093                                           const QString &category,
0094                                           const QString &title,
0095                                           const QString &id,
0096                                           const QString &url )
0097 {
0098     QString theTitle = translation( title );
0099 
0100     SatellitesConfigNodeItem *categoryItem;
0101     categoryItem = getSatellitesCategoryItem( body, category, true );
0102 
0103     // exists?
0104     for( int i = 0; i < categoryItem->childrenCount(); ++i ) {
0105         SatellitesConfigAbstractItem *absItem = categoryItem->childAt( i );
0106         if( ( absItem->data( 0, SatellitesConfigAbstractItem::IdListRole ) == id ) ) {
0107             return absItem;
0108         }
0109     }
0110 
0111     // add it
0112     SatellitesConfigLeafItem *newItem;
0113     newItem = new SatellitesConfigLeafItem( theTitle, id );
0114     if( !url.isNull() && !url.isEmpty() ) {
0115         newItem->setData( 0, SatellitesConfigAbstractItem::UrlListRole, url );
0116     }
0117     categoryItem->appendChild( newItem );
0118     return newItem;
0119 }
0120 
0121 SatellitesConfigAbstractItem*
0122 SatellitesConfigDialog::addTLESatelliteItem( const QString &category,
0123                                              const QString &title,
0124                                              const QString &url )
0125 {
0126     // TLE items always have their id set to their url and
0127     // are always related to the earth
0128     return addSatelliteItem( "Earth", category, title, url, url );
0129 }
0130 
0131 void SatellitesConfigDialog::setDialogActive( bool active )
0132 {
0133     m_configWidget->tabWidget->clear();
0134 
0135     if( active ) {
0136         m_configWidget->tabWidget->addTab( m_configWidget->tabSatellites,
0137                                            tr( "&Satellites" ) );
0138         m_configWidget->tabWidget->addTab( m_configWidget->tabDataSources,
0139                                            tr( "&Data Sources" ) );
0140     } else {
0141         m_configWidget->tabWidget->addTab( m_configWidget->tabDisabled,
0142                                            tr( "&Activate Plugin" ) );
0143     }
0144 
0145     QDialogButtonBox *bBox = m_configWidget->buttonBox;
0146     bBox->button( QDialogButtonBox::Ok )->setEnabled( active );
0147     bBox->button( QDialogButtonBox::Reset )->setEnabled( active );
0148 }
0149 
0150 Ui::SatellitesConfigDialog* SatellitesConfigDialog::configWidget()
0151 {
0152     return m_configWidget;
0153 }
0154 
0155 void SatellitesConfigDialog::initialize()
0156 {
0157     m_configWidget = new Ui::SatellitesConfigDialog();
0158     m_configWidget->setupUi( this );
0159 
0160     setupDataSourcesTab();
0161 
0162     setDialogActive( false );
0163     connect( m_configWidget->buttonDisabled, SIGNAL(clicked()),
0164              this, SIGNAL(activatePluginClicked()) );
0165 
0166     update();
0167 }
0168 
0169 void SatellitesConfigDialog::setupDataSourcesTab()
0170 {
0171     connect( m_configWidget->buttonAddDataSource,
0172         SIGNAL(clicked()), SLOT(addDataSource()) );
0173     connect( m_configWidget->buttonOpenDataSource,
0174         SIGNAL(clicked()), SLOT(openDataSource()) );
0175     connect( m_configWidget->buttonRemoveDataSource,
0176         SIGNAL(clicked()), SLOT(removeSelectedDataSource()) );
0177     connect( m_configWidget->buttonReloadDataSources,
0178         SIGNAL(clicked()), SLOT(reloadDataSources()) );
0179 
0180     connect( m_configWidget->listDataSources,
0181         SIGNAL(itemSelectionChanged()), SLOT(updateButtonState()) );
0182 }
0183 
0184 SatellitesConfigNodeItem* SatellitesConfigDialog::getSatellitesCategoryItem(
0185     const QString &body,
0186     const QString &category,
0187     bool create )
0188 {
0189     QString theCategory = translation( category );
0190 
0191     SatellitesConfigNodeItem *catalogItem;
0192     catalogItem = getSatellitesBodyItem( body, create );
0193 
0194     if( catalogItem == nullptr ) {
0195         return nullptr;
0196     }
0197 
0198     // find category
0199     for( int i = 0; i < catalogItem->childrenCount(); ++i ) {
0200         if( catalogItem->childAt( i )->name() == theCategory ) {
0201             return dynamic_cast<SatellitesConfigNodeItem*>(catalogItem->childAt( i ) );
0202         }
0203     }
0204 
0205     // not found, create?
0206     if( create ) {
0207         SatellitesConfigNodeItem *newItem;
0208         newItem = new SatellitesConfigNodeItem( theCategory );
0209         catalogItem->appendChild( newItem );
0210         return newItem;
0211     }
0212 
0213     return nullptr; // not found, not created
0214 }
0215 
0216 SatellitesConfigNodeItem* SatellitesConfigDialog::getSatellitesBodyItem(
0217     const QString &body,
0218     bool create )
0219 {
0220     QString theBody = translation( body );
0221 
0222     SatellitesConfigModel *model = dynamic_cast<SatellitesConfigModel*>( m_configWidget->treeView->model() );
0223     SatellitesConfigNodeItem *rootItem = model->rootItem();
0224 
0225     // try to find it
0226     for( int i = 0; i < rootItem->childrenCount(); ++i ) {
0227         if( rootItem->childAt( i )->name() == theBody ) {
0228             return dynamic_cast<SatellitesConfigNodeItem*>(rootItem->childAt( i ) );
0229         }
0230     }
0231 
0232     // not found, create?
0233     if( create ) {
0234         SatellitesConfigNodeItem *newItem;
0235         newItem = new SatellitesConfigNodeItem( theBody );
0236         rootItem->appendChild( newItem );
0237         return newItem;
0238     }
0239 
0240     return nullptr; // not found, not created
0241 }
0242 
0243 void SatellitesConfigDialog::reloadDataSources()
0244 {
0245     emit dataSourcesReloadRequested();
0246 }
0247 
0248 void SatellitesConfigDialog::addDataSource()
0249 {
0250     QListWidget *list = m_configWidget->listDataSources;
0251 
0252     bool ok;
0253     QString text = QInputDialog::getText( this,
0254                                           tr("Add Data Source"),
0255                                           tr("URL or File path:"),
0256                                           QLineEdit::Normal,
0257                                           "", &ok);
0258 
0259     if( ok && !text.isEmpty() ) {
0260         QUrl url = QUrl::fromUserInput( text );
0261         if( !url.isValid() ) {
0262             mDebug() << "Invalid data source input:" << text;
0263             QMessageBox::critical( this,
0264                                    tr( "Invalid data source input" ),
0265                                    tr( "Please enter a valid URL or file path!" ),
0266                                    QMessageBox::Cancel );
0267             return;
0268         }
0269 
0270         // add item
0271         QListWidgetItem *item = new QListWidgetItem( url.toString(), list );
0272         item->setFlags( Qt::ItemIsSelectable |
0273                         Qt::ItemIsEnabled );
0274         item->setData( IsLoadedRole, QVariant( false ) );
0275 
0276         mDebug() << "Added satellite data source:" << item->text();
0277         m_userDataSources << item->text();
0278 
0279         emit userDataSourceAdded( item->text() );
0280         emit userDataSourcesChanged();
0281     }
0282 }
0283 
0284 void SatellitesConfigDialog::openDataSource()
0285 {
0286     QListWidget *list = m_configWidget->listDataSources;
0287 
0288     const QString filter = QString("%1;;%2;;%3").arg(
0289         tr( "All Supported Files (*.txt *.msc)" ),
0290         tr( "Marble Satellite Catalog (*.msc)" ),
0291         tr( "Two Line Element Set (*.txt)" ),
0292         tr( "All Files (*.*)" ) );
0293 
0294     QString filename = QFileDialog::getOpenFileName( this,
0295         tr( "Open Satellite Data File" ), "", filter );
0296 
0297     if( !filename.isNull() ) {
0298         QString url = QUrl::fromLocalFile( filename ).toString();
0299 
0300         if( m_configWidget->listDataSources->findItems(
0301                 url, Qt::MatchFixedString ).size() > 0 ) {
0302             mDebug() << "Satellite data source exists:" << url;
0303             return; // already in list
0304         }
0305 
0306         QListWidgetItem *item = new QListWidgetItem( url, list );
0307         item->setFlags( Qt::ItemIsSelectable |
0308                         Qt::ItemIsEnabled );
0309         item->setData( IsLoadedRole, QVariant( false ) );
0310 
0311         mDebug() << "Added satellite data source:" << url;
0312         m_userDataSources << url;
0313 
0314         emit userDataSourceAdded( url );
0315         emit userDataSourcesChanged();
0316     }
0317 
0318 }
0319 
0320 void SatellitesConfigDialog::removeSelectedDataSource()
0321 {
0322     int row = m_configWidget->listDataSources->currentRow();
0323     if( row >= 0 && 
0324         QMessageBox::question( this,
0325             tr( "Delete selected data source" ),
0326             tr( "Do you really want to delete the selected data source?" ),
0327             QMessageBox::Yes | QMessageBox::No,
0328             QMessageBox::No ) == QMessageBox::Yes ) {
0329 
0330         QListWidgetItem *item;
0331         item = m_configWidget->listDataSources->takeItem( row );
0332         QString source = item->text();
0333 
0334         mDebug() << "Removing satellite data source:" << source;
0335         m_userDataSources.removeAll( source );
0336         emit userDataSourceRemoved( source );
0337 
0338         delete item;
0339 
0340         emit userDataSourcesChanged();
0341     }
0342 }
0343 
0344 void SatellitesConfigDialog::updateButtonState()
0345 {
0346     m_configWidget->buttonRemoveDataSource->setEnabled(
0347         ( m_configWidget->listDataSources->currentIndex().row() >= 0 ) );
0348 }
0349 
0350 void SatellitesConfigDialog::expandTreeView()
0351 {
0352     QTreeView *treeView = m_configWidget->treeView;
0353 
0354     if( !treeView->model() ) {
0355         return;
0356     }
0357 
0358     // expand only branches with selected items
0359     treeView->expandAll();
0360 
0361     for ( int i = 0; i < treeView->model()->columnCount(); ++i ) {
0362         treeView->resizeColumnToContents( i );
0363     }
0364 }
0365 
0366 QString SatellitesConfigDialog::translation( const QString &from ) const
0367 {
0368     if( m_translations.contains( from ) ) {
0369         return m_translations.value( from );
0370     }
0371 
0372     return from;
0373 }
0374 
0375 } // namespace Marble
0376 
0377 #include "moc_SatellitesConfigDialog.cpp"
0378