Files
qt5-legatus-legacy/TetraIF/LogView/LogViewTelegramDialog.cpp
2026-08-13 18:33:10 +02:00

498 lines
17 KiB
C++

// **************************************************************************
//
// (C) Copyright 2009 Swiss SIMTEC AG
//
// **************************************************************************
//
// $HeadURL$
// $LastChangedBy$
// $LastChangedDate$
// $LastChangedRevision$
//
// **************************************************************************
#include "LogViewTelegramDialog.hpp"
#include "LogViewTelegram.hpp"
#include <QApplication>
#include <QDesktopWidget>
#include <QDir>
#include <QFileDialog>
#include <QGroupBox>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QSettings>
#include <QScrollArea>
#include <QTextEdit>
#include <QVBoxLayout>
#include "LogViewXdrElement.hpp"
#include "LogViewField.hpp"
#include "IntegerCalculator.hpp"
#include "LogViewBooleanEdit.hpp"
#include "LogViewTextEdit.hpp"
#include "LogViewValueEdit.hpp"
#include "LogViewEnumEdit.hpp"
#include "LogViewDateTimeEdit.hpp"
#include "LogViewSpinBox.hpp"
#include "LogViewTableWidget.hpp"
#include "LogViewTabWidget.hpp"
namespace N_LogView
{
// todo:
// - feld einfärben wenn geändert, wenn falsch
// - mache hartcodierte oder konfigurierbare ranges für spezielle Werte wie GPS-Position: signed 24-bit
// ---------------------------------------------------------------
LogViewTelegramDialog::LogViewTelegramDialog(QWidget *a_parent, const bool a_readonly)
: QDialog(a_parent)
, m_ReadOnly(a_readonly)
, m_logger(getLogger("LogViewTelegramDialog"))
{
setAttribute(Qt::WA_DeleteOnClose);
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showDialog(const QSharedPointer<LogViewTelegram> &a_telegram)
{
delete layout();
hide();
m_Telegram = a_telegram;
a_telegram->dump();
m_fieldTree.reset(a_telegram->getFieldTree());
if (m_fieldTree)
{
QGridLayout *dialogLayout = new QGridLayout;
if (!m_ReadOnly)
{
// edit wait-time
QLabel *waitTimeLabel = new QLabel(tr("Wartezeit [ms]"), this);
dialogLayout->addWidget(waitTimeLabel, dialogLayout->rowCount(), 0);
m_WaitTimeEdit = new QLineEdit(QString::number(a_telegram->getWaitTime()), this);
dialogLayout->addWidget(m_WaitTimeEdit, dialogLayout->rowCount() - 1, 1);
// edit name
QLabel *nameLabel = new QLabel(tr("Name"), this);
dialogLayout->addWidget(nameLabel, dialogLayout->rowCount(), 0);
m_NameEdit = new QLineEdit(a_telegram->getName(), this);
dialogLayout->addWidget(m_NameEdit, dialogLayout->rowCount() - 1, 1);
QFrame *f = new QFrame(this);
f->setFrameShape(QFrame::HLine);
f->setFrameShadow(QFrame::Sunken);
dialogLayout->addWidget(f, dialogLayout->rowCount(), 0, 1, 2);
}
//INFO_LOG(m_logger) << "--------------- create dialog " << fieldTree->getName().toStdString() << "--------------";
//m_fieldTree->dump();
showTree(m_fieldTree.data(), dialogLayout);
if (this->findChild<LogViewTableWidget *>() == nullptr)
dialogLayout->setRowStretch(dialogLayout->rowCount(), 1);
// build the dialog
QVBoxLayout *mainLayout = new QVBoxLayout(this);
// make dialog scrollable
m_contentsWidget = new QWidget;
m_contentsWidget->setLayout(dialogLayout);
m_ScrollArea = new QScrollArea(this);
m_ScrollArea->setWidget(m_contentsWidget);
m_ScrollArea->setWidgetResizable(true);
mainLayout->addWidget(m_ScrollArea);
// buttons
QHBoxLayout *btnLayout = new QHBoxLayout;
btnLayout->addStretch();
showButtons(btnLayout);
mainLayout->addLayout(btnLayout);
setWindowTitle(m_fieldTree->cleanName() + QStringLiteral(" (%1)").arg(a_telegram->getTelId()));
setModal(true);
show();
makePretty();
}
else
showDataDump(a_telegram, true);
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showDataDump(const QSharedPointer<LogViewTelegram> &a_telegram, bool showErrorMessage)
{
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(new QLabel(tr("Telegramm-Dump")));
if (showErrorMessage)
// show error-message in dialog
layout->addWidget(new QLabel(tr("Konnte Dialog basierend auf Struktur \'%1\' nicht generieren!").arg(a_telegram->getStructName())));
else
layout->addWidget(new QLabel(tr("HexData from \'%1\' - telegram:").arg(a_telegram->getName())));
// generate the telegram-dump
QString theDump = QLatin1String("<code>");
const QByteArray &data = a_telegram->getData();
for (int i = 0; i < data.size(); i++)
{
if (0 == (i % 8))
theDump += QStringLiteral("%1:").arg(i, 4, 16, QLatin1Char('0'));
theDump += QStringLiteral(" %1").arg(static_cast<unsigned char>(data[i]), 2, 16, QLatin1Char('0'));
if (7 == (i % 8))
theDump += QLatin1String("<br>");
}
theDump += QLatin1String("</code>");
QTextEdit *telegramDump = new QTextEdit(theDump);
layout->addWidget(telegramDump);
QPushButton *btnClose = new QPushButton(QIcon(QLatin1String(":icons/16x16/edit-delete.png")), tr("&Schliessen"));
QHBoxLayout *btnLayout = new QHBoxLayout;
btnLayout->addStretch();
btnLayout->addWidget(btnClose);
layout->addLayout(btnLayout);
connect(btnClose, &QPushButton::clicked,
this, &LogViewTelegramDialog::reject);
setLayout(layout);
show();
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::makePretty()
{
return;
// set the size and position of dialog
int sbWidth = m_ScrollArea->width() - m_ScrollArea->viewport()->width();
int wDiff = m_contentsWidget->width() - m_ScrollArea->width();
int hDiff = m_contentsWidget->height() - m_ScrollArea->viewport()->height();
const QRect screenSize = QApplication::desktop()->screenGeometry(this);
//QRect winGeo = geometry();
int newWidth = std::min(width() + wDiff + sbWidth, screenSize.width() * 9 / 10);
int newHeight = std::min(height() + hDiff, screenSize.height() * 9 / 10);
//setGeometry(winGeo);
//QSize size = settings.value(SIZE, sizeHint()).toSize();
resize(QSize(newWidth, newHeight));
//move(settings.value(POS, QPoint(0, 0)).toPoint());
// --------------------------------------------------------------------
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showTree(LogViewField *a_fieldTree, QGridLayout *a_box)
{
int i = 0;
while (LogViewField *child = a_fieldTree->child(i++))
{
if (!a_fieldTree->hasContent())
child->setHasContent(false);
switch (child->kind())
{
case LogViewField::e_FieldKindBorder:
{
QGroupBox *groupBox = new QGroupBox(child->cleanName());
QGridLayout *actBox = new QGridLayout(groupBox);
a_box->addWidget(groupBox, a_box->rowCount(), 0, 1, 2);
showTree(child, actBox);
break;
}
case LogViewField::e_FieldKindTab:
showTab(child, a_box);
break;
case LogViewField::e_FieldKindTabChild:
{
QWidget *widget = new QWidget;
widget->setContentsMargins(QMargins());
QGridLayout *actBox = new QGridLayout(widget);
a_box->addWidget(widget, a_box->rowCount(), 0, 1, 2);
showTree(child, actBox);
break;
}
case LogViewField::e_FieldKindEdit:
case LogViewField::e_FieldKindPodArray:
case LogViewField::e_FieldKindPodArrayChild:
showEditField(child, a_box);
break;
}
}
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::fillTelegram(LogViewTelegram *a_telegram)
{
INFO_LOG(m_logger) << "******************************************";
// check whether all changed values are valid
// ------------------------------------------
for (const auto ptr : qAsConst(m_EditInfoList))
{
if (!ptr->isValid())
{
INFO_LOG(m_logger) << ptr->field()->name() << " is invalid";
return; // abort when a value is not vaild
}
}
// now save the values
// -------------------
a_telegram->resetOffset();
a_telegram->clearJsonData();
for (auto ptr : qAsConst(m_EditInfoList))
{
if (!ptr->saveContent(a_telegram))
{
QMessageBox::warning(this, tr("Error while saving telegram"),
tr("Found an invalid value - the telegram may be not saved correctly"));
}
}
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::saveTelegram()
{
fillTelegram(m_Telegram.data());
// save wait-time and name
N_SST::IntegerCalculator calculator;
N_SST::IntegerCalculator::E_Error error;
m_Telegram->setWaitTime(calculator.calc(m_WaitTimeEdit->text().toStdString(), error));
m_Telegram->setName(m_NameEdit->text());
accept();
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::sendCurrentTelegram()
{
emit sendTelegram(m_Telegram);
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showButtons(QLayout *a_layout)
{
if (N_CoPrtCnv::CoPrtCnvLogHeader::e_DestProtocolCentral == m_Telegram->getProtocol())
{
QPushButton *btnSend = new QPushButton(QIcon(QLatin1String(":icons/16x16/mail-send.png")), tr("&Send"));
btnSend->setEnabled(true); // TODO: Status ob wirklich möglich ggf. überprüfen
connect(btnSend, &QPushButton::clicked, this, &LogViewTelegramDialog::sendCurrentTelegram);
a_layout->addWidget(btnSend);
}
if (m_ReadOnly)
{
QPushButton *btnClose = new QPushButton(QIcon(QLatin1String(":icons/16x16/edit-delete.png")), tr("&Schliessen"));
connect(btnClose, &QPushButton::clicked, this, &LogViewTelegramDialog::reject);
a_layout->addWidget(btnClose);
}
else
{
QPushButton *btnClose = new QPushButton(QIcon(QLatin1String(":icons/16x16/edit-delete.png")), tr("&Abbrechen"));
connect(btnClose, &QPushButton::clicked, this, &LogViewTelegramDialog::reject);
a_layout->addWidget(btnClose);
QPushButton *btnOk = new QPushButton(QIcon(QLatin1String(":icons/16x16/dialog-ok-apply.png")), tr("&OK"));
btnOk->setDefault(true);
// fixme: absturz, wenn feld ungültiger wert enthält und ok gedrückt wird
connect(btnOk, &QPushButton::clicked, this, &LogViewTelegramDialog::saveTelegram);
a_layout->addWidget(btnOk);
}
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showEditField(LogViewField *a_logViewField, QGridLayout *a_box)
{
// INFO_LOG(m_logger) << a_logViewField->getName() <<
// << " a_logViewField->getValueListSize()=" << a_logViewField->getValueListSize()
// << " a_logViewField->isIsDynamicArray()=" << a_logViewField->isIsDynamicArray()
// << " a_logViewField->getValue(0)=" << a_logViewField->getValue(0).toStdString()
// << " a_logViewField->getXdrElement())->getValueKind()=" << (int)(static_cast<const LogViewXdrStandardType*>(a_logViewField->getXdrElement())->getValueKind())
// ;
switch (a_logViewField->valueListSize())
{
case 1:
// 1 field (single or multi-line)
if (m_ReadOnly || !a_logViewField->isDynamicArray() || (LogViewXdrStandardType::e_Character == static_cast<const LogViewXdrStandardType *>(a_logViewField->xdrElement())->getValueKind()))
{
QLabel *label = new QLabel(a_logViewField->cleanName());
a_box->addWidget(label, a_box->rowCount(), 0);
LogViewWidget *valueWidget = nullptr;
//QString value = a_logViewField->getValue(0);
// if (-1 == value.indexOf("<br>") && value.length() < 80)
{
// single line
// -----------
if (LogViewXdrElement::e_KindEnum == a_logViewField->xdrElement()->getKind())
{
// enum => combobox
// ----------------
valueWidget = new LogViewEnumEdit(a_logViewField, this, m_ReadOnly, 0);
}
else
{
if (a_logViewField->isDateTimeField() || a_logViewField->isMSecsField())
{
// date-time-field
// ---------------
valueWidget = new LogViewDateTimeEdit(a_logViewField, this, m_ReadOnly);
}
else
{
switch (static_cast<const LogViewXdrStandardType *>(a_logViewField->xdrElement())->getValueKind())
{
case LogViewXdrStandardType::e_Boolean:
valueWidget = new LogViewBooleanEdit(a_logViewField, this, m_ReadOnly);
break;
case LogViewXdrStandardType::e_Signed:
case LogViewXdrStandardType::e_Unsigned:
case LogViewXdrStandardType::e_Float:
case LogViewXdrStandardType::e_Data:
valueWidget = new LogViewValueEdit(a_logViewField, this, m_ReadOnly);
break;
case LogViewXdrStandardType::e_Character: // Text
valueWidget = new LogViewTextEdit(a_logViewField, this, m_ReadOnly);
break;
}
}
}
if (valueWidget)
m_EditInfoList.push_back(valueWidget);
}
// else
// {
// // ----------------------------------------------------------------
// // fixme: not used => take away
// // multi-line
// valueWidget = new QTextEdit(value);
// static_cast<QTextEdit*>(valueWidget)->setReadOnly(true);
// // make proper width of widget
// QFontMetrics fm(valueWidget->font());
// // the 0 (at end) are here, because QFontMetrics does not understand the <code> and <b> tags.
// // So not the correct font will be used for calculating the width.
// // The solution here is suboptimal, but will hopefully work with a lot of fonts...
// valueWidget->setMinimumWidth(fm.width("0000: 00 00 00 00 00 00 00")*1.7);
// // ----------------------------------------------------------------
// }
QWidget *w = dynamic_cast<QWidget *>(valueWidget);
if (w)
a_box->addWidget(w, a_box->rowCount() - 1, 1);
else
WARNING_LOG(m_logger) << "Internal error - LogViewWidget is not derived from QWidget... !?";
break;
}
// fall through for not read-only and dyn. array
Q_FALLTHROUGH();
case 0:
if (m_ReadOnly)
{
// no field
a_box->addWidget(new QLabel(tr("Keine %1").arg(a_logViewField->cleanName())));
break;
}
// fall through for not read-only
Q_FALLTHROUGH();
default:
{
// show the title of table
QLabel *label = new QLabel(a_logViewField->cleanName());
a_box->addWidget(label, a_box->rowCount(), 0);
// show the spin-box for changing the dyn. array-size
LogViewSpinBox *spinBox = nullptr;
if (!m_ReadOnly && a_logViewField->isDynamicArray())
{
spinBox = new LogViewSpinBox(a_logViewField, this, a_logViewField->valueListSize());
a_box->addWidget(spinBox, a_box->rowCount() - 1, 1);
}
// show the table for changing the array-values
LogViewTableWidget *tableWidget = new LogViewTableWidget(a_logViewField, this, m_ReadOnly);
m_EditInfoList.push_back(tableWidget);
a_box->addWidget(tableWidget, a_box->rowCount(), 0, 1, 2);
// connect signals
if (spinBox)
{
connect(spinBox, &LogViewSpinBox::valueEditingFinished,
tableWidget, &LogViewTableWidget::changeSize);
}
}
break;
}
}
// ---------------------------------------------------------------
void LogViewTelegramDialog::showTab(LogViewField *a_logViewField, QGridLayout *a_box)
{
LogViewSpinBox *spinBox = nullptr;
if (!m_ReadOnly && a_logViewField->isDynamicArray())
{
// show the spin-box for changing the dyn. array-size
QLabel *label = new QLabel(a_logViewField->cleanName());
a_box->addWidget(label, a_box->rowCount(), 0);
spinBox = new LogViewSpinBox(a_logViewField, this, 0);
a_box->addWidget(spinBox, a_box->rowCount() - 1, 1);
}
LogViewTabWidget *a_tabWidget = new LogViewTabWidget(a_logViewField, this, spinBox);
m_EditInfoList.push_back(dynamic_cast<LogViewWidget *>(a_tabWidget));
a_box->addWidget(a_tabWidget, a_box->rowCount(), 0, 1, 2);
// connect signals
if (spinBox)
{
connect(spinBox, &LogViewSpinBox::valueEditingFinished,
a_tabWidget, &LogViewTabWidget::changeSize);
}
// add the tab
if (a_logViewField->hasContent())
{
for (int i = 0; i < a_logViewField->childCount(); ++i)
a_tabWidget->addTab(a_logViewField, false, i);
}
}
// ---------------------------------------------------------------
bool LogViewTelegramDialog::removeItemsFromEditInfoList(const QStringList &jsonPath)
{
if (m_EditInfoList.empty())
return false;
for (int i = m_EditInfoList.size() - 1; i >= 0; --i)
{
LogViewWidget *lvw = m_EditInfoList.at(i);
const QStringList jsonPathChild = lvw->field()->jsonPath();
if (jsonPathChild.size() < jsonPath.size())
continue;
bool bIsChild = true;
for (int j = 0; j < jsonPath.size(); ++j)
{
if (jsonPath.at(j) != jsonPathChild.at(j))
{
bIsChild = false;
break;
}
}
if (!bIsChild)
continue;
delete m_EditInfoList.at(i);
m_EditInfoList.removeAt(i);
}
m_EditInfoList.resize(m_EditInfoList.size() - 1);
return true;
}
} // namespace N_LogView