@ -6,20 +6,22 @@
# include <QMessageBox>
# include <QScrollBar>
# include <QTimer>
# include <QVBoxLayout>
# include "selfdrive/ui/qt/util.h"
# include "tools/cabana/canmessages.h"
# include "tools/cabana/commands.h"
# include "tools/cabana/dbcmanager.h"
// DetailWidget
DetailWidget : : DetailWidget ( ChartsWidget * charts , QWidget * parent ) : charts ( charts ) , QWidget ( parent ) {
undo_stack = new QUndoStack ( this ) ;
QVBoxLayout * main_layout = new QVBoxLayout ( this ) ;
main_layout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
main_layout - > setSpacing ( 0 ) ;
// tabbar
// tabbar
tabbar = new QTabBar ( this ) ;
tabbar - > setTabsClosable ( true ) ;
tabbar - > setDrawBase ( false ) ;
@ -78,9 +80,8 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
container_layout - > addWidget ( binary_view ) ;
// signals
signals_container = new QWidget ( this ) ;
signals_container - > setLayout ( new QVBoxLayout ) ;
container_layout - > addWidget ( signals_container ) ;
signals_layout = new QVBoxLayout ( ) ;
container_layout - > addLayout ( signals_layout ) ;
// history log
history_log = new HistoryLog ( this ) ;
@ -88,7 +89,7 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
QObject : : connect ( binary_view , & BinaryView : : resizeSignal , this , & DetailWidget : : resizeSignal ) ;
QObject : : connect ( binary_view , & BinaryView : : addSignal , this , & DetailWidget : : addSignal ) ;
QObject : : connect ( can , & CANMessages : : updat ed, this , & DetailWidget : : updateState ) ;
QObject : : connect ( can , & CANMessages : : msgsReceiv ed, this , & DetailWidget : : updateState ) ;
QObject : : connect ( dbc ( ) , & DBCManager : : DBCFileChanged , [ this ] ( ) { dbcMsgChanged ( ) ; } ) ;
QObject : : connect ( tabbar , & QTabBar : : customContextMenuRequested , this , & DetailWidget : : showTabBarContextMenu ) ;
QObject : : connect ( tabbar , & QTabBar : : currentChanged , [ this ] ( int index ) {
@ -99,6 +100,10 @@ DetailWidget::DetailWidget(ChartsWidget *charts, QWidget *parent) : charts(chart
QObject : : connect ( tabbar , & QTabBar : : tabCloseRequested , tabbar , & QTabBar : : removeTab ) ;
QObject : : connect ( charts , & ChartsWidget : : chartOpened , [ this ] ( const QString & id , const Signal * sig ) { updateChartState ( id , sig , true ) ; } ) ;
QObject : : connect ( charts , & ChartsWidget : : chartClosed , [ this ] ( const QString & id , const Signal * sig ) { updateChartState ( id , sig , false ) ; } ) ;
QObject : : connect ( undo_stack , & QUndoStack : : indexChanged , [ this ] ( ) {
if ( undo_stack - > count ( ) > 0 )
dbcMsgChanged ( ) ;
} ) ;
}
void DetailWidget : : showTabBarContextMenu ( const QPoint & pt ) {
@ -107,103 +112,82 @@ void DetailWidget::showTabBarContextMenu(const QPoint &pt) {
QMenu menu ( this ) ;
menu . addAction ( tr ( " Close Other Tabs " ) ) ;
if ( menu . exec ( tabbar - > mapToGlobal ( pt ) ) ) {
tabbar - > setCurrentIndex ( index ) ;
// remove all tabs before the one to keep
for ( int i = 0 ; i < index ; + + i ) {
tabbar - > removeTab ( 0 ) ;
}
// remove all tabs after the one to keep
while ( tabbar - > count ( ) > 1 ) {
tabbar - > moveTab ( index , 0 ) ;
tabbar - > setCurrentIndex ( 0 ) ;
while ( tabbar - > count ( ) > 1 )
tabbar - > removeTab ( 1 ) ;
}
}
}
}
void DetailWidget : : setMessage ( const QString & message_id ) {
if ( message_id . isEmpty ( ) ) return ;
int index = - 1 ;
for ( int i = 0 ; i < tabbar - > count ( ) ; + + i ) {
if ( tabbar - > tabText ( i ) = = message_id ) {
index = i ;
break ;
}
}
msg_id = message_id ;
int index = tabbar - > count ( ) - 1 ;
for ( /**/ ; index > = 0 & & tabbar - > tabText ( index ) ! = msg_id ; - - index ) { /**/ }
if ( index = = - 1 ) {
index = tabbar - > addTab ( message_id ) ;
tabbar - > setTabToolTip ( index , msgName ( message_id ) ) ;
}
tabbar - > setCurrentIndex ( index ) ;
dbcMsgChanged ( ) ;
scroll - > verticalScrollBar ( ) - > setValue ( 0 ) ;
}
void DetailWidget : : dbcMsgChanged ( int show_form_idx ) {
if ( msg_id . isEmpty ( ) ) return ;
setUpdatesEnabled ( false ) ;
QStringList warnings ;
for ( auto f : signal_list ) f - > hide ( ) ;
const Msg * msg = dbc ( ) - > msg ( msg_id ) ;
binary_view - > setMessage ( msg_id ) ;
history_log - > setMessage ( msg_id ) ;
int i = 0 ;
QStringList warnings ;
const DBCMsg * msg = dbc ( ) - > msg ( msg_id ) ;
if ( msg ) {
for ( int i = 0 ; i < msg - > sigs . size ( ) ; + + i ) {
for ( auto & [ name , sig ] : msg - > sigs ) {
SignalEdit * form = i < signal_list . size ( ) ? signal_list [ i ] : nullptr ;
if ( ! form ) {
form = new SignalEdit ( i ) ;
QObject : : connect ( form , & SignalEdit : : showFormClicked , this , & DetailWidget : : showForm ) ;
QObject : : connect ( form , & SignalEdit : : remove , this , & DetailWidget : : removeSignal ) ;
QObject : : connect ( form , & SignalEdit : : save , this , & DetailWidget : : saveSignal ) ;
QObject : : connect ( form , & SignalEdit : : highlight , binary_view , & BinaryView : : highlight ) ;
QObject : : connect ( binary_view , & BinaryView : : signalHovered , form , & SignalEdit : : signalHovered ) ;
QObject : : connect ( form , & SignalEdit : : showChart , charts , & ChartsWidget : : showChart ) ;
signals_container - > layout ( ) - > addWidget ( form ) ;
signals_layout - > addWidget ( form ) ;
signal_list . push_back ( form ) ;
}
form - > setSignal ( msg_id , & ( msg - > sigs [ i ] ) , i = = show_form_idx ) ;
form - > setChartOpened ( charts - > isChartOpened ( msg_id , & ( msg - > sigs [ i ] ) ) ) ;
form - > show ( ) ;
form - > setSignal ( msg_id , & sig ) ;
form - > setChartOpened ( charts - > isChartOpened ( msg_id , & sig ) ) ;
+ + i ;
}
if ( msg - > size ! = can - > lastMessage ( msg_id ) . dat . size ( ) )
warnings . push_back ( tr ( " Message size (%1) is incorrect. " ) . arg ( msg - > size ) ) ;
}
for ( /**/ ; i < signal_list . size ( ) ; + + i )
signal_list [ i ] - > hide ( ) ;
toolbar - > setVisible ( ! msg_id . isEmpty ( ) ) ;
remove_msg_act - > setEnabled ( msg ! = nullptr ) ;
name_label - > setText ( msgName ( msg_id ) ) ;
binary_view - > setMessage ( msg_id ) ;
history_log - > setMessage ( msg_id ) ;
// Check overlapping bits
if ( auto overlapping = binary_view - > getOverlappingSignals ( ) ; ! overlapping . isEmpty ( ) ) {
for ( auto s : overlapping )
warnings . push_back ( tr ( " %1 has overlapping bits. " ) . arg ( s - > name . c_str ( ) ) ) ;
}
for ( auto s : binary_view - > getOverlappingSignals ( ) )
warnings . push_back ( tr ( " %1 has overlapping bits. " ) . arg ( s - > name . c_str ( ) ) ) ;
warning_label - > setText ( warnings . join ( ' \n ' ) ) ;
warning_widget - > setVisible ( ! warnings . isEmpty ( ) ) ;
setUpdatesEnabled ( true ) ;
scroll - > verticalScrollBar ( ) - > setValue ( 0 ) ;
QTimer : : singleShot ( 1 , [ this ] ( ) { setUpdatesEnabled ( true ) ; } ) ;
}
void DetailWidget : : updateState ( ) {
void DetailWidget : : updateState ( const QHash < QString , CanData > * msgs ) {
time_label - > setText ( QString : : number ( can - > currentSec ( ) , ' f ' , 3 ) ) ;
if ( msg_id . isEmpty ( ) ) return ;
if ( ! msgs - > contains ( msg_id ) )
return ;
binary_view - > updateState ( ) ;
history_log - > updateState ( ) ;
}
void DetailWidget : : showForm ( ) {
SignalEdit * sender = qobject_cast < SignalEdit * > ( QObject : : sender ( ) ) ;
setUpdatesEnabled ( false ) ;
for ( auto f : signal_list )
f - > setFormVisible ( f = = sender & & ! f - > isFormVisible ( ) ) ;
QTimer : : singleShot ( 1 , [ this ] ( ) { setUpdatesEnabled ( true ) ; } ) ;
}
void DetailWidget : : updateChartState ( const QString & id , const Signal * sig , bool opened ) {
for ( auto f : signal_list )
if ( f - > msg_id = = id & & f - > sig = = sig ) f - > setChartOpened ( opened ) ;
@ -215,45 +199,34 @@ void DetailWidget::editMsg() {
int size = msg ? msg - > size : can - > lastMessage ( id ) . dat . size ( ) ;
EditMessageDialog dlg ( id , msgName ( id ) , size , this ) ;
if ( dlg . exec ( ) ) {
dbc ( ) - > updateMsg ( id , dlg . name_edit - > text ( ) , dlg . size_spin - > value ( ) ) ;
dbcMsgChanged ( ) ;
undo_stack - > push ( new EditMsgCommand ( msg_id , dlg . name_edit - > text ( ) , dlg . size_spin - > value ( ) ) ) ;
}
}
void DetailWidget : : removeMsg ( ) {
QString id = msg_id ;
if ( auto msg = dbc ( ) - > msg ( id ) ) {
QString text = tr ( " Are you sure you want to remove '%1' " ) . arg ( msg - > name . c_str ( ) ) ;
if ( QMessageBox : : Yes = = QMessageBox : : question ( this , tr ( " Remove Message " ) , text ) ) {
dbc ( ) - > removeMsg ( id ) ;
dbcMsgChanged ( ) ;
}
}
undo_stack - > push ( new RemoveMsgCommand ( msg_id ) ) ;
}
void DetailWidget : : addSignal ( int start_bit , int size , bool little_endian ) {
auto msg = dbc ( ) - > msg ( msg_id ) ;
if ( ! msg ) {
for ( int i = 1 ; /**/ ; + + i ) {
std : : string name = " NEW_MSG_ " + std : : to_strin g( i ) ;
auto it = std : : find_if ( dbc ( ) - > getDBC ( ) - > msgs . begin ( ) , dbc ( ) - > getDBC ( ) - > msgs . end ( ) , [ & ] ( auto & m ) { return m . name = = name ; } ) ;
if ( it = = dbc ( ) - > getDBC ( ) - > msgs . end ( ) ) {
dbc ( ) - > updateMsg ( msg_id , name . c_str ( ) , can - > lastMessage ( msg_id ) . dat . size ( ) ) ;
QString name = QString ( " NEW_MSG_%1 " ) . arg ( i ) ;
auto it = std : : find_if ( dbc ( ) - > messages ( ) . begin ( ) , dbc ( ) - > messages ( ) . end ( ) , [ & ] ( auto & m ) { return m . second . name = = name ; } ) ;
if ( it = = dbc ( ) - > messages ( ) . end ( ) ) {
undo_stack - > push ( new EditMsgCommand ( msg_id , name , can - > lastMessage ( msg_id ) . dat . size ( ) ) ) ;
msg = dbc ( ) - > msg ( msg_id ) ;
break ;
}
}
}
Signal sig = { } ;
Signal sig = { . is_little_endian = little_endian } ;
for ( int i = 1 ; /**/ ; + + i ) {
sig . name = " NEW_SIGNAL_ " + std : : to_string ( i ) ;
auto it = std : : find_if ( msg - > sigs . begin ( ) , msg - > sigs . end ( ) , [ & ] ( auto & s ) { return sig . name = = s . name ; } ) ;
if ( it = = msg - > sigs . end ( ) ) break ;
if ( msg - > sigs . count ( sig . name . c_str ( ) ) = = 0 ) break ;
}
sig . is_little_endian = little_endian ;
updateSigSizeParamsFromRange ( sig , start_bit , size ) ;
dbc ( ) - > addSignal ( msg_id , sig ) ;
dbcMsgChanged ( msg - > sigs . size ( ) - 1 ) ;
undo_stack - > push ( new AddSigCommand ( msg_id , sig ) ) ;
}
void DetailWidget : : resizeSignal ( const Signal * sig , int start_bit , int size ) {
@ -265,14 +238,13 @@ void DetailWidget::resizeSignal(const Signal *sig, int start_bit, int size) {
void DetailWidget : : saveSignal ( const Signal * sig , const Signal & new_sig ) {
auto msg = dbc ( ) - > msg ( msg_id ) ;
if ( new_sig . name ! = sig - > name ) {
auto it = std : : find_if ( msg - > sigs . begin ( ) , msg - > sigs . end ( ) , [ & ] ( auto & s ) { return s . name = = new_sig . name ; } ) ;
auto it = msg - > sigs . find ( new_sig . name . c_str ( ) ) ;
if ( it ! = msg - > sigs . end ( ) ) {
QString warning_str = tr ( " There is already a signal with the same name '%1' " ) . arg ( new_sig . name . c_str ( ) ) ;
QMessageBox : : warning ( this , tr ( " Failed to save signal " ) , warning_str ) ;
return ;
}
}
auto [ start , end ] = getSignalRange ( & new_sig ) ;
if ( start < 0 | | end > = msg - > size * 8 ) {
QString warning_str = tr ( " Signal size [%1] exceed limit " ) . arg ( new_sig . size ) ;
@ -280,16 +252,11 @@ void DetailWidget::saveSignal(const Signal *sig, const Signal &new_sig) {
return ;
}
dbc ( ) - > updateSignal ( msg_id , sig - > name . c_str ( ) , new_sig ) ;
dbcMsgChanged ( ) ;
undo_stack - > push ( new EditSignalCommand ( msg_id , sig , new_sig ) ) ;
}
void DetailWidget : : removeSignal ( const Signal * sig ) {
QString text = tr ( " Are you sure you want to remove signal '%1' " ) . arg ( sig - > name . c_str ( ) ) ;
if ( QMessageBox : : Yes = = QMessageBox : : question ( this , tr ( " Remove signal " ) , text ) ) {
dbc ( ) - > removeSignal ( msg_id , sig - > name . c_str ( ) ) ;
dbcMsgChanged ( ) ;
}
undo_stack - > push ( new RemoveSigCommand ( msg_id , sig ) ) ;
}
// EditMessageDialog
@ -300,6 +267,7 @@ EditMessageDialog::EditMessageDialog(const QString &msg_id, const QString &title
form_layout - > addRow ( " ID " , new QLabel ( msg_id ) ) ;
name_edit = new QLineEdit ( title , this ) ;
name_edit - > setValidator ( new QRegExpValidator ( QRegExp ( " ^( \\ w+) " ) , name_edit ) ) ;
form_layout - > addRow ( tr ( " Name " ) , name_edit ) ;
size_spin = new QSpinBox ( this ) ;