File indexing completed on 2024-04-28 03:43:15
0001 /* 0002 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 SPDX-FileCopyrightText: 2021 Wolfgang Reissenberger <sterne-jaeger@openfuture.de> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "capturepreviewwidget.h" 0009 #include "sequencejob.h" 0010 #include <ekos_capture_debug.h> 0011 #include "ksutils.h" 0012 #include "ksmessagebox.h" 0013 #include "ekos/mount/mount.h" 0014 #include "Options.h" 0015 #include "capture.h" 0016 #include "sequencejob.h" 0017 #include "fitsviewer/fitsdata.h" 0018 #include "fitsviewer/summaryfitsview.h" 0019 #include "ekos/scheduler/scheduler.h" 0020 0021 using Ekos::SequenceJob; 0022 0023 CapturePreviewWidget::CapturePreviewWidget(QWidget *parent) : QWidget(parent) 0024 { 0025 setupUi(this); 0026 overlay = new CaptureProcessOverlay(); 0027 overlay->setVisible(false); 0028 // history navigation 0029 connect(overlay->historyBackwardButton, &QPushButton::clicked, this, &CapturePreviewWidget::showPreviousFrame); 0030 connect(overlay->historyForwardButton, &QPushButton::clicked, this, &CapturePreviewWidget::showNextFrame); 0031 // deleting of captured frames 0032 connect(overlay->deleteCurrentFrameButton, &QPushButton::clicked, this, &CapturePreviewWidget::deleteCurrentFrame); 0033 } 0034 0035 void CapturePreviewWidget::shareCaptureModule(Ekos::Capture *module) 0036 { 0037 captureModule = module; 0038 captureCountsWidget->shareCaptureProcess(module); 0039 0040 if (captureModule != nullptr) 0041 { 0042 connect(captureModule, &Ekos::Capture::newDownloadProgress, captureCountsWidget, 0043 &CaptureCountsWidget::updateDownloadProgress); 0044 connect(captureModule, &Ekos::Capture::newExposureProgress, captureCountsWidget, 0045 &CaptureCountsWidget::updateExposureProgress); 0046 connect(captureModule, &Ekos::Capture::captureTarget, this, &CapturePreviewWidget::setTargetName); 0047 } 0048 } 0049 0050 void CapturePreviewWidget::shareSchedulerModule(Ekos::Scheduler *module) 0051 { 0052 schedulerModule = module; 0053 captureCountsWidget->shareSchedulerProcess(module); 0054 } 0055 0056 void CapturePreviewWidget::shareMountModule(Ekos::Mount *module) 0057 { 0058 mountModule = module; 0059 connect(mountModule, &Ekos::Mount::newTargetName, this, &CapturePreviewWidget::setTargetName); 0060 } 0061 0062 void CapturePreviewWidget::updateJobProgress(Ekos::SequenceJob *job, const QSharedPointer<FITSData> &data) 0063 { 0064 // forward first to the counting widget 0065 captureCountsWidget->updateJobProgress(job); 0066 0067 // without FITS data, we do nothing 0068 if (data == nullptr) 0069 return; 0070 0071 // cache frame meta data 0072 m_currentFrame.frameType = job->getFrameType(); 0073 if (job->getFrameType() == FRAME_LIGHT) 0074 { 0075 if (schedulerModule != nullptr && schedulerModule->activeJob() != nullptr) 0076 m_currentFrame.target = schedulerModule->activeJob()->getName(); 0077 else 0078 m_currentFrame.target = m_mountTarget; 0079 } 0080 else 0081 m_currentFrame.target = ""; 0082 0083 m_currentFrame.filterName = job->getCoreProperty(SequenceJob::SJ_Filter).toString(); 0084 m_currentFrame.exptime = job->getCoreProperty(SequenceJob::SJ_Exposure).toDouble(); 0085 m_currentFrame.targetdrift = -1.0; // will be updated later 0086 m_currentFrame.binning = job->getCoreProperty(SequenceJob::SJ_Binning).toPoint(); 0087 m_currentFrame.gain = job->getCoreProperty(SequenceJob::SJ_Gain).toDouble(); 0088 m_currentFrame.offset = job->getCoreProperty(SequenceJob::SJ_Offset).toDouble(); 0089 m_currentFrame.filename = data->filename(); 0090 m_currentFrame.width = data->width(); 0091 m_currentFrame.height = data->height(); 0092 0093 const auto ISOIndex = job->getCoreProperty(SequenceJob::SJ_Offset).toInt(); 0094 if (ISOIndex >= 0 && ISOIndex <= captureModule->captureISOS->count()) 0095 m_currentFrame.iso = captureModule->captureISOS->itemText(ISOIndex); 0096 else 0097 m_currentFrame.iso = ""; 0098 0099 // add it to the overlay 0100 overlay->addFrameData(m_currentFrame); 0101 overlay->setVisible(true); 0102 0103 // load frame 0104 if (m_fitsPreview != nullptr && Options::useSummaryPreview()) 0105 m_fitsPreview->loadData(data); 0106 } 0107 0108 void CapturePreviewWidget::showNextFrame() 0109 { 0110 overlay->setEnabled(false); 0111 if (overlay->showNextFrame()) 0112 m_fitsPreview->loadFile(overlay->currentFrame().filename); 0113 // Hint: since the FITSView loads in the background, we have to wait for FITSView::load() to enable the layer 0114 else 0115 overlay->setEnabled(true); 0116 } 0117 0118 void CapturePreviewWidget::showPreviousFrame() 0119 { 0120 overlay->setEnabled(false); 0121 if (overlay->showPreviousFrame()) 0122 m_fitsPreview->loadFile(overlay->currentFrame().filename); 0123 // Hint: since the FITSView loads in the background, we have to wait for FITSView::load() to enable the layer 0124 else 0125 overlay->setEnabled(true); 0126 } 0127 0128 void CapturePreviewWidget::deleteCurrentFrame() 0129 { 0130 overlay->setEnabled(false); 0131 if (overlay->hasFrames() == false) 0132 // nothing to delete 0133 return; 0134 0135 // make sure that the history does not change inbetween 0136 int pos = overlay->currentPosition(); 0137 CaptureProcessOverlay::FrameData current = overlay->getFrame(pos); 0138 QFile *file = new QFile(current.filename); 0139 0140 // prepare a warning dialog 0141 // move to trash or delete permanently 0142 QCheckBox *permanentlyDeleteCB = new QCheckBox(i18n("Delete directly, do not move to trash.")); 0143 permanentlyDeleteCB->setChecked(m_permanentlyDelete); 0144 KSMessageBox::Instance()->setCheckBox(permanentlyDeleteCB); 0145 connect(permanentlyDeleteCB, &QCheckBox::toggled, this, [this](bool checked) 0146 { 0147 this->m_permanentlyDelete = checked; 0148 }); 0149 // Delete 0150 connect(KSMessageBox::Instance(), &KSMessageBox::accepted, this, [this, pos, file]() 0151 { 0152 KSMessageBox::Instance()->disconnect(this); 0153 bool success = false; 0154 if (this->m_permanentlyDelete == false && (success = file->moveToTrash())) 0155 { 0156 qCInfo(KSTARS_EKOS_CAPTURE) << overlay->currentFrame().filename << "moved to Trash."; 0157 } 0158 else if (this->m_permanentlyDelete && (success = file->remove())) 0159 { 0160 qCInfo(KSTARS_EKOS_CAPTURE) << overlay->currentFrame().filename << "deleted."; 0161 } 0162 0163 if (success) 0164 { 0165 // delete it from the history and update the FITS view 0166 if (overlay->deleteFrame(pos) && overlay->hasFrames()) 0167 { 0168 m_fitsPreview->loadFile(overlay->currentFrame().filename); 0169 // Hint: since the FITSView loads in the background, we have to wait for FITSView::load() to enable the layer 0170 } 0171 else 0172 { 0173 m_fitsPreview->clearData(); 0174 overlay->setEnabled(true); 0175 } 0176 } 0177 else 0178 { 0179 qCWarning(KSTARS_EKOS_CAPTURE) << "Deleting" << overlay->currentFrame().filename << "failed!"; 0180 // give up 0181 overlay->setEnabled(true); 0182 } 0183 // clear the check box 0184 KSMessageBox::Instance()->setCheckBox(nullptr); 0185 }); 0186 0187 // Cancel 0188 connect(KSMessageBox::Instance(), &KSMessageBox::rejected, this, [this]() 0189 { 0190 KSMessageBox::Instance()->disconnect(this); 0191 // clear the check box 0192 KSMessageBox::Instance()->setCheckBox(nullptr); 0193 //do nothing 0194 overlay->setEnabled(true); 0195 }); 0196 0197 // open the message box 0198 QFileInfo fileinfo(current.filename); 0199 KSMessageBox::Instance()->warningContinueCancel(i18n("Do you really want to delete %1 from the file system?", 0200 fileinfo.fileName()), 0201 i18n("Delete %1", fileinfo.fileName()), 0, false, i18n("Delete")); 0202 0203 } 0204 0205 void CapturePreviewWidget::setSummaryFITSView(SummaryFITSView *view) 0206 { 0207 m_fitsPreview = view; 0208 QVBoxLayout * vlayout = new QVBoxLayout(); 0209 vlayout->setContentsMargins(0, 0, 0, 0); 0210 vlayout->addWidget(view); 0211 previewWidget->setLayout(vlayout); 0212 previewWidget->setContentsMargins(0, 0, 0, 0); 0213 0214 // initialize the FITS data overlay 0215 // create vertically info box as overlay 0216 QVBoxLayout *layout = new QVBoxLayout(view->processInfoWidget); 0217 layout->addWidget(overlay, 0); 0218 0219 view->processInfoWidget->setLayout(layout); 0220 // react upon signals 0221 connect(view, &FITSView::loaded, [&]() 0222 { 0223 overlay->setEnabled(true); 0224 }); 0225 connect(view, &FITSView::failed, [&]() 0226 { 0227 overlay->setEnabled(true); 0228 }); 0229 } 0230 0231 void CapturePreviewWidget::setEnabled(bool enabled) 0232 { 0233 // forward to sub widget 0234 captureCountsWidget->setEnabled(enabled); 0235 QWidget::setEnabled(enabled); 0236 } 0237 0238 void CapturePreviewWidget::reset() 0239 { 0240 overlay->setVisible(false); 0241 // forward to sub widget 0242 captureCountsWidget->reset(); 0243 } 0244 0245 void CapturePreviewWidget::updateCaptureStatus(Ekos::CaptureState status) 0246 { 0247 // forward to sub widgets 0248 captureStatusWidget->setCaptureState(status); 0249 captureCountsWidget->updateCaptureStatus(status); 0250 } 0251 0252 void CapturePreviewWidget::updateTargetDistance(double targetDiff) 0253 { 0254 // forward it to the overlay 0255 overlay->updateTargetDistance(targetDiff); 0256 } 0257 0258 void CapturePreviewWidget::updateCaptureCountDown(int delta) 0259 { 0260 // forward to sub widget 0261 captureCountsWidget->updateCaptureCountDown(delta); 0262 } 0263 0264 void CapturePreviewWidget::setTargetName(QString name) 0265 { 0266 targetLabel->setVisible(!name.isEmpty()); 0267 mountTarget->setVisible(!name.isEmpty()); 0268 mountTarget->setText(name); 0269 m_mountTarget = name; 0270 m_currentFrame.target = name; 0271 } 0272