DecoderSelector: Properly name utility methods
[pulseview.git] / pv / subwindows / decoder_selector / subwindow.cpp
index 375e749e789b9860af5988f07422a42c404d5ea9..e768a5fcb28f330d3f76cb92f3b48f2846d57815 100644 (file)
@@ -22,6 +22,7 @@
 #include <QDebug>
 #include <QInputDialog>
 #include <QLabel>
+#include <QLineEdit>
 #include <QPushButton>
 #include <QVBoxLayout>
 
@@ -36,6 +37,24 @@ namespace subwindows {
 namespace decoder_selector {
 
 
+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)
 {
@@ -53,17 +72,30 @@ SubWindow::SubWindow(Session& session, QWidget* parent) :
        info_label_body_(new QLabel()),
        info_label_footer_(new QLabel()),
        model_(new DecoderCollectionModel()),
-       sort_filter_model_(new QSortFilterProxyModel())
+       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_);
 
+       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);
@@ -81,6 +113,9 @@ SubWindow::SubWindow(Session& session, QWidget* parent) :
        info_label_body_->setWordWrap(true);
        info_label_body_->setText(tr("Select a decoder to see its description here."));
 
+       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&)),
@@ -106,39 +141,32 @@ const srd_decoder* SubWindow::get_srd_decoder_from_id(QString id) const
 {
        const srd_decoder* ret_val = nullptr;
 
-       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);
 
                if (QString::fromUtf8(d->id) == id)
                        ret_val = d;
        }
-       g_slist_free(l);
 
        return ret_val;
 }
 
-vector<const char*> SubWindow::decoder_inputs(const srd_decoder* d) const
+vector<const char*> SubWindow::get_decoder_inputs(const srd_decoder* d) const
 {
        vector<const char*> 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<const srd_decoder*> SubWindow::decoders_providing(const char* output) const
+vector<const srd_decoder*> SubWindow::get_decoders_providing(const char* output) const
 {
        vector<const srd_decoder*> 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);
 
@@ -149,7 +177,6 @@ vector<const srd_decoder*> 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;
 }
@@ -173,14 +200,12 @@ void SubWindow::on_item_changed(const QModelIndex& index)
        const QString doc = QString::fromUtf8(srd_decoder_doc_get(d));
 
        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("<span style='font-size:large;font-weight:bold'>%1 (%2)</span><br>%3")
                .arg(longname, id, desc));
@@ -204,7 +229,7 @@ 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<const char*> inputs = decoder_inputs(decoders.front());
+       vector<const char*> inputs = get_decoder_inputs(decoders.front());
        if (inputs.size() == 0) {
                qWarning() << "Protocol decoder" << decoder_name << "cannot have 0 inputs!";
                return;
@@ -217,7 +242,7 @@ void SubWindow::on_item_activated(const QModelIndex& index)
 
        // Check if we can automatically fulfill the stacking requirements
        while (strncmp(inputs.at(0), "logic", 5) != 0) {
-               vector<const srd_decoder*> prov_decoders = decoders_providing(inputs.at(0));
+               vector<const srd_decoder*> 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
@@ -248,7 +273,7 @@ void SubWindow::on_item_activated(const QModelIndex& index)
                        decoders.push_back(get_srd_decoder_from_id(d));
                }
 
-               inputs = decoder_inputs(decoders.back());
+               inputs = get_decoder_inputs(decoders.back());
        }
 
        // Reverse decoder list and add the stack
@@ -256,6 +281,11 @@ void SubWindow::on_item_activated(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