This commit is contained in:
deeaitch committed 2026-10-06 17:14:50 -04:00
1 parent e5d818d9b2
commit a533d9aa00
13 files changed
+527 -12

No files matched your search

+128
View File
@@ -0,0 +1,128 @@
// SPDX-License-Identifier: MIT
#include "dbc_tree_model.h"
#include <QVariantList>
#include <QVariantMap>
#include <limits>
#include <stdexcept>
DbcTreeModel::DbcTreeModel(QObject *parent) : QAbstractItemModel(parent) {}
void DbcTreeModel::SetTree(std::unique_ptr<TreeNode> root) {
if (root && (root->GetType() != NodeType::Root || root->GetParent()))
throw std::invalid_argument("Model requires a detached root node");
beginResetModel();
m_root = std::move(root);
endResetModel();
}
const TreeNode *DbcTreeModel::Node(const QModelIndex &index) const {
if (!index.isValid() || index.model() != this || index.column() < 0 ||
index.column() >= ColumnCount || index.row() < 0)
return nullptr;
return static_cast<const TreeNode *>(index.internalPointer());
}
QModelIndex DbcTreeModel::index(int row, int column, const QModelIndex &parentIndex) const {
if (row < 0 || column < 0 || column >= ColumnCount ||
(parentIndex.isValid() && parentIndex.column() != 0))
return {};
const TreeNode *owner = parentIndex.isValid() ? Node(parentIndex) : m_root.get();
if (!owner)
return {};
const TreeNode *child = owner->GetChild(static_cast<std::size_t>(row));
return child ? createIndex(row, column, const_cast<TreeNode *>(child)) : QModelIndex();
}
QModelIndex DbcTreeModel::parent(const QModelIndex &childIndex) const {
const TreeNode *child = Node(childIndex);
const TreeNode *owner = child ? child->GetParent() : nullptr;
if (!owner || owner == m_root.get())
return {};
return createIndex(static_cast<int>(owner->GetRow()), 0, const_cast<TreeNode *>(owner));
}
int DbcTreeModel::rowCount(const QModelIndex &parentIndex) const {
if (parentIndex.isValid() && parentIndex.column() != 0)
return 0;
const TreeNode *owner = parentIndex.isValid() ? Node(parentIndex) : m_root.get();
if (!owner)
return 0;
return static_cast<int>(qMin(owner->GetChildCount(), static_cast<std::size_t>(std::numeric_limits<int>::max())));
}
int DbcTreeModel::columnCount(const QModelIndex &parentIndex) const {
return parentIndex.isValid() && !Node(parentIndex) ? 0 : ColumnCount;
}
QVariant DbcTreeModel::data(const QModelIndex &item, int role) const {
const TreeNode *node = Node(item);
if (!node)
return {};
const FrameInfo *frame = node->GetFrame();
const SignalInfo *signal = node->GetSignal();
const QString comment = QString::fromStdString(frame ? frame->comment : signal ? signal->comment
: "");
if (role == Qt::ToolTipRole || role == CommentRole)
return comment;
if (role == NodeTypeRole)
return static_cast<int>(node->GetType());
if (role == ValueDescriptionsRole && signal) {
QVariantList descriptions;
for (const auto &entry: signal->valueDescriptions) {
QVariantMap pair;
if (const auto *number = std::get_if<std::int64_t>(&entry.first))
pair.insert("value", QVariant::fromValue(static_cast<qlonglong>(*number)));
else
pair.insert("value", QVariant::fromValue(static_cast<qulonglong>(std::get<std::uint64_t>(entry.first))));
pair.insert("description", QString::fromStdString(entry.second));
descriptions.append(pair);
}
return descriptions;
}
if (frame) {
if (role == CanIdRole) return frame->canId;
if (role == PayloadLengthRole) return static_cast<int>(frame->dlc);
if (role == ExtendedRole) return frame->isExtended;
}
if (signal) {
if (role == StartBitRole) return signal->startBit;
if (role == BitLengthRole) return signal->length;
if (role == LittleEndianRole) return signal->isLittleEndian;
if (role == SignedRole) return signal->isSigned;
if (role == UnitRole) return QString::fromStdString(signal->unit);
}
if (role != Qt::DisplayRole) return {};
switch (item.column()) {
case Name:
return QString::fromStdString(node->GetName());
case CanId:
return frame ? QVariant(QString("0x%1").arg(frame->canId, 0, 16).toUpper()) : QVariant();
case PayloadLength:
return frame ? QVariant(static_cast<int>(frame->dlc)) : QVariant();
case StartBit:
return signal ? QVariant(signal->startBit) : QVariant();
case BitLength:
return signal ? QVariant(signal->length) : QVariant();
case ByteOrder:
return signal ? QVariant(signal->isLittleEndian ? "Intel" : "Motorola") : QVariant();
case Signed:
return signal ? QVariant(signal->isSigned ? "Signed" : "Unsigned") : QVariant();
case Unit:
return signal ? QVariant(QString::fromStdString(signal->unit)) : QVariant();
case Comment:
return comment;
default:
return {};
}
}
QVariant DbcTreeModel::headerData(int section, Qt::Orientation orientation, int role) const {
static const char *const headers[] = {"Name", "CAN ID", "Payload (bytes)", "Start bit", "Length (bits)", "Byte order", "Signedness", "Unit", "Comment"};
if (orientation != Qt::Horizontal || role != Qt::DisplayRole || section < 0 || section >= ColumnCount)
return {};
return QString::fromLatin1(headers[section]);
}
Qt::ItemFlags DbcTreeModel::flags(const QModelIndex &item) const {
return Node(item) ? Qt::ItemIsEnabled | Qt::ItemIsSelectable : Qt::NoItemFlags;
}
+50
View File
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: MIT
#ifndef DBC_TREE_MODEL_H
#define DBC_TREE_MODEL_H
#include "tree_node.h"
#include <QAbstractItemModel>
/** Read-only model. Owns an immutable tree; all indexes expire on SetTree().
* Use QPersistentModelIndex to observe reset invalidation. Call on the model thread.
*/
class DbcTreeModel : public QAbstractItemModel {
public:
enum Column { Name,
CanId,
PayloadLength,
StartBit,
BitLength,
ByteOrder,
Signed,
Unit,
Comment,
ColumnCount };
// Metadata roles apply on every column; inapplicable roles return invalid QVariant.
enum Role { NodeTypeRole = Qt::UserRole + 1,
CanIdRole,
PayloadLengthRole,
StartBitRole,
BitLengthRole,
LittleEndianRole,
SignedRole,
UnitRole,
CommentRole,
ValueDescriptionsRole,
ExtendedRole };
explicit DbcTreeModel(QObject *parent = nullptr);
void SetTree(std::unique_ptr<TreeNode> root);
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
private:
const TreeNode *Node(const QModelIndex &index) const;
std::unique_ptr<TreeNode> m_root;
};
#endif
+11
View File
@@ -0,0 +1,11 @@
include($$PWD/../core/core.pri)
QT += core
INCLUDEPATH += $$PWD
isEmpty(DBC_QT_BUILD_DIR): DBC_QT_BUILD_DIR = $$clean_path($$OUT_PWD/../qt)
# Put the adapter before core for static linker dependency ordering.
LIBS = -L$$DBC_QT_BUILD_DIR -ldbc_qt $$LIBS
win32-msvc*: DBC_QT_LIBRARY = $$DBC_QT_BUILD_DIR/dbc_qt.lib
else: DBC_QT_LIBRARY = $$DBC_QT_BUILD_DIR/libdbc_qt.a
PRE_TARGETDEPS += $$DBC_QT_LIBRARY
CONFIG += no_keywords
+11
View File
@@ -0,0 +1,11 @@
TEMPLATE = lib
TARGET = dbc_qt
CONFIG += staticlib c++17
QT += core
QT -= gui
include(../core/core.pri)
HEADERS += dbc_tree_model.h
SOURCES += dbc_tree_model.cpp
CONFIG -= debug_and_release debug_and_release_target
CONFIG += no_keywords