X-Git-Url: http://git.code-monkey.de/?p=pulseview.git;a=blobdiff_plain;f=pv%2Fsubwindows%2Fdecoder_selector%2Fsubwindow.cpp;h=af6de2d95f295a87827805083b0892f75e4ad533;hp=781e494fbc85d5196bcb823cd63098db6d123df9;hb=e0cfcb0e4f744a1e28f83b1babb4bc48ef680f79;hpb=c2b80ad9a17caef1089848134b2354c544ea1dc3 diff --git a/pv/subwindows/decoder_selector/subwindow.cpp b/pv/subwindows/decoder_selector/subwindow.cpp index 781e494..af6de2d 100644 --- a/pv/subwindows/decoder_selector/subwindow.cpp +++ b/pv/subwindows/decoder_selector/subwindow.cpp @@ -19,10 +19,14 @@ #include +#include #include +#include #include #include +#include #include +#include #include #include "pv/session.hpp" @@ -35,43 +39,110 @@ namespace pv { namespace subwindows { namespace decoder_selector { +const QString initial_notice = QApplication::tr("Select a decoder to see its description here."); +const int min_width_margin = 75; + + +bool QCustomSortFilterProxyModel::filterAcceptsRow(int source_row, + const QModelIndex& source_parent) const +{ + // Search model recursively + + if (QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent)) + return true; + + const QModelIndex index = sourceModel()->index(source_row, 0, source_parent); + + for (int i = 0; i < sourceModel()->rowCount(index); i++) + if (filterAcceptsRow(i, index)) + return true; + + return false; +} + + +void QCustomTreeView::currentChanged(const QModelIndex& current, + const QModelIndex& previous) +{ + QTreeView::currentChanged(current, previous); + currentChanged(current); +} + SubWindow::SubWindow(Session& session, QWidget* parent) : SubWindowBase(session, parent), splitter_(new QSplitter()), - tree_view_(new QTreeView()), + tree_view_(new QCustomTreeView()), info_box_(new QWidget()), info_label_header_(new QLabel()), info_label_body_(new QLabel()), info_label_footer_(new QLabel()), - model_(new DecoderCollectionModel()) + model_(new DecoderCollectionModel()), + sort_filter_model_(new QCustomSortFilterProxyModel()) { QVBoxLayout* root_layout = new QVBoxLayout(this); root_layout->setContentsMargins(0, 0, 0, 0); root_layout->addWidget(splitter_); + QWidget* upper_container = new QWidget(); + QVBoxLayout* upper_layout = new QVBoxLayout(upper_container); + upper_layout->setContentsMargins(0, 5, 0, 0); + QLineEdit* filter = new QLineEdit(); + upper_layout->addWidget(filter); + upper_layout->addWidget(tree_view_); + splitter_->setOrientation(Qt::Vertical); - splitter_->addWidget(tree_view_); + splitter_->addWidget(upper_container); splitter_->addWidget(info_box_); - tree_view_->setModel(model_); + const QIcon filter_icon(QIcon::fromTheme("search", + QIcon(":/icons/search.svg"))); + filter->setClearButtonEnabled(true); + filter->addAction(filter_icon, QLineEdit::LeadingPosition); + + sort_filter_model_->setSourceModel(model_); + sort_filter_model_->setFilterCaseSensitivity(Qt::CaseInsensitive); + + tree_view_->setModel(sort_filter_model_); tree_view_->setRootIsDecorated(true); + tree_view_->setSortingEnabled(true); + tree_view_->sortByColumn(0, Qt::AscendingOrder); // 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(initial_notice); + info_label_body_->setAlignment(Qt::AlignTop); + info_label_footer_->setWordWrap(true); + info_label_footer_->setTextInteractionFlags(flags); - connect(tree_view_, SIGNAL(clicked(const QModelIndex&)), - this, SLOT(on_item_clicked(const QModelIndex&))); - connect(tree_view_, SIGNAL(doubleClicked(const QModelIndex&)), - this, SLOT(on_item_double_clicked(const QModelIndex&))); + connect(filter, SIGNAL(textChanged(const QString&)), + this, SLOT(on_filter_changed(const QString&))); + + connect(tree_view_, SIGNAL(currentChanged(const QModelIndex&)), + this, SLOT(on_item_changed(const QModelIndex&))); + connect(tree_view_, SIGNAL(activated(const QModelIndex&)), + this, SLOT(on_item_activated(const QModelIndex&))); connect(this, SIGNAL(new_decoders_selected(vector)), &session, SLOT(on_new_decoders_selected(vector))); @@ -89,43 +160,29 @@ 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; - - GSList* l = g_slist_copy((GSList*)srd_decoder_list()); - for (GSList* li = l; li; li = li->next) { - const srd_decoder* d = (srd_decoder*)li->data; - assert(d); + QFontMetrics m(info_label_body_->font()); + const int label_width = m.width(initial_notice); - if (QString::fromUtf8(d->id) == id) - ret_val = d; - } - g_slist_free(l); - - 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; - GSList* l = g_slist_copy(d->inputs); - for (GSList* li = l; li; li = li->next) { - const char* input = (const char*)li->data; - ret_val.push_back(input); - } - g_slist_free(l); + for (GSList* li = d->inputs; li; li = li->next) + ret_val.push_back((const char*)li->data); return ret_val; } -vector SubWindow::decoders_providing(const char* output) const +vector SubWindow::get_decoders_providing(const char* output) const { vector ret_val; - GSList* l = g_slist_copy((GSList*)srd_decoder_list()); - for (GSList* li = l; li; li = li->next) { + for (GSList* li = (GSList*)srd_decoder_list(); li; li = li->next) { const srd_decoder* d = (srd_decoder*)li->data; assert(d); @@ -136,12 +193,11 @@ vector SubWindow::decoders_providing(const char* output) con if (strncmp((char*)(d->outputs->data), output, strlen(output)) == 0) ret_val.push_back(d); } - g_slist_free(l); return ret_val; } -void SubWindow::on_item_clicked(const QModelIndex& index) +void SubWindow::on_item_changed(const QModelIndex& index) { if (!index.isValid()) return; @@ -152,30 +208,28 @@ void SubWindow::on_item_clicked(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; - GSList* l = g_slist_copy((GSList*)d->tags); - for (GSList* li = l; li; li = li->next) { - QString s = (li == l) ? + for (GSList* li = (GSList*)d->tags; li; li = li->next) { + QString s = (li == (GSList*)d->tags) ? tr((char*)li->data) : QString(tr(", %1")).arg(tr((char*)li->data)); tags.append(s); } - g_slist_free(l); - 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)); } -void SubWindow::on_item_double_clicked(const QModelIndex& index) +void SubWindow::on_item_activated(const QModelIndex& index) { if (!index.isValid()) return; @@ -183,7 +237,7 @@ void SubWindow::on_item_double_clicked(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; @@ -191,7 +245,7 @@ void SubWindow::on_item_double_clicked(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; @@ -204,7 +258,7 @@ void SubWindow::on_item_double_clicked(const QModelIndex& index) // 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)); + 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 @@ -232,10 +286,10 @@ void SubWindow::on_item_double_clicked(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 @@ -243,6 +297,11 @@ void SubWindow::on_item_double_clicked(const QModelIndex& index) new_decoders_selected(decoders); } +void SubWindow::on_filter_changed(const QString& text) +{ + sort_filter_model_->setFilterFixedString(text); +} + } // namespace decoder_selector } // namespace subwindows } // namespace pv