File indexing completed on 2024-05-12 15:27:48

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