Skip to content

Commit 8d5c6a6

Browse files
committed
Finished implementing the Checkpoint feature.
1 parent 70d1912 commit 8d5c6a6

11 files changed

+515
-27
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"terminate" that switches to a "restart".
2020
* Fixed bug when adding variable to tracker. Sometimes would not refresh value.
2121
* Raise Logger or Tracker tab when new variable is added.
22+
* Implment gdb's "checkpoint" feature. As simple time-travel feature.
2223

2324
## [2.5] - 2024-12-24
2425
* Console now supports a subset of ANSI color codes.

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ set(HEADER_FILES
7676
SeerCatchpointsBrowserWidget.h
7777
SeerPrintpointCreateDialog.h
7878
SeerPrintpointsBrowserWidget.h
79+
SeerCheckpointsBrowserWidget.h
7980
SeerSeerLogWidget.h
8081
SeerConsoleWidget.h
8182
SeerConfigDialog.h
@@ -176,6 +177,7 @@ set(SOURCE_FILES
176177
SeerCatchpointsBrowserWidget.cpp
177178
SeerPrintpointCreateDialog.cpp
178179
SeerPrintpointsBrowserWidget.cpp
180+
SeerCheckpointsBrowserWidget.cpp
179181
SeerSeerLogWidget.cpp
180182
SeerConsoleWidget.cpp
181183
SeerConfigDialog.cpp

src/SeerCheckpointsBrowserWidget.cpp

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
#include "SeerCheckpointsBrowserWidget.h"
2+
#include "SeerUtl.h"
3+
#include <QtWidgets/QTreeWidget>
4+
#include <QtWidgets/QTreeWidgetItemIterator>
5+
#include <QtWidgets/QApplication>
6+
#include <QtWidgets/QMessageBox>
7+
#include <QtCore/QDebug>
8+
9+
SeerCheckpointsBrowserWidget::SeerCheckpointsBrowserWidget (QWidget* parent) : QWidget(parent) {
10+
11+
// Construct the UI.
12+
setupUi(this);
13+
14+
// Setup the widgets
15+
checkpointsTreeWidget->clear();
16+
17+
checkpointsTreeWidget->setSortingEnabled(false);
18+
checkpointsTreeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
19+
checkpointsTreeWidget->resizeColumnToContents(0); // state
20+
checkpointsTreeWidget->resizeColumnToContents(1); // number
21+
checkpointsTreeWidget->resizeColumnToContents(2); // process
22+
checkpointsTreeWidget->resizeColumnToContents(3); // file
23+
checkpointsTreeWidget->resizeColumnToContents(4); // line
24+
25+
// Connect things.
26+
QObject::connect(checkpointsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &SeerCheckpointsBrowserWidget::handleItemDoubleClicked);
27+
QObject::connect(refreshCheckpointsToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleRefreshToolButton);
28+
QObject::connect(addCheckpointToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleAddToolButton);
29+
QObject::connect(deleteCheckpointsToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleDeleteToolButton);
30+
QObject::connect(selectCheckpointToolButton, &QToolButton::clicked, this, &SeerCheckpointsBrowserWidget::handleSelectToolButton);
31+
}
32+
33+
SeerCheckpointsBrowserWidget::~SeerCheckpointsBrowserWidget () {
34+
}
35+
36+
void SeerCheckpointsBrowserWidget::handleText (const QString& text) {
37+
38+
// Don't do any work if the widget is hidden.
39+
if (isHidden()) {
40+
return;
41+
}
42+
43+
if (text.startsWith("^done,checkpoints=[") && text.endsWith("]")) {
44+
45+
//
46+
// "^done,checkpoints=[
47+
// {id="0",state="*",process="Thread 0x7ffff7e7f740 (LWP 31803) (main process) at 0x0",file="",line=""},
48+
// {id="1",state=" ",process="process 31806 at 0x55555555513f",file="hellostruct.cpp",line="49"},
49+
// {id="2",state=" ",process="process 31807 at 0x5555555552a0",file="hellostruct.cpp",line="62"}
50+
// ]
51+
//
52+
53+
checkpointsTreeWidget->clear();
54+
checkpointsTreeWidget->setSortingEnabled(false);
55+
checkpointsTreeWidget->sortByColumn(-1, Qt::AscendingOrder);
56+
57+
QString checkpoints_text = Seer::parseFirst(text, "checkpoints=", '[', ']', false);
58+
59+
QStringList checkpoints_list = Seer::parse(checkpoints_text, "", '{', '}', false);
60+
61+
for (const auto& checkpoint_entry : checkpoints_list) {
62+
63+
QString id_text = Seer::parseFirst(checkpoint_entry, "id=", '"', '"', false);
64+
QString state_text = Seer::parseFirst(checkpoint_entry, "state=", '"', '"', false);
65+
QString process_text = Seer::parseFirst(checkpoint_entry, "process=", '"', '"', false);
66+
QString file_text = Seer::parseFirst(checkpoint_entry, "file=", '"', '"', false);
67+
QString line_text = Seer::parseFirst(checkpoint_entry, "line=", '"', '"', false);
68+
69+
// Add the function to the tree.
70+
QTreeWidgetItem* item = new QTreeWidgetItem;
71+
72+
item->setText(0, state_text);
73+
item->setText(1, id_text);
74+
item->setText(2, process_text);
75+
item->setText(3, file_text);
76+
item->setText(4, line_text);
77+
78+
checkpointsTreeWidget->addTopLevelItem(item);
79+
}
80+
}else{
81+
// Ignore others.
82+
}
83+
84+
checkpointsTreeWidget->resizeColumnToContents(0);
85+
checkpointsTreeWidget->resizeColumnToContents(1);
86+
checkpointsTreeWidget->resizeColumnToContents(2);
87+
checkpointsTreeWidget->resizeColumnToContents(3);
88+
checkpointsTreeWidget->resizeColumnToContents(4);
89+
90+
QApplication::restoreOverrideCursor();
91+
}
92+
93+
void SeerCheckpointsBrowserWidget::handleStoppingPointReached () {
94+
95+
// Don't do any work if the widget is hidden.
96+
if (isHidden()) {
97+
return;
98+
}
99+
100+
emit refreshCheckpointsList();
101+
}
102+
103+
void SeerCheckpointsBrowserWidget::handleSessionTerminated () {
104+
105+
// Delete previous contents.
106+
checkpointsTreeWidget->clear();
107+
}
108+
109+
void SeerCheckpointsBrowserWidget::handleItemDoubleClicked (QTreeWidgetItem* item, int column) {
110+
111+
Q_UNUSED(column);
112+
113+
emit selectCheckpoint(item->text(1));
114+
}
115+
116+
void SeerCheckpointsBrowserWidget::handleRefreshToolButton () {
117+
118+
emit refreshCheckpointsList();
119+
}
120+
121+
void SeerCheckpointsBrowserWidget::handleAddToolButton () {
122+
123+
// Otherwise send the command to create the checkpoint.
124+
emit insertCheckpoint();
125+
}
126+
127+
void SeerCheckpointsBrowserWidget::handleSelectToolButton () {
128+
129+
// Any items in the tree?
130+
if (checkpointsTreeWidget->topLevelItemCount() == 0) {
131+
QMessageBox::warning(this, "Seer", QString("There are no checkpoints to switch to."), QMessageBox::Ok, QMessageBox::Ok);
132+
return;
133+
}
134+
135+
// Get selected tree items.
136+
QList<QTreeWidgetItem*> items = checkpointsTreeWidget->selectedItems();
137+
138+
if (items.count() == 0) {
139+
QMessageBox::warning(this, "Seer", QString("Selected a checkpoint to switch to."), QMessageBox::Ok, QMessageBox::Ok);
140+
return;
141+
}
142+
143+
if (items.count() > 1) {
144+
QMessageBox::warning(this, "Seer", QString("Select only 1 checkpoint to switch to."), QMessageBox::Ok, QMessageBox::Ok);
145+
return;
146+
}
147+
148+
// Build a string that is a list of checkpoints.
149+
QString checkpoints;
150+
151+
QList<QTreeWidgetItem*>::iterator i;
152+
for (i = items.begin(); i != items.end(); ++i) {
153+
154+
if (i != items.begin()) {
155+
checkpoints += " ";
156+
}
157+
158+
checkpoints += (*i)->text(1);
159+
}
160+
161+
// Don't do anything if the list of checkpoints is empty.
162+
if (checkpoints == "") {
163+
return;
164+
}
165+
166+
// Send the signal.
167+
emit selectCheckpoint(checkpoints);
168+
}
169+
170+
void SeerCheckpointsBrowserWidget::handleDeleteToolButton () {
171+
172+
// Any items in the tree?
173+
if (checkpointsTreeWidget->topLevelItemCount() == 0) {
174+
QMessageBox::warning(this, "Seer", QString("There are no checkpoints to delete."), QMessageBox::Ok, QMessageBox::Ok);
175+
return;
176+
}
177+
178+
// Get selected tree items.
179+
QList<QTreeWidgetItem*> items = checkpointsTreeWidget->selectedItems();
180+
181+
if (items.count() == 0) {
182+
QMessageBox::warning(this, "Seer", QString("Select checkpoints to delete."), QMessageBox::Ok, QMessageBox::Ok);
183+
return;
184+
}
185+
186+
// Build a string that is a list of checkpoints.
187+
QString checkpoints;
188+
189+
QList<QTreeWidgetItem*>::iterator i;
190+
for (i = items.begin(); i != items.end(); ++i) {
191+
if (i != items.begin()) {
192+
checkpoints += " ";
193+
}
194+
checkpoints += (*i)->text(1);
195+
}
196+
197+
// Don't do anything if the list of checkpoints is empty.
198+
if (checkpoints == "") {
199+
return;
200+
}
201+
202+
// Send the signal.
203+
emit deleteCheckpoints(checkpoints);
204+
}
205+
206+
void SeerCheckpointsBrowserWidget::showEvent (QShowEvent* event) {
207+
208+
QWidget::showEvent(event);
209+
210+
emit refreshCheckpointsList();
211+
}
212+

src/SeerCheckpointsBrowserWidget.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#pragma once
2+
3+
#include <QtWidgets/QWidget>
4+
#include <QtCore/QString>
5+
#include <QtCore/QStringList>
6+
#include "ui_SeerCheckpointsBrowserWidget.h"
7+
8+
class SeerCheckpointsBrowserWidget : public QWidget, protected Ui::SeerCheckpointsBrowserWidgetForm {
9+
10+
Q_OBJECT
11+
12+
public:
13+
explicit SeerCheckpointsBrowserWidget (QWidget* parent = 0);
14+
~SeerCheckpointsBrowserWidget ();
15+
16+
public slots:
17+
void handleText (const QString& text);
18+
void handleStoppingPointReached ();
19+
void handleSessionTerminated ();
20+
21+
private slots:
22+
void handleItemDoubleClicked (QTreeWidgetItem* item, int column);
23+
void handleRefreshToolButton ();
24+
void handleAddToolButton ();
25+
void handleDeleteToolButton ();
26+
void handleSelectToolButton ();
27+
28+
signals:
29+
void refreshCheckpointsList ();
30+
void insertCheckpoint ();
31+
void selectCheckpoint (QString checkpoint);
32+
void deleteCheckpoints (QString checkpoints);
33+
34+
protected:
35+
void showEvent (QShowEvent* event);
36+
37+
private:
38+
};
39+

0 commit comments

Comments
 (0)