@ -18,6 +18,12 @@
// SignalModel
// SignalModel
static QString signalTypeToString ( cabana : : Signal : : Type type ) {
if ( type = = cabana : : Signal : : Type : : Multiplexor ) return " Multiplexor Signal " ;
else if ( type = = cabana : : Signal : : Type : : Multiplexed ) return " Multiplexed Signal " ;
else return " Normal Signal " ;
}
SignalModel : : SignalModel ( QObject * parent ) : root ( new Item ) , QAbstractItemModel ( parent ) {
SignalModel : : SignalModel ( QObject * parent ) : root ( new Item ) , QAbstractItemModel ( parent ) {
QObject : : connect ( dbc ( ) , & DBCManager : : DBCFileChanged , this , & SignalModel : : refresh ) ;
QObject : : connect ( dbc ( ) , & DBCManager : : DBCFileChanged , this , & SignalModel : : refresh ) ;
QObject : : connect ( dbc ( ) , & DBCManager : : msgUpdated , this , & SignalModel : : handleMsgChanged ) ;
QObject : : connect ( dbc ( ) , & DBCManager : : msgUpdated , this , & SignalModel : : handleMsgChanged ) ;
@ -30,7 +36,8 @@ SignalModel::SignalModel(QObject *parent) : root(new Item), QAbstractItemModel(p
void SignalModel : : insertItem ( SignalModel : : Item * parent_item , int pos , const cabana : : Signal * sig ) {
void SignalModel : : insertItem ( SignalModel : : Item * parent_item , int pos , const cabana : : Signal * sig ) {
Item * item = new Item { . sig = sig , . parent = parent_item , . title = sig - > name , . type = Item : : Sig } ;
Item * item = new Item { . sig = sig , . parent = parent_item , . title = sig - > name , . type = Item : : Sig } ;
parent_item - > children . insert ( pos , item ) ;
parent_item - > children . insert ( pos , item ) ;
QString titles [ ] { " Name " , " Size " , " Little Endian " , " Signed " , " Offset " , " Factor " , " Extra Info " , " Unit " , " Comment " , " Minimum Value " , " Maximum Value " , " Value Descriptions " } ;
QString titles [ ] { " Name " , " Size " , " Little Endian " , " Signed " , " Offset " , " Factor " , " Type " , " Multiplex Value " , " Extra Info " ,
" Unit " , " Comment " , " Minimum Value " , " Maximum Value " , " Value Descriptions " } ;
for ( int i = 0 ; i < std : : size ( titles ) ; + + i ) {
for ( int i = 0 ; i < std : : size ( titles ) ; + + i ) {
item - > children . push_back ( new Item { . sig = sig , . parent = item , . title = titles [ i ] , . type = ( Item : : Type ) ( i + Item : : Name ) } ) ;
item - > children . push_back ( new Item { . sig = sig , . parent = item , . title = titles [ i ] , . type = ( Item : : Type ) ( i + Item : : Name ) } ) ;
}
}
@ -87,6 +94,9 @@ Qt::ItemFlags SignalModel::flags(const QModelIndex &index) const {
if ( index . column ( ) = = 1 & & item - > type ! = Item : : Sig & & item - > type ! = Item : : ExtraInfo ) {
if ( index . column ( ) = = 1 & & item - > type ! = Item : : Sig & & item - > type ! = Item : : ExtraInfo ) {
flags | = ( item - > type = = Item : : Endian | | item - > type = = Item : : Signed ) ? Qt : : ItemIsUserCheckable : Qt : : ItemIsEditable ;
flags | = ( item - > type = = Item : : Endian | | item - > type = = Item : : Signed ) ? Qt : : ItemIsUserCheckable : Qt : : ItemIsEditable ;
}
}
if ( item - > type = = Item : : MultiplexValue & & item - > sig - > type ! = cabana : : Signal : : Type : : Multiplexed ) {
flags & = ~ Qt : : ItemIsEnabled ;
}
return flags ;
return flags ;
}
}
@ -124,6 +134,8 @@ QVariant SignalModel::data(const QModelIndex &index, int role) const {
case Item : : Sig : return item - > sig_val ;
case Item : : Sig : return item - > sig_val ;
case Item : : Name : return item - > sig - > name ;
case Item : : Name : return item - > sig - > name ;
case Item : : Size : return item - > sig - > size ;
case Item : : Size : return item - > sig - > size ;
case Item : : SignalType : return signalTypeToString ( item - > sig - > type ) ;
case Item : : MultiplexValue : return item - > sig - > multiplex_value ;
case Item : : Offset : return doubleToString ( item - > sig - > offset ) ;
case Item : : Offset : return doubleToString ( item - > sig - > offset ) ;
case Item : : Factor : return doubleToString ( item - > sig - > factor ) ;
case Item : : Factor : return doubleToString ( item - > sig - > factor ) ;
case Item : : Unit : return item - > sig - > unit ;
case Item : : Unit : return item - > sig - > unit ;
@ -160,6 +172,8 @@ bool SignalModel::setData(const QModelIndex &index, const QVariant &value, int r
switch ( item - > type ) {
switch ( item - > type ) {
case Item : : Name : s . name = value . toString ( ) ; break ;
case Item : : Name : s . name = value . toString ( ) ; break ;
case Item : : Size : s . size = value . toInt ( ) ; break ;
case Item : : Size : s . size = value . toInt ( ) ; break ;
case Item : : SignalType : s . type = ( cabana : : Signal : : Type ) value . toInt ( ) ; break ;
case Item : : MultiplexValue : s . multiplex_value = value . toInt ( ) ; break ;
case Item : : Endian : s . is_little_endian = value . toBool ( ) ; break ;
case Item : : Endian : s . is_little_endian = value . toBool ( ) ; break ;
case Item : : Signed : s . is_signed = value . toBool ( ) ; break ;
case Item : : Signed : s . is_signed = value . toBool ( ) ; break ;
case Item : : Offset : s . offset = value . toDouble ( ) ; break ;
case Item : : Offset : s . offset = value . toDouble ( ) ; break ;
@ -265,6 +279,14 @@ void SignalModel::handleSignalAdded(MessageId id, const cabana::Signal *sig) {
void SignalModel : : handleSignalUpdated ( const cabana : : Signal * sig ) {
void SignalModel : : handleSignalUpdated ( const cabana : : Signal * sig ) {
if ( int row = signalRow ( sig ) ; row ! = - 1 ) {
if ( int row = signalRow ( sig ) ; row ! = - 1 ) {
emit dataChanged ( index ( row , 0 ) , index ( row , 1 ) , { Qt : : DisplayRole , Qt : : EditRole , Qt : : CheckStateRole } ) ;
emit dataChanged ( index ( row , 0 ) , index ( row , 1 ) , { Qt : : DisplayRole , Qt : : EditRole , Qt : : CheckStateRole } ) ;
// move row when the order changes.
int to = dbc ( ) - > msg ( msg_id ) - > indexOf ( sig ) ;
if ( to ! = row ) {
beginMoveRows ( { } , row , row , { } , to > row ? to + 1 : to ) ;
root - > children . move ( row , to ) ;
endMoveRows ( ) ;
}
}
}
}
}
@ -289,13 +311,18 @@ SignalItemDelegate::SignalItemDelegate(QObject *parent) : QStyledItemDelegate(pa
QSize SignalItemDelegate : : sizeHint ( const QStyleOptionViewItem & option , const QModelIndex & index ) const {
QSize SignalItemDelegate : : sizeHint ( const QStyleOptionViewItem & option , const QModelIndex & index ) const {
int width = option . widget - > size ( ) . width ( ) / 2 ;
int width = option . widget - > size ( ) . width ( ) / 2 ;
if ( index . column ( ) = = 0 ) {
if ( index . column ( ) = = 0 ) {
auto text = index . data ( Qt : : DisplayRole ) . toString ( ) ;
int spacing = option . widget - > style ( ) - > pixelMetric ( QStyle : : PM_TreeViewIndentation ) + color_label_width + 8 ;
auto text = index . data ( Qt : : DisplayRole ) . toString ( ) ; ;
auto item = ( SignalModel : : Item * ) index . internalPointer ( ) ;
if ( item - > type = = SignalModel : : Item : : Sig & & item - > sig - > type ! = cabana : : Signal : : Type : : Normal ) {
text + = item - > sig - > type = = cabana : : Signal : : Type : : Multiplexor ? QString ( " M " ) : QString ( " m%1 " ) . arg ( item - > sig - > multiplex_value ) ;
spacing + = ( option . widget - > style ( ) - > pixelMetric ( QStyle : : PM_FocusFrameHMargin ) + 1 ) * 2 ;
}
auto it = width_cache . find ( text ) ;
auto it = width_cache . find ( text ) ;
if ( it = = width_cache . end ( ) ) {
if ( it = = width_cache . end ( ) ) {
int spacing = option . widget - > style ( ) - > pixelMetric ( QStyle : : PM_TreeViewIndentation ) + color_label_width + 8 ;
it = width_cache . insert ( text , option . fontMetrics . width ( text ) ) ;
it = width_cache . insert ( text , option . fontMetrics . width ( text ) + spacing ) ;
}
}
width = std : : min < int > ( option . widget - > size ( ) . width ( ) / 3.0 , it . value ( ) ) ;
width = std : : min < int > ( option . widget - > size ( ) . width ( ) / 3.0 , it . value ( ) + spacing ) ;
}
}
return { width , QApplication : : fontMetrics ( ) . height ( ) } ;
return { width , QApplication : : fontMetrics ( ) . height ( ) } ;
}
}
@ -334,11 +361,24 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
painter - > drawText ( icon_rect , Qt : : AlignCenter , QString : : number ( item - > row ( ) + 1 ) ) ;
painter - > drawText ( icon_rect , Qt : : AlignCenter , QString : : number ( item - > row ( ) + 1 ) ) ;
r . setLeft ( icon_rect . right ( ) + h_margin * 2 ) ;
r . setLeft ( icon_rect . right ( ) + h_margin * 2 ) ;
// multiplexer indicator
if ( item - > sig - > type ! = cabana : : Signal : : Type : : Normal ) {
QString indicator = item - > sig - > type = = cabana : : Signal : : Type : : Multiplexor ? QString ( " M " ) : QString ( " m%1 " ) . arg ( item - > sig - > multiplex_value ) ;
QRect indicator_rect { r . x ( ) , r . y ( ) , option . fontMetrics . width ( indicator ) , r . height ( ) } ;
painter - > setBrush ( Qt : : gray ) ;
painter - > setPen ( Qt : : NoPen ) ;
painter - > drawRoundedRect ( indicator_rect , 3 , 3 ) ;
painter - > setPen ( Qt : : white ) ;
painter - > drawText ( indicator_rect , Qt : : AlignCenter , indicator ) ;
r . setLeft ( indicator_rect . right ( ) + h_margin * 2 ) ;
}
// name
auto text = option . fontMetrics . elidedText ( index . data ( Qt : : DisplayRole ) . toString ( ) , Qt : : ElideRight , r . width ( ) ) ;
auto text = option . fontMetrics . elidedText ( index . data ( Qt : : DisplayRole ) . toString ( ) , Qt : : ElideRight , r . width ( ) ) ;
painter - > setPen ( option . palette . color ( option . state & QStyle : : State_Selected ? QPalette : : HighlightedText : QPalette : : Text ) ) ;
painter - > setPen ( option . palette . color ( option . state & QStyle : : State_Selected ? QPalette : : HighlightedText : QPalette : : Text ) ) ;
painter - > setFont ( option . font ) ;
painter - > setFont ( option . font ) ;
painter - > drawText ( r , option . displayAlignment , text ) ;
painter - > drawText ( r , option . displayAlignment , text ) ;
} else if ( index . column ( ) = = 1 ) {
} else if ( index . column ( ) = = 1 & & ! item - > sparkline . pixmap . isNull ( ) ) {
// sparkline
// sparkline
QSize sparkline_size = item - > sparkline . pixmap . size ( ) / item - > sparkline . pixmap . devicePixelRatio ( ) ;
QSize sparkline_size = item - > sparkline . pixmap . size ( ) / item - > sparkline . pixmap . devicePixelRatio ( ) ;
painter - > drawPixmap ( QRect ( r . topLeft ( ) , sparkline_size ) , item - > sparkline . pixmap ) ;
painter - > drawPixmap ( QRect ( r . topLeft ( ) , sparkline_size ) , item - > sparkline . pixmap ) ;
@ -356,8 +396,15 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
painter - > drawText ( rect , Qt : : AlignLeft | Qt : : AlignBottom , min ) ;
painter - > drawText ( rect , Qt : : AlignLeft | Qt : : AlignBottom , min ) ;
QFontMetrics fm ( minmax_font ) ;
QFontMetrics fm ( minmax_font ) ;
value_adjust = std : : max ( fm . width ( min ) , fm . width ( max ) ) + 5 ;
value_adjust = std : : max ( fm . width ( min ) , fm . width ( max ) ) + 5 ;
} else if ( item - > sig - > type = = cabana : : Signal : : Type : : Multiplexed ) {
// display freq of multiplexed signal
painter - > setFont ( label_font ) ;
QString freq = QString ( " %1 hz " ) . arg ( item - > sparkline . freq ( ) , 0 , ' g ' , 2 ) ;
painter - > drawText ( rect . adjusted ( 5 , 0 , 0 , 0 ) , Qt : : AlignLeft | Qt : : AlignVCenter , freq ) ;
QFontMetrics fm ( label_font ) ;
value_adjust = fm . width ( freq ) + 10 ;
}
}
// value
// signal value
painter - > setFont ( option . font ) ;
painter - > setFont ( option . font ) ;
rect . adjust ( value_adjust , 0 , - button_size . width ( ) , 0 ) ;
rect . adjust ( value_adjust , 0 , - button_size . width ( ) , 0 ) ;
auto text = option . fontMetrics . elidedText ( index . data ( Qt : : DisplayRole ) . toString ( ) , Qt : : ElideRight , rect . width ( ) ) ;
auto text = option . fontMetrics . elidedText ( index . data ( Qt : : DisplayRole ) . toString ( ) , Qt : : ElideRight , rect . width ( ) ) ;
@ -371,10 +418,11 @@ void SignalItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &op
QWidget * SignalItemDelegate : : createEditor ( QWidget * parent , const QStyleOptionViewItem & option , const QModelIndex & index ) const {
QWidget * SignalItemDelegate : : createEditor ( QWidget * parent , const QStyleOptionViewItem & option , const QModelIndex & index ) const {
auto item = ( SignalModel : : Item * ) index . internalPointer ( ) ;
auto item = ( SignalModel : : Item * ) index . internalPointer ( ) ;
if ( item - > type = = SignalModel : : Item : : Name | | item - > type = = SignalModel : : Item : : Offset | |
if ( item - > type = = SignalModel : : Item : : Name | | item - > type = = SignalModel : : Item : : Offset | |
item - > type = = SignalModel : : Item : : Factor | | item - > type = = SignalModel : : Item : : Min | | item - > type = = SignalModel : : Item : : Max ) {
item - > type = = SignalModel : : Item : : Factor | | item - > type = = SignalModel : : Item : : MultiplexValue | |
item - > type = = SignalModel : : Item : : Min | | item - > type = = SignalModel : : Item : : Max ) {
QLineEdit * e = new QLineEdit ( parent ) ;
QLineEdit * e = new QLineEdit ( parent ) ;
e - > setFrame ( false ) ;
e - > setFrame ( false ) ;
e - > setValidator ( index . row ( ) = = 0 ? name_validator : double_validator ) ;
e - > setValidator ( item - > type = = SignalModel : : Item : : Name ? name_validator : double_validator ) ;
if ( item - > type = = SignalModel : : Item : : Name ) {
if ( item - > type = = SignalModel : : Item : : Name ) {
QCompleter * completer = new QCompleter ( dbc ( ) - > signalNames ( ) ) ;
QCompleter * completer = new QCompleter ( dbc ( ) - > signalNames ( ) ) ;
@ -389,6 +437,15 @@ QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionVie
spin - > setFrame ( false ) ;
spin - > setFrame ( false ) ;
spin - > setRange ( 1 , 64 ) ;
spin - > setRange ( 1 , 64 ) ;
return spin ;
return spin ;
} else if ( item - > type = = SignalModel : : Item : : SignalType ) {
QComboBox * c = new QComboBox ( parent ) ;
c - > addItem ( signalTypeToString ( cabana : : Signal : : Type : : Normal ) , ( int ) cabana : : Signal : : Type : : Normal ) ;
if ( ! dbc ( ) - > msg ( ( ( SignalModel * ) index . model ( ) ) - > msg_id ) - > multiplexor ) {
c - > addItem ( signalTypeToString ( cabana : : Signal : : Type : : Multiplexor ) , ( int ) cabana : : Signal : : Type : : Multiplexor ) ;
} else if ( item - > sig - > type ! = cabana : : Signal : : Type : : Multiplexor ) {
c - > addItem ( signalTypeToString ( cabana : : Signal : : Type : : Multiplexed ) , ( int ) cabana : : Signal : : Type : : Multiplexed ) ;
}
return c ;
} else if ( item - > type = = SignalModel : : Item : : Desc ) {
} else if ( item - > type = = SignalModel : : Item : : Desc ) {
ValueDescriptionDlg dlg ( item - > sig - > val_desc , parent ) ;
ValueDescriptionDlg dlg ( item - > sig - > val_desc , parent ) ;
dlg . setWindowTitle ( item - > sig - > name ) ;
dlg . setWindowTitle ( item - > sig - > name ) ;
@ -400,6 +457,15 @@ QWidget *SignalItemDelegate::createEditor(QWidget *parent, const QStyleOptionVie
return QStyledItemDelegate : : createEditor ( parent , option , index ) ;
return QStyledItemDelegate : : createEditor ( parent , option , index ) ;
}
}
void SignalItemDelegate : : setModelData ( QWidget * editor , QAbstractItemModel * model , const QModelIndex & index ) const {
auto item = ( SignalModel : : Item * ) index . internalPointer ( ) ;
if ( item - > type = = SignalModel : : Item : : SignalType ) {
model - > setData ( index , ( ( QComboBox * ) editor ) - > currentData ( ) . toInt ( ) ) ;
return ;
}
QStyledItemDelegate : : setModelData ( editor , model , index ) ;
}
// SignalView
// SignalView
SignalView : : SignalView ( ChartsWidget * charts , QWidget * parent ) : charts ( charts ) , QFrame ( parent ) {
SignalView : : SignalView ( ChartsWidget * charts , QWidget * parent ) : charts ( charts ) , QFrame ( parent ) {
@ -438,6 +504,7 @@ SignalView::SignalView(ChartsWidget *charts, QWidget *parent) : charts(charts),
tree - > setHeaderHidden ( true ) ;
tree - > setHeaderHidden ( true ) ;
tree - > setMouseTracking ( true ) ;
tree - > setMouseTracking ( true ) ;
tree - > setExpandsOnDoubleClick ( false ) ;
tree - > setExpandsOnDoubleClick ( false ) ;
tree - > setEditTriggers ( QAbstractItemView : : AllEditTriggers ) ;
tree - > header ( ) - > setSectionResizeMode ( 0 , QHeaderView : : ResizeToContents ) ;
tree - > header ( ) - > setSectionResizeMode ( 0 , QHeaderView : : ResizeToContents ) ;
tree - > header ( ) - > setStretchLastSection ( true ) ;
tree - > header ( ) - > setStretchLastSection ( true ) ;
tree - > setMinimumHeight ( 300 ) ;
tree - > setMinimumHeight ( 300 ) ;
@ -579,8 +646,10 @@ void SignalView::updateState(const QHash<MessageId, CanData> *msgs) {
if ( model - > rowCount ( ) = = 0 | | ( msgs & & ! msgs - > contains ( model - > msg_id ) ) | | last_msg . dat . size ( ) = = 0 ) return ;
if ( model - > rowCount ( ) = = 0 | | ( msgs & & ! msgs - > contains ( model - > msg_id ) ) | | last_msg . dat . size ( ) = = 0 ) return ;
for ( auto item : model - > root - > children ) {
for ( auto item : model - > root - > children ) {
double value = get_raw_value ( ( uint8_t * ) last_msg . dat . constData ( ) , last_msg . dat . size ( ) , * item - > sig ) ;
double value = 0 ;
item - > sig_val = item - > sig - > formatValue ( value ) ;
if ( item - > sig - > getValue ( ( uint8_t * ) last_msg . dat . constData ( ) , last_msg . dat . size ( ) , & value ) ) {
item - > sig_val = item - > sig - > formatValue ( value ) ;
}
max_value_width = std : : max ( max_value_width , fontMetrics ( ) . width ( item - > sig_val ) ) ;
max_value_width = std : : max ( max_value_width , fontMetrics ( ) . width ( item - > sig_val ) ) ;
}
}
@ -620,11 +689,6 @@ void SignalView::resizeEvent(QResizeEvent* event) {
QFrame : : resizeEvent ( event ) ;
QFrame : : resizeEvent ( event ) ;
}
}
void SignalView : : leaveEvent ( QEvent * event ) {
emit highlight ( nullptr ) ;
QWidget : : leaveEvent ( event ) ;
}
// ValueDescriptionDlg
// ValueDescriptionDlg
ValueDescriptionDlg : : ValueDescriptionDlg ( const ValueDescription & descriptions , QWidget * parent ) : QDialog ( parent ) {
ValueDescriptionDlg : : ValueDescriptionDlg ( const ValueDescription & descriptions , QWidget * parent ) : QDialog ( parent ) {