/** * @RDE_HEADER@ * HMI Plugin for Observer Controller - BaseDownloader Dialog * $Id$ * $HeadURL$ * $Author$ * Created by Patric Karwat, SLSE, 2018-03-17 */ #include "obd_base_downloader.h" #include "ui_obd_base_downloader.h" #include "obd_base_downloader_pdf_selector.h" #include #include #include #include #include #include #include #include namespace OcBaseDownload { BaseDownloader::BaseDownloader(const QString &menuGroup, LtsSession::LtsSession *session, QWidget *parent) : LtsWidgets::LtsDialog(parent, LtsWidgets::ButtonCombination::SeamlessDialog) , m_menuGroup(menuGroup) , m_errorMsg(QString()) , m_model(new ExModel(this)) , m_session(session) , m_messageDlg(nullptr) , m_state(ConnectionState::Start) , m_socket(new QWebSocket(QString(), QWebSocketProtocol::Version13, this)) , m_timer(new QTimer(this)) , m_ftcTimer(new QTimer(this)) , m_exmDtc(nullptr) , m_requestHelper(new LtsUtils::RequestHelper(this)) , m_ui(new Ui::BaseDownloader) , m_logger(getLogger("BaseDownloaderDialog")) { m_ui->setupUi(this); m_ui->leStatus->setText(tr("Not Connected")); #ifndef LTS_DEBUG //hide server things m_ui->leServer->setVisible(false); m_ui->lblServer->setVisible(false); m_ui->spPort->setVisible(false); #endif setUnchangeable(true); m_timer->setSingleShot(true); m_timer->setInterval(5000); connect(m_timer, &QTimer::timeout, this, &BaseDownloader::onTimerTimeout); m_ftcTimer->setInterval(5*60*1000); connect(m_ftcTimer, &QTimer::timeout, this, &BaseDownloader::onFtcTimerTimeout); connect(m_ui->pbDownload, &QPushButton::clicked, this, &BaseDownloader::startBaseDownload); connect(m_ui->tvExercises, &LtsDataView::LtsDataView::selectionChanged, this, &BaseDownloader::selectionChanged); connect(m_ui->pbConnect, &QPushButton::clicked, this, &BaseDownloader::downloadExercises); //connect(m_ui->leServer, &QLineEdit::editingFinished , this, &BaseDownloader::downloadExercises); connect(m_ui->leServer, &QLineEdit::textChanged, this, [this] { m_ui->pbConnect->setEnabled(!m_ui->leServer->text().isEmpty()); }); connect(m_socket, &QWebSocket::stateChanged, this, &BaseDownloader::onNewSocketState); connect(m_socket, &QWebSocket::textMessageReceived, this, &BaseDownloader::onNewTextMessageFromSocket); } // end of ctor() BaseDownloader::~BaseDownloader() { m_socket->disconnect(this); delete m_ui; delete m_messageDlg; } bool BaseDownloader::init() { if (!m_session->getFtc(m_ftc)) return false; if (!m_session->getDtc(m_exmDtc)) return false; if (strcmp(PROJECTBUILD, "guez") == 0) m_ui->pbPdfDownload->hide(); m_proxyModel = new ExProxyModel(this); m_proxyModel->setSourceModel(m_model); m_ui->tvExercises->setModel(m_proxyModel); #ifndef LTS_DEBUG m_ui->tvExercises->setColumnHidden(ExModel::Id, true); #endif m_ui->leServer->setText(NGL::Connections::hostName(NGL::Connections::eConnection::SCM_WEBSOCKET)); m_ui->spPort->setValue(NGL::Connections::port(NGL::Connections::eConnection::SCM_WEBSOCKET)); selectionChanged(); m_messageDlg = new BaseDownloaderMessage(this); connect(m_messageDlg, &BaseDownloaderMessage::finished, this, [this] { if (m_ui) { m_ui->pbDownload->setEnabled(true); m_ui->pbPdfDownload->setEnabled(true); } }); connect(m_ui->pbPdfDownload, &QPushButton::clicked, this, &BaseDownloader::onPdfDownloadClicked); connect(m_ui->pbOcPdfDownload, &QPushButton::clicked, this, &BaseDownloader::onOcPdfDownloadClicked); m_ui->pbOcPdfDownload->hide(); return true; } void BaseDownloader::onStartBaseDownloadReply(const BaseDownloadReply &replyObject) { DEBUG_LOG(m_logger) << "NEW STATE REPLY: " << replyObject.currentStep() << " \n" << replyObject.progress(); switch (replyObject.replyState().underlying()) { case Core::FtReplyState::InProgress: { //restart Timer m_ftcTimer->start(); m_messageDlg->setText(tr("Download in Progress
%1").arg(QCoreApplication::translate("dds", replyObject.currentStep().c_str()))); m_messageDlg->setProgress(replyObject.progress()); break; } case Core::FtReplyState::Completed: { m_ftcTimer->stop(); m_messageDlg->setText(tr("Download Complete")); m_messageDlg->setCloseable(true); m_messageDlg->setProgress(100); m_ui->pbDownload->setEnabled(true); m_ui->pbPdfDownload->setEnabled(true); break; } case Core::FtReplyState::NotStarted: break; case Core::FtReplyState::Error: { m_ftcTimer->stop(); m_messageDlg->setText(tr("Error Downloading Base Data for Exercise %1
Error: %2").arg(m_exerciseId).arg(QString::fromStdString(replyObject.errorString()))); m_messageDlg->setCloseable(true); m_ui->pbDownload->setEnabled(true); m_ui->pbPdfDownload->setEnabled(true); break; } } } void BaseDownloader::onStartPdfDownloadReply(const PdfDownloadReply &reply) { m_messageDlg->setText(QString::fromStdString(reply.currentStep()) + QStringLiteral(" ") + QString::number(reply.replyState().underlying())); switch (reply.replyState().underlying()) { case Core::FtReplyState::InProgress: //restart Timer m_ftcTimer->start(); m_messageDlg->setText(tr("Download in Progress
%1").arg(QCoreApplication::translate("dds", reply.currentStep().c_str()))); m_messageDlg->setProgress(reply.progress()); break; case Core::FtReplyState::Completed: { m_ftcTimer->stop(); m_messageDlg->setText(tr("Download Complete")); m_messageDlg->setCloseable(true); m_messageDlg->setProgress(100); m_ui->pbDownload->setEnabled(true); m_ui->pbPdfDownload->setEnabled(true); break; } case Core::FtReplyState::NotStarted: break; case Core::FtReplyState::Error: m_ftcTimer->stop(); m_messageDlg->setText(tr("Error Downloading PDF data")); m_messageDlg->setCloseable(true); m_ui->pbDownload->setEnabled(true); m_ui->pbPdfDownload->setEnabled(true); break; } } void BaseDownloader::startBaseDownload() { auto ret = LtsWidgets::LtsMessageDialog::showMessage(this, tr("Currently downloaded exercise will be deleted. This may take some time."), windowTitle(), LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Ok | LtsWidgets::Button::Cancel); if (ret != LtsWidgets::Button::Ok) return; m_exerciseId = m_model->getRowData(m_ui->tvExercises->currentIndex().row()).id(); const StartBaseDownloadRequest req(m_exerciseId, LtsSessionData::LtsSessionData::getInstance()->getOperatorId(), m_ui->spPort->value(), m_ui->leServer->text().toStdString(), QDateTime::currentMSecsSinceEpoch()); DEBUG_LOG(m_logger) << "EXERCISE ID: " << m_exerciseId; // NO request helper here, as we got a custom function with a state if (m_ftc->startBaseDownloadRequest(req, this)) { m_ui->pbDownload->setEnabled(false); m_ui->pbPdfDownload->setEnabled(false); m_messageDlg->setText(tr("Start Base Download for Exercise %1").arg(m_exerciseId)); m_messageDlg->show(); } } void BaseDownloader::selectionChanged() { bool isEnabled = m_ui->tvExercises->selectionModel()->selectedRows().size() == 1; m_ui->pbDownload->setEnabled(isEnabled); m_ui->pbPdfDownload->setEnabled(isEnabled); } void BaseDownloader::downloadExercises() { if (m_state != ConnectionState::Start) { m_socket->close(); m_state = ConnectionState::Start; } else m_socket->open(getUrl(m_ui->leServer->text(), m_ui->spPort->value())); } void BaseDownloader::onNewSocketState(QAbstractSocket::SocketState state) { bool enable = true; switch (state) { case QAbstractSocket::UnconnectedState: { m_ui->leStatus->setText(tr("Not Connected: %1").arg(m_errorMsg)); break; } case QAbstractSocket::ConnectingState: { enable = false; m_errorMsg.clear(); m_ui->leStatus->setText(tr("Connecting to: %1").arg(m_ui->leServer->text())); m_ui->pbDownload->setEnabled(false); m_ui->pbPdfDownload->setEnabled(false); break; } case QAbstractSocket::ConnectedState: { enable = false; if (m_state == ConnectionState::Start) { m_state = ConnectionState::ConnectedToExternalServer; m_ui->leStatus->setText(tr("Connected to: %1 (Service Management").arg(m_ui->leServer->text())); sendProcessListRequest(); } else if (m_state == ConnectionState::ConnectedToExternalServer) { m_state = ConnectionState::ConnectedToExerciseManagement; m_ui->leStatus->setText(tr("Connected to: %1 (Exercise Management").arg(m_ui->leServer->text())); sendExerciseListRequest(); } m_ui->pbConnect->setEnabled(true); m_ui->pbConnect->setText(tr("Disconnect")); break; } case QAbstractSocket::ClosingState: { if (m_state == ConnectionState::ConnectedToExerciseManagement) { //go back to start m_state = ConnectionState::Start; } m_model->clear(); m_ui->pbConnect->setEnabled(true); m_ui->pbConnect->setText(tr("Get Exercises")); m_ui->pbDownload->setEnabled(false); m_ui->pbPdfDownload->setEnabled(false); break; } case QAbstractSocket::HostLookupState: { m_errorMsg = QStringLiteral(": ") + tr("Can't connect to: %1").arg(m_ui->leServer->text()); break; } case QAbstractSocket::ListeningState: case QAbstractSocket::BoundState: break; } m_ui->leServer->setEnabled(enable); m_ui->spPort->setEnabled(enable); } void BaseDownloader::onNewTextMessageFromSocket(const QString &message) { // stop timer first then handle message m_timer->stop(); if (m_state == ConnectionState::ConnectedToExternalServer) { DEBUG_LOG(m_logger) << "message from SVC " << message; doConnectToExerciseManagement(message); } else if (m_state == ConnectionState::ConnectedToExerciseManagement) { DEBUG_LOG(m_logger) << "message from EXM " << message; fillExerciseModel(message); } } void BaseDownloader::onTimerTimeout() { QString processName = m_state == ConnectionState::ConnectedToExerciseManagement ? tr("Exercise Management") : tr("Service Management"); m_errorMsg = QStringLiteral(": ") + tr("No Answer from %1 (%2)").arg(m_ui->leServer->text(), processName); m_socket->close(); } void BaseDownloader::onFtcTimerTimeout() { //can't use singleshot m_ftcTimer->stop(); m_messageDlg->setText(tr("Error while downloading data: bailing out.")); m_messageDlg->setCloseable(true); m_ui->pbDownload->setEnabled(true); m_ui->pbPdfDownload->setEnabled(true); } void BaseDownloader::onPdfDownloadClicked() { m_exerciseId = m_model->getRowData(m_ui->tvExercises->currentIndex().row()).id(); if (m_exmDtc->exercise(m_exerciseId).id() != m_exerciseId) { LtsWidgets::LtsMessageDialog::showMessage(this, tr("Make sure to download exercise with ID %1 first.").arg(m_exerciseId), windowTitle(), LtsWidgets::Behaviour::Modal, LtsWidgets::Button::Ok); return; } BaseDownloaderPdfSelector *pdfSel = new BaseDownloaderPdfSelector(this); pdfSel->show(); GetPdfListRequest req(m_exerciseId, m_ui->leServer->text().toStdString(), m_ui->spPort->value()); m_ftc->getPdfListRequest(req, pdfSel); connect(pdfSel, &BaseDownloaderPdfSelector::ok, this, [this, pdfSel]() { if (m_ftc->startPdfDownloadRequest({pdfSel->checkedPdfIds(), m_ui->leServer->text().toStdString(), m_model->getRowData(m_ui->tvExercises->currentIndex().row()).id() }, this)) { m_ui->pbDownload->setEnabled(false); m_ui->pbPdfDownload->setEnabled(false); m_messageDlg->setText(tr("Start PDF download for Exercise %1").arg(m_exerciseId)); m_messageDlg->show(); } pdfSel->close(); }); } void BaseDownloader::onOcPdfDownloadClicked() { LtsUtils::ProjectSettings *ps = LtsUtils::ProjectSettings::getInstance(); const int folderId = ps->value(QStringLiteral("obd"), QStringLiteral("ocPdfDownloadFolderId")).toInt(); if(folderId <= 0) { LtsWidgets::LtsMessageDialog::showMessage(this, tr("Couldn't download pdf files: Folder id invalid!")); return; } const QString matrixOperator = LtsSessionData::LtsSessionData::getInstance()->getOperatorName(); DEBUG_LOG(m_logger)<ocPdfDownloadRequest(req, this); } void BaseDownloader::retranslate() { translate(m_ui, tr("Base Downloader")); } void BaseDownloader::doConnectToExerciseManagement(const QString &message) { m_socket->close(); int exPort = -1; QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8()); if (!doc.isObject()) { WARNING_LOG(m_logger) << "No Valid Object in " << message; return; } if (!doc.object().value(QStringLiteral("data")).isArray()) { WARNING_LOG(m_logger) << "No Data Array in" << message; return; } const QJsonArray exercises = doc.object().value(QStringLiteral("data")).toArray(); QJsonArray services; for (const QJsonValue &exercise : exercises) { const QJsonObject &exe = exercise.toObject(); if (exe.value(QStringLiteral("exerciseId")).toInt(-1) == 0) { services = exe.value(QStringLiteral("services")).toArray(); break; } } for (const QJsonValue &service : qAsConst(services)) { const QJsonObject &obj = service.toObject(); if (obj.value(QStringLiteral("name")).toString() == QStringLiteral("ExerciseManagement")) { const QJsonArray ports = obj.value(QStringLiteral("ports")).toArray(); for (const QJsonValue &port : ports) { if (port.toObject().value(QStringLiteral("typeId")).toInt() == 1) exPort = port.toObject().value(QStringLiteral("number")).toInt(-1); } } } if (exPort > 0) { DEBUG_LOG(m_logger) << "Connect To EXM"; m_socket->open(getUrl(m_ui->leServer->text(), exPort)); } } QUrl BaseDownloader::getUrl(const QString &adress, unsigned short port) const { QString url = QLatin1String("ws://") + adress + QLatin1Char(':') + QString::number(port); DEBUG_LOG(m_logger) << "Connect to: " << url; return QUrl(url); } void BaseDownloader::sendProcessListRequest() { DEBUG_LOG(m_logger) << "send processListRequest message to SVC"; m_timer->start(); m_socket->sendTextMessage(QStringLiteral("{\"type\": \"servicePortsInformationRequest\",\"uuid\": \"7777\"}")); m_ui->leStatus->setText(tr("Wait for Service Data.")); } void BaseDownloader::sendExerciseListRequest() { DEBUG_LOG(m_logger) << "send exerciseListRequest message to EXM"; m_timer->start(); m_ftcTimer->start(); m_socket->sendTextMessage(QStringLiteral("{\"type\": \"exerciseInformationRequest\",\"uuid\": \"7777\"}")); m_ui->leStatus->setText(tr("Wait for Exercise Data.")); } void BaseDownloader::fillExerciseModel(const QString &exerciseList) { //Exercise{"data":[{"description":"","endTime":1523688359000,"id":35,"name":"Test Exercise 35","startTime":1522824359000,"status":1,"timeZone":"Z"},{"description":"","endTime":1523688359000,"id":42,"name":"Test Exercise 42","startTime":1522824359000,"status":2,"timeZone":"Z"}],"type":"exerciseInformation","uuid":"7777"} (OcBaseDownload/Gui/BaseDownloader/obd_ex_model.cpp:45) m_ui->leStatus->setText(tr("Got Data from Exercise Management.")); QJsonDocument doc = QJsonDocument::fromJson(exerciseList.toUtf8()); if (!doc.isObject() || !doc.object().value(QStringLiteral("data")).isArray()) { WARNING_LOG(m_logger) << "No Valid Object in " << exerciseList; m_ui->leStatus->setText(tr("Got Invalid Data from Exercise Management.")); return; } m_model->clear(); const QJsonArray exercises = doc.object().value(QStringLiteral("data")).toArray(); for (const QJsonValue &exercise : exercises) { const QJsonObject &exe = exercise.toObject(); m_model->addExercise(exe); } } } // namespace OcBaseDownload