9#include "config-kstars.h"
11#include "devicemanager.h"
12#include "indidevice.h"
15#include "kstarsdata.h"
18#include "ui_indihostconf.h"
24#include <KActionCollection>
26#include <QRadioButton>
38#include <QStandardPaths>
41#include <sys/socket.h>
42#include <netinet/in.h>
46#define ERRMSG_SIZE 1024
48DeviceManagerUI::DeviceManagerUI(
QWidget *parent) :
QFrame(parent)
55 localTreeWidget->setSortingEnabled(
false);
56 localTreeWidget->setRootIsDecorated(
true);
58 clientTreeWidget->setSortingEnabled(
false);
72void DeviceManagerUI::makePortEditable(
QTreeWidgetItem *selectedItem,
int column)
75 if (column == INDIDriver::LOCAL_PORT_COLUMN)
78 localTreeWidget->editItem(selectedItem, INDIDriver::LOCAL_PORT_COLUMN);
83 currentPort = Options::serverPortStart().toInt() - 1;
87 ui =
new DeviceManagerUI(
this);
89 setCaption(
xi18n(
"Device Manager"));
90 setButtons(QDialog::Close);
92 foreach (INDIHostsInfo *host, ksw->data()->INDIHostsList)
96 item->
setIcon(HOST_STATUS_COLUMN, ui->disconnected);
97 item->
setText(HOST_NAME_COLUMN, host->name);
98 item->
setText(HOST_PORT_COLUMN, host->portnumber);
104 QObject::connect(ui->modifyB, SIGNAL(clicked()),
this, SLOT(modifyINDIHost()));
105 QObject::connect(ui->removeB, SIGNAL(clicked()),
this, SLOT(removeINDIHost()));
108 QObject::connect(ui->connectHostB, SIGNAL(clicked()),
this, SLOT(activateHostConnection()));
109 QObject::connect(ui->disconnectHostB, SIGNAL(clicked()),
this, SLOT(activateHostDisconnection()));
110 QObject::connect(ui->runServiceB, SIGNAL(clicked()),
this, SLOT(activateRunService()));
111 QObject::connect(ui->stopServiceB, SIGNAL(clicked()),
this, SLOT(activateStopService()));
209void INDIDriver::activateRunService()
211 processLocalTree(IDevice::DEV_START);
214void INDIDriver::activateStopService()
216 processLocalTree(IDevice::DEV_TERMINATE);
219void INDIDriver::activateHostConnection()
221 processRemoteTree(IDevice::DEV_START);
224void INDIDriver::activateHostDisconnection()
226 processRemoteTree(IDevice::DEV_TERMINATE);
229void INDIDriver::updateLocalTab()
231 if (ui->localTreeWidget->currentItem() ==
nullptr)
234 foreach (IDevice *device, devices)
236 if (ui->localTreeWidget->currentItem()->text(LOCAL_NAME_COLUMN) == device->tree_label)
238 ui->runServiceB->
setEnabled(device->state == IDevice::DEV_TERMINATE);
239 ui->stopServiceB->
setEnabled(device->state == IDevice::DEV_START);
241 ui->serverLogText->clear();
242 ui->serverLogText->append(device->getServerBuffer());
249void INDIDriver::updateClientTab()
251 if (ui->clientTreeWidget->currentItem() ==
nullptr)
254 foreach (INDIHostsInfo *host, ksw->
data()->INDIHostsList)
256 if (ui->clientTreeWidget->currentItem()->text(HOST_NAME_COLUMN) == host->name &&
257 ui->clientTreeWidget->currentItem()->text(HOST_PORT_COLUMN) == host->portnumber)
259 ui->connectHostB->
setEnabled(!host->isConnected);
260 ui->disconnectHostB->
setEnabled(host->isConnected);
266void INDIDriver::processLocalTree(IDevice::DeviceStatus dev_request)
269 DeviceManager *deviceManager =
nullptr;
275 foreach (IDevice *device, devices)
278 if (item->
text(LOCAL_NAME_COLUMN) == device->tree_label && device->state != dev_request)
280 processed_devices.
append(device);
285 if (port == 0 && item->
text(LOCAL_PORT_COLUMN).
isEmpty() ==
false)
287 port = item->
text(LOCAL_PORT_COLUMN).
toInt(&portOK);
299 if (processed_devices.
empty())
303 port = getINDIPort(port);
305 if (dev_request == IDevice::DEV_START)
314 deviceManager = ksw->indiMenu()->initDeviceManager(
315 "localhost", ((uint)port), ui->localR->isChecked() ? DeviceManager::M_LOCAL : DeviceManager::M_SERVER);
317 if (deviceManager ==
nullptr)
319 kWarning() <<
"Warning: device manager has not been established properly";
323 deviceManager->appendManagedDevices(processed_devices);
324 deviceManager->startServer();
325 connect(deviceManager, SIGNAL(newServerInput()),
this, SLOT(updateLocalTab()));
328 ksw->indiMenu()->stopDeviceManager(processed_devices);
331void INDIDriver::processRemoteTree(IDevice::DeviceStatus dev_request)
333 DeviceManager *deviceManager =
nullptr;
337 bool toConnect = (dev_request == IDevice::DEV_START);
339 foreach (INDIHostsInfo *host, ksw->
data()->INDIHostsList)
341 if (currentItem->
text(HOST_NAME_COLUMN) == host->name &&
342 currentItem->
text(HOST_PORT_COLUMN) == host->portnumber)
345 if (host->isConnected == toConnect)
351 deviceManager = ksw->indiMenu()->initDeviceManager(host->hostname, host->portnumber.
toUInt(),
352 DeviceManager::M_CLIENT);
354 if (deviceManager ==
nullptr)
357 kWarning() <<
"Warning: device manager has not been established properly";
361 host->deviceManager = deviceManager;
362 deviceManager->connectToServer();
365 ksw->indiMenu()->removeDeviceManager(host->deviceManager);
372void INDIDriver::newTelescopeDiscovered()
377void INDIDriver::newCCDDiscovered()
382void INDIDriver::resizeDeviceColumn()
384 ui->localTreeWidget->resizeColumnToContents(0);
387void INDIDriver::updateMenuActions()
393 INDIMenu *devMenu = ksw->indiMenu();
394 bool activeDevice =
false;
395 bool activeImaging =
false;
396 INDI_P *imgProp =
nullptr;
398 if (devMenu ==
nullptr)
401 if (devMenu->managers.count() > 0)
404 foreach (DeviceManager *dev_managers, devMenu->managers)
406 foreach (
INDI_D *device, dev_managers->indi_dev)
408 imgProp = device->findProp(
"CCD_EXPOSURE");
409 if (imgProp && device->isOn())
411 activeImaging =
true;
419 if (tmpAction !=
nullptr)
423 if (tmpAction !=
nullptr)
427bool INDIDriver::isDeviceRunning(
const QString &deviceLabel)
429 foreach (IDevice *dev, devices)
431 if (deviceLabel == dev->tree_label)
432 return dev->state == IDevice::DEV_START;
437int INDIDriver::getINDIPort(
int customPort)
439 int lastPort = Options::serverPortEnd().toInt();
441 bool success =
false;
445 if (currentPort > lastPort)
446 currentPort = Options::serverPortStart().toInt();
462 for (; currentPort <= lastPort; currentPort++)
474bool INDIDriver::readXMLDrivers()
479 QString driversDir = Options::indiDriversDir();
481 if (Options::indiDriversAreInternal())
485 if (indiDir.
cd(driversDir) ==
false)
488 "path in KStars configuration",
503 if (fileInfo.
fileName() ==
"drivers.xml")
509 if (driverName.
isEmpty() ==
false &&
QFile(driverName).exists())
511 processXMLDriver(driverName);
517 processXMLDriver(driverName);
523void INDIDriver::processXMLDriver(
QString &driverName)
525 QFile file(driverName);
532 char errmsg[ERRMSG_SIZE];
534 LilXML *xmlParser = newLilXML();
535 XMLEle *root =
nullptr;
538 xmlSource = IDevice::PRIMARY_XML;
540 xmlSource = IDevice::THIRD_PARTY_XML;
542 while (file.getChar(&c))
544 root = readXMLEle(xmlParser, c, errmsg);
548 if (!buildDeviceGroup(root, errmsg))
549 prXMLEle(stderr, root, 0);
556 delLilXML(xmlParser);
561 delLilXML(xmlParser);
564bool INDIDriver::buildDeviceGroup(XMLEle *root,
char errmsg[])
570 int groupType = KSTARS_TELESCOPE;
573 if (strlen(tagXMLEle(root)) > 1024)
577 ap = findXMLAtt(root,
"group");
581 snprintf(errmsg, ERRMSG_SIZE,
"Tag %.64s does not have a group attribute", tagXMLEle(root));
585 groupName = valuXMLAtt(ap);
587 if (groupName.
indexOf(
"Telescopes") != -1)
588 groupType = KSTARS_TELESCOPE;
589 else if (groupName.
indexOf(
"CCDs") != -1)
590 groupType = KSTARS_CCD;
591 else if (groupName.
indexOf(
"Filter") != -1)
592 groupType = KSTARS_FILTER;
593 else if (groupName.
indexOf(
"Video") != -1)
594 groupType = KSTARS_VIDEO;
595 else if (groupName.
indexOf(
"Focusers") != -1)
596 groupType = KSTARS_FOCUSER;
597 else if (groupName.
indexOf(
"Domes") != -1)
598 groupType = KSTARS_DOME;
599 else if (groupName.
indexOf(
"Receivers") != -1)
600 groupType = KSTARS_RECEIVERS;
601 else if (groupName.
indexOf(
"GPS") != -1)
602 groupType = KSTARS_GPS;
604#ifndef HAVE_CFITSIO_H
606 if (groupType == KSTARS_CCD || groupType == KSTARS_VIDEO)
620 for (ep = nextXMLEle(root, 1); ep !=
nullptr; ep = nextXMLEle(root, 0))
621 if (!buildDriverElement(ep, group, groupType, errmsg))
627bool INDIDriver::buildDriverElement(XMLEle *root,
QTreeWidgetItem *DGroup,
int groupType,
char errmsg[])
637 double focal_length(-1), aperture(-1);
639 ap = findXMLAtt(root,
"label");
642 snprintf(errmsg, ERRMSG_SIZE,
"Tag %.64s does not have a label attribute", tagXMLEle(root));
646 label = valuXMLAtt(ap);
649 ap = findXMLAtt(root,
"port");
651 port = valuXMLAtt(ap);
654 ap = findXMLAtt(root,
"focal_length");
658 ap = findXMLAtt(root,
"aperture");
662 el = findXMLEle(root,
"driver");
667 driver = pcdataXMLEle(el);
669 ap = findXMLAtt(el,
"name");
672 snprintf(errmsg, ERRMSG_SIZE,
"Tag %.64s does not have a name attribute", tagXMLEle(el));
676 name = valuXMLAtt(ap);
678 el = findXMLEle(root,
"version");
687 device->
setText(LOCAL_NAME_COLUMN, label);
688 device->
setIcon(LOCAL_STATUS_COLUMN, ui->stopPix);
689 device->
setText(LOCAL_VERSION_COLUMN, version);
690 device->
setText(LOCAL_PORT_COLUMN, port);
694 if ((xmlSource == IDevice::PRIMARY_XML) && driversList.
contains(driver) ==
false)
695 driversList.
insert(driver, name);
697 dv =
new IDevice(name, label, driver, version);
698 dv->type = groupType;
699 dv->xmlSource = xmlSource;
701 if (focal_length > 0)
702 dv->focal_length = focal_length;
704 dv->aperture = aperture;
713void INDIDriver::updateCustomDrivers()
721 double focal_length(-1), aperture(-1);
731 foreach (
OAL::Scope *s, *(KStarsData::Instance()->logObject()->scopeList()))
733 label = s->vendor() +
' ' + s->model();
735 if (s->driver() ==
xi18n(
"None") || findDeviceByLabel(label))
739 if (i != driversList.
constEnd() && i.key() == s->driver())
743 focal_length = s->focalLength();
744 aperture = s->aperture();
745 driver = s->driver();
750 device->
setIcon(LOCAL_STATUS_COLUMN, ui->stopPix);
755 dv =
new IDevice(name, label, driver, version);
756 dv->type = KSTARS_TELESCOPE;
757 dv->xmlSource = IDevice::EM_XML;
758 dv->focal_length = focal_length;
759 dv->aperture = aperture;
765 foreach (IDevice *dev, devices)
768 if (dev->xmlSource != IDevice::EM_XML || dev->state == IDevice::DEV_START)
772 if (KStarsData::Instance()->logObject()->findScopeById(dev->id))
780 widgetDev = devList[0];
791void INDIDriver::addINDIHost()
794 Ui::INDIHostConf hostConf;
795 hostConf.
setupUi(&hostConfDialog);
801 INDIHostsInfo *hostItem =
new INDIHostsInfo;
802 hostItem->name = hostConf.nameIN->text();
803 hostItem->hostname = hostConf.hostname->text();
804 hostItem->portnumber = hostConf.portnumber->text();
805 hostItem->isConnected =
false;
806 hostItem->deviceManager =
nullptr;
808 hostItem->portnumber.
toInt(&portOk);
819 foreach (INDIHostsInfo *host, ksw->
data()->INDIHostsList)
820 if (hostItem->name == host->name && hostItem->portnumber == host->portnumber)
827 ksw->
data()->INDIHostsList.append(hostItem);
830 item->
setIcon(HOST_STATUS_COLUMN, ui->disconnected);
831 item->
setText(HOST_NAME_COLUMN, hostConf.nameIN->text());
832 item->
setText(HOST_PORT_COLUMN, hostConf.portnumber->text());
838void INDIDriver::modifyINDIHost()
841 Ui::INDIHostConf hostConf;
842 hostConf.
setupUi(&hostConfDialog);
847 if (currentItem ==
nullptr)
850 foreach (INDIHostsInfo *host, ksw->
data()->INDIHostsList)
852 if (currentItem->
text(HOST_NAME_COLUMN) == host->name &&
853 currentItem->
text(HOST_PORT_COLUMN) == host->portnumber)
855 hostConf.nameIN->setText(host->name);
856 hostConf.hostname->setText(host->hostname);
857 hostConf.portnumber->setText(host->portnumber);
862 host->name = hostConf.nameIN->text();
863 host->hostname = hostConf.hostname->text();
864 host->portnumber = hostConf.portnumber->text();
866 currentItem->
setText(HOST_NAME_COLUMN, hostConf.nameIN->text());
867 currentItem->
setText(HOST_PORT_COLUMN, hostConf.portnumber->text());
878void INDIDriver::removeINDIHost()
880 if (ui->clientTreeWidget->currentItem() ==
nullptr)
883 for (
int i = 0; i < ksw->
data()->INDIHostsList.count(); i++)
885 if (ui->clientTreeWidget->currentItem()->text(HOST_NAME_COLUMN) == ksw->
data()->INDIHostsList[i]->name &&
886 ui->clientTreeWidget->currentItem()->text(HOST_PORT_COLUMN) == ksw->
data()->INDIHostsList[i]->portnumber)
888 if (ksw->
data()->INDIHostsList[i]->isConnected)
895 xi18n(
"Are you sure you want to remove the %1 client?",
896 ui->clientTreeWidget->currentItem()->text(HOST_NAME_COLUMN)),
897 xi18n(
"Delete Confirmation"),
901 delete ksw->
data()->INDIHostsList.takeAt(i);
902 delete (ui->clientTreeWidget->currentItem());
909void INDIDriver::saveHosts()
920 "Unable to write to file 'indihosts.xml'\nAny changes to INDI hosts configurations will not be saved.");
921 KMessageBox::sorry(0, message,
xi18n(
"Could Not Open File"));
928 foreach (INDIHostsInfo *host, ksw->
data()->INDIHostsList)
930 hostData =
"<INDIHost name='";
931 hostData += host->name;
932 hostData +=
"' hostname='";
933 hostData += host->hostname;
934 hostData +=
"' port='";
935 hostData += host->portnumber;
936 hostData +=
"' />\n";
938 outstream << hostData;
944IDevice *INDIDriver::findDeviceByLabel(
const QString &label)
946 foreach (IDevice *dev, devices)
948 if (dev->tree_label == label)
954INDIDriver::~INDIDriver()
964 tree_label = inLabel;
965 unique_label.
clear();
970 xmlSource = PRIMARY_XML;
973 state = IDevice::DEV_TERMINATE;
981 deviceManager =
nullptr;
996 state = IDevice::DEV_TERMINATE;
997 deviceManager =
nullptr;
999 unique_label.
clear();
1002QString IDevice::getServerBuffer()
1004 if (deviceManager !=
nullptr)
1005 return deviceManager->getServerBuffer();
1010#include "indidriver.moc"
INDI_D represents an INDI GUI Device.
INDI_P represents a single INDI property (Switch, Text, Number, Light, or BLOB).
Q_INVOKABLE QAction * action(const QString &name) const
This is the main window for KStars.
KStarsData * data() const
virtual KActionCollection * actionCollection() const
Information on telescope used in observation.
QString xi18n(const char *text, const TYPE &arg...)
KDB_EXPORT KDbVersionInfo version()
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)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
KIOCORE_EXPORT QStringList list(const QString &fileClass)
QString name(StandardAction id)
QString label(StandardShortcut id)
QString applicationDirPath()
bool cd(const QString &dirName)
QFileInfoList entryInfoList(Filters filters, SortFlags sort) const const
QString filePath(const QString &fileName) const const
void setFilter(Filters filters)
void setNameFilters(const QStringList &nameFilters)
bool open(FILE *fh, OpenMode mode, FileHandleFlags handleFlags)
void setFileName(const QString &name)
virtual void close() override
QString fileName() const const
const_iterator constEnd() const const
const_iterator constFind(const Key &key) const const
bool contains(const Key &key) const const
iterator insert(const Key &key, const T &value)
QIcon fromTheme(const QString &name)
void append(QList< T > &&value)
bool isEmpty() const const
bool removeOne(const AT &t)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString arg(Args &&... args) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
double toDouble(bool *ok) const const
int toInt(bool *ok, int base) const const
uint toUInt(bool *ok, int base) const const
QTextStream & endl(QTextStream &stream)
bool listen(const QHostAddress &address, quint16 port)
QFuture< ArgsType< Signal > > connect(Sender *sender, Signal signal)
void setText(int column, const QString &text)
QString text(int column) const const