#include "LogViewGui.hpp" #include "LogViewTelegram.hpp" #include "LogViewXdrParser.hpp" #include "LogViewTelegramDialog.hpp" #include "LogViewOptionDialog.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "LogViewInjectionThread.hpp" #include "LogViewTelegramEdit.hpp" #include "LogViewTetraTelegramsParser.hpp" #include namespace N_LogView { const QLatin1String LogViewGui::WINDOW_GROUP("MainWindow"); const QLatin1String LogViewGui::SIZE("Size"); const QLatin1String LogViewGui::SCREEN("Screen"); const QLatin1String LogViewGui::POS("Pos"); const QLatin1String LogViewGui::SPLITTPOS("SplittPos"); const QLatin1String LogViewGui::TOOLBOXINDEX("ToolBoxIndex"); LogViewGui::LogViewGui(QWidget* a_parent) : QMainWindow(a_parent) , RADIO_BUTTON_ICON_SIZE(16, 16) , m_LogfileSize(0) , m_DoReload(false) , m_EditTelegramController(new TelegramEdit(this)) , m_TailTimer(nullptr) , m_InjectionThread(nullptr) , m_replayTimer(new QTimer(this)) , m_currentReplayRow(-1) , m_logger(getLogger("LogViewGui")) { setWindowIcon(QIcon(QLatin1String(":icons/16x16/rde_16x16.png"))); QSettings settings; settings.beginGroup(WINDOW_GROUP); m_InjectionStatus = new QLabel(this); m_InjectionStatus->setFrameStyle(QFrame::Panel | QFrame::Sunken); statusBar()->addPermanentWidget(m_InjectionStatus); m_ParticipantStatus = new QLabel(this); m_ParticipantStatus->setFrameStyle(QFrame::Panel | QFrame::Sunken); statusBar()->addPermanentWidget(m_ParticipantStatus); m_TelegramStatus = new QLabel(this); m_TelegramStatus->setFrameStyle(QFrame::Panel | QFrame::Sunken); statusBar()->addPermanentWidget(m_TelegramStatus); QToolBar* toolBar = addToolBar(tr("Datei")); toolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon); QString tipText; QAction* action = new QAction(tr("Neue Log-Datei"), this); action->setIcon(QIcon(QLatin1String(":icons/16x16/document-new.png"))); action->setShortcut(tr("Ctrl+N")); tipText = tr("Eine neue Telegram-Log-Datei anzeigen (Ctrl-N)"); action->setStatusTip(tipText); action->setToolTip(tipText); connect(action, &QAction::triggered, this, &LogViewGui::newTelegramFile); toolBar->addAction(action); action = new QAction(tr("Log-Datei hinzu"), this); action->setIcon(QIcon(QLatin1String(":icons/16x16/document-import.png"))); action->setShortcut(tr("Ctrl+O")); tipText = tr("Eine weitere Telegramm-Log-Datei anzeigen (Ctrl-O)"); action->setStatusTip(tipText); action->setToolTip(tipText); connect(action, &QAction::triggered, this, &LogViewGui::loadTelegramFile); toolBar->addAction(action); m_reloadAction = new QAction(tr("&Reload"), this); m_reloadAction->setCheckable(true); m_reloadAction->setChecked(m_DoReload); m_reloadAction->setIcon(QIcon(QLatin1String(":icons/16x16/edit-redo.png"))); m_reloadAction->setShortcut(tr("Ctrl+R")); tipText = tr("Reload des Logfiles ein-/ausschalten (Ctrl-R)"); m_reloadAction->setStatusTip(tipText); m_reloadAction->setToolTip(tipText); connect(m_reloadAction, &QAction::triggered, this, &LogViewGui::reloadOnOff); toolBar->addAction(m_reloadAction); action = new QAction(tr("&Einstellungen"), this); action->setIcon(QIcon(QLatin1String(":icons/16x16/configure.png"))); action->setShortcut(tr("Ctrl+E")); tipText = tr("Verhalten des Programmes einstellen (Ctrl-E)"); action->setStatusTip(tipText); action->setToolTip(tipText); connect(action, &QAction::triggered, this, &LogViewGui::changeSettings); toolBar->addAction(action); toolBar->addSeparator(); action = new QAction(tr("&Beenden"), this); action->setIcon(QIcon(QLatin1String(":icons/16x16/edit-delete.png"))); action->setShortcut(tr("Alt-F4")); tipText = tr("LogView beenden (Alt-F4)"); action->setStatusTip(tipText); action->setToolTip(tipText); connect(action, &QAction::triggered, this, &LogViewGui::close); toolBar->addAction(action); createCentralSelectionWidget(); createTetraSelectionWidget(); createWlsSelectionWidget(); m_ParticipantTableView = new QTableView(this); m_participantProxyModel = new QSortFilterProxyModel(this); m_participantModel = new ParticipantModel(this); m_participantProxyModel->setSourceModel(m_participantModel); m_ParticipantTableView->setModel(m_participantProxyModel); m_ParticipantTableView->setAlternatingRowColors(true); m_ParticipantTableView->setSelectionBehavior(QAbstractItemView::SelectRows); m_ParticipantTableView->setSelectionMode(QAbstractItemView::MultiSelection); m_ParticipantTableView->setSortingEnabled(true); m_ParticipantTableView->setTabKeyNavigation(false); m_ParticipantTableView->verticalHeader()->hide(); m_ParticipantTableView->verticalHeader()->setMinimumSectionSize(QApplication::font().pointSize() * 2.5); m_ParticipantTableView->verticalHeader()->setDefaultSectionSize(QApplication::font().pointSize() * 2.5); m_ParticipantTableView->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch); m_ParticipantTableView->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch); connect(m_ParticipantTableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &LogViewGui::selectedParticipantChanged); QVBoxLayout* participantBox = new QVBoxLayout; participantBox->addWidget(m_ParticipantTableView); m_ParticipantSelectionGroup = new QGroupBox(tr("Teilnehmer-Filter &aktivieren"), this); m_ParticipantSelectionGroup->setCheckable(true); m_ParticipantSelectionGroup->setChecked(false); m_ParticipantSelectionGroup->setLayout(participantBox); connect(m_ParticipantSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::selectedParticipantChanged); m_ToolBox = new QToolBox(this); m_ToolBox->addItem(m_CentralSelectionGroup, QIcon(QLatin1String(":/image/Central.png")), tr("&Zentral-Telegramm-Filter")); m_ToolBox->addItem(m_TetraSelectionGroup, QIcon(QLatin1String(":/image/Tetra.png")), tr("TET&RA-Telegramm-Filter")); m_ToolBox->addItem(m_WlsSelectionGroup, QIcon(QLatin1String(":/image/Wls.png")), tr("&WLS-Telegramm-Filter")); m_ToolBox->addItem(m_ParticipantSelectionGroup, QIcon(QLatin1String(":/image/TNE.png")), tr("Teilnehmer-&Filter")); m_ToolBox->addItem(m_EditTelegramController->tableView(), QIcon(QLatin1String(":icons/16x16/document-edit.png")), tr("&Edit && Sende Telegramme")); m_ToolBox->setCurrentIndex(settings.value(TOOLBOXINDEX).toInt()); m_logTelegramView = new QTableView(this); m_logTelegramView->setAlternatingRowColors(true); m_logTelegramView->setSelectionBehavior(QAbstractItemView::SelectRows); m_logTelegramView->setSelectionMode(QAbstractItemView::ContiguousSelection); m_logTelegramView->verticalHeader()->hide(); m_logTelegramView->verticalHeader()->setMinimumSectionSize(QApplication::font().pointSize() * 2.5); m_logTelegramView->verticalHeader()->setDefaultSectionSize(QApplication::font().pointSize() * 2.5); m_logTelegramView->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); m_logTelegramView->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_logTelegramView, &QTableView::customContextMenuRequested, this, &LogViewGui::customMenuRequested); m_telegramModel = new TelegramModel(m_logTelegramView); m_telegramProxyModel = new TelegramProxyModel(m_logTelegramView); m_telegramProxyModel->setSourceModel(m_telegramModel); m_logTelegramView->setModel(m_telegramProxyModel); connect(m_logTelegramView, &QTableView::doubleClicked, this, &LogViewGui::onLogTelegramViewDoubleClicked); m_logTelegramView->horizontalHeader()->setSortIndicatorShown(true); m_logTelegramView->horizontalHeader()->setSortIndicator(3, Qt::AscendingOrder); m_logTelegramView->setSortingEnabled(true); QVBoxLayout* telegramBox = new QVBoxLayout; telegramBox->addWidget(m_logTelegramView); QGroupBox* telegramGroup = new QGroupBox(tr("&Log-Telegramme"), this); telegramGroup->setLayout(telegramBox); m_Splitter = new QSplitter(Qt::Horizontal, this); m_Splitter->addWidget(m_ToolBox); m_Splitter->addWidget(telegramGroup); const QList splitterSizesAsVariant = settings.value(SPLITTPOS).toList(); QList splitterSizes; splitterSizes.reserve(splitterSizesAsVariant.size()); if (splitterSizesAsVariant.isEmpty()) { splitterSizes << 235 << 1000; } else { for (const QVariant &item : splitterSizesAsVariant) splitterSizes << item.toInt(); } m_Splitter->setSizes(splitterSizes); setCentralWidget(m_Splitter); m_CentralSelectionGroup->setChecked(true); m_ackCentralTelCheckBox->setChecked(true); m_ackCentralTelCheckBox->setChecked(false); m_PosCentralTelCheckBox->setChecked(true); m_PosCentralTelCheckBox->setChecked(false); m_SentCentralTelCheckBox->setChecked(true); m_ReceivedCentralTelCheckBox->setChecked(true); m_TetraSelectionGroup->setChecked(true); m_SentTetraTelCheckBox->setChecked(true); m_ReceivedTetraTelCheckBox->setChecked(true); m_PosTetraTelCheckBox->setChecked(true); m_PosTetraTelCheckBox->setChecked(false); m_FragmentedTetraTelCheckBox->setChecked(true); m_LoginTetraTelCheckBox->setChecked(true); m_RegisterTetraTelCheckBox->setChecked(true); m_ReportTetraTelCheckBox->setChecked(false); m_AirInterfaceLoadTetraTelCheckBox->setChecked(false); m_WlsSelectionGroup->setChecked(true); m_PosWlsTelCheckBox->setChecked(true); m_PosWlsTelCheckBox->setChecked(false); m_SentWlsTelCheckBox->setChecked(true); m_ReceivedWlsTelCheckBox->setChecked(true); QSize size = settings.value(SIZE, sizeHint()).toSize(); resize(size.isNull() ? QSize(1280, 768) : size); move(settings.value(POS, QPoint(0, 0)).toPoint()); settings.endGroup(); connect(m_replayTimer, &QTimer::timeout, this, &LogViewGui::onReplayTimerTimeout); QTimer::singleShot(0, this, &LogViewGui::loadSpecificationFiles); startInjectionThread(); } void LogViewGui::createCentralSelectionWidget() { m_SentCentralTelCheckBox = createRadioButton(tr("&gesendete Telegramme"), QLatin1String(":/image/P2C.png")); m_ReceivedCentralTelCheckBox = createRadioButton(tr("&empfangene Telegramme"), QLatin1String(":/image/C2P.png")); m_PosCentralTelCheckBox = createRadioButton(tr("&Positionsmeldungen"), QLatin1String(":/image/CentralPos.png")); m_ackCentralTelCheckBox = createRadioButton(tr("&Bestaetigungstelegramme"), QLatin1String(":/image/CentralAck.png")); QVBoxLayout* centralFilterBox = new QVBoxLayout; centralFilterBox->addWidget(m_SentCentralTelCheckBox); centralFilterBox->addWidget(m_ReceivedCentralTelCheckBox); centralFilterBox->addWidget(m_PosCentralTelCheckBox); centralFilterBox->addWidget(m_ackCentralTelCheckBox); centralFilterBox->addStretch(1); m_CentralSelectionGroup = new QGroupBox(tr("Telegramme anzeigen"), this); m_CentralSelectionGroup->setCheckable(true); m_CentralSelectionGroup->setChecked(false); m_CentralSelectionGroup->setLayout(centralFilterBox); connect(m_CentralSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::showTelegramTable); } void LogViewGui::createTetraSelectionWidget() { m_SentTetraTelCheckBox = createRadioButton(tr("&gesendete Telegramme"), QLatin1String(":/image/T2P.png")); m_ReceivedTetraTelCheckBox = createRadioButton(tr("&empfangene Telegramme"), QLatin1String(":/image/P2T.png")); m_PosTetraTelCheckBox = createRadioButton(tr("&Positionsmeldungen"), QLatin1String(":/image/TetraPos.png")); m_FragmentedTetraTelCheckBox = createRadioButton(tr("&Fragmentierte Meldungen"), QLatin1String(":/image/TetraFragmented.png")); m_LoginTetraTelCheckBox = createRadioButton(tr("&Loginmeldungen"), QLatin1String(":/image/TetraLogin.png")); m_RegisterTetraTelCheckBox = createRadioButton(tr("&Registermeldungen"), QLatin1String(":/image/TetraRegister.png")); m_ReportTetraTelCheckBox = createRadioButton(tr("&Reportmeldungen"), QLatin1String(":/image/TetraReport.png")); m_AirInterfaceLoadTetraTelCheckBox = createRadioButton(tr("&Air-Load Meldungen"), QLatin1String(":/image/TetraAirInterface.png")); QVBoxLayout* tetraFilterBox = new QVBoxLayout; tetraFilterBox->addWidget(m_SentTetraTelCheckBox); tetraFilterBox->addWidget(m_ReceivedTetraTelCheckBox); tetraFilterBox->addWidget(m_PosTetraTelCheckBox); tetraFilterBox->addWidget(m_FragmentedTetraTelCheckBox); tetraFilterBox->addWidget(m_LoginTetraTelCheckBox); tetraFilterBox->addWidget(m_RegisterTetraTelCheckBox); tetraFilterBox->addWidget(m_ReportTetraTelCheckBox); tetraFilterBox->addWidget(m_AirInterfaceLoadTetraTelCheckBox); tetraFilterBox->addStretch(1); m_TetraSelectionGroup = new QGroupBox(tr("Telegramme anzeigen"), this); m_TetraSelectionGroup->setCheckable(true); m_TetraSelectionGroup->setChecked(false); m_TetraSelectionGroup->setLayout(tetraFilterBox); connect(m_TetraSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::showTelegramTable); } void LogViewGui::createWlsSelectionWidget() { m_SentWlsTelCheckBox = createRadioButton(tr("&gesendete Telegramme"), QLatin1String(":/image/P2W.png")); m_ReceivedWlsTelCheckBox = createRadioButton(tr("&empfangene Telegramme"), QLatin1String(":/image/W2P.png")); m_PosWlsTelCheckBox = createRadioButton(tr("&Positionsmeldungen"), QLatin1String(":/image/WlsPos.png")); QVBoxLayout* wlsFilterBox = new QVBoxLayout; wlsFilterBox->addWidget(m_SentWlsTelCheckBox); wlsFilterBox->addWidget(m_ReceivedWlsTelCheckBox); wlsFilterBox->addWidget(m_PosWlsTelCheckBox); wlsFilterBox->addStretch(1); m_WlsSelectionGroup = new QGroupBox(tr("Telegramme anzeigen"), this); m_WlsSelectionGroup->setCheckable(true); m_WlsSelectionGroup->setChecked(false); m_WlsSelectionGroup->setLayout(wlsFilterBox); connect(m_WlsSelectionGroup, &QGroupBox::toggled, this, &LogViewGui::showTelegramTable); } void LogViewGui::customMenuRequested(const QPoint &pos) { QMenu menu(this); menu.addAction(tr("Add Telegram to EditList"), this, &LogViewGui::addTelegramToEdit); menu.addAction(tr("Show HexData"), this, &LogViewGui::showHexData); menu.addAction(tr("Export as CSV file"), this, &LogViewGui::exportAsCsv); menu.addAction(tr("Export as JSon file"), this, &LogViewGui::exportAsJson); #ifdef LTS_DEBUG if (m_EditTelegramController && m_EditTelegramController->isInjectionPossible()) { const QString str = m_replayTimer->isActive() ? tr("Stop replay") : tr("Start Replay from here"); menu.addAction(str, this, &LogViewGui::onStartLogReplay); } #endif menu.exec(m_logTelegramView->viewport()->mapToGlobal(pos)); } void LogViewGui::addTelegramToEdit() { for (const QModelIndex &orig: m_logTelegramView->selectionModel()->selectedRows()) { const QModelIndex idx = m_telegramProxyModel->mapToSource(orig); QSharedPointer tele = m_telegramModel->telegram(idx.row()); if (!tele) continue; m_EditTelegramController->appendTelegram(tele); } } void LogViewGui::showHexData() { const QModelIndex idx = m_telegramProxyModel->mapToSource(m_logTelegramView->currentIndex()); QSharedPointer tele = m_telegramModel->telegram(idx.row()); if (!tele) return; LogViewTelegramDialog* showTelegramDialog = new LogViewTelegramDialog(this, true); showTelegramDialog->showDataDump(tele, false); } void LogViewGui::exportAsCsv() { const int idx = m_ActualLogfile.lastIndexOf(QLatin1Char('.')); const QString suggestion = m_ActualLogfile.left(idx) + QLatin1String(".csv"); const QString fn = QFileDialog::getSaveFileName(this, tr("Export logdata as CSV"), suggestion, tr("CSV file (*.csv)")); if (fn.isEmpty()) return; QFile f(fn); if (!f.open(QIODevice::WriteOnly)) return; for (int c = 0; c < m_telegramProxyModel->columnCount(); ++c) { f.write(m_telegramProxyModel->headerData(c, Qt::Horizontal).toString().toUtf8()); f.write(";"); } f.write("ISSI\n"); const int rc = m_telegramProxyModel->rowCount(); for (int r = 0; r < rc; ++r) { QSharedPointer tele = m_telegramProxyModel->telegram(r); if (!tele) continue; f.write(QByteArray::number(tele->getDestination())); f.write(";"); f.write(tele->getName().toUtf8()); f.write(";"); f.write(QByteArray::number(tele->getParticipantId())); f.write(";"); f.write(QByteArray::number(tele->getLogTimeMsec())); f.write(";"); f.write(QByteArray::number(tele->getGpsTime())); f.write(";"); f.write(QByteArray::number(tele->getDelay())); f.write(";"); f.write(QByteArray::number(tele->getISSI())); f.write("\n"); } f.close(); } void LogViewGui::exportAsJson() { const int idx = m_ActualLogfile.lastIndexOf(QLatin1Char('.')); const QString suggestion = m_ActualLogfile.left(idx) + QLatin1String(".csv"); const QString fn = QFileDialog::getSaveFileName(this, tr("Export logdata as Json"), suggestion, tr("JSon file (*.json)")); if (fn.isEmpty()) return; QFile f(fn); if (!f.open(QIODevice::WriteOnly)) return; QJsonArray arr; const int rc = m_telegramProxyModel->rowCount(); for (int r = 0; r < rc; ++r) { QSharedPointer tele = m_telegramProxyModel->telegram(r); if (!tele) continue; if (tele->jsonData().isEmpty()) continue; arr += tele->jsonData(); } f.write(QJsonDocument(arr).toJson(QJsonDocument::Indented)); f.close(); } void LogViewGui::onStartLogReplay() { #ifndef LTS_DEBUG return; #endif if (m_replayTimer->isActive()) { m_replayTimer->stop(); return; } m_reloadAction->setChecked(false); m_PosCentralTelCheckBox->setChecked(true); if (!m_EditTelegramController || !m_EditTelegramController->isInjectionPossible()) return; m_currentReplayRow = m_telegramProxyModel->mapToSource(m_logTelegramView->currentIndex()).row(); if (m_currentReplayRow < 0) return; m_replayTimer->start(0); } void LogViewGui::onReplayTimerTimeout() { auto findNextCentralTelegram = [&]() { static constexpr auto sendToCentralBits = N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral | N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend; auto tele = m_telegramModel->telegram(m_currentReplayRow); while (tele && (tele->getDestination() != sendToCentralBits || tele->getTelId() == GEF_BESTAETIGUNG)) tele = m_telegramModel->telegram(++m_currentReplayRow); return tele; }; QSharedPointer tele = findNextCentralTelegram(); auto checkTele = [&]() { if (!tele) { m_replayTimer->stop(); m_currentReplayRow = -1; QMessageBox::information(this, tr("Sending finished"), tr("No more telegrams to send - stopping")); return false; } return true; }; if (!checkTele()) return; const uint64_t curSendTime = tele->getLogTimeMsec(); auto teleCopy = QSharedPointer(new LogViewTelegram(*(tele.data()))); teleCopy->actualizeGpsTime(); m_InjectionThread->sendTelegram(teleCopy.data(), true); ++m_currentReplayRow; tele = findNextCentralTelegram(); if (!checkTele()) return; uint64_t nextSendTime = (tele->getLogTimeMsec() - curSendTime); DEBUG_LOG(m_logger) << "Next SendTime: " << nextSendTime << ", telId: " << tele->getTelId() << ", next row: " << m_currentReplayRow << ", equipNo: " << tele->getParticipantId(); QModelIndex idx = m_telegramModel->index(m_currentReplayRow, 0, QModelIndex()); m_logTelegramView->setCurrentIndex(m_telegramProxyModel->mapFromSource(idx)); m_replayTimer->start(nextSendTime); } void LogViewGui::loadSpecificationFiles() { QSettings settings; settings.beginGroup(LogViewOptionDialog::SPEC_FILES_GROUP); QString defString = QCoreApplication::applicationDirPath() + QLatin1String("/training_area_telegrams.h"); QString filename = settings.value(LogViewOptionDialog::P0_FILENAME, defString).toString(); INFO_LOG(m_logger) << "Load central-protocol spezification-file: " << filename.toStdString(); if (!QFile::exists(filename)) { QMessageBox::warning(this, tr("LogView"), tr("Die Spezifikations-Datei \'%1\' fuer Zentral-Telegramme existiert nicht!

