File indexing completed on 2025-10-26 03:35:32

0001 /*
0002     File                 : ImportDialog.cc
0003     Project              : LabPlot
0004     Description          : import file data dialog
0005     --------------------------------------------------------------------
0006     SPDX-FileCopyrightText: 2008-2019 Alexander Semke <alexander.semke@web.de>
0007     SPDX-FileCopyrightText: 2008-2015 Stefan Gerlach <stefan.gerlach@uni.kn>
0008     SPDX-License-Identifier: GPL-2.0-or-later
0009 */
0010 
0011 #include "ImportFileDialog.h"
0012 #include "ImportErrorDialog.h"
0013 #include "ImportFileWidget.h"
0014 #include "backend/core/AspectTreeModel.h"
0015 #include "backend/core/Settings.h"
0016 #include "backend/core/Workbook.h"
0017 #include "backend/datasources/filters/AbstractFileFilter.h"
0018 #include "backend/datasources/filters/filters.h"
0019 #include "backend/matrix/Matrix.h"
0020 #include "backend/spreadsheet/Spreadsheet.h"
0021 #include "commonfrontend/widgets/TreeViewComboBox.h"
0022 #include "kdefrontend/MainWin.h"
0023 
0024 #ifdef HAVE_MQTT
0025 #include "backend/datasources/MQTTClient.h"
0026 #endif
0027 
0028 #include <KLocalizedString>
0029 #include <KWindowConfig>
0030 
0031 #include <QDialogButtonBox>
0032 #include <QDir>
0033 #include <QElapsedTimer>
0034 #include <QInputDialog>
0035 #include <QLocalSocket>
0036 #include <QMenu>
0037 #include <QProgressBar>
0038 #include <QStatusBar>
0039 #include <QTcpSocket>
0040 #include <QUdpSocket>
0041 #include <QWindow>
0042 
0043 /*!
0044     \class ImportFileDialog
0045     \brief Dialog for importing data from a file. Embeds \c ImportFileWidget and provides the standard buttons.
0046 
0047     \ingroup kdefrontend
0048  */
0049 
0050 ImportFileDialog::ImportFileDialog(MainWin* parent, bool liveDataSource, const QString& fileName)
0051     : ImportDialog(parent)
0052     , m_importFileWidget(new ImportFileWidget(this, liveDataSource, fileName)) {
0053     vLayout->addWidget(m_importFileWidget);
0054 
0055     // dialog buttons
0056     auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Reset | QDialogButtonBox::Cancel);
0057     okButton = buttonBox->button(QDialogButtonBox::Ok);
0058     m_optionsButton = buttonBox->button(QDialogButtonBox::Reset); // we highjack the default "Reset" button and use if for showing/hiding the options
0059     okButton->setEnabled(false); // ok is only available if a valid container was selected
0060     vLayout->addWidget(buttonBox);
0061 
0062     // hide the data-source related widgets
0063     if (!liveDataSource)
0064         setModel();
0065 
0066     // Signals/Slots
0067     connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
0068     connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
0069 
0070     if (!liveDataSource)
0071         setWindowTitle(i18nc("@title:window", "Import Data to Spreadsheet or Matrix"));
0072     else
0073         setWindowTitle(i18nc("@title:window", "Add New Live Data Source"));
0074 
0075     setWindowIcon(QIcon::fromTheme(QStringLiteral("document-import-database")));
0076 
0077     // restore saved settings if available
0078     create(); // ensure there's a window created
0079 
0080     QApplication::processEvents(QEventLoop::AllEvents, 0);
0081     m_importFileWidget->loadSettings();
0082 
0083     KConfigGroup conf = Settings::group(QStringLiteral("ImportFileDialog"));
0084     if (conf.exists()) {
0085         m_showOptions = conf.readEntry("ShowOptions", false);
0086 
0087         KWindowConfig::restoreWindowSize(windowHandle(), conf);
0088         resize(windowHandle()->size()); // workaround for QTBUG-40584
0089     } else
0090         resize(QSize(0, 0).expandedTo(minimumSize()));
0091 
0092     m_importFileWidget->showOptions(m_showOptions);
0093     // do the signal-slot connections after all settings were loaded in import file widget and check the OK button after this
0094     connect(m_importFileWidget, &ImportFileWidget::enableImportToMatrix, this, &ImportFileDialog::enableImportToMatrix);
0095     connect(m_importFileWidget, QOverload<>::of(&ImportFileWidget::fileNameChanged), this, &ImportFileDialog::checkOkButton);
0096     connect(m_importFileWidget, QOverload<>::of(&ImportFileWidget::sourceTypeChanged), this, &ImportFileDialog::checkOkButton);
0097     connect(m_importFileWidget, &ImportFileWidget::hostChanged, this, &ImportFileDialog::checkOkButton);
0098     connect(m_importFileWidget, &ImportFileWidget::portChanged, this, &ImportFileDialog::checkOkButton);
0099     connect(m_importFileWidget, &ImportFileWidget::error, this, &ImportFileDialog::showErrorMessage);
0100     connect(this, &ImportDialog::dataContainerChanged, m_importFileWidget, &ImportFileWidget::dataContainerChanged);
0101 #ifdef HAVE_MQTT
0102     connect(m_importFileWidget, &ImportFileWidget::subscriptionsChanged, this, &ImportFileDialog::checkOkButton);
0103     connect(m_importFileWidget, &ImportFileWidget::checkFileType, this, &ImportFileDialog::checkOkButton);
0104 #endif
0105 
0106     m_showOptions ? m_optionsButton->setText(i18n("Hide Options")) : m_optionsButton->setText(i18n("Show Options"));
0107     connect(m_optionsButton, &QPushButton::clicked, this, &ImportFileDialog::toggleOptions);
0108 
0109     ImportFileDialog::checkOkButton();
0110 }
0111 
0112 ImportFileDialog::~ImportFileDialog() {
0113     // save current settings
0114     KConfigGroup conf = Settings::group(QStringLiteral("ImportFileDialog"));
0115     conf.writeEntry("ShowOptions", m_showOptions);
0116     if (cbPosition)
0117         conf.writeEntry("Position", cbPosition->currentIndex());
0118 
0119     KWindowConfig::saveWindowSize(windowHandle(), conf);
0120 }
0121 
0122 LiveDataSource::SourceType ImportFileDialog::sourceType() const {
0123     return m_importFileWidget->currentSourceType();
0124 }
0125 
0126 /*!
0127   triggers data import to the live data source \c source
0128 */
0129 void ImportFileDialog::importToLiveDataSource(LiveDataSource* source, QStatusBar* statusBar) const {
0130     DEBUG(Q_FUNC_INFO);
0131     m_importFileWidget->saveSettings(source);
0132 
0133     // show a progress bar in the status bar
0134     auto* progressBar = new QProgressBar();
0135     progressBar->setRange(0, 100);
0136     connect(source->filter(), &AbstractFileFilter::completed, progressBar, &QProgressBar::setValue);
0137 
0138     statusBar->clearMessage();
0139     statusBar->addWidget(progressBar, 1);
0140     WAIT_CURSOR;
0141 
0142     QElapsedTimer timer;
0143     timer.start();
0144     DEBUG(" Initial read()");
0145     source->read();
0146     statusBar->showMessage(i18n("Live data source created in %1 seconds.", (float)timer.elapsed() / 1000));
0147 
0148     RESET_CURSOR;
0149     statusBar->removeWidget(progressBar);
0150 }
0151 
0152 #ifdef HAVE_MQTT
0153 /*!
0154   triggers data import to the MQTTClient \c client
0155 */
0156 void ImportFileDialog::importToMQTT(MQTTClient* client) const {
0157     m_importFileWidget->saveMQTTSettings(client);
0158     client->read();
0159     client->ready();
0160 }
0161 #endif
0162 
0163 /*!
0164   triggers data import to the currently selected data container
0165 */
0166 void ImportFileDialog::importTo(QStatusBar* statusBar) const {
0167     DEBUG(Q_FUNC_INFO);
0168     QDEBUG("    cbAddTo->currentModelIndex() =" << cbAddTo->currentModelIndex());
0169     AbstractAspect* aspect = static_cast<AbstractAspect*>(cbAddTo->currentModelIndex().internalPointer());
0170     if (!aspect) {
0171         DEBUG(Q_FUNC_INFO << ", ERROR: No aspect available");
0172         DEBUG(" cbAddTo->currentModelIndex().isValid() = " << cbAddTo->currentModelIndex().isValid());
0173         DEBUG(" cbAddTo->currentModelIndex() row/column = " << cbAddTo->currentModelIndex().row() << ' ' << cbAddTo->currentModelIndex().column());
0174         return;
0175     }
0176 
0177     auto filter = m_importFileWidget->currentFileFilter();
0178     if (m_importFileWidget->importValid()) {
0179         DEBUG(Q_FUNC_INFO << ", Import VALID!")
0180         auto errors = filter->lastErrors();
0181         if (errors.isEmpty()) {
0182             // Default message, because not all filters implement lastErrors yet
0183             errors.append(i18n("No data to import."));
0184         }
0185         ImportErrorDialog* d = new ImportErrorDialog(errors);
0186         d->setAttribute(Qt::WA_DeleteOnClose);
0187         d->show();
0188         return;
0189     }
0190 
0191     QString fileName = m_importFileWidget->fileName();
0192     auto mode = AbstractFileFilter::ImportMode(cbPosition->currentIndex());
0193 
0194     // show a progress bar in the status bar
0195     auto* progressBar = new QProgressBar();
0196     progressBar->setRange(0, 100);
0197     connect(filter, &AbstractFileFilter::completed, progressBar, &QProgressBar::setValue);
0198 
0199     statusBar->clearMessage();
0200     statusBar->addWidget(progressBar, 1);
0201 
0202     WAIT_CURSOR;
0203     QApplication::processEvents(QEventLoop::AllEvents, 100);
0204 
0205     QElapsedTimer timer;
0206     timer.start();
0207 
0208     if (aspect->inherits(AspectType::Matrix)) {
0209         DEBUG(Q_FUNC_INFO << ", to Matrix");
0210         auto* matrix = qobject_cast<Matrix*>(aspect);
0211         filter->readDataFromFile(fileName, matrix, mode);
0212     } else if (aspect->inherits(AspectType::Spreadsheet)) {
0213         DEBUG(Q_FUNC_INFO << ", to Spreadsheet");
0214         auto* spreadsheet = qobject_cast<Spreadsheet*>(aspect);
0215         filter->readDataFromFile(fileName, spreadsheet, mode);
0216     } else if (aspect->inherits(AspectType::Workbook)) {
0217         DEBUG(Q_FUNC_INFO << ", to Workbook");
0218         auto* workbook = static_cast<Workbook*>(aspect);
0219         workbook->setUndoAware(false);
0220         auto sheets = workbook->children<AbstractAspect>();
0221 
0222         AbstractFileFilter::FileType fileType = m_importFileWidget->currentFileType();
0223         // types supporting multiple data sets/variables
0224         if (fileType == AbstractFileFilter::FileType::HDF5 || fileType == AbstractFileFilter::FileType::NETCDF || fileType == AbstractFileFilter::FileType::ROOT
0225             || fileType == AbstractFileFilter::FileType::MATIO || fileType == AbstractFileFilter::FileType::XLSX
0226             || fileType == AbstractFileFilter::FileType::Ods || fileType == AbstractFileFilter::FileType::VECTOR_BLF) {
0227             QStringList names;
0228             if (fileType == AbstractFileFilter::FileType::HDF5)
0229                 names = m_importFileWidget->selectedHDF5Names();
0230             else if (fileType == AbstractFileFilter::FileType::VECTOR_BLF)
0231                 names = QStringList({QStringLiteral("TODO")}); // m_importFileWidget->selectedVectorBLFNames();
0232             else if (fileType == AbstractFileFilter::FileType::NETCDF)
0233                 names = m_importFileWidget->selectedNetCDFNames();
0234             else if (fileType == AbstractFileFilter::FileType::ROOT)
0235                 names = m_importFileWidget->selectedROOTNames();
0236             else if (fileType == AbstractFileFilter::FileType::MATIO)
0237                 names = m_importFileWidget->selectedMatioNames();
0238             else if (fileType == AbstractFileFilter::FileType::XLSX)
0239                 names = m_importFileWidget->selectedXLSXRegionNames();
0240             else if (fileType == AbstractFileFilter::FileType::Ods)
0241                 names = m_importFileWidget->selectedOdsSheetNames();
0242 
0243             int nrNames = names.size(), offset = sheets.size();
0244             QDEBUG(Q_FUNC_INFO << ", selected names: " << names)
0245 
0246             // TODO: think about importing multiple sets into one sheet
0247 
0248             int start = 0; // add nrNames sheets (0 to nrNames)
0249 
0250             // in replace mode add only missing sheets (from offset to nrNames)
0251             // and rename the already available sheets
0252             if (mode == AbstractFileFilter::ImportMode::Replace) {
0253                 start = offset;
0254 
0255                 // if there are more available spreadsheets, than needed,
0256                 // delete the unneeded spreadsheets
0257                 if (offset > nrNames) {
0258                     for (int i = nrNames; i < offset; i++)
0259                         sheets.at(i)->remove();
0260                     offset = nrNames;
0261                 }
0262 
0263                 // rename the available sheets
0264                 for (int i = 0; i < offset; ++i) {
0265                     // HDF5 and Ods names contain the whole path, remove it and keep the name only
0266                     QString sheetName = names.at(i);
0267                     if (fileType == AbstractFileFilter::FileType::HDF5 || fileType == AbstractFileFilter::FileType::Ods)
0268                         sheetName = sheetName.split(QLatin1Char('/')).last();
0269 
0270                     auto* sheet = sheets.at(i);
0271                     sheet->setUndoAware(false);
0272                     sheet->setName(sheetName);
0273                     sheet->setUndoAware(true);
0274                 }
0275             }
0276 
0277             // add additional spreadsheets
0278             for (int i = start; i < nrNames; ++i) {
0279                 // HDF5 and Ods names contain the whole path, remove it and keep the name only
0280                 QString sheetName = names.at(i);
0281                 if (fileType == AbstractFileFilter::FileType::HDF5 || fileType == AbstractFileFilter::FileType::Ods)
0282                     sheetName = sheetName.split(QLatin1Char('/')).last();
0283 
0284                 auto* spreadsheet = new Spreadsheet(sheetName);
0285                 if (mode == AbstractFileFilter::ImportMode::Prepend && !sheets.isEmpty())
0286                     workbook->insertChildBefore(spreadsheet, sheets.at(0));
0287                 else
0288                     workbook->addChildFast(spreadsheet);
0289             }
0290 
0291             // start at offset for append, else at 0
0292             if (mode != AbstractFileFilter::ImportMode::Append)
0293                 offset = 0;
0294 
0295             // import every set to a different sheet
0296             sheets = workbook->children<AbstractAspect>();
0297             for (int i = 0; i < nrNames; ++i) {
0298                 if (fileType == AbstractFileFilter::FileType::HDF5)
0299                     static_cast<HDF5Filter*>(filter)->setCurrentDataSetName(names.at(i));
0300                 else if (fileType == AbstractFileFilter::FileType::NETCDF)
0301                     static_cast<NetCDFFilter*>(filter)->setCurrentVarName(names.at(i));
0302                 else if (fileType == AbstractFileFilter::FileType::MATIO)
0303                     static_cast<MatioFilter*>(filter)->setCurrentVarName(names.at(i));
0304                 else if (fileType == AbstractFileFilter::FileType::Ods) // all selected sheets are imported
0305                     static_cast<OdsFilter*>(filter)->setSelectedSheetNames(QStringList() << names.at(i));
0306                 else if (fileType == AbstractFileFilter::FileType::XLSX) {
0307                     const auto& nameSplit = names.at(i).split(QLatin1Char('!'));
0308                     const auto& sheet = nameSplit.at(0);
0309                     const auto& range = nameSplit.at(1);
0310                     static_cast<XLSXFilter*>(filter)->setCurrentSheet(sheet);
0311                     static_cast<XLSXFilter*>(filter)->setCurrentRange(range);
0312                 } else
0313                     static_cast<ROOTFilter*>(filter)->setCurrentObject(names.at(i));
0314 
0315                 int index = i + offset;
0316                 filter->readDataFromFile(fileName, qobject_cast<Spreadsheet*>(sheets.at(index)));
0317             }
0318 
0319             workbook->setUndoAware(true);
0320         } else { // single import file types
0321             // use active spreadsheet/matrix if present, else new spreadsheet
0322             auto* sheet = workbook->currentSpreadsheet();
0323             if (sheet)
0324                 filter->readDataFromFile(fileName, sheet, mode);
0325             else {
0326                 workbook->setUndoAware(true);
0327                 auto* spreadsheet = new Spreadsheet(fileName);
0328                 workbook->addChild(spreadsheet);
0329                 workbook->setUndoAware(false);
0330                 filter->readDataFromFile(fileName, spreadsheet, mode);
0331             }
0332         }
0333     }
0334     statusBar->showMessage(i18n("File %1 imported in %2 seconds.", fileName, (float)timer.elapsed() / 1000));
0335 
0336     const auto errors = filter->lastErrors();
0337     if (!errors.isEmpty()) {
0338         ImportErrorDialog* d = new ImportErrorDialog(errors);
0339         d->setAttribute(Qt::WA_DeleteOnClose);
0340         d->show();
0341     }
0342 
0343     RESET_CURSOR;
0344     statusBar->removeWidget(progressBar);
0345     DEBUG(Q_FUNC_INFO << ", DONE")
0346 }
0347 
0348 void ImportFileDialog::toggleOptions() {
0349     m_importFileWidget->showOptions(!m_showOptions);
0350     m_showOptions = !m_showOptions;
0351     m_showOptions ? m_optionsButton->setText(i18n("Hide Options")) : m_optionsButton->setText(i18n("Show Options"));
0352 
0353     // resize the dialog
0354     layout()->activate();
0355     resize(QSize(this->width(), 0).expandedTo(minimumSize()));
0356 }
0357 
0358 void ImportFileDialog::enableImportToMatrix(const bool enable) {
0359     if (cbAddTo) {
0360         QDEBUG("cbAddTo->currentModelIndex() = " << cbAddTo->currentModelIndex());
0361         AbstractAspect* aspect = static_cast<AbstractAspect*>(cbAddTo->currentModelIndex().internalPointer());
0362         if (!aspect) {
0363             DEBUG("ERROR: no aspect available.");
0364             return;
0365         }
0366 
0367         if (aspect->inherits(AspectType::Matrix)) {
0368             okButton->setEnabled(enable);
0369             if (enable)
0370                 okButton->setToolTip(i18n("Close the dialog and import the data."));
0371             else
0372                 okButton->setToolTip(i18n("Cannot import into a matrix since the data contains non-numerical data."));
0373         }
0374     }
0375 }
0376 
0377 void ImportFileDialog::checkOkButton() {
0378     DEBUG(Q_FUNC_INFO);
0379     if (cbAddTo) { // only check for the target container when no file data source is being added
0380         QDEBUG(" cbAddTo->currentModelIndex() = " << cbAddTo->currentModelIndex());
0381         AbstractAspect* aspect = static_cast<AbstractAspect*>(cbAddTo->currentModelIndex().internalPointer());
0382         if (!aspect) {
0383             okButton->setEnabled(false);
0384             okButton->setToolTip(i18n("Select a data container where the data has to be imported into."));
0385             lPosition->setEnabled(false);
0386             cbPosition->setEnabled(false);
0387             cbAddTo->setFocus(); // set the focus to make the user aware about the fact that a data container needs to be provided
0388             return;
0389         } else {
0390             lPosition->setEnabled(true);
0391             cbPosition->setEnabled(true);
0392         }
0393     }
0394 
0395     QString fileName = ImportFileWidget::absolutePath(m_importFileWidget->fileName());
0396     if (fileName.isEmpty())
0397         return;
0398 
0399     DEBUG(Q_FUNC_INFO << ", Data Source Type: " << ENUM_TO_STRING(LiveDataSource, SourceType, m_importFileWidget->currentSourceType()));
0400     switch (m_importFileWidget->currentSourceType()) {
0401     case LiveDataSource::SourceType::FileOrPipe: {
0402         DEBUG(Q_FUNC_INFO << ", fileName = " << qPrintable(fileName));
0403         const bool enable = QFile::exists(fileName);
0404         okButton->setEnabled(enable);
0405         if (enable) {
0406             okButton->setToolTip(i18n("Close the dialog and import the data."));
0407             showErrorMessage(QString());
0408         } else {
0409             QString msg = i18n("The provided file doesn't exist.");
0410             okButton->setToolTip(msg);
0411 
0412             // suppress the error widget when the dialog is opened the first time.
0413             // show only the error widget if the file was really a non-existing file.
0414             showErrorMessage(msg);
0415         }
0416 
0417         break;
0418     }
0419     case LiveDataSource::SourceType::LocalSocket: {
0420         const bool enable = QFile::exists(fileName);
0421         if (enable) {
0422             QLocalSocket lsocket{this};
0423             DEBUG("CONNECT");
0424             lsocket.connectToServer(fileName, QLocalSocket::ReadOnly);
0425             if (lsocket.waitForConnected()) {
0426                 // this is required for server that send data as soon as connected
0427                 lsocket.waitForReadyRead();
0428 
0429                 DEBUG("DISCONNECT");
0430                 lsocket.disconnectFromServer();
0431                 // read-only socket is disconnected immediately (no waitForDisconnected())
0432                 okButton->setEnabled(true);
0433                 okButton->setToolTip(i18n("Close the dialog and import the data."));
0434                 showErrorMessage(QString());
0435             } else {
0436                 okButton->setEnabled(false);
0437                 QString msg = i18n("Could not connect to the provided local socket. Error: %1.", lsocket.errorString());
0438                 okButton->setToolTip(msg);
0439                 showErrorMessage(msg);
0440             }
0441         } else {
0442             okButton->setEnabled(false);
0443             QString msg = i18n("Could not connect to the provided local socket. The socket does not exist.");
0444             okButton->setToolTip(msg);
0445             showErrorMessage(msg);
0446         }
0447 
0448         break;
0449     }
0450     case LiveDataSource::SourceType::NetworkTCPSocket: {
0451         const bool enable = !m_importFileWidget->host().isEmpty() && !m_importFileWidget->port().isEmpty();
0452         if (enable) {
0453             QTcpSocket socket(this);
0454             socket.connectToHost(m_importFileWidget->host(), m_importFileWidget->port().toUShort(), QTcpSocket::ReadOnly);
0455             if (socket.waitForConnected()) {
0456                 okButton->setEnabled(true);
0457                 okButton->setToolTip(i18n("Close the dialog and import the data."));
0458                 showErrorMessage(QString());
0459                 socket.disconnectFromHost();
0460             } else {
0461                 okButton->setEnabled(false);
0462                 QString msg = i18n("Could not connect to the provided TCP socket. Error: %1.", socket.errorString());
0463                 okButton->setToolTip(msg);
0464                 showErrorMessage(msg);
0465             }
0466         } else {
0467             okButton->setEnabled(false);
0468             QString msg = i18n("Either the host name or the port number is missing.");
0469             okButton->setToolTip(msg);
0470             showErrorMessage(msg);
0471         }
0472         break;
0473     }
0474     case LiveDataSource::SourceType::NetworkUDPSocket: {
0475         const bool enable = !m_importFileWidget->host().isEmpty() && !m_importFileWidget->port().isEmpty();
0476         if (enable) {
0477             QUdpSocket socket(this);
0478             socket.bind(QHostAddress(m_importFileWidget->host()), m_importFileWidget->port().toUShort());
0479             socket.connectToHost(m_importFileWidget->host(), 0, QUdpSocket::ReadOnly);
0480             if (socket.waitForConnected()) {
0481                 okButton->setEnabled(true);
0482                 okButton->setToolTip(i18n("Close the dialog and import the data."));
0483                 showErrorMessage(QString());
0484                 socket.disconnectFromHost();
0485                 // read-only socket is disconnected immediately (no waitForDisconnected())
0486             } else {
0487                 okButton->setEnabled(false);
0488                 QString msg = i18n("Could not connect to the provided UDP socket. Error: %1.", socket.errorString());
0489                 okButton->setToolTip(msg);
0490                 showErrorMessage(msg);
0491             }
0492         } else {
0493             okButton->setEnabled(false);
0494             okButton->setToolTip(i18n("Either the host name or the port number is missing."));
0495         }
0496 
0497         break;
0498     }
0499     case LiveDataSource::SourceType::SerialPort: {
0500 #ifdef HAVE_QTSERIALPORT
0501         const QString sPort = m_importFileWidget->serialPort();
0502 
0503         if (!sPort.isEmpty()) {
0504             QSerialPort serialPort{this};
0505             const int baudRate = m_importFileWidget->baudRate();
0506 
0507             DEBUG(" Port: " << STDSTRING(sPort) << ", Settings: " << baudRate << ',' << serialPort.dataBits() << ',' << serialPort.parity() << ','
0508                             << serialPort.stopBits());
0509             serialPort.setPortName(sPort);
0510             serialPort.setBaudRate(baudRate);
0511 
0512             const bool serialPortOpened = serialPort.open(QIODevice::ReadOnly);
0513             okButton->setEnabled(serialPortOpened);
0514             if (serialPortOpened) {
0515                 okButton->setToolTip(i18n("Close the dialog and import the data."));
0516                 showErrorMessage(QString());
0517                 serialPort.close();
0518             } else {
0519                 QString msg = i18n("Could not connect to the provided serial port.");
0520                 okButton->setToolTip(msg);
0521                 showErrorMessage(msg);
0522             }
0523         } else {
0524             okButton->setEnabled(false);
0525             QString msg = i18n("Serial port number is missing.");
0526             okButton->setToolTip(msg);
0527             showErrorMessage(msg);
0528         }
0529 #endif
0530         break;
0531     }
0532     case LiveDataSource::SourceType::MQTT: {
0533 #ifdef HAVE_MQTT
0534         const bool enable = m_importFileWidget->isMqttValid();
0535         showErrorMessage(QString());
0536         if (enable) {
0537             okButton->setEnabled(true);
0538             okButton->setToolTip(i18n("Close the dialog and import the data."));
0539         } else {
0540             okButton->setEnabled(false);
0541             okButton->setToolTip(i18n("Either there is no connection, or no subscriptions were made, or the file filter is not ASCII."));
0542         }
0543 #endif
0544         break;
0545     }
0546     }
0547 }
0548 
0549 QString ImportFileDialog::selectedObject() const {
0550     return m_importFileWidget->selectedObject();
0551 }