]> sigrok.org Git - pulseview.git/commitdiff
Implement MainViewRange meta obj and tab_dec::ViewModeVisible
authorSoeren Apel <redacted>
Wed, 29 Apr 2020 14:44:58 +0000 (16:44 +0200)
committerUwe Hermann <redacted>
Sun, 3 May 2020 15:20:55 +0000 (17:20 +0200)
pv/metadata_obj.cpp
pv/metadata_obj.hpp
pv/views/tabular_decoder/model.cpp
pv/views/tabular_decoder/view.cpp
pv/views/tabular_decoder/view.hpp
pv/views/trace/view.cpp

index 72b4be66ca9eb597a4b5c39c87d585efc2ab3362..b6e77461c0f706d1984cbdf97aff123242dbd8ff 100644 (file)
 
 namespace pv {
 
-const char* MetadataObjectNames[MetadataObjTypeCount] = {
+const char* MetadataObjectNames[MetadataObjectTypeCount] = {
        "main_view_range",
        "selection",
        "time_marker"
 };
 
-const char* MetadataValueNames[MetadataObjValueCount] = {
+const char* MetadataValueNames[MetadataValueTypeCount] = {
        "start_sample",
        "end_sample"
        "text"
 };
 
 
+void MetadataObjObserverInterface::on_metadata_object_created(MetadataObject* obj)
+{
+       (void)obj;
+}
+
+void MetadataObjObserverInterface::on_metadata_object_deleted(MetadataObject* obj)
+{
+       (void)obj;
+}
+
+void MetadataObjObserverInterface::on_metadata_object_changed(MetadataObject* obj,
+       MetadataValueType value_type)
+{
+       (void)obj;
+       (void)value_type;
+}
+
+
 MetadataObject::MetadataObject(MetadataObjManager* obj_manager, uint32_t obj_id,
        MetadataObjectType obj_type) :
        obj_manager_(obj_manager),
@@ -42,7 +60,7 @@ MetadataObject::MetadataObject(MetadataObjManager* obj_manager, uint32_t obj_id,
        type_(obj_type)
 {
        // Make sure we accept all value type indices
-       values_.resize(MetadataObjValueCount);
+       values_.resize(MetadataValueTypeCount);
 }
 
 uint32_t MetadataObject::id() const
@@ -55,7 +73,7 @@ MetadataObjectType MetadataObject::type() const
        return type_;
 }
 
-void MetadataObject::set_value(MetadataValueType value_type, QVariant& value)
+void MetadataObject::set_value(MetadataValueType value_type, const QVariant& value)
 {
        values_.at((uint8_t)value_type) = value;
        obj_manager_->notify_observers(this, value_type);
@@ -76,21 +94,19 @@ MetadataObject* MetadataObjManager::create_object(MetadataObjectType obj_type)
        MetadataObject* obj = &(objects_.back());
 
        for (MetadataObjObserverInterface *cb : callbacks_)
-               cb->on_metadata_object_created(obj->id(), obj->type());
+               cb->on_metadata_object_created(obj);
 
        return obj;
 }
 
 void MetadataObjManager::delete_object(uint32_t obj_id)
 {
-       MetadataObjectType type = objects_.at(obj_id).type();
+       for (MetadataObjObserverInterface *cb : callbacks_)
+               cb->on_metadata_object_deleted(&(objects_.at(obj_id)));
 
        objects_.erase(std::remove_if(objects_.begin(), objects_.end(),
                [&](MetadataObject obj) { return obj.id() == obj_id; }),
                objects_.end());
-
-       for (MetadataObjObserverInterface *cb : callbacks_)
-               cb->on_metadata_object_deleted(obj_id, type);
 }
 
 MetadataObject* MetadataObjManager::find_object_by_type(MetadataObjectType obj_type)
@@ -135,8 +151,7 @@ void MetadataObjManager::notify_observers(MetadataObject* obj,
        MetadataValueType changed_value)
 {
        for (MetadataObjObserverInterface *cb : callbacks_)
-               cb->on_metadata_object_changed(obj->id(), obj->type(), changed_value,
-                       obj->value(changed_value));
+               cb->on_metadata_object_changed(obj, changed_value);
 }
 
 } // namespace pv
index 593fe968a79913e69830046d39be48d3c58243af..fef77795173d0707531ac41fade8a41582439eeb 100644 (file)
@@ -26,6 +26,7 @@
 #include <QObject>
 #include <QSettings>
 #include <QString>
+#include <QVariant>
 
 using std::deque;
 using std::vector;
@@ -38,31 +39,32 @@ enum MetadataObjectType {
        MetadataObjMainViewRange,
        MetadataObjSelection,
        MetadataObjTimeMarker,
-       MetadataObjTypeCount  // Indicates how many metadata object types there are, must always be last
+       MetadataObjectTypeCount  // Indicates how many metadata object types there are, must always be last
 };
 
 // When adding an entry here, don't forget to update MetadataValueNames as well
 enum MetadataValueType {
-       MetadataObjStartSample,
-       MetadataObjEndSample,
-       MetadataObjText,
-       MetadataObjValueCount  // Indicates how many metadata value types there are, must always be last
+       MetadataValueStartSample,  // int64_t / qlonglong
+       MetadataValueEndSample,    // int64_t / qlonglong
+       MetadataValueText,
+       MetadataValueTypeCount  // Indicates how many metadata value types there are, must always be last
 };
 
-extern const char* MetadataObjectNames[MetadataObjTypeCount];
-extern const char* MetadataValueNames[MetadataObjValueCount];
+extern const char* MetadataObjectNames[MetadataObjectTypeCount];
+extern const char* MetadataValueNames[MetadataValueTypeCount];
 
 
 class MetadataObjManager;
+class MetadataObject;
 
 
 class MetadataObjObserverInterface
 {
 public:
-       virtual void on_metadata_object_created(uint32_t obj_id, MetadataObjectType obj_type) = 0;
-       virtual void on_metadata_object_deleted(uint32_t obj_id, MetadataObjectType obj_type) = 0;
-       virtual void on_metadata_object_changed(uint32_t obj_id, MetadataObjectType obj_type,
-               MetadataValueType value_type, const QVariant& value) = 0;
+       virtual void on_metadata_object_created(MetadataObject* obj);
+       virtual void on_metadata_object_deleted(MetadataObject* obj);
+       virtual void on_metadata_object_changed(MetadataObject* obj,
+               MetadataValueType value_type);
 };
 
 
@@ -75,7 +77,7 @@ public:
        virtual uint32_t id() const;
        virtual MetadataObjectType type() const;
 
-       virtual void set_value(MetadataValueType value_type, QVariant& value);
+       virtual void set_value(MetadataValueType value_type, const QVariant& value);
        virtual QVariant value(MetadataValueType value_type) const;
 private:
        MetadataObjManager* obj_manager_;
index 28467de4a3424db932b06c5f32243e91b663cc4d..b0632f7ad35b5d3d2be9e6084cd930baa9a2a7d0 100644 (file)
@@ -44,6 +44,8 @@ AnnotationCollectionModel::AnnotationCollectionModel(QObject* parent) :
        signal_(nullptr),
        prev_segment_(0),
        prev_last_row_(0),
+       start_index_(0),
+       end_index_(0),
        hide_hidden_(false)
 {
        GlobalSettings::add_change_handler(this);
@@ -137,8 +139,13 @@ QModelIndex AnnotationCollectionModel::index(int row, int column,
 
        QModelIndex idx;
 
-       if ((size_t)row < dataset_->size())
-               idx = createIndex(row, column, (void*)dataset_->at(row));
+       if (start_index_ == end_index_) {
+               if ((size_t)row < dataset_->size())
+                       idx = createIndex(row, column, (void*)dataset_->at(row));
+       } else {
+               if ((size_t)row < (end_index_ - start_index_))
+                       idx = createIndex(row, column, (void*)dataset_->at(start_index_ + row));
+       }
 
        return idx;
 }
@@ -157,7 +164,10 @@ int AnnotationCollectionModel::rowCount(const QModelIndex& parent_idx) const
        if (!dataset_)
                return 0;
 
-       return dataset_->size();
+       if (start_index_ == end_index_)
+               return dataset_->size();
+       else
+               return (end_index_ - start_index_);
 }
 
 int AnnotationCollectionModel::columnCount(const QModelIndex& parent_idx) const
@@ -192,6 +202,9 @@ void AnnotationCollectionModel::set_signal_and_segment(data::DecodeSignal* signa
                return;
        }
 
+       // Re-apply the requested sample range
+       set_sample_range(start_sample_, end_sample_);
+
        const size_t new_row_count = dataset_->size() - 1;
 
        // Force the view associated with this model to update when the segment changes
@@ -210,6 +223,62 @@ void AnnotationCollectionModel::set_signal_and_segment(data::DecodeSignal* signa
        prev_last_row_ = new_row_count;
 }
 
+void AnnotationCollectionModel::set_sample_range(uint64_t start_sample, uint64_t end_sample)
+{
+       // Check if there's even anything to reset
+       if ((start_sample == end_sample) && (start_index_ == end_index_))
+               return;
+
+       if (!dataset_ || dataset_->empty() || (end_sample == 0)) {
+               start_index_ = 0;
+               end_index_ = 0;
+               start_sample_ = 0;
+               end_sample_ = 0;
+
+               dataChanged(QModelIndex(), QModelIndex());
+               layoutChanged();
+               return;
+       }
+
+       start_sample_ = start_sample;
+       end_sample_ = end_sample;
+
+       // Determine first and last indices into the annotation list
+       int64_t i = -1;
+       bool ann_outside_range;
+       do {
+               i++;
+
+               if (i == (int64_t)dataset_->size()) {
+                       start_index_ = 0;
+                       end_index_ = 0;
+
+                       dataChanged(QModelIndex(), QModelIndex());
+                       layoutChanged();
+                       return;
+               }
+               const Annotation* ann = (*dataset_)[i];
+               ann_outside_range =
+                       ((ann->start_sample() < start_sample) && (ann->end_sample() < start_sample));
+       } while (ann_outside_range);
+       start_index_ = i;
+
+       // Ideally, we would be able to set end_index_ to the last annotation that
+       // is within range. However, as annotations in the list are sorted by
+       // start sample and hierarchy level, we may encounter this scenario:
+       //   [long annotation that spans across view]
+       //   [short annotations that aren't seen]
+       //   [short annotations that are seen]
+       // ..in which our output would only show the first long annotations.
+       // For this reason, we simply show everything after the first visible
+       // annotation for now.
+
+       end_index_ = dataset_->size();
+
+       dataChanged(index(0, 0), index((end_index_ - start_index_), 0));
+       layoutChanged();
+}
+
 void AnnotationCollectionModel::set_hide_hidden(bool hide_hidden)
 {
        hide_hidden_ = hide_hidden;
@@ -221,6 +290,16 @@ void AnnotationCollectionModel::set_hide_hidden(bool hide_hidden)
                dataset_ = all_annotations_;
                all_annotations_without_hidden_.clear();  // To conserve memory
        }
+
+       // Re-apply the requested sample range
+       set_sample_range(start_sample_, end_sample_);
+
+       if (dataset_)
+               dataChanged(index(0, 0), index(dataset_->size(), 0));
+       else
+               dataChanged(QModelIndex(), QModelIndex());
+
+       layoutChanged();
 }
 
 void AnnotationCollectionModel::update_annotations_without_hidden()
@@ -243,9 +322,6 @@ void AnnotationCollectionModel::update_annotations_without_hidden()
        }
 
        all_annotations_without_hidden_.resize(count);
