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),
type_(obj_type)
{
// Make sure we accept all value type indices
- values_.resize(MetadataObjValueCount);
+ values_.resize(MetadataValueTypeCount);
}
uint32_t MetadataObject::id() 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);
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)
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
#include <QObject>
#include <QSettings>
#include <QString>
+#include <QVariant>
using std::deque;
using std::vector;
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);
};
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_;
signal_(nullptr),
prev_segment_(0),
prev_last_row_(0),
+ start_index_(0),
+ end_index_(0),
hide_hidden_(false)
{
GlobalSettings::add_change_handler(this);
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;
}
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
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
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;
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()
}
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)
using pv::util::Timestamp;
using std::make_shared;
+using std::max;
using std::shared_ptr;
namespace pv {
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
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;
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)
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();
#include <QToolButton>
#include "pv/globalsettings.hpp"
+#include "pv/metadata_obj.hpp"
#include "pv/views/viewbase.hpp"
#include "pv/data/decodesignal.hpp"
enum ViewModeType {
ViewModeAll,
ViewModeLatest,
-// ViewModeVisible,
+ ViewModeVisible,
ViewModeCount // Indicates how many view mode types there are, must always be last
};
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();
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_;
};
};
-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;
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:
#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"
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)),
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();
}
}