Files
dbc/qt/dbc_tree_model.cpp
T
2026-10-06 17:14:50 -04:00

129 lines
5.5 KiB
C++

// 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;
}