-
-       dataChanged(index(0, 0), index(count, 0));
-       layoutChanged();
 }
 
 void AnnotationCollectionModel::on_setting_changed(const QString &key, const QVariant &value)
index 6ee3e2ac13b1871b632bfa229c44ef0f4d4b4ca4..b4bb93de3086f88ce501787ea8c3996d5dfe84ed 100644 (file)
@@ -45,6 +45,7 @@ using pv::data::decode::Decoder;
 using pv::util::Timestamp;
 
 using std::make_shared;
+using std::max;
 using std::shared_ptr;
 
 namespace pv {
@@ -58,8 +59,8 @@ const char* SaveTypeNames[SaveTypeCount] = {
 
 const char* ViewModeNames[ViewModeCount] = {
        "Show all",
-       "Show all and focus on newest"
-//     "Show visible in main view"
+       "Show all and focus on newest",
+       "Show visible in main view"
 };
 
 QSize QCustomTableView::minimumSizeHint() const
@@ -178,9 +179,17 @@ View::View(Session &session, bool is_main_view, QMainWindow *parent) :
        connect(table_view_->horizontalHeader(), SIGNAL(customContextMenuRequested(const QPoint&)),
                this, SLOT(on_table_header_requested(const QPoint&)));
 
+       // Set up metadata event handler
+       session_.metadata_obj_manager()->add_observer(this);
+
        reset_view_state();
 }
 
+View::~View()
+{
+       session_.metadata_obj_manager()->remove_observer(this);
+}
+
 ViewType View::get_type() const
 {
        return ViewTypeTabularDecoder;
@@ -400,7 +409,24 @@ void View::on_hide_hidden_changed(bool checked)
 
 void View::on_view_mode_changed(int index)
 {
-       (void)index;
+       if (index == ViewModeVisible) {
+               MetadataObject *md_obj =
+                       session_.metadata_obj_manager()->find_object_by_type(MetadataObjMainViewRange);
+               assert(md_obj);
+
+               int64_t start_sample = md_obj->value(MetadataValueStartSample).toLongLong();
+               int64_t end_sample = md_obj->value(MetadataValueEndSample).toLongLong();
+
+               model_->set_sample_range(max((int64_t)0, start_sample),
+                       max((int64_t)0, end_sample));
+       } else {
+               // Reset the model's data range
+               model_->set_sample_range(0, 0);
+       }
+
+       if (index == ViewModeLatest)
+               table_view_->scrollTo(model_->index(model_->rowCount() - 1, 0),
+                       QAbstractItemView::PositionAtBottom);
 }
 
 void View::on_signal_name_changed(const QString &name)
@@ -543,6 +569,25 @@ void View::on_table_header_toggled(bool checked)
        table_view_->horizontalHeader()->setSectionHidden(column, !checked);
 }
 
+void View::on_metadata_object_changed(MetadataObject* obj,
+       MetadataValueType value_type)
+{
+       // Check if we need to update the model's data range. We only work on the
+       // end sample value because the start sample value is updated first and
+       // we don't want to update the model twice
+
+       if ((view_mode_selector_->currentIndex() == ViewModeVisible) &&
+               (obj->type() == MetadataObjMainViewRange) &&
+               (value_type == MetadataValueEndSample)) {
+
+               int64_t start_sample = obj->value(MetadataValueStartSample).toLongLong();
+               int64_t end_sample = obj->value(MetadataValueEndSample).toLongLong();
+
+               model_->set_sample_range(max((int64_t)0, start_sample),
+                       max((int64_t)0, end_sample));
+       }
+}
+
 void View::perform_delayed_view_update()
 {
        update_data();
index 290e42a14b8f06d57bf079dd9e4aec351a3e832a..6bb89c86616e33ab680b60bd86488ef4eaa0b28f 100644 (file)
@@ -27,6 +27,7 @@
 #include <QToolButton>
 
 #include "pv/globalsettings.hpp"
+#include "pv/metadata_obj.hpp"
 #include "pv/views/viewbase.hpp"
 #include "pv/data/decodesignal.hpp"
 
@@ -48,7 +49,7 @@ enum SaveType {
 enum ViewModeType {
        ViewModeAll,
        ViewModeLatest,
-//     ViewModeVisible,
+       ViewModeVisible,
        ViewModeCount // Indicates how many view mode types there are, must always be last
 };
 
@@ -78,6 +79,7 @@ public:
        int columnCount(const QModelIndex& parent_idx = QModelIndex()) const override;
 
        void set_signal_and_segment(data::DecodeSignal* signal, uint32_t current_segment);
+       void set_sample_range(uint64_t start_sample, uint64_t end_sample);
        void set_hide_hidden(bool hide_hidden);
 
        void update_annotations_without_hidden();
@@ -92,6 +94,7 @@ private:
        data::DecodeSignal* signal_;
        uint32_t prev_segment_;
        uint64_t prev_last_row_;
+       uint64_t start_sample_, end_sample_, start_index_, end_index_;
        bool hide_hidden_;
        bool theme_is_dark_;
 };
@@ -107,12 +110,13 @@ public:
 };
 
 
-class View : public ViewBase
+class View : public ViewBase, public MetadataObjObserverInterface
 {
        Q_OBJECT
 
 public:
        explicit View(Session &session, bool is_main_view=false, QMainWindow *parent = nullptr);
+       ~View();
 
        virtual ViewType get_type() const;
 
@@ -155,6 +159,9 @@ private Q_SLOTS:
        void on_table_header_requested(const QPoint& pos);
        void on_table_header_toggled(bool checked);
 
+       virtual void on_metadata_object_changed(MetadataObject* obj,
+               MetadataValueType value_type);
+
        virtual void perform_delayed_view_update();
 
 private:
index 33122047745048e341c155956e6f99076b73e136..0a51a96fb5398a590997e558a9fc7427c9e3679b 100644 (file)
@@ -52,6 +52,7 @@
 #include "view.hpp"
 #include "viewport.hpp"
 
+#include "pv/metadata_obj.hpp"
 #include "pv/data/logic.hpp"
 #include "pv/data/logicsegment.hpp"
 #include "pv/devices/device.hpp"
@@ -182,6 +183,12 @@ View::View(Session &session, bool is_main_view, QMainWindow *parent) :
 
        GlobalSettings::add_change_handler(this);
 
+       // Set up metadata objects and event handlers
+       if (is_main_view)
+               session_.metadata_obj_manager()->create_object(MetadataObjMainViewRange);
+
+
+       // Set up UI event handlers
        connect(scrollarea_->horizontalScrollBar(), SIGNAL(valueChanged(int)),
                this, SLOT(h_scroll_value_changed(int)));
        connect(scrollarea_->verticalScrollBar(), SIGNAL(valueChanged(int)),
@@ -525,6 +532,22 @@ void View::set_offset(const pv::util::Timestamp& offset, bool force_update)
        if ((offset_ != offset) || force_update) {
                offset_ = offset;
                ruler_offset_ = offset_ + zero_offset_;
+
+               const int w = viewport_->width();
+               if (w > 0) {
+                       const double samplerate = session_.get_samplerate();
+                       // Note: sample_num = time * samplerate
+                       // Note: samples_per_pixel = samplerate * scale
+                       int64_t start_sample = (offset_ * samplerate).convert_to<int64_t>();
+                       int64_t end_sample = (offset_ * samplerate).convert_to<int64_t>() +
+                               (w * session_.get_samplerate() * scale_);
+
+                       MetadataObject* md_obj =
+                               session_.metadata_obj_manager()->find_object_by_type(MetadataObjMainViewRange);
+                       md_obj->set_value(MetadataValueStartSample, QVariant((qlonglong)start_sample));
+                       md_obj->set_value(MetadataValueEndSample, QVariant((qlonglong)end_sample));
+               }
+
                offset_changed();
        }
 }