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

0001 /*
0002     SPDX-FileCopyrightText: 2009 Prakash Mohan <prakash.mohan@kdemail.net>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "oal/execute.h"
0008 
0009 #include "kstars.h"
0010 #include "kstarsdata.h"
0011 #include "ksnotification.h"
0012 #include "observinglist.h"
0013 #include "dialogs/finddialog.h"
0014 #include "dialogs/locationdialog.h"
0015 #include "oal/observeradd.h"
0016 #include "skycomponents/skymapcomposite.h"
0017 #include "skyobjects/starobject.h"
0018 
0019 #include <QFileDialog>
0020 
0021 Execute::Execute()
0022 {
0023     QWidget *w = new QWidget;
0024     ui.setupUi(w);
0025 #ifdef Q_OS_OSX
0026     setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
0027 #endif
0028 
0029     QVBoxLayout *mainLayout = new QVBoxLayout;
0030     mainLayout->addWidget(w);
0031     setLayout(mainLayout);
0032 
0033     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
0034     mainLayout->addWidget(buttonBox);
0035     connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
0036 
0037     QPushButton *execB  = new QPushButton(i18n("End Session"));
0038     QPushButton *addObs = new QPushButton(i18n("Manage Observers"));
0039     execB->setToolTip(i18n("Save and End the current session"));
0040     buttonBox->addButton(execB, QDialogButtonBox::ActionRole);
0041     buttonBox->addButton(addObs, QDialogButtonBox::ActionRole);
0042     connect(execB, SIGNAL(clicked()), this, SLOT(slotEndSession()));
0043     connect(addObs, SIGNAL(clicked()), this, SLOT(slotObserverAdd()));
0044 
0045     setWindowTitle(i18nc("@title:window", "Execute Session"));
0046 
0047     //initialize the global logObject
0048     logObject = KStarsData::Instance()->logObject();
0049 
0050     //initialize the lists and parameters
0051     init();
0052     ui.Target->hide();
0053     ui.AddObject->hide();
0054     ui.RemoveObject->hide();
0055     ui.NextButton->hide();
0056     ui.NextButton->setEnabled(false);
0057     ui.Slew->setEnabled(false);
0058 
0059     //make connections
0060     connect(ui.NextButton, SIGNAL(clicked()), this, SLOT(slotNext()));
0061     connect(ui.Slew, SIGNAL(clicked()), this, SLOT(slotSlew()));
0062     connect(ui.Location, SIGNAL(clicked()), this, SLOT(slotLocation()));
0063     connect(ui.Target, SIGNAL(currentTextChanged(QString)), this, SLOT(slotSetTarget(QString)));
0064     connect(ui.SessionURL, SIGNAL(leftClickedUrl()), this, SLOT(slotShowSession()));
0065     connect(ui.ObservationsURL, SIGNAL(leftClickedUrl()), this, SLOT(slotShowTargets()));
0066     connect(ui.AddObject, SIGNAL(leftClickedUrl()), this, SLOT(slotAddObject()));
0067     connect(ui.RemoveObject, SIGNAL(leftClickedUrl()), this, SLOT(slotRemoveObject()));
0068 }
0069 
0070 void Execute::init()
0071 {
0072     //initialize geo to current location of the ObservingList
0073     geo = KStarsData::Instance()->geo();
0074     ui.Location->setText(geo->fullName());
0075 
0076     // JM: Aren't we suppose to take KStars time? The one returned by the OL is the time of the LAST object
0077     // in the list which doesn't make sense.
0078 
0079     /*
0080     //set the date time to the dateTime from the OL
0081     ui.Begin->setDateTime( ks->observingList()->dateTime() );
0082     */
0083     ui.Begin->setDateTime(KStarsData::Instance()->geo()->UTtoLT(KStarsData::Instance()->clock()->utc()));
0084 
0085     KStarsData::Instance()->logObject()->readAll();
0086 
0087     //load Targets
0088     loadTargets();
0089 
0090     //load Equipment
0091     loadEquipment();
0092 
0093     //load Observers
0094     loadObservers();
0095 
0096     if (logObject->scopeList()->isEmpty() || logObject->observerList()->isEmpty())
0097     {
0098         ui.hintLabel->show();
0099     }
0100     else
0101     {
0102         ui.hintLabel->hide();
0103     }
0104 
0105     //set Current Items
0106     loadCurrentItems();
0107 }
0108 void Execute::loadCurrentItems()
0109 {
0110     //Set the current target, equipments and observer
0111     if (currentTarget)
0112         ui.Target->setCurrentRow(findIndexOfTarget(currentTarget->name()), QItemSelectionModel::SelectCurrent);
0113     else
0114         ui.Target->setCurrentRow(0, QItemSelectionModel::SelectCurrent);
0115 
0116     if (currentObserver)
0117         ui.Observer->setCurrentIndex(ui.Observer->findText(currentObserver->name() + ' ' + currentObserver->surname()));
0118     if (currentScope)
0119         ui.Scope->setCurrentIndex(ui.Scope->findText(currentScope->name()));
0120     if (currentEyepiece)
0121         ui.Eyepiece->setCurrentIndex(ui.Eyepiece->findText(currentEyepiece->name()));
0122     if (currentLens)
0123         ui.Lens->setCurrentIndex(ui.Lens->findText(currentLens->name()));
0124     if (currentFilter)
0125         ui.Filter->setCurrentIndex(ui.Filter->findText(currentFilter->name()));
0126 }
0127 
0128 int Execute::findIndexOfTarget(QString name)
0129 {
0130     for (int i = 0; i < ui.Target->count(); i++)
0131         if (ui.Target->item(i)->text() == name)
0132             return i;
0133     return -1;
0134 }
0135 
0136 void Execute::slotNext()
0137 {
0138     switch (ui.stackedWidget->currentIndex())
0139     {
0140         case 0:
0141         {
0142             saveSession();
0143             break;
0144         }
0145         case 1:
0146         {
0147             addTargetNotes();
0148             break;
0149         }
0150         case 2:
0151         {
0152             addObservation();
0153             ui.stackedWidget->setCurrentIndex(1);
0154             ui.NextButton->setText(i18n("Next Page >"));
0155             QString prevTarget = currentTarget->name();
0156             loadTargets();
0157             ui.Target->setCurrentRow(findIndexOfTarget(prevTarget), QItemSelectionModel::SelectCurrent);
0158             selectNextTarget();
0159             break;
0160         }
0161     }
0162 }
0163 
0164 bool Execute::saveSession()
0165 {
0166     OAL::Site *site = logObject->findSiteByName(geo->fullName());
0167     if (!site)
0168     {
0169         while (logObject->findSiteById(i18n("site_") + QString::number(nextSite)))
0170             nextSite++;
0171         site = new OAL::Site(geo, i18n("site_") + QString::number(nextSite++));
0172         logObject->siteList()->append(site);
0173     }
0174     if (currentSession)
0175     {
0176         currentSession->setSession(currentSession->id(), site->id(), KStarsDateTime(ui.Begin->dateTime()),
0177                                    KStarsDateTime(ui.Begin->dateTime()), ui.Weather->toPlainText(),
0178                                    ui.Equipment->toPlainText(), ui.Comment->toPlainText(),
0179                                    ui.Language->text());
0180     }
0181     else
0182     {
0183         while (logObject->findSessionByName(i18n("session_") + QString::number(nextSession)))
0184             nextSession++;
0185         currentSession = new OAL::Session(i18n("session_") + QString::number(nextSession++), site->id(),
0186                                           KStarsDateTime(ui.Begin->dateTime()), KStarsDateTime(ui.Begin->dateTime()),
0187                                           ui.Weather->toPlainText(), ui.Equipment->toPlainText(),
0188                                           ui.Comment->toPlainText(), ui.Language->text());
0189         logObject->sessionList()->append(currentSession);
0190     }
0191     ui.stackedWidget->setCurrentIndex(1); //Move to the next page
0192     return true;
0193 }
0194 
0195 void Execute::slotLocation()
0196 {
0197     QPointer<LocationDialog> ld = new LocationDialog(this);
0198     if (ld->exec() == QDialog::Accepted)
0199     {
0200         geo = ld->selectedCity();
0201         ui.Location->setText(geo->fullName());
0202     }
0203     delete ld;
0204 }
0205 
0206 void Execute::loadTargets()
0207 {
0208     ui.Target->clear();
0209     sortTargetList();
0210 
0211     for (auto &o : KStarsData::Instance()->observingList()->sessionList())
0212     {
0213         ui.Target->addItem(getObjectName(o.data(), false));
0214     }
0215 }
0216 
0217 void Execute::loadEquipment()
0218 {
0219     ui.Scope->clear();
0220     ui.Eyepiece->clear();
0221     ui.Lens->clear();
0222     ui.Filter->clear();
0223     foreach (OAL::Scope *s, *(logObject->scopeList()))
0224         ui.Scope->addItem(s->name());
0225     foreach (OAL::Eyepiece *e, *(logObject->eyepieceList()))
0226         ui.Eyepiece->addItem(e->name());
0227     foreach (OAL::Lens *l, *(logObject->lensList()))
0228         ui.Lens->addItem(l->name());
0229     foreach (OAL::Filter *f, *(logObject->filterList()))
0230         ui.Filter->addItem(f->name());
0231 }
0232 
0233 void Execute::loadObservers()
0234 {
0235     ui.Observer->clear();
0236     foreach (OAL::Observer *o, *(logObject->observerList()))
0237         ui.Observer->addItem(o->name() + ' ' + o->surname());
0238 }
0239 
0240 void Execute::sortTargetList()
0241 {
0242     auto timeLessThan = [](QSharedPointer<SkyObject> o1, QSharedPointer<SkyObject> o2)
0243     {
0244         QTime t1 = KStarsData::Instance()->observingList()->scheduledTime(o1.data());
0245         QTime t2 = KStarsData::Instance()->observingList()->scheduledTime(o2.data());
0246 
0247         if (t1 < QTime(12, 0, 0))
0248             t1.setHMS(t1.hour() + 12, t1.minute(), t1.second());
0249         else
0250             t1.setHMS(t1.hour() - 12, t1.minute(), t1.second());
0251         if (t2 < QTime(12, 0, 0))
0252             t2.setHMS(t2.hour() + 12, t2.minute(), t2.second());
0253         else
0254             t2.setHMS(t2.hour() - 12, t2.minute(), t2.second());
0255         return (t1 < t2);
0256     };
0257 
0258     std::sort(KStarsData::Instance()->observingList()->sessionList().begin(),
0259           KStarsData::Instance()->observingList()->sessionList().end(), timeLessThan);
0260 }
0261 
0262 void Execute::addTargetNotes()
0263 {
0264     if (!ui.Target->count())
0265         return;
0266     SkyObject *o = KStarsData::Instance()->observingList()->findObjectByName(ui.Target->currentItem()->text());
0267     if (o)
0268     {
0269         currentTarget = o;
0270         KStarsData::Instance()->updateUserLog(o->name(), ui.Notes->toPlainText());
0271         ui.Notes->clear();
0272         loadObservationTab();
0273     }
0274 }
0275 
0276 void Execute::loadObservationTab()
0277 {
0278     ui.Time->setTime(KStarsDateTime::currentDateTime().time());
0279     ui.stackedWidget->setCurrentIndex(2);
0280     ui.NextButton->setText(i18n("Next Target >"));
0281 }
0282 
0283 bool Execute::addObservation()
0284 {
0285     slotSetCurrentObjects();
0286     while (logObject->findObservationByName(i18n("observation_") + QString::number(nextObservation)))
0287         nextObservation++;
0288     KStarsDateTime dt = currentSession->begin();
0289     dt.setTime(ui.Time->time());
0290     OAL::Observation *o = new OAL::Observation(
0291         i18n("observation_") + QString::number(nextObservation++), currentObserver, currentSession, currentTarget, dt,
0292         ui.FaintestStar->value(), ui.Seeing->value(), currentScope, currentEyepiece, currentLens, currentFilter,
0293         ui.Description->toPlainText(), ui.Language->text());
0294     logObject->observationList()->append(o);
0295     ui.Description->clear();
0296     return true;
0297 }
0298 void Execute::slotEndSession()
0299 {
0300     if (currentSession)
0301     {
0302         currentSession->setSession(currentSession->id(), currentSession->site(), KStarsDateTime(ui.Begin->dateTime()),
0303                                    KStarsDateTime::currentDateTime(), ui.Weather->toPlainText(),
0304                                    ui.Equipment->toPlainText(), ui.Comment->toPlainText(), ui.Language->text());
0305 
0306         QUrl fileURL = QFileDialog::getSaveFileUrl(nullptr, i18nc("@title:window", "Save Session"), QUrl(QDir::homePath()), "*.xml");
0307 
0308         if (fileURL.isEmpty())
0309         {
0310             // Cancel
0311             return;
0312         }
0313 
0314         if (fileURL.isValid())
0315         {
0316             QFile f(fileURL.toLocalFile());
0317             if (!f.open(QIODevice::WriteOnly))
0318             {
0319                 QString message = i18n("Could not open file %1", f.fileName());
0320                 KSNotification::sorry(message, i18n("Could Not Open File"));
0321                 return;
0322             }
0323             QTextStream ostream(&f);
0324             ostream << logObject->writeLog(false);
0325             f.close();
0326         }
0327     }
0328     hide();
0329     ui.stackedWidget->setCurrentIndex(0);
0330     logObject->observationList()->clear();
0331     logObject->sessionList()->clear();
0332     delete currentSession;
0333     currentTarget  = nullptr;
0334     currentSession = nullptr;
0335 }
0336 void Execute::slotObserverAdd()
0337 {
0338     QPointer<ObserverAdd> m_observerAdd = new ObserverAdd();
0339     m_observerAdd->exec();
0340     delete m_observerAdd;
0341 }
0342 
0343 void Execute::slotSetTarget(const QString &name)
0344 {
0345     currentTarget = KStarsData::Instance()->observingList()->findObjectByName(name);
0346     if (!currentTarget)
0347     {
0348         ui.NextButton->setEnabled(false);
0349         ui.Slew->setEnabled(false);
0350         return;
0351     }
0352     else
0353     {
0354         ui.NextButton->setEnabled(true);
0355         ui.Slew->setEnabled(true);
0356         KStarsData::Instance()->observingList()->selectObject(currentTarget);
0357         KStarsData::Instance()->observingList()->slotCenterObject();
0358         QString smag = "--";
0359         if (-30.0 < currentTarget->mag() && currentTarget->mag() < 90.0)
0360             smag = QString::number(currentTarget->mag(), 'g',
0361                                    2); // The lower limit to avoid display of unrealistic comet magnitudes
0362         ui.Mag->setText(smag);
0363         ui.Type->setText(currentTarget->typeName());
0364         ui.SchTime->setText(
0365             KStarsData::Instance()->observingList()->scheduledTime(currentTarget).toString("h:mm:ss AP"));
0366         SkyPoint p = currentTarget->recomputeCoords(KStarsDateTime::currentDateTime(), geo);
0367         dms lst(geo->GSTtoLST(KStarsDateTime::currentDateTime().gst()));
0368         p.EquatorialToHorizontal(&lst, geo->lat());
0369         ui.RA->setText(p.ra().toHMSString());
0370         ui.Dec->setText(p.dec().toDMSString());
0371         ui.Alt->setText(p.alt().toDMSString());
0372         ui.Az->setText(p.az().toDMSString());
0373         ui.Notes->setText(KStarsData::Instance()->getUserData(currentTarget->name()).userLog);
0374     }
0375 }
0376 
0377 void Execute::slotSlew()
0378 {
0379     KStarsData::Instance()->observingList()->slotSlewToObject();
0380 }
0381 
0382 void Execute::selectNextTarget()
0383 {
0384     int i = findIndexOfTarget(currentTarget->name()) + 1;
0385     if (i < ui.Target->count())
0386     {
0387         ui.Target->selectionModel()->clear();
0388         ui.Target->setCurrentRow(i, QItemSelectionModel::SelectCurrent);
0389     }
0390 }
0391 
0392 void Execute::slotSetCurrentObjects()
0393 {
0394     currentScope    = logObject->findScopeByName(ui.Scope->currentText());
0395     currentEyepiece = logObject->findEyepieceByName(ui.Eyepiece->currentText());
0396     currentLens     = logObject->findLensByName(ui.Lens->currentText());
0397     currentFilter   = logObject->findFilterByName(ui.Filter->currentText());
0398     currentObserver = logObject->findObserverByName(ui.Observer->currentText());
0399 }
0400 
0401 void Execute::slotShowSession()
0402 {
0403     ui.Target->hide();
0404     ui.stackedWidget->setCurrentIndex(0);
0405     ui.NextButton->hide();
0406     ui.AddObject->hide();
0407     ui.RemoveObject->hide();
0408 }
0409 
0410 void Execute::slotShowTargets()
0411 {
0412     if (saveSession())
0413     {
0414         ui.Target->show();
0415         ui.AddObject->show();
0416         ui.RemoveObject->show();
0417         ui.stackedWidget->setCurrentIndex(1);
0418         ui.NextButton->show();
0419         ui.NextButton->setText(i18n("Next Page >"));
0420     }
0421 }
0422 
0423 void Execute::slotAddObject()
0424 {
0425     if (FindDialog::Instance()->exec() == QDialog::Accepted)
0426     {
0427         SkyObject *o = FindDialog::Instance()->targetObject();
0428         if (o != nullptr)
0429         {
0430             KStarsData::Instance()->observingList()->slotAddObject(o, true);
0431             init();
0432         }
0433     }
0434 }
0435 
0436 void Execute::slotRemoveObject()
0437 {
0438     QModelIndex i  = ui.Target->currentIndex();
0439     SkyObject *obj = nullptr;
0440 
0441     if (i.isValid())
0442     {
0443         QString ObjName = i.data().toString();
0444 
0445         obj = KStarsData::Instance()->skyComposite()->findByName(ObjName);
0446     }
0447 
0448     if (obj != nullptr)
0449     {
0450         KStarsData::Instance()->observingList()->slotRemoveObject(obj, true);
0451         loadTargets();
0452     }
0453 }
0454 
0455 QString Execute::getObjectName(const SkyObject *o, bool translated)
0456 {
0457     QString finalObjectName;
0458 
0459     if (o->name() == "star")
0460     {
0461         StarObject *s = (StarObject *)o;
0462 
0463         // JM: Enable HD Index stars to be added to the observing list.
0464         if (s->getHDIndex() != 0)
0465             finalObjectName = QString("HD %1").arg(QString::number(s->getHDIndex()));
0466     }
0467     else
0468         finalObjectName = translated ? o->translatedName() : o->name();
0469 
0470     return finalObjectName;
0471 }