# include "tools/cabana/mainwin.h"
# include <QApplication>
# include <QCompleter>
# include <QDialogButtonBox>
# include <QFile>
# include <QFileDialog>
# include <QFileInfo>
# include <QHBoxLayout>
# include <QPushButton>
# include <QScreen>
# include <QVBoxLayout>
# include "tools/replay/util.h"
static MainWindow * main_win = nullptr ;
void qLogMessageHandler ( QtMsgType type , const QMessageLogContext & context , const QString & msg ) {
if ( main_win ) emit main_win - > showMessage ( msg , 0 ) ;
}
MainWindow : : MainWindow ( ) : QWidget ( ) {
QVBoxLayout * main_layout = new QVBoxLayout ( this ) ;
main_layout - > setContentsMargins ( 11 , 11 , 11 , 5 ) ;
main_layout - > setSpacing ( 0 ) ;
QHBoxLayout * h_layout = new QHBoxLayout ( ) ;
h_layout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
main_layout - > addLayout ( h_layout ) ;
splitter = new QSplitter ( Qt : : Horizontal , this ) ;
splitter - > setHandleWidth ( 11 ) ;
// DBC file selector
QWidget * messages_container = new QWidget ( this ) ;
QVBoxLayout * messages_layout = new QVBoxLayout ( messages_container ) ;
messages_layout - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
QHBoxLayout * dbc_file_layout = new QHBoxLayout ( ) ;
dbc_combo = new QComboBox ( this ) ;
auto dbc_names = dbc ( ) - > allDBCNames ( ) ;
for ( const auto & name : dbc_names ) {
dbc_combo - > addItem ( QString : : fromStdString ( name ) ) ;
}
dbc_combo - > model ( ) - > sort ( 0 ) ;
dbc_combo - > setEditable ( true ) ;
dbc_combo - > setCurrentText ( QString ( ) ) ;
dbc_combo - > setInsertPolicy ( QComboBox : : NoInsert ) ;
dbc_combo - > completer ( ) - > setCompletionMode ( QCompleter : : PopupCompletion ) ;
QFont font ;
font . setBold ( true ) ;
dbc_combo - > lineEdit ( ) - > setFont ( font ) ;
dbc_file_layout - > addWidget ( dbc_combo ) ;
QPushButton * load_from_paste = new QPushButton ( tr ( " Load from paste " ) , this ) ;
dbc_file_layout - > addWidget ( load_from_paste ) ;
dbc_file_layout - > addStretch ( ) ;
QPushButton * save_btn = new QPushButton ( tr ( " Save DBC " ) , this ) ;
dbc_file_layout - > addWidget ( save_btn ) ;
messages_layout - > addLayout ( dbc_file_layout ) ;
messages_widget = new MessagesWidget ( this ) ;
messages_layout - > addWidget ( messages_widget ) ;
splitter - > addWidget ( messages_container ) ;
charts_widget = new ChartsWidget ( this ) ;
detail_widget = new DetailWidget ( charts_widget , this ) ;
splitter - > addWidget ( detail_widget ) ;
h_layout - > addWidget ( splitter ) ;
// right widgets
QWidget * right_container = new QWidget ( this ) ;
right_container - > setFixedWidth ( 640 ) ;
r_layout = new QVBoxLayout ( right_container ) ;
r_layout - > setContentsMargins ( 11 , 0 , 0 , 0 ) ;
QHBoxLayout * right_hlayout = new QHBoxLayout ( ) ;
QLabel * fingerprint_label = new QLabel ( this ) ;
right_hlayout - > addWidget ( fingerprint_label ) ;
// TODO: click to select another route.
right_hlayout - > addWidget ( new QLabel ( can - > route ( ) ) ) ;
QPushButton * settings_btn = new QPushButton ( " Settings " ) ;
right_hlayout - > addWidget ( settings_btn , 0 , Qt : : AlignRight ) ;
r_layout - > addLayout ( right_hlayout ) ;
video_widget = new VideoWidget ( this ) ;
r_layout - > addWidget ( video_widget , 0 , Qt : : AlignTop ) ;
r_layout - > addWidget ( charts_widget ) ;
h_layout - > addWidget ( right_container ) ;
// status bar
status_bar = new QStatusBar ( this ) ;
status_bar - > setFixedHeight ( 20 ) ;
status_bar - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
status_bar - > setSizeGripEnabled ( true ) ;
progress_bar = new QProgressBar ( ) ;
progress_bar - > setRange ( 0 , 100 ) ;
progress_bar - > setTextVisible ( true ) ;
progress_bar - > setFixedSize ( { 230 , 16 } ) ;
progress_bar - > setVisible ( false ) ;
status_bar - > addPermanentWidget ( progress_bar ) ;
main_layout - > addWidget ( status_bar ) ;
qRegisterMetaType < uint64_t > ( " uint64_t " ) ;
qRegisterMetaType < ReplyMsgType > ( " ReplyMsgType " ) ;
installMessageHandler ( [ this ] ( ReplyMsgType type , const std : : string msg ) {
// use queued connection to recv the log messages from replay.
emit showMessage ( QString : : fromStdString ( msg ) , 3000 ) ;
} ) ;
installDownloadProgressHandler ( [ this ] ( uint64_t cur , uint64_t total , bool success ) {
emit updateProgressBar ( cur , total , success ) ;
} ) ;
main_win = this ;
qInstallMessageHandler ( qLogMessageHandler ) ;
QFile json_file ( " ./car_fingerprint_to_dbc.json " ) ;
if ( json_file . open ( QIODevice : : ReadOnly ) ) {
fingerprint_to_dbc = QJsonDocument : : fromJson ( json_file . readAll ( ) ) ;
}
QObject : : connect ( dbc_combo , SIGNAL ( activated ( const QString & ) ) , SLOT ( loadDBCFromName ( const QString & ) ) ) ;
QObject : : connect ( load_from_paste , & QPushButton : : clicked , this , & MainWindow : : loadDBCFromPaste ) ;
QObject : : connect ( save_btn , & QPushButton : : clicked , this , & MainWindow : : saveDBC ) ;
QObject : : connect ( this , & MainWindow : : showMessage , status_bar , & QStatusBar : : showMessage ) ;
QObject : : connect ( this , & MainWindow : : updateProgressBar , this , & MainWindow : : updateDownloadProgress ) ;
QObject : : connect ( messages_widget , & MessagesWidget : : msgSelectionChanged , detail_widget , & DetailWidget : : setMessage ) ;
QObject : : connect ( charts_widget , & ChartsWidget : : dock , this , & MainWindow : : dockCharts ) ;
QObject : : connect ( charts_widget , & ChartsWidget : : rangeChanged , video_widget , & VideoWidget : : rangeChanged ) ;
QObject : : connect ( settings_btn , & QPushButton : : clicked , this , & MainWindow : : setOption ) ;
QObject : : connect ( can , & CANMessages : : streamStarted , this , & MainWindow : : loadDBCFromFingerprint ) ;
QObject : : connect ( can , & CANMessages : : streamStarted , [ = ] ( ) { fingerprint_label - > setText ( can - > carFingerprint ( ) ) ; } ) ;
}
void MainWindow : : loadDBCFromName ( const QString & name ) {
if ( name ! = dbc ( ) - > name ( ) ) {
dbc ( ) - > open ( name ) ;
dbc_combo - > setCurrentText ( name ) ;
}
}
void MainWindow : : loadDBCFromPaste ( ) {
LoadDBCDialog dlg ( this ) ;
if ( dlg . exec ( ) ) {
dbc ( ) - > open ( " from paste " , dlg . dbc_edit - > toPlainText ( ) ) ;
dbc_combo - > setCurrentText ( " loaded from paste " ) ;
}
}
void MainWindow : : loadDBCFromFingerprint ( ) {
auto fingerprint = can - > carFingerprint ( ) ;
if ( ! fingerprint . isEmpty ( ) & & dbc ( ) - > name ( ) . isEmpty ( ) ) {
auto dbc_name = fingerprint_to_dbc [ fingerprint ] ;
if ( dbc_name ! = QJsonValue : : Undefined ) {
loadDBCFromName ( dbc_name . toString ( ) ) ;
}
}
}
void MainWindow : : saveDBC ( ) {
SaveDBCDialog dlg ( this ) ;
dlg . dbc_edit - > setText ( dbc ( ) - > generateDBC ( ) ) ;
dlg . exec ( ) ;
}
void MainWindow : : updateDownloadProgress ( uint64_t cur , uint64_t total , bool success ) {
if ( success & & cur < total ) {
progress_bar - > setValue ( ( cur / ( double ) total ) * 100 ) ;
progress_bar - > setFormat ( tr ( " Downloading %p% (%1) " ) . arg ( formattedDataSize ( total ) . c_str ( ) ) ) ;
progress_bar - > show ( ) ;
} else {
progress_bar - > hide ( ) ;
}
}
void MainWindow : : dockCharts ( bool dock ) {
if ( dock & & floating_window ) {
floating_window - > removeEventFilter ( charts_widget ) ;
r_layout - > addWidget ( charts_widget ) ;
floating_window - > deleteLater ( ) ;
floating_window = nullptr ;
} else if ( ! dock & & ! floating_window ) {
floating_window = new QWidget ( nullptr ) ;
floating_window - > setLayout ( new QVBoxLayout ( ) ) ;
floating_window - > layout ( ) - > addWidget ( charts_widget ) ;
floating_window - > installEventFilter ( charts_widget ) ;
floating_window - > setMinimumSize ( QGuiApplication : : primaryScreen ( ) - > size ( ) / 2 ) ;
floating_window - > showMaximized ( ) ;
}
}
void MainWindow : : closeEvent ( QCloseEvent * event ) {
main_win = nullptr ;
if ( floating_window )
floating_window - > deleteLater ( ) ;
QWidget : : closeEvent ( event ) ;
}
void MainWindow : : setOption ( ) {
SettingsDlg dlg ( this ) ;
dlg . exec ( ) ;
}
// LoadDBCDialog
LoadDBCDialog : : LoadDBCDialog ( QWidget * parent ) : QDialog ( parent ) {
QVBoxLayout * main_layout = new QVBoxLayout ( this ) ;
dbc_edit = new QTextEdit ( this ) ;
dbc_edit - > setAcceptRichText ( false ) ;
dbc_edit - > setPlaceholderText ( tr ( " paste DBC file here " ) ) ;
main_layout - > addWidget ( dbc_edit ) ;
auto buttonBox = new QDialogButtonBox ( QDialogButtonBox : : Ok | QDialogButtonBox : : Cancel ) ;
main_layout - > addWidget ( buttonBox ) ;
setMinimumSize ( { 640 , 480 } ) ;
QObject : : connect ( buttonBox , & QDialogButtonBox : : accepted , this , & QDialog : : accept ) ;
QObject : : connect ( buttonBox , & QDialogButtonBox : : rejected , this , & QDialog : : reject ) ;
}
// SaveDBCDialog
SaveDBCDialog : : SaveDBCDialog ( QWidget * parent ) : QDialog ( parent ) {
setWindowTitle ( tr ( " Save DBC " ) ) ;
QVBoxLayout * main_layout = new QVBoxLayout ( this ) ;
dbc_edit = new QTextEdit ( this ) ;
dbc_edit - > setAcceptRichText ( false ) ;
main_layout - > addWidget ( dbc_edit ) ;
QPushButton * copy_to_clipboard = new QPushButton ( tr ( " Copy To Clipboard " ) , this ) ;
QPushButton * save_as = new QPushButton ( tr ( " Save As " ) , this ) ;
QHBoxLayout * btn_layout = new QHBoxLayout ( ) ;
btn_layout - > addStretch ( ) ;
btn_layout - > addWidget ( copy_to_clipboard ) ;
btn_layout - > addWidget ( save_as ) ;
main_layout - > addLayout ( btn_layout ) ;
setMinimumSize ( { 640 , 480 } ) ;
QObject : : connect ( copy_to_clipboard , & QPushButton : : clicked , this , & SaveDBCDialog : : copytoClipboard ) ;
QObject : : connect ( save_as , & QPushButton : : clicked , this , & SaveDBCDialog : : saveAs ) ;
}
void SaveDBCDialog : : copytoClipboard ( ) {
dbc_edit - > selectAll ( ) ;
dbc_edit - > copy ( ) ;
QDialog : : accept ( ) ;
}
void SaveDBCDialog : : saveAs ( ) {
QString file_name = QFileDialog : : getSaveFileName ( this , tr ( " Save File " ) ,
QDir : : homePath ( ) + " /untitled.dbc " , tr ( " DBC (*.dbc) " ) ) ;
if ( ! file_name . isEmpty ( ) ) {
QFile file ( file_name ) ;
if ( file . open ( QIODevice : : WriteOnly ) ) {
file . write ( dbc_edit - > toPlainText ( ) . toUtf8 ( ) ) ;
}
QDialog : : accept ( ) ;
}
}