diff --git a/Tests/kstars_ui/test_ekos_wizard.cpp b/Tests/kstars_ui/test_ekos_wizard.cpp index e9763aa01..37c8c0906 100644 --- a/Tests/kstars_ui/test_ekos_wizard.cpp +++ b/Tests/kstars_ui/test_ekos_wizard.cpp @@ -1,92 +1,92 @@ /* KStars UI tests Copyright (C) 2017 Csaba Kertesz Copyright (C) 2020 Eric Dejouhanet This application is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #include "kstars_ui_tests.h" #if defined(HAVE_INDI) #include "Options.h" #include "test_ekos_wizard.h" #include "test_ekos.h" #include "ekos/manager.h" #include "kswizard.h" #include "auxiliary/kspaths.h" #include "ekos/profilewizard.h" #include TestEkosWizard::TestEkosWizard(QObject *parent) : QObject(parent) { } void TestEkosWizard::init() { } void TestEkosWizard::cleanup() { foreach (QDialog * d, KStars::Instance()->findChildren()) if (d->isVisible()) d->hide(); } void TestEkosWizard::testProfileWizard() { // Update our INDI installation specs Options::setIndiDriversAreInternal(true); // Locate INDI server - this is highly suspicious, but will cover most of the installation cases I suppose if (QFile("/usr/local/bin/indiserver").exists()) Options::setIndiServer("/usr/local/bin/indiserver"); else if (QFile("/usr/bin/indiserver").exists()) - Options::setIndiDriversDir("/usr/bin/indiserver"); + Options::setIndiServer("/usr/bin/indiserver"); QVERIFY(QDir(Options::indiDriversDir()).exists()); // Locate INDI drivers - the XML list of drivers is the generic data path QFile drivers(KSPaths::locate(QStandardPaths::GenericDataLocation, "indidrivers.xml")); if (drivers.exists()) Options::setIndiDriversDir(QFileInfo(drivers).dir().path()); QVERIFY(QDir(Options::indiDriversDir()).exists()); // The Ekos new profile wizard opens when starting Ekos for the first time bool wizardDone = false; std::function closeWizard = [&] { KStars * const k = KStars::Instance(); QVERIFY(k != nullptr); // Wait for the KStars Wizard to appear if(k->findChild () == nullptr) { QTimer::singleShot(500, KStars::Instance(), closeWizard); return; } ProfileWizard * const w = k->findChild (); QVERIFY(w != nullptr); QTRY_VERIFY_WITH_TIMEOUT(w->isVisible(), 1000); // Just dismiss the wizard for now QDialogButtonBox* buttons = w->findChild(); QVERIFY(nullptr != buttons); QTest::mouseClick(buttons->button(QDialogButtonBox::Close), Qt::LeftButton); QTRY_VERIFY_WITH_TIMEOUT(!w->isVisible(), 1000); wizardDone = true; }; QTimer::singleShot(500, Ekos::Manager::Instance(), closeWizard); KTRY_OPEN_EKOS(); KVERIFY_EKOS_IS_OPENED(); QTRY_VERIFY_WITH_TIMEOUT(wizardDone, 1000); KTRY_CLOSE_EKOS(); KVERIFY_EKOS_IS_HIDDEN(); } #endif // HAVE_INDI diff --git a/kstars/indi/guimanager.cpp b/kstars/indi/guimanager.cpp index a572177eb..8ad2424ae 100644 --- a/kstars/indi/guimanager.cpp +++ b/kstars/indi/guimanager.cpp @@ -1,289 +1,289 @@ /* INDI frontend for KStars Copyright (C) 2012 Jasem Mutlaq This application is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #include "guimanager.h" #include "clientmanager.h" #include "deviceinfo.h" #include "indidevice.h" #include "kstars.h" #include "Options.h" #include "fitsviewer/fitsviewer.h" #include "ksnotification.h" #include #include #include #include #include #include #include #include extern const char *libindi_strings_context; GUIManager *GUIManager::_GUIManager = nullptr; GUIManager *GUIManager::Instance() { if (_GUIManager == nullptr) _GUIManager = new GUIManager(Options::independentWindowINDI() ? nullptr : KStars::Instance()); return _GUIManager; } void GUIManager::release() { delete _GUIManager; } GUIManager::GUIManager(QWidget *parent) : QWidget(parent, Qt::Window) { #ifdef Q_OS_OSX if (Options::independentWindowINDI()) setWindowFlags(Qt::Window); else { setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint); connect(QApplication::instance(), SIGNAL(applicationStateChanged(Qt::ApplicationState)), this, SLOT(changeAlwaysOnTop(Qt::ApplicationState))); } #endif mainLayout = new QVBoxLayout(this); mainLayout->setContentsMargins(10, 10, 10, 10); mainLayout->setSpacing(10); mainTabWidget = new QTabWidget(this); mainLayout->addWidget(mainTabWidget); setWindowIcon(QIcon::fromTheme("kstars_indi")); setWindowTitle(i18n("INDI Control Panel")); setAttribute(Qt::WA_ShowModal, false); clearB = new QPushButton(i18n("Clear")); closeB = new QPushButton(i18n("Close")); QHBoxLayout *buttonLayout = new QHBoxLayout; buttonLayout->insertStretch(0); buttonLayout->addWidget(clearB, 0, Qt::AlignRight); buttonLayout->addWidget(closeB, 0, Qt::AlignRight); mainLayout->addLayout(buttonLayout); connect(closeB, SIGNAL(clicked()), this, SLOT(close())); connect(clearB, SIGNAL(clicked()), this, SLOT(clearLog())); resize(Options::iNDIWindowWidth(), Options::iNDIWindowHeight()); } void GUIManager::changeAlwaysOnTop(Qt::ApplicationState state) { if (isVisible()) { if (state == Qt::ApplicationActive) setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint); else setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); show(); } } void GUIManager::closeEvent(QCloseEvent * /*event*/) { KStars *ks = KStars::Instance(); if (ks) { QAction *showINDIPanel = KStars::Instance()->actionCollection()->action("show_control_panel"); showINDIPanel->setChecked(false); } Options::setINDIWindowWidth(width()); Options::setINDIWindowHeight(height()); } void GUIManager::hideEvent(QHideEvent * /*event*/) { KStars *ks = KStars::Instance(); if (ks) { QAction *a = KStars::Instance()->actionCollection()->action("show_control_panel"); a->setChecked(false); } } void GUIManager::showEvent(QShowEvent * /*event*/) { QAction *a = KStars::Instance()->actionCollection()->action("show_control_panel"); a->setEnabled(true); a->setChecked(true); } /********************************************************************* ** Traverse the drivers list, check for updated drivers and take ** appropriate action *********************************************************************/ void GUIManager::updateStatus(bool toggle_behavior) { QAction *showINDIPanel = KStars::Instance()->actionCollection()->action("show_control_panel"); if (guidevices.count() == 0) { KSNotification::error(i18n("No INDI devices currently running. To run devices, please select devices from the " "Device Manager in the devices menu.")); showINDIPanel->setChecked(false); showINDIPanel->setEnabled(false); return; } showINDIPanel->setChecked(true); if (isVisible() && isActiveWindow() && toggle_behavior) { hide(); } else { raise(); activateWindow(); showNormal(); } } INDI_D *GUIManager::findGUIDevice(const QString &deviceName) { for (auto oneGUIDevice : guidevices) { if (oneGUIDevice->name() == deviceName) return oneGUIDevice; } return nullptr; } void GUIManager::clearLog() { INDI_D *dev = findGUIDevice(mainTabWidget->tabText(mainTabWidget->currentIndex()).remove(QChar('&'))); if (dev) dev->clearMessageLog(); } void GUIManager::addClient(ClientManager *cm) { clients.append(cm); Qt::ConnectionType type = Qt::QueuedConnection; #ifdef USE_QT5_INDI type = Qt::DirectConnection; #endif connect(cm, SIGNAL(newINDIDevice(DeviceInfo*)), this, SLOT(buildDevice(DeviceInfo*)), type); connect(cm, &ClientManager::removeINDIDevice, this, &GUIManager::removeDevice); } void GUIManager::removeClient(ClientManager *cm) { clients.removeOne(cm); foreach (INDI_D *gdv, guidevices) { if (gdv->getClientManager() == cm) { for (int i = 0; i < mainTabWidget->count(); i++) { if (mainTabWidget->tabText(i).remove('&') == QString(gdv->getBaseDevice()->getDeviceName())) { mainTabWidget->removeTab(i); break; } } guidevices.removeOne(gdv); gdv->deleteLater(); //break; } } if (clients.size() == 0) hide(); } void GUIManager::removeDevice(const QString &name) { INDI_D *dp = findGUIDevice(name); if (dp == nullptr) return; // Hack to give mainTabWidget sometime to remove its item as these calls are coming from a different thread // the clientmanager thread. Sometimes removeTab() requires sometime to be removed properly and hence the wait. if (mainTabWidget->count() != guidevices.count()) QThread::msleep(100); for (int i = 0; i < mainTabWidget->count(); i++) { if (mainTabWidget->tabText(i).remove('&') == name) { mainTabWidget->removeTab(i); break; } } guidevices.removeOne(dp); delete (dp); if (guidevices.isEmpty()) { QAction *showINDIPanel = KStars::Instance()->actionCollection()->action("show_control_panel"); showINDIPanel->setEnabled(false); } } void GUIManager::buildDevice(DeviceInfo *di) { //qDebug() << "In build Device for device with tree label " << di->getTreeLabel() << endl; ClientManager *cm = di->getDriverInfo()->getClientManager(); if (cm == nullptr) { qCritical() << "ClientManager is null in build device!" << endl; return; } INDI_D *gdm = new INDI_D(di->getBaseDevice(), cm); - connect(cm, SIGNAL(newINDIProperty(INDI::Property*)), gdm, SLOT(buildProperty(INDI::Property*))); - //connect(cm, SIGNAL(removeINDIProperty(INDI::Property*)), gdm, SLOT(removeProperty(INDI::Property*)), type); - connect(cm, &ClientManager::removeINDIProperty, [gdm](const QString & device, const QString & name) - { - if (device == gdm->name()) - QMetaObject::invokeMethod(gdm, "removeProperty", Qt::QueuedConnection, Q_ARG(QString, name)); - }); - - connect(cm, SIGNAL(newINDISwitch(ISwitchVectorProperty*)), gdm, SLOT(updateSwitchGUI(ISwitchVectorProperty*))); - connect(cm, SIGNAL(newINDIText(ITextVectorProperty*)), gdm, SLOT(updateTextGUI(ITextVectorProperty*))); - connect(cm, SIGNAL(newINDINumber(INumberVectorProperty*)), gdm, SLOT(updateNumberGUI(INumberVectorProperty*))); - connect(cm, SIGNAL(newINDILight(ILightVectorProperty*)), gdm, SLOT(updateLightGUI(ILightVectorProperty*))); - connect(cm, SIGNAL(newINDIBLOB(IBLOB*)), gdm, SLOT(updateBLOBGUI(IBLOB*))); - - connect(cm, SIGNAL(newINDIMessage(INDI::BaseDevice*, int)), gdm, SLOT(updateMessageLog(INDI::BaseDevice*, int))); + connect(cm, &ClientManager::newINDIProperty, gdm, &INDI_D::buildProperty); + connect(cm, &ClientManager::removeINDIProperty, gdm, &INDI_D::removeProperty, Qt::QueuedConnection); + // connect(cm, &ClientManager::removeINDIProperty, [gdm](const QString & device, const QString & name) + // { + // if (device == gdm->name()) + // QMetaObject::invokeMethod(gdm, "removeProperty", Qt::QueuedConnection, Q_ARG(QString, name)); + // }); + + connect(cm, &ClientManager::newINDISwitch, gdm, &INDI_D::updateSwitchGUI); + connect(cm, &ClientManager::newINDIText, gdm, &INDI_D::updateTextGUI); + connect(cm, &ClientManager::newINDINumber, gdm, &INDI_D::updateNumberGUI); + connect(cm, &ClientManager::newINDILight, gdm, &INDI_D::updateLightGUI); + connect(cm, &ClientManager::newINDIBLOB, gdm, &INDI_D::updateBLOBGUI); + + connect(cm, &ClientManager::newINDIMessage, gdm, &INDI_D::updateMessageLog); mainTabWidget->addTab(gdm->getDeviceBox(), di->getBaseDevice()->getDeviceName()); guidevices.append(gdm); updateStatus(false); } diff --git a/kstars/indi/indidevice.cpp b/kstars/indi/indidevice.cpp index 44d65d6de..c11e9b6d6 100644 --- a/kstars/indi/indidevice.cpp +++ b/kstars/indi/indidevice.cpp @@ -1,337 +1,341 @@ /* GUI Device Manager Copyright (C) 2012 Jasem Mutlaq (mutlaqja AT ikarustech DOT com) This application is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kstars.h" #include "skymap.h" #include "Options.h" #include "skyobjects/skyobject.h" #include "dialogs/timedialog.h" #include "geolocation.h" #include "indiproperty.h" #include "indidevice.h" #include "indigroup.h" #include "indielement.h" #include const char *libindi_strings_context = "string from libindi, used in the config dialog"; INDI_D::INDI_D(INDI::BaseDevice *in_dv, ClientManager *in_cm) : QDialog() { #ifdef Q_OS_OSX setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint); #endif m_BaseDevice = in_dv; m_ClientManager = in_cm; m_Name = m_BaseDevice->getDeviceName(); deviceVBox = new QSplitter(); deviceVBox->setOrientation(Qt::Vertical); groupContainer = new QTabWidget(); msgST_w = new QTextEdit(); msgST_w->setReadOnly(true); deviceVBox->addWidget(groupContainer); deviceVBox->addWidget(msgST_w); //parent->mainTabWidget->addTab(deviceVBox, label); } bool INDI_D::buildProperty(INDI::Property *prop) { if (!prop->getRegistered()) return false; QString groupName(prop->getGroupName()); if (prop->getDeviceName() != m_Name) return false; INDI_G *pg = getGroup(groupName); if (pg == nullptr) { pg = new INDI_G(this, groupName); groupsList.append(pg); groupContainer->addTab(pg->getScrollArea(), i18nc(libindi_strings_context, groupName.toUtf8())); } return pg->addProperty(prop); } +#if 0 bool INDI_D::removeProperty(INDI::Property *prop) { if (prop == nullptr) return false; QString groupName(prop->getGroupName()); if (strcmp(prop->getDeviceName(), m_BaseDevice->getDeviceName())) { // qDebug() << "Ignoring property " << prop->getName() << " for device " << prop->getgetDeviceName() << " because our device is " // << dv->getDeviceName() << endl; return false; } // qDebug() << "Received new property " << prop->getName() << " for our device " << dv->getDeviceName() << endl; INDI_G *pg = getGroup(groupName); if (pg == nullptr) return false; bool removeResult = pg->removeProperty(prop->getName()); if (pg->size() == 0 && removeResult) { //qDebug() << "Removing tab for group " << pg->getName() << " with an index of " << groupsList.indexOf(pg) << endl; groupContainer->removeTab(groupsList.indexOf(pg)); groupsList.removeOne(pg); delete (pg); } return removeResult; } +#endif -bool INDI_D::removeProperty(const QString &name) +bool INDI_D::removeProperty(const QString &device, const QString &name) { + Q_UNUSED(device) + for (auto &oneGroup : groupsList) { for (auto &oneProperty : oneGroup->getProperties()) { if (name == oneProperty->getName()) { bool rc = oneGroup->removeProperty(name); if (oneGroup->size() == 0) { int index = groupsList.indexOf(oneGroup); groupContainer->removeTab(index); delete groupsList.takeAt(index); } return rc; } } } return false; } bool INDI_D::updateSwitchGUI(ISwitchVectorProperty *svp) { INDI_P *guiProp = nullptr; QString propName(svp->name); if (m_Name != svp->device) return false; for (const auto &pg : groupsList) { if ((guiProp = pg->getProperty(propName)) != nullptr) break; } if (guiProp == nullptr) return false; guiProp->updateStateLED(); if (guiProp->getGUIType() == PG_MENU) guiProp->updateMenuGUI(); else { for (const auto &lp : guiProp->getElements()) lp->syncSwitch(); } return true; } bool INDI_D::updateTextGUI(ITextVectorProperty *tvp) { INDI_P *guiProp = nullptr; QString propName(tvp->name); if (m_Name != tvp->device) return false; for (const auto &pg : groupsList) { if ((guiProp = pg->getProperty(propName)) != nullptr) break; } if (guiProp == nullptr) return false; guiProp->updateStateLED(); for (const auto &lp : guiProp->getElements()) lp->syncText(); return true; } bool INDI_D::updateNumberGUI(INumberVectorProperty *nvp) { INDI_P *guiProp = nullptr; QString propName(nvp->name); if (m_Name != nvp->device) return false; for (const auto &pg : groupsList) { if ((guiProp = pg->getProperty(propName)) != nullptr) break; } if (guiProp == nullptr) return false; guiProp->updateStateLED(); for (const auto &lp : guiProp->getElements()) lp->syncNumber(); return true; } bool INDI_D::updateLightGUI(ILightVectorProperty *lvp) { INDI_P *guiProp = nullptr; QString propName(lvp->name); if (m_Name != lvp->device) return false; for (const auto &pg : groupsList) { if ((guiProp = pg->getProperty(propName)) != nullptr) break; } if (guiProp == nullptr) return false; guiProp->updateStateLED(); for (const auto &lp : guiProp->getElements()) lp->syncLight(); return true; } bool INDI_D::updateBLOBGUI(IBLOB *bp) { INDI_P *guiProp = nullptr; QString propName(bp->bvp->name); if (m_Name != bp->bvp->device) return false; for (const auto &pg : groupsList) { if ((guiProp = pg->getProperty(propName)) != nullptr) break; } if (guiProp == nullptr) return false; guiProp->updateStateLED(); return true; } void INDI_D::updateMessageLog(INDI::BaseDevice *idv, int messageID) { if (idv != m_BaseDevice) return; QString message = QString::fromStdString(m_BaseDevice->messageQueue(messageID)); QString formatted = message; // TODO the colors should be from the color scheme if (message.mid(21, 2) == "[E") formatted = QString("%1").arg(message); else if (message.mid(21, 2) == "[W") formatted = QString("%1").arg(message); else if (message.mid(21, 2) != "[I") { // Debug message qCDebug(KSTARS_INDI) << idv->getDeviceName() << ":" << message.mid(21); return; } if (Options::showINDIMessages()) KStars::Instance()->statusBar()->showMessage(i18nc("INDI message shown in status bar", "%1", message), 0); msgST_w->ensureCursorVisible(); msgST_w->insertHtml(i18nc("Message shown in INDI control panel", "%1", formatted)); msgST_w->insertPlainText("\n"); QTextCursor c = msgST_w->textCursor(); c.movePosition(QTextCursor::Start); msgST_w->setTextCursor(c); qCInfo(KSTARS_INDI) << idv->getDeviceName() << ": " << message.mid(21); } INDI_D::~INDI_D() { while (!groupsList.isEmpty()) delete groupsList.takeFirst(); } INDI_G *INDI_D::getGroup(const QString &groupName) { for (const auto &pg : groupsList) { if (pg->getName() == groupName) return pg; } return nullptr; } void INDI_D::clearMessageLog() { msgST_w->clear(); } diff --git a/kstars/indi/indidevice.h b/kstars/indi/indidevice.h index 5b11aecf0..1acd7aab1 100644 --- a/kstars/indi/indidevice.h +++ b/kstars/indi/indidevice.h @@ -1,98 +1,98 @@ /* GUI Device Manager Copyright (C) 2012 Jasem Mutlaq (mutlaqja@ikarustech.com) This application is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. */ #pragma once #include #include #include #include #include #include #include #include class QTextEdit; class QTabWidget; class QSplitter; class GUIManager; class ClientManager; class INDI_G; /** * @class INDI_D * INDI_D represents an INDI GUI Device. INDI_D is the top level device container. It contains a collection of groups of properties. * Each group is represented as a separate tab within the GUI. * * @author Jasem Mutlaq */ class INDI_D : public QDialog { Q_OBJECT public: INDI_D(INDI::BaseDevice *in_idv, ClientManager *in_cm); ~INDI_D(); QSplitter *getDeviceBox() { return deviceVBox; } ClientManager *getClientManager() { return m_ClientManager; } INDI_G *getGroup(const QString &groupName); INDI::BaseDevice *getBaseDevice() { return m_BaseDevice; } QList getGroups() { return groupsList; } void clearMessageLog(); const QString &name() const { return m_Name; } public slots: bool buildProperty(INDI::Property *prop); - bool removeProperty(INDI::Property *prop); - bool removeProperty(const QString &name); + //bool removeProperty(INDI::Property *prop); + bool removeProperty(const QString &device, const QString &name); bool updateSwitchGUI(ISwitchVectorProperty *svp); bool updateTextGUI(ITextVectorProperty *tvp); bool updateNumberGUI(INumberVectorProperty *nvp); bool updateLightGUI(ILightVectorProperty *lvp); bool updateBLOBGUI(IBLOB *bp); void updateMessageLog(INDI::BaseDevice *idv, int messageID); private: QString m_Name; // GUI QSplitter *deviceVBox { nullptr }; QTabWidget *groupContainer { nullptr }; QTextEdit *msgST_w { nullptr }; // Managers INDI::BaseDevice *m_BaseDevice { nullptr }; ClientManager *m_ClientManager { nullptr }; QList groupsList; }; diff --git a/kstars/indi/indilistener.cpp b/kstars/indi/indilistener.cpp index 085fc2f5a..b52b6fe46 100644 --- a/kstars/indi/indilistener.cpp +++ b/kstars/indi/indilistener.cpp @@ -1,472 +1,472 @@ /* INDI Listener Copyright (C) 2012 Jasem Mutlaq (mutlaqja@ikarustech.com) This application is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Handle INDI Standard properties. */ #include "indilistener.h" #include "clientmanager.h" #include "deviceinfo.h" #include "indicap.h" #include "indiccd.h" #include "indidome.h" #include "indifilter.h" #include "indifocuser.h" #include "indilightbox.h" #include "inditelescope.h" #include "indiweather.h" #include "kstars.h" #include "Options.h" #include "auxiliary/ksnotification.h" #include #include #include #define NINDI_STD 35 /* INDI standard property used across all clients to enable interoperability. */ static const char *indi_std[NINDI_STD] = { "CONNECTION", "DEVICE_PORT", "TIME_UTC", "TIME_LST", "GEOGRAPHIC_COORD", "EQUATORIAL_COORD", "EQUATORIAL_EOD_COORD", "EQUATORIAL_EOD_COORD_REQUEST", "HORIZONTAL_COORD", "TELESCOPE_ABORT_MOTION", "ON_COORD_SET", "SOLAR_SYSTEM", "TELESCOPE_MOTION_NS", "TELESCOPE_MOTION_WE", "TELESCOPE_PARK", "DOME_PARK", "GPS_REFRESH", "WEATHER_STATUS", "CCD_EXPOSURE", "CCD_TEMPERATURE", "CCD_FRAME", "CCD_FRAME_TYPE", "CCD_BINNING", "CCD_INFO", "CCD_VIDEO_STREAM", "RAW_STREAM", "IMAGE_STREAM", "FOCUS_SPEED", "FOCUS_MOTION", "FOCUS_TIMER", "FILTER_SLOT", "WATCHDOG_HEARTBEAT", "CAP_PARK", "FLAT_LIGHT_CONTROL", "FLAT_LIGHT_INTENSITY" }; INDIListener *INDIListener::_INDIListener = nullptr; INDIListener *INDIListener::Instance() { if (_INDIListener == nullptr) { _INDIListener = new INDIListener(KStars::Instance()); connect(_INDIListener, &INDIListener::newTelescope, [&]() { KStars::Instance()->slotSetTelescopeEnabled(true); }); connect(_INDIListener, &INDIListener::newDome, [&]() { KStars::Instance()->slotSetDomeEnabled(true); }); } return _INDIListener; } INDIListener::INDIListener(QObject *parent) : QObject(parent) { } INDIListener::~INDIListener() { qDeleteAll(devices); qDeleteAll(st4Devices); } bool INDIListener::isStandardProperty(const QString &name) { for (auto &item : indi_std) { if (!strcmp(name.toLatin1().constData(), item)) return true; } return false; } ISD::GDInterface *INDIListener::getDevice(const QString &name) { for (auto &oneDevice : devices) { if (oneDevice->getDeviceName() == name) return oneDevice; } return nullptr; } void INDIListener::addClient(ClientManager *cm) { qCDebug(KSTARS_INDI) << "INDIListener: Adding a new client manager to INDI listener.."; clients.append(cm); - connect(cm, SIGNAL(newINDIDevice(DeviceInfo*)), this, SLOT(processDevice(DeviceInfo*)), Qt::BlockingQueuedConnection); - connect(cm, SIGNAL(newINDIProperty(INDI::Property*)), this, SLOT(registerProperty(INDI::Property*))); + connect(cm, &ClientManager::newINDIDevice, this, &INDIListener::processDevice, Qt::BlockingQueuedConnection); + connect(cm, &ClientManager::newINDIProperty, this, &INDIListener::registerProperty); - connect(cm, &ClientManager::removeINDIDevice, this, &INDIListener::removeDevice); - connect(cm, &ClientManager::removeINDIProperty, this, &INDIListener::removeProperty); + connect(cm, &ClientManager::removeINDIDevice, this, &INDIListener::removeDevice, Qt::DirectConnection); + connect(cm, &ClientManager::removeINDIProperty, this, &INDIListener::removeProperty, Qt::DirectConnection); - connect(cm, SIGNAL(newINDISwitch(ISwitchVectorProperty*)), this, SLOT(processSwitch(ISwitchVectorProperty*))); - connect(cm, SIGNAL(newINDIText(ITextVectorProperty*)), this, SLOT(processText(ITextVectorProperty*))); - connect(cm, SIGNAL(newINDINumber(INumberVectorProperty*)), this, SLOT(processNumber(INumberVectorProperty*))); - connect(cm, SIGNAL(newINDILight(ILightVectorProperty*)), this, SLOT(processLight(ILightVectorProperty*))); - connect(cm, SIGNAL(newINDIBLOB(IBLOB*)), this, SLOT(processBLOB(IBLOB*))); + connect(cm, &ClientManager::newINDISwitch, this, &INDIListener::processSwitch); + connect(cm, &ClientManager::newINDIText, this, &INDIListener::processText); + connect(cm, &ClientManager::newINDINumber, this, &INDIListener::processNumber); + connect(cm, &ClientManager::newINDILight, this, &INDIListener::processLight); + connect(cm, &ClientManager::newINDIBLOB, this, &INDIListener::processBLOB); #if INDI_VERSION_MAJOR >= 1 && INDI_VERSION_MINOR >= 5 - connect(cm, SIGNAL(newINDIUniversalMessage(QString)), this, SLOT(processUniversalMessage(QString))); + connect(cm, &ClientManager::newINDIUniversalMessage, this, &INDIListener::processUniversalMessage); #endif } void INDIListener::removeClient(ClientManager *cm) { qCDebug(KSTARS_INDI) << "INDIListener: Removing client manager for server" << cm->getHost() << "@" << cm->getPort(); QList::iterator it = devices.begin(); clients.removeOne(cm); while (it != devices.end()) { DriverInfo *dv = (*it)->getDriverInfo(); bool hostSource = (dv->getDriverSource() == HOST_SOURCE) || (dv->getDriverSource() == GENERATED_SOURCE); if (cm->isDriverManaged(dv)) { // If we have multiple devices per driver, we need to remove them all if (dv->getAuxInfo().value("mdpd", false).toBool() == true) { while (it != devices.end()) { if (dv->getDevice((*it)->getDeviceName()) != nullptr) { it = devices.erase(it); } else break; } } else it = devices.erase(it); cm->removeManagedDriver(dv); cm->disconnect(this); if (hostSource) return; } else ++it; } } void INDIListener::processDevice(DeviceInfo *dv) { qCDebug(KSTARS_INDI) << "INDIListener: New device" << dv->getBaseDevice()->getDeviceName(); ISD::GDInterface *gd = new ISD::GenericDevice(*dv); devices.append(gd); emit newDevice(gd); } //void INDIListener::removeDevice(DeviceInfo *dv) //{ // qCDebug(KSTARS_INDI) << "INDIListener: Removing device" << dv->getBaseDevice()->getDeviceName() << "with unique label " // << dv->getDriverInfo()->getUniqueLabel(); // foreach (ISD::GDInterface *gd, devices) // { // if (gd->getDeviceInfo() == dv) // { // emit deviceRemoved(gd); // devices.removeOne(gd); // delete (gd); // } // } //} void INDIListener::removeDevice(const QString &deviceName) { qCDebug(KSTARS_INDI) << "INDIListener: Removing device" << deviceName; for (ISD::GDInterface *oneDevice : devices) { if (oneDevice->getDeviceName() == deviceName) { emit deviceRemoved(oneDevice); devices.removeOne(oneDevice); delete (oneDevice); break; } } } void INDIListener::registerProperty(INDI::Property *prop) { if (!prop->getRegistered()) return; qCDebug(KSTARS_INDI) << "<" << prop->getDeviceName() << ">: <" << prop->getName() << ">"; for (auto oneDevice : devices) { if (oneDevice->getDeviceName() == prop->getDeviceName()) { if (!strcmp(prop->getName(), "ON_COORD_SET") || !strcmp(prop->getName(), "EQUATORIAL_EOD_COORD") || !strcmp(prop->getName(), "EQUATORIAL_COORD") || !strcmp(prop->getName(), "HORIZONTAL_COORD")) { if (oneDevice->getType() == KSTARS_UNKNOWN) { devices.removeOne(oneDevice); oneDevice = new ISD::Telescope(oneDevice); devices.append(oneDevice); } emit newTelescope(oneDevice); } else if (!strcmp(prop->getName(), "CCD_EXPOSURE")) { //if (gd->getType() != KSTARS_CCD) if (oneDevice->getDriverInterface() & INDI::BaseDevice::CCD_INTERFACE) { devices.removeOne(oneDevice); oneDevice = new ISD::CCD(oneDevice); devices.append(oneDevice); } emit newCCD(oneDevice); } else if (!strcmp(prop->getName(), "FILTER_NAME")) { if (oneDevice->getType() == KSTARS_UNKNOWN) { devices.removeOne(oneDevice); oneDevice = new ISD::Filter(oneDevice); devices.append(oneDevice); } emit newFilter(oneDevice); } else if (!strcmp(prop->getName(), "FOCUS_MOTION")) { if (oneDevice->getType() == KSTARS_UNKNOWN) { devices.removeOne(oneDevice); oneDevice = new ISD::Focuser(oneDevice); devices.append(oneDevice); } emit newFocuser(oneDevice); } else if (!strcmp(prop->getName(), "DOME_SHUTTER") || !strcmp(prop->getName(), "DOME_MOTION")) { if (oneDevice->getType() == KSTARS_UNKNOWN) { devices.removeOne(oneDevice); oneDevice = new ISD::Dome(oneDevice); devices.append(oneDevice); } emit newDome(oneDevice); } else if (!strcmp(prop->getName(), "WEATHER_STATUS")) { if (oneDevice->getType() == KSTARS_UNKNOWN) { devices.removeOne(oneDevice); oneDevice = new ISD::Weather(oneDevice); devices.append(oneDevice); } emit newWeather(oneDevice); } else if (!strcmp(prop->getName(), "CAP_PARK")) { if (oneDevice->getType() == KSTARS_UNKNOWN) { devices.removeOne(oneDevice); oneDevice = new ISD::DustCap(oneDevice); devices.append(oneDevice); } emit newDustCap(oneDevice); } else if (!strcmp(prop->getName(), "FLAT_LIGHT_CONTROL")) { // If light box part of dust cap if (oneDevice->getType() == KSTARS_UNKNOWN) { if (oneDevice->getBaseDevice()->getDriverInterface() & INDI::BaseDevice::DUSTCAP_INTERFACE) { devices.removeOne(oneDevice); oneDevice = new ISD::DustCap(oneDevice); devices.append(oneDevice); emit newDustCap(oneDevice); } // If stand-alone light box else { devices.removeOne(oneDevice); oneDevice = new ISD::LightBox(oneDevice); devices.append(oneDevice); emit newLightBox(oneDevice); } } } if (!strcmp(prop->getName(), "TELESCOPE_TIMED_GUIDE_WE")) { ISD::ST4 *st4Driver = new ISD::ST4(oneDevice->getBaseDevice(), oneDevice->getDriverInfo()->getClientManager()); st4Devices.append(st4Driver); emit newST4(st4Driver); } oneDevice->registerProperty(prop); break; } } } void INDIListener::removeProperty(const QString &device, const QString &name) { for (auto &oneDevice : devices) { if (oneDevice->getDeviceName() == device) { oneDevice->removeProperty(name); return; } } } void INDIListener::processSwitch(ISwitchVectorProperty *svp) { for (auto &oneDevice : devices) { if (oneDevice->getDeviceName() == svp->device) { oneDevice->processSwitch(svp); break; } } } void INDIListener::processNumber(INumberVectorProperty *nvp) { for (auto &oneDevice : devices) { if (oneDevice->getDeviceName() == nvp->device) { oneDevice->processNumber(nvp); break; } } } void INDIListener::processText(ITextVectorProperty *tvp) { for (auto &oneDevice : devices) { if (oneDevice->getDeviceName() == tvp->device) { oneDevice->processText(tvp); break; } } } void INDIListener::processLight(ILightVectorProperty *lvp) { for (auto &oneDevice : devices) { if (oneDevice->getDeviceName() == lvp->device) { oneDevice->processLight(lvp); break; } } } void INDIListener::processBLOB(IBLOB *bp) { for (auto &oneDevice : devices) { if (oneDevice->getDeviceName() == bp->bvp->device) { oneDevice->processBLOB(bp); break; } } } void INDIListener::processMessage(INDI::BaseDevice *dp, int messageID) { for (auto &oneDevice : devices) { if (oneDevice->getDeviceName() == dp->getDeviceName()) { oneDevice->processMessage(messageID); break; } } } void INDIListener::processUniversalMessage(const QString &message) { QString displayMessage = message; // Remove timestamp info as it is not suitable for message box int colonIndex = displayMessage.indexOf(": "); if (colonIndex > 0) displayMessage = displayMessage.mid(colonIndex + 2); // Special case for Alignment since it is not tied to a device if (displayMessage.startsWith("[ALIGNMENT]")) { qCDebug(KSTARS_INDI) << "AlignmentSubSystem:" << displayMessage; return; } if (Options::messageNotificationINDI()) { KNotification::event(QLatin1String("IndiServerMessage"), displayMessage + " (INDI)"); } else { KSNotification::transient(displayMessage, i18n("INDI Server Message")); } }