X-Git-Url: https://sigrok.org/gitweb/?p=pulseview.git;a=blobdiff_plain;f=pv%2Fsubwindows%2Fdecoder_selector%2Fsubwindow.cpp;h=0b49c34aa190af74235473839dec121ce2392651;hp=e6245ab4bf67f2ed06ae8b02c55b30bd24a3ce93;hb=1fd847fedce2d8b93080ee7cd4d8c86aa916f6d2;hpb=486bcf0119d06242f624d47aef74d6d29c828f94 diff --git a/pv/subwindows/decoder_selector/subwindow.cpp b/pv/subwindows/decoder_selector/subwindow.cpp index e6245ab4..0b49c34a 100644 --- a/pv/subwindows/decoder_selector/subwindow.cpp +++ b/pv/subwindows/decoder_selector/subwindow.cpp @@ -19,23 +19,31 @@ #include +#include #include +#include #include #include #include #include +#include #include #include "pv/session.hpp" #include "pv/subwindows/decoder_selector/subwindow.hpp" using std::reverse; -using std::shared_ptr; namespace pv { namespace subwindows { namespace decoder_selector { +const char *initial_notice = + QT_TRANSLATE_NOOP("pv::subwindows::decoder_selector::SubWindow", + "Select a decoder to see its description here."); // clazy:exclude=non-pod-global-static + +const int min_width_margin = 75; + bool QCustomSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const @@ -96,6 +104,7 @@ SubWindow::SubWindow(Session& session, QWidget* parent) : sort_filter_model_->setSourceModel(model_); sort_filter_model_->setFilterCaseSensitivity(Qt::CaseInsensitive); + sort_filter_model_->setFilterKeyColumn(-1); tree_view_->setModel(sort_filter_model_); tree_view_->setRootIsDecorated(true); @@ -105,16 +114,35 @@ SubWindow::SubWindow(Session& session, QWidget* parent) : // Hide the columns that hold the detailed item information tree_view_->hideColumn(2); // ID + // Ensure that all decoder tag names are fully visible by default + tree_view_->resizeColumnToContents(0); + + tree_view_->setIndentation(10); + + QScrollArea* info_label_body_container = new QScrollArea(); + info_label_body_container->setWidget(info_label_body_); + info_label_body_container->setWidgetResizable(true); + info_box_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); QVBoxLayout* info_box_layout = new QVBoxLayout(info_box_); info_box_layout->addWidget(info_label_header_); - info_box_layout->addWidget(info_label_body_); + info_box_layout->addWidget(info_label_body_container); info_box_layout->addWidget(info_label_footer_); + info_box_layout->setAlignment(Qt::AlignTop); + Qt::TextInteractionFlags flags = Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard; + info_label_header_->setWordWrap(true); + info_label_header_->setTextInteractionFlags(flags); info_label_body_->setWordWrap(true); - info_label_body_->setText(tr("Select a decoder to see its description here.")); + info_label_body_->setTextInteractionFlags(flags); + info_label_body_->setText(QString(tr(initial_notice))); + info_label_body_->setAlignment(Qt::AlignTop); + info_label_footer_->setWordWrap(true); + info_label_footer_->setTextInteractionFlags(flags); connect(filter, SIGNAL(textChanged(const QString&)), this, SLOT(on_filter_changed(const QString&))); + connect(filter, SIGNAL(returnPressed()), + this, SLOT(on_filter_return_pressed())); connect(tree_view_, SIGNAL(currentChanged(const QModelIndex&)), this, SLOT(on_item_changed(const QModelIndex&))); @@ -123,6 +151,9 @@ SubWindow::SubWindow(Session& session, QWidget* parent) : connect(this, SIGNAL(new_decoders_selected(vector)), &session, SLOT(on_new_decoders_selected(vector))); + + // Place the keyboard cursor in the filter QLineEdit initially + filter->setFocus(); } bool SubWindow::has_toolbar() const @@ -137,22 +168,15 @@ QToolBar* SubWindow::create_toolbar(QWidget *parent) const return toolbar; } -const srd_decoder* SubWindow::get_srd_decoder_from_id(QString id) const +int SubWindow::minimum_width() const { - const srd_decoder* ret_val = nullptr; - - for (GSList* li = (GSList*)srd_decoder_list(); li; li = li->next) { - const srd_decoder* d = (srd_decoder*)li->data; - assert(d); - - if (QString::fromUtf8(d->id) == id) - ret_val = d; - } + QFontMetrics m(info_label_body_->font()); + const int label_width = m.width(QString(tr(initial_notice))); - return ret_val; + return label_width + min_width_margin; } -vector SubWindow::decoder_inputs(const srd_decoder* d) const +vector SubWindow::get_decoder_inputs(const srd_decoder* d) const { vector ret_val; @@ -162,7 +186,7 @@ vector SubWindow::decoder_inputs(const srd_decoder* d) const return ret_val; } -vector SubWindow::decoders_providing(const char* output) const +vector SubWindow::get_decoders_providing(const char* output) const { vector ret_val; @@ -173,8 +197,10 @@ vector SubWindow::decoders_providing(const char* output) con if (!d->outputs) continue; + const int maxlen = 1024; + // TODO For now we ignore that d->outputs is actually a list - if (strncmp((char*)(d->outputs->data), output, strlen(output)) == 0) + if (strncmp((char*)(d->outputs->data), output, maxlen) == 0) ret_val.push_back(d); } @@ -192,12 +218,12 @@ void SubWindow::on_item_changed(const QModelIndex& index) if (decoder_name.isEmpty()) return; - const srd_decoder* d = get_srd_decoder_from_id(decoder_name); + const srd_decoder* d = srd_decoder_get_by_id(decoder_name.toUtf8()); const QString id = QString::fromUtf8(d->id); const QString longname = QString::fromUtf8(d->longname); const QString desc = QString::fromUtf8(d->desc); - const QString doc = QString::fromUtf8(srd_decoder_doc_get(d)); + const QString doc = QString::fromUtf8(srd_decoder_doc_get(d)).trimmed(); QString tags; for (GSList* li = (GSList*)d->tags; li; li = li->next) { @@ -207,7 +233,7 @@ void SubWindow::on_item_changed(const QModelIndex& index) tags.append(s); } - info_label_header_->setText(QString("%1 (%2)
%3") + info_label_header_->setText(QString("%1 (%2)
%3") .arg(longname, id, desc)); info_label_body_->setText(doc); info_label_footer_->setText(tr("

