TabularDecView: Make the model/view work
authorSoeren Apel <soeren@apelpie.net>
Fri, 10 Apr 2020 11:49:52 +0000 (13:49 +0200)
committerUwe Hermann <uwe@hermann-uwe.de>
Sun, 3 May 2020 15:20:55 +0000 (17:20 +0200)
14 files changed:
CMakeLists.txt
pv/data/decode/annotation.cpp
pv/data/decode/annotation.hpp
pv/data/decode/decoder.cpp
pv/data/decode/decoder.hpp
pv/data/decode/rowdata.cpp
pv/data/decode/rowdata.hpp
pv/data/decodesignal.cpp
pv/data/decodesignal.hpp
pv/views/tabular_decoder/item.cpp [deleted file]
pv/views/tabular_decoder/model.cpp
pv/views/tabular_decoder/view.cpp
pv/views/tabular_decoder/view.hpp
test/CMakeLists.txt

index f429553ebba2c26edec055f013e50daa1eba3962..c77435d462c37ba352e9482aa3e799d4668b4b34 100644 (file)
@@ -399,7 +399,6 @@ if(ENABLE_DECODE)
                pv/subwindows/decoder_selector/subwindow.cpp
                pv/views/decoder_binary/view.cpp
                pv/views/decoder_binary/QHexView.cpp
-               pv/views/tabular_decoder/item.cpp
                pv/views/tabular_decoder/model.cpp
                pv/views/tabular_decoder/view.cpp
                pv/views/trace/decodetrace.cpp
index 8ac8d5f9e4970e193771cffe107c414da73f077a..689c08dec6eaf16a1ba9a52acc259fd38c30f36e 100644 (file)
@@ -86,8 +86,7 @@ Annotation& Annotation::operator=(Annotation&& a)
 
 Annotation::~Annotation()
 {
-       if (annotations_)
-               delete annotations_;
+       delete annotations_;
 }
 
 uint64_t Annotation::start_sample() const
@@ -118,6 +117,11 @@ const vector<QString>* Annotation::annotations() const
        return annotations_;
 }
 
