File indexing completed on 2024-04-21 14:46:52

0001 /*
0002     SPDX-FileCopyrightText: 2009 Jerome SONRIER <jsid@emor3j.fr.eu.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "flagmanager.h"
0008 
0009 #include "config-kstars.h"
0010 
0011 #include "kspaths.h"
0012 #include "ksnotification.h"
0013 #include "kstars.h"
0014 #include "kstars_debug.h"
0015 #include "kstarsdata.h"
0016 #include "Options.h"
0017 #include "skymap.h"
0018 #include "skycomponents/flagcomponent.h"
0019 #include "skycomponents/skymapcomposite.h"
0020 
0021 #ifdef HAVE_INDI
0022 #include <basedevice.h>
0023 #include "indi/indilistener.h"
0024 #include "indi/indistd.h"
0025 #include "indi/indimount.h"
0026 #include "indi/driverinfo.h"
0027 #endif
0028 
0029 #include <KMessageBox>
0030 
0031 #include <QStandardItemModel>
0032 #include <QSortFilterProxyModel>
0033 
0034 FlagManagerUI::FlagManagerUI(QWidget *p) : QFrame(p)
0035 {
0036     setupUi(this);
0037 }
0038 
0039 FlagManager::FlagManager(QWidget *ks) : QDialog(ks)
0040 {
0041 #ifdef Q_OS_OSX
0042     setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
0043 #endif
0044     QList<QStandardItem *> itemList;
0045     QList<QImage> imageList;
0046     QStringList flagNames;
0047     int i;
0048 
0049     ui = new FlagManagerUI(this);
0050 
0051     setWindowTitle(i18nc("@title:window", "Flag Manager"));
0052 
0053     QVBoxLayout *mainLayout = new QVBoxLayout;
0054     mainLayout->addWidget(ui);
0055     setLayout(mainLayout);
0056 
0057     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
0058     mainLayout->addWidget(buttonBox);
0059     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
0060 
0061     m_Ks = KStars::Instance();
0062 
0063     ui->hintLabel->setText(i18n("To add custom icons, just add images in %1. File names must begin with flag. "
0064                                 "For example, the file <i>flagSmall_red_cross.png</i> will be shown as <b>Small red "
0065                                 "cross</b> in the combo box.",
0066                                 KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)));
0067     //Set up the Table Views
0068     m_Model = new QStandardItemModel(0, 5, this);
0069     m_Model->setHorizontalHeaderLabels(QStringList() << i18nc("Right Ascension", "RA") << i18nc("Declination", "Dec")
0070                                        << i18n("Epoch") << i18n("Icon") << i18n("Label"));
0071     m_SortModel = new QSortFilterProxyModel(this);
0072     m_SortModel->setSourceModel(m_Model);
0073     m_SortModel->setDynamicSortFilter(true);
0074     ui->flagList->setModel(m_SortModel);
0075     ui->flagList->horizontalHeader()->setStretchLastSection(true);
0076 
0077     ui->flagList->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
0078 
0079     ui->saveButton->setEnabled(false);
0080 
0081     ui->raBox->setUnits(dmsBox::HOURS);
0082 
0083     //Fill the list
0084     imageList = m_Ks->data()->skyComposite()->flags()->imageList();
0085     flagNames = m_Ks->data()->skyComposite()->flags()->getNames();
0086 
0087     FlagComponent *flags = m_Ks->data()->skyComposite()->flags();
0088     QPixmap pixmap;
0089 
0090     for (i = 0; i < m_Ks->data()->skyComposite()->flags()->size(); ++i)
0091     {
0092         QStandardItem *labelItem = new QStandardItem(flags->label(i));
0093         labelItem->setForeground(QBrush(flags->labelColor(i)));
0094 
0095         itemList << new QStandardItem(flags->pointList().at(i)->ra0().toHMSString())
0096                  << new QStandardItem(flags->pointList().at(i)->dec0().toDMSString())
0097                  << new QStandardItem(flags->epoch(i))
0098                  << new QStandardItem(QIcon(pixmap.fromImage(flags->image(i))), flags->imageName(i)) << labelItem;
0099         m_Model->appendRow(itemList);
0100         itemList.clear();
0101     }
0102 
0103     //Fill the combobox
0104     for (i = 0; i < imageList.size(); ++i)
0105     {
0106         ui->flagCombobox->addItem(QIcon(pixmap.fromImage(flags->imageList(i))), flagNames.at(i), flagNames.at(i));
0107     }
0108 
0109     //Connect buttons
0110     connect(ui->addButton, SIGNAL(clicked()), this, SLOT(slotAddFlag()));
0111     connect(ui->delButton, SIGNAL(clicked()), this, SLOT(slotDeleteFlag()));
0112     connect(ui->CenterButton, SIGNAL(clicked()), this, SLOT(slotCenterFlag()));
0113     connect(ui->ScopeButton, SIGNAL(clicked()), this, SLOT(slotCenterTelescope()));
0114     connect(ui->flagList, SIGNAL(clicked(QModelIndex)), this, SLOT(slotSetShownFlag(QModelIndex)));
0115     connect(ui->flagList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotCenterFlag()));
0116 
0117     connect(ui->saveButton, SIGNAL(clicked()), this, SLOT(slotSaveChanges()));
0118 }
0119 
0120 void FlagManager::setRaDec(const dms &ra, const dms &dec)
0121 {
0122     ui->raBox->show(ra);
0123     ui->decBox->show(dec);
0124 }
0125 
0126 void FlagManager::clearFields()
0127 {
0128     ui->raBox->clear();
0129     ui->decBox->clear();
0130 
0131     ui->epochBox->setText("2000.0");
0132     ui->flagLabel->clear();
0133     ui->flagLabel->setFocus();
0134 
0135     //disable "Save Changes" button
0136     ui->saveButton->setEnabled(false);
0137 
0138     //unselect item from flagList
0139     ui->flagList->clearSelection();
0140 }
0141 
0142 void FlagManager::showFlag(int flagIdx)
0143 {
0144     if (flagIdx < 0 || flagIdx >= m_Model->rowCount())
0145     {
0146         return;
0147     }
0148 
0149     else
0150     {
0151         ui->raBox->setText(m_Model->data(m_Model->index(flagIdx, 0)).toString());
0152         ui->decBox->setText(m_Model->data(m_Model->index(flagIdx, 1)).toString());
0153         ui->epochBox->setText(m_Model->data(m_Model->index(flagIdx, 2)).toString());
0154 
0155         //ui->flagCombobox->setCurrentItem( m_Model->data( m_Model->index( flagIdx, 3) ).toString() );
0156         ui->flagCombobox->setCurrentText(m_Model->data(m_Model->index(flagIdx, 3)).toString());
0157         ui->flagLabel->setText(m_Model->data(m_Model->index(flagIdx, 4)).toString());
0158 
0159         QColor labelColor = m_Model->item(flagIdx, 4)->foreground().color();
0160         ui->labelColorcombo->setColor(labelColor);
0161     }
0162 
0163     ui->flagList->selectRow(flagIdx);
0164     ui->saveButton->setEnabled(true);
0165 }
0166 
0167 bool FlagManager::validatePoint()
0168 {
0169     bool raOk(false), decOk(false);
0170     dms ra(ui->raBox->createDms(&raOk));
0171     dms dec(ui->decBox->createDms(&decOk));
0172 
0173     QString message;
0174 
0175     //check if ra & dec values were successfully converted
0176     if (!raOk || !decOk)
0177     {
0178         KSNotification::error(i18n("Invalid coordinates."));
0179         return false;
0180     }
0181 
0182     //make sure values are in valid range
0183     if (ra.Hours() < 0.0 || ra.Degrees() > 360.0)
0184         message = i18n("The Right Ascension value must be between 0.0 and 24.0.");
0185     if (dec.Degrees() < -90.0 || dec.Degrees() > 90.0)
0186         message += '\n' + i18n("The Declination value must be between -90.0 and 90.0.");
0187     if (!message.isEmpty())
0188     {
0189         KSNotification::sorry(message, i18n("Invalid Coordinate Data"));
0190         return false;
0191     }
0192 
0193     //all checks passed
0194     return true;
0195 }
0196 
0197 void FlagManager::deleteFlagItem(int flagIdx)
0198 {
0199     if (flagIdx < m_Model->rowCount())
0200     {
0201         m_Model->removeRow(flagIdx);
0202     }
0203 }
0204 
0205 void FlagManager::slotAddFlag()
0206 {
0207     if (validatePoint() == false)
0208         return;
0209 
0210     dms ra(ui->raBox->createDms());
0211     dms dec(ui->decBox->createDms());
0212 
0213     insertFlag(true);
0214 
0215     FlagComponent *flags = m_Ks->data()->skyComposite()->flags();
0216     //Add flag in FlagComponent
0217     SkyPoint flagPoint(ra, dec);
0218     flags->add(flagPoint, ui->epochBox->text(), ui->flagCombobox->currentText(), ui->flagLabel->text(),
0219                ui->labelColorcombo->color());
0220 
0221     ui->flagList->selectRow(m_Model->rowCount() - 1);
0222     ui->saveButton->setEnabled(true);
0223 
0224     flags->saveToFile();
0225 
0226     //Redraw map
0227     m_Ks->map()->forceUpdate(false);
0228 }
0229 
0230 void FlagManager::slotDeleteFlag()
0231 {
0232     int flag = ui->flagList->currentIndex().row();
0233 
0234     //Remove from FlagComponent
0235     m_Ks->data()->skyComposite()->flags()->remove(flag);
0236 
0237     //Remove from list
0238     m_Model->removeRow(flag);
0239 
0240     //Clear form fields
0241     clearFields();
0242 
0243     //Remove from file
0244     m_Ks->data()->skyComposite()->flags()->saveToFile();
0245 
0246     //Redraw map
0247     m_Ks->map()->forceUpdate(false);
0248 }
0249 
0250 void FlagManager::slotCenterFlag()
0251 {
0252     if (ui->flagList->currentIndex().isValid())
0253     {
0254         m_Ks->map()->setClickedObject(nullptr);
0255         m_Ks->map()->setClickedPoint(
0256             m_Ks->data()->skyComposite()->flags()->pointList().at(ui->flagList->currentIndex().row()).get());
0257         m_Ks->map()->slotCenter();
0258     }
0259 }
0260 
0261 void FlagManager::slotCenterTelescope()
0262 {
0263 #ifdef HAVE_INDI
0264 
0265     if (INDIListener::Instance()->size() == 0)
0266     {
0267         KSNotification::sorry(i18n("No connected mounts found."));
0268         return;
0269     }
0270 
0271     for (auto oneDevice : INDIListener::devices())
0272     {
0273         if (!(oneDevice->getDriverInterface() & INDI::BaseDevice::TELESCOPE_INTERFACE))
0274             continue;
0275 
0276         if (oneDevice->isConnected() == false)
0277         {
0278             KSNotification::error(
0279                 i18n("Telescope %1 is offline. Please connect and retry again.", oneDevice->getDeviceName()));
0280             return;
0281         }
0282 
0283         auto mount = oneDevice->getMount();
0284         if (!mount)
0285             continue;
0286 
0287         mount->Slew(m_Ks->data()->skyComposite()->flags()->pointList().at(ui->flagList->currentIndex().row()).get());
0288 
0289         return;
0290     }
0291 
0292     KSNotification::sorry(i18n("No connected mounts found."));
0293 
0294 #endif
0295 }
0296 
0297 void FlagManager::slotSaveChanges()
0298 {
0299     int row = ui->flagList->currentIndex().row();
0300 
0301     if (validatePoint() == false)
0302         return;
0303 
0304     insertFlag(false, row);
0305 
0306     m_Ks->map()->forceUpdate();
0307 
0308     dms ra(ui->raBox->createDms());
0309     dms dec(ui->decBox->createDms());
0310 
0311     SkyPoint flagPoint(ra, dec);
0312 
0313     //Update FlagComponent
0314     m_Ks->data()->skyComposite()->flags()->updateFlag(row, flagPoint, ui->epochBox->text(),
0315             ui->flagCombobox->currentText(), ui->flagLabel->text(),
0316             ui->labelColorcombo->color());
0317 
0318     //Save changes to file
0319     m_Ks->data()->skyComposite()->flags()->saveToFile();
0320 
0321     ui->flagList->selectRow(row);
0322 }
0323 
0324 void FlagManager::slotSetShownFlag(QModelIndex idx)
0325 {
0326     showFlag(idx.row());
0327 }
0328 
0329 void FlagManager::insertFlag(bool isNew, int row)
0330 {
0331     dms ra(ui->raBox->createDms());
0332     dms dec(ui->decBox->createDms());
0333     SkyPoint flagPoint(ra, dec);
0334 
0335     // Add flag in the list
0336     QList<QStandardItem *> itemList;
0337 
0338     QStandardItem *labelItem = new QStandardItem(ui->flagLabel->text());
0339     labelItem->setForeground(QBrush(ui->labelColorcombo->color()));
0340 
0341     FlagComponent *flags = m_Ks->data()->skyComposite()->flags();
0342 
0343     QPixmap pixmap;
0344     itemList << new QStandardItem(flagPoint.ra0().toHMSString()) << new QStandardItem(flagPoint.dec0().toDMSString())
0345              << new QStandardItem(ui->epochBox->text())
0346              << new QStandardItem(QIcon(pixmap.fromImage(flags->imageList(ui->flagCombobox->currentIndex()))),
0347                                   ui->flagCombobox->currentText())
0348              << labelItem;
0349 
0350     if (isNew)
0351     {
0352         m_Model->appendRow(itemList);
0353     }
0354 
0355     else
0356     {
0357         for (int i = 0; i < m_Model->columnCount(); i++)
0358         {
0359             m_Model->setItem(row, i, itemList.at(i));
0360         }
0361     }
0362 }