Files
StarPilot/tools/cabana/messageswidget.cc
T
Dean Lee 62adf87f40 Cabana: stable initial release (#26004)
* increase form size & fix wrong charts number

* set max axisy to 1.0 if no value

* show 'close' button in floating window

* alwasy show scroll bar

* complete the logs

* more

* increase size to 50

* keep logs for all messages

* more

* rename signal

* better height

* avoid flicker

* dont call setupdatesenabled

* filter dbc files bye typing

* remove all charts if dbc file changed

* fix wrong idx

* bolder dbc filename

* update chart if signal has been edited

* new signals signalAdded,signalUpdated

* split class Parser into CanMessages and DBCManager

* cleanup

* updateState after set message

* cleanup

* emit msgUpdated

* clear history log if selected range changed

* always update time

* change title layout

* show selected range

hide title bar if no charts

less space between title and chart

* custome historylogmodel for extreme fast update

* move historylog to seperate file

* 2 decimal

* cleanup

cleanup

* left click on the chart to set start time

* todo

* show tooltip for header item&cleanup binaryview

add hline to signal form

* better paint

* cleanup signals/slots

* better range if min==max

* set historylog's minheight to 300

* 3x faster,sortable message list.

* zero copy in queued connection

* proxymodel

* clear log if loop to the begin

* simplify history log

* remove icon

* remove assets

* hide linemarker on initialization

* rubber width may less than 0

* dont zoom char if selected range is too small

* cleanup messageslist

* don't zoom chart if selected range less than 500ms

* typo

* check boundary

* check msg_id

* capital first letter

* move history log out of scrollarea

* Show only one form at a time

* auto scroll to header

d

* reduce msg size
entire row clickable

rename filter_msgs
old-commit-hash: 0fa1588f6c0bf9c9f1bebde91e02699506389ecd
2022-10-12 13:55:17 -07:00

138 lines
4.7 KiB
C++

#include "tools/cabana/messageswidget.h"
#include <QComboBox>
#include <QCompleter>
#include <QHeaderView>
#include <QLineEdit>
#include <QPushButton>
#include <QSortFilterProxyModel>
#include <QVBoxLayout>
#include "tools/cabana/dbcmanager.h"
MessagesWidget::MessagesWidget(QWidget *parent) : QWidget(parent) {
QVBoxLayout *main_layout = new QVBoxLayout(this);
// DBC file selector
QHBoxLayout *dbc_file_layout = new QHBoxLayout();
QComboBox *combo = new QComboBox(this);
auto dbc_names = dbc()->allDBCNames();
for (const auto &name : dbc_names) {
combo->addItem(QString::fromStdString(name));
}
combo->setEditable(true);
combo->setCurrentText(QString());
combo->setInsertPolicy(QComboBox::NoInsert);
combo->completer()->setCompletionMode(QCompleter::PopupCompletion);
QFont font;
font.setBold(true);
combo->lineEdit()->setFont(font);
dbc_file_layout->addWidget(combo);
dbc_file_layout->addStretch();
QPushButton *save_btn = new QPushButton(tr("Save DBC"), this);
dbc_file_layout->addWidget(save_btn);
main_layout->addLayout(dbc_file_layout);
// message filter
QLineEdit *filter = new QLineEdit(this);
filter->setPlaceholderText(tr("filter messages"));
main_layout->addWidget(filter);
// message table
table_widget = new QTableView(this);
model = new MessageListModel(this);
QSortFilterProxyModel *proxy_model = new QSortFilterProxyModel(this);
proxy_model->setSourceModel(model);
proxy_model->setFilterCaseSensitivity(Qt::CaseInsensitive);
proxy_model->setDynamicSortFilter(false);
table_widget->setModel(proxy_model);
table_widget->setSelectionBehavior(QAbstractItemView::SelectRows);
table_widget->setSelectionMode(QAbstractItemView::SingleSelection);
table_widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
table_widget->setSortingEnabled(true);
table_widget->setColumnWidth(0, 250);
table_widget->setColumnWidth(1, 80);
table_widget->setColumnWidth(2, 80);
table_widget->horizontalHeader()->setStretchLastSection(true);
table_widget->verticalHeader()->hide();
table_widget->sortByColumn(0, Qt::AscendingOrder);
main_layout->addWidget(table_widget);
// signals/slots
QObject::connect(filter, &QLineEdit::textChanged, proxy_model, &QSortFilterProxyModel::setFilterFixedString);
QObject::connect(can, &CANMessages::updated, model, &MessageListModel::updateState);
QObject::connect(combo, SIGNAL(activated(const QString &)), SLOT(dbcSelectionChanged(const QString &)));
QObject::connect(save_btn, &QPushButton::clicked, [=]() {
// TODO: save DBC to file
});
QObject::connect(table_widget->selectionModel(), &QItemSelectionModel::currentChanged, [=](const QModelIndex &current, const QModelIndex &previous) {
if (current.isValid()) {
emit msgSelectionChanged(table_widget->model()->data(current, Qt::UserRole).toString());
}
});
// For test purpose
combo->setCurrentText("toyota_nodsu_pt_generated");
}
void MessagesWidget::dbcSelectionChanged(const QString &dbc_file) {
dbc()->open(dbc_file);
// update detailwidget
auto current = table_widget->selectionModel()->currentIndex();
if (current.isValid()) {
emit msgSelectionChanged(table_widget->model()->data(current, Qt::UserRole).toString());
}
}
// MessageListModel
QVariant MessageListModel::headerData(int section, Qt::Orientation orientation, int role) const {
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return (QString[]){"Name", "ID", "Count", "Bytes"}[section];
else if (orientation == Qt::Vertical && role == Qt::DisplayRole) {
// return QString::number(section);
}
return {};
}
QVariant MessageListModel::data(const QModelIndex &index, int role) const {
if (role == Qt::DisplayRole) {
auto it = std::next(can->can_msgs.begin(), index.row());
if (it != can->can_msgs.end() && !it.value().empty()) {
const auto &d = it.value().front();
const QString &msg_id = it.key();
switch (index.column()) {
case 0: {
auto msg = dbc()->msg(msg_id);
QString name = msg ? msg->name.c_str() : "untitled";
return name;
}
case 1: return msg_id;
case 2: return can->counters[msg_id];
case 3: return toHex(d.dat);
}
}
} else if (role == Qt::UserRole) {
return std::next(can->can_msgs.begin(), index.row()).key();
}
return {};
}
void MessageListModel::updateState() {
int prev_row_count = row_count;
row_count = can->can_msgs.size();
int delta = row_count - prev_row_count;
if (delta > 0) {
beginInsertRows({}, prev_row_count, row_count - 1);
endInsertRows();
} else if (delta < 0) {
beginRemoveRows({}, row_count, prev_row_count - 1);
endRemoveRows();
}
if (row_count > 0) {
emit dataChanged(index(0, 0), index(row_count - 1, 3));
}
}