mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-02-18 20:03:53 +08:00
cabana: add automatic session save/restore (#36736)
adds auto session save/store
This commit is contained in:
@@ -275,16 +275,13 @@ void BinaryViewModel::refresh() {
|
||||
row_count = can->lastMessage(msg_id).dat.size();
|
||||
items.resize(row_count * column_count);
|
||||
}
|
||||
int valid_rows = std::min<int>(can->lastMessage(msg_id).dat.size(), row_count);
|
||||
for (int i = 0; i < valid_rows * column_count; ++i) {
|
||||
items[i].valid = true;
|
||||
}
|
||||
endResetModel();
|
||||
updateState();
|
||||
}
|
||||
|
||||
void BinaryViewModel::updateItem(int row, int col, uint8_t val, const QColor &color) {
|
||||
auto &item = items[row * column_count + col];
|
||||
item.valid = true;
|
||||
if (item.val != val || item.bg_color != color) {
|
||||
item.val = val;
|
||||
item.bg_color = color;
|
||||
|
||||
@@ -322,6 +322,32 @@ void ChartsWidget::splitChart(ChartView *src_chart) {
|
||||
}
|
||||
}
|
||||
|
||||
QStringList ChartsWidget::serializeChartIds() const {
|
||||
QStringList chart_ids;
|
||||
for (auto c : charts) {
|
||||
QStringList ids;
|
||||
for (const auto& s : c->sigs)
|
||||
ids += QString("%1|%2").arg(s.msg_id.toString(), s.sig->name);
|
||||
chart_ids += ids.join(',');
|
||||
}
|
||||
std::reverse(chart_ids.begin(), chart_ids.end());
|
||||
return chart_ids;
|
||||
}
|
||||
|
||||
void ChartsWidget::restoreChartsFromIds(const QStringList& chart_ids) {
|
||||
for (const auto& chart_id : chart_ids) {
|
||||
int index = 0;
|
||||
for (const auto& part : chart_id.split(',')) {
|
||||
const auto sig_parts = part.split('|');
|
||||
if (sig_parts.size() != 2) continue;
|
||||
MessageId msg_id = MessageId::fromString(sig_parts[0]);
|
||||
if (auto* msg = dbc()->msg(msg_id))
|
||||
if (auto* sig = msg->sig(sig_parts[1]))
|
||||
showChart(msg_id, sig, true, index++ > 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChartsWidget::setColumnCount(int n) {
|
||||
n = std::clamp(n, 1, MAX_COLUMN_COUNT);
|
||||
if (column_count != n) {
|
||||
|
||||
@@ -43,6 +43,8 @@ public:
|
||||
ChartsWidget(QWidget *parent = nullptr);
|
||||
void showChart(const MessageId &id, const cabana::Signal *sig, bool show, bool merge);
|
||||
inline bool hasSignal(const MessageId &id, const cabana::Signal *sig) { return findChart(id, sig) != nullptr; }
|
||||
QStringList serializeChartIds() const;
|
||||
void restoreChartsFromIds(const QStringList &chart_ids);
|
||||
|
||||
public slots:
|
||||
void setColumnCount(int n);
|
||||
|
||||
@@ -20,6 +20,12 @@ struct MessageId {
|
||||
return QString("%1:%2").arg(source).arg(QString::number(address, 16).toUpper());
|
||||
}
|
||||
|
||||
inline static MessageId fromString(const QString &str) {
|
||||
auto parts = str.split(':');
|
||||
if (parts.size() != 2) return {};
|
||||
return MessageId{.source = uint8_t(parts[0].toUInt()), .address = parts[1].toUInt(nullptr, 16)};
|
||||
}
|
||||
|
||||
bool operator==(const MessageId &other) const {
|
||||
return source == other.source && address == other.address;
|
||||
}
|
||||
|
||||
@@ -118,10 +118,7 @@ void DetailWidget::showTabBarContextMenu(const QPoint &pt) {
|
||||
}
|
||||
}
|
||||
|
||||
void DetailWidget::setMessage(const MessageId &message_id) {
|
||||
if (std::exchange(msg_id, message_id) == message_id) return;
|
||||
|
||||
tabbar->blockSignals(true);
|
||||
int DetailWidget::findOrAddTab(const MessageId& message_id) {
|
||||
int index = tabbar->count() - 1;
|
||||
for (/**/; index >= 0; --index) {
|
||||
if (tabbar->tabData(index).value<MessageId>() == message_id) break;
|
||||
@@ -131,6 +128,14 @@ void DetailWidget::setMessage(const MessageId &message_id) {
|
||||
tabbar->setTabData(index, QVariant::fromValue(message_id));
|
||||
tabbar->setTabToolTip(index, msgName(message_id));
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
void DetailWidget::setMessage(const MessageId &message_id) {
|
||||
if (std::exchange(msg_id, message_id) == message_id) return;
|
||||
|
||||
tabbar->blockSignals(true);
|
||||
int index = findOrAddTab(message_id);
|
||||
tabbar->setCurrentIndex(index);
|
||||
tabbar->blockSignals(false);
|
||||
|
||||
@@ -142,6 +147,29 @@ void DetailWidget::setMessage(const MessageId &message_id) {
|
||||
setUpdatesEnabled(true);
|
||||
}
|
||||
|
||||
std::pair<QString, QStringList> DetailWidget::serializeMessageIds() const {
|
||||
QStringList msgs;
|
||||
for (int i = 0; i < tabbar->count(); ++i) {
|
||||
MessageId id = tabbar->tabData(i).value<MessageId>();
|
||||
msgs.append(id.toString());
|
||||
}
|
||||
return std::make_pair(msg_id.toString(), msgs);
|
||||
}
|
||||
|
||||
void DetailWidget::restoreTabs(const QString active_msg_id, const QStringList& msg_ids) {
|
||||
tabbar->blockSignals(true);
|
||||
for (const auto& str_id : msg_ids) {
|
||||
MessageId id = MessageId::fromString(str_id);
|
||||
if (dbc()->msg(id) != nullptr)
|
||||
findOrAddTab(id);
|
||||
}
|
||||
tabbar->blockSignals(false);
|
||||
|
||||
auto active_id = MessageId::fromString(active_msg_id);
|
||||
if (dbc()->msg(active_id) != nullptr)
|
||||
setMessage(active_id);
|
||||
}
|
||||
|
||||
void DetailWidget::refresh() {
|
||||
QStringList warnings;
|
||||
auto msg = dbc()->msg(msg_id);
|
||||
@@ -244,13 +272,13 @@ CenterWidget::CenterWidget(QWidget *parent) : QWidget(parent) {
|
||||
main_layout->addWidget(welcome_widget = createWelcomeWidget());
|
||||
}
|
||||
|
||||
void CenterWidget::setMessage(const MessageId &msg_id) {
|
||||
DetailWidget* CenterWidget::ensureDetailWidget() {
|
||||
if (!detail_widget) {
|
||||
delete welcome_widget;
|
||||
welcome_widget = nullptr;
|
||||
layout()->addWidget(detail_widget = new DetailWidget(((MainWindow*)parentWidget())->charts_widget, this));
|
||||
}
|
||||
detail_widget->setMessage(msg_id);
|
||||
return detail_widget;
|
||||
}
|
||||
|
||||
void CenterWidget::clear() {
|
||||
|
||||
@@ -34,9 +34,12 @@ public:
|
||||
DetailWidget(ChartsWidget *charts, QWidget *parent);
|
||||
void setMessage(const MessageId &message_id);
|
||||
void refresh();
|
||||
std::pair<QString, QStringList> serializeMessageIds() const;
|
||||
void restoreTabs(const QString active_msg_id, const QStringList &msg_ids);
|
||||
|
||||
private:
|
||||
void createToolBar();
|
||||
int findOrAddTab(const MessageId& message_id);
|
||||
void showTabBarContextMenu(const QPoint &pt);
|
||||
void editMsg();
|
||||
void removeMsg();
|
||||
@@ -60,7 +63,9 @@ class CenterWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
CenterWidget(QWidget *parent);
|
||||
void setMessage(const MessageId &msg_id);
|
||||
void setMessage(const MessageId &message_id) { ensureDetailWidget()->setMessage(message_id); }
|
||||
DetailWidget* getDetailWidget() { return detail_widget; }
|
||||
DetailWidget* ensureDetailWidget();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
|
||||
@@ -235,6 +235,8 @@ void MainWindow::DBCFileChanged() {
|
||||
title.push_back(tr("(%1) %2").arg(toString(dbc()->sources(f)), f->name()));
|
||||
}
|
||||
setWindowFilePath(title.join(" | "));
|
||||
|
||||
QTimer::singleShot(0, this, &::MainWindow::restoreSessionState);
|
||||
}
|
||||
|
||||
void MainWindow::selectAndOpenStream() {
|
||||
@@ -563,6 +565,7 @@ void MainWindow::closeEvent(QCloseEvent *event) {
|
||||
settings.message_header_state = messages_widget->saveHeaderState();
|
||||
}
|
||||
|
||||
saveSessionState();
|
||||
QWidget::closeEvent(event);
|
||||
}
|
||||
|
||||
@@ -607,6 +610,39 @@ void MainWindow::toggleFullScreen() {
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::saveSessionState() {
|
||||
settings.recent_dbc_file = "";
|
||||
settings.active_msg_id = "";
|
||||
settings.selected_msg_ids.clear();
|
||||
settings.active_charts.clear();
|
||||
|
||||
for (auto &f : dbc()->allDBCFiles())
|
||||
if (!f->isEmpty()) { settings.recent_dbc_file = f->filename; break; }
|
||||
|
||||
if (auto *detail = center_widget->getDetailWidget()) {
|
||||
auto [active_id, ids] = detail->serializeMessageIds();
|
||||
settings.active_msg_id = active_id;
|
||||
settings.selected_msg_ids = ids;
|
||||
}
|
||||
if (charts_widget)
|
||||
settings.active_charts = charts_widget->serializeChartIds();
|
||||
}
|
||||
|
||||
void MainWindow::restoreSessionState() {
|
||||
if (settings.recent_dbc_file.isEmpty() || dbc()->nonEmptyDBCCount() == 0) return;
|
||||
|
||||
QString dbc_file;
|
||||
for (auto& f : dbc()->allDBCFiles())
|
||||
if (!f->isEmpty()) { dbc_file = f->filename; break; }
|
||||
if (dbc_file != settings.recent_dbc_file) return;
|
||||
|
||||
if (!settings.selected_msg_ids.isEmpty())
|
||||
center_widget->ensureDetailWidget()->restoreTabs(settings.active_msg_id, settings.selected_msg_ids);
|
||||
|
||||
if (charts_widget != nullptr && !settings.active_charts.empty())
|
||||
charts_widget->restoreChartsFromIds(settings.active_charts);
|
||||
}
|
||||
|
||||
// HelpOverlay
|
||||
HelpOverlay::HelpOverlay(MainWindow *parent) : QWidget(parent) {
|
||||
setAttribute(Qt::WA_NoSystemBackground, true);
|
||||
|
||||
@@ -72,6 +72,8 @@ protected:
|
||||
void updateLoadSaveMenus();
|
||||
void createDockWidgets();
|
||||
void eventsMerged();
|
||||
void saveSessionState();
|
||||
void restoreSessionState();
|
||||
|
||||
VideoWidget *video_widget = nullptr;
|
||||
QDockWidget *video_dock;
|
||||
|
||||
@@ -41,6 +41,10 @@ void settings_op(SettingOperation op) {
|
||||
op(s, "log_path", settings.log_path);
|
||||
op(s, "drag_direction", (int &)settings.drag_direction);
|
||||
op(s, "suppress_defined_signals", settings.suppress_defined_signals);
|
||||
op(s, "recent_dbc_file", settings.recent_dbc_file);
|
||||
op(s, "active_msg_id", settings.active_msg_id);
|
||||
op(s, "selected_msg_ids", settings.selected_msg_ids);
|
||||
op(s, "active_charts", settings.active_charts);
|
||||
}
|
||||
|
||||
Settings::Settings() {
|
||||
|
||||
@@ -46,6 +46,12 @@ public:
|
||||
QByteArray message_header_state;
|
||||
DragDirection drag_direction = MsbFirst;
|
||||
|
||||
// session data
|
||||
QString recent_dbc_file;
|
||||
QString active_msg_id;
|
||||
QStringList selected_msg_ids;
|
||||
QStringList active_charts;
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user