Kstars

profileeditor.cpp
1 /*
2  SPDX-FileCopyrightText: 2016 Jasem Mutlaq <[email protected]>
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 
23 ProfileEditorUI::ProfileEditorUI(QWidget *p) : QFrame(p)
24 {
25  setupUi(this);
26 }
27 
28 ProfileEditor::ProfileEditor(QWidget *w) : QDialog(w)
29 {
30  setObjectName("profileEditorDialog");
31 #ifdef Q_OS_OSX
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 
109 void 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  {
121  QList<QSharedPointer<ProfileInfo>> existingProfiles;
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 
268 void 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 
305 void 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 
496 QString ProfileEditor::getTooltip(DriverInfo *dv)
497 {
498  bool locallyAvailable = false;
499  if (dv->getAuxInfo().contains("LOCALLY_AVAILABLE"))
500  locallyAvailable = dv->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  dv->getLabel(), dv->getName(), dv->getExecutable());
508 
509  return toolTipText;
510 }
511 
512 void 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 
524  QVector<QComboBox *> boxes;
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();
569  const QList<DeviceFamily> auxFamily = QList<DeviceFamily>()
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 (DriverInfo *dv : DriverManager::Instance()->getDrivers())
589  {
590  bool locallyAvailable = false;
591  QIcon icon;
592  if (dv->getAuxInfo().contains("LOCALLY_AVAILABLE"))
593  locallyAvailable = dv->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(dv);
603 
604  switch (dv->getType())
605  {
606  case KSTARS_CCD:
607  break;
608 
609  case KSTARS_ADAPTIVE_OPTICS:
610  {
611  ui->AOCombo->addItem(icon, dv->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, dv->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, dv->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, dv->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
661  box->addItem(remoteIcon, selectedItemText);
662  }
663  else
664  {
665  box->setCurrentIndex(index);
666  }
667 
668  box->model()->sort(0);
669  }
670 }
671 
672 void ProfileEditor::setProfileName(const QString &name)
673 {
674  ui->profileIN->setText(name);
675 }
676 
677 void ProfileEditor::setAuxDrivers(const QStringList &aux)
678 {
679  QStringList auxList(aux);
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 
701 void 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 
708 void ProfileEditor::setWebManager(bool enabled, const QString &port)
709 {
710  ui->INDIWebManagerCheck->setChecked(enabled);
711  ui->INDIWebManagerPort->setText(port);
712 }
713 
714 void 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 
726 void 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 
749 void 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 
798 void 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 
812  m_INDIHub = profile["indihub"].toInt(m_INDIHub);
813 
814  // Drivers
815  const QString mount = profile["mount"].toString("--");
816  if (mount == "--")
817  ui->mountCombo->setCurrentIndex(0);
818  else
819  {
820  ui->mountCombo->addItem(mount);
821  ui->mountCombo->setCurrentIndex(ui->mountCombo->count() - 1);
822  }
823 
824  const QString ccd = profile["ccd"].toString("--");
825  if (ccd == "--")
826  ui->ccdCombo->setCurrentIndex(0);
827  else
828  {
829  ui->ccdCombo->addItem(ccd);
830  ui->ccdCombo->setCurrentIndex(ui->ccdCombo->count() - 1);
831  }
832 
833  const QString guider = profile["guider"].toString("--");
834  if (guider == "--")
835  ui->guiderCombo->setCurrentIndex(0);
836  else
837  {
838  ui->guiderCombo->addItem(guider);
839  ui->guiderCombo->setCurrentIndex(ui->guiderCombo->count() - 1);
840  }
841 
842  const QString focuser = profile["focuser"].toString("--");
843  if (focuser == "--")
844  ui->focuserCombo->setCurrentIndex(0);
845  else
846  {
847  ui->focuserCombo->addItem(focuser);
848  ui->focuserCombo->setCurrentIndex(ui->focuserCombo->count() - 1);
849  }
850 
851  ui->filterCombo->setCurrentText(profile["filter"].toString("--"));
852  ui->AOCombo->setCurrentText(profile["ao"].toString("--"));
853  ui->domeCombo->setCurrentText(profile["dome"].toString("--"));
854  ui->weatherCombo->setCurrentText(profile["weather"].toString("--"));
855 
856  const auto aux1 = profile["aux1"].toString("--");
857  if (aux1.isEmpty() || aux1 == "--")
858  ui->aux1Combo->setCurrentIndex(0);
859  else
860  {
861  ui->aux1Combo->addItem(aux1);
862  ui->aux1Combo->setCurrentIndex(ui->aux1Combo->count() - 1);
863  }
864 
865  const auto aux2 = profile["aux2"].toString("--");
866  if (aux2.isEmpty() || aux2 == "--")
867  ui->aux2Combo->setCurrentIndex(0);
868  else
869  {
870  ui->aux2Combo->addItem(aux2);
871  ui->aux2Combo->setCurrentIndex(ui->aux2Combo->count() - 1);
872  }
873 
874  const auto aux3 = profile["aux3"].toString("--");
875  if (aux3.isEmpty() || aux3 == "--")
876  ui->aux3Combo->setCurrentIndex(0);
877  else
878  {
879  ui->aux3Combo->addItem(aux3);
880  ui->aux3Combo->setCurrentIndex(ui->aux3Combo->count() - 1);
881  }
882 
883  const auto aux4 = profile["aux4"].toString("--");
884  if (aux4.isEmpty() || aux4 == "--")
885  ui->aux4Combo->setCurrentIndex(0);
886  else
887  {
888  ui->aux4Combo->addItem(aux4);
889  ui->aux4Combo->setCurrentIndex(ui->aux4Combo->count() - 1);
890  }
891 }
892 
893 void ProfileEditor::scanNetwork()
894 {
895  delete (m_ProgressDialog);
896  m_ProgressDialog = new QProgressDialog(this);
897  m_ProgressDialog->setWindowTitle(i18nc("@title:window", "Scanning Network"));
898  m_ProgressDialog->setLabelText(i18n("Scanning network for INDI Web Managers..."));
899  connect(m_ProgressDialog, &QProgressDialog::canceled, this, [this]()
900  {
901  m_CancelScan = true;
902  clearAllRequests();
903  });
904  m_ProgressDialog->setMinimum(0);
905  m_ProgressDialog->setMaximum(0);
906  m_ProgressDialog->show();
907  m_ProgressDialog->raise();
908 
909  m_CancelScan = false;
910 
912  std::sort(addresses.begin(), addresses.end(), [](const QHostAddress & a, const QHostAddress & b) -> bool
913  { return a.toString() < b.toString();});
914 
915  for(QHostAddress address : addresses)
916  {
917  if (address.isLoopback() || address.protocol() & QAbstractSocket::IPv6Protocol)
918  continue;
919 
920  QString ipv4 = address.toString();
921 
922  if (ipv4.startsWith("10.250"))
923  {
924  scanIP("10.250.250.1");
925  }
926  else
927  {
928  QString prefixIP = ipv4.remove(ipv4.lastIndexOf("."), 10);
929  // Blind search all over subnet
930  // TODO better subnet detection instead of assuming it finishes at 254
931  for (int i = 1; i <= 254; i++)
932  {
933  scanIP(prefixIP + "." + QString::number(i));
934  }
935  }
936  }
937 
938 }
939 
940 void ProfileEditor::scanIP(const QString &ip)
941 {
942  QUrl url(QString("http://%1:8624/api/server/status").arg(ip));
943 
944  qCDebug(KSTARS_EKOS) << "Scanning" << url;
945 
946  QNetworkReply *response = m_Manager.get(QNetworkRequest(url));
947  m_Replies.append(response);
948  connect(response, &QNetworkReply::finished, [this, response, ip]()
949  {
950  m_Replies.removeOne(response);
951  response->deleteLater();
952  if (m_CancelScan)
953  return;
954  if (response->error() == QNetworkReply::NoError)
955  {
956  clearAllRequests();
957  m_ProgressDialog->close();
958  ui->remoteHost->setText(ip);
959 
960  qCDebug(KSTARS_EKOS) << "Found Web Manager server at" << ip;
961 
962  KSNotification::info(i18n("Found INDI Web Manager at %1", ip));
963  }
964  });
965 }
966 
967 void ProfileEditor::clearAllRequests()
968 {
969  for (QNetworkReply *oneReply : m_Replies)
970  {
971  oneReply->abort();
972  oneReply->deleteLater();
973  }
974 
975  m_Replies.clear();
976 }
977 
978 void ProfileEditor::showINDIHub()
979 {
980  QDialog hub;
981  Ui::INDIHub indihub;
982  indihub.setupUi(&hub);
983 
984  indihub.modeButtonGroup->setId(indihub.offR, 0);
985  indihub.modeButtonGroup->setId(indihub.solorR, 1);
986  indihub.modeButtonGroup->setId(indihub.shareR, 2);
987  indihub.modeButtonGroup->setId(indihub.roboticR, 3);
988 
989  indihub.logoLabel->setPixmap(QIcon(":/icons/indihub_logo.svg").pixmap(QSize(128, 128)));
990 
991  indihub.modeButtonGroup->button(m_INDIHub)->setChecked(true);
992  connect(indihub.closeB, &QPushButton::clicked, &hub, &QDialog::close);
993 
994  hub.exec();
995 
996  m_INDIHub = indihub.modeButtonGroup->checkedId();
997 }
998 
999 void ProfileEditor::populateManufacturerCombo(QStandardItemModel *model, QComboBox *combo, const QString &selectedDriver,
1000  bool isLocal, const QList<DeviceFamily> &families)
1001 {
1002  if (isLocal)
1003  {
1004  QStandardItem *selectedItem = nullptr;
1005  model->appendRow(new QStandardItem("--"));
1006  for (DriverInfo *dv : DriverManager::Instance()->getDrivers())
1007  {
1008  if (!families.contains(dv->getType()))
1009  continue;
1010 
1011  QString manufacturer = dv->manufacturer();
1012  QList<QStandardItem*> manufacturers = model->findItems(manufacturer);
1013 
1014  QStandardItem *parentItem = nullptr;
1015  if (model->findItems(manufacturer).empty())
1016  {
1017  parentItem = new QStandardItem(manufacturer);
1018  parentItem->setSelectable(false);
1019  model->appendRow(parentItem);
1020  }
1021  else
1022  {
1023  parentItem = manufacturers.first();
1024  }
1025 
1026  QStandardItem *item = new QStandardItem(dv->getLabel());
1027  item->setData(getTooltip(dv), Qt::ToolTipRole);
1028  parentItem->appendRow(item);
1029  if (selectedDriver == dv->getLabel())
1030  selectedItem = item;
1031  }
1032  QTreeView *view = new QTreeView(this);
1033  view->setModel(model);
1034  view->sortByColumn(0, Qt::AscendingOrder);
1035  combo->setView(view);
1036  combo->setModel(model);
1037  if (selectedItem)
1038  {
1039  // JM: Only way to make it the QTreeView sets the current index
1040  // in the combo way
1041 
1042  QModelIndex index = model->indexFromItem(selectedItem);
1043 
1044  // First set current index to the child
1045  combo->setRootModelIndex(index.parent());
1046  combo->setModelColumn(index.column());
1047  combo->setCurrentIndex(index.row());
1048 
1049  // Now reset
1050  combo->setRootModelIndex(QModelIndex());
1051  view->setCurrentIndex(index);
1052  }
1053  }
1054  else
1055  {
1056  QIcon remoteIcon = QIcon::fromTheme("network-modem");
1057  combo->setView(new QListView(this));
1058  model->appendRow(new QStandardItem("--"));
1059  QIcon icon;
1060  for (DriverInfo *dv : DriverManager::Instance()->getDrivers())
1061  {
1062  if (!families.contains(dv->getType()))
1063  continue;
1064 
1065  bool locallyAvailable = false;
1066  if (dv->getAuxInfo().contains("LOCALLY_AVAILABLE"))
1067  locallyAvailable = dv->getAuxInfo().value("LOCALLY_AVAILABLE", false).toBool();
1068  icon = locallyAvailable ? QIcon() : remoteIcon;
1069 
1070  QStandardItem *mount = new QStandardItem(icon, dv->getLabel());
1071  mount->setData(getTooltip(dv), Qt::ToolTipRole);
1072  model->appendRow(mount);
1073  }
1074  combo->setModel(model);
1075  combo->setCurrentText(selectedDriver);
1076  }
1077 }
1078 
1079 void ProfileEditor::executeScriptEditor()
1080 {
1081  if (pi == nullptr)
1082  return;
1083  QStringList currentDrivers;
1084  for (auto &oneCombo : ui->driversGroupBox->findChildren<QComboBox *>())
1085  currentDrivers << oneCombo->currentText();
1086  currentDrivers.removeAll("--");
1087  currentDrivers.removeAll("");
1088  currentDrivers.sort();
1089  ProfileScriptDialog dialog(currentDrivers, pi->scripts, this);
1090  dialog.exec();
1091  auto settings = dialog.jsonSettings();
1092  pi->scripts = QJsonDocument(settings).toJson(QJsonDocument::Compact);
1093 }
T & first()
void setCurrentText(const QString &text)
QString toString(const T &enumerator)
ToolTipRole
QModelIndex indexFromItem(const QStandardItem *item) const const
QString number(int n, int base)
virtual void reject()
virtual void setModel(QAbstractItemModel *model) override
int removeAll(const T &value)
int column() const const
QNetworkReply::NetworkError error() const const
void clear()
void append(const T &value)
void clicked(bool checked)
AscendingOrder
QIcon fromTheme(const QString &name)
void sortByColumn(int column)
void setCurrentIndex(int index)
KSUserDB * userdb()
Definition: kstarsdata.h:214
QAbstractItemModel * model() const const
bool close()
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
bool contains(const T &value) const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void toggled(bool checked)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
QString country() const
Definition: geolocation.h:124
QList< QStandardItem * > findItems(const QString &text, Qt::MatchFlags flags, int column) const const
void setRootModelIndex(const QModelIndex &index)
KIOCORE_EXPORT SimpleJob * mount(bool ro, const QByteArray &fstype, const QString &dev, const QString &point, JobFlags flags=DefaultFlags)
void deleteLater()
void rejected()
QString i18n(const char *text, const TYPE &arg...)
void setWindowFlags(Qt::WindowFlags type)
void setModel(QAbstractItemModel *model)
const T & at(int i) const const
GeoLocation * geo()
Definition: kstarsdata.h:229
void setWindowTitle(const QString &)
void setView(QAbstractItemView *itemView)
void setModelColumn(int visibleColumn)
PostalAddress address(const QVariant &location)
virtual int exec()
void setupUi(QWidget *widget)
QString name() const
Definition: geolocation.h:106
virtual void sort(int column, Qt::SortOrder order)
QString & remove(int position, int n)
QString province() const
Definition: geolocation.h:115
int row() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
ScriptableExtension * host() const
void setCurrentIndex(const QModelIndex &index)
int findText(const QString &text, Qt::MatchFlags flags) const const
int count() const const
void setObjectName(const QString &name)
QList< QHostAddress > allAddresses()
void appendRow(const QList< QStandardItem * > &items)
QByteArray toJson() const const
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QList::iterator begin()
QModelIndex parent() const const
void addItem(const QString &text, const QVariant &userData)
virtual void setData(const QVariant &value, int role)
void setSelectable(bool selectable)
void setLayout(QLayout *layout)
QList::iterator end()
void appendRow(const QList< QStandardItem * > &items)
virtual void abort()=0
void GetAllProfiles(QList< QSharedPointer< ProfileInfo > > &profiles)
GetAllProfiles Return all profiles in a QList.
Definition: ksuserdb.cpp:2257
void sort(Qt::CaseSensitivity cs)
void accepted()
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 03:57:33 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.