File indexing completed on 2024-07-14 07:17:15

0001 /*
0002     SPDX-FileCopyrightText: 2011 Jérôme SONRIER <jsid@emor3j.fr.eu.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "opssatellites.h"
0008 
0009 #include "kstars.h"
0010 #include "kstarsdata.h"
0011 #include "Options.h"
0012 #include "satellite.h"
0013 #include "skymapcomposite.h"
0014 #include "skycomponents/satellitescomponent.h"
0015 #include "skymap.h"
0016 
0017 #include <QStandardItemModel>
0018 #include <QStatusBar>
0019 
0020 static const char *satgroup_strings_context = "Satellite group name";
0021 
0022 SatelliteSortFilterProxyModel::SatelliteSortFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent)
0023 {
0024 }
0025 
0026 bool SatelliteSortFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
0027 {
0028     QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
0029 
0030     if (sourceModel()->hasChildren(index))
0031     {
0032         for (int i = 0; i < sourceModel()->rowCount(index); ++i)
0033             if (filterAcceptsRow(i, index))
0034                 return true;
0035         return false;
0036     }
0037 
0038     return sourceModel()->data(index).toString().contains(filterRegExp());
0039 }
0040 
0041 OpsSatellites::OpsSatellites() : QFrame(KStars::Instance())
0042 {
0043     setupUi(this);
0044 
0045     m_ConfigDialog = KConfigDialog::exists("settings");
0046 
0047     //Set up the Table Views
0048     m_Model     = new QStandardItemModel(0, 1, this);
0049     m_SortModel = new SatelliteSortFilterProxyModel(this);
0050     m_SortModel->setSourceModel(m_Model);
0051     SatListTreeView->setModel(m_SortModel);
0052     SatListTreeView->setEditTriggers(QTreeView::NoEditTriggers);
0053     SatListTreeView->setSortingEnabled(false);
0054 
0055     // Populate satellites list
0056     updateListView();
0057 
0058     // Signals and slots connections
0059     connect(UpdateTLEButton, SIGNAL(clicked()), this, SLOT(slotUpdateTLEs()));
0060     connect(kcfg_ShowSatellites, SIGNAL(toggled(bool)), SLOT(slotShowSatellites(bool)));
0061     connect(m_ConfigDialog->button(QDialogButtonBox::Apply), SIGNAL(clicked()), SLOT(slotApply()));
0062     connect(m_ConfigDialog->button(QDialogButtonBox::Ok), SIGNAL(clicked()), SLOT(slotApply()));
0063     connect(m_ConfigDialog->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), SLOT(slotCancel()));
0064     connect(FilterEdit, SIGNAL(textChanged(QString)), this, SLOT(slotFilterReg(QString)));
0065     connect(m_Model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(slotItemChanged(QStandardItem*)));
0066 
0067     #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
0068     connect(satelliteButtonGroup, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::buttonPressed), this,
0069             [&]() { isDirty = true; });
0070     #else
0071     connect(satelliteButtonGroup, static_cast<void (QButtonGroup::*)(int)>(&QButtonGroup::idPressed), this,
0072             [&]() { isDirty = true; });
0073     #endif
0074 
0075     isDirty = false;
0076 }
0077 
0078 void OpsSatellites::slotUpdateTLEs()
0079 {
0080     // Save existing satellites
0081     saveSatellitesList();
0082 
0083     // Get new data files
0084     KStarsData::Instance()->skyComposite()->satellites()->updateTLEs();
0085 
0086     isDirty = true;
0087 
0088     // Refresh satellites list
0089     updateListView();
0090 }
0091 
0092 void OpsSatellites::updateListView()
0093 {
0094     KStarsData *data = KStarsData::Instance();
0095 
0096     // Clear satellites list
0097     m_Model->clear();
0098     SatListTreeView->reset();
0099 
0100     m_Model->setHorizontalHeaderLabels(QStringList(i18n("Satellite Name")));
0101 
0102     // Add each groups and satellites in the list
0103     foreach (SatelliteGroup *sat_group, data->skyComposite()->satellites()->groups())
0104     {
0105         QStandardItem *group_item;
0106         QStandardItem *sat_item;
0107         bool all_sat_checked   = true;
0108         bool all_sat_unchecked = true;
0109 
0110         // Add the group
0111         group_item = new QStandardItem(i18nc(satgroup_strings_context, sat_group->name().toUtf8()));
0112         group_item->setCheckable(true);
0113         m_Model->appendRow(group_item);
0114 
0115         // Add all satellites of the group
0116         for (int i = 0; i < sat_group->count(); ++i)
0117         {
0118             sat_item = new QStandardItem(sat_group->at(i)->name());
0119             sat_item->setCheckable(true);
0120             if (Options::selectedSatellites().contains(sat_group->at(i)->name()))
0121             {
0122                 sat_item->setCheckState(Qt::Checked);
0123                 all_sat_unchecked = false;
0124             }
0125             else
0126                 all_sat_checked = false;
0127             group_item->setChild(i, sat_item);
0128         }
0129 
0130         // If all satellites of the group are selected, select the group
0131         if (all_sat_checked)
0132             group_item->setCheckState(Qt::Checked);
0133         else if (all_sat_unchecked)
0134             group_item->setCheckState(Qt::Unchecked);
0135         else
0136             group_item->setCheckState(Qt::PartiallyChecked);
0137     }
0138 }
0139 
0140 void OpsSatellites::saveSatellitesList()
0141 {
0142     KStarsData *data = KStarsData::Instance();
0143     QString sat_name;
0144     QStringList selected_satellites;
0145     QModelIndex group_index, sat_index;
0146     QStandardItem *group_item;
0147     QStandardItem *sat_item;
0148 
0149     // Retrieve each satellite in the list and select it if checkbox is checked
0150     for (int i = 0; i < m_Model->rowCount(SatListTreeView->rootIndex()); ++i)
0151     {
0152         group_index = m_Model->index(i, 0, SatListTreeView->rootIndex());
0153         group_item  = m_Model->itemFromIndex(group_index);
0154 
0155         for (int j = 0; j < m_Model->rowCount(group_item->index()); ++j)
0156         {
0157             sat_index = m_Model->index(j, 0, group_index);
0158             sat_item  = m_Model->itemFromIndex(sat_index);
0159             sat_name  = sat_item->data(0).toString();
0160 
0161             Satellite *sat = data->skyComposite()->satellites()->findSatellite(sat_name);
0162             if (sat)
0163             {
0164                 if (sat_item->checkState() == Qt::Checked)
0165                 {
0166                     int rc = sat->updatePos();
0167                     // If position calculation fails, unselect it
0168                     if (rc == 0)
0169                     {
0170                         sat->setSelected(true);
0171                         selected_satellites.append(sat_name);
0172                     }
0173                     else
0174                     {
0175                         KStars::Instance()->statusBar()->showMessage(
0176                             i18n("%1 position calculation error: %2.", sat->name(), sat->sgp4ErrorString(rc)), 0);
0177                         sat->setSelected(false);
0178                         sat_item->setCheckState(Qt::Unchecked);
0179                     }
0180                 }
0181                 else
0182                 {
0183                     sat->setSelected(false);
0184                 }
0185             }
0186         }
0187     }
0188 
0189     Options::setSelectedSatellites(selected_satellites);
0190 }
0191 
0192 void OpsSatellites::slotApply()
0193 {
0194     if (isDirty == false)
0195         return;
0196 
0197     isDirty = false;
0198 
0199     saveSatellitesList();
0200 
0201     // update time for all objects because they might be not initialized
0202     // it's needed when using horizontal coordinates
0203     KStars::Instance()->data()->setFullTimeUpdate();
0204     KStars::Instance()->updateTime();
0205     KStars::Instance()->map()->forceUpdate();
0206 }
0207 
0208 void OpsSatellites::slotCancel()
0209 {
0210     // Update satellites list
0211     updateListView();
0212 }
0213 
0214 void OpsSatellites::slotShowSatellites(bool on)
0215 {
0216     isDirty = true;
0217     kcfg_ShowVisibleSatellites->setEnabled(on);
0218     kcfg_ShowSatellitesLabels->setEnabled(on);
0219     kcfg_DrawSatellitesLikeStars->setEnabled(on);
0220 }
0221 
0222 void OpsSatellites::slotFilterReg(const QString &filter)
0223 {
0224     m_SortModel->setFilterRegExp(QRegExp(filter, Qt::CaseInsensitive, QRegExp::RegExp));
0225     m_SortModel->setFilterKeyColumn(-1);
0226 
0227     isDirty = true;
0228 
0229     // Expand all categories when the user use filter
0230     if (filter.length() > 0)
0231         SatListTreeView->expandAll();
0232     else
0233         SatListTreeView->collapseAll();
0234 }
0235 
0236 void OpsSatellites::slotItemChanged(QStandardItem *item)
0237 {
0238     if (item->parent() == nullptr && !item->hasChildren())
0239     {
0240         return;
0241     }
0242 
0243     isDirty = true;
0244 
0245     QModelIndex sat_index;
0246     QStandardItem *sat_item;
0247 
0248     disconnect(m_Model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(slotItemChanged(QStandardItem*)));
0249 
0250     // If a group has been (un)checked, (un)check all satellites of the group
0251     // else a satellite has been (un)checked, (un)check his group
0252     if (item->hasChildren())
0253     {
0254         for (int i = 0; i < m_Model->rowCount(item->index()); ++i)
0255         {
0256             sat_index = m_Model->index(i, 0, item->index());
0257             sat_item  = m_Model->itemFromIndex(sat_index);
0258 
0259             if (item->checkState() == Qt::Checked)
0260                 sat_item->setCheckState(Qt::Checked);
0261             else
0262                 sat_item->setCheckState(Qt::Unchecked);
0263         }
0264     }
0265     else
0266     {
0267         bool all_sat_checked   = true;
0268         bool all_sat_unchecked = true;
0269 
0270         for (int i = 0; i < item->parent()->model()->rowCount(item->parent()->index()); ++i)
0271         {
0272             sat_index = m_Model->index(i, 0, item->parent()->index());
0273             sat_item  = m_Model->itemFromIndex(sat_index);
0274 
0275             if (sat_item->checkState() == Qt::Checked)
0276                 all_sat_unchecked = false;
0277             else
0278                 all_sat_checked = false;
0279         }
0280 
0281         if (all_sat_checked)
0282             item->parent()->setCheckState(Qt::Checked);
0283         else if (all_sat_unchecked)
0284             item->parent()->setCheckState(Qt::Unchecked);
0285         else
0286             item->parent()->setCheckState(Qt::PartiallyChecked);
0287     }
0288 
0289     connect(m_Model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(slotItemChanged(QStandardItem*)));
0290 }