2025-08-26 17:26:05 -05:00
// SPDX-FileCopyrightText: 2021 Ernie Pasveer <epasveer@att.net>
//
// SPDX-License-Identifier: GPL-3.0-or-later
2021-09-01 13:58:59 -05:00
# include "SeerBreakpointsBrowserWidget.h"
# include "SeerBreakpointCreateDialog.h"
# include "SeerUtl.h"
# include <QtWidgets/QTreeWidget>
# include <QtWidgets/QTreeWidgetItemIterator>
# include <QtWidgets/QApplication>
2023-06-13 17:56:13 -05:00
# include <QtWidgets/QMessageBox>
# include <QtWidgets/QInputDialog>
2022-02-28 20:49:34 -06:00
# include <QtCore/QFileInfo>
2021-09-01 13:58:59 -05:00
# include <QtCore/QDebug>
SeerBreakpointsBrowserWidget : : SeerBreakpointsBrowserWidget ( QWidget * parent ) : QWidget ( parent ) {
// Construct the UI.
setupUi ( this ) ;
// Setup the widgets
breakpointsTreeWidget - > clear ( ) ;
breakpointsTreeWidget - > setSortingEnabled ( false ) ;
breakpointsTreeWidget - > setSelectionMode ( QAbstractItemView : : ExtendedSelection ) ;
breakpointsTreeWidget - > resizeColumnToContents ( 0 ) ; // number
breakpointsTreeWidget - > resizeColumnToContents ( 1 ) ; // type
breakpointsTreeWidget - > resizeColumnToContents ( 2 ) ; // disp
breakpointsTreeWidget - > resizeColumnToContents ( 3 ) ; // enabled
breakpointsTreeWidget - > resizeColumnToContents ( 4 ) ; // addr
//breakpointsTreeWidget->resizeColumnToContents(5); // func Too long to show
breakpointsTreeWidget - > resizeColumnToContents ( 6 ) ; // file
//breakpointsTreeWidget->resizeColumnToContents(7); // fullname Too long to show
breakpointsTreeWidget - > resizeColumnToContents ( 8 ) ; // line
breakpointsTreeWidget - > resizeColumnToContents ( 9 ) ; // thread-groups
2023-01-11 19:58:22 -06:00
breakpointsTreeWidget - > resizeColumnToContents ( 10 ) ; // cond
breakpointsTreeWidget - > resizeColumnToContents ( 11 ) ; // times
breakpointsTreeWidget - > resizeColumnToContents ( 12 ) ; // ignore
2023-07-04 11:08:33 -05:00
//breakpointsTreeWidget->resizeColumnToContents(13); // script Too long to show
breakpointsTreeWidget - > resizeColumnToContents ( 14 ) ; // original-location
2021-09-01 13:58:59 -05:00
/*
breakpointsTreeWidget->setColumnHidden(1, true); // ??? Hide or have a config to hide/show columns.
breakpointsTreeWidget->setColumnHidden(6, true);
*/
// Connect things.
QObject : : connect ( breakpointsTreeWidget , & QTreeWidget : : itemDoubleClicked , this , & SeerBreakpointsBrowserWidget : : handleItemDoubleClicked ) ;
QObject : : connect ( refreshBreakpointsToolButton , & QToolButton : : clicked , this , & SeerBreakpointsBrowserWidget : : handleRefreshToolButton ) ;
QObject : : connect ( addBreakpointToolButton , & QToolButton : : clicked , this , & SeerBreakpointsBrowserWidget : : handleAddToolButton ) ;
QObject : : connect ( deleteBreakpointsToolButton , & QToolButton : : clicked , this , & SeerBreakpointsBrowserWidget : : handleDeleteToolButton ) ;
QObject : : connect ( enableBreakpointsToolButton , & QToolButton : : clicked , this , & SeerBreakpointsBrowserWidget : : handleEnableToolButton ) ;
QObject : : connect ( disableBreakpointsToolButton , & QToolButton : : clicked , this , & SeerBreakpointsBrowserWidget : : handleDisableToolButton ) ;
2023-06-13 17:56:13 -05:00
QObject : : connect ( conditionBreakpointToolButton , & QToolButton : : clicked , this , & SeerBreakpointsBrowserWidget : : handleConditionToolButton ) ;
QObject : : connect ( ignoreBreakpointToolButton , & QToolButton : : clicked , this , & SeerBreakpointsBrowserWidget : : handleIgnoreToolButton ) ;
QObject : : connect ( commandsBreakpointToolButton , & QToolButton : : clicked , this , & SeerBreakpointsBrowserWidget : : handleCommandsToolButton ) ;
2021-09-01 13:58:59 -05:00
}
SeerBreakpointsBrowserWidget : : ~ SeerBreakpointsBrowserWidget ( ) {
}
2022-03-05 16:40:37 -06:00
bool SeerBreakpointsBrowserWidget : : isEmpty ( ) const {
return ( breakpointsTreeWidget - > topLevelItemCount ( ) = = 0 ) ;
}
2024-01-22 17:49:43 -06:00
QStringList SeerBreakpointsBrowserWidget : : breakpoints ( ) const {
return QStringList ( ) ;
}
2021-09-01 13:58:59 -05:00
void SeerBreakpointsBrowserWidget : : handleText ( const QString & text ) {
// Don't do any work if the widget is hidden.
if ( isHidden ( ) ) {
return ;
}
QApplication : : setOverrideCursor ( Qt : : BusyCursor ) ;
if ( text . startsWith ( " ^done,BreakpointTable={ " ) & & text . endsWith ( " } " ) ) {
breakpointsTreeWidget - > clear ( ) ;
//
// ^done,BreakpointTable={
// nr_rows="2",nr_cols="6",
//
// hdr=[
// {width="7",alignment="-1",col_name="number",colhdr="Num"},
// {width="14",alignment="-1",col_name="type",colhdr="Type"},
// {width="4",alignment="-1",col_name="disp",colhdr="Disp"},
// {width="3",alignment="-1",col_name="enabled",colhdr="Enb"},
// {width="18",alignment="-1",col_name="addr",colhdr="Address"},
// {width="40",alignment="2",col_name="what",colhdr="What"}
// ],
//
// body=[
// bkpt={number="2",type="breakpoint",disp="keep",enabled="y",addr="0x0000000000400c17",func="main(int, char**)",file="helloworld.cpp",fullname="/home/erniep/Development/Peak/src/Seer/helloworld/helloworld.cpp",line="8",thread-groups=["i1"],times="0",original-location="main"},
// bkpt={number="3",
// type="breakpoint",
// disp="keep",
// enabled="y",
// addr="0x0000000000400d72",
// func="function1(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)",
// file="function1.cpp",
// fullname="/home/erniep/Development/Peak/src/Seer/helloworld/function1.cpp",
// line="7",
// thread-groups=["i1"],
2023-01-11 19:58:22 -06:00
// cond="1 == 1",
2021-09-01 13:58:59 -05:00
// times="0",
2023-07-04 11:08:33 -05:00
// script={"print i argc"},
2021-09-01 13:58:59 -05:00
// original-location="function1"}
// ]
// }
//
2023-11-24 13:11:49 -06:00
//qDebug().noquote() << bkpt_list;
2021-09-01 13:58:59 -05:00
2023-11-24 13:11:49 -06:00
QString newtext = Seer : : filterEscapes ( text ) ; // Filter escaped characters.
2021-09-01 13:58:59 -05:00
2023-11-24 13:11:49 -06:00
QString body_text = Seer : : parseFirst ( text , " body= " , ' [ ' , ' ] ' , false ) ;
2021-09-01 13:58:59 -05:00
if ( body_text ! = " " ) {
QStringList bkpt_list = Seer : : parse ( newtext , " bkpt= " , ' { ' , ' } ' , false ) ;
2024-09-11 17:34:46 -05:00
for ( const auto & bkpt_text : bkpt_list ) {
2023-11-24 13:11:49 -06:00
//
// A different way (better?) of parsing the table output
//
// Divide test into a list, delimited by a ','.
// Then morph that list into a map, delimited by a '='.
// Remove bookends.
//
2024-11-29 10:58:36 -06:00
QStringList items = Seer : : parseCommaList ( bkpt_text , ' [ ' , ' ] ' ) ;
2023-11-24 13:11:49 -06:00
QMap < QString , QString > keyValueMap = Seer : : createKeyValueMap ( items , ' = ' ) ;
QString number_text = Seer : : filterBookends ( keyValueMap [ " number " ] , ' " ' , ' " ' ) ;
QString type_text = Seer : : filterBookends ( keyValueMap [ " type " ] , ' " ' , ' " ' ) ;
QString disp_text = Seer : : filterBookends ( keyValueMap [ " disp " ] , ' " ' , ' " ' ) ;
QString enabled_text = Seer : : filterBookends ( keyValueMap [ " enabled " ] , ' " ' , ' " ' ) ;
QString addr_text = Seer : : filterBookends ( keyValueMap [ " addr " ] , ' " ' , ' " ' ) ;
QString func_text = Seer : : filterBookends ( keyValueMap [ " func " ] , ' " ' , ' " ' ) ;
QString file_text = Seer : : filterBookends ( keyValueMap [ " file " ] , ' " ' , ' " ' ) ;
QString fullname_text = Seer : : filterBookends ( keyValueMap [ " fullname " ] , ' " ' , ' " ' ) ;
QString line_text = Seer : : filterBookends ( keyValueMap [ " line " ] , ' " ' , ' " ' ) ;
QString thread_groups_text = Seer : : filterBookends ( keyValueMap [ " thread-groups " ] , ' [ ' , ' ] ' ) ;
QString cond_text = Seer : : filterBookends ( keyValueMap [ " cond " ] , ' " ' , ' " ' ) ;
QString times_text = Seer : : filterBookends ( keyValueMap [ " times " ] , ' " ' , ' " ' ) ;
QString ignore_text = Seer : : filterBookends ( keyValueMap [ " ignore " ] , ' " ' , ' " ' ) ;
2024-11-29 10:58:36 -06:00
QString script_text = Seer : : filterBookends ( keyValueMap [ " script " ] , ' [ ' , ' ] ' ) ;
2023-11-24 13:11:49 -06:00
QString original_location_text = Seer : : filterBookends ( keyValueMap [ " original-location " ] , ' " ' , ' " ' ) ;
2021-09-01 13:58:59 -05:00
// Only look for 'breakpoint' type break points.
if ( type_text ! = " breakpoint " ) {
continue ;
}
2023-07-13 12:10:10 -05:00
script_text = Seer : : filterBookends ( Seer : : parseCommaList ( script_text , ' { ' , ' } ' ) , ' " ' , ' " ' ) . join ( ' \n ' ) ;
2021-09-01 13:58:59 -05:00
// Add the level to the tree.
QTreeWidgetItem * topItem = new QTreeWidgetItem ;
topItem - > setText ( 0 , number_text ) ;
topItem - > setText ( 1 , type_text ) ;
topItem - > setText ( 2 , disp_text ) ;
topItem - > setText ( 3 , enabled_text ) ;
topItem - > setText ( 4 , addr_text ) ;
topItem - > setText ( 5 , func_text ) ;
2022-02-28 20:49:34 -06:00
topItem - > setText ( 6 , QFileInfo ( file_text ) . fileName ( ) ) ;
2021-09-01 13:58:59 -05:00
topItem - > setText ( 7 , fullname_text ) ;
topItem - > setText ( 8 , line_text ) ;
topItem - > setText ( 9 , thread_groups_text ) ;
2023-01-11 19:58:22 -06:00
topItem - > setText ( 10 , cond_text ) ;
topItem - > setText ( 11 , times_text ) ;
topItem - > setText ( 12 , ignore_text ) ;
2023-07-04 11:08:33 -05:00
topItem - > setText ( 13 , script_text ) ;
topItem - > setText ( 14 , original_location_text ) ;
2021-09-01 13:58:59 -05:00
2023-07-13 12:10:10 -05:00
for ( int i = 0 ; i < topItem - > columnCount ( ) ; i + + ) {
topItem - > setTextAlignment ( i , Qt : : AlignLeft | Qt : : AlignTop ) ;
}
2021-09-01 13:58:59 -05:00
breakpointsTreeWidget - > addTopLevelItem ( topItem ) ;
}
}
} else {
// Ignore others.
}
breakpointsTreeWidget - > resizeColumnToContents ( 0 ) ;
breakpointsTreeWidget - > resizeColumnToContents ( 1 ) ;
breakpointsTreeWidget - > resizeColumnToContents ( 2 ) ;
breakpointsTreeWidget - > resizeColumnToContents ( 3 ) ;
breakpointsTreeWidget - > resizeColumnToContents ( 4 ) ;
//breakpointsTreeWidget->resizeColumnToContents(5);
breakpointsTreeWidget - > resizeColumnToContents ( 6 ) ;
//breakpointsTreeWidget->resizeColumnToContents(7);
breakpointsTreeWidget - > resizeColumnToContents ( 8 ) ;
breakpointsTreeWidget - > resizeColumnToContents ( 9 ) ;
breakpointsTreeWidget - > resizeColumnToContents ( 10 ) ;
breakpointsTreeWidget - > resizeColumnToContents ( 11 ) ;
2023-01-11 19:58:22 -06:00
breakpointsTreeWidget - > resizeColumnToContents ( 12 ) ;
2023-07-04 11:08:33 -05:00
//breakpointsTreeWidget->resizeColumnToContents(13);
breakpointsTreeWidget - > resizeColumnToContents ( 14 ) ;
2021-09-01 13:58:59 -05:00
QApplication : : restoreOverrideCursor ( ) ;
}
void SeerBreakpointsBrowserWidget : : handleStoppingPointReached ( ) {
// Don't do any work if the widget is hidden.
if ( isHidden ( ) ) {
return ;
}
emit refreshBreakpointsList ( ) ;
}
2025-04-20 09:33:31 -05:00
void SeerBreakpointsBrowserWidget : : handleSessionTerminated ( ) {
// Delete previous contents.
breakpointsTreeWidget - > clear ( ) ;
}
2021-09-01 13:58:59 -05:00
void SeerBreakpointsBrowserWidget : : handleItemDoubleClicked ( QTreeWidgetItem * item , int column ) {
Q_UNUSED ( column ) ;
int lineno = item - > text ( 8 ) . toInt ( ) ;
emit selectedFile ( item - > text ( 6 ) , item - > text ( 7 ) , lineno ) ;
2025-12-19 13:16:52 -06:00
emit maybeSelectedAddress ( item - > text ( 6 ) , item - > text ( 7 ) , item - > text ( 4 ) ) ;
2021-09-01 13:58:59 -05:00
}
void SeerBreakpointsBrowserWidget : : handleRefreshToolButton ( ) {
emit refreshBreakpointsList ( ) ;
}
void SeerBreakpointsBrowserWidget : : handleAddToolButton ( ) {
SeerBreakpointCreateDialog dlg ( this ) ;
int ret = dlg . exec ( ) ;
if ( ret = = 0 ) {
return ;
}
// Build a breakpoint specification.
QString breakpointParameters = dlg . breakpointText ( ) ;
// If nothing, just return.
if ( breakpointParameters = = " " ) {
return ;
}
// Otherwise send the command to create the breakpoint.
emit insertBreakpoint ( breakpointParameters ) ;
}
void SeerBreakpointsBrowserWidget : : handleDeleteToolButton ( ) {
// Get selected tree items.
QList < QTreeWidgetItem * > items = breakpointsTreeWidget - > selectedItems ( ) ;
// Build a string that is a list of breakpoints.
QString breakpoints ;
QList < QTreeWidgetItem * > : : iterator i ;
for ( i = items . begin ( ) ; i ! = items . end ( ) ; + + i ) {
if ( i ! = items . begin ( ) ) {
breakpoints + = " " ;
}
breakpoints + = ( * i ) - > text ( 0 ) ;
}
// Don't do anything if the list of breakpoints is empty.
if ( breakpoints = = " " ) {
return ;
}
// Send the signal.
emit deleteBreakpoints ( breakpoints ) ;
}
void SeerBreakpointsBrowserWidget : : handleEnableToolButton ( ) {
// Get selected tree items.
QList < QTreeWidgetItem * > items = breakpointsTreeWidget - > selectedItems ( ) ;
// Build a string that is a list of breakpoints.
QString breakpoints ;
QList < QTreeWidgetItem * > : : iterator i ;
for ( i = items . begin ( ) ; i ! = items . end ( ) ; + + i ) {
if ( i ! = items . begin ( ) ) {
breakpoints + = " " ;
}
breakpoints + = ( * i ) - > text ( 0 ) ;
}
// Don't do anything if the list of breakpoints is empty.
if ( breakpoints = = " " ) {
return ;
}
// Send the signal.
emit enableBreakpoints ( breakpoints ) ;
}
void SeerBreakpointsBrowserWidget : : handleDisableToolButton ( ) {
// Get selected tree items.
QList < QTreeWidgetItem * > items = breakpointsTreeWidget - > selectedItems ( ) ;
// Build a string that is a list of breakpoints.
QString breakpoints ;
QList < QTreeWidgetItem * > : : iterator i ;
for ( i = items . begin ( ) ; i ! = items . end ( ) ; + + i ) {
if ( i ! = items . begin ( ) ) {
breakpoints + = " " ;
}
breakpoints + = ( * i ) - > text ( 0 ) ;
}
// Don't do anything if the list of breakpoints is empty.
if ( breakpoints = = " " ) {
return ;
}
// Send the signal.
emit disableBreakpoints ( breakpoints ) ;
}
2023-06-13 17:56:13 -05:00
void SeerBreakpointsBrowserWidget : : handleConditionToolButton ( ) {
// Get selected tree items. Only allow one.
QList < QTreeWidgetItem * > items = breakpointsTreeWidget - > selectedItems ( ) ;
if ( items . count ( ) = = 0 ) {
return ;
}
if ( items . count ( ) > 1 ) {
QMessageBox : : warning ( this , " Seer " , " Select only one breakpoint when adding a condition. " , QMessageBox : : Ok ) ;
return ;
}
// Get the condition text.
bool ok ;
2023-11-24 13:11:49 -06:00
QString condition = QInputDialog : : getText ( this , " Seer " , " Enter the condition for this breakpoint. \n A blank condition will remove an existing one. \n \n if: " , QLineEdit : : Normal , items . front ( ) - > text ( 10 ) , & ok ) ;
2023-06-13 17:56:13 -05:00
if ( ok = = false ) {
return ;
}
// Get the selected breakpoint number.
QString breakpoint = items . front ( ) - > text ( 0 ) ;
// Send the signal.
emit addBreakpointCondition ( breakpoint , condition ) ;
}
void SeerBreakpointsBrowserWidget : : handleIgnoreToolButton ( ) {
// Get selected tree items. Only allow one.
QList < QTreeWidgetItem * > items = breakpointsTreeWidget - > selectedItems ( ) ;
if ( items . count ( ) = = 0 ) {
return ;
}
if ( items . count ( ) > 1 ) {
QMessageBox : : warning ( this , " Seer " , " Select only one breakpoint when adding an ignore count. " , QMessageBox : : Ok ) ;
return ;
}
// Get the ignore text.
bool ok ;
2023-07-04 11:08:33 -05:00
int count = QInputDialog : : getInt ( this , " Seer " , " Enter the ignore count for this breakpoint. \n A count of 0 will remove an existing one. " , items . front ( ) - > text ( 12 ) . toInt ( ) , 0 , 2147483647 , 1 , & ok ) ;
2023-06-13 17:56:13 -05:00
if ( ok = = false ) {
return ;
}
// Get the selected breakpoint number.
QString breakpoint = items . front ( ) - > text ( 0 ) ;
// Send the signal.
emit addBreakpointIgnore ( breakpoint , QString : : number ( count ) ) ;
}
void SeerBreakpointsBrowserWidget : : handleCommandsToolButton ( ) {
// Get selected tree items. Only allow one.
QList < QTreeWidgetItem * > items = breakpointsTreeWidget - > selectedItems ( ) ;
if ( items . count ( ) = = 0 ) {
return ;
}
if ( items . count ( ) > 1 ) {
QMessageBox : : warning ( this , " Seer " , " Select only one breakpoint when adding commands. " , QMessageBox : : Ok ) ;
return ;
}
// Get the ignore text.
bool ok ;
2023-07-13 15:25:37 -05:00
QString commandstr = QInputDialog : : getMultiLineText ( this , " Seer " , " Enter the commands to execute for this breakpoint. \n A blank list will remove existing ones. " , items . front ( ) - > text ( 13 ) , & ok ) ;
2023-06-13 17:56:13 -05:00
if ( ok = = false ) {
return ;
}
// Get the selected breakpoint number.
QString breakpoint = items . front ( ) - > text ( 0 ) ;
2023-07-13 15:25:37 -05:00
QStringList commands = Seer : : quoteChars ( commandstr . split ( ' \n ' , Qt : : SkipEmptyParts ) , " \" " ) ;
2023-06-13 17:56:13 -05:00
// Send the signal.
2023-07-13 15:25:37 -05:00
emit addBreakpointCommands ( breakpoint , commands ) ;
2023-06-13 17:56:13 -05:00
}
2021-09-01 13:58:59 -05:00
void SeerBreakpointsBrowserWidget : : showEvent ( QShowEvent * event ) {
QWidget : : showEvent ( event ) ;
emit refreshBreakpointsList ( ) ;
}