/* * This file is part of the DSView project. * DSView is based on PulseView. * * Copyright (C) 2013 DreamSourceLab * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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(srd_decoder_list()); std::map 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 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 &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 rows = decoder_stack->get_rows_lshow(); int column = _model_proxy.filterKeyColumn(); for (std::map::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 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 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(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