Tags: %1

").arg(tags)); @@ -221,7 +247,7 @@ void SubWindow::on_item_activated(const QModelIndex& index) QModelIndex id_index = index.model()->index(index.row(), 2, index.parent()); QString decoder_name = index.model()->data(id_index, Qt::DisplayRole).toString(); - const srd_decoder* chosen_decoder = get_srd_decoder_from_id(decoder_name); + const srd_decoder* chosen_decoder = srd_decoder_get_by_id(decoder_name.toUtf8()); if (chosen_decoder == nullptr) return; @@ -229,20 +255,20 @@ void SubWindow::on_item_activated(const QModelIndex& index) decoders.push_back(chosen_decoder); // If the decoder only depends on logic inputs, we add it and are done - vector inputs = decoder_inputs(decoders.front()); + vector inputs = get_decoder_inputs(decoders.front()); if (inputs.size() == 0) { qWarning() << "Protocol decoder" << decoder_name << "cannot have 0 inputs!"; return; } - if (strncmp(inputs.at(0), "logic", 5) == 0) { + if (strcmp(inputs.at(0), "logic") == 0) { new_decoders_selected(decoders); return; } // Check if we can automatically fulfill the stacking requirements - while (strncmp(inputs.at(0), "logic", 5) != 0) { - vector prov_decoders = decoders_providing(inputs.at(0)); + while (strcmp(inputs.at(0), "logic") != 0) { + vector prov_decoders = get_decoders_providing(inputs.at(0)); if (prov_decoders.size() == 0) { // Emit warning and add the stack that we could gather so far @@ -270,10 +296,10 @@ void SubWindow::on_item_activated(const QModelIndex& index) return; QString d = item.section(' ', 0, 0); - decoders.push_back(get_srd_decoder_from_id(d)); + decoders.push_back(srd_decoder_get_by_id(d.toUtf8())); } - inputs = decoder_inputs(decoders.back()); + inputs = get_decoder_inputs(decoders.back()); } // Reverse decoder list and add the stack @@ -284,6 +310,31 @@ void SubWindow::on_item_activated(const QModelIndex& index) void SubWindow::on_filter_changed(const QString& text) { sort_filter_model_->setFilterFixedString(text); + + // Expand the "All Decoders" category/tag if the user filtered + tree_view_->setExpanded(tree_view_->model()->index(0, 0), !text.isEmpty()); +} + +void SubWindow::on_filter_return_pressed() +{ + int num_visible_decoders = 0; + QModelIndex last_valid_index; + + QModelIndex index = tree_view_->model()->index(0, 0); + + while (index.isValid()) { + QModelIndex id_index = index.model()->index(index.row(), 2, index.parent()); + QString decoder_name = index.model()->data(id_index, Qt::DisplayRole).toString(); + if (!decoder_name.isEmpty()) { + last_valid_index = index; + num_visible_decoders++; + } + index = tree_view_->indexBelow(index); + } + + // If only one decoder matches the filter, apply it when the user presses enter + if (num_visible_decoders == 1) + tree_view_->activated(last_valid_index); } } // namespace decoder_selector