Werde die Default-Datei verwenden...").arg(filename)); filename = defString; } LogViewTelegram::jsonParser()->parse(filename); defString = QCoreApplication::applicationDirPath() + QLatin1String("/zsksxd_tetraForLogView.x"); filename = settings.value(LogViewOptionDialog::P5_FILENAME, defString).toString(); INFO_LOG(m_logger) << "Load tetra-protocol spezification-file: " << filename.toStdString(); if (!QFile::exists(filename)) { QMessageBox::warning(this, tr("LogView"), tr("Die Spezifikations-Datei \'%1\' fuer TETRA-Telegramme existiert nicht!

Werde die Default-Datei verwenden...").arg(filename)); filename = defString; } LogViewTelegram::tetraParser()->parseX_File(filename); INFO_LOG(m_logger) << "Browse telegram-log-file"; newTelegramFile(); } void LogViewGui::newTelegramFile() { if (m_TailTimer) m_TailTimer->stop(); m_participantModel->clearParticipants(); m_telegramModel->clearTelegrams(); m_participantListTelCount.clear(); m_participantListIssi.clear(); m_ParticipantStatus->setText(tr("0 Teilnehmer")); loadTelegramFile(); } void LogViewGui::loadTelegramFile() { const QLatin1String DIR("Dir"); QSettings settings; settings.beginGroup(QLatin1String("LogFiles")); QString filename = QFileDialog::getOpenFileName(this, tr("Bitte eine Log-Datei auswaehlen"), settings.value(DIR).toString(), LogViewOptionDialog::KRLOG_FILES); if (filename.isEmpty()) return; QDir dir; settings.setValue(DIR, dir.filePath(filename)); readTelegramsFromLogFile(filename); showTelegramTable(); startInjectionThread(); m_logTelegramView->resizeColumnsToContents(); m_ParticipantTableView->resizeColumnsToContents(); if (!m_TailTimer) m_TailTimer = new QTimer(this); connect(m_TailTimer, &QTimer::timeout, this, &LogViewGui::updateLogfile, Qt::QueuedConnection); m_TailTimer->setInterval(1000); m_TailTimer->start(); } void LogViewGui::updateLogfile() { if(!m_DoReload) return; m_TailTimer->stop(); QFileInfo fileInfo = QFileInfo(m_ActualLogfile); if (fileInfo.exists()) { if (fileInfo.size() > m_LogfileSize) { try { readTelegramsFromLogFile(m_ActualLogfile, m_LogfileSize); } catch (const std::exception& e) { WARNING_LOG(m_logger) << "Error: " << e.what(); } } else { QString dateFromFile; const QString format = QStringLiteral("yyMMdd_hh"); for (int iterator = fileInfo.baseName().size() - format.size(); iterator < fileInfo.baseName().size(); ++iterator) dateFromFile.append(fileInfo.baseName().at(iterator)); QDateTime nextDateCalc = QDateTime::fromString(dateFromFile, format); nextDateCalc = nextDateCalc.addYears(100); nextDateCalc = nextDateCalc.addSecs(3600); QString nextDate = nextDateCalc.toString(format); nextDateCalc = nextDateCalc.addSecs(3600); QString checkDate = nextDateCalc.toString(format); QString filePath(fileInfo.absolutePath() + QLatin1Char('/')); const QString baseName = fileInfo.baseName(); const QVector parts = baseName.splitRef(QLatin1Char('_')); for (int iterator = 0; iterator < parts.size() - 2; ++iterator) filePath += parts.at(iterator).toString() + QLatin1Char('_'); QString nextFile(filePath + nextDate + QLatin1Char('.') + fileInfo.completeSuffix()); QString checkFile(filePath + checkDate + QLatin1Char('.') + fileInfo.completeSuffix()); QFileInfo infoNextFile(nextFile); QFileInfo infoCheckFile(checkFile); if (infoNextFile.exists() && infoNextFile.isFile() && !infoCheckFile.exists()) { m_LogfileSize = 0; readTelegramsFromLogFile(nextFile, m_LogfileSize); } } } m_TailTimer->start(); } void LogViewGui::readTelegramsFromLogFile(const QString& a_fileName, const qint64 a_filePos) { QFile telegramFile(a_fileName); if (telegramFile.open(QIODevice::ReadOnly)) { m_ActualLogfile = a_fileName; telegramFile.seek(a_filePos); setWindowTitle(QFileInfo(m_ActualLogfile).baseName()); m_logTelegramView->blockSignals(true); m_logTelegramView->setUpdatesEnabled(false); QVector > newTelegrams; N_CoPrtCnv::CoPrtCnvLogHeader lh; while (true) { if (sizeof(lh) == telegramFile.read((char*)&lh, sizeof(lh))) { if (lh.m_Version == 3 || lh.m_Version == 4) { qint64 telegramLength = lh.m_Length - sizeof(lh); QByteArray buf(telegramLength, Qt::Uninitialized); if (telegramLength == telegramFile.read(buf.data(), telegramLength)) { m_LogfileSize = telegramFile.pos(); if (lh.m_Version == 4) buf = qUncompress(buf); N_CoPrtCnv::CoPrtCnvLogHeader::E_CoPrtCnvProtocol protocol = static_cast(lh.m_Protocol); QSharedPointer telegram(new LogViewTelegram(protocol, lh.m_Time, buf)); if (!telegram->isValid()) { ERROR_LOG(m_logger) << "Trying to read/parse unknown data from logfile '" << a_fileName << "' at position " << telegramFile.pos() - (telegramLength + sizeof(lh)); continue; } newTelegrams.push_back(telegram); addToParticipantList(telegram); } } else { QMessageBox::warning(this, tr("Falsche Version"), tr("LogViewer kann Telegramm-Logs der Version %1 nicht einlesen").arg(lh.m_Version)); ERROR_LOG(m_logger) << "Trying to read/parse unknown data from logfile '" << a_fileName << "' at position " << telegramFile.pos() - sizeof(lh); } } else { break; } } syncParticipantList(); m_telegramModel->appendTelegrams(newTelegrams); m_ParticipantStatus->setText(tr("%1 Teilnehmer").arg(m_participantModel->rowCount())); m_logTelegramView->setUpdatesEnabled(true); m_logTelegramView->blockSignals(false); statusBar()->showMessage(tr("%1 Telegramme eingelesen").arg(m_telegramModel->rowCount())); } else { QMessageBox::warning(this, tr("Dateifehler"), tr("Konnte die Datei %1 nicht oeffnen").arg(a_fileName)); } telegramFile.close(); } void LogViewGui::selectedParticipantChanged() { std::set selectedParticipantIds; const QModelIndexList selectedParticipants = m_ParticipantTableView->selectionModel()->selectedRows(0); for (const QModelIndex &participantIdx : selectedParticipants) { const QModelIndex idx = m_participantProxyModel->mapToSource(participantIdx); selectedParticipantIds.insert(m_participantModel->data(idx).toInt()); } m_telegramProxyModel->setAllowedEquipmentIds(selectedParticipantIds); showTelegramTable(); } static void updateFilteredPosTelegramIds(std::set &teleIds, bool bEnable) { if (bEnable) { teleIds.erase(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG); teleIds.erase(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG_LFZ); teleIds.erase(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG_MIT_TEILNEHMER); teleIds.erase(TrainingAreaBase::TetraIcd::IPS_POSITIONSDATEN); } else { teleIds.insert(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG); teleIds.insert(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG_LFZ); teleIds.insert(TrainingAreaBase::TetraIcd::POSITIONS_MELDUNG_MIT_TEILNEHMER); teleIds.insert(TrainingAreaBase::TetraIcd::IPS_POSITIONSDATEN); } } void LogViewGui::showTelegramTable() { updateFilteredPosTelegramIds(m_CentralTelegramFilterList, m_PosCentralTelCheckBox->isChecked()); updateFilteredPosTelegramIds(m_TetraTelegramFilterList, m_PosTetraTelCheckBox->isChecked()); updateFilteredPosTelegramIds(m_WlsTelegramFilterList, m_PosWlsTelCheckBox->isChecked()); if (m_ackCentralTelCheckBox->isChecked()) m_CentralTelegramFilterList.erase(TrainingAreaBase::TetraIcd::BESTAETIGUNG); else m_CentralTelegramFilterList.insert(TrainingAreaBase::TetraIcd::BESTAETIGUNG); m_telegramProxyModel->setFilteredCentralTelegramIds(m_CentralTelegramFilterList); m_telegramProxyModel->setFilteredTetraTelegramIds(m_TetraTelegramFilterList); m_telegramProxyModel->setFilteredWlsTelegramIds(m_WlsTelegramFilterList); m_telegramProxyModel->setFilterByEquipmentIds(m_ParticipantSelectionGroup->isChecked()); m_PosCentralTelCheckBox->setEnabled(m_SentCentralTelCheckBox->isChecked() && m_CentralSelectionGroup->isChecked()); m_PosTetraTelCheckBox->setEnabled(m_SentTetraTelCheckBox->isChecked() && m_TetraSelectionGroup->isChecked()); m_PosWlsTelCheckBox->setEnabled(m_ReceivedWlsTelCheckBox->isChecked() && m_WlsSelectionGroup->isChecked()); const bool bShowCentralTelegrams = m_CentralSelectionGroup->isChecked(); m_telegramProxyModel->setFilterCentralTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend, !m_SentCentralTelCheckBox->isChecked() || !bShowCentralTelegrams); m_telegramProxyModel->setFilterCentralTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive, !m_ReceivedCentralTelCheckBox->isChecked() || !bShowCentralTelegrams); const bool bShowTetraTelegrams = m_TetraSelectionGroup->isChecked(); m_telegramProxyModel->setFilterTetraTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend, !m_SentTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); m_telegramProxyModel->setFilterTetraTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive, !m_ReceivedTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterInd, !m_RegisterTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_RegisterRsp, !m_RegisterTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_DataIndReq, !bShowTetraTelegrams); m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_ReportIndReq, !m_ReportTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirInterfaceLoadReq, !m_AirInterfaceLoadTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); m_telegramProxyModel->setFilterTetraPDU(N_CoPrtCnv::CoPrtCnvRadioTelegram::e_AirLoadHyterra, !m_AirInterfaceLoadTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); m_telegramProxyModel->setFilterTetraLogin(!m_LoginTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); m_telegramProxyModel->setFilterTetraFragmented(!m_FragmentedTetraTelCheckBox->isChecked() || !bShowTetraTelegrams); const bool bShowWlsTelegrams = m_WlsSelectionGroup->isChecked(); m_telegramProxyModel->setFilterWlsTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestSend, !m_SentWlsTelCheckBox->isChecked() || !bShowWlsTelegrams); m_telegramProxyModel->setFilterWlsTelegrams(N_CoPrtCnv::CoPrtCnvLogHeader::e_DestReceive, !m_ReceivedWlsTelCheckBox->isChecked() || !bShowWlsTelegrams); m_TelegramStatus->setText(tr("%1 telegrams (unfiltered: %2)") .arg(m_telegramProxyModel->rowCount()) .arg(m_telegramModel->rowCount())); } void LogViewGui::addToParticipantList(const QSharedPointer &a_telegram) { int partId = a_telegram->getParticipantId(); m_participantListTelCount[partId]++; auto &issi = m_participantListIssi[partId]; if (issi == 0) issi = a_telegram->getISSI(); } void LogViewGui::syncParticipantList() { QVector eqIds; QVector issis; QVector numberOfTelegrams; eqIds.reserve(m_participantListTelCount.size()); issis.reserve(m_participantListTelCount.size()); numberOfTelegrams.reserve(m_participantListTelCount.size()); for (auto it = m_participantListTelCount.constBegin(); it != m_participantListTelCount.constEnd(); ++it) { eqIds.push_back(it.key()); issis.push_back(m_participantListIssi.value(it.key())); numberOfTelegrams.push_back(it.value()); } m_participantModel->addUpdateParticipants(eqIds, issis, numberOfTelegrams); } void LogViewGui::changeSettings() { LogViewOptionDialog optionDialog(this); connect(&optionDialog, &LogViewOptionDialog::settingsChanged, this, &LogViewGui::onSettingsChanged); optionDialog.exec(); } QCheckBox* LogViewGui::createRadioButton(const QString& a_buttonName, const QString& a_iconName) { QCheckBox* checkBox = new QCheckBox(a_buttonName, this); checkBox->setIcon(QIcon(a_iconName)); checkBox->setIconSize(RADIO_BUTTON_ICON_SIZE); connect(checkBox, &QCheckBox::toggled, this, &LogViewGui::showTelegramTable); return checkBox; } void LogViewGui::startInjectionThread() { if (m_InjectionThread) { m_InjectionThread->quit(); m_InjectionThread->wait(); delete m_InjectionThread; } m_InjectionThread = new LogViewInjectionThread(); QSettings settings; settings.beginGroup(QLatin1String("LogFiles")); QString filePath = settings.value(QLatin1String("Dir")).toString(); QString exerciseName; QVector parts = filePath.splitRef(QLatin1Char('/')); if (parts.size() >= 2) exerciseName = QLatin1Char('_') + parts.at(parts.size() - 2).toString(); QString portFilePath = QCoreApplication::applicationDirPath() + QDir::separator() + QLatin1String("PrtCnv") + exerciseName + QLatin1String(".dat"); QFileInfo checkPortFile(portFilePath); if(checkPortFile.exists() && checkPortFile.isFile()) { QSettings portSetting(portFilePath, QSettings::IniFormat); m_InjectionThread->setPort(portSetting.value(QLatin1String("Injection/Port")).toInt()); } m_EditTelegramController->setInjectionThread(m_InjectionThread); connect(m_InjectionThread, &LogViewInjectionThread::updateStatus, this, &LogViewGui::updateInjectionStatus); m_InjectionThread->start(); } void LogViewGui::reloadOnOff() { m_DoReload = !m_DoReload; } void LogViewGui::closeEvent(QCloseEvent* a_closeEvent) { QSettings settings; settings.beginGroup(WINDOW_GROUP); settings.setValue(TOOLBOXINDEX, m_ToolBox->currentIndex()); settings.setValue(SIZE, size()); QPoint position = pos(); settings.setValue(POS, position); #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0) int screenNbr = QApplication::desktop()->screenNumber(position); #else QScreen *scr = QGuiApplication::screenAt(position); int screenNbr = QGuiApplication::screens().indexOf(scr); #endif settings.setValue(SCREEN, screenNbr); const QList splitterSizes = m_Splitter->sizes(); QList splitterSizesAsVariant; splitterSizesAsVariant.reserve(splitterSizes.size()); for (int item : splitterSizes) splitterSizesAsVariant << QVariant(item); settings.setValue(SPLITTPOS, splitterSizesAsVariant); settings.endGroup(); QMainWindow::closeEvent(a_closeEvent); } void LogViewGui::updateInjectionStatus(const QString& a_picName, const QString& a_toopTipText) { m_InjectionStatus->setPixmap(QPixmap(a_picName)); m_InjectionStatus->setToolTip(a_toopTipText); } void LogViewGui::onLogTelegramViewDoubleClicked(const QModelIndex &index) { if (!m_telegramProxyModel || !m_telegramModel) return; QModelIndex idx = m_telegramProxyModel->mapToSource(index); if (!idx.isValid()) return; QSharedPointer telegram = m_telegramModel->telegram(idx.row()); if (!telegram) return; LogViewTelegramDialog* showTelegramDialog = new LogViewTelegramDialog(this, true); showTelegramDialog->showDialog(telegram); } void LogViewGui::onSettingsChanged(uint32_t changedFlags) { if ((changedFlags & LogViewOptionDialog::SpecFilesGroup) == LogViewOptionDialog::SpecFilesGroup) loadSpecificationFiles(); if ((changedFlags & LogViewOptionDialog::InjectionGroup) == LogViewOptionDialog::InjectionGroup) startInjectionThread(); } }