Kstars

profileeditor.cpp
1/*
2 SPDX-FileCopyrightText: 2016 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "profileeditor.h"
8
9#include "geolocation.h"
10#include "kstarsdata.h"
11#include "ksnotification.h"
12#include "Options.h"
13#include "guide/guide.h"
14#include "indi/driverinfo.h"
15#include "indi/drivermanager.h"
16#include "profilescriptdialog.h"
17#include "ui_indihub.h"
18
19#include "ekos_debug.h"
20
21#include <QNetworkInterface>
22
23ProfileEditorUI::ProfileEditorUI(QWidget *p) : QFrame(p)
24{
25 setupUi(this);
26}
27
28ProfileEditor::ProfileEditor(QWidget *w) : QDialog(w)
29{
30 setObjectName("profileEditorDialog");
31#ifdef Q_OS_OSX
32 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
33#endif
34 ui = new ProfileEditorUI(this);
35
36 pi = nullptr;
37
38 m_MountModel = new QStandardItemModel(this);
39 m_CameraModel = new QStandardItemModel(this);
40 m_GuiderModel = new QStandardItemModel(this);
41 m_FocuserModel = new QStandardItemModel(this);
42
43 QVBoxLayout *mainLayout = new QVBoxLayout;
44 mainLayout->addWidget(ui);
45 setLayout(mainLayout);
46
47 setWindowTitle(i18nc("@title:window", "Profile Editor"));
48
49 // Create button box and link it to save and reject functions
51
52 buttonBox->setObjectName("dialogButtons");
53 mainLayout->addWidget(buttonBox);
54 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
55 connect(buttonBox, SIGNAL(accepted()), this, SLOT(saveProfile()));
56
57 connect(ui->scriptsB, &QPushButton::clicked, this, &ProfileEditor::executeScriptEditor);
58
59 connect(ui->openWebManagerB, &QPushButton::clicked, this, [this]()
60 {
61 QUrl url(QString("http://" + ui->remoteHost->text() + ":8624"));
62 QDesktopServices::openUrl(url);
63 });
64
65 connect(ui->INDIWebManagerCheck, &QCheckBox::toggled, this, [&](bool enabled)
66 {
67 ui->openWebManagerB->setEnabled(enabled);
68 ui->remoteDrivers->setEnabled(enabled || ui->localMode->isChecked());
69 ui->scriptsB->setEnabled(enabled || ui->localMode->isChecked());
70 });
71
72 connect(ui->guideTypeCombo, SIGNAL(activated(int)), this, SLOT(updateGuiderSelection(int)));
73
74 connect(ui->scanB, &QPushButton::clicked, this, &ProfileEditor::scanNetwork);
75
76#ifdef Q_OS_WIN
77 ui->remoteMode->setChecked(true);
78 ui->localMode->setEnabled(false);
79 setRemoteMode(true);
80#else
81 connect(ui->remoteMode, SIGNAL(toggled(bool)), this, SLOT(setRemoteMode(bool)));
82#endif
83
84 connect(ui->indihubB, &QPushButton::clicked, this, &ProfileEditor::showINDIHub);
85
86 // Load all drivers
87 loadDrivers();
88
89 // Shared tooltips
90 ui->remoteDrivers->setToolTip(ui->remoteDriversLabel->toolTip());
91 ui->aux1Combo->setToolTip(ui->aux1Label->toolTip());
92 ui->aux2Combo->setToolTip(ui->aux2Label->toolTip());
93 ui->aux3Combo->setToolTip(ui->aux3Label->toolTip());
94 ui->aux4Combo->setToolTip(ui->aux4Label->toolTip());
95 ui->filterCombo->setToolTip(ui->filterLabel->toolTip());
96 ui->AOCombo->setToolTip(ui->AOLabel->toolTip());
97 ui->domeCombo->setToolTip(ui->domeLabel->toolTip());
98 ui->weatherCombo->setToolTip(ui->weatherLabel->toolTip());
99 ui->localMode->setToolTip(ui->modeLabel->toolTip());
100 ui->remoteMode->setToolTip(ui->modeLabel->toolTip());
101 ui->remoteHostLabel->setToolTip(ui->remoteHost->toolTip());
102 ui->remotePortLabel->setToolTip(ui->remotePort->toolTip());
103 ui->externalGuidePortLabel->setToolTip(ui->externalGuidePort->toolTip());
104 ui->INDIWebManagerPortLabel->setToolTip(ui->INDIWebManagerPort->toolTip());
105 ui->guideTypeCombo->setToolTip(ui->guidingTypeLabel->toolTip());
106 ui->externalGuideHostLabel->setToolTip(ui->externalGuideHost->toolTip());
107}
108
109void ProfileEditor::saveProfile()
110{
111 bool newProfile = (pi.isNull());
112
113 if (ui->profileIN->text().isEmpty())
114 {
115 KSNotification::error(i18n("Cannot save an empty profile."));
116 return;
117 }
118
119 if (newProfile)
120 {
122 KStarsData::Instance()->userdb()->GetAllProfiles(existingProfiles);
123 for (auto &profileInfo : existingProfiles)
124 {
125 if (ui->profileIN->text() == profileInfo->name)
126 {
127 KSNotification::error(i18n("Profile name already exists."));
128 return;
129 }
130 }
131 int id = KStarsData::Instance()->userdb()->AddProfile(ui->profileIN->text());
132 pi.reset(new ProfileInfo(id, ui->profileIN->text()));
133 }
134 else
135 pi->name = ui->profileIN->text();
136
137 // Local Mode
138 if (ui->localMode->isChecked())
139 {
140 pi->host.clear();
141 pi->port = -1;
142 pi->INDIWebManagerPort = -1;
143 //pi->customDrivers = ui->customDriversIN->text();
144 }
145 // Remote Mode
146 else
147 {
148 pi->host = ui->remoteHost->text().trimmed();
149 pi->port = ui->remotePort->text().toInt();
150 if (ui->INDIWebManagerCheck->isChecked())
151 pi->INDIWebManagerPort = ui->INDIWebManagerPort->text().toInt();
152 else
153 pi->INDIWebManagerPort = -1;
154 //pi->customDrivers.clear();
155 }
156
157 // City Info
158 if (ui->loadSiteCheck->isEnabled() && ui->loadSiteCheck->isChecked())
159 {
160 pi->city = KStarsData::Instance()->geo()->name();
161 pi->province = KStarsData::Instance()->geo()->province();
162 pi->country = KStarsData::Instance()->geo()->country();
163 }
164 else
165 {
166 pi->city.clear();
167 pi->province.clear();
168 pi->country.clear();
169 }
170
171 pi->indihub = m_INDIHub;
172
173 // Auto Connect
174 pi->autoConnect = ui->autoConnectCheck->isChecked();
175 // Port Selector
176 pi->portSelector = ui->portSelectorCheck->isChecked();
177
178 // Guider Type
179 pi->guidertype = ui->guideTypeCombo->currentIndex();
180 if (pi->guidertype != Ekos::Guide::GUIDE_INTERNAL)
181 {
182 pi->guiderhost = ui->externalGuideHost->text();
183 pi->guiderport = ui->externalGuidePort->text().toInt();
184
185 if (pi->guidertype == Ekos::Guide::GUIDE_PHD2)
186 {
187 Options::setPHD2Host(pi->guiderhost);
188 Options::setPHD2Port(pi->guiderport);
189 }
190 else if (pi->guidertype == Ekos::Guide::GUIDE_LINGUIDER)
191 {
192 Options::setLinGuiderHost(pi->guiderhost);
193 Options::setLinGuiderPort(pi->guiderport);
194 }
195 }
196
197 if (ui->mountCombo->currentText().isEmpty() || ui->mountCombo->currentText() == "--")
198 pi->drivers.remove("Mount");
199 else
200 pi->drivers["Mount"] = ui->mountCombo->currentText();
201
202 if (ui->ccdCombo->currentText().isEmpty() || ui->ccdCombo->currentText() == "--")
203 pi->drivers.remove("CCD");
204 else
205 pi->drivers["CCD"] = ui->ccdCombo->currentText();
206
207 if (ui->guiderCombo->currentText().isEmpty() || ui->guiderCombo->currentText() == "--")
208 pi->drivers.remove("Guider");
209 else
210 pi->drivers["Guider"] = ui->guiderCombo->currentText();
211
212 if (ui->focuserCombo->currentText().isEmpty() || ui->focuserCombo->currentText() == "--")
213 pi->drivers.remove("Focuser");
214 else
215 pi->drivers["Focuser"] = ui->focuserCombo->currentText();
216
217 if (ui->filterCombo->currentText().isEmpty() || ui->filterCombo->currentText() == "--")
218 pi->drivers.remove("Filter");
219 else
220 pi->drivers["Filter"] = ui->filterCombo->currentText();
221
222 if (ui->AOCombo->currentText().isEmpty() || ui->AOCombo->currentText() == "--")
223 pi->drivers.remove("AO");
224 else
225 pi->drivers["AO"] = ui->AOCombo->currentText();
226
227 if (ui->domeCombo->currentText().isEmpty() || ui->domeCombo->currentText() == "--")
228 pi->drivers.remove("Dome");
229 else
230 pi->drivers["Dome"] = ui->domeCombo->currentText();
231
232 if (ui->weatherCombo->currentText().isEmpty() || ui->weatherCombo->currentText() == "--")
233 pi->drivers.remove("Weather");
234 else
235 pi->drivers["Weather"] = ui->weatherCombo->currentText();
236
237 if (ui->aux1Combo->currentText().isEmpty() || ui->aux1Combo->currentText() == "--")
238 pi->drivers.remove("Aux1");
239 else
240 pi->drivers["Aux1"] = ui->aux1Combo->currentText();
241
242 if (ui->aux2Combo->currentText().isEmpty() || ui->aux2Combo->currentText() == "--")
243 pi->drivers.remove("Aux2");
244 else
245 pi->drivers["Aux2"] = ui->aux2Combo->currentText();
246
247 if (ui->aux3Combo->currentText().isEmpty() || ui->aux3Combo->currentText() == "--")
248 pi->drivers.remove("Aux3");
249 else
250 pi->drivers["Aux3"] = ui->aux3Combo->currentText();
251
252 if (ui->aux4Combo->currentText().isEmpty() || ui->aux4Combo->currentText() == "--")
253 pi->drivers.remove("Aux4");
254 else
255 pi->drivers["Aux4"] = ui->aux4Combo->currentText();
256
257 pi->remotedrivers = ui->remoteDrivers->text();
258
259 KStarsData::Instance()->userdb()->SaveProfile(pi);
260
261 // Ekos manager will reload and new profiles will be created
262 if (newProfile)
263 pi.clear();
264
265 accept();
266}
267
268void ProfileEditor::setRemoteMode(bool enable)
269{
270 loadDrivers(); //This is needed to reload the drivers because some may not be available locally
271
272 ui->remoteHost->setEnabled(enable);
273 ui->remoteHostLabel->setEnabled(enable);
274 ui->remotePort->setEnabled(enable);
275 ui->remotePortLabel->setEnabled(enable);
276
277 //ui->customLabel->setEnabled(!enable);
278 //ui->customDriversIN->setEnabled(!enable);
279
280 ui->mountCombo->setEditable(enable);
281 ui->ccdCombo->setEditable(enable);
282 ui->guiderCombo->setEditable(enable);
283 ui->focuserCombo->setEditable(enable);
284 ui->filterCombo->setEditable(enable);
285 ui->AOCombo->setEditable(enable);
286 ui->domeCombo->setEditable(enable);
287 ui->weatherCombo->setEditable(enable);
288 ui->aux1Combo->setEditable(enable);
289 ui->aux2Combo->setEditable(enable);
290 ui->aux3Combo->setEditable(enable);
291 ui->aux4Combo->setEditable(enable);
292
293 ui->remoteDrivers->setEnabled(!enable);
294
295 ui->loadSiteCheck->setEnabled(enable);
296
297 ui->INDIWebManagerCheck->setEnabled(enable);
298 if (enable == false)
299 ui->INDIWebManagerCheck->setChecked(false);
300 ui->INDIWebManagerPort->setEnabled(enable);
301
302 ui->scriptsB->setEnabled(!enable || ui->INDIWebManagerCheck->isChecked());
303}
304
305void ProfileEditor::setPi(const QSharedPointer<ProfileInfo> &newProfile)
306{
307 pi = newProfile;
308
309 ui->profileIN->setText(pi->name);
310
311 ui->loadSiteCheck->setChecked(!pi->city.isEmpty());
312 ui->autoConnectCheck->setChecked(pi->autoConnect);
313 ui->portSelectorCheck->setChecked(pi->portSelector);
314
315 if (pi->city.isEmpty() == false)
316 {
317 if (pi->province.isEmpty())
318 ui->loadSiteCheck->setText(ui->loadSiteCheck->text() + QString(" (%1, %2)").arg(pi->country, pi->city));
319 else
320 ui->loadSiteCheck->setText(ui->loadSiteCheck->text() +
321 QString(" (%1, %2, %3)").arg(pi->country, pi->province, pi->city));
322 }
323
324 if (pi->host.isEmpty() == false)
325 {
326 ui->remoteHost->setText(pi->host);
327 ui->remotePort->setText(QString::number(pi->port));
328
329 ui->remoteMode->setChecked(true);
330
331 if (pi->INDIWebManagerPort > 0)
332 {
333 ui->INDIWebManagerCheck->setChecked(true);
334 ui->INDIWebManagerPort->setText(QString::number(pi->INDIWebManagerPort));
335 }
336 else
337 {
338 ui->INDIWebManagerCheck->setChecked(false);
339 ui->INDIWebManagerPort->setText("8624");
340 }
341 }
342
343 if (pi->remotedrivers.isEmpty() == false)
344 ui->remoteDrivers->setText(pi->remotedrivers);
345
346 ui->guideTypeCombo->setCurrentIndex(pi->guidertype);
347 updateGuiderSelection(ui->guideTypeCombo->currentIndex());
348 if (pi->guidertype == Ekos::Guide::GUIDE_PHD2)
349 {
350 Options::setPHD2Host(pi->guiderhost);
351 Options::setPHD2Port(pi->guiderport);
352 }
353 else if (pi->guidertype == Ekos::Guide::GUIDE_LINGUIDER)
354 {
355 Options::setLinGuiderHost(pi->guiderhost);
356 Options::setLinGuiderPort(pi->guiderport);
357 }
358
359 QMapIterator<QString, QString> i(pi->drivers);
360
361 while (i.hasNext())
362 {
363 int row = 0;
364 i.next();
365
366 QString key = i.key();
367 QString value = i.value();
368
369 if (key == "Mount")
370 {
371 // If driver doesn't exist, let's add it to the list
372 if ((row = ui->mountCombo->findText(value)) == -1)
373 {
374 ui->mountCombo->addItem(value);
375 row = ui->mountCombo->count() - 1;
376 }
377
378 // Set index to our driver
379 ui->mountCombo->setCurrentIndex(row);
380 }
381 else if (key == "CCD")
382 {
383 if ((row = ui->ccdCombo->findText(value)) == -1)
384 {
385 ui->ccdCombo->addItem(value);
386 row = ui->ccdCombo->count() - 1;
387 }
388
389 ui->ccdCombo->setCurrentIndex(row);
390 }
391 else if (key == "Guider")
392 {
393 if ((row = ui->guiderCombo->findText(value)) == -1)
394 {
395 ui->guiderCombo->addItem(value);
396 row = ui->guiderCombo->count() - 1;
397 }
398
399 ui->guiderCombo->setCurrentIndex(row);
400 }
401 else if (key == "Focuser")
402 {
403 if ((row = ui->focuserCombo->findText(value)) == -1)
404 {
405 ui->focuserCombo->addItem(value);
406 row = ui->focuserCombo->count() - 1;
407 }
408
409 ui->focuserCombo->setCurrentIndex(row);
410 }
411 else if (key == "Filter")
412 {
413 if ((row = ui->filterCombo->findText(value)) == -1)
414 {
415 ui->filterCombo->addItem(value);
416 row = ui->filterCombo->count() - 1;
417 }
418
419 ui->filterCombo->setCurrentIndex(row);
420 }
421 else if (key == "AO")
422 {
423 if ((row = ui->AOCombo->findText(value)) == -1)
424 {
425 ui->AOCombo->addItem(value);
426 row = ui->AOCombo->count() - 1;
427 }
428
429 ui->AOCombo->setCurrentIndex(row);
430 }
431 else if (key == "Dome")
432 {
433 if ((row = ui->domeCombo->findText(value)) == -1)
434 {
435 ui->domeCombo->addItem(value);
436 row = ui->domeCombo->count() - 1;
437 }
438
439 ui->domeCombo->setCurrentIndex(row);
440 }
441 else if (key == "Weather")
442 {
443 if ((row = ui->weatherCombo->findText(value)) == -1)
444 {
445 ui->weatherCombo->addItem(value);
446 row = ui->weatherCombo->count() - 1;
447 }
448
449 ui->weatherCombo->setCurrentIndex(row);
450 }
451 else if (key == "Aux1")
452 {
453 if ((row = ui->aux1Combo->findText(value)) == -1)
454 {
455 ui->aux1Combo->addItem(value);
456 row = ui->aux1Combo->count() - 1;
457 }
458
459 ui->aux1Combo->setCurrentIndex(row);
460 }
461 else if (key == "Aux2")
462 {
463 if ((row = ui->aux2Combo->findText(value)) == -1)
464 {
465 ui->aux2Combo->addItem(value);
466 row = ui->aux2Combo->count() - 1;
467 }
468
469 ui->aux2Combo->setCurrentIndex(row);
470 }
471 else if (key == "Aux3")
472 {
473 if ((row = ui->aux3Combo->findText(value)) == -1)
474 {
475 ui->aux3Combo->addItem(value);
476 row = ui->aux3Combo->count() - 1;
477 }
478
479 ui->aux3Combo->setCurrentIndex(row);
480 }
481 else if (key == "Aux4")
482 {
483 if ((row = ui->aux4Combo->findText(value)) == -1)
484 {
485 ui->aux4Combo->addItem(value);
486 row = ui->aux4Combo->count() - 1;
487 }
488
489 ui->aux4Combo->setCurrentIndex(row);
490 }
491 }
492
493 m_INDIHub = pi->indihub;
494}
495
496QString ProfileEditor::getTooltip(const QSharedPointer<DriverInfo> &driver)
497{
498 bool locallyAvailable = false;
499 if (driver->getAuxInfo().contains("LOCALLY_AVAILABLE"))
500 locallyAvailable = driver->getAuxInfo().value("LOCALLY_AVAILABLE", false).toBool();
501 QString toolTipText;
502 if (!locallyAvailable)
503 toolTipText = i18n(
504 "<nobr>Available as <b>Remote</b> Driver. To use locally, install the corresponding driver.<nobr/>");
505 else
506 toolTipText = i18n("<nobr><b>Label</b>: %1 &#9473; <b>Driver</b>: %2 &#9473; <b>Exec</b>: %3<nobr/>",
507 driver->getLabel(), driver->getName(), driver->getExecutable());
508
509 return toolTipText;
510}
511
512void ProfileEditor::loadDrivers()
513{
514 // We need to save this now since we have two models for the mounts
515 QString selectedMount = ui->mountCombo->currentText();
516 QString selectedCamera = ui->ccdCombo->currentText();
517 QString selectedGuider = ui->guiderCombo->currentText();
518 QString selectedFocuser = ui->focuserCombo->currentText();
519 QString selectedAux1 = ui->aux1Combo->currentText();
520 QString selectedAux2 = ui->aux2Combo->currentText();
521 QString selectedAux3 = ui->aux3Combo->currentText();
522 QString selectedAux4 = ui->aux4Combo->currentText();
523
525 boxes.append(ui->mountCombo);
526 boxes.append(ui->ccdCombo);
527 boxes.append(ui->guiderCombo);
528 boxes.append(ui->AOCombo);
529 boxes.append(ui->focuserCombo);
530 boxes.append(ui->filterCombo);
531 boxes.append(ui->domeCombo);
532 boxes.append(ui->weatherCombo);
533 boxes.append(ui->aux1Combo);
534 boxes.append(ui->aux2Combo);
535 boxes.append(ui->aux3Combo);
536 boxes.append(ui->aux4Combo);
537
538 QVector<QString> selectedItems;
539
540 for (QComboBox *box : boxes)
541 {
542 selectedItems.append(box->currentText());
543 box->clear();
544 box->addItem("--");
545 box->setMaxVisibleItems(20);
546 }
547
548 QIcon remoteIcon = QIcon::fromTheme("network-modem");
549
550 // Create the model
551 delete (m_MountModel);
552 m_MountModel = new QStandardItemModel(this);
553 delete (m_CameraModel);
554 m_CameraModel = new QStandardItemModel(this);
555 delete (m_GuiderModel);
556 m_GuiderModel = new QStandardItemModel(this);
557 delete (m_FocuserModel);
558 m_FocuserModel = new QStandardItemModel(this);
559 delete (m_Aux1Model);
560 m_Aux1Model = new QStandardItemModel(this);
561 delete (m_Aux2Model);
562 m_Aux2Model = new QStandardItemModel(this);
563 delete (m_Aux3Model);
564 m_Aux3Model = new QStandardItemModel(this);
565 delete (m_Aux4Model);
566 m_Aux4Model = new QStandardItemModel(this);
567
568 const bool isLocal = ui->localMode->isChecked();
570 << KSTARS_AUXILIARY
571 << KSTARS_CCD
572 << KSTARS_FOCUSER
573 << KSTARS_FILTER
574 << KSTARS_WEATHER
575 << KSTARS_SPECTROGRAPHS
576 << KSTARS_DETECTORS;
577
578 populateManufacturerCombo(m_MountModel, ui->mountCombo, selectedMount, isLocal, QList<DeviceFamily>() << KSTARS_TELESCOPE);
579 populateManufacturerCombo(m_CameraModel, ui->ccdCombo, selectedCamera, isLocal, QList<DeviceFamily>() << KSTARS_CCD);
580 populateManufacturerCombo(m_GuiderModel, ui->guiderCombo, selectedGuider, isLocal, QList<DeviceFamily>() << KSTARS_CCD);
581 populateManufacturerCombo(m_FocuserModel, ui->focuserCombo, selectedFocuser, isLocal,
582 QList<DeviceFamily>() << KSTARS_FOCUSER);
583 populateManufacturerCombo(m_Aux1Model, ui->aux1Combo, selectedAux1, isLocal, auxFamily);
584 populateManufacturerCombo(m_Aux2Model, ui->aux2Combo, selectedAux2, isLocal, auxFamily);
585 populateManufacturerCombo(m_Aux3Model, ui->aux3Combo, selectedAux3, isLocal, auxFamily);
586 populateManufacturerCombo(m_Aux4Model, ui->aux4Combo, selectedAux4, isLocal, auxFamily);
587
588 for (QSharedPointer<DriverInfo>driver : DriverManager::Instance()->getDrivers())
589 {
590 bool locallyAvailable = false;
591 QIcon icon;
592 if (driver->getAuxInfo().contains("LOCALLY_AVAILABLE"))
593 locallyAvailable = driver->getAuxInfo().value("LOCALLY_AVAILABLE", false).toBool();
594 if (!locallyAvailable)
595 {
596 if (ui->localMode->isChecked())
597 continue;
598 else
599 icon = remoteIcon;
600 }
601
602 QString toolTipText = getTooltip(driver);
603
604 switch (driver->getType())
605 {
606 case KSTARS_CCD:
607 break;
608
609 case KSTARS_ADAPTIVE_OPTICS:
610 {
611 ui->AOCombo->addItem(icon, driver->getLabel());
612 ui->AOCombo->setItemData(ui->AOCombo->count() - 1, toolTipText, Qt::ToolTipRole);
613 }
614 break;
615
616 case KSTARS_FOCUSER:
617 break;
618
619 case KSTARS_FILTER:
620 {
621 ui->filterCombo->addItem(icon, driver->getLabel());
622 ui->filterCombo->setItemData(ui->filterCombo->count() - 1, toolTipText, Qt::ToolTipRole);
623 }
624 break;
625
626 case KSTARS_DOME:
627 {
628 ui->domeCombo->addItem(icon, driver->getLabel());
629 ui->domeCombo->setItemData(ui->domeCombo->count() - 1, toolTipText, Qt::ToolTipRole);
630 }
631 break;
632
633 case KSTARS_WEATHER:
634 {
635 ui->weatherCombo->addItem(icon, driver->getLabel());
636 ui->weatherCombo->setItemData(ui->weatherCombo->count() - 1, toolTipText, Qt::ToolTipRole);
637 }
638 break;
639
640 case KSTARS_AUXILIARY:
641 case KSTARS_SPECTROGRAPHS:
642 case KSTARS_DETECTORS:
643 break;
644
645 default:
646 continue;
647 }
648 }
649
650 // Skip mount/ccd/guider/focuser since we handled it above
651 for (int i = 4; i < boxes.count(); i++)
652 {
653 QComboBox *box = boxes.at(i);
654 QString selectedItemText = selectedItems.at(i);
655 int index = box->findText(selectedItemText);
656 if (index == -1)
657 {
658 if (ui->localMode->isChecked())
659 box->setCurrentIndex(0);
660 else
662 }
663 else
664 {
665 box->setCurrentIndex(index);
666 }
667
668 box->model()->sort(0);
669 }
670}
671
672void ProfileEditor::setProfileName(const QString &name)
673{
674 ui->profileIN->setText(name);
675}
676
677void ProfileEditor::setAuxDrivers(const QStringList &aux)
678{
680
681 if (auxList.isEmpty())
682 return;
683 ui->aux1Combo->setCurrentText(auxList.first());
684 auxList.removeFirst();
685
686 if (auxList.isEmpty())
687 return;
688 ui->aux2Combo->setCurrentText(auxList.first());
689 auxList.removeFirst();
690
691 if (auxList.isEmpty())
692 return;
693 ui->aux3Combo->setCurrentText(auxList.first());
694 auxList.removeFirst();
695
696 if (auxList.isEmpty())
697 return;
698 ui->aux4Combo->setCurrentText(auxList.first());
699}
700
701void ProfileEditor::setHostPort(const QString &host, const QString &port)
702{
703 ui->remoteMode->setChecked(true);
704 ui->remoteHost->setText(host);
705 ui->remotePort->setText(port);
706}
707
708void ProfileEditor::setWebManager(bool enabled, const QString &port)
709{
710 ui->INDIWebManagerCheck->setChecked(enabled);
711 ui->INDIWebManagerPort->setText(port);
712}
713
714void ProfileEditor::setGuiderType(int type)
715{
716 ui->guideTypeCombo->setCurrentIndex(type);
717 if (type != Ekos::Guide::GUIDE_INTERNAL)
718 {
719 ui->externalGuideHostLabel->setEnabled(true);
720 ui->externalGuideHost->setEnabled(true);
721 ui->externalGuidePortLabel->setEnabled(true);
722 ui->externalGuidePort->setEnabled(true);
723 }
724}
725
726void ProfileEditor::setConnectionOptionsEnabled(bool enable)
727{
728 // Enable or disable connection related options
729 ui->modeLabel->setEnabled(enable);
730 ui->localMode->setEnabled(enable);
731 ui->remoteMode->setEnabled(enable);
732 ui->remoteHostLabel->setEnabled(enable);
733 ui->remoteHost->setEnabled(enable);
734 ui->remotePortLabel->setEnabled(enable);
735 ui->remotePort->setEnabled(enable);
736 ui->INDIWebManagerCheck->setEnabled(enable);
737 ui->INDIWebManagerPort->setEnabled(enable);
738 ui->INDIWebManagerPortLabel->setEnabled(enable);
739 ui->guidingTypeLabel->setEnabled(enable);
740 ui->guideTypeCombo->setEnabled(enable);
741 ui->remoteDrivers->setEnabled(enable);
742
743 updateGuiderSelection(ui->guideTypeCombo->currentIndex());
744
745 if (enable == false)
746 ui->mountCombo->setFocus();
747}
748
749void ProfileEditor::updateGuiderSelection(int id)
750{
751
752 if (id == Ekos::Guide::GUIDE_INTERNAL)
753 {
754 ui->externalGuideHost->setText("localhost");
755 ui->externalGuidePort->clear();
756
757 ui->externalGuideHost->setEnabled(false);
758 ui->externalGuideHostLabel->setEnabled(false);
759 ui->externalGuidePort->setEnabled(false);
760 ui->externalGuidePortLabel->setEnabled(false);
761 return;
762 }
763
764 QString host;
765 int port = -1;
766
767 ui->externalGuideHost->setEnabled(true);
768 ui->externalGuideHostLabel->setEnabled(true);
769 ui->externalGuidePort->setEnabled(true);
770 ui->externalGuidePortLabel->setEnabled(true);
771
772 if (pi && pi->guidertype == id)
773 {
774 host = pi->guiderhost;
775 port = pi->guiderport;
776 }
777
778 if (id == Ekos::Guide::GUIDE_PHD2)
779 {
780 if (host.isEmpty())
781 host = Options::pHD2Host();
782 if (port < 0)
783 port = Options::pHD2Port();
784 }
785 else if (id == Ekos::Guide::GUIDE_LINGUIDER)
786 {
787 if (host.isEmpty())
788 host = Options::linGuiderHost();
789 if (port < 0)
790 port = Options::linGuiderPort();
791 }
792
793 ui->externalGuideHost->setText(host);
794 ui->externalGuidePort->setText(QString::number(port));
795
796}
797
798void ProfileEditor::setSettings(const QJsonObject &profile)
799{
800 ui->profileIN->setText(profile["name"].toString());
801 ui->autoConnectCheck->setChecked(profile["auto_connect"].toBool(true));
802 ui->portSelectorCheck->setChecked(profile["port_selector"].toBool(false));
803 ui->localMode->setChecked(profile["mode"].toString() == "local");
804 ui->remoteMode->setChecked(profile["mode"].toString() == "remote");
805 ui->remoteHost->setText(profile["remote_host"].toString("localhost"));
806 ui->remotePort->setText(profile["remote_port"].toString("7624"));
807 ui->guideTypeCombo->setCurrentText(profile["guiding"].toString(i18n("Internal")));
808 ui->externalGuideHost->setText(profile["remote_guiding_host"].toString(("localhost")));
809 ui->externalGuideHost->setText(profile["remote_guiding_port"].toString());
810 ui->INDIWebManagerCheck->setChecked(profile["use_web_manager"].toBool());
811 ui->remoteDrivers->setText(profile["remote"].toString(ui->remoteDrivers->text()));
812
813 m_INDIHub = profile["indihub"].toInt(m_INDIHub);
814
815 // Drivers
816 const QString mount = profile["mount"].toString("--");
817 if (mount == "--")
818 ui->mountCombo->setCurrentIndex(0);
819 else
820 {
821 ui->mountCombo->addItem(mount);
822 ui->mountCombo->setCurrentIndex(ui->mountCombo->count() - 1);
823 }
824
825 const QString ccd = profile["ccd"].toString("--");
826 if (ccd == "--")
827 ui->ccdCombo->setCurrentIndex(0);
828 else
829 {
830 ui->ccdCombo->addItem(ccd);
831 ui->ccdCombo->setCurrentIndex(ui->ccdCombo->count() - 1);
832 }
833
834 const QString guider = profile["guider"].toString("--");
835 if (guider == "--")
836 ui->guiderCombo->setCurrentIndex(0);
837 else
838 {
839 ui->guiderCombo->addItem(guider);
840 ui->guiderCombo->setCurrentIndex(ui->guiderCombo->count() - 1);
841 }
842
843 const QString focuser = profile["focuser"].toString("--");
844 if (focuser == "--")
845 ui->focuserCombo->setCurrentIndex(0);
846 else
847 {
848 ui->focuserCombo->addItem(focuser);
849 ui->focuserCombo->setCurrentIndex(ui->focuserCombo->count() - 1);
850 }
851
852 ui->filterCombo->setCurrentText(profile["filter"].toString("--"));
853 ui->AOCombo->setCurrentText(profile["ao"].toString("--"));
854 ui->domeCombo->setCurrentText(profile["dome"].toString("--"));
855 ui->weatherCombo->setCurrentText(profile["weather"].toString("--"));
856
857 const auto aux1 = profile["aux1"].toString("--");
858 if (aux1.isEmpty() || aux1 == "--")
859 ui->aux1Combo->setCurrentIndex(0);
860 else
861 {
862 ui->aux1Combo->addItem(aux1);
863 ui->aux1Combo->setCurrentIndex(ui->aux1Combo->count() - 1);
864 }
865
866 const auto aux2 = profile["aux2"].toString("--");
867 if (aux2.isEmpty() || aux2 == "--")
868 ui->aux2Combo->setCurrentIndex(0);
869 else
870 {
871 ui->aux2Combo->addItem(aux2);
872 ui->aux2Combo->setCurrentIndex(ui->aux2Combo->count() - 1);
873 }
874
875 const auto aux3 = profile["aux3"].toString("--");
876 if (aux3.isEmpty() || aux3 == "--")
877 ui->aux3Combo->setCurrentIndex(0);
878 else
879 {
880 ui->aux3Combo->addItem(aux3);
881 ui->aux3Combo->setCurrentIndex(ui->aux3Combo->count() - 1);
882 }
883
884 const auto aux4 = profile["aux4"].toString("--");
885 if (aux4.isEmpty() || aux4 == "--")
886 ui->aux4Combo->setCurrentIndex(0);
887 else
888 {
889 ui->aux4Combo->addItem(aux4);
890 ui->aux4Combo->setCurrentIndex(ui->aux4Combo->count() - 1);
891 }
892}
893
894void ProfileEditor::scanNetwork()
895{
896 delete (m_ProgressDialog);
897 m_ProgressDialog = new QProgressDialog(this);
898 m_ProgressDialog->setWindowTitle(i18nc("@title:window", "Scanning Network"));
899 m_ProgressDialog->setLabelText(i18n("Scanning network for INDI Web Managers..."));
900 connect(m_ProgressDialog, &QProgressDialog::canceled, this, [this]()
901 {
902 m_CancelScan = true;
903 clearAllRequests();
904 });
905 m_ProgressDialog->setMinimum(0);
906 m_ProgressDialog->setMaximum(0);
907 m_ProgressDialog->show();
908 m_ProgressDialog->raise();
909
910 m_CancelScan = false;
911
913 std::sort(addresses.begin(), addresses.end(), [](const QHostAddress & a, const QHostAddress & b) -> bool
914 { return a.toString() < b.toString();});
915
916 for(QHostAddress address : addresses)
917 {
918 if (address.isLoopback() || address.protocol() & QAbstractSocket::IPv6Protocol)
919 continue;
920
921 QString ipv4 = address.toString();
922
923 if (ipv4.startsWith("10.250"))
924 {
925 scanIP("10.250.250.1");
926 }
927 else
928 {
929 QString prefixIP = ipv4.remove(ipv4.lastIndexOf("."), 10);
930 // Blind search all over subnet
931 // TODO better subnet detection instead of assuming it finishes at 254
932 for (int i = 1; i <= 254; i++)
933 {
934 scanIP(prefixIP + "." + QString::number(i));
935 }
936 }
937 }
938
939}
940
941void ProfileEditor::scanIP(const QString &ip)
942{
943 QUrl url(QString("http://%1:8624/api/server/status").arg(ip));
944
945 qCDebug(KSTARS_EKOS) << "Scanning" << url;
946
947 QNetworkReply *response = m_Manager.get(QNetworkRequest(url));
948 m_Replies.append(response);
950 {
951 m_Replies.removeOne(response);
952 response->deleteLater();
953 if (m_CancelScan)
954 return;
955 if (response->error() == QNetworkReply::NoError)
956 {
957 clearAllRequests();
958 m_ProgressDialog->close();
959 ui->remoteHost->setText(ip);
960
961 qCDebug(KSTARS_EKOS) << "Found Web Manager server at" << ip;
962
963 KSNotification::info(i18n("Found INDI Web Manager at %1", ip));
964 }
965 });
966}
967
968void ProfileEditor::clearAllRequests()
969{
970 for (QNetworkReply *oneReply : m_Replies)
971 {
972 oneReply->abort();
973 oneReply->deleteLater();
974 }
975
976 m_Replies.clear();
977}
978
979void ProfileEditor::showINDIHub()
980{
981 QDialog hub;
982 Ui::INDIHub indihub;
983 indihub.setupUi(&hub);
984
985 indihub.modeButtonGroup->setId(indihub.offR, 0);
986 indihub.modeButtonGroup->setId(indihub.solorR, 1);
987 indihub.modeButtonGroup->setId(indihub.shareR, 2);
988 indihub.modeButtonGroup->setId(indihub.roboticR, 3);
989
990 indihub.logoLabel->setPixmap(QIcon(":/icons/indihub_logo.svg").pixmap(QSize(128, 128)));
991
992 indihub.modeButtonGroup->button(m_INDIHub)->setChecked(true);
993 connect(indihub.closeB, &QPushButton::clicked, &hub, &QDialog::close);
994
995 hub.exec();
996
997 m_INDIHub = indihub.modeButtonGroup->checkedId();
998}
999
1000void ProfileEditor::populateManufacturerCombo(QStandardItemModel *model, QComboBox *combo, const QString &selectedDriver,
1001 bool isLocal, const QList<DeviceFamily> &families)
1002{
1003 if (isLocal)
1004 {
1005 QStandardItem *selectedItem = nullptr;
1006 model->appendRow(new QStandardItem("--"));
1007 for (QSharedPointer<DriverInfo>driver : DriverManager::Instance()->getDrivers())
1008 {
1009 if (!families.contains(driver->getType()))
1010 continue;
1011
1012 QString manufacturer = driver->manufacturer();
1013 QList<QStandardItem*> manufacturers = model->findItems(manufacturer);
1014
1015 QStandardItem *parentItem = nullptr;
1016 if (model->findItems(manufacturer).empty())
1017 {
1018 parentItem = new QStandardItem(manufacturer);
1019 parentItem->setSelectable(false);
1020 model->appendRow(parentItem);
1021 }
1022 else
1023 {
1024 parentItem = manufacturers.first();
1025 }
1026
1027 QStandardItem *item = new QStandardItem(driver->getLabel());
1028 item->setData(getTooltip(driver), Qt::ToolTipRole);
1029 parentItem->appendRow(item);
1030 if (selectedDriver == driver->getLabel())
1031 selectedItem = item;
1032 }
1033 QTreeView *view = new QTreeView(this);
1034 view->setModel(model);
1036 combo->setView(view);
1037 combo->setModel(model);
1038 if (selectedItem)
1039 {
1040 // JM: Only way to make it the QTreeView sets the current index
1041 // in the combo way
1042
1043 QModelIndex index = model->indexFromItem(selectedItem);
1044
1045 // First set current index to the child
1046 combo->setRootModelIndex(index.parent());
1047 combo->setModelColumn(index.column());
1048 combo->setCurrentIndex(index.row());
1049
1050 // Now reset
1051 combo->setRootModelIndex(QModelIndex());
1052 view->setCurrentIndex(index);
1053 }
1054 }
1055 else
1056 {
1057 QIcon remoteIcon = QIcon::fromTheme("network-modem");
1058 combo->setView(new QListView(this));
1059 model->appendRow(new QStandardItem("--"));
1060 QIcon icon;
1061 for (QSharedPointer<DriverInfo>driver : DriverManager::Instance()->getDrivers())
1062 {
1063 if (!families.contains(driver->getType()))
1064 continue;
1065
1066 bool locallyAvailable = false;
1067 if (driver->getAuxInfo().contains("LOCALLY_AVAILABLE"))
1068 locallyAvailable = driver->getAuxInfo().value("LOCALLY_AVAILABLE", false).toBool();
1069 icon = locallyAvailable ? QIcon() : remoteIcon;
1070
1071 QStandardItem *mount = new QStandardItem(icon, driver->getLabel());
1072 mount->setData(getTooltip(driver), Qt::ToolTipRole);
1073 model->appendRow(mount);
1074 }
1075 combo->setModel(model);
1076 combo->setCurrentText(selectedDriver);
1077 }
1078}
1079
1080void ProfileEditor::executeScriptEditor()
1081{
1082 if (pi == nullptr)
1083 return;
1085 for (auto &oneCombo : ui->driversGroupBox->findChildren<QComboBox *>())
1086 currentDrivers << oneCombo->currentText();
1087 currentDrivers.removeAll("--");
1088 currentDrivers.removeAll("");
1089 currentDrivers.sort();
1090 ProfileScriptDialog dialog(currentDrivers, pi->scripts, this);
1091 dialog.exec();
1092 auto settings = dialog.jsonSettings();
1093 pi->scripts = QJsonDocument(settings).toJson(QJsonDocument::Compact);
1094}
DriverManager is the primary class to handle all operations related to starting and stopping INDI dri...
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
KIOCORE_EXPORT SimpleJob * mount(bool ro, const QByteArray &fstype, const QString &dev, const QString &point, JobFlags flags=DefaultFlags)
PostalAddress address(const QVariant &location)
void clicked(bool checked)
void toggled(bool checked)
void setCurrentIndex(const QModelIndex &index)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
virtual void accept()
QIcon fromTheme(const QString &name)
QByteArray toJson(JsonFormat format) const const
void append(QList< T > &&value)
void clear()
bool removeOne(const AT &t)
int column() const const
QModelIndex parent() const const
int row() const const
QNetworkReply * get(const QNetworkRequest &request)
QList< QHostAddress > allAddresses()
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QList< T > findChildren(Qt::FindChildOptions options) const const
void setObjectName(QAnyStringView name)
bool isNull() const const
void appendRow(QStandardItem *item)
virtual void setData(const QVariant &value, int role)
void setSelectable(bool selectable)
void appendRow(QStandardItem *item)
QList< QStandardItem * > findItems(const QString &text, Qt::MatchFlags flags, int column) const const
QModelIndex indexFromItem(const QStandardItem *item) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
ToolTipRole
AscendingOrder
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
virtual void setModel(QAbstractItemModel *model) override
void sortByColumn(int column, Qt::SortOrder order)
bool close()
bool isEnabled() const const
void setFocus()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:19:03 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.