Kstars

stellarsolverprofileeditor.cpp
1/*
2 SPDX-FileCopyrightText: 2017 Jasem Mutlaq <mutlaqja@ikarustech.com>
3 SPDX-FileCopyrightText: 2017 Robert Lancaster <rlancaste@gmail.com>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6*/
7
8#include "stellarsolverprofileeditor.h"
9
10#include "kstars.h"
11#include "Options.h"
12#include "kspaths.h"
13#include "ksmessagebox.h"
14#include "stellarsolverprofile.h"
15
16#include <KConfigDialog>
17#include <QInputDialog>
18#include <QFileDialog>
19#include <QSettings>
20#include <stellarsolver.h>
21
22namespace Ekos
23{
24
25void StellarSolverProfileEditor::showEvent(QShowEvent *e)
26{
28 // Since we can have multiple editors (in align, fitsviewer, image overlay)
29 // make sure every time we bring up the editor we have the most recent profiles.
30 // This won't update an editor that's showing if we happen to have 2 being displayed
31 // at the same time, but that's a rare event (that could be fixed with more effort).
32 // The issue with the above, though, is that loading profiles changes the value of the
33 // currently edited profile. So, we cache the value and restore it after loading.
34 QString currentProfile = optionsProfile->currentText();
35 loadProfiles(false);
36 optionsProfile->setCurrentText(currentProfile);
37}
38
39StellarSolverProfileEditor::StellarSolverProfileEditor(QWidget *parent, ProfileGroup group,
40 KConfigDialog *dialog) : QWidget(KStars::Instance())
41{
42 Q_UNUSED(parent);
43 setupUi(this);
44
45 //Get a pointer to the KConfigDialog
46 m_ConfigDialog = dialog;
47
48 setProfileGroup(group);
49 optionsProfileGroup->setEnabled(false);
50
51 /* // we may want to do this eventually
52 connect(optionsProfileGroup, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index){
53 setProfileGroup((ProfileGroup)index);
54 });
55 */
56
57 openProfile->setIcon(
58 QIcon::fromTheme("document-open"));
60 connect(openProfile, &QPushButton::clicked, this, &StellarSolverProfileEditor::openSingleProfile);
61
62 saveProfile->setIcon(
63 QIcon::fromTheme("document-save"));
64 saveProfile->setAttribute(Qt::WA_LayoutUsesWidgetRect);
65 connect(saveProfile, &QPushButton::clicked, this, &StellarSolverProfileEditor::saveSingleProfile);
66
67 /* This is not implemented yet.
68 copyProfile->setIcon(
69 QIcon::fromTheme("edit-copy"));
70 copyProfile->setAttribute(Qt::WA_LayoutUsesWidgetRect);
71 */
72 copyProfile->setVisible(false); //until we enable it.
73
74 saveBackups->setIcon(
75 QIcon::fromTheme("document-save"));
77 connect(saveBackups, &QPushButton::clicked, this, &StellarSolverProfileEditor::saveBackupProfiles);
78
79 loadBackups->setIcon(
80 QIcon::fromTheme("document-open"));
82 connect(loadBackups, &QPushButton::clicked, this, &StellarSolverProfileEditor::openBackupProfiles);
83
84 reloadProfiles->setIcon(
85 QIcon::fromTheme("system-reboot"));
87 connect(reloadProfiles, &QPushButton::clicked, this, &StellarSolverProfileEditor::loadProfiles);
88
89 loadDefaults->setIcon(
90 QIcon::fromTheme("go-down"));
92 connect(loadDefaults, &QPushButton::clicked, this, &StellarSolverProfileEditor::loadDefaultProfiles);
93
95 {
96 bool ok;
97 QString name = QInputDialog::getText(this, tr("New Options Profile"),
98 tr("What would you like your profile to be called?"), QLineEdit::Normal,
99 "", &ok);
100 if (ok && !name.isEmpty())
101 {
102 disconnectOptionsProfileComboBox();
103 SSolver::Parameters params = getSettingsFromUI();
104 params.listName = name;
105 optionsList.append(params);
106 optionsProfile->addItem(name);
107 optionsProfile->setCurrentText(name);
108 openOptionsProfileNum = optionsProfile->count() - 1;
109 settingJustChanged();
110 connectOptionsProfileComboBox();
111 }
112 });
113
115 {
116 if(optionsList.count() == 0)
117 return;
118 int item = optionsProfile->currentIndex();
119 disconnectOptionsProfileComboBox();
120 optionsProfile->removeItem(item);
121 optionsList.removeAt(item);
122 if(optionsProfile->count() > 0)
123 {
124 if(item > optionsList.count() - 1) //So that it doesn't try to set the new list to a nonexistant one
125 item--;
126 openOptionsProfileNum = item;
127 loadOptionsProfileIgnoreOldSettings(item); //Because the old one no longer exists
128 }
129 settingJustChanged();
130 connectOptionsProfileComboBox();
131 });
132
133 connect(description, &QTextEdit::textChanged, this, &StellarSolverProfileEditor::settingJustChanged);
134
136 for(QLineEdit *line : lines)
137 connect(line, &QLineEdit::textEdited, this, &StellarSolverProfileEditor::settingJustChanged);
138
140 for(QCheckBox *check : checks)
141 connect(check, &QCheckBox::stateChanged, this, &StellarSolverProfileEditor::settingJustChanged);
142
144 for(QComboBox *combo : combos)
145 {
146 if(combo != optionsProfile)
147 connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &StellarSolverProfileEditor::settingJustChanged);
148 }
149
151 for(QSpinBox *spin : spins)
152 connect(spin, QOverload<int>::of(&QSpinBox::valueChanged), this, &StellarSolverProfileEditor::settingJustChanged);
153
154 if(selectedProfileGroup != AlignProfiles)
155 astrometryOptions->setVisible(false);
156 connect(m_ConfigDialog->button(QDialogButtonBox::Apply), SIGNAL(clicked()), SLOT(slotApply()));
157 connect(m_ConfigDialog->button(QDialogButtonBox::Ok), SIGNAL(clicked()), SLOT(slotApply()));
158}
159
160void StellarSolverProfileEditor::setProfileGroup(ProfileGroup group, bool warn)
161{
162 selectedProfileGroup = group;
163 optionsProfileGroup->setCurrentIndex(static_cast<int>(group));
165 switch(selectedProfileGroup)
166 {
167 case AlignProfiles:
168 profileGroupFileName = "SavedAlignProfiles.ini";
169 break;
170 case FocusProfiles:
171 profileGroupFileName = "SavedFocusProfiles.ini";
172 break;
173 case GuideProfiles:
174 profileGroupFileName = "SavedGuideProfiles.ini";
175 break;
176 case HFRProfiles:
177 profileGroupFileName = "SavedHFRProfiles.ini";
178 break;
179 }
180
181 savedOptionsProfiles = QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(profileGroupFileName);
182 loadProfiles(warn);
183}
184
185void StellarSolverProfileEditor::connectOptionsProfileComboBox()
186{
188 &StellarSolverProfileEditor::loadOptionsProfile);
189}
190
191void StellarSolverProfileEditor::disconnectOptionsProfileComboBox()
192{
194 &StellarSolverProfileEditor::loadOptionsProfile);
195}
196
197void StellarSolverProfileEditor::settingJustChanged()
198{
199 optionsAreSaved = false;
200 m_ConfigDialog->button(QDialogButtonBox::Apply)->setEnabled(true);
201}
202
203void StellarSolverProfileEditor::loadProfile(const QString &profile)
204{
205 optionsProfile->setCurrentText(profile);
206}
207
208void StellarSolverProfileEditor::loadOptionsProfile()
209{
210 if(optionsProfile->count() == 0)
211 return;
212 if(openOptionsProfileNum < optionsList.count() && openOptionsProfileNum > 0)
213 {
214 SSolver::Parameters editorOptions = getSettingsFromUI();
215 SSolver::Parameters currentProfile = optionsList.at(openOptionsProfileNum);
216 if(!(editorOptions == currentProfile) || editorOptions.description != currentProfile.description)
217 {
218 editorOptions.listName = currentProfile.listName;
219 optionsList.replace(openOptionsProfileNum, editorOptions);
220 }
221 }
222 SSolver::Parameters newProfile = optionsList.at(optionsProfile->currentIndex());
223 QList<QWidget *> controls = this->findChildren<QWidget *>();
224 for(QWidget *control : controls)
225 control->blockSignals(true);
226 sendSettingsToUI(newProfile);
227 for(QWidget *control : controls)
228 control->blockSignals(false);
229 openOptionsProfileNum = optionsProfile->currentIndex();
230}
231
232void StellarSolverProfileEditor::loadOptionsProfileIgnoreOldSettings(int index)
233{
234 if(index >= optionsProfile->count())
235 return;
236 SSolver::Parameters newProfile = optionsList.at(index);
237 QList<QWidget *> controls = this->findChildren<QWidget *>();
238 for(QWidget *control : controls)
239 control->blockSignals(true);
240 sendSettingsToUI(newProfile);
241 optionsProfile->setCurrentIndex(index);
242 openOptionsProfileNum = optionsProfile->currentIndex();
243 for(QWidget *control : controls)
244 control->blockSignals(false);
245}
246
247//This sets all the settings for either the internal or external sextractor
248//based on the requested settings in the mainwindow interface.
249//If you are implementing the StellarSolver Library in your progra, you may choose to change some or all of these settings or use the defaults.
250SSolver::Parameters StellarSolverProfileEditor::getSettingsFromUI()
251{
252 SSolver::Parameters params;
253 params.description = description->toPlainText();
254 //These are to pass the parameters to the internal sextractor
255 params.apertureShape = (SSolver::Shape) apertureShape->currentIndex();
256 params.kron_fact = kron_fact->text().toDouble();
257 params.subpix = subpix->text().toInt() ;
258 params.r_min = r_min->text().toFloat();
259 params.magzero = magzero->text().toFloat();
260 params.threshold_bg_multiple = threshMultiple->text().toFloat();
261 params.threshold_offset = threshOffset->text().toFloat();
262 params.minarea = minarea->text().toFloat();
263 params.deblend_thresh = deblend_thresh->text().toInt();
264 params.deblend_contrast = deblend_contrast->text().toFloat();
265 params.clean = (cleanCheckBox->isChecked()) ? 1 : 0;
266 params.clean_param = clean_param->text().toDouble();
267 params.convFilterType = (SSolver::ConvFilterType) convFilter->currentIndex();
268 params.fwhm = fwhm->value();
269
270 //Star Filter Settings
271 params.resort = resort->isChecked();
272 params.maxSize = maxSize->text().toDouble();
273 params.minSize = minSize->text().toDouble();
274 params.maxEllipse = maxEllipse->text().toDouble();
275 params.initialKeep = initialKeep->text().toInt();
276 params.keepNum = keepNum->text().toInt();
277 params.removeBrightest = brightestPercent->text().toDouble();
278 params.removeDimmest = dimmestPercent->text().toDouble();
279 params.saturationLimit = saturationLimit->text().toDouble();
280
281 //Settings that usually get set by the config file
282
283 params.maxwidth = maxWidth->text().toDouble();
284 params.minwidth = minWidth->text().toDouble();
285 params.inParallel = inParallel->isChecked();
286 params.multiAlgorithm = (SSolver::MultiAlgo)multiAlgo->currentIndex();
287 params.solverTimeLimit = solverTimeLimit->text().toInt();
288
289 params.resort = resort->isChecked();
290 params.autoDownsample = autoDownsample->isChecked();
291 params.downsample = downsample->value();
292 params.search_radius = radius->text().toDouble();
293
294 return params;
295}
296
297void StellarSolverProfileEditor::sendSettingsToUI(SSolver::Parameters a)
298{
299
300 description->setText(a.description);
301 //Sextractor Settings
302
303 apertureShape->setCurrentIndex(a.apertureShape);
304 kron_fact->setText(QString::number(a.kron_fact));
305 subpix->setText(QString::number(a.subpix));
306 r_min->setText(QString::number(a.r_min));
307
308 magzero->setText(QString::number(a.magzero));
309 threshMultiple->setText(QString::number(a.threshold_bg_multiple));
310 threshOffset->setText(QString::number(a.threshold_offset));
311 minarea->setText(QString::number(a.minarea));
312 deblend_thresh->setText(QString::number(a.deblend_thresh));
313 deblend_contrast->setText(QString::number(a.deblend_contrast));
314 cleanCheckBox->setChecked(a.clean == 1);
315 clean_param->setText(QString::number(a.clean_param));
316 convFilter->setCurrentIndex(a.convFilterType);
317 fwhm->setValue(a.fwhm);
318
319 //Star Filter Settings
320
321 maxSize->setText(QString::number(a.maxSize));
322 minSize->setText(QString::number(a.minSize));
323 maxEllipse->setText(QString::number(a.maxEllipse));
324 initialKeep->setText(QString::number(a.initialKeep));
325 keepNum->setText(QString::number(a.keepNum));
326 brightestPercent->setText(QString::number(a.removeBrightest));
327 dimmestPercent->setText(QString::number(a.removeDimmest));
328 saturationLimit->setText(QString::number(a.saturationLimit));
329
330 //Astrometry Settings
331
332 autoDownsample->setChecked(a.autoDownsample);
333 downsample->setValue(a.downsample);
334 inParallel->setChecked(a.inParallel);
335 multiAlgo->setCurrentIndex(a.multiAlgorithm);
336 solverTimeLimit->setText(QString::number(a.solverTimeLimit));
337 minWidth->setText(QString::number(a.minwidth));
338 maxWidth->setText(QString::number(a.maxwidth));
339 radius->setText(QString::number(a.search_radius));
340 resort->setChecked(a.resort);
341}
342
343void StellarSolverProfileEditor::copySingleProfile()
344{
345
346}
347
348void StellarSolverProfileEditor::openSingleProfile()
349{
350 QString fileURL = QFileDialog::getOpenFileName(nullptr, "Load Options Profiles File", dirPath,
351 "INI files(*.ini)");
352 if (fileURL.isEmpty())
353 return;
355 {
356 KSMessageBox::warning(this, "Message", "The file doesn't exist");
357 return;
358 }
360 QStringList groups = settings.childGroups();
361 for(QString group : groups)
362 {
363 settings.beginGroup(group);
364 QStringList keys = settings.childKeys();
366 for(QString key : keys)
367 map.insert(key, settings.value(key));
368 SSolver::Parameters newParams = SSolver::Parameters::convertFromMap(map);
369 optionsList.append(newParams);
370 optionsProfile->addItem(group);
371 }
372 if(optionsProfile->count() > 0)
373 loadProfile(groups.first());
374 m_ConfigDialog->button(QDialogButtonBox::Apply)->setEnabled(true);
375}
376
377void StellarSolverProfileEditor::loadProfiles(bool warn)
378{
379 if(warn && !optionsAreSaved )
380 {
381 if(QMessageBox::question(this, "Abort?",
382 "You made unsaved changes in the settings, do you really wish to overwrite them?") == QMessageBox::No)
383 {
384 return;
385 }
386 optionsAreSaved = true; //They just got overwritten
387 }
388 disconnectOptionsProfileComboBox();
389 optionsProfile->clear();
390 if(QFile(savedOptionsProfiles).exists())
391 optionsList = StellarSolver::loadSavedOptionsProfiles(savedOptionsProfiles);
392 else
393 optionsList = getDefaultProfiles();
394 if (selectedProfileGroup == FocusProfiles)
395 {
396 bool defaultProfile = false;
397 bool defaultProfileDonut = false;
398 for(SSolver::Parameters params : optionsList)
399 {
400 optionsProfile->addItem(params.listName);
401 if (params.listName == FOCUS_DEFAULT_NAME)
402 defaultProfile = true;
403 else if (params.listName == FOCUS_DEFAULT_DONUT_NAME)
404 defaultProfileDonut = true;
405 }
406 if (!defaultProfile)
407 {
408 optionsList.append(getFocusOptionsProfileDefault());
409 optionsProfile->addItem(FOCUS_DEFAULT_NAME);
410 }
412 {
413 optionsList.append(getFocusOptionsProfileDefaultDonut());
414 optionsProfile->addItem(FOCUS_DEFAULT_DONUT_NAME);
415 }
416 }
417 else
418 {
419 for(SSolver::Parameters params : optionsList)
420 optionsProfile->addItem(params.listName);
421 }
422 if(optionsList.count() > 0)
423 {
424 sendSettingsToUI(optionsList.at(0));
425 openOptionsProfileNum = 0;
426 }
427 connectOptionsProfileComboBox();
428 m_ConfigDialog->button(QDialogButtonBox::Apply)->setEnabled(false);
429}
430
431void StellarSolverProfileEditor::saveSingleProfile()
432{
433 QString fileURL = QFileDialog::getSaveFileName(nullptr, "Save Options Profiles", dirPath,
434 "INI files(*.ini)");
435 if (fileURL.isEmpty())
436 return;
438 SSolver::Parameters params = optionsList.at(optionsProfile->currentIndex());
439 settings.beginGroup(params.listName);
440 QMap<QString, QVariant> map = SSolver::Parameters::convertToMap(params);
442 while(it.hasNext())
443 {
444 it.next();
445 settings.setValue(it.key(), it.value());
446 }
447 settings.endGroup();
448}
449
450void StellarSolverProfileEditor::saveProfiles()
451{
452 QSettings settings(savedOptionsProfiles, QSettings::IniFormat);
453 for(int i = 0 ; i < optionsList.count(); i++)
454 {
455 SSolver::Parameters params = optionsList.at(i);
456 settings.beginGroup(params.listName);
457 QMap<QString, QVariant> map = SSolver::Parameters::convertToMap(params);
459 while(it.hasNext())
460 {
461 it.next();
462 settings.setValue(it.key(), it.value());
463 }
464 settings.endGroup();
465 }
466 QStringList groups = settings.childGroups();
467 for(QString group : groups)
468 {
469 bool groupInList = false;
470 for(SSolver::Parameters params : optionsList)
471 {
472 if(params.listName == group)
473 groupInList = true;
474 }
475 if( ! groupInList)
476 settings.remove(group);
477 }
478}
479
480QList<SSolver::Parameters> StellarSolverProfileEditor::getDefaultProfiles()
481{
482 switch(selectedProfileGroup)
483 {
484 case FocusProfiles:
485 return getDefaultFocusOptionsProfiles();
486 case HFRProfiles:
487 return getDefaultHFROptionsProfiles();
488 case GuideProfiles:
489 return getDefaultGuideOptionsProfiles();
490 default:
491 case AlignProfiles:
492 return getDefaultAlignOptionsProfiles();
493 }
494}
495
496void StellarSolverProfileEditor::loadDefaultProfiles()
497{
498 if( !optionsAreSaved )
499 {
500 if(QMessageBox::question(this, "Abort?",
501 "You made unsaved changes in the settings, do you really wish to overwrite them?") == QMessageBox::No)
502 {
503 return;
504 }
505 optionsAreSaved = true; //They just got overwritten
506 }
507 disconnectOptionsProfileComboBox();
508 optionsList = getDefaultProfiles();
509 optionsProfile->clear();
510 for(SSolver::Parameters param : optionsList)
511 optionsProfile->addItem(param.listName);
512 connectOptionsProfileComboBox();
513 if(optionsProfile->count() > 0)
514 loadOptionsProfileIgnoreOldSettings(0);
515 m_ConfigDialog->button(QDialogButtonBox::Apply)->setEnabled(true);
516}
517
518void StellarSolverProfileEditor::saveBackupProfiles()
519{
520 QString fileURL = QFileDialog::getSaveFileName(nullptr, "Save Options Profiles", dirPath,
521 "INI files(*.ini)");
522 if (fileURL.isEmpty())
523 return;
525 for(int i = 0 ; i < optionsList.count(); i++)
526 {
527 SSolver::Parameters params = optionsList.at(i);
528 settings.beginGroup(params.listName);
529 QMap<QString, QVariant> map = SSolver::Parameters::convertToMap(params);
531 while(it.hasNext())
532 {
533 it.next();
534 settings.setValue(it.key(), it.value());
535 }
536 settings.endGroup();
537 }
538}
539
540void StellarSolverProfileEditor::openBackupProfiles()
541{
542 QString fileURL = QFileDialog::getOpenFileName(nullptr, "Load Options Profiles File", dirPath,
543 "INI files(*.ini)");
544 if (fileURL.isEmpty())
545 return;
546 if(!QFileInfo(fileURL).exists())
547 {
548 QMessageBox::warning(this, "Message", "The file doesn't exist");
549 return;
550 }
551 disconnectOptionsProfileComboBox();
552 optionsList.clear();
554 QStringList groups = settings.childGroups();
555 for(QString group : groups)
556 {
557 settings.beginGroup(group);
558 QStringList keys = settings.childKeys();
560 for(QString key : keys)
561 map.insert(key, settings.value(key));
562 SSolver::Parameters newParams = SSolver::Parameters::convertFromMap(map);
563 optionsList.append(newParams);
564 optionsProfile->addItem(group);
565 }
566 if(optionsProfile->count() > 0)
567 loadOptionsProfileIgnoreOldSettings(0);
568 connectOptionsProfileComboBox();
569 m_ConfigDialog->button(QDialogButtonBox::Apply)->setEnabled(true);
570}
571
572void StellarSolverProfileEditor::slotApply()
573{
574 int index = optionsProfile->currentIndex();
575 SSolver::Parameters currentParams = getSettingsFromUI();
576
577 if (index >= 0 && index < optionsList.count())
578 {
579 SSolver::Parameters savedParams = optionsList.at(index);
580 if(!(currentParams == savedParams) || currentParams.description != savedParams.description)
581 {
582 currentParams.listName = savedParams.listName;
583 optionsList.replace(index, currentParams);
584 }
585 }
586 optionsAreSaved = true;
587
588 saveProfiles();
589 emit optionsProfilesUpdated();
590}
591
592}
This is the main window for KStars.
Definition kstars.h:91
Ekos is an advanced Astrophotography tool for Linux.
Definition align.cpp:78
KGuiItem insert()
QString name(StandardShortcut id)
void clicked(bool checked)
void currentIndexChanged(int index)
QString filePath(const QString &fileName) const const
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, Options options)
bool exists() const const
Int toInt() const const
QIcon fromTheme(const QString &name)
QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, Qt::WindowFlags flags, Qt::InputMethodHints inputMethodHints)
T & first()
StandardButton question(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
StandardButton warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
QString & append(QChar ch)
const QChar at(qsizetype position) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
WA_LayoutUsesWidgetRect
QFuture< void > map(Iterator begin, Iterator end, MapFunctor &&function)
void textChanged()
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
virtual void showEvent(QShowEvent *event)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:02 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.