Initial commit

This commit is contained in:
torsten committed 2026-08-13 18:33:10 +02:00
commit b7d90b9afe
16245 files changed
+3396666

No files matched your search

+534
View File
@@ -0,0 +1,534 @@
/**
* @RDE_HEADER@
*
* TableModel for dynamic topics
*
* $Id$
* $HeadURL$
* $Author$
*/
#include "samplemodel.h"
#include <QMimeData>
#include <QStringList>
#include <QDomDocument>
#include "detailviewdlg.h"
#include "nglsettings.h"
#include "xmlhelper.h"
//
// SampleModel::SampleData
//
QByteArray SampleModel::SampleData::encodeForMime() const
{
QByteArray encodedData;
QDataStream stream(&encodedData, QIODevice::WriteOnly);
stream << QString::fromStdString(typeName)
<< reinterpret_cast<quint64>(legatusData.data())
<< topicName
<< description
<< pause;
return encodedData;
}
SampleModel::SampleData SampleModel::SampleData::decodeFromMime(const QByteArray &encodedData)
{
SampleData ret;
QDataStream stream(const_cast<QByteArray *>(&encodedData), QIODevice::ReadOnly);
QString tn;
quint64 ptr;
dds::core::xtypes::DynamicData *dynDataPtr;
stream >> tn >> ptr >> ret.topicName >> ret.description >> ret.pause;
ret.typeName = tn.toStdString();
dynDataPtr = reinterpret_cast<dds::core::xtypes::DynamicData *>(ptr);
ret.legatusData = QSharedPointer<dds::core::xtypes::DynamicData>(new dds::core::xtypes::DynamicData(*dynDataPtr));
return ret;
}
//
// SampleModel
//
SampleModel::SampleModel(QObject *parent)
: QAbstractTableModel(parent)
, m_logger(DdsView::getLogger("SampleModel"))
{}
SampleModel::~SampleModel()
{
for (const SampleData &sd : qAsConst(m_data))
delete sd.dialog;
}
int SampleModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return m_data.size();
}
int SampleModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return Column::Maximum + 1;
}
QVariant SampleModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.column() >= columnCount(QModelIndex()) ||
index.row() >= rowCount(QModelIndex()))
return QVariant();
const SampleData &data = m_data[index.row()];
if (role == Qt::ToolTipRole
&& index.column() == Column::TopicName)
return QString::fromStdString(data.typeName);
if (role != Qt::DisplayRole &&
role != Qt::EditRole)
return QVariant();
if (data.typeName.empty())
return QVariant();
switch (index.column())
{
case Column::TopicName:
return data.topicName;
case Column::Description:
return data.description;
case Column::TypeName:
return QString::fromStdString(data.typeName);
case Column::Pause:
return data.pause;
}
return QVariant();
}
bool SampleModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (!index.isValid() ||
role != Qt::EditRole)
return false;
if (index.column() >= columnCount(QModelIndex()) ||
index.row() >= rowCount(QModelIndex()))
return false;
SampleData &data = m_data[index.row()];
bool retVal = false;
switch (index.column())
{
// Non editable!
case Column::TopicName:
case Column::TypeName:
break;
case Column::Description:
data.description = value.toString();
retVal = true;
if (data.dialog)
data.dialog->setWindowTitle(QString::fromLatin1("%1 (%2)").arg(data.description, data.topicName));
break;
case Column::Pause:
{
int i = value.toInt(&retVal);
if (retVal)
data.pause = i;
break;
}
}
if (retVal)
emit dataChanged(index, index);
return retVal;
}
bool SampleModel::updateRow(const QModelIndex &index,
const QSharedPointer<dds::core::xtypes::DynamicData> &data,
const QString &topicName)
{
int row = index.row();
if (row < 0 || row >= rowCount(QModelIndex()))
return false;
SampleData &sample = m_data[row];
if (sample.legatusData->type() != data->type())
return false;
sample.legatusData = data;
sample.topicName = topicName;
return true;
}
Qt::DropActions SampleModel::supportedDropActions() const
{
return Qt::CopyAction | Qt::MoveAction;
}
Qt::DropActions SampleModel::supportedDragActions() const
{
return Qt::MoveAction | Qt::CopyAction;
}
QVariant SampleModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
{
switch (section)
{
case Column::TopicName:
return tr("Topic Name");
case Column::Description:
return tr("Description");
case Column::TypeName:
return tr("Type Name");
case Column::Pause:
return tr("Pause");
}
}
return QAbstractTableModel::headerData(section, orientation, role);
}
std::string SampleModel::typeName(const QModelIndex &index) const
{
int row = index.row();
if (row < 0 || row >= m_data.size())
return std::string();
return m_data[row].typeName;
}
bool SampleModel::addRow(const SampleData &sample, int position)
{
if (position < 0 || position > m_data.size())
position = m_data.size();
beginInsertRows(QModelIndex(), position, position);
m_data.insert(position, sample);
endInsertRows();
return true;
}
bool SampleModel::deleteRow(const QModelIndex &index)
{
int position = index.row();
if (position < 0 || position > m_data.size())
return false;
beginRemoveRows(QModelIndex(), position, position);
delete m_data[position].dialog;
m_data.remove(position);
endRemoveRows();
return true;
}
void SampleModel::onClear()
{
beginResetModel();
auto it = m_data.begin();
while (it != m_data.end())
{
delete (*it).dialog;
it = m_data.erase(it);
}
endResetModel();
}
Qt::ItemFlags SampleModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = QAbstractTableModel::flags(index) | Qt::ItemIsDropEnabled;
if (index.isValid())
flags |= Qt::ItemIsDragEnabled;
if (index.column() == Column::Description || index.column() == Column::Pause)
flags |= Qt::ItemIsEditable;
return flags;
}
QMimeData *SampleModel::mimeData(const QModelIndexList &indexes) const
{
QMimeData *mimeData = new QMimeData();
QModelIndex mi = indexes.value(0);
if (!mi.isValid())
return mimeData;
const SampleData &sample = m_data[mi.row()];
mimeData->setData(QLatin1String("SampleModel/SampleData"), sample.encodeForMime());
return mimeData;
}
bool SampleModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
int row, int column, const QModelIndex &parent)
{
Q_UNUSED(column)
if (action == Qt::IgnoreAction)
return true;
if ((action != Qt::MoveAction) && (action != Qt::CopyAction))
return false;
if (data->hasFormat(QLatin1String("SampleModel/SampleData")))
{
const QByteArray encodedData = data->data(QLatin1String("SampleModel/SampleData"));
SampleData sample = SampleData::decodeFromMime(encodedData);
int beginRow;
if (row != -1)
beginRow = row;
else if (parent.isValid())
beginRow = parent.row();
else
beginRow = rowCount(QModelIndex());
addRow(sample, beginRow);
}
else if (data->hasFormat(QLatin1String("dds::core::xtypes::DynamicData/Pointer+TopicName")))
{
QByteArray encodedData = data->data(QLatin1String("dds::core::xtypes::DynamicData/Pointer+TopicName"));
QDataStream stream(&encodedData, QIODevice::ReadOnly);
while (!stream.atEnd())
{
SampleData sample;
quint64 ptrVal;
stream >> ptrVal;
stream >> sample.topicName;
dds::core::xtypes::DynamicData *ptr = reinterpret_cast<dds::core::xtypes::DynamicData *>(ptrVal);
if (ptr->type_kind() != dds::core::xtypes::TypeKind::STRUCTURE_TYPE)
continue;
sample.legatusData = QSharedPointer<dds::core::xtypes::DynamicData>(new dds::core::xtypes::DynamicData(*ptr));
sample.typeName = ptr->type().name();
sample.description = sample.topicName;
int beginRow;
if (row != -1)
beginRow = row;
else if (parent.isValid())
beginRow = parent.row();
else
beginRow = rowCount(QModelIndex());
addRow(sample, beginRow);
}
}
else if (data->hasFormat(QLatin1String("Text/TopicName+TypeName")))
{
QByteArray topicName, typeName;
QByteArray encodedData = data->data(QLatin1String("Text/TopicName+TypeName"));
QDataStream stream(&encodedData, QIODevice::ReadOnly);
stream >> topicName;
stream >> typeName;
SampleData sample;
// TODO: set topicName
sample.typeName = typeName.toStdString();
sample.topicName = QString::fromLatin1(topicName.data());
sample.description = sample.topicName;
sample.legatusData = QSharedPointer<dds::core::xtypes::DynamicData>(new dds::core::xtypes::DynamicData(NGLSettings::instance()->dataTopic(sample.topicName).type));
int beginRow;
if (row != -1)
beginRow = row;
else if (parent.isValid())
beginRow = parent.row();
else
beginRow = rowCount(QModelIndex());
addRow(sample, beginRow);
}
return true;
}
QStringList SampleModel::mimeTypes() const
{
QStringList sl;
sl << QLatin1String("SampleModel/SampleData"); // (SampleModel::SampleData)
sl << QLatin1String("dds::core::xtypes::DynamicData/Pointer+TopicName"); // (dds::core::xtypes::DynamicData*) & topicName
sl << QLatin1String("Text/TopicName+TypeName"); // e.g. "LTS_ExerciseParticipant" & "ParticipantManagement::ExerciseParticipant"
return sl;
}
bool SampleModel::addRow(const dds::core::xtypes::DynamicData &data, const QString &topicName, const QString &description)
{
SampleData id;
id.typeName = data.type().name();
id.topicName = topicName;
id.description = description.isEmpty() ? topicName : description;
id.legatusData = QSharedPointer<dds::core::xtypes::DynamicData>(new dds::core::xtypes::DynamicData(data.type()));
return addRow(id);
}
SampleModel::SampleData SampleModel::sampleData(const QModelIndex &index) const
{
int row = index.row();
if (row < 0 || row >= m_data.size())
return SampleData();
SampleData data = m_data.value(row);
//DEBUG_LOG(m_logger) << "intern: " << data.legatusData.data()->type().name();
return data;
}
void SampleModel::setDialog(const QModelIndex &index, DetailViewDlg *dlg)
{
// Dialog will not be destructed! It will be hidden and reused on second usage.
// ~SampleModel takes care tp destruct anyways.
int row = index.row();
if (row < 0 || row >= m_data.size())
return;
m_data[row].dialog = dlg;
}
QModelIndex SampleModel::indexByDialog(const DetailViewDlg *dlg) const
{
for (int i = 0; i < m_data.size(); ++i)
if (m_data[i].dialog == dlg)
return index(i, 0);
return QModelIndex();
}
//
// SampleSortModel
//
bool SampleSortModel::lessThan(const QModelIndex &left,
const QModelIndex &right) const
{
if (left.column() != right.column())
return QSortFilterProxyModel::lessThan(left, right);
SampleModel *srcModel = qobject_cast<SampleModel *>(sourceModel());
if (!srcModel)
return QSortFilterProxyModel::lessThan(left, right);
SampleModel::SampleData dataLeft = srcModel->sampleData(left);
SampleModel::SampleData dataRight = srcModel->sampleData(right);
switch (left.column())
{
case SampleModel::Column::TopicName:
return dataLeft.topicName < dataRight.topicName;
case SampleModel::Column::Description:
return dataLeft.description < dataRight.description;
case SampleModel::Column::TypeName:
return dataLeft.typeName < dataRight.typeName;
case SampleModel::Column::Pause:
return dataLeft.pause < dataRight.pause;
}
return QSortFilterProxyModel::lessThan(left, right);
}
void SampleSortModel::sort(int column, Qt::SortOrder order)
{
QModelIndex ind = index(m_currentRow, 0);
int sourceRow = mapToSource(ind).row();
QSortFilterProxyModel::sort(column, order);
QModelIndex dex = sourceModel()->index(sourceRow, 0);
m_currentRow = mapFromSource(dex).row();
emit headerDataChanged(Qt::Vertical, m_currentRow, m_currentRow);
}
QVariant SampleSortModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QSortFilterProxyModel::headerData(section, orientation, role);
if (orientation == Qt::Vertical)
{
if (section == m_currentRow)
return QChar(0x21D2);
return QString();
}
return sourceModel()->headerData(section, orientation, role);
}
void SampleModel::SampleData::toXml(QDomDocument &doc, QDomElement &elem) const
{
QDomElement deSample = doc.createElement(QLatin1String("Sample"));
elem.appendChild(deSample);
QDomElement deTopicName = doc.createElement(QLatin1String("TopicName"));
deSample.appendChild(deTopicName);
QDomText deTopicNameContents = doc.createTextNode(topicName);
deTopicName.appendChild(deTopicNameContents);
QDomElement deTypeName = doc.createElement(QLatin1String("TypeName"));
deSample.appendChild(deTypeName);
QDomText deTypeNameContents = doc.createTextNode(QString::fromStdString(typeName));
deTypeName.appendChild(deTypeNameContents);
QDomElement dePause = doc.createElement(QLatin1String("Pause"));
deSample.appendChild(dePause);
QDomText dePauseContents = doc.createTextNode(QString::number(pause));
dePause.appendChild(dePauseContents);
XmlHelper::dds2Xml(*legatusData, topicName, doc, deSample);
}
bool SampleModel::SampleData::fromXml(QDomElement &elem)
{
if (elem.nodeName().compare(QLatin1String("Sample"), Qt::CaseInsensitive) != 0)
return false;
bool succ = false;
QDomNodeList dnl = elem.childNodes();
for (int i = 0; i < dnl.size(); ++i)
{
QDomNode dn = dnl.at(i);
if (!dn.isElement())
continue;
QDomElement de = dn.toElement();
if (de.nodeName() == QLatin1String("TopicName"))
topicName = de.text();
else if (de.nodeName() == QLatin1String("Type"))
typeName = de.text().toStdString();
else if (de.nodeName() == QLatin1String("Pause"))
{
bool ok;
pause = de.text().toInt(&ok);
if (!ok)
pause = 1000;
}
else if (de.nodeName() == QLatin1String("DdsData"))
{
const QString topicName = XmlHelper::topicNameFromXml(de);
const TopicDescriptionEx td = NGLSettings::instance()->topicFromTopicName(topicName);
const dds::core::xtypes::DynamicData data = XmlHelper::xml2Dds(de, td);
dds::core::xtypes::TypeKind kind = dds::core::xtypes::TypeKind::PRIMITIVE_TYPE;
try
{
kind = data.type_kind();
}
catch (dds::core::Exception &e)
{
qWarning("dds exception: %s", e.what());
continue;
}
if (kind != dds::core::xtypes::TypeKind::STRUCTURE_TYPE)
continue;
legatusData = QSharedPointer<dds::core::xtypes::DynamicData>(new dds::core::xtypes::DynamicData(data));
typeName = data.type().name();
succ = (typeName != "Unknown");
}
}
if (topicName.isEmpty())
topicName = QString::fromStdString(typeName);
if (description.isEmpty())
description = topicName;
return succ;
}