X-Git-Url: http://git.code-monkey.de/?a=blobdiff_plain;f=pv%2Fsubwindows%2Fdecoder_selector%2Fsubwindow.cpp;fp=pv%2Fsubwindows%2Fdecoder_selector%2Fsubwindow.cpp;h=80b0f382faee4182fb860452f78421f4fa860c30;hb=97378470ded88af84edaa0f1063d10d834475665;hp=0000000000000000000000000000000000000000;hpb=58cd5b584f5bcb19d7c9bd28391c53dd2488fc59;p=pulseview.git diff --git a/pv/subwindows/decoder_selector/subwindow.cpp b/pv/subwindows/decoder_selector/subwindow.cpp new file mode 100644 index 0000000..80b0f38 --- /dev/null +++ b/pv/subwindows/decoder_selector/subwindow.cpp @@ -0,0 +1,198 @@ +/* + * This file is part of the PulseView project. + * + * Copyright (C) 2018 Soeren Apel + * + * 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, see . + */ + +#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 { + + +SubWindow::SubWindow(Session& session, QWidget* parent) : + SubWindowBase(session, parent), + splitter_(new QSplitter()), + tree_view_(new QTreeView()), + model_(new DecoderCollectionModel()) +{ + QVBoxLayout* root_layout = new QVBoxLayout(this); + root_layout->setContentsMargins(0, 0, 0, 0); + root_layout->addWidget(splitter_); + + splitter_->addWidget(tree_view_); + + tree_view_->setModel(model_); + tree_view_->setRootIsDecorated(true); + + // Hide the columns that hold the detailed item information + tree_view_->hideColumn(2); // ID + + connect(tree_view_, SIGNAL(doubleClicked(const QModelIndex&)), + this, SLOT(on_item_double_clicked(const QModelIndex&))); + + connect(this, SIGNAL(new_decoders_selected(vector)), + &session, SLOT(on_new_decoders_selected(vector))); +} + +bool SubWindow::has_toolbar() const +{ + return true; +} + +QToolBar* SubWindow::create_toolbar(QWidget *parent) const +{ + QToolBar* toolbar = new QToolBar(parent); + + return toolbar; +} + +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) { + 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 SubWindow::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); + + return ret_val; +} + +vector SubWindow::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) { + const srd_decoder* d = (srd_decoder*)li->data; + assert(d); + + if (!d->outputs) + continue; + + // TODO For now we ignore that d->outputs is actually a list + 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_double_clicked(const QModelIndex& index) +{ + if (!index.isValid()) + return; + + 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); + if (chosen_decoder == nullptr) + return; + + vector decoders; + 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()); + if (inputs.size() == 0) { + qWarning() << "Protocol decoder" << decoder_name << "cannot have 0 inputs!"; + return; + } + + if (strncmp(inputs.at(0), "logic", 5) == 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)); + + if (prov_decoders.size() == 0) { + // Emit warning and add the stack that we could gather so far + qWarning() << "Protocol decoder" << QString::fromUtf8(decoders.back()->id) \ + << "has input that no other decoder provides:" << QString::fromUtf8(inputs.at(0)); + break; + } + + if (prov_decoders.size() == 1) { + decoders.push_back(prov_decoders.front()); + } else { + // Let user decide which one to use + QString caption = QString(tr("Protocol decoder %1 requires input type %2 " \ + "which several decoders provide.
Choose which one to use:
")) + .arg(QString::fromUtf8(decoders.back()->id), QString::fromUtf8(inputs.at(0))); + + QStringList items; + for (const srd_decoder* d : prov_decoders) + items << QString::fromUtf8(d->id) + " (" + QString::fromUtf8(d->longname) + ")"; + bool ok_clicked; + QString item = QInputDialog::getItem(this, tr("Choose Decoder"), + tr(caption.toUtf8()), items, 0, false, &ok_clicked); + + if ((!ok_clicked) || (item.isEmpty())) + return; + + QString d = item.section(' ', 0, 0); + decoders.push_back(get_srd_decoder_from_id(d)); + } + + inputs = decoder_inputs(decoders.back()); + } + + // Reverse decoder list and add the stack + reverse(decoders.begin(), decoders.end()); + new_decoders_selected(decoders); +} + +} // namespace decoder_selector +} // namespace subwindows +} // namespace pv