File indexing completed on 2024-04-28 03:43:08
0001 /* 0002 SPDX-FileCopyrightText: 2022 Jasem Mutlaq <mutlaqja@ikarustech.com> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "opticaltrainmanager.h" 0008 #include <kstars_debug.h> 0009 0010 #include "ksnotification.h" 0011 #include "kstarsdata.h" 0012 #include "kstars.h" 0013 #include "indi/indilistener.h" 0014 #include "ekos/auxiliary/profilesettings.h" 0015 #include "oal/equipmentwriter.h" 0016 0017 #include <QTimer> 0018 #include <QSqlTableModel> 0019 #include <QSqlDatabase> 0020 #include <QSqlRecord> 0021 0022 #include <basedevice.h> 0023 0024 #include <algorithm> 0025 0026 namespace Ekos 0027 { 0028 0029 OpticalTrainManager *OpticalTrainManager::m_Instance = nullptr; 0030 0031 //////////////////////////////////////////////////////////////////////////// 0032 /// 0033 //////////////////////////////////////////////////////////////////////////// 0034 OpticalTrainManager *OpticalTrainManager::Instance() 0035 { 0036 if (m_Instance == nullptr) 0037 m_Instance = new OpticalTrainManager(); 0038 0039 return m_Instance; 0040 } 0041 0042 //////////////////////////////////////////////////////////////////////////// 0043 /// 0044 //////////////////////////////////////////////////////////////////////////// 0045 void OpticalTrainManager::release() 0046 { 0047 delete(m_Instance); 0048 m_Instance = nullptr; 0049 } 0050 0051 //////////////////////////////////////////////////////////////////////////// 0052 /// 0053 //////////////////////////////////////////////////////////////////////////// 0054 OpticalTrainManager::OpticalTrainManager() : QDialog(KStars::Instance()) 0055 { 0056 #ifdef Q_OS_OSX 0057 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); 0058 #endif 0059 0060 setupUi(this); 0061 0062 connect(this, &QDialog::finished, this, [this]() 0063 { 0064 emit configurationRequested(false); 0065 }); 0066 0067 // Mount Combo 0068 connect(mountComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, 0069 [this]() 0070 { 0071 updateOpticalTrainValue(mountComboBox, "mount"); 0072 }); 0073 0074 // DustCap Combo 0075 connect(dustCapComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, 0076 [this]() 0077 { 0078 updateOpticalTrainValue(dustCapComboBox, "dustcap"); 0079 }); 0080 0081 // Light Box 0082 connect(lightBoxComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, 0083 [this]() 0084 { 0085 updateOpticalTrainValue(lightBoxComboBox, "lightbox"); 0086 }); 0087 0088 // Scope / Lens 0089 connect(scopeComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, 0090 [this]() 0091 { 0092 updateOpticalTrainValue(scopeComboBox, "scope"); 0093 }); 0094 0095 // Reducer 0096 connect(reducerSpinBox, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, 0097 [this](double value) 0098 { 0099 updateOpticalTrainValue(value, "reducer"); 0100 }); 0101 0102 // Rotator 0103 connect(rotatorComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, 0104 [this]() 0105 { 0106 updateOpticalTrainValue(rotatorComboBox, "rotator"); 0107 }); 0108 0109 // Focuser 0110 connect(focusComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, 0111 [this]() 0112 { 0113 updateOpticalTrainValue(focusComboBox, "focuser"); 0114 }); 0115 0116 // Filter Wheel 0117 connect(filterComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, 0118 [this]() 0119 { 0120 updateOpticalTrainValue(filterComboBox, "filterwheel"); 0121 }); 0122 0123 // Camera 0124 connect(cameraComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, 0125 [this]() 0126 { 0127 updateOpticalTrainValue(cameraComboBox, "camera"); 0128 }); 0129 0130 // Guider 0131 connect(guiderComboBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, 0132 [this]() 0133 { 0134 updateOpticalTrainValue(guiderComboBox, "guider"); 0135 }); 0136 0137 connect(addB, &QPushButton::clicked, this, [this]() 0138 { 0139 addOpticalTrain(m_TrainNames.count(), i18n("New Train")); 0140 m_OpticalTrainsModel->select(); 0141 refreshModel(); 0142 trainNamesList->setCurrentRow(trainNamesList->count() - 1); 0143 selectOpticalTrain(trainNamesList->currentItem()); 0144 }); 0145 0146 connect(removeB, &QPushButton::clicked, this, [this]() 0147 { 0148 if (trainNamesList->currentItem() != nullptr) 0149 { 0150 removeOpticalTrain(trainNamesList->currentItem()->text()); 0151 removeB->setEnabled(false); 0152 } 0153 }); 0154 0155 connect(resetB, &QPushButton::clicked, this, &OpticalTrainManager::reset); 0156 0157 connect(opticalElementsB, &QPushButton::clicked, this, [this]() 0158 { 0159 QScopedPointer<EquipmentWriter> writer(new EquipmentWriter()); 0160 writer->loadEquipment(); 0161 writer->exec(); 0162 refreshOpticalElements(); 0163 }); 0164 0165 connect(trainNamesList, &QListWidget::itemClicked, this, [this](QListWidgetItem * item) 0166 { 0167 selectOpticalTrain(item); 0168 }); 0169 connect(trainNamesList, &QListWidget::itemChanged, this, [this](QListWidgetItem * item) 0170 { 0171 renameCurrentOpticalTrain(item->text()); 0172 }); 0173 connect(trainNamesList, &QListWidget::currentRowChanged, this, [this](int row) 0174 { 0175 if (row >= 0) 0176 selectOpticalTrain(trainNamesList->currentItem()); 0177 }); 0178 0179 m_CheckMissingDevicesTimer.setInterval(5000); 0180 m_CheckMissingDevicesTimer.setSingleShot(true); 0181 connect(&m_CheckMissingDevicesTimer, &QTimer::timeout, this, &OpticalTrainManager::checkMissingDevices); 0182 0183 m_DelegateTimer.setInterval(1000); 0184 m_DelegateTimer.setSingleShot(true); 0185 connect(&m_DelegateTimer, &QTimer::timeout, this, [this]() 0186 { 0187 if (m_Profile) 0188 setProfile(m_Profile); 0189 }); 0190 0191 initModel(); 0192 } 0193 0194 //////////////////////////////////////////////////////////////////////////// 0195 /// 0196 //////////////////////////////////////////////////////////////////////////// 0197 void OpticalTrainManager::initModel() 0198 { 0199 auto userdb = QSqlDatabase::database(KStarsData::Instance()->userdb()->connectionName()); 0200 m_OpticalTrainsModel = new QSqlTableModel(this, userdb); 0201 connect(m_OpticalTrainsModel, &QSqlTableModel::dataChanged, this, [this]() 0202 { 0203 m_OpticalTrains.clear(); 0204 for (int i = 0; i < m_OpticalTrainsModel->rowCount(); ++i) 0205 { 0206 QVariantMap recordMap; 0207 QSqlRecord record = m_OpticalTrainsModel->record(i); 0208 for (int j = 0; j < record.count(); j++) 0209 recordMap[record.fieldName(j)] = record.value(j); 0210 0211 m_OpticalTrains.append(recordMap); 0212 } 0213 0214 m_TrainNames.clear(); 0215 for (auto &oneTrain : m_OpticalTrains) 0216 m_TrainNames << oneTrain["name"].toString(); 0217 0218 trainNamesList->clear(); 0219 trainNamesList->addItems(m_TrainNames); 0220 trainNamesList->setEditTriggers(QAbstractItemView::AllEditTriggers); 0221 emit updated(); 0222 }); 0223 } 0224 0225 void OpticalTrainManager::syncDevices() 0226 { 0227 syncDelegatesToDevices(); 0228 if (m_Profile) 0229 { 0230 refreshModel(); 0231 emit updated(); 0232 } 0233 } 0234 0235 //////////////////////////////////////////////////////////////////////////// 0236 /// 0237 //////////////////////////////////////////////////////////////////////////// 0238 void OpticalTrainManager::refreshModel() 0239 { 0240 KStars::Instance()->data()->userdb()->GetOpticalTrains(m_Profile->id, m_OpticalTrains); 0241 m_TrainNames.clear(); 0242 for (auto &oneTrain : m_OpticalTrains) 0243 m_TrainNames << oneTrain["name"].toString(); 0244 0245 trainNamesList->clear(); 0246 trainNamesList->addItems(m_TrainNames); 0247 } 0248 0249 //////////////////////////////////////////////////////////////////////////// 0250 /// 0251 //////////////////////////////////////////////////////////////////////////// 0252 void OpticalTrainManager::syncActiveDevices() 0253 { 0254 for (auto &oneTrain : m_OpticalTrains) 0255 { 0256 auto train = oneTrain["name"].toString(); 0257 QSharedPointer<ISD::GenericDevice> device; 0258 0259 if (getGenericDevice(train, Mount, device)) 0260 syncActiveProperties(oneTrain, device); 0261 if (getGenericDevice(train, Camera, device)) 0262 syncActiveProperties(oneTrain, device); 0263 if (getGenericDevice(train, GuideVia, device)) 0264 syncActiveProperties(oneTrain, device); 0265 if (getGenericDevice(train, Focuser, device)) 0266 syncActiveProperties(oneTrain, device); 0267 if (getGenericDevice(train, FilterWheel, device)) 0268 syncActiveProperties(oneTrain, device); 0269 if (getGenericDevice(train, Rotator, device)) 0270 syncActiveProperties(oneTrain, device); 0271 if (getGenericDevice(train, DustCap, device)) 0272 syncActiveProperties(oneTrain, device); 0273 if (getGenericDevice(train, LightBox, device)) 0274 syncActiveProperties(oneTrain, device); 0275 } 0276 } 0277 0278 //////////////////////////////////////////////////////////////////////////// 0279 /// 0280 //////////////////////////////////////////////////////////////////////////// 0281 void OpticalTrainManager::syncActiveProperties(const QVariantMap &train, const QSharedPointer<ISD::GenericDevice> &device) 0282 { 0283 auto tvp = device->getProperty("ACTIVE_DEVICES"); 0284 if (!tvp) 0285 return; 0286 0287 auto name = train["name"].toString(); 0288 0289 for (auto &it : *tvp.getText()) 0290 { 0291 QList<QSharedPointer<ISD::GenericDevice>> devs; 0292 QString elementText = it.getText(); 0293 if (it.isNameMatch("ACTIVE_TELESCOPE")) 0294 { 0295 auto activeDevice = train["mount"].toString(); 0296 if (activeDevice == "--") 0297 elementText.clear(); 0298 else if (activeDevice != elementText) 0299 { 0300 QSharedPointer<ISD::GenericDevice> genericDevice; 0301 if (getGenericDevice(name, Mount, genericDevice)) 0302 devs.append(genericDevice); 0303 } 0304 } 0305 else if (it.isNameMatch("ACTIVE_DOME")) 0306 { 0307 devs = INDIListener::devicesByInterface(INDI::BaseDevice::DOME_INTERFACE); 0308 } 0309 else if (it.isNameMatch("ACTIVE_GPS")) 0310 { 0311 devs = INDIListener::devicesByInterface(INDI::BaseDevice::GPS_INTERFACE); 0312 } 0313 else if (it.isNameMatch("ACTIVE_ROTATOR")) 0314 { 0315 auto activeDevice = train["rotator"].toString(); 0316 if (activeDevice == "--") 0317 elementText.clear(); 0318 else if (activeDevice != elementText) 0319 { 0320 QSharedPointer<ISD::GenericDevice> genericDevice; 0321 if (getGenericDevice(name, Rotator, genericDevice)) 0322 devs.append(genericDevice); 0323 } 0324 } 0325 else if (it.isNameMatch("ACTIVE_FOCUSER")) 0326 { 0327 auto activeDevice = train["focuser"].toString(); 0328 if (activeDevice == "--") 0329 elementText.clear(); 0330 else if (activeDevice != elementText) 0331 { 0332 QSharedPointer<ISD::GenericDevice> genericDevice; 0333 if (getGenericDevice(name, Focuser, genericDevice)) 0334 devs.append(genericDevice); 0335 } 0336 } 0337 else if (it.isNameMatch("ACTIVE_FILTER")) 0338 { 0339 auto activeDevice = train["filterwheel"].toString(); 0340 if (activeDevice == "--") 0341 elementText.clear(); 0342 else if (activeDevice != elementText) 0343 { 0344 QSharedPointer<ISD::GenericDevice> genericDevice; 0345 if (getGenericDevice(name, FilterWheel, genericDevice)) 0346 devs.append(genericDevice); 0347 } 0348 } 0349 0350 if (!devs.empty()) 0351 { 0352 if (it.getText() != devs.first()->getDeviceName()) 0353 { 0354 it.setText(devs.first()->getDeviceName().toLatin1().constData()); 0355 device->sendNewProperty(tvp.getText()); 0356 } 0357 } 0358 // Clear element if required 0359 else if (elementText.isEmpty() && !QString(it.getText()).isEmpty()) 0360 { 0361 it.setText(""); 0362 device->sendNewProperty(tvp.getText()); 0363 } 0364 } 0365 0366 } 0367 0368 //////////////////////////////////////////////////////////////////////////// 0369 /// 0370 //////////////////////////////////////////////////////////////////////////// 0371 void OpticalTrainManager::setProfile(const QSharedPointer<ProfileInfo> &profile) 0372 { 0373 m_DelegateTimer.stop(); 0374 0375 // Load optical train model 0376 if (m_Profile != profile) 0377 { 0378 m_Profile = profile; 0379 refreshModel(); 0380 } 0381 0382 // Are we still updating delegates? If yes, return. 0383 if (syncDelegatesToDevices()) 0384 { 0385 m_CheckMissingDevicesTimer.start(); 0386 0387 // Start delegate timer to ensure no more changes are pending. 0388 m_DelegateTimer.start(); 0389 0390 syncActiveDevices(); 0391 } 0392 else 0393 { 0394 checkOpticalTrains(); 0395 } 0396 } 0397 0398 //////////////////////////////////////////////////////////////////////////// 0399 /// 0400 //////////////////////////////////////////////////////////////////////////// 0401 void OpticalTrainManager::checkOpticalTrains() 0402 { 0403 if (m_OpticalTrains.empty()) 0404 { 0405 generateOpticalTrains(); 0406 refreshModel(); 0407 if (!m_OpticalTrains.empty()) 0408 { 0409 auto primaryTrainID = m_OpticalTrains[0]["id"].toUInt(); 0410 ProfileSettings::Instance()->setOneSetting(ProfileSettings::PrimaryOpticalTrain, primaryTrainID); 0411 ProfileSettings::Instance()->setOneSetting(ProfileSettings::CaptureOpticalTrain, primaryTrainID); 0412 ProfileSettings::Instance()->setOneSetting(ProfileSettings::FocusOpticalTrain, primaryTrainID); 0413 ProfileSettings::Instance()->setOneSetting(ProfileSettings::MountOpticalTrain, primaryTrainID); 0414 ProfileSettings::Instance()->setOneSetting(ProfileSettings::AlignOpticalTrain, primaryTrainID); 0415 ProfileSettings::Instance()->setOneSetting(ProfileSettings::DarkLibraryOpticalTrain, primaryTrainID); 0416 if (m_OpticalTrains.count() > 1) 0417 ProfileSettings::Instance()->setOneSetting(ProfileSettings::GuideOpticalTrain, m_OpticalTrains[1]["id"].toInt()); 0418 else 0419 ProfileSettings::Instance()->setOneSetting(ProfileSettings::GuideOpticalTrain, primaryTrainID); 0420 } 0421 0422 emit updated(); 0423 show(); 0424 raise(); 0425 emit configurationRequested(true); 0426 } 0427 else 0428 { 0429 m_CheckMissingDevicesTimer.start(); 0430 emit updated(); 0431 } 0432 } 0433 //////////////////////////////////////////////////////////////////////////// 0434 /// This method tries to guess possible optical train configuration 0435 //////////////////////////////////////////////////////////////////////////// 0436 void OpticalTrainManager::generateOpticalTrains() 0437 { 0438 // We should have primary train 0439 addOpticalTrain(0, i18n("Primary")); 0440 // Check if need secondary train 0441 if (cameraComboBox->count() > 2) 0442 addOpticalTrain(1, i18n("Secondary")); 0443 // Check if need tertiary train 0444 if (cameraComboBox->count() > 3) 0445 addOpticalTrain(2, i18n("Tertiary")); 0446 } 0447 0448 //////////////////////////////////////////////////////////////////////////// 0449 /// 0450 //////////////////////////////////////////////////////////////////////////// 0451 QString OpticalTrainManager::addOpticalTrain(uint8_t index, const QString &name) 0452 { 0453 QVariantMap train; 0454 train["profile"] = m_Profile->id; 0455 train["name"] = uniqueTrainName(name); 0456 0457 train["mount"] = mountComboBox->itemText(mountComboBox->count() - 1); 0458 train["dustcap"] = dustCapComboBox->itemText(dustCapComboBox->count() - 1); 0459 train["lightbox"] = lightBoxComboBox->itemText(lightBoxComboBox->count() - 1); 0460 train["reducer"] = 1.0; 0461 train["rotator"] = rotatorComboBox->itemText(rotatorComboBox->count() - 1); 0462 train["focuser"] = focusComboBox->itemText(focusComboBox->count() - 1); 0463 train["filterwheel"] = filterComboBox->itemText(filterComboBox->count() - 1); 0464 train["guider"] = guiderComboBox->itemText(guiderComboBox->count() - 1); 0465 0466 QJsonObject opticalElement; 0467 if (KStars::Instance()->data()->userdb()->getLastOpticalElement(opticalElement)) 0468 train["scope"] = opticalElement["name"].toString(); 0469 0470 train["camera"] = "--"; 0471 // Primary train 0472 if (index == 0 && cameraComboBox->count() > 1) 0473 train["camera"] = cameraComboBox->itemText(1); 0474 // Any other trains 0475 else if (index > 0) 0476 { 0477 // For 2nd train and beyond, we get the N camera appropiate for this train if one exist. 0478 // We add + 1 because first element in combobox is "--" 0479 auto cameraIndex = index + 1; 0480 if (cameraComboBox->count() >= cameraIndex) 0481 train["camera"] = cameraComboBox->itemText(cameraIndex); 0482 } 0483 0484 KStarsData::Instance()->userdb()->AddOpticalTrain(train); 0485 return train["name"].toString(); 0486 } 0487 0488 //////////////////////////////////////////////////////////////////////////// 0489 /// 0490 //////////////////////////////////////////////////////////////////////////// 0491 void OpticalTrainManager::addOpticalTrain(const QJsonObject &value) 0492 { 0493 auto newTrain = value.toVariantMap(); 0494 newTrain["profile"] = m_Profile->id; 0495 KStarsData::Instance()->userdb()->AddOpticalTrain(newTrain); 0496 0497 refreshTrains(); 0498 } 0499 0500 //////////////////////////////////////////////////////////////////////////// 0501 /// 0502 //////////////////////////////////////////////////////////////////////////// 0503 bool OpticalTrainManager::setOpticalTrainValue(const QString &name, const QString &field, const QVariant &value) 0504 { 0505 for (auto &oneTrain : m_OpticalTrains) 0506 { 0507 if (oneTrain["name"].toString() == name) 0508 { 0509 // If value did not change, just return true 0510 if (oneTrain[field] == value) 0511 return true; 0512 0513 // Update field and database. 0514 oneTrain[field] = value; 0515 KStarsData::Instance()->userdb()->UpdateOpticalTrain(oneTrain, oneTrain["id"].toInt()); 0516 syncActiveDevices(); 0517 emit updated(); 0518 return true; 0519 } 0520 } 0521 return false; 0522 } 0523 0524 //////////////////////////////////////////////////////////////////////////// 0525 /// 0526 //////////////////////////////////////////////////////////////////////////// 0527 void OpticalTrainManager::renameCurrentOpticalTrain(const QString &name) 0528 { 0529 if (m_CurrentOpticalTrain != nullptr && (*m_CurrentOpticalTrain)["name"] != name) 0530 { 0531 auto pos = trainNamesList->currentRow(); 0532 // ensure train name uniqueness 0533 auto unique = uniqueTrainName(name); 0534 // update the train database entry 0535 setOpticalTrainValue((*m_CurrentOpticalTrain)["name"].toString(), "name", unique); 0536 // propagate the unique name to the current selection 0537 trainNamesList->currentItem()->setText(unique); 0538 // refresh the trains 0539 refreshTrains(); 0540 // refresh selection 0541 selectOpticalTrain(unique); 0542 trainNamesList->setCurrentRow(pos); 0543 } 0544 } 0545 0546 //////////////////////////////////////////////////////////////////////////// 0547 /// 0548 //////////////////////////////////////////////////////////////////////////// 0549 bool OpticalTrainManager::setOpticalTrain(const QJsonObject &train) 0550 { 0551 auto oneOpticalTrain = getOpticalTrain(train["id"].toInt()); 0552 if (!oneOpticalTrain.empty()) 0553 { 0554 KStarsData::Instance()->userdb()->UpdateOpticalTrain(train.toVariantMap(), oneOpticalTrain["id"].toInt()); 0555 refreshTrains(); 0556 return true; 0557 } 0558 return false; 0559 } 0560 0561 //////////////////////////////////////////////////////////////////////////// 0562 /// 0563 //////////////////////////////////////////////////////////////////////////// 0564 bool OpticalTrainManager::removeOpticalTrain(const QString &name) 0565 { 0566 for (auto &oneTrain : m_OpticalTrains) 0567 { 0568 if (oneTrain["name"].toString() == name) 0569 { 0570 auto id = oneTrain["id"].toInt(); 0571 KStarsData::Instance()->userdb()->DeleteOpticalTrain(id); 0572 KStarsData::Instance()->userdb()->DeleteOpticalTrainSettings(id); 0573 refreshTrains(); 0574 selectOpticalTrain(nullptr); 0575 return true; 0576 } 0577 } 0578 0579 return false; 0580 } 0581 0582 //////////////////////////////////////////////////////////////////////////// 0583 /// 0584 //////////////////////////////////////////////////////////////////////////// 0585 bool OpticalTrainManager::syncDelegatesToDevices() 0586 { 0587 auto changed = false; 0588 0589 // Mounts 0590 auto mounts = INDIListener::devicesByInterface(INDI::BaseDevice::TELESCOPE_INTERFACE); 0591 QStringList values; 0592 for (auto &oneMount : mounts) 0593 values << oneMount->getDeviceName(); 0594 changed |= !values.empty() && values != m_MountNames; 0595 m_MountNames = values; 0596 auto currentMount = mountComboBox->currentText(); 0597 mountComboBox->clear(); 0598 mountComboBox->addItems(QStringList() << "--" << values); 0599 mountComboBox->setCurrentText(currentMount); 0600 0601 // Dust Caps 0602 values.clear(); 0603 auto dustcaps = INDIListener::devicesByInterface(INDI::BaseDevice::DUSTCAP_INTERFACE); 0604 for (auto &oneCap : dustcaps) 0605 values << oneCap->getDeviceName(); 0606 changed |= !values.empty() && values != m_DustCapNames; 0607 m_DustCapNames = values; 0608 auto currentCap = dustCapComboBox->currentText(); 0609 dustCapComboBox->clear(); 0610 dustCapComboBox->addItems(QStringList() << "--" << values); 0611 dustCapComboBox->setCurrentText(currentCap); 0612 0613 // Light Boxes 0614 values.clear(); 0615 auto lightboxes = INDIListener::devicesByInterface(INDI::BaseDevice::LIGHTBOX_INTERFACE); 0616 for (auto &oneBox : lightboxes) 0617 values << oneBox->getDeviceName(); 0618 changed |= !values.empty() && values != m_LightBoxNames; 0619 auto currentLightBox = lightBoxComboBox->currentText(); 0620 m_LightBoxNames = values; 0621 lightBoxComboBox->clear(); 0622 lightBoxComboBox->addItems(QStringList() << "--" << values); 0623 lightBoxComboBox->setCurrentText(currentLightBox); 0624 0625 // Scopes 0626 values = KStars::Instance()->data()->userdb()->getOpticalElementNames(); 0627 changed |= !values.empty() && values != m_ScopeNames; 0628 m_ScopeNames = values; 0629 auto currentScope = scopeComboBox->currentText(); 0630 scopeComboBox->clear(); 0631 scopeComboBox->addItems(QStringList() << "--" << values); 0632 scopeComboBox->setCurrentText(currentScope); 0633 0634 // Rotators 0635 values.clear(); 0636 auto rotators = INDIListener::devicesByInterface(INDI::BaseDevice::ROTATOR_INTERFACE); 0637 for (auto &oneRotator : rotators) 0638 values << oneRotator->getDeviceName(); 0639 changed |= !values.empty() && values != m_RotatorNames; 0640 m_RotatorNames = values; 0641 auto currentRotator = rotatorComboBox->currentText(); 0642 rotatorComboBox->clear(); 0643 rotatorComboBox->addItems(QStringList() << "--" << values); 0644 rotatorComboBox->setCurrentText(currentRotator); 0645 0646 // Focusers 0647 values.clear(); 0648 auto focusers = INDIListener::devicesByInterface(INDI::BaseDevice::FOCUSER_INTERFACE); 0649 for (auto &oneFocuser : focusers) 0650 values << oneFocuser->getDeviceName(); 0651 changed |= !values.empty() && values != m_FocuserNames; 0652 m_FocuserNames = values; 0653 auto currentFocuser = focusComboBox->currentText(); 0654 focusComboBox->clear(); 0655 focusComboBox->addItems(QStringList() << "--" << values); 0656 focusComboBox->setCurrentText(currentFocuser); 0657 0658 // Filter Wheels 0659 values.clear(); 0660 auto filterwheels = INDIListener::devicesByInterface(INDI::BaseDevice::FILTER_INTERFACE); 0661 for (auto &oneFilterWheel : filterwheels) 0662 values << oneFilterWheel->getDeviceName(); 0663 changed |= !values.empty() && values != m_FilterWheelNames; 0664 m_FilterWheelNames = values; 0665 auto currentFilter = filterComboBox->currentText(); 0666 filterComboBox->clear(); 0667 filterComboBox->addItems(QStringList() << "--" << values); 0668 filterComboBox->setCurrentText(currentFilter); 0669 0670 // Cameras 0671 values.clear(); 0672 auto cameras = INDIListener::devicesByInterface(INDI::BaseDevice::CCD_INTERFACE); 0673 for (auto &oneCamera : cameras) 0674 values << oneCamera->getDeviceName(); 0675 changed |= !values.empty() && values != m_CameraNames; 0676 m_CameraNames = values; 0677 auto currentCamera = cameraComboBox->currentText(); 0678 cameraComboBox->clear(); 0679 cameraComboBox->addItems(QStringList() << "--" << values); 0680 cameraComboBox->setCurrentText(currentCamera); 0681 0682 // Guiders 0683 values.clear(); 0684 auto guiders = INDIListener::devicesByInterface(INDI::BaseDevice::GUIDER_INTERFACE); 0685 for (auto &oneGuider : guiders) 0686 values << oneGuider->getDeviceName(); 0687 changed |= !values.empty() && values != m_GuiderNames; 0688 m_GuiderNames = values; 0689 auto currentGuider = guiderComboBox->currentText(); 0690 guiderComboBox->clear(); 0691 guiderComboBox->addItems(QStringList() << "--" << values); 0692 guiderComboBox->setCurrentText(currentGuider); 0693 0694 return changed; 0695 } 0696 0697 //////////////////////////////////////////////////////////////////////////// 0698 /// 0699 //////////////////////////////////////////////////////////////////////////// 0700 QString OpticalTrainManager::uniqueTrainName(QString name) 0701 { 0702 QString result = name; 0703 int nr = 1; 0704 while (m_TrainNames.contains(result)) 0705 result = QString("%1 (%2)").arg(name).arg(nr++); 0706 0707 return result; 0708 } 0709 0710 //////////////////////////////////////////////////////////////////////////// 0711 /// 0712 //////////////////////////////////////////////////////////////////////////// 0713 bool OpticalTrainManager::selectOpticalTrain(QListWidgetItem *item) 0714 { 0715 if (item != nullptr && selectOpticalTrain(item->text())) 0716 { 0717 item->setFlags(item->flags() | Qt::ItemIsEditable); 0718 return true; 0719 } 0720 return false; 0721 } 0722 0723 //////////////////////////////////////////////////////////////////////////// 0724 /// 0725 //////////////////////////////////////////////////////////////////////////// 0726 QString OpticalTrainManager::findTrainContainingDevice(const QString &name, Role role) 0727 { 0728 for (auto &oneTrain : m_OpticalTrains) 0729 { 0730 auto train = oneTrain["name"].toString(); 0731 0732 switch (role) 0733 { 0734 case Mount: 0735 if (oneTrain["mount"].toString() == name) 0736 return train; 0737 break; 0738 case Camera: 0739 if (oneTrain["camera"].toString() == name) 0740 return train; 0741 break; 0742 case Rotator: 0743 if (oneTrain["rotator"].toString() == name) 0744 return train; 0745 break; 0746 case GuideVia: 0747 if (oneTrain["guider"].toString() == name) 0748 return train; 0749 break; 0750 case DustCap: 0751 if (oneTrain["dustcap"].toString() == name) 0752 return train; 0753 break; 0754 case Scope: 0755 if (oneTrain["scope"].toString() == name) 0756 return train; 0757 break; 0758 case FilterWheel: 0759 if (oneTrain["filterwheel"].toString() == name) 0760 return train; 0761 break; 0762 case Focuser: 0763 if (oneTrain["focuser"].toString() == name) 0764 return train; 0765 break; 0766 case Reducer: 0767 if (oneTrain["reducer"].toString() == name) 0768 return train; 0769 break; 0770 case LightBox: 0771 if (oneTrain["lightbox"].toString() == name) 0772 return train; 0773 break; 0774 } 0775 0776 } 0777 0778 return QString(); 0779 } 0780 0781 //////////////////////////////////////////////////////////////////////////// 0782 /// 0783 //////////////////////////////////////////////////////////////////////////// 0784 bool OpticalTrainManager::selectOpticalTrain(const QString &name) 0785 { 0786 for (auto &oneTrain : m_OpticalTrains) 0787 { 0788 if (oneTrain["name"].toString() == name) 0789 { 0790 m_Persistent = false; 0791 m_CurrentOpticalTrain = &oneTrain; 0792 mountComboBox->setCurrentText(oneTrain["mount"].toString()); 0793 dustCapComboBox->setCurrentText(oneTrain["dustcap"].toString()); 0794 lightBoxComboBox->setCurrentText(oneTrain["lightbox"].toString()); 0795 scopeComboBox->setCurrentText(oneTrain["scope"].toString()); 0796 reducerSpinBox->setValue(oneTrain["reducer"].toDouble()); 0797 rotatorComboBox->setCurrentText(oneTrain["rotator"].toString()); 0798 focusComboBox->setCurrentText(oneTrain["focuser"].toString()); 0799 filterComboBox->setCurrentText(oneTrain["filterwheel"].toString()); 0800 cameraComboBox->setCurrentText(oneTrain["camera"].toString()); 0801 guiderComboBox->setCurrentText(oneTrain["guider"].toString()); 0802 removeB->setEnabled(m_OpticalTrains.length() > 1); 0803 trainConfigBox->setEnabled(true); 0804 m_Persistent = true; 0805 return true; 0806 } 0807 } 0808 0809 // none found 0810 m_Persistent = false; 0811 m_CurrentOpticalTrain = nullptr; 0812 mountComboBox->setCurrentText("--"); 0813 dustCapComboBox->setCurrentText("--"); 0814 lightBoxComboBox->setCurrentText("--"); 0815 scopeComboBox->setCurrentText("--"); 0816 reducerSpinBox->setValue(1.0); 0817 rotatorComboBox->setCurrentText("--"); 0818 focusComboBox->setCurrentText("--"); 0819 filterComboBox->setCurrentText("--"); 0820 cameraComboBox->setCurrentText("--"); 0821 guiderComboBox->setCurrentText("--"); 0822 removeB->setEnabled(false); 0823 trainConfigBox->setEnabled(false); 0824 m_Persistent = true; 0825 return false; 0826 } 0827 0828 //////////////////////////////////////////////////////////////////////////// 0829 /// 0830 //////////////////////////////////////////////////////////////////////////// 0831 void OpticalTrainManager::openEditor(const QString &name) 0832 { 0833 selectOpticalTrain(name); 0834 QList<QListWidgetItem*> matches = trainNamesList->findItems(name, Qt::MatchExactly); 0835 if (matches.count() > 0) 0836 trainNamesList->setCurrentItem(matches.first()); 0837 emit configurationRequested(true); 0838 show(); 0839 } 0840 0841 //////////////////////////////////////////////////////////////////////////// 0842 /// 0843 //////////////////////////////////////////////////////////////////////////// 0844 bool OpticalTrainManager::getGenericDevice(const QString &train, Role role, QSharedPointer<ISD::GenericDevice> &generic) 0845 { 0846 for (auto &oneTrain : m_OpticalTrains) 0847 { 0848 if (oneTrain["name"].toString() == train) 0849 { 0850 switch (role) 0851 { 0852 case Mount: 0853 return INDIListener::findDevice(oneTrain["mount"].toString(), generic); 0854 case Camera: 0855 return INDIListener::findDevice(oneTrain["camera"].toString(), generic); 0856 case Rotator: 0857 return INDIListener::findDevice(oneTrain["rotator"].toString(), generic); 0858 case GuideVia: 0859 return INDIListener::findDevice(oneTrain["guider"].toString(), generic); 0860 case DustCap: 0861 return INDIListener::findDevice(oneTrain["dustcap"].toString(), generic); 0862 case FilterWheel: 0863 return INDIListener::findDevice(oneTrain["filterwheel"].toString(), generic); 0864 case Focuser: 0865 return INDIListener::findDevice(oneTrain["focuser"].toString(), generic); 0866 case LightBox: 0867 return INDIListener::findDevice(oneTrain["lightbox"].toString(), generic); 0868 default: 0869 break; 0870 } 0871 } 0872 } 0873 0874 return false; 0875 } 0876 0877 //////////////////////////////////////////////////////////////////////////// 0878 /// 0879 //////////////////////////////////////////////////////////////////////////// 0880 ISD::Mount *OpticalTrainManager::getMount(const QString &name) 0881 { 0882 for (auto &oneTrain : m_OpticalTrains) 0883 { 0884 if (oneTrain["name"].toString() == name) 0885 { 0886 QSharedPointer<ISD::GenericDevice> generic; 0887 if (INDIListener::findDevice(oneTrain["mount"].toString(), generic)) 0888 return generic->getMount(); 0889 } 0890 } 0891 0892 return nullptr; 0893 } 0894 0895 //////////////////////////////////////////////////////////////////////////// 0896 /// 0897 //////////////////////////////////////////////////////////////////////////// 0898 ISD::DustCap *OpticalTrainManager::getDustCap(const QString &name) 0899 { 0900 for (auto &oneTrain : m_OpticalTrains) 0901 { 0902 if (oneTrain["name"].toString() == name) 0903 { 0904 QSharedPointer<ISD::GenericDevice> generic; 0905 if (INDIListener::findDevice(oneTrain["dustcap"].toString(), generic)) 0906 return generic->getDustCap(); 0907 } 0908 } 0909 0910 return nullptr; 0911 } 0912 0913 //////////////////////////////////////////////////////////////////////////// 0914 /// 0915 //////////////////////////////////////////////////////////////////////////// 0916 ISD::LightBox *OpticalTrainManager::getLightBox(const QString &name) 0917 { 0918 for (auto &oneTrain : m_OpticalTrains) 0919 { 0920 if (oneTrain["name"].toString() == name) 0921 { 0922 QSharedPointer<ISD::GenericDevice> generic; 0923 if (INDIListener::findDevice(oneTrain["lightbox"].toString(), generic)) 0924 return generic->getLightBox(); 0925 } 0926 } 0927 0928 return nullptr; 0929 } 0930 0931 //////////////////////////////////////////////////////////////////////////// 0932 /// 0933 //////////////////////////////////////////////////////////////////////////// 0934 QJsonObject OpticalTrainManager::getScope(const QString &name) 0935 { 0936 QJsonObject oneOpticalElement; 0937 for (auto &oneTrain : m_OpticalTrains) 0938 { 0939 if (oneTrain["name"].toString() == name) 0940 { 0941 if (KStars::Instance()->data()->userdb()->getOpticalElementByName(oneTrain["scope"].toString(), oneOpticalElement)) 0942 return oneOpticalElement; 0943 } 0944 } 0945 0946 return oneOpticalElement; 0947 } 0948 0949 //////////////////////////////////////////////////////////////////////////// 0950 /// 0951 //////////////////////////////////////////////////////////////////////////// 0952 double OpticalTrainManager::getReducer(const QString &name) 0953 { 0954 for (auto &oneTrain : m_OpticalTrains) 0955 { 0956 if (oneTrain["name"].toString() == name) 0957 return oneTrain["reducer"].toDouble(); 0958 } 0959 0960 return 1; 0961 } 0962 0963 //////////////////////////////////////////////////////////////////////////// 0964 /// 0965 //////////////////////////////////////////////////////////////////////////// 0966 ISD::Rotator *OpticalTrainManager::getRotator(const QString &name) 0967 { 0968 for (auto &oneTrain : m_OpticalTrains) 0969 { 0970 if (oneTrain["name"].toString() == name) 0971 { 0972 QSharedPointer<ISD::GenericDevice> generic; 0973 if (INDIListener::findDevice(oneTrain["rotator"].toString(), generic)) 0974 return generic->getRotator(); 0975 } 0976 } 0977 0978 return nullptr; 0979 } 0980 0981 //////////////////////////////////////////////////////////////////////////// 0982 /// 0983 //////////////////////////////////////////////////////////////////////////// 0984 ISD::Focuser *OpticalTrainManager::getFocuser(const QString &name) 0985 { 0986 for (auto &oneTrain : m_OpticalTrains) 0987 { 0988 if (oneTrain["name"].toString() == name) 0989 { 0990 QSharedPointer<ISD::GenericDevice> generic; 0991 if (INDIListener::findDevice(oneTrain["focuser"].toString(), generic)) 0992 return generic->getFocuser(); 0993 } 0994 } 0995 0996 return nullptr; 0997 } 0998 0999 //////////////////////////////////////////////////////////////////////////// 1000 /// 1001 //////////////////////////////////////////////////////////////////////////// 1002 ISD::FilterWheel *OpticalTrainManager::getFilterWheel(const QString &name) 1003 { 1004 for (auto &oneTrain : m_OpticalTrains) 1005 { 1006 if (oneTrain["name"].toString() == name) 1007 { 1008 QSharedPointer<ISD::GenericDevice> generic; 1009 if (INDIListener::findDevice(oneTrain["filterwheel"].toString(), generic)) 1010 return generic->getFilterWheel(); 1011 } 1012 } 1013 1014 return nullptr; 1015 } 1016 1017 //////////////////////////////////////////////////////////////////////////// 1018 /// 1019 //////////////////////////////////////////////////////////////////////////// 1020 ISD::Camera *OpticalTrainManager::getCamera(const QString &name) 1021 { 1022 for (auto &oneTrain : m_OpticalTrains) 1023 { 1024 if (oneTrain["name"].toString() == name) 1025 { 1026 QSharedPointer<ISD::GenericDevice> generic; 1027 if (INDIListener::findDevice(oneTrain["camera"].toString(), generic)) 1028 return generic->getCamera(); 1029 } 1030 } 1031 1032 return nullptr; 1033 } 1034 1035 //////////////////////////////////////////////////////////////////////////// 1036 /// 1037 //////////////////////////////////////////////////////////////////////////// 1038 ISD::Guider *OpticalTrainManager::getGuider(const QString &name) 1039 { 1040 for (auto &oneTrain : m_OpticalTrains) 1041 { 1042 if (oneTrain["name"].toString() == name) 1043 { 1044 QSharedPointer<ISD::GenericDevice> generic; 1045 if (INDIListener::findDevice(oneTrain["guider"].toString(), generic)) 1046 return generic->getGuider(); 1047 } 1048 } 1049 1050 return nullptr; 1051 } 1052 1053 //////////////////////////////////////////////////////////////////////////// 1054 /// 1055 //////////////////////////////////////////////////////////////////////////// 1056 ISD::AdaptiveOptics *OpticalTrainManager::getAdaptiveOptics(const QString &name) 1057 { 1058 // FIXME not implmeneted yet. 1059 // Need to add to database later 1060 for (auto &oneTrain : m_OpticalTrains) 1061 { 1062 if (oneTrain["name"].toString() == name) 1063 { 1064 QSharedPointer<ISD::GenericDevice> generic; 1065 if (INDIListener::findDevice(oneTrain["adaptiveoptics"].toString(), generic)) 1066 return generic->getAdaptiveOptics(); 1067 } 1068 } 1069 1070 return nullptr; 1071 } 1072 1073 //////////////////////////////////////////////////////////////////////////// 1074 /// 1075 //////////////////////////////////////////////////////////////////////////// 1076 const QVariantMap OpticalTrainManager::getOpticalTrain(uint8_t id) const 1077 { 1078 for (auto &oneTrain : m_OpticalTrains) 1079 { 1080 if (oneTrain["id"].toInt() == id) 1081 return oneTrain; 1082 } 1083 1084 return QVariantMap(); 1085 } 1086 1087 //////////////////////////////////////////////////////////////////////////// 1088 /// 1089 //////////////////////////////////////////////////////////////////////////// 1090 bool OpticalTrainManager::exists(uint8_t id) const 1091 { 1092 for (auto &oneTrain : m_OpticalTrains) 1093 { 1094 if (oneTrain["id"].toInt() == id) 1095 return true; 1096 } 1097 1098 return false; 1099 } 1100 1101 //////////////////////////////////////////////////////////////////////////// 1102 /// 1103 //////////////////////////////////////////////////////////////////////////// 1104 const QVariantMap OpticalTrainManager::getOpticalTrain(const QString &name) const 1105 { 1106 for (auto &oneTrain : m_OpticalTrains) 1107 { 1108 if (oneTrain["name"].toString() == name) 1109 return oneTrain; 1110 } 1111 1112 return QVariantMap(); 1113 } 1114 1115 //////////////////////////////////////////////////////////////////////////// 1116 /// 1117 //////////////////////////////////////////////////////////////////////////// 1118 void OpticalTrainManager::refreshTrains() 1119 { 1120 refreshModel(); 1121 emit updated(); 1122 } 1123 1124 //////////////////////////////////////////////////////////////////////////// 1125 /// 1126 //////////////////////////////////////////////////////////////////////////// 1127 void OpticalTrainManager::refreshOpticalElements() 1128 { 1129 m_ScopeNames = KStars::Instance()->data()->userdb()->getOpticalElementNames(); 1130 syncDelegatesToDevices(); 1131 } 1132 1133 //////////////////////////////////////////////////////////////////////////// 1134 /// 1135 //////////////////////////////////////////////////////////////////////////// 1136 int OpticalTrainManager::id(const QString &name) const 1137 { 1138 for (auto &oneTrain : m_OpticalTrains) 1139 { 1140 if (oneTrain["name"].toString() == name) 1141 return oneTrain["id"].toUInt(); 1142 } 1143 1144 return -1; 1145 } 1146 1147 //////////////////////////////////////////////////////////////////////////// 1148 /// 1149 //////////////////////////////////////////////////////////////////////////// 1150 QString OpticalTrainManager::name(int id) const 1151 { 1152 for (auto &oneTrain : m_OpticalTrains) 1153 { 1154 if (oneTrain["id"].toInt() == id) 1155 return oneTrain["name"].toString(); 1156 } 1157 1158 return QString(); 1159 } 1160 1161 //////////////////////////////////////////////////////////////////////////// 1162 /// 1163 //////////////////////////////////////////////////////////////////////////// 1164 void OpticalTrainManager::checkMissingDevices() 1165 { 1166 // Double check the sanity of the train. If devices are added or missing, then we need to show it to alert the user. 1167 auto devices = getMissingDevices(); 1168 if (!devices.empty()) 1169 { 1170 if (devices.count() == 1) 1171 { 1172 KSNotification::event(QLatin1String("IndiServerMessage"), 1173 i18n("Missing device detected (%1). Please reconfigure the optical trains before proceeding any further.", 1174 devices.first()), 1175 KSNotification::General, KSNotification::Warn); 1176 } 1177 else 1178 { 1179 KSNotification::event(QLatin1String("IndiServerMessage"), 1180 i18n("Missing devices detected (%1). Please reconfigure the optical trains before proceeding any further.", 1181 devices.join(", ")), 1182 KSNotification::General, KSNotification::Warn); 1183 } 1184 show(); 1185 raise(); 1186 emit configurationRequested(true); 1187 } 1188 } 1189 1190 //////////////////////////////////////////////////////////////////////////// 1191 /// 1192 //////////////////////////////////////////////////////////////////////////// 1193 QStringList OpticalTrainManager::getMissingDevices() const 1194 { 1195 auto missing = QStringList(); 1196 for (auto &oneTrain : m_OpticalTrains) 1197 { 1198 auto mount = oneTrain["mount"].toString(); 1199 if (mount != "--" && m_MountNames.contains(mount) == false) 1200 missing << mount; 1201 1202 auto camera = oneTrain["camera"].toString(); 1203 if (camera != "--" && m_CameraNames.contains(camera) == false) 1204 missing << camera; 1205 1206 auto dustcap = oneTrain["dustcap"].toString(); 1207 if (dustcap != "--" && m_DustCapNames.contains(dustcap) == false) 1208 missing << dustcap; 1209 1210 auto lightbox = oneTrain["lightbox"].toString(); 1211 if (lightbox != "--" && m_LightBoxNames.contains(lightbox) == false) 1212 missing << lightbox; 1213 1214 auto focuser = oneTrain["focuser"].toString(); 1215 if (focuser != "--" && m_FocuserNames.contains(focuser) == false) 1216 missing << focuser; 1217 1218 auto filterwheel = oneTrain["filterwheel"].toString(); 1219 if (filterwheel != "--" && m_FilterWheelNames.contains(filterwheel) == false) 1220 missing << filterwheel; 1221 1222 auto guider = oneTrain["guider"].toString(); 1223 if (guider != "--" && m_GuiderNames.contains(guider) == false) 1224 missing << guider; 1225 1226 } 1227 1228 return missing; 1229 } 1230 1231 //////////////////////////////////////////////////////////////////////////// 1232 /// 1233 //////////////////////////////////////////////////////////////////////////// 1234 void Ekos::OpticalTrainManager::updateOpticalTrainValue(QComboBox *cb, const QString &element) 1235 { 1236 if (trainNamesList->currentItem() != nullptr && m_Persistent == true) 1237 setOpticalTrainValue(trainNamesList->currentItem()->text(), element, cb->currentText()); 1238 } 1239 1240 //////////////////////////////////////////////////////////////////////////// 1241 /// 1242 //////////////////////////////////////////////////////////////////////////// 1243 void OpticalTrainManager::updateOpticalTrainValue(double value, const QString &element) 1244 { 1245 if (trainNamesList->currentItem() != nullptr && m_Persistent == true) 1246 setOpticalTrainValue(trainNamesList->currentItem()->text(), element, value); 1247 1248 } 1249 1250 //////////////////////////////////////////////////////////////////////////// 1251 /// Reset optical train to default values. 1252 //////////////////////////////////////////////////////////////////////////// 1253 void OpticalTrainManager::reset() 1254 { 1255 if (m_CurrentOpticalTrain != nullptr) 1256 { 1257 auto id = m_CurrentOpticalTrain->value("id"); 1258 auto name = m_CurrentOpticalTrain->value("name"); 1259 int row = trainNamesList->currentRow(); 1260 m_CurrentOpticalTrain->clear(); 1261 1262 m_CurrentOpticalTrain->insert("id", id); 1263 m_CurrentOpticalTrain->insert("name", name); 1264 m_CurrentOpticalTrain->insert("mount", "--"); 1265 m_CurrentOpticalTrain->insert("camera", "--"); 1266 m_CurrentOpticalTrain->insert("rotator", "--"); 1267 m_CurrentOpticalTrain->insert("guider", "--"); 1268 m_CurrentOpticalTrain->insert("dustcap", "--"); 1269 m_CurrentOpticalTrain->insert("scope", "--"); 1270 m_CurrentOpticalTrain->insert("filterwheel", "--"); 1271 m_CurrentOpticalTrain->insert("focuser", "--"); 1272 m_CurrentOpticalTrain->insert("reducer", 1); 1273 m_CurrentOpticalTrain->insert("lightbox", "--"); 1274 1275 KStarsData::Instance()->userdb()->UpdateOpticalTrain(*m_CurrentOpticalTrain, id.toInt()); 1276 refreshTrains(); 1277 selectOpticalTrain(name.toString()); 1278 trainNamesList->setCurrentRow(row); 1279 } 1280 } 1281 1282 }