File indexing completed on 2024-04-28 03:43:10
0001 /* 0002 SPDX-FileCopyrightText: 2017 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 SPDX-FileCopyrightText: 2017 Robert Lancaster <rlancaste@gmail.com> 0004 0005 SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 #include "stellarsolverprofileeditor.h" 0009 0010 #include "kstars.h" 0011 #include "Options.h" 0012 #include "kspaths.h" 0013 #include "ksmessagebox.h" 0014 #include "stellarsolverprofile.h" 0015 0016 #include <KConfigDialog> 0017 #include <QInputDialog> 0018 #include <QFileDialog> 0019 #include <QSettings> 0020 #include <stellarsolver.h> 0021 0022 namespace Ekos 0023 { 0024 StellarSolverProfileEditor::StellarSolverProfileEditor(QWidget *parent, ProfileGroup group, 0025 KConfigDialog *dialog) : QWidget(KStars::Instance()) 0026 { 0027 Q_UNUSED(parent); 0028 setupUi(this); 0029 0030 //Get a pointer to the KConfigDialog 0031 m_ConfigDialog = dialog; 0032 0033 setProfileGroup(group); 0034 optionsProfileGroup->setEnabled(false); 0035 0036 /* // we may want to do this eventually 0037 connect(optionsProfileGroup, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index){ 0038 setProfileGroup((ProfileGroup)index); 0039 }); 0040 */ 0041 0042 openProfile->setIcon( 0043 QIcon::fromTheme("document-open")); 0044 openProfile->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0045 connect(openProfile, &QPushButton::clicked, this, &StellarSolverProfileEditor::openSingleProfile); 0046 0047 saveProfile->setIcon( 0048 QIcon::fromTheme("document-save")); 0049 saveProfile->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0050 connect(saveProfile, &QPushButton::clicked, this, &StellarSolverProfileEditor::saveSingleProfile); 0051 0052 /* This is not implemented yet. 0053 copyProfile->setIcon( 0054 QIcon::fromTheme("edit-copy")); 0055 copyProfile->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0056 */ 0057 copyProfile->setVisible(false); //until we enable it. 0058 0059 saveBackups->setIcon( 0060 QIcon::fromTheme("document-save")); 0061 saveBackups->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0062 connect(saveBackups, &QPushButton::clicked, this, &StellarSolverProfileEditor::saveBackupProfiles); 0063 0064 loadBackups->setIcon( 0065 QIcon::fromTheme("document-open")); 0066 loadBackups->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0067 connect(loadBackups, &QPushButton::clicked, this, &StellarSolverProfileEditor::openBackupProfiles); 0068 0069 reloadProfiles->setIcon( 0070 QIcon::fromTheme("system-reboot")); 0071 reloadProfiles->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0072 connect(reloadProfiles, &QPushButton::clicked, this, &StellarSolverProfileEditor::loadProfiles); 0073 0074 loadDefaults->setIcon( 0075 QIcon::fromTheme("go-down")); 0076 loadDefaults->setAttribute(Qt::WA_LayoutUsesWidgetRect); 0077 connect(loadDefaults, &QPushButton::clicked, this, &StellarSolverProfileEditor::loadDefaultProfiles); 0078 0079 connect(addOptionProfile, &QAbstractButton::clicked, this, [this]() 0080 { 0081 bool ok; 0082 QString name = QInputDialog::getText(this, tr("New Options Profile"), 0083 tr("What would you like your profile to be called?"), QLineEdit::Normal, 0084 "", &ok); 0085 if (ok && !name.isEmpty()) 0086 { 0087 disconnectOptionsProfileComboBox(); 0088 SSolver::Parameters params = getSettingsFromUI(); 0089 params.listName = name; 0090 optionsList.append(params); 0091 optionsProfile->addItem(name); 0092 optionsProfile->setCurrentText(name); 0093 openOptionsProfileNum = optionsProfile->count() - 1; 0094 settingJustChanged(); 0095 connectOptionsProfileComboBox(); 0096 } 0097 }); 0098 0099 connect(removeOptionProfile, &QAbstractButton::clicked, this, [this]() 0100 { 0101 if(optionsList.count() == 0) 0102 return; 0103 int item = optionsProfile->currentIndex(); 0104 disconnectOptionsProfileComboBox(); 0105 optionsProfile->removeItem(item); 0106 optionsList.removeAt(item); 0107 if(optionsProfile->count() > 0) 0108 { 0109 if(item > optionsList.count() - 1) //So that it doesn't try to set the new list to a nonexistant one 0110 item--; 0111 openOptionsProfileNum = item; 0112 loadOptionsProfileIgnoreOldSettings(item); //Because the old one no longer exists 0113 } 0114 settingJustChanged(); 0115 connectOptionsProfileComboBox(); 0116 }); 0117 0118 connect(description, &QTextEdit::textChanged, this, &StellarSolverProfileEditor::settingJustChanged); 0119 0120 QList<QLineEdit *> lines = this->findChildren<QLineEdit *>(); 0121 for(QLineEdit *line : lines) 0122 connect(line, &QLineEdit::textEdited, this, &StellarSolverProfileEditor::settingJustChanged); 0123 0124 QList<QCheckBox *> checks = this->findChildren<QCheckBox *>(); 0125 for(QCheckBox *check : checks) 0126 connect(check, &QCheckBox::stateChanged, this, &StellarSolverProfileEditor::settingJustChanged); 0127 0128 QList<QComboBox *> combos = this->findChildren<QComboBox *>(); 0129 for(QComboBox *combo : combos) 0130 { 0131 if(combo != optionsProfile) 0132 connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &StellarSolverProfileEditor::settingJustChanged); 0133 } 0134 0135 QList<QSpinBox *> spins = this->findChildren<QSpinBox *>(); 0136 for(QSpinBox *spin : spins) 0137 connect(spin, QOverload<int>::of(&QSpinBox::valueChanged), this, &StellarSolverProfileEditor::settingJustChanged); 0138 0139 if(selectedProfileGroup != AlignProfiles) 0140 astrometryOptions->setVisible(false); 0141 connect(m_ConfigDialog->button(QDialogButtonBox::Apply), SIGNAL(clicked()), SLOT(slotApply())); 0142 connect(m_ConfigDialog->button(QDialogButtonBox::Ok), SIGNAL(clicked()), SLOT(slotApply())); 0143 } 0144 0145 void StellarSolverProfileEditor::setProfileGroup(ProfileGroup group) 0146 { 0147 selectedProfileGroup = group; 0148 optionsProfileGroup->setCurrentIndex(static_cast<int>(group)); 0149 QString profileGroupFileName; 0150 switch(selectedProfileGroup) 0151 { 0152 case AlignProfiles: 0153 profileGroupFileName = "SavedAlignProfiles.ini"; 0154 break; 0155 case FocusProfiles: 0156 profileGroupFileName = "SavedFocusProfiles.ini"; 0157 break; 0158 case GuideProfiles: 0159 profileGroupFileName = "SavedGuideProfiles.ini"; 0160 break; 0161 case HFRProfiles: 0162 profileGroupFileName = "SavedHFRProfiles.ini"; 0163 break; 0164 } 0165 0166 savedOptionsProfiles = QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation)).filePath(profileGroupFileName); 0167 loadProfiles(); 0168 } 0169 0170 void StellarSolverProfileEditor::connectOptionsProfileComboBox() 0171 { 0172 connect(optionsProfile, QOverload<int>::of(&QComboBox::currentIndexChanged), this, 0173 &StellarSolverProfileEditor::loadOptionsProfile); 0174 } 0175 0176 void StellarSolverProfileEditor::disconnectOptionsProfileComboBox() 0177 { 0178 disconnect(optionsProfile, QOverload<int>::of(&QComboBox::currentIndexChanged), this, 0179 &StellarSolverProfileEditor::loadOptionsProfile); 0180 } 0181 0182 void StellarSolverProfileEditor::settingJustChanged() 0183 { 0184 optionsAreSaved = false; 0185 m_ConfigDialog->button(QDialogButtonBox::Apply)->setEnabled(true); 0186 } 0187 0188 void StellarSolverProfileEditor::loadProfile(const QString &profile) 0189 { 0190 optionsProfile->setCurrentText(profile); 0191 } 0192 0193 void StellarSolverProfileEditor::loadOptionsProfile() 0194 { 0195 if(optionsProfile->count() == 0) 0196 return; 0197 if(openOptionsProfileNum < optionsList.count() && openOptionsProfileNum > 0) 0198 { 0199 SSolver::Parameters editorOptions = getSettingsFromUI(); 0200 SSolver::Parameters currentProfile = optionsList.at(openOptionsProfileNum); 0201 if(!(editorOptions == currentProfile) || editorOptions.description != currentProfile.description) 0202 { 0203 editorOptions.listName = currentProfile.listName; 0204 optionsList.replace(openOptionsProfileNum, editorOptions); 0205 } 0206 } 0207 SSolver::Parameters newProfile = optionsList.at(optionsProfile->currentIndex()); 0208 QList<QWidget *> controls = this->findChildren<QWidget *>(); 0209 for(QWidget *control : controls) 0210 control->blockSignals(true); 0211 sendSettingsToUI(newProfile); 0212 for(QWidget *control : controls) 0213 control->blockSignals(false); 0214 openOptionsProfileNum = optionsProfile->currentIndex(); 0215 } 0216 0217 void StellarSolverProfileEditor::loadOptionsProfileIgnoreOldSettings(int index) 0218 { 0219 if(index >= optionsProfile->count()) 0220 return; 0221 SSolver::Parameters newProfile = optionsList.at(index); 0222 QList<QWidget *> controls = this->findChildren<QWidget *>(); 0223 for(QWidget *control : controls) 0224 control->blockSignals(true); 0225 sendSettingsToUI(newProfile); 0226 optionsProfile->setCurrentIndex(index); 0227 openOptionsProfileNum = optionsProfile->currentIndex(); 0228 for(QWidget *control : controls) 0229 control->blockSignals(false); 0230 } 0231 0232 //This sets all the settings for either the internal or external sextractor 0233 //based on the requested settings in the mainwindow interface. 0234 //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. 0235 SSolver::Parameters StellarSolverProfileEditor::getSettingsFromUI() 0236 { 0237 SSolver::Parameters params; 0238 params.description = description->toPlainText(); 0239 //These are to pass the parameters to the internal sextractor 0240 params.apertureShape = (SSolver::Shape) apertureShape->currentIndex(); 0241 params.kron_fact = kron_fact->text().toDouble(); 0242 params.subpix = subpix->text().toInt() ; 0243 params.r_min = r_min->text().toFloat(); 0244 params.magzero = magzero->text().toFloat(); 0245 params.threshold_bg_multiple = threshMultiple->text().toFloat(); 0246 params.threshold_offset = threshOffset->text().toFloat(); 0247 params.minarea = minarea->text().toFloat(); 0248 params.deblend_thresh = deblend_thresh->text().toInt(); 0249 params.deblend_contrast = deblend_contrast->text().toFloat(); 0250 params.clean = (cleanCheckBox->isChecked()) ? 1 : 0; 0251 params.clean_param = clean_param->text().toDouble(); 0252 params.convFilterType = (SSolver::ConvFilterType) convFilter->currentIndex(); 0253 params.fwhm = fwhm->value(); 0254 0255 //Star Filter Settings 0256 params.resort = resort->isChecked(); 0257 params.maxSize = maxSize->text().toDouble(); 0258 params.minSize = minSize->text().toDouble(); 0259 params.maxEllipse = maxEllipse->text().toDouble(); 0260 params.initialKeep = initialKeep->text().toInt(); 0261 params.keepNum = keepNum->text().toInt(); 0262 params.removeBrightest = brightestPercent->text().toDouble(); 0263 params.removeDimmest = dimmestPercent->text().toDouble(); 0264 params.saturationLimit = saturationLimit->text().toDouble(); 0265 0266 //Settings that usually get set by the config file 0267 0268 params.maxwidth = maxWidth->text().toDouble(); 0269 params.minwidth = minWidth->text().toDouble(); 0270 params.inParallel = inParallel->isChecked(); 0271 params.multiAlgorithm = (SSolver::MultiAlgo)multiAlgo->currentIndex(); 0272 params.solverTimeLimit = solverTimeLimit->text().toInt(); 0273 0274 params.resort = resort->isChecked(); 0275 params.autoDownsample = autoDownsample->isChecked(); 0276 params.downsample = downsample->value(); 0277 params.search_radius = radius->text().toDouble(); 0278 0279 return params; 0280 } 0281 0282 void StellarSolverProfileEditor::sendSettingsToUI(SSolver::Parameters a) 0283 { 0284 0285 description->setText(a.description); 0286 //Sextractor Settings 0287 0288 apertureShape->setCurrentIndex(a.apertureShape); 0289 kron_fact->setText(QString::number(a.kron_fact)); 0290 subpix->setText(QString::number(a.subpix)); 0291 r_min->setText(QString::number(a.r_min)); 0292 0293 magzero->setText(QString::number(a.magzero)); 0294 threshMultiple->setText(QString::number(a.threshold_bg_multiple)); 0295 threshOffset->setText(QString::number(a.threshold_offset)); 0296 minarea->setText(QString::number(a.minarea)); 0297 deblend_thresh->setText(QString::number(a.deblend_thresh)); 0298 deblend_contrast->setText(QString::number(a.deblend_contrast)); 0299 cleanCheckBox->setChecked(a.clean == 1); 0300 clean_param->setText(QString::number(a.clean_param)); 0301 convFilter->setCurrentIndex(a.convFilterType); 0302 fwhm->setValue(a.fwhm); 0303 0304 //Star Filter Settings 0305 0306 maxSize->setText(QString::number(a.maxSize)); 0307 minSize->setText(QString::number(a.minSize)); 0308 maxEllipse->setText(QString::number(a.maxEllipse)); 0309 initialKeep->setText(QString::number(a.initialKeep)); 0310 keepNum->setText(QString::number(a.keepNum)); 0311 brightestPercent->setText(QString::number(a.removeBrightest)); 0312 dimmestPercent->setText(QString::number(a.removeDimmest)); 0313 saturationLimit->setText(QString::number(a.saturationLimit)); 0314 0315 //Astrometry Settings 0316 0317 autoDownsample->setChecked(a.autoDownsample); 0318 downsample->setValue(a.downsample); 0319 inParallel->setChecked(a.inParallel); 0320 multiAlgo->setCurrentIndex(a.multiAlgorithm); 0321 solverTimeLimit->setText(QString::number(a.solverTimeLimit)); 0322 minWidth->setText(QString::number(a.minwidth)); 0323 maxWidth->setText(QString::number(a.maxwidth)); 0324 radius->setText(QString::number(a.search_radius)); 0325 resort->setChecked(a.resort); 0326 } 0327 0328 void StellarSolverProfileEditor::copySingleProfile() 0329 { 0330 0331 } 0332 0333 void StellarSolverProfileEditor::openSingleProfile() 0334 { 0335 QString fileURL = QFileDialog::getOpenFileName(nullptr, "Load Options Profiles File", dirPath, 0336 "INI files(*.ini)"); 0337 if (fileURL.isEmpty()) 0338 return; 0339 if(!QFileInfo::exists(fileURL)) 0340 { 0341 KSMessageBox::warning(this, "Message", "The file doesn't exist"); 0342 return; 0343 } 0344 QSettings settings(fileURL, QSettings::IniFormat); 0345 QStringList groups = settings.childGroups(); 0346 for(QString group : groups) 0347 { 0348 settings.beginGroup(group); 0349 QStringList keys = settings.childKeys(); 0350 QMap<QString, QVariant> map; 0351 for(QString key : keys) 0352 map.insert(key, settings.value(key)); 0353 SSolver::Parameters newParams = SSolver::Parameters::convertFromMap(map); 0354 optionsList.append(newParams); 0355 optionsProfile->addItem(group); 0356 } 0357 if(optionsProfile->count() > 0) 0358 loadProfile(groups.first()); 0359 m_ConfigDialog->button(QDialogButtonBox::Apply)->setEnabled(true); 0360 } 0361 0362 void StellarSolverProfileEditor::loadProfiles() 0363 { 0364 if( !optionsAreSaved ) 0365 { 0366 if(QMessageBox::question(this, "Abort?", 0367 "You made unsaved changes in the settings, do you really wish to overwrite them?") == QMessageBox::No) 0368 { 0369 return; 0370 } 0371 optionsAreSaved = true; //They just got overwritten 0372 } 0373 disconnectOptionsProfileComboBox(); 0374 optionsProfile->clear(); 0375 if(QFile(savedOptionsProfiles).exists()) 0376 optionsList = StellarSolver::loadSavedOptionsProfiles(savedOptionsProfiles); 0377 else 0378 optionsList = getDefaultProfiles(); 0379 for(SSolver::Parameters params : optionsList) 0380 optionsProfile->addItem(params.listName); 0381 if(optionsList.count() > 0) 0382 { 0383 sendSettingsToUI(optionsList.at(0)); 0384 openOptionsProfileNum = 0; 0385 } 0386 connectOptionsProfileComboBox(); 0387 m_ConfigDialog->button(QDialogButtonBox::Apply)->setEnabled(false); 0388 } 0389 0390 void StellarSolverProfileEditor::saveSingleProfile() 0391 { 0392 QString fileURL = QFileDialog::getSaveFileName(nullptr, "Save Options Profiles", dirPath, 0393 "INI files(*.ini)"); 0394 if (fileURL.isEmpty()) 0395 return; 0396 QSettings settings(fileURL, QSettings::IniFormat); 0397 SSolver::Parameters params = optionsList.at(optionsProfile->currentIndex()); 0398 settings.beginGroup(params.listName); 0399 QMap<QString, QVariant> map = SSolver::Parameters::convertToMap(params); 0400 QMapIterator<QString, QVariant> it(map); 0401 while(it.hasNext()) 0402 { 0403 it.next(); 0404 settings.setValue(it.key(), it.value()); 0405 } 0406 settings.endGroup(); 0407 } 0408 0409 void StellarSolverProfileEditor::saveProfiles() 0410 { 0411 QSettings settings(savedOptionsProfiles, QSettings::IniFormat); 0412 for(int i = 0 ; i < optionsList.count(); i++) 0413 { 0414 SSolver::Parameters params = optionsList.at(i); 0415 settings.beginGroup(params.listName); 0416 QMap<QString, QVariant> map = SSolver::Parameters::convertToMap(params); 0417 QMapIterator<QString, QVariant> it(map); 0418 while(it.hasNext()) 0419 { 0420 it.next(); 0421 settings.setValue(it.key(), it.value()); 0422 } 0423 settings.endGroup(); 0424 } 0425 QStringList groups = settings.childGroups(); 0426 for(QString group : groups) 0427 { 0428 bool groupInList = false; 0429 for(SSolver::Parameters params : optionsList) 0430 { 0431 if(params.listName == group) 0432 groupInList = true; 0433 } 0434 if( ! groupInList) 0435 settings.remove(group); 0436 } 0437 } 0438 0439 QList<SSolver::Parameters> StellarSolverProfileEditor::getDefaultProfiles() 0440 { 0441 switch(selectedProfileGroup) 0442 { 0443 case FocusProfiles: 0444 return getDefaultFocusOptionsProfiles(); 0445 case HFRProfiles: 0446 return getDefaultHFROptionsProfiles(); 0447 case GuideProfiles: 0448 return getDefaultGuideOptionsProfiles(); 0449 default: 0450 case AlignProfiles: 0451 return getDefaultAlignOptionsProfiles(); 0452 } 0453 } 0454 0455 void StellarSolverProfileEditor::loadDefaultProfiles() 0456 { 0457 if( !optionsAreSaved ) 0458 { 0459 if(QMessageBox::question(this, "Abort?", 0460 "You made unsaved changes in the settings, do you really wish to overwrite them?") == QMessageBox::No) 0461 { 0462 return; 0463 } 0464 optionsAreSaved = true; //They just got overwritten 0465 } 0466 disconnectOptionsProfileComboBox(); 0467 optionsList = getDefaultProfiles(); 0468 optionsProfile->clear(); 0469 for(SSolver::Parameters param : optionsList) 0470 optionsProfile->addItem(param.listName); 0471 connectOptionsProfileComboBox(); 0472 if(optionsProfile->count() > 0) 0473 loadOptionsProfileIgnoreOldSettings(0); 0474 m_ConfigDialog->button(QDialogButtonBox::Apply)->setEnabled(true); 0475 } 0476 0477 void StellarSolverProfileEditor::saveBackupProfiles() 0478 { 0479 QString fileURL = QFileDialog::getSaveFileName(nullptr, "Save Options Profiles", dirPath, 0480 "INI files(*.ini)"); 0481 if (fileURL.isEmpty()) 0482 return; 0483 QSettings settings(fileURL, QSettings::IniFormat); 0484 for(int i = 0 ; i < optionsList.count(); i++) 0485 { 0486 SSolver::Parameters params = optionsList.at(i); 0487 settings.beginGroup(params.listName); 0488 QMap<QString, QVariant> map = SSolver::Parameters::convertToMap(params); 0489 QMapIterator<QString, QVariant> it(map); 0490 while(it.hasNext()) 0491 { 0492 it.next(); 0493 settings.setValue(it.key(), it.value()); 0494 } 0495 settings.endGroup(); 0496 } 0497 } 0498 0499 void StellarSolverProfileEditor::openBackupProfiles() 0500 { 0501 QString fileURL = QFileDialog::getOpenFileName(nullptr, "Load Options Profiles File", dirPath, 0502 "INI files(*.ini)"); 0503 if (fileURL.isEmpty()) 0504 return; 0505 if(!QFileInfo(fileURL).exists()) 0506 { 0507 QMessageBox::warning(this, "Message", "The file doesn't exist"); 0508 return; 0509 } 0510 disconnectOptionsProfileComboBox(); 0511 optionsList.clear(); 0512 QSettings settings(fileURL, QSettings::IniFormat); 0513 QStringList groups = settings.childGroups(); 0514 for(QString group : groups) 0515 { 0516 settings.beginGroup(group); 0517 QStringList keys = settings.childKeys(); 0518 QMap<QString, QVariant> map; 0519 for(QString key : keys) 0520 map.insert(key, settings.value(key)); 0521 SSolver::Parameters newParams = SSolver::Parameters::convertFromMap(map); 0522 optionsList.append(newParams); 0523 optionsProfile->addItem(group); 0524 } 0525 if(optionsProfile->count() > 0) 0526 loadOptionsProfileIgnoreOldSettings(0); 0527 connectOptionsProfileComboBox(); 0528 m_ConfigDialog->button(QDialogButtonBox::Apply)->setEnabled(true); 0529 } 0530 0531 void StellarSolverProfileEditor::slotApply() 0532 { 0533 int index = optionsProfile->currentIndex(); 0534 SSolver::Parameters currentParams = getSettingsFromUI(); 0535 SSolver::Parameters savedParams = optionsList.at(index); 0536 if(!(currentParams == savedParams) || currentParams.description != savedParams.description) 0537 { 0538 currentParams.listName = savedParams.listName; 0539 optionsList.replace(index, currentParams); 0540 } 0541 optionsAreSaved = true; 0542 0543 saveProfiles(); 0544 emit optionsProfilesUpdated(); 0545 } 0546 0547 }