DBC Framework
DBC parsing and CAN signal decoding framework
Loading...
Searching...
No Matches
dbc_tree_model.cpp
1// SPDX-License-Identifier: MIT
2#include "dbc_tree_model.h"
3#include <QVariantList>
4#include <QVariantMap>
5#include <limits>
6#include <stdexcept>
7
8namespace {
9 QVariantList ToVariantList(const ValueDescriptions &values) {
10 QVariantList descriptions;
11 for (const ValueDescriptions::value_type &entry : values) {
12 QVariantMap pair;
13 if (const std::int64_t *number = std::get_if<std::int64_t>(&entry.first))
14 pair.insert("value", QVariant::fromValue(static_cast<qlonglong>(*number)));
15 else
16 pair.insert("value", QVariant::fromValue(
17 static_cast<qulonglong>(std::get<std::uint64_t>(entry.first))));
18 pair.insert("description", QString::fromStdString(entry.second));
19 descriptions.append(pair);
20 }
21 return descriptions;
22 }
23} // namespace
24
25DbcTreeModel::DbcTreeModel(QObject *parent) : QAbstractItemModel(parent) {}
26
27void DbcTreeModel::SetTree(std::unique_ptr<TreeNode> root) {
28 if (root && (root->GetType() != NodeType::Root || root->GetParent()))
29 throw std::invalid_argument("Model requires a detached root node");
30 beginResetModel();
31 m_root = std::move(root);
32 endResetModel();
33}
34
35const TreeNode *DbcTreeModel::Node(const QModelIndex &index) const {
36 if (!index.isValid() || index.model() != this || index.column() < 0 ||
37 index.column() >= ColumnCount || index.row() < 0)
38 return nullptr;
39 return static_cast<const TreeNode *>(index.internalPointer());
40}
41
42QModelIndex DbcTreeModel::index(int row, int column, const QModelIndex &parentIndex) const {
43 if (row < 0 || column < 0 || column >= ColumnCount ||
44 (parentIndex.isValid() && parentIndex.column() != 0))
45 return {};
46 const TreeNode *owner = parentIndex.isValid() ? Node(parentIndex) : m_root.get();
47 if (!owner)
48 return {};
49 const TreeNode *child = owner->GetChild(static_cast<std::size_t>(row));
50 return child ? createIndex(row, column, const_cast<TreeNode *>(child)) : QModelIndex();
51}
52
53QModelIndex DbcTreeModel::parent(const QModelIndex &childIndex) const {
54 const TreeNode *child = Node(childIndex);
55 const TreeNode *owner = child ? child->GetParent() : nullptr;
56 if (!owner || owner == m_root.get())
57 return {};
58 return createIndex(static_cast<int>(owner->GetRow()), 0, const_cast<TreeNode *>(owner));
59}
60
61int DbcTreeModel::rowCount(const QModelIndex &parentIndex) const {
62 if (parentIndex.isValid() && parentIndex.column() != 0)
63 return 0;
64 const TreeNode *owner = parentIndex.isValid() ? Node(parentIndex) : m_root.get();
65 if (!owner)
66 return 0;
67 return static_cast<int>(qMin(owner->GetChildCount(), static_cast<std::size_t>(std::numeric_limits<int>::max())));
68}
69
70int DbcTreeModel::columnCount(const QModelIndex &parentIndex) const {
71 return parentIndex.isValid() && !Node(parentIndex) ? 0 : ColumnCount;
72}
73
74QVariant DbcTreeModel::data(const QModelIndex &item, int role) const {
75 const TreeNode *node = Node(item);
76 if (!node)
77 return {};
78 const FrameInfo *frame = node->GetFrame();
79 const SignalInfo *signal = node->GetSignal();
80 QString comment;
81 if (frame != nullptr)
82 comment = QString::fromStdString(frame->comment);
83 else if (signal != nullptr)
84 comment = QString::fromStdString(signal->comment);
85 if (role == Qt::ToolTipRole || role == CommentRole)
86 return comment;
87 if (role == NodeTypeRole)
88 return static_cast<int>(node->GetType());
89 if (role == ValueDescriptionsRole && signal) {
90 return ToVariantList(signal->valueDescriptions);
91 }
92 if (frame) {
93 if (role == CanIdRole)
94 return frame->canId;
95 if (role == PayloadLengthRole)
96 return static_cast<int>(frame->dlc);
97 if (role == ExtendedRole)
98 return frame->isExtended;
99 }
100 if (signal) {
101 if (role == StartBitRole)
102 return signal->startBit;
103 if (role == BitLengthRole)
104 return signal->length;
105 if (role == LittleEndianRole)
106 return signal->isLittleEndian;
107 if (role == SignedRole)
108 return signal->isSigned;
109 if (role == UnitRole)
110 return QString::fromStdString(signal->unit);
111 }
112 if (role != Qt::DisplayRole)
113 return {};
114 switch (item.column()) {
115 case Name:
116 return QString::fromStdString(node->GetName());
117 case CanId:
118 return frame ? QVariant(QString("0x%1").arg(frame->canId, 0, 16).toUpper()) : QVariant();
119 case PayloadLength:
120 return frame ? QVariant(static_cast<int>(frame->dlc)) : QVariant();
121 case StartBit:
122 return signal ? QVariant(signal->startBit) : QVariant();
123 case BitLength:
124 return signal ? QVariant(signal->length) : QVariant();
125 case ByteOrder:
126 return signal ? QVariant(signal->isLittleEndian ? "Intel" : "Motorola") : QVariant();
127 case Signed:
128 return signal ? QVariant(signal->isSigned ? "Signed" : "Unsigned") : QVariant();
129 case Unit:
130 return signal ? QVariant(QString::fromStdString(signal->unit)) : QVariant();
131 case Comment:
132 return comment;
133 default:
134 return {};
135 }
136}
137
138QVariant DbcTreeModel::headerData(int section, Qt::Orientation orientation, int role) const {
139 static const char *const headers[] = {"Name", "CAN ID", "Payload (bytes)", "Start bit", "Length (bits)", "Byte order", "Signedness", "Unit", "Comment"};
140 if (orientation != Qt::Horizontal || role != Qt::DisplayRole || section < 0 || section >= ColumnCount)
141 return {};
142 return QString::fromLatin1(headers[section]);
143}
144
145Qt::ItemFlags DbcTreeModel::flags(const QModelIndex &item) const {
146 return Node(item) ? Qt::ItemIsEnabled | Qt::ItemIsSelectable : Qt::NoItemFlags;
147}
Tree node for later use in model/view or other hierarchy consumers.
Definition tree_node.h:35
const SignalInfo * GetSignal() const
Get signal payload if node is signal.
Definition tree_node.cpp:64
const TreeNode * GetChild(std::size_t index) const
Get child by index.
Definition tree_node.cpp:38
const TreeNode * GetParent() const
Definition tree_node.cpp:68
const std::string & GetName() const
Get display name.
Definition tree_node.cpp:56
std::size_t GetChildCount() const
Get child count.
Definition tree_node.cpp:34
std::size_t GetRow() const
Definition tree_node.cpp:72
NodeType GetType() const
Get node type.
Definition tree_node.cpp:52
const FrameInfo * GetFrame() const
Get frame payload if node is frame.
Definition tree_node.cpp:60
ByteOrder
Signal byte order used for runtime decoding.
Describes one CAN frame from a DBC file.
Definition frame_info.h:24
bool isExtended
Definition frame_info.h:27
std::uint8_t dlc
Definition frame_info.h:30
std::string comment
Definition frame_info.h:32
std::uint32_t canId
Definition frame_info.h:26
Describes one signal inside a DBC frame.
Definition signal_info.h:24
std::uint32_t length
Definition signal_info.h:28
std::string unit
Definition signal_info.h:35
ValueDescriptions valueDescriptions
Definition signal_info.h:37
bool isSigned
Definition signal_info.h:30
std::string comment
Definition signal_info.h:38
std::uint32_t startBit
Definition signal_info.h:27
bool isLittleEndian
Definition signal_info.h:29