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)
 
  268    QList<IDevice *> processed_devices;
 
  269    DeviceManager *deviceManager = 
nullptr;
 
  273    foreach (QTreeWidgetItem *item, ui->localTreeWidget->selectedItems())
 
  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;
 
  334    QTreeWidgetItem *currentItem = ui->clientTreeWidget->currentItem();
 
  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()
 
  392    QAction *tmpAction = 
nullptr;
 
  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;
 
  417    tmpAction = ksw->actionCollection()->action(
"capture_sequence");
 
  419    if (tmpAction != 
nullptr)
 
  422    tmpAction = ksw->actionCollection()->action(
"indi_cpl");
 
  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();
 
  448    QTcpServer temp_server;
 
  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",
 
  497    foreach (QFileInfo fileInfo, list)
 
  503        if (fileInfo.
fileName() == 
"drivers.xml")
 
  509            if (driverName.
isEmpty() == 
false && QFile(driverName).exists())
 
  511                processXMLDriver(driverName);
 
  516        driverName = QString(
"%1/%2").
arg(driversDir).
arg(fileInfo.
fileName());
 
  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;
 
  537    if (driverName.
endsWith(QLatin1String(
"drivers.xml")))
 
  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);
 
  555            kDebug() << QString(errmsg) << 
endl;
 
  556            delLilXML(xmlParser);
 
  561    delLilXML(xmlParser);
 
  564bool INDIDriver::buildDeviceGroup(XMLEle *root, 
char errmsg[])
 
  569    QTreeWidgetItem *group;
 
  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)
 
  611    QList<QTreeWidgetItem *> treeList = ui->localTreeWidget->findItems(groupName, 
Qt::MatchExactly);
 
  615        group = 
new QTreeWidgetItem(ui->localTreeWidget, lastGroup);
 
  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");
 
  656        focal_length = QString(valuXMLAtt(ap)).toDouble();
 
  658    ap = findXMLAtt(root, 
"aperture");
 
  660        aperture = QString(valuXMLAtt(ap)).toDouble();
 
  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");
 
  685    QTreeWidgetItem *device = 
new QTreeWidgetItem(DGroup, lastDevice);
 
  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()
 
  720    QTreeWidgetItem *group, *widgetDev;
 
  721    double focal_length(-1), aperture(-1);
 
  724    QList<QTreeWidgetItem *> treeList = ui->localTreeWidget->findItems(
"Telescopes", 
Qt::MatchExactly);
 
  731    foreach (OAL::Scope *s, *(KStarsData::Instance()->logObject()->scopeList()))
 
  733        label = s->vendor() + 
' ' + s->model();
 
  735        if (s->driver() == 
xi18n(
"None") || findDeviceByLabel(label))
 
  738        QHash<QString, QString>::const_iterator i = driversList.constFind(s->driver());
 
  739        if (i != driversList.constEnd() && i.key() == s->driver())
 
  743        focal_length = s->focalLength();
 
  744        aperture     = s->aperture();
 
  745        driver       = s->driver();
 
  748        QTreeWidgetItem *device = 
new QTreeWidgetItem(group, lastDevice);
 
  749        device->
setText(LOCAL_NAME_COLUMN, QString(label));
 
  750        device->
setIcon(LOCAL_STATUS_COLUMN, ui->stopPix);
 
  751        device->
setText(LOCAL_VERSION_COLUMN, QString(version));
 
  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))
 
  776        QList<QTreeWidgetItem *> devList =
 
  780            widgetDev = devList[0];
 
  786        devices.removeOne(dev);
 
  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);
 
  829        QTreeWidgetItem *item = 
new QTreeWidgetItem(ui->clientTreeWidget);
 
  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);
 
  845    QTreeWidgetItem *currentItem = ui->clientTreeWidget->currentItem();
 
  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()
 
  919        QString message = 
xi18n(
 
  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"));
 
  925    QTextStream outstream(&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()
 
  958    while (!devices.isEmpty())
 
  959        delete devices.takeFirst();
 
  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" 
This is the main window for KStars.
 
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()
 
QDialog(QWidget *parent, Qt::WindowFlags f)
 
bool cd(const QString &dirName)
 
QFileInfoList entryInfoList(Filters filters, SortFlags sort) 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
 
QIcon fromTheme(const QString &name)
 
void append(QList< T > &&value)
 
bool isEmpty() const const
 
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
 
QString & append(QChar ch)
 
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
 
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