Kstars

drivermanager.cpp
1/*
2 SPDX-FileCopyrightText: 2012 Jasem Mutlaq <mutlaqja@ikarustech.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#include "drivermanager.h"
8
9#include "config-kstars.h"
10
11#include "clientmanager.h"
12#include "driverinfo.h"
13#include "guimanager.h"
14#include "indilistener.h"
15#include "kspaths.h"
16#include "kstars.h"
17#include "indidbus.h"
18#include "kstarsdata.h"
19#include "Options.h"
20#include "servermanager.h"
21#include "ui_indihostconf.h"
22#include "auxiliary/ksnotification.h"
23
24#include <basedevice.h>
25
26#ifndef KSTARS_LITE
27#include <KMessageBox>
28#include <KActionCollection>
29#include <KNotifications/KNotification>
30#endif
31
32#include <QTcpServer>
33#include <QtConcurrent>
34#include <indi_debug.h>
35
36#define INDI_MAX_TRIES 2
37#define ERRMSG_SIZE 1024
38
39DriverManagerUI::DriverManagerUI(QWidget *parent) : QFrame(parent)
40{
41 setupUi(this);
42
43 localTreeWidget->setSortingEnabled(false);
44 localTreeWidget->setRootIsDecorated(true);
45
46 clientTreeWidget->setSortingEnabled(false);
47
48 runningPix = QIcon::fromTheme("system-run");
49 stopPix = QIcon::fromTheme("dialog-cancel");
50 localMode = QIcon::fromTheme("computer");
51 serverMode = QIcon::fromTheme("network-server");
52
53 connected = QIcon::fromTheme("network-connect");
54 disconnected = QIcon::fromTheme("network-disconnect");
55
57 &DriverManagerUI::makePortEditable);
58}
59
60void DriverManagerUI::makePortEditable(QTreeWidgetItem *selectedItem, int column)
61{
62 // If it's the port column, then make it user-editable
63 if (column == ::DriverManager::LOCAL_PORT_COLUMN)
66
67 localTreeWidget->editItem(selectedItem, ::DriverManager::LOCAL_PORT_COLUMN);
68}
69
70DriverManager *DriverManager::_DriverManager = nullptr;
71INDIDBus *DriverManager::_INDIDBus = nullptr;
72
73DriverManager *DriverManager::Instance()
74{
75 if (_DriverManager == nullptr)
76 {
77 _DriverManager = new DriverManager(KStars::Instance());
78 _INDIDBus = new INDIDBus(KStars::Instance());
79
80 qRegisterMetaType<QSharedPointer<DriverInfo>>("QSharedPointer<DriverInfo>");
81 }
82
83 return _DriverManager;
84}
85
86void DriverManager::release()
87{
88 delete (_DriverManager);
89 delete (_INDIDBus);
90 _DriverManager = nullptr;
91 _INDIDBus = nullptr;
92}
93
94DriverManager::DriverManager(QWidget *parent) : QDialog(parent)
95{
96#ifdef Q_OS_OSX
97 setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
98#endif
99
100 currentPort = Options::serverPortStart() - 1;
101
102 QVBoxLayout *mainLayout = new QVBoxLayout;
103 ui = new DriverManagerUI(this);
104 mainLayout->addWidget(ui);
105 setLayout(mainLayout);
106 setWindowTitle(i18nc("@title:window", "Device Manager"));
107
109 mainLayout->addWidget(buttonBox);
110
112
113 connect(ui->addB, &QPushButton::clicked, this, &DriverManager::addINDIHost);
114 connect(ui->modifyB, &QPushButton::clicked, this, &DriverManager::modifyINDIHost);
115 connect(ui->removeB, &QPushButton::clicked, this, &DriverManager::removeINDIHost);
116
117 connect(ui->connectHostB, &QPushButton::clicked, this, &DriverManager::activateHostConnection);
118 connect(ui->disconnectHostB, &QPushButton::clicked, this, &DriverManager::activateHostDisconnection);
119 connect(ui->runServiceB, &QPushButton::clicked, this, &DriverManager::activateRunService);
120 connect(ui->stopServiceB, &QPushButton::clicked, this, &DriverManager::activateStopService);
121 connect(ui->localTreeWidget, &QTreeWidget::itemClicked, this, &DriverManager::updateLocalTab);
122 connect(ui->clientTreeWidget, &QTreeWidget::itemClicked, this, &DriverManager::updateClientTab);
123 connect(ui->localTreeWidget, &QTreeWidget::expanded, this, &DriverManager::resizeDeviceColumn);
124
125 // Do not use KSPaths here, this is for INDI
126 if (Options::indiDriversDir().isEmpty())
127 Options::setIndiDriversDir(
130
131 readXMLDrivers();
132
133 readINDIHosts();
134
135 m_CustomDrivers = new CustomDrivers(this, driversList);
136
137 updateCustomDrivers();
138
139#ifdef Q_OS_WIN
140 ui->localTreeWidget->setEnabled(false);
141#endif
142}
143
144DriverManager::~DriverManager()
145{
146 clearServers();
147}
148
149void DriverManager::processDeviceStatus(const QSharedPointer<DriverInfo> &driver)
150{
151 if (driver.isNull() || driver->getDriverSource() == GENERATED_SOURCE)
152 return;
153
155 ServerMode mode = connectionMode;
156 ServerManager *manager = driver->getServerManager();
157 bool dState = false;
158 bool cState = false;
159
160 if (driver->getDriverSource() != HOST_SOURCE)
161 {
162 if (ui->localTreeWidget->currentItem())
163 currentDriver = ui->localTreeWidget->currentItem()->text(LOCAL_NAME_COLUMN);
164
165 for (auto &item : ui->localTreeWidget->findItems(
166 driver->getLabel(), Qt::MatchExactly | Qt::MatchRecursive))
167 {
168 item->setText(LOCAL_VERSION_COLUMN, driver->getVersion());
169
170 if (manager)
171 mode = manager->getMode();
172
173 dState = driver->getServerState();
174 cState = driver->getClientState() && dState;
175
176 bool locallyAvailable = false;
177 if (driver->getAuxInfo().contains("LOCALLY_AVAILABLE"))
179 driver->getAuxInfo().value("LOCALLY_AVAILABLE", false).toBool();
180
181 switch (mode)
182 {
183 case SERVER_ONLY:
185 {
186 ui->runServiceB->setEnabled(!dState);
187 ui->stopServiceB->setEnabled(dState);
188 item->setIcon(LOCAL_STATUS_COLUMN,
189 dState ? ui->runningPix : ui->stopPix);
190 }
191 else
192 {
193 ui->runServiceB->setEnabled(false);
194 ui->stopServiceB->setEnabled(false);
195 }
196
197 if (dState)
198 {
199 item->setIcon(LOCAL_MODE_COLUMN, ui->serverMode);
200 if (manager)
201 {
202 item->setText(LOCAL_PORT_COLUMN, QString::number(manager->getPort()));
203 }
204 }
205 else
206 {
207 item->setIcon(LOCAL_MODE_COLUMN, QIcon());
208 item->setText(LOCAL_PORT_COLUMN, QString::number(driver->getUserPort()));
209 }
210
211 break;
212
213 case SERVER_CLIENT:
215 {
216 ui->runServiceB->setEnabled(!cState);
217 ui->stopServiceB->setEnabled(cState);
218 item->setIcon(LOCAL_STATUS_COLUMN,
219 cState ? ui->runningPix : ui->stopPix);
220 }
221 else
222 {
223 ui->runServiceB->setEnabled(false);
224 ui->stopServiceB->setEnabled(false);
225 }
226
227 if (cState)
228 {
229 item->setIcon(LOCAL_MODE_COLUMN, ui->localMode);
230
231 if (manager)
232 {
233 item->setText(LOCAL_PORT_COLUMN, QString::number(manager->getPort()));
234 }
235 }
236 else
237 {
238 item->setIcon(LOCAL_MODE_COLUMN, QIcon());
239 const auto port = driver->getUserPort() == -1 ? QString() : QString::number(driver->getUserPort());
240 item->setText(LOCAL_PORT_COLUMN, port);
241 }
242
243 break;
244 }
245
246 // Only update the log if the current driver is selected
247 if (currentDriver == driver->getLabel())
248 {
249 ui->serverLogText->clear();
250 ui->serverLogText->append(driver->getServerBuffer());
251 }
252 }
253 }
254 else
255 {
256 for (auto &item : ui->clientTreeWidget->findItems(driver->getName(), Qt::MatchExactly,
257 HOST_NAME_COLUMN))
258 {
259 if (driver->getClientState())
260 {
261 item->setIcon(HOST_STATUS_COLUMN, ui->connected);
262 ui->connectHostB->setEnabled(false);
263 ui->disconnectHostB->setEnabled(true);
264 }
265 else
266 {
267 item->setIcon(HOST_STATUS_COLUMN, ui->disconnected);
268 ui->connectHostB->setEnabled(true);
269 ui->disconnectHostB->setEnabled(false);
270 }
271 }
272 }
273}
274
277{
278 bool found = false;
279
280 // Iterate over all drivers
281 for (auto &dv : dList)
282 {
284
285 // Let's see for drivers with identical hosts and ports
286 for (auto &idv : dList)
287 {
288 // If we get a match between port and hostname, we add it to the list
289 if ((dv->getHost() == idv->getHost() && dv->getPort() == idv->getPort()))
290 {
291 // Check if running already
292 if (dv->getClientState() || dv->getServerState())
293 {
295 nullptr,
296 i18n("Driver %1 is already running, do you want to restart it?",
297 dv->getLabel()));
299 continue;
300 else
301 {
303 stopList.append(dv);
304 stopDevices(stopList);
305 }
306 }
307
308 found = false;
309
310 // Check to see if the driver already been added elsewhere
311 for (auto &qdi : uHosts)
312 {
314 {
315 if (di == idv)
316 {
317 found = true;
318 break;
319 }
320 }
321 }
322
323 if (found == false)
324 uList.append(idv);
325 }
326 }
327
328 if (uList.empty() == false)
329 uHosts.append(uList);
330 }
331}
332
333void DriverManager::startDevices(const QList<QSharedPointer<DriverInfo>> &dList)
334{
335 ServerManager *serverManager = nullptr;
336 int port = -1;
337
340
341 qCDebug(KSTARS_INDI) << "INDI: Starting local drivers...";
342
343 for (auto &qdv : uHosts)
344 {
345 if (qdv.empty())
346 continue;
347
348 port = qdv.at(0)->getPort();
349 auto host = qdv.at(0)->getHost();
350
351 // Select random port within range is none specified.
352 if (port == -1)
353 port = getINDIPort(port);
354
355 if (port <= 0)
356 {
357 emit serverFailed(host, port, i18n("Cannot start INDI server: port error."));
358 return;
359 }
360
361 serverManager = new ServerManager(host, port);
362
363 if (serverManager == nullptr)
364 {
365 emit serverFailed(host, port, i18n("Failed to create local INDI server"));
366 return;
367 }
368
369 servers.append(serverManager);
370 serverManager->setPendingDrivers(qdv);
371 serverManager->setMode(connectionMode);
372
373 connect(serverManager, &ServerManager::newServerLog, this, &DriverManager::updateLocalTab, Qt::UniqueConnection);
374 connect(serverManager, &ServerManager::started, this, &DriverManager::setServerStarted, Qt::UniqueConnection);
375 connect(serverManager, &ServerManager::failed, this, &DriverManager::setServerFailed, Qt::UniqueConnection);
376 connect(serverManager, &ServerManager::terminated, this, &DriverManager::setServerTerminated, Qt::UniqueConnection);
377
378 serverManager->start();
379 }
380}
381
382void DriverManager::startLocalDrivers(ServerManager *serverManager)
383{
384 connect(serverManager, &ServerManager::driverStarted, this, &DriverManager::processDriverStartup, Qt::UniqueConnection);
385 connect(serverManager, &ServerManager::driverFailed, this, &DriverManager::processDriverFailure, Qt::UniqueConnection);
386 QtConcurrent::run(serverManager, &ServerManager::startDriver, serverManager->pendingDrivers().first());
387}
388
389void DriverManager::processDriverStartup(const QSharedPointer<DriverInfo> &driver)
390{
391 emit driverStarted(driver);
392
393 auto manager = driver->getServerManager();
394 // Do we have more pending drivers?
395 if (manager->pendingDrivers().count() > 0)
396 {
397 QtConcurrent::run(manager, &ServerManager::startDriver, manager->pendingDrivers().first());
398 return;
399 }
400
401 // Nothing to do more if SERVER ONLY
402 if (connectionMode == SERVER_ONLY)
403 {
404 return;
405 }
406
407 // Otherwise proceed to start Client Manager
408 startClientManager(manager->managedDrivers(), manager->getHost(), manager->getPort());
409}
410
411void DriverManager::processDriverFailure(const QSharedPointer<DriverInfo> &driver, const QString &message)
412{
413 emit driverFailed(driver, message);
414
415 qCWarning(KSTARS_INDI) << "Driver" << driver->getName() << "failed to start. Retrying in 5 seconds...";
416
417 QTimer::singleShot(5000, this, [driver]()
418 {
419 auto manager = driver->getServerManager();
420 // Do we have more pending drivers?
421 if (manager->pendingDrivers().count() > 0)
422 {
423 QtConcurrent::run(manager, &ServerManager::startDriver, manager->pendingDrivers().first());
424 return;
425 }
426 });
427}
428
429void DriverManager::startClientManager(const QList<QSharedPointer<DriverInfo>> &qdv, const QString &host, int port)
430{
431 auto clientManager = new ClientManager();
432
433 for (auto &dv : qdv)
434 clientManager->appendManagedDriver(dv);
435
436 connect(clientManager, &ClientManager::started, this, &DriverManager::setClientStarted, Qt::UniqueConnection);
437 connect(clientManager, &ClientManager::failed, this, &DriverManager::setClientFailed, Qt::UniqueConnection);
438 connect(clientManager, &ClientManager::terminated, this, &DriverManager::setClientTerminated, Qt::UniqueConnection);
439
440 clientManager->setServer(host.toLatin1().constData(), port);
441
442 GUIManager::Instance()->addClient(clientManager);
443 INDIListener::Instance()->addClient(clientManager);
444
445 clientManager->establishConnection();
446}
447
448void DriverManager::stopDevices(const QList<QSharedPointer<DriverInfo>> &dList)
449{
450 qCDebug(KSTARS_INDI) << "INDI: Stopping local drivers...";
451
452 // #1 Disconnect all clients
454 {
455 ClientManager *cm = dv->getClientManager();
456
457 if (cm == nullptr)
458 continue;
459
460 cm->removeManagedDriver(dv);
461
462 if (cm->count() == 0)
463 {
464 GUIManager::Instance()->removeClient(cm);
465 INDIListener::Instance()->removeClient(cm);
466 cm->disconnectServer();
467 clients.removeOne(cm);
468 cm->deleteLater();
469
470 KStars::Instance()->slotSetTelescopeEnabled(false);
471 KStars::Instance()->slotSetDomeEnabled(false);
472 }
473 }
474
475 // #2 Disconnect all servers
477 {
478 ServerManager *sm = dv->getServerManager();
479
480 if (sm != nullptr)
481 {
482 sm->stopDriver(dv);
483
484 if (sm->size() == 0)
485 {
486 sm->stop();
487 servers.removeOne(sm);
488 sm->deleteLater();
489 }
490 }
491 }
492
493 // Reset current port
494 currentPort = Options::serverPortStart() - 1;
495
496 updateMenuActions();
497}
498
499void DriverManager::disconnectClients()
500{
501 for (auto &clientManager : clients)
502 {
503 clientManager->disconnectAll();
504 clientManager->disconnect();
505 }
506}
507
508void DriverManager::clearServers()
509{
510 for (auto &serverManager : servers)
511 serverManager->stop();
512
513 qDeleteAll(servers);
514}
515
516void DriverManager::activateRunService()
517{
518 processLocalTree(true);
519}
520
521void DriverManager::activateStopService()
522{
523 processLocalTree(false);
524}
525
526void DriverManager::activateHostConnection()
527{
528 processRemoteTree(true);
529}
530
531void DriverManager::activateHostDisconnection()
532{
533 processRemoteTree(false);
534}
535
536ClientManager *DriverManager::getClientManager(const QSharedPointer<DriverInfo> &driver)
537{
538 auto cm = driver->getClientManager();
539 if (cm)
540 return cm;
541 // If no client manager found for the driver, return the first client manager on the same host and port number
542 else if (!clients.isEmpty())
543 {
544 auto host = driver->getHost();
545 auto port = driver->getPort();
546 auto it = std::find_if(clients.begin(), clients.end(), [host, port](const auto & oneClient)
547 {
548 return oneClient->getHost() == host && oneClient->getPort() == port;
549 }
550 );
551 if (it != clients.end())
552 return *it;
553 }
554
555 return nullptr;
556}
557
558void DriverManager::updateLocalTab()
559{
560 if (ui->localTreeWidget->currentItem() == nullptr)
561 return;
562
563 QString currentDriver = ui->localTreeWidget->currentItem()->text(LOCAL_NAME_COLUMN);
564
565 auto device = std::find_if(driversList.begin(), driversList.end(), [currentDriver](const auto & oneDriver)
566 {
567 return currentDriver == oneDriver->getLabel();
568 });
569 if (device != driversList.end())
570 processDeviceStatus(*device);
571}
572
573void DriverManager::updateClientTab()
574{
575 QTreeWidgetItem *item = ui->clientTreeWidget->currentItem();
576
577 if (item == nullptr)
578 return;
579
580 auto hostname = item->text(HOST_NAME_COLUMN);
581 int port = item->text(HOST_PORT_COLUMN).toInt();
582
583 auto device = std::find_if(driversList.begin(), driversList.end(), [hostname, port](const auto & oneDriver)
584 {
585 return hostname == oneDriver->getName() && port == oneDriver->getPort();
586 });
587 if (device != driversList.end())
588 processDeviceStatus(*device);
589}
590
591void DriverManager::processLocalTree(bool dState)
592{
594
595 int port;
596 bool portOK = false;
597
598 connectionMode = ui->localR->isChecked() ? SERVER_CLIENT : SERVER_ONLY;
599
600 for (auto &item : ui->localTreeWidget->selectedItems())
601 {
602 for (auto &device : driversList)
603 {
604 port = -1;
605
606 //device->state = (dev_request == DriverInfo::DEV_TERMINATE) ? DriverInfo::DEV_START : DriverInfo::DEV_TERMINATE;
607 if (item->text(LOCAL_NAME_COLUMN) == device->getLabel() &&
608 device->getServerState() != dState)
609 {
610 processed_devices.append(device);
611
612 // N.B. If multiple devices are selected to run under one device manager
613 // then we select the port for the first device that has a valid port
614 // entry, the rest are ignored.
615 if (port == -1 && item->text(LOCAL_PORT_COLUMN).isEmpty() == false)
616 {
617 port = item->text(LOCAL_PORT_COLUMN).toInt(&portOK);
618 // If we encounter conversion error, we abort
619 if (portOK == false)
620 {
621 KSNotification::error(i18n("Invalid port entry: %1", item->text(LOCAL_PORT_COLUMN)));
622 return;
623 }
624 }
625
626 device->setHostParameters("localhost", port);
627 }
628 }
629 }
630
631 if (processed_devices.empty())
632 return;
633
634 if (dState)
635 startDevices(processed_devices);
636 else
637 stopDevices(processed_devices);
638}
639
640void DriverManager::setClientFailed(const QString &message)
641{
642 auto client = qobject_cast<ClientManager*>(sender());
643
644 if (client == nullptr)
645 return;
646
647 auto host = client->getHost();
648 auto port = client->getPort();
649
651
652 emit clientFailed(host, port, message);
653
654 GUIManager::Instance()->removeClient(client);
655 INDIListener::Instance()->removeClient(client);
656
657 KSNotification::event(QLatin1String("IndiServerMessage"), message, KSNotification::INDI);
658
659 clients.removeOne(client);
660 client->deleteLater();
661
662 if (connectionMode == SERVER_CLIENT)
663 activateStopService();
664
665 updateMenuActions();
666 updateLocalTab();
667}
668
669void DriverManager::setClientTerminated(const QString &message)
670{
671 auto client = qobject_cast<ClientManager*>(sender());
672
673 if (client == nullptr)
674 return;
675
676 auto host = client->getHost();
677 auto port = client->getPort();
678
680
681 emit clientTerminated(host, port, message);
682
683 GUIManager::Instance()->removeClient(client);
684 INDIListener::Instance()->removeClient(client);
685
686 KSNotification::event(QLatin1String("IndiServerMessage"), message, KSNotification::INDI, KSNotification::Alert);
687
688 clients.removeOne(client);
689 client->deleteLater();
690
691 updateMenuActions();
692 updateLocalTab();
693 updateClientTab();
694}
695
696void DriverManager::setServerStarted()
697{
698 auto manager = qobject_cast<ServerManager*>(sender());
699 qCDebug(KSTARS_INDI) << "INDI: INDI Server started locally on port " << manager->getPort();
700 startLocalDrivers(manager);
701 emit serverStarted(manager->getHost(), manager->getPort());
702}
703
704void DriverManager::setServerFailed(const QString &message)
705{
706 auto server = qobject_cast<ServerManager *>(sender());
707
708 if (server == nullptr)
709 return;
710
711 for (auto &dv : driversList)
712 {
713 if (dv->getServerManager() == server)
714 {
715 dv->reset();
716 }
717 }
718
719 if (server->getMode() == SERVER_ONLY)
720 KSNotification::error(message);
721
722 emit serverFailed(server->getHost(), server->getPort(), message);
723 servers.removeOne(server);
724 server->deleteLater();
725
726 updateLocalTab();
727}
728
729void DriverManager::setServerTerminated(const QString &message)
730{
731 auto server = qobject_cast<ServerManager *>(sender());
732
733 if (server == nullptr)
734 return;
735
736 for (auto &dv : driversList)
737 {
738 if (dv->getServerManager() == server)
739 {
740 dv->reset();
741 }
742 }
743
744 if (server->getMode() == SERVER_ONLY)
745 KSNotification::error(message);
746
747 emit serverTerminated(server->getHost(), server->getPort(), message);
748 servers.removeOne(server);
749 server->deleteLater();
750
751 updateLocalTab();
752}
753
754void DriverManager::processRemoteTree(bool dState)
755{
756 QTreeWidgetItem *currentItem = ui->clientTreeWidget->currentItem();
757 if (!currentItem)
758 return;
759
760 for (auto &dv : driversList)
761 {
762 if (dv->getDriverSource() != HOST_SOURCE)
763 continue;
764
765 //qDebug() << Q_FUNC_INFO << "Current item port " << currentItem->text(HOST_PORT_COLUMN) << " current dev " << dv->getName() << " -- port " << dv->getPort() << Qt::endl;
766 //qDebug() << Q_FUNC_INFO << "dState is : " << (dState ? "True" : "False") << Qt::endl;
767
768 if (currentItem->text(HOST_NAME_COLUMN) == dv->getName() &&
769 currentItem->text(HOST_PORT_COLUMN).toInt() == dv->getPort())
770 {
771 // Nothing changed, return
772 if (dv->getClientState() == dState)
773 return;
774
775 // connect to host
776 if (dState)
777 connectRemoteHost(dv);
778 // Disconnect form host
779 else
780 disconnectRemoteHost(dv);
781 }
782 }
783}
784
785void DriverManager::connectRemoteHost(const QSharedPointer<DriverInfo> &driver)
786{
787 auto host = driver->getHost();
788 auto port = driver->getPort();
789
790 auto clientManager = new ClientManager();
791
792 clientManager->appendManagedDriver(driver);
793
794 connect(clientManager, &ClientManager::started, this, &DriverManager::setClientStarted, Qt::UniqueConnection);
795 connect(clientManager, &ClientManager::failed, this, &DriverManager::setClientFailed, Qt::UniqueConnection);
796 connect(clientManager, &ClientManager::terminated, this, &DriverManager::setClientTerminated, Qt::UniqueConnection);
797
798 clientManager->setServer(host.toLatin1().constData(), port);
799
800 GUIManager::Instance()->addClient(clientManager);
801 INDIListener::Instance()->addClient(clientManager);
802
803 clientManager->establishConnection();
804}
805
806void DriverManager::setClientStarted()
807{
808 auto clientManager = qobject_cast<ClientManager *>(sender());
809 if (clientManager == nullptr)
810 return;
811
812 clients.append(clientManager);
813 updateLocalTab();
814 updateMenuActions();
815
816 KSNotification::event(QLatin1String("ConnectionSuccessful"),
817 i18n("Connected to INDI server"));
818
819 emit clientStarted(clientManager->getHost(), clientManager->getPort());
820}
821
822bool DriverManager::disconnectRemoteHost(const QSharedPointer<DriverInfo> &driver)
823{
824 ClientManager *clientManager = driver->getClientManager();
825
826 if (clientManager)
827 {
828 clientManager->removeManagedDriver(driver);
829 clientManager->disconnectAll();
830 GUIManager::Instance()->removeClient(clientManager);
831 INDIListener::Instance()->removeClient(clientManager);
832 clients.removeOne(clientManager);
833 clientManager->deleteLater();
834 updateMenuActions();
835 return true;
836 }
837
838 return false;
839}
840
841void DriverManager::resizeDeviceColumn()
842{
843 ui->localTreeWidget->resizeColumnToContents(0);
844}
845
846void DriverManager::updateMenuActions()
847{
848 // We iterate over devices, we enable INDI Control Panel if we have any active device
849 // We enable capture image sequence if we have any imaging device
850
851 QAction *tmpAction = nullptr;
852 bool activeDevice = false;
853
854 if (clients.size() > 0)
855 activeDevice = true;
856
857 tmpAction = KStars::Instance()->actionCollection()->action("indi_cpl");
858 if (tmpAction != nullptr)
859 {
860 //qDebug() << Q_FUNC_INFO << "indi_cpl action set to active" << Qt::endl;
861 tmpAction->setEnabled(activeDevice);
862 }
863}
864
865int DriverManager::getINDIPort(int customPort)
866{
867#ifdef Q_OS_WIN
868 qWarning() << "INDI server is currently not supported on Windows.";
869 return -1;
870#else
871 int lastPort = Options::serverPortEnd();
872 bool success = false;
873 currentPort++;
874
875 // recycle
876 if (currentPort > lastPort)
877 currentPort = Options::serverPortStart();
878
880
881 if (customPort != -1)
882 {
884 if (success)
885 {
886 temp_server.close();
887 return customPort;
888 }
889 else
890 return -1;
891 }
892
893 for (; currentPort <= lastPort; currentPort++)
894 {
895 success = temp_server.listen(QHostAddress::LocalHost, currentPort);
896 if (success)
897 {
898 temp_server.close();
899 return currentPort;
900 }
901 }
902 return -1;
903#endif
904}
905
906bool DriverManager::readINDIHosts()
907{
908 QString indiFile("indihosts.xml");
909 //QFile localeFile;
910 QFile file;
911 char errmsg[1024];
912 char c;
914 XMLEle *root = nullptr;
915 XMLAtt *ap = nullptr;
917
918 lastGroup = nullptr;
920 if (file.fileName().isEmpty() || !file.open(QIODevice::ReadOnly))
921 {
923 return false;
924 }
925
926 while (file.getChar(&c))
927 {
928 root = readXMLEle(xmlParser, c, errmsg);
929
930 if (root)
931 {
932 // Get host name
933 ap = findXMLAtt(root, "name");
934 if (!ap)
935 {
937 return false;
938 }
939
941
942 // Get host name
943 ap = findXMLAtt(root, "hostname");
944
945 if (!ap)
946 {
948 return false;
949 }
950
952
953 ap = findXMLAtt(root, "port");
954
955 if (!ap)
956 {
958 return false;
959 }
960
962
964 dv->setHostParameters(hHost, hPort.toInt());
965 dv->setDriverSource(HOST_SOURCE);
966
967 connect(dv.get(), &DriverInfo::deviceStateChanged, this, [dv, this]()
968 {
969 processDeviceStatus(dv);
970 });
971
972 driversList.append(dv);
973
974 QTreeWidgetItem *item = new QTreeWidgetItem(ui->clientTreeWidget, lastGroup);
975 lastGroup = item;
976 item->setIcon(HOST_STATUS_COLUMN, ui->disconnected);
977 item->setText(HOST_NAME_COLUMN, hName);
978 item->setText(HOST_PORT_COLUMN, hPort);
979
980 delXMLEle(root);
981 }
982 else if (errmsg[0])
983 {
984 qDebug() << Q_FUNC_INFO << errmsg;
986 return false;
987 }
988 }
989
991
992 return true;
993}
994
995bool DriverManager::readXMLDrivers()
996{
998 QString driverName;
999
1000 QString driversDir = Options::indiDriversDir();
1001#ifdef Q_OS_OSX
1002 if (Options::indiDriversAreInternal())
1003 driversDir =
1004 QCoreApplication::applicationDirPath() + "/../Resources/DriverSupport";
1005#endif
1006
1007 if (indiDir.cd(driversDir) == false)
1008 {
1009 KSNotification::error(i18n("Unable to find INDI drivers directory: %1\nPlease "
1010 "make sure to set the correct "
1011 "path in KStars configuration",
1012 driversDir));
1013 return false;
1014 }
1015
1016 indiDir.setNameFilters(QStringList() << "indi_*.xml"
1017 << "drivers.xml");
1019 QFileInfoList list = indiDir.entryInfoList();
1020
1021 for (auto &fileInfo : list)
1022 {
1023 if (fileInfo.fileName().endsWith(QLatin1String("_sk.xml")))
1024 continue;
1025
1026 processXMLDriver(fileInfo.absoluteFilePath());
1027 }
1028
1029 // JM 2022.08.24: Process local source last as INDI sources should have higher priority than KStars own database.
1030 processXMLDriver(QLatin1String(":/indidrivers.xml"));
1031
1032 return true;
1033}
1034
1035void DriverManager::processXMLDriver(const QString &driverName)
1036{
1037 QFile file(driverName);
1039 {
1040 KSNotification::error(i18n("Failed to open INDI Driver file: %1", driverName));
1041 return;
1042 }
1043
1044 char errmsg[ERRMSG_SIZE];
1045 char c;
1047 XMLEle *root = nullptr;
1048 XMLEle *ep = nullptr;
1049
1050 if (driverName.endsWith(QLatin1String("drivers.xml")))
1051 driverSource = PRIMARY_XML;
1052 else
1053 driverSource = THIRD_PARTY_XML;
1054
1055 while (file.getChar(&c))
1056 {
1057 root = readXMLEle(xmlParser, c, errmsg);
1058
1059 if (root)
1060 {
1061 // If the XML file is using the INDI Library v1.3+ format
1062 if (!strcmp(tagXMLEle(root), "driversList"))
1063 {
1064 for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
1065 {
1066 if (!buildDeviceGroup(ep, errmsg))
1067 prXMLEle(stderr, ep, 0);
1068 }
1069 }
1070 // If using the older format
1071 else
1072 {
1073 if (!buildDeviceGroup(root, errmsg))
1074 prXMLEle(stderr, root, 0);
1075 }
1076
1077 delXMLEle(root);
1078 }
1079 else if (errmsg[0])
1080 {
1081 qCDebug(KSTARS_INDI) << QString(errmsg);
1083 return;
1084 }
1085 }
1086
1088}
1089
1090bool DriverManager::buildDeviceGroup(XMLEle *root, char errmsg[])
1091{
1092 XMLAtt *ap;
1093 XMLEle *ep;
1094 QString groupName;
1095 QTreeWidgetItem *group;
1096 DeviceFamily groupType = KSTARS_TELESCOPE;
1097
1098 // avoid overflow
1099 if (strlen(tagXMLEle(root)) > 1024)
1100 return false;
1101
1102 // Get device grouping name
1103 ap = findXMLAtt(root, "group");
1104
1105 if (!ap)
1106 {
1107 snprintf(errmsg, ERRMSG_SIZE, "Tag %.64s does not have a group attribute",
1108 tagXMLEle(root));
1109 return false;
1110 }
1111
1112 groupName = valuXMLAtt(ap);
1113 groupType = DeviceFamilyLabels.key(groupName);
1114
1115#ifndef HAVE_CFITSIO
1116 // We do not create these groups if we don't have CFITSIO support
1117 if (groupType == KSTARS_CCD || groupType == KSTARS_VIDEO)
1118 return true;
1119#endif
1120
1121 // Find if the group already exists
1123 ui->localTreeWidget->findItems(groupName, Qt::MatchExactly);
1124 if (!treeList.isEmpty())
1125 group = treeList[0];
1126 else
1127 group = new QTreeWidgetItem(ui->localTreeWidget, lastGroup);
1128
1129 group->setText(0, groupName);
1130 lastGroup = group;
1131
1132 for (ep = nextXMLEle(root, 1); ep != nullptr; ep = nextXMLEle(root, 0))
1133 {
1134 if (!buildDriverElement(ep, group, groupType, errmsg))
1135 return false;
1136 }
1137
1138 return true;
1139}
1140
1141bool DriverManager::buildDriverElement(XMLEle *root, QTreeWidgetItem *DGroup,
1142 DeviceFamily groupType, char errmsg[])
1143{
1144 XMLAtt *ap;
1145 XMLEle *el;
1146 QString label;
1147 QString driver;
1149 // N.B. NOT an i18n string.
1150 QString manufacturer("Others");
1151 QString name;
1152 QString port;
1153 QString skel;
1154 QVariantMap vMap;
1155 //double focal_length(-1), aperture(-1);
1156
1157 ap = findXMLAtt(root, "label");
1158 if (!ap)
1159 {
1160 snprintf(errmsg, ERRMSG_SIZE, "Tag %.64s does not have a label attribute",
1161 tagXMLEle(root));
1162 return false;
1163 }
1164
1165 label = valuXMLAtt(ap);
1166
1167 // Label is unique, so if we have the same label, we simply ignore
1168 if (findDriverByLabel(label) != nullptr)
1169 return true;
1170
1171 ap = findXMLAtt(root, "manufacturer");
1172 if (ap)
1173 manufacturer = valuXMLAtt(ap);
1174
1175 // Search for optional port attribute
1176 ap = findXMLAtt(root, "port");
1177 if (ap)
1178 port = valuXMLAtt(ap);
1179
1180 // Search for skel file, if any
1181 // Search for optional port attribute
1182 ap = findXMLAtt(root, "skel");
1183 if (ap)
1184 skel = valuXMLAtt(ap);
1185
1186 // Find MDPD: Multiple Devices Per Driver
1187 ap = findXMLAtt(root, "mdpd");
1188 if (ap)
1189 {
1190 bool mdpd = false;
1191 mdpd = (QString(valuXMLAtt(ap)) == QString("true")) ? true : false;
1192 vMap.insert("mdpd", mdpd);
1193 }
1194
1195 el = findXMLEle(root, "driver");
1196
1197 if (!el)
1198 return false;
1199
1200 driver = pcdataXMLEle(el);
1201
1202 ap = findXMLAtt(el, "name");
1203 if (!ap)
1204 {
1205 snprintf(errmsg, ERRMSG_SIZE, "Tag %.64s does not have a name attribute",
1206 tagXMLEle(el));
1207 return false;
1208 }
1209
1210 name = valuXMLAtt(ap);
1211
1212 el = findXMLEle(root, "version");
1213
1214 if (!el)
1215 return false;
1216
1217 version = pcdataXMLEle(el);
1218 bool versionOK = false;
1219 version.toDouble(&versionOK);
1220 if (versionOK == false)
1221 version = "1.0";
1222
1223 bool driverIsAvailable = checkDriverAvailability(driver);
1224
1225 vMap.insert("LOCALLY_AVAILABLE", driverIsAvailable);
1226 QIcon remoteIcon = QIcon::fromTheme("network-modem");
1227
1228 QTreeWidgetItem *device = new QTreeWidgetItem(DGroup);
1229
1230 device->setText(LOCAL_NAME_COLUMN, label);
1232 device->setIcon(LOCAL_STATUS_COLUMN, ui->stopPix);
1233 else
1234 device->setIcon(LOCAL_STATUS_COLUMN, remoteIcon);
1235 device->setText(LOCAL_VERSION_COLUMN, version);
1236 device->setText(LOCAL_PORT_COLUMN, port);
1237
1238 //if ((driverSource == PRIMARY_XML) && driversStringList.contains(driver) == false)
1239 if (groupType == KSTARS_TELESCOPE && driversStringList.contains(driver) == false)
1240 driversStringList.append(driver);
1241
1243
1244 dv->setLabel(label);
1245 dv->setVersion(version);
1246 dv->setExecutable(driver);
1247 dv->setManufacturer(manufacturer);
1248 dv->setSkeletonFile(skel);
1249 dv->setType(groupType);
1250 dv->setDriverSource(driverSource);
1251 dv->setUserPort(port.isEmpty() ? 7624 : port.toInt());
1252 dv->setAuxInfo(vMap);
1253
1254 connect(dv.get(), &DriverInfo::deviceStateChanged, this, [dv, this]()
1255 {
1256 processDeviceStatus(dv);
1257 });
1258
1259 driversList.append(dv);
1260
1261 return true;
1262}
1263
1264bool DriverManager::checkDriverAvailability(const QString &driver)
1265{
1266 QString indiServerDir = Options::indiServer();
1267 if (Options::indiServerIsInternal())
1269 else
1270 indiServerDir = QFileInfo(Options::indiServer()).dir().path();
1271
1272 QFile driverFile(indiServerDir + '/' + driver);
1273
1274 if (driverFile.exists() == false)
1275 return (!QStandardPaths::findExecutable(indiServerDir + '/' + driver).isEmpty());
1276
1277 return true;
1278}
1279
1280void DriverManager::updateCustomDrivers()
1281{
1282 for (const QVariantMap &oneDriver : m_CustomDrivers->customDrivers())
1283 {
1285 dv->setLabel(oneDriver["Label"].toString());
1286 dv->setUniqueLabel(dv->getLabel());
1287 dv->setExecutable(oneDriver["Exec"].toString());
1288 dv->setVersion(oneDriver["Version"].toString());
1289 dv->setManufacturer(oneDriver["Manufacturer"].toString());
1290 dv->setType(DeviceFamilyLabels.key(oneDriver["Family"].toString()));
1291 dv->setDriverSource(CUSTOM_SOURCE);
1292
1293 bool driverIsAvailable = checkDriverAvailability(oneDriver["Exec"].toString());
1294 QVariantMap vMap;
1295 vMap.insert("LOCALLY_AVAILABLE", driverIsAvailable);
1296 dv->setAuxInfo(vMap);
1297
1298 driversList.append(dv);
1299 }
1300}
1301
1302// JM 2018-07-23: Disabling the old custom drivers method
1303#if 0
1304void DriverManager::updateCustomDrivers()
1305{
1306 QString label;
1307 QString driver;
1309 QString name;
1310 QTreeWidgetItem *group = nullptr;
1311 QTreeWidgetItem *widgetDev = nullptr;
1312 QVariantMap vMap;
1314
1315 // Find if the group already exists
1316 QList<QTreeWidgetItem *> treeList = ui->localTreeWidget->findItems("Telescopes", Qt::MatchExactly);
1317 if (!treeList.isEmpty())
1318 group = treeList[0];
1319 else
1320 return;
1321
1322 KStarsData::Instance()->logObject()->readAll();
1323
1324 // Find custom telescope to ADD/UPDATE
1325 foreach (OAL::Scope *s, *(KStarsData::Instance()->logObject()->scopeList()))
1326 {
1327 name = label = s->name();
1328
1329 if (s->driver() == i18n("None"))
1330 continue;
1331
1332 // If driver already exists, just update values
1333 if ((drv = findDriverByLabel(label)))
1334 {
1335 if (s->aperture() > 0 && s->focalLength() > 0)
1336 {
1337 vMap.insert("TELESCOPE_APERTURE", s->aperture());
1338 vMap.insert("TELESCOPE_FOCAL_LENGTH", s->focalLength());
1339 drv->setAuxInfo(vMap);
1340 }
1341
1342 drv->setExecutable(s->driver());
1343
1344 continue;
1345 }
1346
1347 driver = s->driver();
1348 version = QString("1.0");
1349
1350 QTreeWidgetItem *device = new QTreeWidgetItem(group);
1351 device->setText(LOCAL_NAME_COLUMN, QString(label));
1352 device->setIcon(LOCAL_STATUS_COLUMN, ui->stopPix);
1353 device->setText(LOCAL_VERSION_COLUMN, QString(version));
1354
1356
1357 dv->setLabel(label);
1358 dv->setExecutable(driver);
1359 dv->setVersion(version);
1360 dv->setType(KSTARS_TELESCOPE);
1361 dv->setDriverSource(EM_XML);
1362
1363 if (s->aperture() > 0 && s->focalLength() > 0)
1364 {
1365 vMap.insert("TELESCOPE_APERTURE", s->aperture());
1366 vMap.insert("TELESCOPE_FOCAL_LENGTH", s->focalLength());
1367 dv->setAuxInfo(vMap);
1368 }
1369
1370 connect(dv, SIGNAL(deviceStateChanged(DriverInfo*)), this, SLOT(processDeviceStatus(DriverInfo*)));
1371 driversList.append(dv);
1372 }
1373
1374 // Find custom telescope to REMOVE
1375 foreach (QSharedPointer<DriverInfo>dev, driversList)
1376 {
1377 // If it's from primary xml file or it is in a running state, continue.
1378 if (dev->getDriverSource() != EM_XML || dev->getClientState())
1379 continue;
1380
1381 if (KStarsData::Instance()->logObject()->findScopeByName(dev->getName()))
1382 continue;
1383
1384 // Find if the group already exists
1386 ui->localTreeWidget->findItems(dev->getLabel(), Qt::MatchExactly | Qt::MatchRecursive);
1387 if (!devList.isEmpty())
1388 {
1389 widgetDev = devList[0];
1390 group->removeChild(widgetDev);
1391 }
1392 else
1393 return;
1394
1395 driversList.removeOne(dev);
1396 delete (dev);
1397 }
1398}
1399#endif
1400
1401void DriverManager::addINDIHost()
1402{
1404 Ui::INDIHostConf hostConf;
1405 hostConf.setupUi(&hostConfDialog);
1406 hostConfDialog.setWindowTitle(i18nc("@title:window", "Add Host"));
1407 bool portOk = false;
1408
1409 if (hostConfDialog.exec() == QDialog::Accepted)
1410 {
1412
1413 hostConf.portnumber->text().toInt(&portOk);
1414
1415 if (portOk == false)
1416 {
1417 KSNotification::error(i18n("Error: the port number is invalid."));
1418 return;
1419 }
1420
1421 hostItem->setHostParameters(hostConf.hostname->text(),
1422 hostConf.portnumber->text().toInt());
1423
1424 //search for duplicates
1425 //for (uint i=0; i < ksw->data()->INDIHostsList.count(); i++)
1426 foreach (QSharedPointer<DriverInfo>host, driversList)
1427 if (hostItem->getName() == host->getName() &&
1428 hostItem->getPort() == host->getPort())
1429 {
1430 KSNotification::error(i18n("Host: %1 Port: %2 already exists.",
1431 hostItem->getName(), hostItem->getPort()));
1432 return;
1433 }
1434
1435 hostItem->setDriverSource(HOST_SOURCE);
1436
1437 connect(hostItem.get(), &DriverInfo::deviceStateChanged, this, [hostItem, this]()
1438 {
1439 processDeviceStatus(hostItem);
1440 });
1441
1442 driversList.append(hostItem);
1443
1444 QTreeWidgetItem *item = new QTreeWidgetItem(ui->clientTreeWidget);
1445 item->setIcon(HOST_STATUS_COLUMN, ui->disconnected);
1446 item->setText(HOST_NAME_COLUMN, hostConf.nameIN->text());
1447 item->setText(HOST_PORT_COLUMN, hostConf.portnumber->text());
1448 }
1449
1450 saveHosts();
1451}
1452
1453void DriverManager::modifyINDIHost()
1454{
1456 Ui::INDIHostConf hostConf;
1457 hostConf.setupUi(&hostConfDialog);
1458 hostConfDialog.setWindowTitle(i18nc("@title:window", "Modify Host"));
1459
1460 QTreeWidgetItem *currentItem = ui->clientTreeWidget->currentItem();
1461
1462 if (currentItem == nullptr)
1463 return;
1464
1465 for (auto &host : driversList)
1466 {
1467 if (currentItem->text(HOST_NAME_COLUMN) == host->getName() &&
1468 currentItem->text(HOST_PORT_COLUMN).toInt() == host->getPort())
1469 {
1470 hostConf.nameIN->setText(host->getName());
1471 hostConf.hostname->setText(host->getHost());
1472 hostConf.portnumber->setText(QString::number(host->getPort()));
1473
1474 if (hostConfDialog.exec() == QDialog::Accepted)
1475 {
1476 host->setName(hostConf.nameIN->text());
1477 host->setHostParameters(hostConf.hostname->text(),
1478 hostConf.portnumber->text().toInt());
1479
1480 currentItem->setText(HOST_NAME_COLUMN, hostConf.nameIN->text());
1481 currentItem->setText(HOST_PORT_COLUMN, hostConf.portnumber->text());
1482
1483 saveHosts();
1484 return;
1485 }
1486 }
1487 }
1488}
1489
1490void DriverManager::removeINDIHost()
1491{
1492 if (ui->clientTreeWidget->currentItem() == nullptr)
1493 return;
1494
1495 foreach (QSharedPointer<DriverInfo>host, driversList)
1496 if (ui->clientTreeWidget->currentItem()->text(HOST_NAME_COLUMN) ==
1497 host->getName() &&
1498 ui->clientTreeWidget->currentItem()->text(HOST_PORT_COLUMN).toInt() ==
1499 host->getPort())
1500 {
1501 if (host->getClientState())
1502 {
1503 KSNotification::error(
1504 i18n("You need to disconnect the client before removing it."));
1505 return;
1506 }
1507
1509 nullptr,
1510 i18n("Are you sure you want to remove the %1 client?",
1511 ui->clientTreeWidget->currentItem()->text(HOST_NAME_COLUMN)),
1512 i18n("Delete Confirmation"),
1514 return;
1515
1516 driversList.removeOne(host);
1517 delete (ui->clientTreeWidget->currentItem());
1518 break;
1519 }
1520
1521 saveHosts();
1522}
1523
1524void DriverManager::saveHosts()
1525{
1526 QFile file;
1528
1529 //determine filename in local user KDE directory tree.
1530 file.setFileName(QDir(KSPaths::writableLocation(QStandardPaths::AppLocalDataLocation))
1531 .filePath("indihosts.xml"));
1532
1533 if (!file.open(QIODevice::WriteOnly))
1534 {
1535 KSNotification::sorry(i18n("Unable to write to file 'indihosts.xml'\nAny changes "
1536 "to INDI hosts configurations will not be saved."),
1537 i18n("Could Not Open File"));
1538 return;
1539 }
1540
1541 QTextStream outstream(&file);
1542
1543 //for (uint i= 0; i < ksw->data()->INDIHostsList.count(); i++)
1544 foreach (QSharedPointer<DriverInfo>host, driversList)
1545 {
1546 if (host->getDriverSource() != HOST_SOURCE)
1547 continue;
1548
1549 hostData = "<INDIHost name='";
1550 hostData += host->getName();
1551 hostData += "' hostname='";
1552 hostData += host->getHost();
1553 hostData += "' port='";
1554 hostData += QString::number(host->getPort());
1555 hostData += "' />\n";
1556
1558 }
1559
1560 file.close();
1561}
1562
1563QSharedPointer<DriverInfo> DriverManager::findDriverByName(const QString &name)
1564{
1565 auto driver = std::find_if(driversList.begin(), driversList.end(), [name](auto & oneDriver)
1566 {
1567 return oneDriver->getName() == name;
1568 });
1569
1570 if (driver != driversList.end())
1571 return *driver;
1572 else
1574}
1575
1576QSharedPointer<DriverInfo> DriverManager::findDriverByLabel(const QString &label)
1577{
1578 auto driver = std::find_if(driversList.begin(), driversList.end(), [label](auto & oneDriver)
1579 {
1580 return oneDriver->getLabel() == label;
1581 });
1582
1583 if (driver != driversList.end())
1584 return *driver;
1585 else
1587}
1588
1589QSharedPointer<DriverInfo> DriverManager::findDriverByExec(const QString &exec)
1590{
1591 auto driver = std::find_if(driversList.begin(), driversList.end(), [exec](auto & oneDriver)
1592 {
1593 return oneDriver->getLabel() == exec;
1594 });
1595
1596 if (driver != driversList.end())
1597 return *driver;
1598 else
1600}
1601
1602QString DriverManager::getUniqueDeviceLabel(const QString &label)
1603{
1604 int nset = 0;
1605 QString uniqueLabel = label;
1606
1607 for (auto &cm : clients)
1608 {
1609 auto devices = cm->getDevices();
1610
1611 for (auto &dv : devices)
1612 {
1613 if (label == QString(dv.getDeviceName()))
1614 nset++;
1615 }
1616 }
1617 if (nset > 0)
1618 uniqueLabel = QString("%1 %2").arg(label).arg(nset + 1);
1619
1620 return uniqueLabel;
1621}
1622
1623QJsonArray DriverManager::getDriverList() const
1624{
1626
1627 for (const auto &drv : driversList)
1628 driverArray.append(drv->toJson());
1629
1630 return driverArray;
1631}
1632
1633bool DriverManager::restartDriver(const QSharedPointer<DriverInfo> &driver)
1634{
1635 for (auto &oneServer : servers)
1636 {
1637 if (oneServer->contains(driver))
1638 {
1639 return oneServer->restartDriver(driver);
1640 }
1641 }
1642
1643 return false;
1644}
ClientManager manages connection to INDI server, creation of devices, and receiving/sending propertie...
void disconnectAll()
disconnectAll Disconnect from server and disconnect all BLOB Managers.
void removeManagedDriver(const QSharedPointer< DriverInfo > &driver)
removeManagedDriver Remove managed driver from pool of drivers managed by this client manager.
Handles adding new drivers to database.
DriverInfo holds all metadata associated with a particular INDI driver.
Definition driverinfo.h:46
DriverManager is the primary class to handle all operations related to starting and stopping INDI dri...
void getUniqueHosts(const QList< QSharedPointer< DriverInfo > > &dList, QList< QList< QSharedPointer< DriverInfo > > > &uHosts)
getUniqueHosts Given a list of DriverInfos, extract all the host:port information from all the driver...
Collection of INDI DBus functions.
Definition indidbus.h:19
static void beep(const QString &reason=QString())
static KStars * Instance()
Definition kstars.h:123
Information on telescope used in observation.
Definition scope.h:18
ServerManager is responsible for starting and shutting local INDI servers.
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QString i18n(const char *text, const TYPE &arg...)
char * toString(const EngineQuery &query)
KDB_EXPORT KDbVersionInfo version()
KIOCORE_EXPORT QString number(KIO::filesize_t size)
ButtonCode warningContinueCancel(QWidget *parent, const QString &text, const QString &title=QString(), const KGuiItem &buttonContinue=KStandardGuiItem::cont(), const KGuiItem &buttonCancel=KStandardGuiItem::cancel(), const QString &dontAskAgainName=QString(), Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
KGuiItem stop()
KGuiItem del()
QString label(StandardShortcut id)
QString name(StandardShortcut id)
NETWORKMANAGERQT_EXPORT QString hostname()
void clicked(bool checked)
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
const char * constData() const const
QString applicationDirPath()
virtual int exec()
QString path() const const
virtual QString fileName() const const override
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
void setFileName(const QString &name)
virtual void close() override
QDir dir() const const
Int toInt() const const
QIcon fromTheme(const QString &name)
bool getChar(char *c)
void append(QList< T > &&value)
iterator begin()
iterator end()
bool isEmpty() const const
bool removeOne(const AT &t)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
QObject * sender() const const
QString findExecutable(const QString &executableName, const QStringList &paths)
QString locate(StandardLocation type, const QString &fileName, LocateOptions options)
QString arg(Args &&... args) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
int toInt(bool *ok, int base) const const
QByteArray toLatin1() const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
UniqueConnection
ItemIsSelectable
MatchExactly
QFuture< T > run(Function function,...)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void expanded(const QModelIndex &index)
void itemClicked(QTreeWidgetItem *item, int column)
void itemDoubleClicked(QTreeWidgetItem *item, int column)
void removeChild(QTreeWidgetItem *child)
void setFlags(Qt::ItemFlags flags)
void setIcon(int column, const QIcon &icon)
void setText(int column, const QString &text)
QString text(int column) const const
bool close()
void setEnabled(bool)
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.