File indexing completed on 2024-04-14 03:42:16

0001 /*
0002     SPDX-FileCopyrightText: 2017 Jasem Mutlaq <mutlaqja@ikarustech.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "profilewizard.h"
0008 
0009 #include <QDesktopServices>
0010 #include <QUrl>
0011 #include <QTcpSocket>
0012 #include <QTimer>
0013 
0014 #include "kstars.h"
0015 #include "auxiliary/kspaths.h"
0016 #include "ksnotification.h"
0017 #include "qMDNS.h"
0018 
0019 ProfileWizard::ProfileWizard() : QDialog(KStars::Instance())
0020 {
0021     setupUi(this);
0022 
0023 #ifdef Q_OS_OSX
0024     setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
0025 #endif
0026 
0027     QPixmap im;
0028     if (im.load(KSPaths::locate(QStandardPaths::AppLocalDataLocation, "wzekos.png")))
0029         wizardPix->setPixmap(im);
0030 
0031     remoteEquipmentSVG->load(QString(":/icons/pi.svg"));
0032 
0033     connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
0034     connect(buttonBox, &QDialogButtonBox::helpRequested, this, []()
0035     {
0036         KStars::Instance()->appHelpActivated();
0037     });
0038     connect(buttonBox, &QDialogButtonBox::clicked, this, [this](QAbstractButton * button)
0039     {
0040         if (button == buttonBox->button(QDialogButtonBox::Reset))
0041             reset();
0042     });
0043 
0044     connect(discoverEkosB, &QPushButton::clicked, this,
0045             []()
0046     {
0047         QDesktopServices::openUrl(QUrl("https://www.indilib.org/about/ekos.html"));
0048     });
0049     connect(videoTutorialsB, &QPushButton::clicked, this,
0050             []()
0051     {
0052         QDesktopServices::openUrl(QUrl("https://www.youtube.com/user/QAstronomy"));
0053     });
0054     connect(INDIInfoB, &QPushButton::clicked, this,
0055             []()
0056     {
0057         QDesktopServices::openUrl(QUrl("https://indilib.org/about/discover-indi.html"));
0058     });
0059 
0060     // Intro actions
0061     connect(introNextB, &QPushButton::clicked, this,
0062             [this]()
0063     {
0064         wizardContainer->setCurrentIndex(EQUIPMENT_LOCATION);
0065     });
0066 
0067     // Equipment Location actions
0068     connect(localEquipmentB, SIGNAL(clicked()), this, SLOT(processLocalEquipment()));
0069     connect(remoteEquipmentB, &QPushButton::clicked, this,
0070             [this]()
0071     {
0072         wizardContainer->setCurrentIndex(REMOTE_EQUIPMENT_SELECTION);
0073     });
0074     equipmentStellarmateB->setIcon(QIcon(":/icons/stellarmate.svg"));
0075     connect(equipmentStellarmateB, &QPushButton::clicked, this, &ProfileWizard::processRemoteEquipmentSelection);
0076 
0077     equipmentAtikbaseB->setIcon(QIcon(":/icons/atikbase.svg"));
0078     connect(equipmentAtikbaseB, &QPushButton::clicked, this, &ProfileWizard::processRemoteEquipmentSelection);
0079 
0080     connect(equipmentOtherB, &QPushButton::clicked, this, &ProfileWizard::processRemoteEquipmentSelection);
0081 
0082     // Remote Equipment Action
0083     connect(remoteEquipmentNextB, SIGNAL(clicked()), this, SLOT(processRemoteEquipment()));
0084 
0085     // StellarMate Equipment Action
0086     connect(stellarMateEquipmentNextB, SIGNAL(clicked()), this, SLOT(processPiEquipment()));
0087 #ifdef Q_OS_WIN
0088     // Auto Detect does not work on Windows yet for some reason.
0089     // Packet is sent correctly, but no replies are received from anything on the LAN outside of PC.
0090     PiAutoDetectB->setEnabled(false);
0091 #else
0092     connect(PiAutoDetectB, SIGNAL(clicked()), this, SLOT(detectStellarMate()));
0093 #endif
0094 
0095     // Local Mac
0096     connect(useExternalINDIB, SIGNAL(clicked()), this, SLOT(processLocalMac()));
0097     connect(useInternalINDIB, SIGNAL(clicked()), this, SLOT(processLocalMac()));
0098 
0099     // Create Profile
0100     connect(createProfileB, SIGNAL(clicked()), this, SLOT(createProfile()));
0101 }
0102 
0103 void ProfileWizard::reset()
0104 {
0105     useInternalServer   = true;
0106     useWebManager       = false;
0107     useJoystick         = false;
0108     useRemoteAstrometry = false;
0109     useSkySafari        = false;
0110     useWatchDog         = false;
0111     useGuiderType       = INTERNAL_GUIDER;
0112 
0113     host.clear();
0114     port = "7624";
0115 
0116     wizardContainer->setCurrentIndex(INTRO);
0117 }
0118 
0119 void ProfileWizard::processLocalEquipment()
0120 {
0121 #if defined(Q_OS_OSX)
0122     wizardContainer->setCurrentIndex(MAC_LOCAL);
0123 #elif defined(Q_OS_WIN)
0124     wizardContainer->setCurrentIndex(WINDOWS_LOCAL);
0125 #else
0126     useInternalServer = true;
0127     useJoystickCheck->setEnabled(true);
0128     useRemoteAstrometryCheck->setEnabled(false);
0129     useWatchDogCheck->setEnabled(false);
0130     useSkySafariCheck->setEnabled(true);
0131     wizardContainer->setCurrentIndex(CREATE_PROFILE);
0132 #endif
0133 }
0134 
0135 void ProfileWizard::processRemoteEquipment()
0136 {
0137     bool portOK = false;
0138     remotePortEdit->text().toInt(&portOK);
0139 
0140     if (portOK == false)
0141     {
0142         KSNotification::error(i18n("Invalid port."));
0143         return;
0144     }
0145 
0146     if (remoteHostEdit->text().isEmpty())
0147     {
0148         KSNotification::error(i18n("Host name cannot be empty."));
0149         return;
0150     }
0151 
0152     useInternalServer = false;
0153 
0154     host = remoteHostEdit->text();
0155     port = remotePortEdit->text();
0156 
0157     if (webManagerNotSureB->isChecked())
0158     {
0159         QTcpSocket socket;
0160         // Should probably make 8624 configurable too?
0161         socket.connectToHost(host, 8624);
0162         useWebManager = socket.waitForConnected();
0163     }
0164     else
0165         useWebManager = webManagerYesR->isChecked();
0166 
0167     useJoystickCheck->setEnabled(true);
0168     useRemoteAstrometryCheck->setEnabled(true);
0169     useWatchDogCheck->setEnabled(true);
0170     useSkySafariCheck->setEnabled(true);
0171 
0172     wizardContainer->setCurrentIndex(CREATE_PROFILE);
0173 }
0174 
0175 void ProfileWizard::processPiEquipment()
0176 {
0177     if (PiHost->text().isEmpty())
0178     {
0179         KSNotification::error(i18n("Host name cannot be empty."));
0180         return;
0181     }
0182 
0183     host = PiHost->text();
0184     port = PiPort->text();
0185 
0186     useInternalServer = false;
0187     useWebManager = true;
0188 
0189     useJoystickCheck->setEnabled(true);
0190     useRemoteAstrometryCheck->setEnabled(true);
0191     useWatchDogCheck->setEnabled(true);
0192     useSkySafariCheck->setEnabled(true);
0193 
0194     wizardContainer->setCurrentIndex(CREATE_PROFILE);
0195 }
0196 
0197 void ProfileWizard::processLocalMac()
0198 {
0199     QPushButton *button = qobject_cast<QPushButton *>(sender());
0200 
0201     if (button == nullptr)
0202         return;
0203 
0204     host = "localhost";
0205     port = "7624";
0206 
0207     useInternalServer = (button == useInternalINDIB);
0208 
0209     useJoystickCheck->setEnabled(false);
0210     useRemoteAstrometryCheck->setEnabled(false);
0211     useWatchDogCheck->setEnabled(false);
0212     useSkySafariCheck->setEnabled(true);
0213 
0214     wizardContainer->setCurrentIndex(CREATE_PROFILE);
0215 }
0216 
0217 void ProfileWizard::createProfile()
0218 {
0219     if (profileNameEdit->text().isEmpty())
0220     {
0221         KSNotification::error(i18n("Profile name cannot be empty."));
0222         return;
0223     }
0224 
0225     useJoystick         = useJoystickCheck->isEnabled() && useJoystickCheck->isChecked();
0226     useWatchDog         = useWatchDogCheck->isEnabled() && useWatchDogCheck->isChecked();
0227     useSkySafari        = useSkySafariCheck->isEnabled() && useSkySafariCheck->isChecked();
0228     useRemoteAstrometry = useRemoteAstrometryCheck->isEnabled() && useRemoteAstrometryCheck->isChecked();
0229     if (useInternalGuiderR->isChecked())
0230         useGuiderType = INTERNAL_GUIDER;
0231     else if (usePHD2R->isChecked())
0232         useGuiderType = PHD2_GUIDER;
0233     else
0234         useGuiderType = LIN_GUIDER;
0235 
0236     profileName = profileNameEdit->text();
0237 
0238     if (useInternalServer)
0239     {
0240         host.clear();
0241         port.clear();
0242     }
0243 
0244     accept();
0245 }
0246 
0247 QStringList ProfileWizard::selectedAuxDrivers()
0248 {
0249     QStringList auxList;
0250 
0251     if (useJoystick)
0252         auxList << "Joystick";
0253     if (useWatchDog)
0254         auxList << "WatchDog";
0255     if (useSkySafari)
0256         auxList << "SkySafari";
0257     if (useRemoteAstrometry)
0258         auxList << "Astrometry";
0259 
0260     return auxList;
0261 }
0262 
0263 int ProfileWizard::selectedExternalGuider()
0264 {
0265     return useGuiderType;
0266 }
0267 
0268 void ProfileWizard::detectStellarMate()
0269 {
0270     stellarMateDetectDialog = new QProgressDialog(this);
0271     stellarMateDetectDialog->setMinimum(0);
0272     stellarMateDetectDialog->setMaximum(0);
0273     stellarMateDetectDialog->setWindowTitle(i18nc("@title:window", "Detecting StellarMate..."));
0274     stellarMateDetectDialog->setLabelText(i18n("Please wait while searching for StellarMate..."));
0275 
0276     stellarMateDetectDialog->show();
0277 
0278     connect(stellarMateDetectDialog.data(), &QProgressDialog::canceled, [&]()
0279     {
0280         qMDNS::getInstance()->disconnect();
0281     });
0282     connect(qMDNS::getInstance(), SIGNAL(hostFound(QHostInfo)), this, SLOT(processHostInfo(QHostInfo)));
0283     QTimer::singleShot(120 * 1000, this, SLOT(detectStellarMateTimeout()));
0284 
0285     qMDNS::getInstance()->lookup("stellarmate");
0286 }
0287 
0288 void ProfileWizard::processHostInfo(QHostInfo info)
0289 {
0290     PiHost->setText(info.hostName());
0291     qMDNS::getInstance()->disconnect();
0292     stellarMateDetectDialog->close();
0293 }
0294 
0295 void ProfileWizard::detectStellarMateTimeout()
0296 {
0297     if (stellarMateDetectDialog->isHidden() == false)
0298     {
0299         KSNotification::error(i18n("Failed to detect any StellarMate gadget. Make sure it is powered and on the same network."));
0300         stellarMateDetectDialog->close();
0301     }
0302 }
0303 
0304 void ProfileWizard::processRemoteEquipmentSelection()
0305 {
0306     QToolButton *button = qobject_cast<QToolButton*>(sender());
0307     if (!button)
0308         wizardContainer->setCurrentIndex(GENERIC_EQUIPMENT);
0309     else if (button == equipmentStellarmateB)
0310     {
0311         PiHost->setText("stellarmate.local");
0312         wizardContainer->setCurrentIndex(PI_EQUIPMENT);
0313     }
0314     else if (button == equipmentAtikbaseB)
0315     {
0316         PiHost->setText("atikbase.local");
0317         wizardContainer->setCurrentIndex(PI_EQUIPMENT);
0318     }
0319 }