2
0
forked from Ivasoft/DSView
Files
DSView/DSView/pv/dock/protocoldock.cpp
2024-04-22 15:41:58 +08:00

1116 lines
34 KiB
C++

/*
* This file is part of the DSView project.
* DSView is based on PulseView.
*
* Copyright (C) 2013 DreamSourceLab <support@dreamsourcelab.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "protocoldock.h"
#include "../sigsession.h"
#include "../view/decodetrace.h"
#include "../data/decodermodel.h"
#include "../data/decoderstack.h"
#include "../dialogs/protocollist.h"
#include "../dialogs/protocolexp.h"
#include "../view/view.h"
#include <QObject>
#include <QHBoxLayout>
#include <QPainter>
#include <QFormLayout>
#include <QStandardItemModel>
#include <QTableView>
#include <QHeaderView>
#include <QScrollBar>
#include <QRegularExpression>
#include <QFuture>
#include <QProgressDialog>
#include <QtConcurrent/QtConcurrent>
#include <QSizePolicy>
#include <assert.h>
#include <map>
#include <string>
#include <algorithm>
#include <QTableWidgetItem>
#include <QHeaderView>
#include "../ui/msgbox.h"
#include "../dsvdef.h"
#include "../config/appconfig.h"
#include "../data/decode/decoderstatus.h"
#include "../data/decode/decoder.h"
#include "../log.h"
#include "../ui/langresource.h"
#include "../appcontrol.h"
#include "../ui/fn.h"
using namespace std;
namespace pv {
namespace dock {
//-----------ProtocolDock
ProtocolDock::ProtocolDock(QWidget *parent, view::View &view, SigSession *session) :
QScrollArea(parent),
_view(view)
{
_session = session;
_cur_search_index = -1;
_search_edited = false;
_pro_add_button = NULL;
//-----------------------------get protocol list
GSList *l = const_cast<GSList*>(srd_decoder_list());
std::map<std::string, int> pro_key_table;
QString repeatNammes;
for(; l; l = l->next)
{
const srd_decoder *const d = (srd_decoder*)l->data;
assert(d);
DecoderInfoItem *info = new DecoderInfoItem();
srd_decoder *dec = (srd_decoder *)(l->data);
info->_data_handle = dec;
_decoderInfoList.push_back(info);
std::string prokey(dec->id);
if (pro_key_table.find(prokey) != pro_key_table.end())
{
if (repeatNammes != "")
repeatNammes += ",";
repeatNammes += QString(dec->id);
}
else
{
pro_key_table[prokey] = 1;
}
}
g_slist_free(l);
sort(_decoderInfoList.begin(), _decoderInfoList.end(), ProtocolDock::protocol_sort_callback);
if (repeatNammes != ""){
QString err = L_S(STR_PAGE_MSG, S_ID(IDS_MSG_DECODER_REPEAT), "Any decoder have repeated id or name:");
err += repeatNammes;
MsgBox::Show(L_S(STR_PAGE_MSG, S_ID(IDS_MSG_ERROR), "error"), err.toUtf8().data());
}
//-----------------------------top panel
QWidget *top_panel = new QWidget();
top_panel->setMinimumHeight(70);
_top_panel = top_panel;
QWidget* bot_panel = new QWidget();
_pro_add_button = new QPushButton(top_panel);
_pro_add_button->setFlat(true);
_del_all_button = new QPushButton(top_panel);
_del_all_button->setFlat(true);
_del_all_button->setCheckable(true);
_pro_keyword_edit = new KeywordLineEdit(top_panel, this);
_pro_keyword_edit->setReadOnly(true);
_pro_search_button = new XToolButton(top_panel);
QHBoxLayout *pro_search_lay = new QHBoxLayout();
pro_search_lay->setSpacing(2);
pro_search_lay->addWidget(_pro_add_button);
pro_search_lay->addWidget(_del_all_button);
pro_search_lay->addWidget(_pro_keyword_edit, 1);
pro_search_lay->addWidget(_pro_search_button);
_top_layout = new QVBoxLayout();
_top_layout->addLayout(pro_search_lay);
_top_layout->addStretch(1);
_top_layout->setSpacing(5);
top_panel->setLayout(_top_layout);
//-----------------------------bottom panel
_bot_set_button = new QPushButton(bot_panel);
_bot_set_button->setFlat(true);
_bot_save_button = new QPushButton(bot_panel);
_bot_save_button->setFlat(true);
_dn_nav_button = new QPushButton(bot_panel);
_dn_nav_button->setFlat(true);
_bot_title_label = new QLabel(bot_panel);
QHBoxLayout *bot_title_layout = new QHBoxLayout();
bot_title_layout->setSpacing(2);
bot_title_layout->addWidget(_bot_set_button);
bot_title_layout->addWidget(_bot_save_button);
bot_title_layout->addWidget(_bot_title_label, 1);
bot_title_layout->addWidget(_dn_nav_button);
_pre_button = new QPushButton(bot_panel);
_ann_search_button = new QPushButton(bot_panel); //search icon
_nxt_button = new QPushButton(bot_panel);
_ann_search_edit = new PopupLineEdit(bot_panel);
_ann_search_edit->EnableCatchKeyPress(true);
_ann_search_button->setFixedWidth(_ann_search_button->height());
_ann_search_button->setDisabled(true);
QHBoxLayout *ann_search_layout = new QHBoxLayout();
ann_search_layout->setSpacing(2);
ann_search_layout->addWidget(_pre_button);
ann_search_layout->addWidget(_ann_search_button);
ann_search_layout->addWidget(_ann_search_edit, 1);
ann_search_layout->addWidget(_nxt_button);
_table_view = new QTableView(bot_panel);
_table_view->setModel(_session->get_decoder_model());
_table_view->setAlternatingRowColors(true);
_table_view->setShowGrid(false);
_table_view->horizontalHeader()->setStretchLastSection(true);
_table_view->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
_table_view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
_matchs_title_label = new QLabel();
_matchs_label = new QLabel();
QHBoxLayout *match_layout = new QHBoxLayout();
match_layout->addWidget(_matchs_title_label, 0, Qt::AlignLeft);
match_layout->addWidget(_matchs_label, 0, Qt::AlignLeft);
match_layout->addStretch(1);
QVBoxLayout *bot_layout = new QVBoxLayout();
bot_layout->addLayout(bot_title_layout);
bot_layout->addLayout(ann_search_layout);
bot_layout->addLayout(match_layout);
bot_layout->addWidget(_table_view);
bot_panel->setLayout(bot_layout);
QSplitter *split_widget = new QSplitter(this);
split_widget->insertWidget(0, top_panel);
split_widget->insertWidget(1, bot_panel);
split_widget->setOrientation(Qt::Vertical);
split_widget->setCollapsible(0, false);
split_widget->setCollapsible(1, false);
this->setWidgetResizable(true);
this->setWidget(split_widget);
split_widget->setObjectName("protocolWidget");
connect(_dn_nav_button, SIGNAL(clicked()),this, SLOT(nav_table_view()));
connect(_bot_save_button, SIGNAL(clicked()),this, SLOT(export_table_view()));
connect(_bot_set_button, SIGNAL(clicked()),this, SLOT(set_model()));
connect(_pre_button, SIGNAL(clicked()),this, SLOT(search_pre()));
connect(_nxt_button, SIGNAL(clicked()),this, SLOT(search_nxt()));
connect(_pro_add_button, SIGNAL(clicked()),this, SLOT(on_add_protocol()));
connect(_del_all_button, SIGNAL(clicked()),this, SLOT(on_del_all_protocol()));
connect(this, SIGNAL(protocol_updated()), this, SLOT(update_model()));
connect(_table_view, SIGNAL(clicked(QModelIndex)), this, SLOT(item_clicked(QModelIndex)));
connect(_table_view->horizontalHeader(), SIGNAL(sectionResized(int,int,int)),
this, SLOT(column_resize(int, int, int)));
connect(_pro_search_button, SIGNAL(clicked()), this, SLOT(show_protocol_select()));
connect(_ann_search_edit, SIGNAL(editingFinished()), this, SLOT(search_changed()));
ADD_UI(this);
}
ProtocolDock::~ProtocolDock()
{
//destroy protocol item layers
for (auto it = _protocol_lay_items.begin(); it != _protocol_lay_items.end(); it++){
DESTROY_QT_LATER(*it);
}
_protocol_lay_items.clear();
//clear protocol infos list
RELEASE_ARRAY(_decoderInfoList);
REMOVE_UI(this);
}
void ProtocolDock::retranslateUi()
{
_ann_search_edit->setPlaceholderText(L_S(STR_PAGE_DLG, S_ID(IDS_DLG_SEARCH), "search"));
_matchs_title_label->setText(L_S(STR_PAGE_DLG, S_ID(IDS_DLG_MATCHING_ITEMS), "Matching Items:"));
_bot_title_label->setText(L_S(STR_PAGE_DLG, S_ID(IDS_DLG_PROTOCOL_LIST_VIEWER), "Protocol List Viewer"));
_pro_keyword_edit->ResetText();
}
void ProtocolDock::reStyle()
{
QString iconPath = GetIconPath();
if (_pro_add_button == NULL)
{
return;
}
_pro_add_button->setIcon(QIcon(iconPath+"/add.svg"));
_del_all_button->setIcon(QIcon(iconPath+"/del.svg"));
_bot_set_button->setIcon(QIcon(iconPath+"/gear.svg"));
_bot_save_button->setIcon(QIcon(iconPath+"/save.svg"));
_dn_nav_button->setIcon(QIcon(iconPath+"/nav.svg"));
_pre_button->setIcon(QIcon(iconPath+"/pre.svg"));
_nxt_button->setIcon(QIcon(iconPath+"/next.svg"));
_ann_search_button->setIcon(QIcon(iconPath+"/search.svg"));
_pro_search_button->setIcon(QIcon(iconPath + "/search.svg"));
for (auto item : _protocol_lay_items){
item->ResetStyle();
}
}
int ProtocolDock::decoder_name_cmp(const void *a, const void *b)
{
return strcmp(((const srd_decoder*)a)->name,
((const srd_decoder*)b)->name);
}
int ProtocolDock::get_protocol_index_by_id(QString id)
{
int dex = 0;
for (auto info : _decoderInfoList){
srd_decoder *dec = (srd_decoder *)(info->_data_handle);
QString proid(dec->id);
if (id == proid){
return dex;
}
++dex;
}
return -1;
}
void ProtocolDock::on_add_protocol()
{
if (_decoderInfoList.size() == 0){
MsgBox::Show(NULL, L_S(STR_PAGE_MSG, S_ID(IDS_MSG_DECODER_LIST_EMPTY), "Decoder list is empty!"));
return;
}
if (_selected_protocol_id == ""){
MsgBox::Show(NULL, L_S(STR_PAGE_MSG, S_ID(IDS_MSG_NO_SEL_DECODER), "Please select a decoder!"));
return;
}
int dex = this->get_protocol_index_by_id(_selected_protocol_id);
assert(dex >= 0);
//check the base protocol
srd_decoder *const dec = (srd_decoder *)(_decoderInfoList[dex]->_data_handle);
QString pro_id(dec->id);
std::list<data::decode::Decoder*> sub_decoders;
assert(dec->inputs);
QString input_id = parse_protocol_id((char *)dec->inputs->data);
if (input_id != "logic")
{
pro_id = ""; //reset base protocol
int base_dex = get_output_protocol_by_id(input_id);
sub_decoders.push_front(new data::decode::Decoder(dec));
while (base_dex != -1)
{
srd_decoder *base_dec = (srd_decoder *)(_decoderInfoList[base_dex]->_data_handle);
pro_id = QString(base_dec->id); //change base protocol
assert(base_dec->inputs);
input_id = parse_protocol_id((char *)base_dec->inputs->data);
if (input_id == "logic")
{
break;
}
sub_decoders.push_front(new data::decode::Decoder(base_dec));
pro_id = ""; //reset base protocol
base_dex = get_output_protocol_by_id(input_id);
}
}
if (pro_id == ""){
MsgBox::Show(L_S(STR_PAGE_MSG, S_ID(IDS_MSG_ERROR), "error"),
L_S(STR_PAGE_MSG, S_ID(IDS_MSG_FIND_BASE_DECODER_ERROR), "find the base decoder error!"));
for(auto sub: sub_decoders){
delete sub;
}
sub_decoders.clear();
return;
}
add_protocol_by_id(pro_id, false, sub_decoders);
}
bool ProtocolDock::add_protocol_by_id(QString id, bool silent, std::list<pv::data::decode::Decoder*> &sub_decoders)
{
if (_session->get_device()->get_work_mode() != LOGIC) {
dsv_info("Protocol Analyzer\nProtocol Analyzer is only valid in Digital Mode!");
return false;
}
int dex = this->get_protocol_index_by_id(id);
if (dex == -1){
dsv_err("Protocol not exists! id:%s", id.toUtf8().data());
return false;
}
srd_decoder *const decoder = (srd_decoder *)(_decoderInfoList[dex]->_data_handle);
DecoderStatus *dstatus = new DecoderStatus();
dstatus->m_format = (int)DecoderDataFormat::hex;
QString protocolName(decoder->name);
QString protocolId(decoder->id);
if (sub_decoders.size()){
auto it = sub_decoders.end();
it--;
protocolName = QString((*it)->decoder()->name);
protocolId = QString((*it)->decoder()->id);
}
pv::view::Trace *trace = NULL;
if (_session->add_decoder(decoder, silent, dstatus, sub_decoders, trace) == false){
return false;
}
// create item layer
ProtocolItemLayer *layer = new ProtocolItemLayer(_top_panel, protocolName, this);
_protocol_lay_items.push_back(layer);
_top_layout->insertLayout(_protocol_lay_items.size(), layer);
layer->m_decoderStatus = dstatus;
layer->m_protocolId = protocolId;
layer->_trace = trace;
// set current protocol format
string fmt = AppConfig::Instance().GetProtocolFormat(protocolId.toStdString());
if (fmt != "")
{
layer->SetProtocolFormat(fmt.c_str());
dstatus->m_format = DecoderDataFormat::Parse(fmt.c_str());
}
// progress connection
const auto &decode_sigs = _session->get_decode_signals();
protocol_updated();
connect(decode_sigs.back(), SIGNAL(decoded_progress(int)), this, SLOT(decoded_progress(int)));
adjustPannelSize();
return true;
}
void ProtocolDock::on_del_all_protocol(){
if (_protocol_lay_items.size() == 0){
MsgBox::Show(NULL, L_S(STR_PAGE_MSG, S_ID(IDS_MSG_NO_DECODER_DEL), "Have no decoder to remove!"), this);
return;
}
QString strMsg(L_S(STR_PAGE_MSG, S_ID(IDS_MSG_DECODER_CONFIRM_DEL_ALL), "Are you sure to remove all decoder?"));
if (MsgBox::Confirm(strMsg, this)){
del_all_protocol();
}
}
void ProtocolDock::del_all_protocol()
{
if (_protocol_lay_items.size() > 0)
{
_session->clear_all_decoder();
for (auto it = _protocol_lay_items.begin(); it != _protocol_lay_items.end(); it++)
{
DESTROY_QT_LATER((*it)); //destory control
}
_protocol_lay_items.clear();
this->update();
protocol_updated();
adjustPannelSize();
}
}
void ProtocolDock::decoded_progress(int progress)
{
const auto &decode_sigs = _session->get_decode_signals();
unsigned int index = 0;
for(auto d : decode_sigs) {
int pg = d->get_progress();
QString err;
if (d->decoder()->out_of_memory())
err = L_S(STR_PAGE_DLG, S_ID(IDS_DLG_OUT_OF_MEMORY), "Out of Memory");
if (index < _protocol_lay_items.size())
{
ProtocolItemLayer &lay = *(_protocol_lay_items.at(index));
lay.SetProgress(pg, err);
// have custom data format
if (pg == 100 && lay.m_decoderStatus != NULL){
lay.enable_format(lay.m_decoderStatus->m_bNumeric);
}
}
index++;
}
if (progress == 0 || progress % 10 == 1){
update_model();
}
}
void ProtocolDock::set_model()
{
pv::dialogs::ProtocolList *protocollist_dlg = new pv::dialogs::ProtocolList(this, _session);
protocollist_dlg->exec();
resize_table_view(_session->get_decoder_model());
_model_proxy.setSourceModel(_session->get_decoder_model());
search_done();
// clear mark_index of all DecoderStacks
const auto &decode_sigs = _session->get_decode_signals();
for(auto d : decode_sigs) {
d->decoder()->set_mark_index(-1);
}
}
void ProtocolDock::update_model()
{
pv::data::DecoderModel *decoder_model = _session->get_decoder_model();
const auto &decode_sigs = _session->get_decode_signals();
if (decode_sigs.size() == 0)
decoder_model->setDecoderStack(NULL);
else if (!decoder_model->getDecoderStack())
decoder_model->setDecoderStack(decode_sigs.at(0)->decoder());
else {
unsigned int index = 0;
for(auto d : decode_sigs) {
if (d->decoder() == decoder_model->getDecoderStack()) {
decoder_model->setDecoderStack(d->decoder());
break;
}
index++;
}
if (index >= decode_sigs.size())
decoder_model->setDecoderStack(decode_sigs.at(0)->decoder());
}
_model_proxy.setSourceModel(decoder_model);
search_done();
resize_table_view(decoder_model);
}
void ProtocolDock::resize_table_view(data::DecoderModel* decoder_model)
{
if (decoder_model->getDecoderStack()) {
for (int i = 0; i < decoder_model->columnCount(QModelIndex()) - 1; i++) {
_table_view->resizeColumnToContents(i);
if (_table_view->columnWidth(i) > 200)
_table_view->setColumnWidth(i, 200);
}
int top_row = _table_view->rowAt(0);
int bom_row = _table_view->rowAt(_table_view->height());
if (bom_row >= top_row && top_row >= 0) {
for (int i = top_row; i <= bom_row; i++)
_table_view->resizeRowToContents(i);
}
}
}
void ProtocolDock::item_clicked(const QModelIndex &index)
{
pv::data::DecoderModel *decoder_model = _session->get_decoder_model();
auto decoder_stack = decoder_model->getDecoderStack();
if (decoder_stack) {
pv::data::decode::Annotation ann;
if (decoder_stack->list_annotation(&ann, index.column(), index.row())) {
const auto &decode_sigs = _session->get_decode_signals();
for(auto d : decode_sigs) {
d->decoder()->set_mark_index(-1);
}
decoder_stack->set_mark_index((ann.start_sample()+ann.end_sample())/2);
_session->show_region(ann.start_sample(), ann.end_sample(), false);
}
}
_table_view->resizeRowToContents(index.row());
if (index.column() != _model_proxy.filterKeyColumn()) {
_model_proxy.setFilterKeyColumn(index.column());
_model_proxy.setSourceModel(decoder_model);
search_done();
}
QModelIndex filterIndex = _model_proxy.mapFromSource(index);
if (filterIndex.isValid()) {
_cur_search_index = filterIndex.row();
} else {
if (_model_proxy.rowCount() == 0) {
_cur_search_index = -1;
} else {
uint64_t up = 0;
uint64_t dn = _model_proxy.rowCount() - 1;
do {
uint64_t md = (up + dn)/2;
QModelIndex curIndex = _model_proxy.mapToSource(_model_proxy.index(md,_model_proxy.filterKeyColumn()));
if (index.row() == curIndex.row()) {
_cur_search_index = md;
break;
} else if (md == up) {
if (curIndex.row() < index.row() && up < dn) {
QModelIndex nxtIndex = _model_proxy.mapToSource(_model_proxy.index(md+1,_model_proxy.filterKeyColumn()));
if (nxtIndex.row() < index.row())
md++;
}
_cur_search_index = md + ((curIndex.row() < index.row()) ? 0.5 : -0.5);
break;
} else if (curIndex.row() < index.row()) {
up = md;
} else if (curIndex.row() > index.row()) {
dn = md;
}
}while(1);
}
}
}
void ProtocolDock::column_resize(int index, int old_size, int new_size)
{
(void)index;
(void)old_size;
(void)new_size;
pv::data::DecoderModel *decoder_model = _session->get_decoder_model();
if (decoder_model->getDecoderStack()) {
int top_row = _table_view->rowAt(0);
int bom_row = _table_view->rowAt(_table_view->height());
if (bom_row >= top_row && top_row >= 0) {
for (int i = top_row; i <= bom_row; i++)
_table_view->resizeRowToContents(i);
}
}
}
void ProtocolDock::export_table_view()
{
pv::dialogs::ProtocolExp *protocolexp_dlg = new pv::dialogs::ProtocolExp(this, _session);
protocolexp_dlg->exec();
}
void ProtocolDock::nav_table_view()
{
uint64_t row_index = 0;
pv::data::DecoderModel *decoder_model = _session->get_decoder_model();
auto decoder_stack = decoder_model->getDecoderStack();
if (decoder_stack) {
uint64_t offset = _view.offset() * (decoder_stack->samplerate() * _view.scale());
std::map<const pv::data::decode::Row, bool> rows = decoder_stack->get_rows_lshow();
int column = _model_proxy.filterKeyColumn();
for (std::map<const pv::data::decode::Row, bool>::const_iterator i = rows.begin();
i != rows.end(); i++) {
if ((*i).second && column-- == 0) {
row_index = decoder_stack->get_annotation_index((*i).first, offset);
break;
}
}
QModelIndex index = _model_proxy.mapToSource(_model_proxy.index(row_index, _model_proxy.filterKeyColumn()));
if(index.isValid()){
pv::data::decode::Annotation ann;
if (decoder_stack->list_annotation(&ann, index.column(), index.row()))
{
_table_view->scrollTo(index);
_table_view->setCurrentIndex(index);
const auto &decode_sigs = _session->get_decode_signals();
for(auto d : decode_sigs) {
d->decoder()->set_mark_index(-1);
}
decoder_stack->set_mark_index((ann.start_sample()+ann.end_sample())/2);
_view.set_all_update(true);
_view.update();
}
}
}
}
void ProtocolDock::search_pre()
{
search_update();
// now the proxy only contains rows that match the name
// let's take the pre one and map it to the original model
if (_model_proxy.rowCount() == 0) {
_table_view->scrollToTop();
_table_view->clearSelection();
_matchs_label->setText(QString::number(0));
_cur_search_index = -1;
return;
}
int i = 0;
uint64_t rowCount = _model_proxy.rowCount();
QModelIndex matchingIndex;
pv::data::DecoderModel *decoder_model = _session->get_decoder_model();
auto decoder_stack = decoder_model->getDecoderStack();
do {
_cur_search_index--;
if (_cur_search_index <= -1 || _cur_search_index >= _model_proxy.rowCount())
_cur_search_index = _model_proxy.rowCount() - 1;
matchingIndex = _model_proxy.mapToSource(_model_proxy.index(ceil(_cur_search_index),_model_proxy.filterKeyColumn()));
if (!decoder_stack || !matchingIndex.isValid())
break;
i = 1;
uint64_t row = matchingIndex.row() + 1;
uint64_t col = matchingIndex.column();
pv::data::decode::Annotation ann;
bool ann_valid = false;
while(i < _str_list.size()) {
QString nxt = _str_list.at(i);
do {
ann_valid = decoder_stack->list_annotation(&ann, col, row);
row++;
}
while(ann_valid && !ann.is_numberic());
if (ann_valid){
QString source = ann.annotations().at(0);
if (source.contains(nxt))
i++;
else
break;
}
else{
break;
}
}
}
while(i < _str_list.size() && --rowCount);
if(i >= _str_list.size() && matchingIndex.isValid()){
_table_view->scrollTo(matchingIndex);
_table_view->setCurrentIndex(matchingIndex);
_table_view->clicked(matchingIndex);
} else {
_table_view->scrollToTop();
_table_view->clearSelection();
_matchs_label->setText(QString::number(0));
_cur_search_index = -1;
}
}
void ProtocolDock::search_nxt()
{
search_update();
// now the proxy only contains rows that match the name
// let's take the pre one and map it to the original model
if (_model_proxy.rowCount() == 0) {
_table_view->scrollToTop();
_table_view->clearSelection();
_matchs_label->setText(QString::number(0));
_cur_search_index = -1;
return;
}
int i = 0;
uint64_t rowCount = _model_proxy.rowCount();
QModelIndex matchingIndex;
pv::data::DecoderModel *decoder_model = _session->get_decoder_model();
auto decoder_stack = decoder_model->getDecoderStack();
if (decoder_stack == NULL){
dsv_err("decoder_stack is null");
return;
}
do {
_cur_search_index++;
if (_cur_search_index < 0 || _cur_search_index >= _model_proxy.rowCount())
_cur_search_index = 0;
matchingIndex = _model_proxy.mapToSource(_model_proxy.index(floor(_cur_search_index),_model_proxy.filterKeyColumn()));
if (!matchingIndex.isValid())
break;
i = 1;
uint64_t row = matchingIndex.row() + 1;
uint64_t col = matchingIndex.column();
pv::data::decode::Annotation ann;
bool ann_valid = false;
while(i < _str_list.size()) {
QString nxt = _str_list.at(i);
do {
ann_valid = decoder_stack->list_annotation(&ann, col, row);
row++;
}
while(ann_valid && !ann.is_numberic());
if (ann_valid){
QString source = ann.annotations().at(0);
if (source.contains(nxt))
i++;
else
break;
}
else{
break;
}
}
}while(i < _str_list.size() && --rowCount);
if(i >= _str_list.size() && matchingIndex.isValid()){
_table_view->scrollTo(matchingIndex);
_table_view->setCurrentIndex(matchingIndex);
_table_view->clicked(matchingIndex);
} else {
_table_view->scrollToTop();
_table_view->clearSelection();
_matchs_label->setText(QString::number(0));
_cur_search_index = -1;
}
}
void ProtocolDock::search_done()
{
QString str = _ann_search_edit->text().trimmed();
QRegularExpression rx("(-)");
_str_list = str.split(rx);
_model_proxy.setFilterFixedString(_str_list.first());
if (_str_list.size() > 1)
_matchs_label->setText("...");
else
_matchs_label->setText(QString::number(_model_proxy.rowCount()));
}
void ProtocolDock::search_changed()
{
_search_edited = true;
_matchs_label->setText("...");
}
void ProtocolDock::search_update()
{
if (!_search_edited)
return;
pv::data::DecoderModel *decoder_model = _session->get_decoder_model();
auto decoder_stack = decoder_model->getDecoderStack();
if (!decoder_stack)
return;
if (decoder_stack->list_annotation_size(_model_proxy.filterKeyColumn()) > ProgressRows) {
QFuture<void> future;
future = QtConcurrent::run([&]{
search_done();
});
Qt::WindowFlags flags = Qt::CustomizeWindowHint;
QProgressDialog dlg(L_S(STR_PAGE_DLG, S_ID(IDS_DLG_SEARCHING), "Searching..."),
L_S(STR_PAGE_DLG, S_ID(IDS_DLG_CANCEL), "Cancel"),0,0,this,flags);
dlg.setWindowModality(Qt::WindowModal);
dlg.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowSystemMenuHint |
Qt::WindowMinimizeButtonHint | Qt::WindowMaximizeButtonHint);
dlg.setCancelButton(NULL);
QFutureWatcher<void> watcher;
connect(&watcher,SIGNAL(finished()),&dlg,SLOT(cancel()));
watcher.setFuture(future);
dlg.exec();
} else {
search_done();
}
_search_edited = false;
}
//-------------------IProtocolItemLayerCallback
void ProtocolDock::OnProtocolSetting(void *handle){
for (auto it = _protocol_lay_items.begin(); it != _protocol_lay_items.end(); it++){
if ((*it) == handle){
void *key_handel = (*it)->get_protocol_key_handel();
_session->rst_decoder_by_key_handel(key_handel);
protocol_updated();
break;
}
}
}
void ProtocolDock::OnProtocolDelete(void *handle){
QString strMsg(L_S(STR_PAGE_MSG, S_ID(IDS_MSG_DECODER_CONFIRM_DEL), "Are you sure to remove this decoder?"));
if (!MsgBox::Confirm(strMsg, this)){
return;
}
for (auto it = _protocol_lay_items.begin(); it != _protocol_lay_items.end(); it++)
{
if ((*it) == handle)
{
auto lay = (*it);
void *key_handel = lay->get_protocol_key_handel();
_protocol_lay_items.erase(it);
DESTROY_QT_LATER(lay);
_session->remove_decoder_by_key_handel(key_handel);
protocol_updated();
break;
}
}
adjustPannelSize();
}
void ProtocolDock::OnProtocolFormatChanged(QString format, void *handle){
for (auto it = _protocol_lay_items.begin(); it != _protocol_lay_items.end(); it++){
if ((*it) == handle){
auto lay = (*it);
AppConfig::Instance().SetProtocolFormat(lay->m_protocolId.toStdString(), format.toStdString());
if (lay->m_decoderStatus != NULL)
{
lay->m_decoderStatus->m_format = DecoderDataFormat::Parse(format.toStdString().c_str());
protocol_updated();
}
break;
}
}
}
bool ProtocolDock::protocol_sort_callback(const DecoderInfoItem *o1, const DecoderInfoItem *o2)
{
srd_decoder *dec1 = (srd_decoder *)(o1->_data_handle);
srd_decoder *dec2 = (srd_decoder *)(o2->_data_handle);
const char *s1 = dec1->name;
const char *s2 = dec2->name;
char c1 = 0;
char c2 = 0;
while (*s1 && *s2)
{
c1 = *s1;
c2 = *s2;
if (c1 >= 'a' && c1 <= 'z') c1 -= 32;
if (c2 >= 'a' && c2 <= 'z') c2 -= 32;
if (c1 > c2)
return false;
else if (c1 < c2)
return true;
s1++;
s2++;
}
if (*s1)
return false;
else if (*s2)
return true;
return true;
}
QString ProtocolDock::parse_protocol_id(const char *id)
{
if (id == NULL || *id == 0){
assert(false);
}
char buf[25];
strncpy(buf, id, sizeof(buf)-1);
char *rd = buf;
char *start = NULL;
unsigned int len = 0;
while (*rd && len - 1 < sizeof(buf))
{
if (*rd == '['){
start = rd++;
}
else if (*rd == ']'){
*rd = 0;
break;
}
++rd;
len++;
}
if (start == NULL){
start = const_cast<char*>(id);
}
return QString(start);
}
int ProtocolDock::get_output_protocol_by_id(QString id)
{
int dex = 0;
for (auto info : _decoderInfoList)
{
srd_decoder *dec = (srd_decoder *)(info->_data_handle);
if (dec->outputs)
{
QString output_id = parse_protocol_id((char*)dec->outputs->data);
if (output_id == id)
{
QString proid(dec->id);
if (!proid.startsWith("0:") || output_id == proid){
return dex;
}
}
}
++dex;
}
return -1;
}
void ProtocolDock::BeginEditKeyword()
{
show_protocol_select();
}
void ProtocolDock::show_protocol_select()
{
SearchComboBox *panel = new SearchComboBox(this);
for (auto info : _decoderInfoList)
{
srd_decoder *dec = (srd_decoder *)(info->_data_handle);
panel->AddDataItem(QString(dec->id), QString(dec->name), info);
}
QFont font = this->font();
font.setPointSizeF(AppConfig::Instance().appOptions.fontSize);
ui::set_form_font(panel, font);
panel->SetItemClickHandle(this);
panel->ShowDlg(_pro_keyword_edit);
}
void ProtocolDock::OnItemClick(void *sender, void *data_handle)
{
(void)sender;
if (data_handle != NULL){
DecoderInfoItem *info = (DecoderInfoItem*)data_handle;
srd_decoder *dec = (srd_decoder *)(info->_data_handle);
this->_pro_keyword_edit->SetInputText(QString(dec->name));
_selected_protocol_id = QString(dec->id);
this->on_add_protocol();
}
}
void ProtocolDock::reset_view()
{
decoded_progress(0);
update();
}
void ProtocolDock::update_view_status()
{
bool bEnable = _session->is_working() == false;
_pro_keyword_edit->setEnabled(bEnable);
_pro_add_button->setEnabled(bEnable);
_pro_search_button->setEnabled(bEnable);
}
void ProtocolDock::update_deocder_item_name(void *trace_handel, const char *name)
{
for(auto p : _protocol_lay_items){
if (p->_trace == trace_handel){
p->set_label_name(QString(name));
break;
}
}
}
void ProtocolDock::UpdateLanguage()
{
retranslateUi();
}
void ProtocolDock::UpdateTheme()
{
reStyle();
}
void ProtocolDock::UpdateFont()
{
QFont font = this->font();
font.setPointSizeF(AppConfig::Instance().appOptions.fontSize);
ui::set_form_font(this, font);
_table_view->setFont(font);
for(auto lay : _protocol_lay_items){
lay->update_font();
}
font.setPointSizeF(font.pointSizeF() + 1);
this->parentWidget()->setFont(font);
_table_view->horizontalHeader()->setFont(font);
_table_view->verticalHeader()->setFont(font);
_table_view->setObjectName("DecodedDataView");
QString style = "#DecodedDataView QHeaderView{font-size: %1pt}";
style = style.arg(AppConfig::Instance().appOptions.fontSize);
_table_view->setStyleSheet(style);
adjustPannelSize();
}
void ProtocolDock::adjustPannelSize()
{
QString str = "DECODER";
QFont font = this->font();
font.setPointSizeF(AppConfig::Instance().appOptions.fontSize);
QFontMetrics fm(font);
QRect rc = fm.boundingRect(str);
int lineHeight = rc.height() + 15;
_pro_keyword_edit->setFixedHeight(rc.height() + 5);
int pannelHeight = lineHeight * _protocol_lay_items.size() + _pro_keyword_edit->height();
if (pannelHeight < 100){
pannelHeight = 100;
}
_top_panel->setMinimumHeight(pannelHeight);
}
} // namespace dock
} // namespace pv