File indexing completed on 2024-04-14 14:11:36

0001 /*
0002     SPDX-FileCopyrightText: 2018 Valentin Boettcher <valentin@boettcher.cf>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "eclipsetool.h"
0008 #include "ui_eclipsetool.h"
0009 #include "ksplanetbase.h"
0010 #include "kstarsdata.h"
0011 #include "geolocation.h"
0012 #include "dialogs/locationdialog.h"
0013 #include "kstars.h"
0014 #include "skymap.h"
0015 
0016 #include <QtConcurrent>
0017 #include <QFileDialog>
0018 #include <QErrorMessage>
0019 #include <QMenu>
0020 
0021 EclipseTool::EclipseTool(QWidget *parent) :
0022     QFrame(parent),
0023     ui(new Ui::EclipseTool)
0024 {
0025     ui->setupUi(this);
0026 
0027     // set up the eclipse-partner selection
0028     ui->Obj1ComboBox->addItem(i18n("Earth Shadow"), KSPlanetBase::EARTH_SHADOW);
0029     ui->Obj2ComboBox->addItem(i18n("Moon"), KSPlanetBase::MOON);
0030 
0031     KStarsData *kd = KStarsData::Instance();
0032     KStarsDateTime dtStart(KStarsDateTime::currentDateTime());
0033     KStarsDateTime dtStop(dtStart.djd() + 365.24l); // one year
0034 
0035     m_geoLocation = kd->geo();
0036     ui->LocationButton->setText(m_geoLocation->fullName());
0037 
0038     ui->startDate->setDateTime(dtStart);
0039     ui->stopDate->setDateTime(dtStop);
0040 
0041     ui->ClearButton->setIcon(QIcon::fromTheme("edit-clear"));
0042 
0043     // set up slots
0044     connect(ui->LocationButton, &QPushButton::clicked, this, &EclipseTool::slotLocation);
0045     connect(ui->ComputeButton, &QPushButton::clicked, this, [&, this]() {
0046         // switch to progress bar
0047         ui->computeStack->setCurrentIndex(1);
0048 
0049         // reset progress
0050         ui->progressBar->setValue(0);
0051 
0052         QtConcurrent::run(this, &EclipseTool::slotCompute);
0053     });
0054 
0055     connect(ui->ClearButton, &QPushButton::clicked, &m_model, &EclipseModel::reset);
0056     connect(ui->ExportButton, &QPushButton::clicked, &m_model, &EclipseModel::exportAsCsv);
0057 
0058     // eclipse table
0059     ui->tableView->setModel(&m_model);
0060     ui->tableView->horizontalHeader()->setStretchLastSection(true);
0061     ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu);
0062 
0063     // double click to view
0064     connect(ui->tableView, &QTableView::doubleClicked, this, [this](const QModelIndex &index){
0065         slotView(m_model.getEvent(index.row()));
0066     });
0067 
0068     connect(ui->tableView, &QTableView::customContextMenuRequested, this,  &EclipseTool::slotContextMenu);
0069 
0070     ui->progressBar->setMinimum(0);
0071     ui->progressBar->setMaximum(100);
0072 }
0073 
0074 EclipseTool::~EclipseTool()
0075 {
0076     delete ui;
0077 }
0078 
0079 void EclipseTool::slotLocation()
0080 {
0081     QPointer<LocationDialog> ld(new LocationDialog(this));
0082     if (ld->exec() == QDialog::Accepted && ld)
0083     {
0084         m_geoLocation = ld->selectedCity();
0085         ui->LocationButton->setText(m_geoLocation->fullName());
0086     }
0087     delete ld;
0088 }
0089 
0090 // NOTE: This will need redesign some day.
0091 void EclipseTool::slotCompute()
0092 {
0093     EclipseHandler * handler;
0094     KStarsDateTime dtStart(ui->startDate->dateTime()); // start date
0095     KStarsDateTime dtStop(ui->stopDate->dateTime());  // stop date
0096     long double startJD    = dtStart.djd();         // start julian day
0097     long double stopJD     = dtStop.djd();
0098 
0099     if(ui->Obj1ComboBox->currentData().toInt() == KSPlanetBase::EARTH_SHADOW && ui->Obj2ComboBox->currentData().toInt() == KSPlanetBase::MOON){
0100         handler = new LunarEclipseHandler();
0101     } else
0102         return;
0103 
0104     connect(handler, &EclipseHandler::signalEventFound, &m_model, &EclipseModel::slotAddEclipse);
0105     connect(handler, &EclipseHandler::signalProgress, ui->progressBar, &QProgressBar::setValue);
0106     connect(handler, &EclipseHandler::signalComputationFinished, this, &EclipseTool::slotFinished);
0107 
0108     handler->setGeoLocation(m_geoLocation);
0109 
0110     // let's go
0111     EclipseHandler::EclipseVector eclipses = handler->computeEclipses(startJD, stopJD);
0112     delete handler;
0113 }
0114 
0115 void EclipseTool::slotFinished()
0116 {
0117     ui->computeStack->setCurrentIndex(0);
0118 }
0119 
0120 void EclipseTool::slotContextMenu(QPoint pos)
0121 {
0122     int row = ui->tableView->indexAt(pos).row();
0123     EclipseEvent_s event = m_model.getEvent(row);
0124 
0125     QMenu * menu = new QMenu(this);
0126     QAction * view = new QAction(i18n("View in SkyMap"), menu);
0127     connect(view, &QAction::triggered, this, [=]{
0128         slotView(event);
0129     });
0130     menu->addAction(view);
0131 
0132     if(event->hasDetails()){
0133         QAction * details = new QAction(i18n("Show Details"), menu);
0134         connect(details, &QAction::triggered, this, [=] {
0135             event->slotShowDetails(); // call virtual
0136         });
0137         menu->addAction(details);
0138     }
0139 
0140     menu->popup(ui->tableView->viewport()->mapToGlobal(pos));
0141 }
0142 
0143 void EclipseTool::slotView(EclipseEvent_s event)
0144 {
0145     SkyMap * map = KStars::Instance()->map();
0146     KStarsData * data = KStarsData::Instance();
0147     KStarsDateTime dt;
0148 
0149     dt.setDJD(event->getJD());
0150     data->changeDateTime(dt);
0151     data->setLocation(event->getGeolocation());
0152 
0153     map->setClickedObject(event->getEclipsingObjectFromSkyComposite());
0154     map->setClickedPoint(map->clickedObject());
0155     map->slotCenter();
0156 }
0157 
0158 EclipseModel::EclipseModel(QObject *parent) : QAbstractTableModel (parent)
0159 {
0160 
0161 }
0162 
0163 int EclipseModel::rowCount(const QModelIndex &) const
0164 {
0165     return m_eclipses.length();
0166 }
0167 
0168 QVariant EclipseModel::data(const QModelIndex &index, int role) const
0169 {
0170     int row = index.row();
0171     int col = index.column();
0172 
0173     if(role != Qt::DisplayRole)
0174         return QVariant();
0175 
0176     EclipseEvent * event = m_eclipses[row].get();
0177 
0178     switch(col) {
0179     case 0: /* Date */ {
0180         KStarsDateTime dt(event->getJD());
0181         return dt.toString(Qt::ISODate);
0182     }
0183     case 1: // Eclipsing Obj
0184         return event->getEclipsingObjectName();
0185     case 2: // Eclipsed Obj
0186         return event->getEclipsedObjectName();
0187     case 3: /* Eclipse Type */ {
0188         switch(event->getType()) {
0189         case EclipseEvent::FULL:
0190             return QString(i18n("Full"));
0191         case EclipseEvent::PARTIAL:
0192             return QString(i18n("Partial"));
0193         }
0194         break;
0195     }
0196     case 4: // Extra Info
0197         return event->getExtraInfo();
0198     }
0199 
0200     return QVariant();
0201 }
0202 
0203 void EclipseModel::slotAddEclipse(EclipseEvent_s eclipse)
0204 {
0205     m_eclipses.append(eclipse);
0206     emit layoutChanged(); // there must be a better way
0207 }
0208 
0209 void EclipseModel::exportAsCsv()
0210 {
0211     int i, j;
0212     QByteArray line;
0213 
0214     QFileDialog dialog;
0215     dialog.setNameFilter(i18n("CSV Files (*.csv)"));
0216     dialog.setDefaultSuffix("csv");
0217     dialog.setWindowTitle(i18nc("@title:window", "Export Eclipses"));
0218 
0219     QString fname;
0220     if(dialog.exec())
0221         fname = dialog.selectedFiles()[0];
0222     else {
0223         QErrorMessage msg;
0224         msg.showMessage(i18n("Could not export."));
0225         return;
0226     }
0227 
0228     QFile file(fname);
0229 
0230     file.open(QIODevice::WriteOnly | QIODevice::Text);
0231 
0232     for (i = 0; i < rowCount(); ++i)
0233     {
0234         for (j = 0; j < columnCount(); ++j)
0235         {
0236             line.append(data(index(i, j), Qt::DisplayRole).toByteArray());
0237             if (j < columnCount() - 1)
0238                 line.append(";");
0239             else
0240                 line.append("\n");
0241         }
0242         file.write(line);
0243         line.clear();
0244     }
0245 
0246     file.close();
0247 }
0248 
0249 QVariant EclipseModel::headerData(int section, Qt::Orientation orientation, int role) const
0250 {
0251     if (role == Qt::DisplayRole)
0252     {
0253         if (orientation == Qt::Horizontal) {
0254             switch (section)
0255             {
0256             case 0:
0257                 return QString("Date");
0258             case 1:
0259                 return QString("Eclipsing Object");
0260             case 2:
0261                 return QString("Eclipsed Object");
0262             case 3:
0263                 return QString("Eclipse Type");
0264             case 4:
0265                 return QString("Extra Information");
0266             }
0267         }
0268     }
0269     return QVariant();
0270 }
0271 
0272 void EclipseModel::reset()
0273 {
0274     emit beginResetModel();
0275     emit endResetModel();
0276 }