129 lines
5.5 KiB
C++
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;
|
|
}
|