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

KDE's Doxygen guidelines are available online.