DLT-Viewer의 메시지 항목에 Context 메뉴 추가하기
DLT-Viewer를 사용하다 보면, 각 메시지를 Clipboard로 copy해서 내용을 정리할 때가 많은데, Index부터 시간 등등 불필요한 정보까지 추가되어서 후처리를 해야될 때가 많습니다.
이럴 경우 후처리에 시간이 많이 소요되어서 업무하는데 비효율적인 면이 있고, 수정하느라 손목에 무리가 갈 때도 많습니다.
그래서, 항목을 Clipboard로 copy할 때, copy할 항목을 변경하도록 Context Menu를 추가해 보도록 하겠습니다.
- 메시지 리스트에서 Context Menu를 표시하는 부분을 찾습니다.
- 필요한 메뉴를 하나더 추가합니다.
- 추가한 메뉴에 연결된 Slot함수를 추가합니다.
- 기존 Clipboard로 Copy하는 부분을 수정해서 새로운 메뉴 함수에 추가합니다.
- Copy해서 메모장에 Paste 해서 정확하게 동작하는지 확인합니다.
아래에 로그가 표시되는 DLT Message Table에서 우클릭을 하면, 아래와 같은 Context Menu가 표시됩니다.
위에서 표시되는 Copy Selection to Clipboard는 인덱스 등 많은 부가 정보가 같이 Copy되기 때문에, 필요하지 않은 것들은 빼고, 클립보드로 카피해주는 Copy Selection to Clipboard With Simple Format 이라는 메뉴를 추가해 보겠습니다.
DLT-Viewer 프로젝트를 QtCreator로 여러 봅니다.
위에서 mainwindow.ui를 더블 클릭해서 ui파일을 열어서 Context Menu를 만드는 부분을 찾아봅니다.
위에 UI부분에서 Context Menu가 표시되는 DLT Message Table에서 우클릭으로 Go to slot...을 선택합니다.
위에서 customContextMenuRequested()가 우클릭으로 Context Menu를 표시하는 부분입니다.
해당 함수를 더블 클릭으로 찾아가면..
MainWindow::on_table_customContextMenuRequested()함수에서 Context Menu 항목을 추가해 줍니다.
mainwindow.cpp 파일에서
void MainWindow::on_tableView_customContextMenuRequested(QPoint pos)
{
/* show custom pop menu for configuration */
//... 생략
action = new QAction("&Copy Selection to Clipboard", this);
connect(action, SIGNAL(triggered()), this, SLOT(on_action_menuConfig_Copy_to_clipboard_triggered()));
menu.addAction(action);
//add feature to v2.27.0
action = new QAction("Copy Selection to Clipboard with &Simple Format", this);
connect(action, SIGNAL(triggered()), this, SLOT(on_action_menuConfig_Copy_to_clipboard_with_simple_format_triggered()));
menu.addAction(action);
action = new QAction("C&opy Selection Payload to Clipboard", this);
connect(action, SIGNAL(triggered()), this, SLOT(onActionAenuConfigCopyPayloadToClipboardTriggered()));
menu.addAction(action);
//... 생략
}
void MainWindow::on_action_menuConfig_Copy_to_clipboard_triggered()
{
exportSelection(true,false);
}
//Context Menu에 포함된 Slot 함수를 추가함
void MainWindow::on_action_menuConfig_Copy_to_clipboard_with_simple_format_triggered()
{
//format을 별도로 정해준다. FormatClipboardWithSimpleFormat
exportSelection(true,false, QDltExporter::FormatClipboardWithSimpleFormat);
}
- on_tableView_customContextMenuRequested()함수에 "Copy Selection to Clipboard with Simple Format" 메뉴 추가합니다.
- 해당 메뉴 Action에서 동작을 받을 SLOT함수를 추가 한다.
- on_action_menuConfig_Copy_to_clipboard_with_simple_format_triggered()
- 해당 함수는 MainWindow.h 파일에 선언을 추가한다.
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
//... 생략
//메시지 table에서 발생하는 이벤트를 받을 함수
void on_action_menuConfig_Copy_to_clipboard_with_simple_format_triggered(); //add feature to v2.27.0
//Search Result에서 발생하는 이벤트를 받을 함수
void onActionMenuConfigSearchTableCopyToClipboardWithSimpleFormatTriggered();//add feature to v2.27.0
//... 생략
}
위에서 Message TableView에 추가할 함수와 Search Result에 추가할 함수가 같이 있어서, Search Result에서 customContextMenuRequested()함수를 찾아서 아래와 같이 추가합니다.
void MainWindow::on_tableView_SearchIndex_customContextMenuRequested(QPoint pos)
{
/* show custom pop menu for search table */
//... 생략
action = new QAction("&Copy Selection to Clipboard", this);
connect(action, &QAction::triggered, this, &MainWindow::onActionMenuConfigSearchTableCopyToClipboardTriggered);
menu.addAction(action);
//add feature v2.27.0
action = new QAction("Copy Selection to Clipboard With &Simple Format", this);
connect(action, &QAction::triggered, this, &MainWindow::onActionMenuConfigSearchTableCopyToClipboardWithSimpleFormatTriggered);
menu.addAction(action);
//... 생략
}
void MainWindow::onActionMenuConfigSearchTableCopyToClipboardTriggered()
{
exportSelection_searchTable(QDltExporter::FormatClipboard);
}
//add feature to v2.27.0
void MainWindow::onActionMenuConfigSearchTableCopyToClipboardWithSimpleFormatTriggered()
{
exportSelection_searchTable(QDltExporter::FormatClipboardWithSimpleFormat);
}
위와 같이 추가하면 MainWindow class에는 모두 다 수정이 되었습니다.
하지만 QDltExporter::FormatClipboardWithSimpleFormat은 아직 정의하지 않았기 때문에 에러가 발생합니다.
qdltexporter.h에서
class QDLT_EXPORT QDltExporter : public QThread
{
Q_OBJECT
public:
typedef enum { FormatDlt,FormatAscii,FormatCsv,FormatClipboard,FormatClipboardWithSimpleFormat,FormatClipboardPayloadOnly,FormatDltDecoded,FormatUTF8,
FormatClipboardJiraTable, FormatClipboardJiraTableHead} DltExportFormat;
typedef enum { SelectionAll,SelectionFiltered,SelectionSelected } DltExportSelection;
//...생략
}
위와 같이 FormatClipboardWithSimpleFormat을 추가합니다.
일단 컴파일해서 동작해 보면, ContextMenu가 잘 표시됨을 볼 수 있습니다.
아직 기능을 추가하지 않았으므로 해당 동작은 하지 않는 상태가 됩니다.
동작 부분을 추가해 봅니다.
먼저 DLT Message Table에서 Copy Selection to Clipboard With Simple Format을 선택하면
void MainWindow::exportSelection(bool ascii = true,bool file = false,QDltExporter::DltExportFormat format = QDltExporter::FormatClipboard)
{
Q_UNUSED(ascii);
Q_UNUSED(file);
QModelIndexList list = ui->tableView->selectionModel()->selection().indexes();
filterUpdate(); // update filters of qfile before starting Exporting for RegEx operation
QDltExporter exporter(&qfile,"",&pluginManager,format,QDltExporter::SelectionSelected,&list,project.settings->automaticTimeSettings,project.settings->utcOffset,project.settings->dst,QDltOptManager::getInstance()->getDelimiter());
connect(&exporter,SIGNAL(clipboard(QString)),this,SLOT(clipboard(QString)));
exporter.exportMessages();
disconnect(&exporter,SIGNAL(clipboard(QString)),this,SLOT(clipboard(QString)));
}
위와 같이 exportSelection()함수가 수행이 되고, QDltExportor 클래스를 생성하면서 format을 넘겨줘서 어떤 포맷을 사용할지 넘겨주고, exporter.exportMessages() 함수에서 실제 Export가 됩니다.
위 exportSelection()함수에서는 수정할 것이 없고, QDltExporter::exportMessage()함수에서도 실질적인 메시지 하나에 대해서 export하는 exportMsg()함수를 수정해야 한다.
bool QDltExporter::exportMsg(unsigned long int num, QDltMsg &msg, QByteArray &buf,QFile &to)
{
//...생략
else if(exportFormat == QDltExporter::FormatAscii ||
exportFormat == QDltExporter::FormatUTF8 ||
exportFormat == QDltExporter::FormatClipboard || //add feature to v2.27.0
exportFormat == QDltExporter::FormatClipboardWithSimpleFormat ||
exportFormat == QDltExporter::FormatClipboardPayloadOnly)
{
QString text;
/* get message ASCII text */
/* get message ASCII text */
if(exportFormat != QDltExporter::FormatClipboardPayloadOnly)
{
//Simple Format일 경우에는 Index는 출력하지 않는다.
if(exportFormat != QDltExporter::FormatClipboardWithSimpleFormat)
{
//Index
if(exportSelection == QDltExporter::SelectionAll)
text += QString("%1 ").arg(num);
else if(exportSelection == QDltExporter::SelectionFiltered)
text += QString("%1 ").arg(from->getMsgFilterPos(num));
else if(exportSelection == QDltExporter::SelectionSelected)
text += QString("%1 ").arg(from->getMsgFilterPos(selectedRows[num]));
else
return false;
}
//Time
if( automaticTimeSettings == 0 )
text += QString("%1.%2").arg(msg.getGmTimeWithOffsetString(utcOffset,dst)).arg(msg.getMicroseconds(),6,10,QLatin1Char('0'));
else
text += QString("%1.%2").arg(msg.getTimeString()).arg(msg.getMicroseconds(),6,10,QLatin1Char('0'));
//Timestamp
text += QString(" %1.%2").arg(msg.getTimestamp()/10000).arg(msg.getTimestamp()%10000,4,10,QLatin1Char('0'));
//Simple Format일 경우에는 출력하지 않는다.
if(exportFormat != QDltExporter::FormatClipboardWithSimpleFormat)
{
text += QString(" %1").arg(msg.getMessageCounter());
text += QString(" %1").arg(msg.getEcuid());
}
text += QString(" %1").arg(msg.getApid());
text += QString(" %1").arg(msg.getCtid());
//Simple Format일 경우에는 출력하지 않는다.
if(exportFormat != QDltExporter::FormatClipboardWithSimpleFormat)
{
text += QString(" %1").arg(msg.getSessionid());
text += QString(" %2").arg(msg.getTypeString());
text += QString(" %2").arg(msg.getSubtypeString());
text += QString(" %2").arg(msg.getModeString());
text += QString(" %1").arg(msg.getNumberOfArguments());
}
text += " ";
}
QString payload = msg.toStringPayload().simplified().remove(QChar::Null);
if(from) from->applyRegExString(msg,payload);
text += payload;
text += "\n";
try
{
if(exportFormat == QDltExporter::FormatAscii)
/* write to file */
to.write(text.toLatin1().constData());
else if (exportFormat == QDltExporter::FormatUTF8)
to.write(text.toUtf8().constData());
else if(exportFormat == QDltExporter::FormatClipboard ||
exportFormat == QDltExporter::FormatClipboardWithSimpleFormat || //add feature to v2.27.0
exportFormat == QDltExporter::FormatClipboardPayloadOnly)
clipboardString += text;
}
catch (...)
{
}
}
//... 생략
}
위에서 Simple Format일 때 출력하지 않을 부분을 if 문으로 묶어 주고 아래 try..catch문에서 FormatClipboardWithSimpleFormat일 경우에도 clipboardString에 문자열을 더해 주도록 추가한다.
그리고, QDltExporter::finish()에서 마지막으로 출력할 부분을 어디로 출력할지 수정해줘야 된다.
bool QDltExporter::finish()
{
//...생략
else if (exportFormat == QDltExporter::FormatClipboard ||
exportFormat == QDltExporter::FormatClipboardWithSimpleFormat || //add feature to v2.27.0
exportFormat == QDltExporter::FormatClipboardPayloadOnly ||
exportFormat == QDltExporter::FormatClipboardJiraTable ||
exportFormat == QDltExporter::FormatClipboardJiraTableHead)
{
/*remove '\n' from the string*/
if (clipboardString.endsWith('\n'))
{
clipboardString.resize(clipboardString.size() - 1);
}
/* remove null characters */
clipboardString.remove(QChar::Null);
emit clipboard(clipboardString);
}
return true;
}
이제 실행 후 메시지를 Copy를 해보면 불필요한 내용은 clipboard로 copy되지 않는 것을 볼 수 있다.
결과비교
- 36232 2025/03/06 16:15:21.109732 5614.6462 208 ECU1 APP1 CID1 1101 log info verbose 1 [Thread #2135] void DLTTester::updateTime(QDateTime, QString) TimeFrom:16:16:19
- 2025/03/06 16:15:21.109732 5614.6462 APP1 CID1 [Thread #2135] void DLTTester::updateTime(QDateTime, QString) TimeFrom:16:16:19
두번째 항목이 Index와 Message Counter 등등이 없는 것을 볼 수 있다.