+const QString Annotation::longest_annotation() const
+{
+       return annotations_->front();
+}
+
 const Row* Annotation::row() const
 {
        return row_;
index cfa5e5e982e54746f79cac80c15062af7cd3f66b..e599bdd447343e75254fe00aa879109a6feb52da 100644 (file)
@@ -53,6 +53,7 @@ public:
        const QString ann_class_name() const;
 
        const vector<QString>* annotations() const;
+       const QString longest_annotation() const;
        const Row* row() const;
 
        bool operator<(const Annotation &other) const;
index e6fe82d22a092d7e663a06e813ab52a4aac908da..600382feddb576346f9c835b44934a1cd049670b 100644 (file)
@@ -36,8 +36,9 @@ namespace pv {
 namespace data {
 namespace decode {
 
-Decoder::Decoder(const srd_decoder *const dec) :
+Decoder::Decoder(const srd_decoder *const dec, uint8_t stack_level) :
        srd_decoder_(dec),
+       stack_level_(stack_level),
        visible_(true),
        decoder_inst_(nullptr)
 {
@@ -96,6 +97,11 @@ const srd_decoder* Decoder::get_srd_decoder() const
        return srd_decoder_;
 }
 
+uint8_t Decoder::get_stack_level() const
+{
+       return stack_level_;
+}
+
 const char* Decoder::name() const
 {
        return srd_decoder_->name;
index eb9a44bf6c1a8841cba632bc1bf3b5aa8d517c91..7b1a20134acaccd7ce4adec6462d11a02c11ffcb 100644 (file)
@@ -82,12 +82,14 @@ struct DecodeBinaryClassInfo
 class Decoder
 {
 public:
-       Decoder(const srd_decoder *const dec);
+       Decoder(const srd_decoder *const dec, uint8_t stack_level);
 
        virtual ~Decoder();
 
        const srd_decoder* get_srd_decoder() const;
 
+       uint8_t get_stack_level() const;
+
        const char* name() const;
 
        bool visible() const;
@@ -97,7 +99,6 @@ public:
        void set_channels(vector<DecodeChannel*> channels);
 
        const map<string, GVariant*>& options() const;
-
        void set_option(const char *id, GVariant *value);
 
        void apply_all_options();
@@ -120,6 +121,7 @@ public:
 
 private:
        const srd_decoder* const srd_decoder_;
+       uint8_t stack_level_;
 
        bool visible_;
 
index 7b6ec2d3f8b71bb0728cd1381a2867bb072f55c5..fc1480a117c590278b57fd57846d55f38f668fec 100644 (file)
@@ -90,8 +90,10 @@ void RowData::get_annotation_subset(
        }
 }
 
-void RowData::emplace_annotation(srd_proto_data *pdata)
+const Annotation* RowData::emplace_annotation(srd_proto_data *pdata)
 {
+       const Annotation* result = nullptr;
+
        // We insert the annotation in a way so that the annotation list
        // is sorted by start sample. Otherwise, we'd have to sort when
        // painting, which is expensive
@@ -108,11 +110,15 @@ void RowData::emplace_annotation(srd_proto_data *pdata)
                if (it != annotations_.begin())
                        it++;
 
-               annotations_.emplace(it, pdata, row_);
+               it = annotations_.emplace(it, pdata, row_);
+               result = &(*it);
        } else {
                annotations_.emplace_back(pdata, row_);
+               result = &(annotations_.back());
                prev_ann_start_sample_ = pdata->start_sample;
        }
+
+       return result;
 }
 
 }  // namespace decode
index 01ea94f4586c7390601c28ea61e68c76a5ca960d..48b6a41a68a260783dd0740b8ac57f63448eb4e9 100644 (file)
@@ -52,7 +52,7 @@ public:
        void get_annotation_subset(deque<const pv::data::decode::Annotation*> &dest,
                uint64_t start_sample, uint64_t end_sample) const;
 
-       void emplace_annotation(srd_proto_data *pdata);
+       const Annotation* emplace_annotation(srd_proto_data *pdata);
 
 private:
        deque<Annotation> annotations_;
index f8e719992d59b2df7a1c22664e4772ad55088567..a488817525ec9f64a6e08400e3812a7e07ef28e5 100644 (file)
@@ -83,7 +83,7 @@ void DecodeSignal::stack_decoder(const srd_decoder *decoder, bool restart_decode
        if ((stack_.empty()) || ((stack_.size() > 0) && (name() == prev_dec_name)))
                set_name(QString::fromUtf8(decoder->name));
 
-       const shared_ptr<Decoder> dec = make_shared<Decoder>(decoder);
+       const shared_ptr<Decoder> dec = make_shared<Decoder>(decoder, stack_.size());
        stack_.push_back(dec);
 
        // Include the newly created decode channels in the channel lists
@@ -642,6 +642,19 @@ const DecodeBinaryClass* DecodeSignal::get_binary_data_class(uint32_t segment_id
        return nullptr;
 }
 
+const deque<const Annotation*>* DecodeSignal::get_all_annotations_by_segment(
+       uint32_t segment_id) const
+{
+       try {
+               const DecodeSegment *segment = &(segments_.at(segment_id));
+               return &(segment->all_annotations);
+       } catch (out_of_range&) {
+               // Do nothing
+       }
+
+       return nullptr;
+}
+
 void DecodeSignal::save_settings(QSettings &settings) const
 {
        SignalBase::save_settings(settings);
@@ -737,7 +750,7 @@ void DecodeSignal::restore_settings(QSettings &settings)
                                continue;
 
                        if (QString::fromUtf8(dec->id) == id) {
-                               shared_ptr<Decoder> decoder = make_shared<Decoder>(dec);
+                               shared_ptr<Decoder> decoder = make_shared<Decoder>(dec, stack_.size());
 
                                stack_.push_back(decoder);
                                decoder->set_visible(settings.value("visible", true).toBool());
@@ -1379,7 +1392,7 @@ void DecodeSignal::connect_input_notifiers()
 void DecodeSignal::create_decode_segment()
 {
        // Create annotation segment
-       segments_.emplace_back(DecodeSegment());
+       segments_.emplace_back();
 
        // Add annotation classes
        for (const shared_ptr<Decoder>& dec : stack_)
@@ -1435,8 +1448,15 @@ void DecodeSignal::annotation_callback(srd_proto_data *pdata, void *decode_signa
        if (!row)
                row = dec->get_row_by_id(0);
 
-       // Add the annotation
-       ds->segments_[ds->current_segment_id_].annotation_rows.at(row).emplace_annotation(pdata);
+       RowData& row_data = ds->segments_[ds->current_segment_id_].annotation_rows.at(row);
+
+       // Add the annotation to the row
+       const Annotation* ann = row_data.emplace_annotation(pdata);
+
+       // Add the annotation to the global annotation list
+       deque<const Annotation*>& all_annotations =
+               ds->segments_[ds->current_segment_id_].all_annotations;
+       all_annotations.emplace_back(ann);
 }
 
 void DecodeSignal::binary_callback(srd_proto_data *pdata, void *decode_signal)
index cee4ccf0eadcf6db1a214483057231e4274c7dbf..51745b7baab8a8d3bf1237e80d9fa96bb10a458e 100644 (file)
@@ -77,11 +77,17 @@ struct DecodeBinaryClass
 
 struct DecodeSegment
 {
+       // Constructor is a no-op
+       DecodeSegment() { };
+       // Copy constructor is a no-op
+       DecodeSegment(DecodeSegment&& ds) { (void)ds; };
+
        map<const Row*, RowData> annotation_rows;
        pv::util::Timestamp start_time;
        double samplerate;
        int64_t samples_decoded_incl, samples_decoded_excl;
        vector<DecodeBinaryClass> binary_classes;
+       deque<const Annotation*> all_annotations;
 };
 
 class DecodeSignal : public SignalBase
@@ -176,6 +182,8 @@ public:
        const DecodeBinaryClass* get_binary_data_class(uint32_t segment_id,
                const Decoder* dec, uint32_t bin_class_id) const;
 
+       const deque<const Annotation*>* get_all_annotations_by_segment(uint32_t segment_id) const;
+
        virtual void save_settings(QSettings &settings) const;
 
        virtual void restore_settings(QSettings &settings);
diff --git a/pv/views/tabular_decoder/item.cpp b/pv/views/tabular_decoder/item.cpp
deleted file mode 100644 (file)
index a4b79f3..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * This file is part of the PulseView project.
- *
- * Copyright (C) 2020 Soeren Apel <soeren@apelpie.net>
- *
- * 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 <http://www.gnu.org/licenses/>.
- */
-
-#include "pv/views/tabular_decoder/view.hpp"
-
-using std::out_of_range;
-
-namespace pv {
-namespace views {
-namespace tabular_decoder {
-
-AnnotationCollectionItem::AnnotationCollectionItem(const vector<QVariant>& data,
-       shared_ptr<AnnotationCollectionItem> parent) :
-       data_(data),
-       parent_(parent)
-{
-}
-
-void AnnotationCollectionItem::appendSubItem(shared_ptr<AnnotationCollectionItem> item)
-{
-       subItems_.push_back(item);
-}
-
-shared_ptr<AnnotationCollectionItem> AnnotationCollectionItem::subItem(int row) const
-{
-       try {
-               return subItems_.at(row);
-       } catch (out_of_range&) {
-               return nullptr;
-       }
-}
-
-shared_ptr<AnnotationCollectionItem> AnnotationCollectionItem::parent() const
-{
-       return parent_;
-}
-
-shared_ptr<AnnotationCollectionItem> AnnotationCollectionItem::findSubItem(
-       const QVariant& value, int column)
-{
-       for (shared_ptr<AnnotationCollectionItem> item : subItems_)
-               if (item->data(column) == value)
-                       return item;
-
-       return nullptr;
-}
-
-int AnnotationCollectionItem::subItemCount() const
-{
-       return subItems_.size();
-}
-
-int AnnotationCollectionItem::columnCount() const
-{
-       return data_.size();
-}
-
-int AnnotationCollectionItem::row() const
-{
-       if (parent_)
-               for (size_t i = 0; i < parent_->subItems_.size(); i++)
-                       if (parent_->subItems_.at(i).get() == const_cast<AnnotationCollectionItem*>(this))
-                               return i;
-
-       return 0;
-}
-
-QVariant AnnotationCollectionItem::data(int column) const
-{
-       try {
-               return data_.at(column);
-       } catch (out_of_range&) {
-               return QVariant();
-       }
-}
-
-} // namespace tabular_decoder
-} // namespace views
-} // namespace pv
index 35cdc9583b8c92c86b283c990107f9eda18be87f..e54fda8c82f096617e681ab4ecddea904fa34ae1 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <QDebug>
 #include <QString>
 
 #include "pv/views/tabular_decoder/view.hpp"
@@ -28,16 +29,17 @@ namespace views {
 namespace tabular_decoder {
 
 AnnotationCollectionModel::AnnotationCollectionModel(QObject* parent) :
-       QAbstractItemModel(parent)
+       QAbstractTableModel(parent),
+       all_annotations_(nullptr),
+       prev_segment_(0),
+       prev_last_row_(0)
 {
-       vector<QVariant> header_data;
-       header_data.emplace_back(tr("ID"));                // Column #0
-       header_data.emplace_back(tr("Start Time"));        // Column #1
-       header_data.emplace_back(tr("End Time"));          // Column #2
-       header_data.emplace_back(tr("Ann Row Name"));      // Column #3
-       header_data.emplace_back(tr("Class Row Name"));    // Column #4
-       header_data.emplace_back(tr("Value"));             // Column #5
-       root_ = make_shared<AnnotationCollectionItem>(header_data);
+       // TBD Maybe use empty columns as indentation levels to indicate stacked decoders
+       header_data_.emplace_back(tr("Start Sample"));      // Column #0
+       header_data_.emplace_back(tr("Start Time"));        // Column #1
+       header_data_.emplace_back(tr("Ann Row Name"));      // Column #2
+       header_data_.emplace_back(tr("Ann Class Name"));    // Column #3
+       header_data_.emplace_back(tr("Value"));             // Column #4
 }
 
 QVariant AnnotationCollectionModel::data(const QModelIndex& index, int role) const
@@ -45,19 +47,18 @@ QVariant AnnotationCollectionModel::data(const QModelIndex& index, int role) con
        if (!index.isValid())
                return QVariant();
 
-       if (role == Qt::DisplayRole)
-       {
-               AnnotationCollectionItem* item =
-                       static_cast<AnnotationCollectionItem*>(index.internalPointer());
-
-               return item->data(index.column());
-       }
-
-       if ((role == Qt::FontRole) && (index.parent().isValid()) && (index.column() == 0))
-       {
-               QFont font;
-               font.setItalic(true);
-               return QVariant(font);
+       if (role == Qt::DisplayRole) {
+               const Annotation* ann =
+                       static_cast<const Annotation*>(index.internalPointer());
+
+               switch (index.column()) {
+               case 0: return QVariant((qulonglong)ann->start_sample());  // Column #0, Start Sample
+               case 1: return QVariant(0/*(qulonglong)ann->start_sample()*/);  // Column #1, Start Time
+               case 2: return QVariant(ann->row()->title());              // Column #2, Ann Row Name
+               case 3: return QVariant(ann->ann_class_name());            // Column #3, Ann Class Name
+               case 4: return QVariant(ann->longest_annotation());        // Column #4, Value
+               default: return QVariant();
+               }
        }
 
        return QVariant();
@@ -66,7 +67,7 @@ QVariant AnnotationCollectionModel::data(const QModelIndex& index, int role) con
 Qt::ItemFlags AnnotationCollectionModel::flags(const QModelIndex& index) const
 {
        if (!index.isValid())
-               return nullptr;
+               return 0;
 
        return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
 }
@@ -75,7 +76,7 @@ QVariant AnnotationCollectionModel::headerData(int section, Qt::Orientation orie
        int role) const
 {
        if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
-               return root_->data(section);
+               return header_data_.at(section);
 
        return QVariant();
 }
@@ -83,55 +84,68 @@ QVariant AnnotationCollectionModel::headerData(int section, Qt::Orientation orie
 QModelIndex AnnotationCollectionModel::index(int row, int column,
        const QModelIndex& parent_idx) const
 {
-       if (!hasIndex(row, column, parent_idx))
-               return QModelIndex();
-
-       AnnotationCollectionItem* parent = root_.get();
+       (void)parent_idx;
 
-       if (parent_idx.isValid())
-               parent = static_cast<AnnotationCollectionItem*>(parent_idx.internalPointer());
+       if (!all_annotations_)
+               return QModelIndex();
 
-       AnnotationCollectionItem* subItem = parent->subItem(row).get();
+       if ((size_t)row > all_annotations_->size())
+               return QModelIndex();
 
-       return subItem ? createIndex(row, column, subItem) : QModelIndex();
+       return createIndex(row, column, (void*)(all_annotations_->at(row)));
 }
 
 QModelIndex AnnotationCollectionModel::parent(const QModelIndex& index) const
 {
-       if (!index.isValid())
-               return QModelIndex();
-
-       AnnotationCollectionItem* subItem =
-               static_cast<AnnotationCollectionItem*>(index.internalPointer());
+       (void)index;
 
-       shared_ptr<AnnotationCollectionItem> parent = subItem->parent();
-
-       return (parent == root_) ? QModelIndex() :
-               createIndex(parent->row(), 0, parent.get());
+       return QModelIndex();
 }
 
 int AnnotationCollectionModel::rowCount(const QModelIndex& parent_idx) const
 {
-       AnnotationCollectionItem* parent = root_.get();
+       (void)parent_idx;
 
-       if (parent_idx.column() > 0)
+       if (!all_annotations_)
                return 0;
 
-       if (parent_idx.isValid())
-               parent = static_cast<AnnotationCollectionItem*>(parent_idx.internalPointer());
-
-       return parent->subItemCount();
+       return all_annotations_->size();
 }
 
 int AnnotationCollectionModel::columnCount(const QModelIndex& parent_idx) const
 {
-       if (parent_idx.isValid())
-               return static_cast<AnnotationCollectionItem*>(
-                       parent_idx.internalPointer())->columnCount();
-       else
-               return root_->columnCount();
+       (void)parent_idx;
+
+       return header_data_.size();
 }
 
+void AnnotationCollectionModel::set_signal_and_segment(data::DecodeSignal* signal, uint32_t current_segment)
+{
+       all_annotations_ = signal->get_all_annotations_by_segment(current_segment);
+
+       if (!all_annotations_ || all_annotations_->empty()) {
+               prev_segment_ = current_segment;
+               return;
+       }
+
+       const size_t new_row_count = all_annotations_->size() - 1;
+
+       // Force the view associated with this model to update when the segment changes
+       if (prev_segment_ != current_segment) {
+               dataChanged(QModelIndex(), QModelIndex());
+               layoutChanged();
+       } else {
+               // Force the view associated with this model to update when we have more annotations
+               if (prev_last_row_ < new_row_count) {
+                       dataChanged(index(prev_last_row_, 0, QModelIndex()),
+                               index(new_row_count, 0, QModelIndex()));
+                       layoutChanged();
+               }
+       }
+
+       prev_segment_ = current_segment;
+       prev_last_row_ = new_row_count;
+}
 
 } // namespace tabular_decoder
 } // namespace views
index 8c5859e3bcb17f7f425a0b7ec66787722fd93c1b..069e55a02e8189a945d49ccc96a91e278b2c0ca9 100644 (file)
 
 #include <climits>
 
+#include <QApplication>
 #include <QDebug>
 #include <QFileDialog>
+#include <QFontMetrics>
+#include <QHeaderView>
 #include <QLabel>
 #include <QMenu>
 #include <QMessageBox>
@@ -40,12 +43,32 @@ using pv::data::SignalBase;
 using pv::data::decode::Decoder;
 using pv::util::Timestamp;
 
+using std::make_shared;
 using std::shared_ptr;
 
 namespace pv {
 namespace views {
 namespace tabular_decoder {
 
+QSize QCustomTableView::minimumSizeHint() const
+{
+       QSize size(QTableView::sizeHint());
+
+       int width = 0;
+       for (int i = 0; i < horizontalHeader()->count(); i++)
+               if (!horizontalHeader()->isSectionHidden(i))
+                       width += horizontalHeader()->sectionSizeHint(i);
+
+       size.setWidth(width + (horizontalHeader()->count() * 1));
+
+       return size;
+}
+
+QSize QCustomTableView::sizeHint() const
+{
+       return minimumSizeHint();
+}
+
 
 View::View(Session &session, bool is_main_view, QMainWindow *parent) :
        ViewBase(session, is_main_view, parent),
@@ -55,9 +78,10 @@ View::View(Session &session, bool is_main_view, QMainWindow *parent) :
        decoder_selector_(new QComboBox()),
        save_button_(new QToolButton()),
        save_action_(new QAction(this)),
-       table_view_(new QTableView()),
+       table_view_(new QCustomTableView()),
        model_(new AnnotationCollectionModel()),
-       signal_(nullptr)
+       signal_(nullptr),
+       updating_data_(false)
 {
        QVBoxLayout *root_layout = new QVBoxLayout(this);
        root_layout->setContentsMargins(0, 0, 0, 0);
@@ -101,6 +125,14 @@ View::View(Session &session, bool is_main_view, QMainWindow *parent) :
        table_view_->setSortingEnabled(true);
        table_view_->sortByColumn(0, Qt::AscendingOrder);
 
+       const int font_height = QFontMetrics(QApplication::font()).height();
+       table_view_->verticalHeader()->setDefaultSectionSize((font_height * 5) / 4);
+
+       table_view_->horizontalHeader()->setSectionResizeMode(model_->columnCount() - 1, QHeaderView::Stretch);
+
+       table_view_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+       parent->setSizePolicy(table_view_->sizePolicy());
+
        reset_view_state();
 }
 
@@ -135,18 +167,12 @@ void View::add_decode_signal(shared_ptr<data::DecodeSignal> signal)
        connect(signal.get(), SIGNAL(decoder_removed(void*)),
                this, SLOT(on_decoder_removed(void*)));
 
-       // Add all decoders provided by this signal
+       // Add the top-level decoder provided by this signal
        auto stack = signal->decoder_stack();
-       if (stack.size() > 1) {
-               for (const shared_ptr<Decoder>& dec : stack) {
-                       QString title = QString("%1 (%2)").arg(signal->name(), dec->name());
-                       decoder_selector_->addItem(title, QVariant::fromValue((void*)dec.get()));
-               }
-       } else
-               if (!stack.empty()) {
-                       shared_ptr<Decoder>& dec = stack.at(0);
-                       decoder_selector_->addItem(signal->name(), QVariant::fromValue((void*)dec.get()));
-               }
+       if (!stack.empty()) {
+               shared_ptr<Decoder>& dec = stack.at(0);
+               decoder_selector_->addItem(signal->name(), QVariant::fromValue((void*)dec.get()));
+       }
 }
 
 void View::remove_decode_signal(shared_ptr<data::DecodeSignal> signal)
@@ -191,7 +217,18 @@ void View::update_data()
        if (!signal_)
                return;
 
-       // TBD
+       if (updating_data_) {
+               if (!delayed_view_updater_.isActive())
+                       delayed_view_updater_.start();
+               return;
+       }
+
+       updating_data_ = true;
+
+       table_view_->setRootIndex(model_->index(1, 0, QModelIndex()));
+       model_->set_signal_and_segment(signal_, current_segment_);
+
+       updating_data_ = false;
 }
 
 void View::save_data() const
@@ -249,9 +286,8 @@ void View::on_selected_decoder_changed(int index)
                        if (decoder_ == dec.get())
                                signal_ = ds.get();
 
-       if (signal_) {
+       if (signal_)
                connect(signal_, SIGNAL(new_annotations()), this, SLOT(on_new_annotations()));
-       }
 
        update_data();
 }
@@ -266,24 +302,15 @@ void View::on_signal_name_changed(const QString &name)
        DecodeSignal* signal = dynamic_cast<DecodeSignal*>(sb);
        assert(signal);
 
-       // Update all decoder entries provided by this signal
+       // Update the top-level decoder provided by this signal
        auto stack = signal->decoder_stack();
-       if (stack.size() > 1) {
-               for (const shared_ptr<Decoder>& dec : stack) {
-                       QString title = QString("%1 (%2)").arg(signal->name(), dec->name());
-                       int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get()));
-
-                       if (index != -1)
-                               decoder_selector_->setItemText(index, title);
-               }
-       } else
-               if (!stack.empty()) {
-                       shared_ptr<Decoder>& dec = stack.at(0);
-                       int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get()));
+       if (!stack.empty()) {
+               shared_ptr<Decoder>& dec = stack.at(0);
+               int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get()));
 
-                       if (index != -1)
-                               decoder_selector_->setItemText(index, signal->name());
-               }
+               if (index != -1)
+                       decoder_selector_->setItemText(index, signal->name());
+       }
 }
 
 void View::on_new_annotations()
@@ -294,8 +321,6 @@ void View::on_new_annotations()
 
 void View::on_decoder_stacked(void* decoder)
 {
-       // TODO This doesn't change existing entries for the same signal - but it should as the naming scheme may change
-
        Decoder* d = static_cast<Decoder*>(decoder);
 
        // Find the signal that contains the selected decoder
@@ -308,9 +333,8 @@ void View::on_decoder_stacked(void* decoder)
 
        assert(signal);
 
-       // Add the decoder to the list
-       QString title = QString("%1 (%2)").arg(signal->name(), d->name());
-       decoder_selector_->addItem(title, QVariant::fromValue((void*)d));
+       if (signal == signal_)
+               update_data();
 }
 
 void View::on_decoder_removed(void* decoder)
index 83a4549161bed2d391312aa8db669317ef9be264..b19ba61450fbe59248f9a6950fc55794585ef324 100644 (file)
@@ -35,31 +35,7 @@ namespace views {
 
 namespace tabular_decoder {
 
-class AnnotationCollectionItem
-{
-public:
-       AnnotationCollectionItem(const vector<QVariant>& data,
-               shared_ptr<AnnotationCollectionItem> parent = nullptr);
-
-       void appendSubItem(shared_ptr<AnnotationCollectionItem> item);
-
-       shared_ptr<AnnotationCollectionItem> subItem(int row) const;
-       shared_ptr<AnnotationCollectionItem> parent() const;
-       shared_ptr<AnnotationCollectionItem> findSubItem(const QVariant& value, int column);
-
-       int subItemCount() const;
-       int columnCount() const;
-       int row() const;
-       QVariant data(int column) const;
-
-private:
-       vector< shared_ptr<AnnotationCollectionItem> > subItems_;
-       vector<QVariant> data_;
-       shared_ptr<AnnotationCollectionItem> parent_;
-};
-
-
-class AnnotationCollectionModel : public QAbstractItemModel
+class AnnotationCollectionModel : public QAbstractTableModel
 {
        Q_OBJECT
 
@@ -79,8 +55,23 @@ public:
        int rowCount(const QModelIndex& parent_idx = QModelIndex()) const override;
        int columnCount(const QModelIndex& parent_idx = QModelIndex()) const override;
 
+       void set_signal_and_segment(data::DecodeSignal* signal, uint32_t current_segment);
+
 private:
-       shared_ptr<AnnotationCollectionItem> root_;
+       vector<QVariant> header_data_;
+       const deque<const Annotation*>* all_annotations_;
+       uint32_t prev_segment_;
+       uint64_t prev_last_row_;
+};
+
+
+class QCustomTableView : public QTableView
+{
+       Q_OBJECT
+
+public:
+       QSize minimumSizeHint() const;
+       QSize sizeHint() const;
 };
 
 
@@ -127,17 +118,18 @@ private Q_SLOTS:
 private:
        QWidget* parent_;
 
-       QComboBox *decoder_selector_;
+       QComboBoxdecoder_selector_;
 
        QToolButton* save_button_;
        QAction* save_action_;
 
-       QTableView* table_view_;
+       QCustomTableView* table_view_;
 
        AnnotationCollectionModel* model_;
 
-       data::DecodeSignal *signal_;
-       const data::decode::Decoder *decoder_;
+       data::DecodeSignal* signal_;
+       const data::decode::Decoder* decoder_;
+       bool updating_data_;
 };
 
 } // namespace tabular_decoder
index d800368b7ba8daa38d6051731fa676e4cfef899a..5ab5afa4a22c1ff839796d83064036462038f763 100644 (file)
@@ -176,7 +176,6 @@ if(ENABLE_DECODE)
                ${PROJECT_SOURCE_DIR}/pv/subwindows/decoder_selector/subwindow.cpp
                ${PROJECT_SOURCE_DIR}/pv/views/decoder_binary/view.cpp
                ${PROJECT_SOURCE_DIR}/pv/views/decoder_binary/QHexView.cpp
-               ${PROJECT_SOURCE_DIR}/pv/views/tabular_decoder/item.cpp
                ${PROJECT_SOURCE_DIR}/pv/views/tabular_decoder/model.cpp
                ${PROJECT_SOURCE_DIR}/pv/views/tabular_decoder/view.cpp
                ${PROJECT_SOURCE_DIR}/pv/views/trace/decodetrace.cpp