From: Soeren Apel Date: Wed, 29 Apr 2020 14:44:58 +0000 (+0200) Subject: Implement MainViewRange meta obj and tab_dec::ViewModeVisible X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=8997f62a4f87c822578aa5d835e1dd8109c6f5eb;p=pulseview.git Implement MainViewRange meta obj and tab_dec::ViewModeVisible --- diff --git a/pv/metadata_obj.cpp b/pv/metadata_obj.cpp index 72b4be66..b6e77461 100644 --- a/pv/metadata_obj.cpp +++ b/pv/metadata_obj.cpp @@ -22,19 +22,37 @@ 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 diff --git a/pv/metadata_obj.hpp b/pv/metadata_obj.hpp index 593fe968..fef77795 100644 --- a/pv/metadata_obj.hpp +++ b/pv/metadata_obj.hpp @@ -26,6 +26,7 @@ #include #include #include +#include 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_; diff --git a/pv/views/tabular_decoder/model.cpp b/pv/views/tabular_decoder/model.cpp index 28467de4..b0632f7a 100644 --- a/pv/views/tabular_decoder/model.cpp +++ b/pv/views/tabular_decoder/model.cpp @@ -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) diff --git a/pv/views/tabular_decoder/view.cpp b/pv/views/tabular_decoder/view.cpp index 6ee3e2ac..b4bb93de 100644 --- a/pv/views/tabular_decoder/view.cpp +++ b/pv/views/tabular_decoder/view.cpp @@ -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(); diff --git a/pv/views/tabular_decoder/view.hpp b/pv/views/tabular_decoder/view.hpp index 290e42a1..6bb89c86 100644 --- a/pv/views/tabular_decoder/view.hpp +++ b/pv/views/tabular_decoder/view.hpp @@ -27,6 +27,7 @@ #include #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: diff --git a/pv/views/trace/view.cpp b/pv/views/trace/view.cpp index 33122047..0a51a96f 100644 --- a/pv/views/trace/view.cpp +++ b/pv/views/trace/view.cpp @@ -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 end_sample = (offset_ * samplerate).convert_to() + + (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(); } }