PulseView  unreleased development snapshot
A Qt-based sigrok GUI
view.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the PulseView project.
3  *
4  * Copyright (C) 2020 Soeren Apel <soeren@apelpie.net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <climits>
21 
22 #include <QApplication>
23 #include <QDebug>
24 #include <QFileDialog>
25 #include <QFontMetrics>
26 #include <QHeaderView>
27 #include <QLabel>
28 #include <QMenu>
29 #include <QMessageBox>
30 #include <QToolBar>
31 #include <QVBoxLayout>
32 
33 #include <libsigrokdecode/libsigrokdecode.h>
34 
35 #include "view.hpp"
36 
37 #include "pv/globalsettings.hpp"
38 #include "pv/session.hpp"
39 #include "pv/util.hpp"
41 
46 
47 using std::make_shared;
48 using std::max;
49 using std::shared_ptr;
50 
51 namespace pv {
52 namespace views {
53 namespace tabular_decoder {
54 
55 const char* SaveTypeNames[SaveTypeCount] = {
56  "CSV, commas escaped",
57  "CSV, fields quoted"
58 };
59 
60 const char* ViewModeNames[ViewModeCount] = {
61  "Show all",
62  "Show all and focus on newest",
63  "Show visible in main view"
64 };
65 
66 
68  QSortFilterProxyModel(parent),
69  range_filtering_enabled_(false)
70 {
71 }
72 
74  const QModelIndex &sourceParent) const
75 {
76  (void)sourceParent;
77  assert(sourceModel() != nullptr);
78 
79  bool result = true;
80 
82  const QModelIndex ann_start_sample_idx = sourceModel()->index(sourceRow, 0);
83  const uint64_t ann_start_sample =
84  sourceModel()->data(ann_start_sample_idx, Qt::DisplayRole).toULongLong();
85 
86  const QModelIndex ann_end_sample_idx = sourceModel()->index(sourceRow, 6);
87  const uint64_t ann_end_sample =
88  sourceModel()->data(ann_end_sample_idx, Qt::DisplayRole).toULongLong();
89 
90  // We consider all annotations as visible that either
91  // a) begin to the left of the range and end within the range or
92  // b) begin and end within the range or
93  // c) begin within the range and end to the right of the range
94  // ...which is equivalent to the negation of "begins and ends outside the range"
95 
96  const bool left_of_range = (ann_end_sample < range_start_sample_);
97  const bool right_of_range = (ann_start_sample > range_end_sample_);
98  const bool entirely_outside_of_range = left_of_range || right_of_range;
99 
100  result = !entirely_outside_of_range;
101  }
102 
103  return result;
104 }
105 
106 void CustomFilterProxyModel::set_sample_range(uint64_t start_sample,
107  uint64_t end_sample)
108 {
109  range_start_sample_ = start_sample;
110  range_end_sample_ = end_sample;
111 
112  invalidateFilter();
113 }
114 
116 {
118 
119  invalidateFilter();
120 }
121 
122 
124 {
125  QSize size(QTableView::sizeHint());
126 
127  int width = 0;
128  for (int i = 0; i < horizontalHeader()->count(); i++)
129  if (!horizontalHeader()->isSectionHidden(i))
130  width += horizontalHeader()->sectionSize(i);
131 
132  size.setWidth(width + (horizontalHeader()->count() * 1));
133 
134  return size;
135 }
136 
138 {
139  return minimumSizeHint();
140 }
141 
142 void CustomTableView::keyPressEvent(QKeyEvent *event)
143 {
144  if ((event->key() == Qt::Key_Return) || (event->key() == Qt::Key_Enter))
145  activatedByKey(currentIndex());
146  else
147  QTableView::keyPressEvent(event);
148 }
149 
150 
151 View::View(Session &session, bool is_main_view, QMainWindow *parent) :
152  ViewBase(session, is_main_view, parent),
153 
154  // Note: Place defaults in View::reset_view_state(), not here
155  parent_(parent),
156  decoder_selector_(new QComboBox()),
157  hide_hidden_cb_(new QCheckBox()),
158  view_mode_selector_(new QComboBox()),
159  save_button_(new QToolButton()),
160  save_action_(new QAction(this)),
161  table_view_(new CustomTableView()),
162  model_(new AnnotationCollectionModel(this)),
163  filter_proxy_model_(new CustomFilterProxyModel(this)),
164  signal_(nullptr)
165 {
166  QVBoxLayout *root_layout = new QVBoxLayout(this);
167  root_layout->setContentsMargins(0, 0, 0, 0);
168  root_layout->addWidget(table_view_);
169 
170  // Create toolbar
171  QToolBar* toolbar = new QToolBar();
172  toolbar->setContextMenuPolicy(Qt::PreventContextMenu);
173  parent->addToolBar(toolbar);
174 
175  // Populate toolbar
176  toolbar->addWidget(new QLabel(tr("Decoder:")));
177  toolbar->addWidget(decoder_selector_);
178  toolbar->addSeparator();
179  toolbar->addWidget(save_button_);
180  toolbar->addSeparator();
181  toolbar->addWidget(view_mode_selector_);
182  toolbar->addSeparator();
183  toolbar->addWidget(hide_hidden_cb_);
184 
185  connect(decoder_selector_, SIGNAL(currentIndexChanged(int)),
186  this, SLOT(on_selected_decoder_changed(int)));
187  connect(view_mode_selector_, SIGNAL(currentIndexChanged(int)),
188  this, SLOT(on_view_mode_changed(int)));
189  connect(hide_hidden_cb_, SIGNAL(toggled(bool)),
190  this, SLOT(on_hide_hidden_changed(bool)));
191 
192  // Configure widgets
193  decoder_selector_->setSizeAdjustPolicy(QComboBox::AdjustToContents);
194 
195  for (int i = 0; i < ViewModeCount; i++)
196  view_mode_selector_->addItem(ViewModeNames[i], QVariant::fromValue(i));
197 
198  hide_hidden_cb_->setText(tr("Hide Hidden Rows/Classes"));
199  hide_hidden_cb_->setChecked(true);
200 
201  // Configure actions
202  save_action_->setText(tr("&Save..."));
203  save_action_->setIcon(QIcon::fromTheme("document-save-as",
204  QIcon(":/icons/document-save-as.png")));
205 #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
206  save_action_->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S));
207 #else
208  save_action_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
209 #endif
210  connect(save_action_, SIGNAL(triggered(bool)),
211  this, SLOT(on_actionSave_triggered()));
212 
213  QMenu *save_menu = new QMenu();
214  connect(save_menu, SIGNAL(triggered(QAction*)),
215  this, SLOT(on_actionSave_triggered(QAction*)));
216 
217  for (int i = 0; i < SaveTypeCount; i++) {
218  QAction *const action = save_menu->addAction(tr(SaveTypeNames[i]));
219  action->setData(QVariant::fromValue(i));
220  }
221 
222  save_button_->setMenu(save_menu);
223  save_button_->setDefaultAction(save_action_);
224  save_button_->setPopupMode(QToolButton::MenuButtonPopup);
225 
226  // Set up the models and the table view
227  filter_proxy_model_->setSourceModel(model_);
228  table_view_->setModel(filter_proxy_model_);
229 
230  table_view_->setSelectionBehavior(QAbstractItemView::SelectRows);
231  table_view_->setSelectionMode(QAbstractItemView::ContiguousSelection);
232  table_view_->setSortingEnabled(true);
233  table_view_->sortByColumn(0, Qt::AscendingOrder);
234 
235  for (uint8_t i = model_->first_hidden_column(); i < model_->columnCount(); i++)
236  table_view_->setColumnHidden(i, true);
237 
238  const int font_height = QFontMetrics(QApplication::font()).height();
239  table_view_->verticalHeader()->setDefaultSectionSize((font_height * 5) / 4);
240  table_view_->verticalHeader()->setVisible(false);
241 
242  table_view_->horizontalHeader()->setStretchLastSection(true);
243  table_view_->horizontalHeader()->setCascadingSectionResizes(true);
244  table_view_->horizontalHeader()->setSectionsMovable(true);
245  table_view_->horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
246 
247  table_view_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
248  parent->setSizePolicy(table_view_->sizePolicy());
249 
250  connect(table_view_, SIGNAL(clicked(const QModelIndex&)),
251  this, SLOT(on_table_item_clicked(const QModelIndex&)));
252  connect(table_view_, SIGNAL(doubleClicked(const QModelIndex&)),
253  this, SLOT(on_table_item_double_clicked(const QModelIndex&)));
254  connect(table_view_, SIGNAL(activatedByKey(const QModelIndex&)),
255  this, SLOT(on_table_item_double_clicked(const QModelIndex&)));
256  connect(table_view_->horizontalHeader(), SIGNAL(customContextMenuRequested(const QPoint&)),
257  this, SLOT(on_table_header_requested(const QPoint&)));
258 
259  // Set up metadata event handler
261 
263 }
264 
266 {
268 }
269 
271 {
272  return ViewTypeTabularDecoder;
273 }
274 
276 {
278 
279  decoder_selector_->clear();
280 }
281 
283 {
284  ViewBase::clear_decode_signals();
285 
286  reset_data();
288 }
289 
290 void View::add_decode_signal(shared_ptr<data::DecodeSignal> signal)
291 {
292  ViewBase::add_decode_signal(signal);
293 
294  connect(signal.get(), SIGNAL(name_changed(const QString&)),
295  this, SLOT(on_signal_name_changed(const QString&)));
296 
297  // Note: At time of initial creation, decode signals have no decoders so we
298  // need to watch for decoder stacking events
299 
300  connect(signal.get(), SIGNAL(decoder_stacked(void*)),
301  this, SLOT(on_decoder_stacked(void*)));
302  connect(signal.get(), SIGNAL(decoder_removed(void*)),
303  this, SLOT(on_decoder_removed(void*)));
304 
305  // Add the top-level decoder provided by an already-existing signal
306  auto stack = signal->decoder_stack();
307  if (!stack.empty()) {
308  shared_ptr<Decoder>& dec = stack.at(0);
309  decoder_selector_->addItem(signal->name(), QVariant::fromValue((void*)dec.get()));
310  }
311 }
312 
313 void View::remove_decode_signal(shared_ptr<data::DecodeSignal> signal)
314 {
315  // Remove all decoders provided by this signal
316  for (const shared_ptr<Decoder>& dec : signal->decoder_stack()) {
317  int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get()));
318 
319  if (index != -1)
320  decoder_selector_->removeItem(index);
321  }
322 
323  ViewBase::remove_decode_signal(signal);
324 
325  if (signal.get() == signal_) {
326  reset_data();
327  update_data();
329  }
330 }
331 
332 void View::save_settings(QSettings &settings) const
333 {
334  ViewBase::save_settings(settings);
335 
336  settings.setValue("view_mode", view_mode_selector_->currentIndex());
337  settings.setValue("hide_hidden", hide_hidden_cb_->isChecked());
338 }
339 
341 {
342  ViewBase::restore_settings(settings);
343 
344  if (settings.contains("view_mode"))
345  view_mode_selector_->setCurrentIndex(settings.value("view_mode").toInt());
346 
347  if (settings.contains("hide_hidden"))
348  hide_hidden_cb_->setChecked(settings.value("hide_hidden").toBool());
349 }
350 
352 {
353  signal_ = nullptr;
354  decoder_ = nullptr;
355 }
356 
358 {
360 }
361 
362 void View::save_data_as_csv(unsigned int save_type) const
363 {
364  // Note: We try to follow RFC 4180 (https://tools.ietf.org/html/rfc4180)
365 
366  assert(decoder_);
367  assert(signal_);
368 
369  if (!signal_)
370  return;
371 
372  const bool save_all = !table_view_->selectionModel()->hasSelection();
373 
374  GlobalSettings settings;
375  const QString dir = settings.value("MainWindow/SaveDirectory").toString();
376 
377  const QString file_name = QFileDialog::getSaveFileName(
378  parent_, tr("Save Annotations as CSV"), dir, tr("CSV Files (*.csv);;Text Files (*.txt);;All Files (*)"));
379 
380  if (file_name.isEmpty())
381  return;
382 
383  QFile file(file_name);
384  if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
385  QTextStream out_stream(&file);
386 
387  if (save_all)
388  table_view_->selectAll();
389 
390  // Write out header columns in visual order, not logical order
391  for (int i = 0; i < table_view_->horizontalHeader()->count(); i++) {
392  int column = table_view_->horizontalHeader()->logicalIndex(i);
393 
394  if (table_view_->horizontalHeader()->isSectionHidden(column))
395  continue;
396 
397  const QString title = filter_proxy_model_->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString();
398 
399  if (save_type == SaveTypeCSVEscaped)
400  out_stream << title;
401  else
402  out_stream << '"' << title << '"';
403 
404  if (i < (table_view_->horizontalHeader()->count() - 1))
405  out_stream << ",";
406  }
407  out_stream << '\r' << '\n';
408 
409 
410  QModelIndexList selected_rows = table_view_->selectionModel()->selectedRows();
411 
412  for (int i = 0; i < selected_rows.size(); i++) {
413  const int row = selected_rows.at(i).row();
414 
415  // Write out columns in visual order, not logical order
416  for (int c = 0; c < table_view_->horizontalHeader()->count(); c++) {
417  const int column = table_view_->horizontalHeader()->logicalIndex(c);
418 
419  if (table_view_->horizontalHeader()->isSectionHidden(column))
420  continue;
421 
422  const QModelIndex idx = filter_proxy_model_->index(row, column);
423  QString s = filter_proxy_model_->data(idx, Qt::DisplayRole).toString();
424 
425  if (save_type == SaveTypeCSVEscaped)
426  out_stream << s.replace(",", "\\,");
427  else
428  out_stream << '"' << s.replace("\"", "\"\"") << '"';
429 
430  if (c < (table_view_->horizontalHeader()->count() - 1))
431  out_stream << ",";
432  }
433 
434  out_stream << '\r' << '\n';
435  }
436 
437  if (out_stream.status() == QTextStream::Ok) {
438  if (save_all)
439  table_view_->clearSelection();
440 
441  return;
442  }
443  }
444 
445  QMessageBox msg(parent_);
446  msg.setText(tr("Error") + "\n\n" + tr("File %1 could not be written to.").arg(file_name));
447  msg.setStandardButtons(QMessageBox::Ok);
448  msg.setIcon(QMessageBox::Warning);
449  msg.exec();
450 }
451 
453 {
454  if (signal_) {
455  disconnect(signal_, SIGNAL(color_changed(QColor)));
456  disconnect(signal_, SIGNAL(new_annotations()));
457  disconnect(signal_, SIGNAL(decode_reset()));
458  }
459 
460  reset_data();
461 
462  decoder_ = (Decoder*)decoder_selector_->itemData(index).value<void*>();
463 
464  // Find the signal that contains the selected decoder
465  for (const shared_ptr<DecodeSignal>& ds : decode_signals_)
466  for (const shared_ptr<Decoder>& dec : ds->decoder_stack())
467  if (decoder_ == dec.get())
468  signal_ = ds.get();
469 
470  if (signal_) {
471  connect(signal_, SIGNAL(color_changed(QColor)), this, SLOT(on_signal_color_changed(QColor)));
472  connect(signal_, SIGNAL(new_annotations()), this, SLOT(on_new_annotations()));
473  connect(signal_, SIGNAL(decode_reset()), this, SLOT(on_decoder_reset()));
474  }
475 
476  update_data();
477 
478  // Force repaint, otherwise the new selection isn't shown for some reason
479  table_view_->viewport()->update();
480 }
481 
483 {
484  model_->set_hide_hidden(checked);
485 
486  // Force repaint, otherwise the new selection isn't shown for some reason
487  table_view_->viewport()->update();
488 }
489 
491 {
492  if (index == ViewModeAll)
494 
495  if (index == ViewModeVisible) {
496  MetadataObject *md_obj =
498  assert(md_obj);
499 
500  int64_t start_sample = md_obj->value(MetadataValueStartSample).toLongLong();
501  int64_t end_sample = md_obj->value(MetadataValueEndSample).toLongLong();
502 
504  filter_proxy_model_->set_sample_range(max((int64_t)0, start_sample),
505  max((int64_t)0, end_sample));
506  }
507 
508  if (index == ViewModeLatest) {
510 
511  table_view_->scrollTo(
512  filter_proxy_model_->mapFromSource(model_->index(model_->rowCount() - 1, 0)),
513  QAbstractItemView::PositionAtBottom);
514  }
515 }
516 
517 void View::on_signal_name_changed(const QString &name)
518 {
519  (void)name;
520 
521  SignalBase* sb = qobject_cast<SignalBase*>(QObject::sender());
522  assert(sb);
523 
524  DecodeSignal* signal = dynamic_cast<DecodeSignal*>(sb);
525  assert(signal);
526 
527  // Update the top-level decoder provided by this signal
528  auto stack = signal->decoder_stack();
529  if (!stack.empty()) {
530  shared_ptr<Decoder>& dec = stack.at(0);
531  int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get()));
532 
533  if (index != -1)
534  decoder_selector_->setItemText(index, signal->name());
535  }
536 }
537 
538 void View::on_signal_color_changed(const QColor &color)
539 {
540  (void)color;
541 
542  // Force immediate repaint, otherwise it's updated after the header popup is closed
543  table_view_->viewport()->update();
544 }
545 
547 {
548  if (view_mode_selector_->currentIndex() == ViewModeLatest) {
549  update_data();
550  table_view_->scrollTo(
551  filter_proxy_model_->index(filter_proxy_model_->rowCount() - 1, 0),
552  QAbstractItemView::PositionAtBottom);
553  } else {
554  if (!delayed_view_updater_.isActive())
555  delayed_view_updater_.start();
556  }
557 }
558 
560 {
561  // Invalidate the model's data connection immediately - otherwise we
562  // will use a stale pointer in model_->index() when called from the table view
564 }
565 
566 void View::on_decoder_stacked(void* decoder)
567 {
568  Decoder* d = static_cast<Decoder*>(decoder);
569 
570  // Find the signal that contains the selected decoder
571  DecodeSignal* signal = nullptr;
572 
573  for (const shared_ptr<DecodeSignal>& ds : decode_signals_)
574  for (const shared_ptr<Decoder>& dec : ds->decoder_stack())
575  if (d == dec.get())
576  signal = ds.get();
577 
578  assert(signal);
579 
580  const shared_ptr<Decoder>& dec = signal->decoder_stack().at(0);
581  int index = decoder_selector_->findData(QVariant::fromValue((void*)dec.get()));
582 
583  if (index == -1) {
584  // Add the decoder to the list
585  decoder_selector_->addItem(signal->name(), QVariant::fromValue((void*)d));
586  }
587 }
588 
589 void View::on_decoder_removed(void* decoder)
590 {
591  Decoder* d = static_cast<Decoder*>(decoder);
592 
593  // Remove the decoder from the list
594  int index = decoder_selector_->findData(QVariant::fromValue((void*)d));
595 
596  if (index != -1)
597  decoder_selector_->removeItem(index);
598 }
599 
600 void View::on_actionSave_triggered(QAction* action)
601 {
602  int save_type = SaveTypeCSVQuoted;
603 
604  if (action)
605  save_type = action->data().toInt();
606 
607  save_data_as_csv(save_type);
608 }
609 
610 void View::on_table_item_clicked(const QModelIndex& index)
611 {
612  (void)index;
613 
614  // Force repaint, otherwise the new selection isn't shown for some reason
615  table_view_->viewport()->update();
616 }
617 
618 void View::on_table_item_double_clicked(const QModelIndex& index)
619 {
620  const QModelIndex src_idx = filter_proxy_model_->mapToSource(index);
621 
622  const Annotation* ann = static_cast<const Annotation*>(src_idx.internalPointer());
623  assert(ann);
624 
625  shared_ptr<views::ViewBase> main_view = session_.main_view();
626 
627  main_view->focus_on_range(ann->start_sample(), ann->end_sample());
628 }
629 
630 void View::on_table_header_requested(const QPoint& pos)
631 {
632  QMenu* menu = new QMenu(this);
633 
634  for (int i = 0; i < table_view_->horizontalHeader()->count(); i++) {
635  int column = table_view_->horizontalHeader()->logicalIndex(i);
636 
637  const QString title =
638  filter_proxy_model_->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString();
639  QAction* action = new QAction(title, this);
640 
641  action->setCheckable(true);
642  action->setChecked(!table_view_->horizontalHeader()->isSectionHidden(column));
643  action->setData(column);
644 
645  connect(action, SIGNAL(toggled(bool)), this, SLOT(on_table_header_toggled(bool)));
646 
647  menu->addAction(action);
648  }
649 
650  menu->popup(table_view_->horizontalHeader()->viewport()->mapToGlobal(pos));
651 }
652 
654 {
655  QAction* action = qobject_cast<QAction*>(QObject::sender());
656  assert(action);
657 
658  const int column = action->data().toInt();
659 
660  table_view_->horizontalHeader()->setSectionHidden(column, !checked);
661 }
662 
664  MetadataValueType value_type)
665 {
666  // Check if we need to update the model's data range. We only work on the
667  // end sample value because the start sample value is updated first and
668  // we don't want to update the model twice
669  if ((view_mode_selector_->currentIndex() == ViewModeVisible) &&
670  (obj->type() == MetadataObjMainViewRange) &&
671  (value_type == MetadataValueEndSample)) {
672 
673  int64_t start_sample = obj->value(MetadataValueStartSample).toLongLong();
674  int64_t end_sample = obj->value(MetadataValueEndSample).toLongLong();
675 
676  filter_proxy_model_->set_sample_range(max((int64_t)0, start_sample),
677  max((int64_t)0, end_sample));
678  }
679 
680  if (obj->type() == MetadataObjMousePos) {
681  QModelIndex first_visible_idx =
682  filter_proxy_model_->mapToSource(filter_proxy_model_->index(0, 0));
683  QModelIndex last_visible_idx =
684  filter_proxy_model_->mapToSource(filter_proxy_model_->index(filter_proxy_model_->rowCount() - 1, 0));
685 
686  if (first_visible_idx.isValid()) {
687  const QModelIndex first_highlighted_idx =
688  model_->update_highlighted_rows(first_visible_idx, last_visible_idx,
689  obj->value(MetadataValueStartSample).toLongLong());
690 
691  if (view_mode_selector_->currentIndex() == ViewModeVisible) {
692  const QModelIndex idx = filter_proxy_model_->mapFromSource(first_highlighted_idx);
693  table_view_->scrollTo(idx, QAbstractItemView::EnsureVisible);
694  }
695 
696  // Force repaint, otherwise the table doesn't immediately update for some reason
697  table_view_->viewport()->update();
698  }
699  }
700 }
701 
703 {
704  update_data();
705 }
706 
707 
708 } // namespace tabular_decoder
709 } // namespace views
710 } // namespace pv
QModelIndex index(int row, int column, const QModelIndex &parent_idx=QModelIndex()) const override
Definition: model.cpp:176
void on_table_item_clicked(const QModelIndex &index)
Definition: view.cpp:610
View(Session &session, bool is_main_view=false, QMainWindow *parent=nullptr)
Definition: view.cpp:151
void on_hide_hidden_changed(bool checked)
Definition: view.cpp:482
const vector< shared_ptr< Decoder > > & decoder_stack() const
void on_table_item_double_clicked(const QModelIndex &index)
Definition: view.cpp:618
virtual void add_decode_signal(shared_ptr< data::DecodeSignal > signal)
Definition: view.cpp:290
QTimer delayed_view_updater_
Definition: viewbase.hpp:137
void save_data_as_csv(unsigned int save_type) const
Definition: view.cpp:362
virtual void save_settings(QSettings &settings) const
Definition: view.cpp:332
const char * ViewModeNames[ViewModeCount]
Definition: view.cpp:60
Session & session_
Definition: viewbase.hpp:123
virtual void save_settings(QSettings &settings) const
Definition: viewbase.cpp:146
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
Definition: view.cpp:73
T value(details::expression_node< T > *n)
Definition: exprtk.hpp:12358
MetadataObject * find_object_by_type(MetadataObjectType obj_type)
uint64_t start_sample() const
Definition: annotation.cpp:77
uint64_t end_sample() const
Definition: annotation.cpp:82
virtual void clear_decode_signals()
Definition: view.cpp:282
void on_selected_decoder_changed(int index)
Definition: view.cpp:452
uint32_t current_segment_
The ID of the currently displayed segment.
Definition: viewbase.hpp:135
MetadataValueType
MetadataObjManager * metadata_obj_manager()
Definition: session.cpp:1050
CustomFilterProxyModel * filter_proxy_model_
Definition: view.hpp:211
QModelIndex update_highlighted_rows(QModelIndex first, QModelIndex last, int64_t sample_num)
Definition: model.cpp:315
T max(const T v0, const T v1)
Definition: exprtk.hpp:1411
int rowCount(const QModelIndex &parent_idx=QModelIndex()) const override
Definition: model.cpp:200
CustomTableView * table_view_
Definition: view.hpp:209
libsigrok allows users to import and export data from files in various formats some of them as generic as others very specific For a list and make sure to check not so common and outright exotic ways to represent data and sigrok tries to suit as many needs as it can To see which formats your version of PulseView just click on the small arrow next to the _Open_ PulseView will ask for the file name to open Once you picked the file
virtual QSize sizeHint() const override
Definition: view.cpp:137
const char * SaveTypeNames[SaveTypeCount]
Definition: view.cpp:55
void on_signal_color_changed(const QColor &color)
Definition: view.cpp:538
virtual MetadataObjectType type() const
virtual void remove_decode_signal(shared_ptr< data::DecodeSignal > signal)
Definition: view.cpp:313
data::DecodeSignal * signal_
Definition: view.hpp:213
int columnCount(const QModelIndex &parent_idx=QModelIndex()) const override
Definition: model.cpp:210
void on_actionSave_triggered(QAction *action=nullptr)
Definition: view.cpp:600
AnnotationCollectionModel * model_
Definition: view.hpp:210
virtual void restore_settings(QSettings &settings)
Definition: view.cpp:340
const data::decode::Decoder * decoder_
Definition: view.hpp:214
shared_ptr< views::ViewBase > main_view() const
Definition: session.cpp:201
void add_observer(MetadataObjObserverInterface *cb)
virtual void reset_view_state()
Definition: viewbase.cpp:72
void set_sample_range(uint64_t start_sample, uint64_t end_sample)
Definition: view.cpp:106
void on_table_header_requested(const QPoint &pos)
Definition: view.cpp:630
void set_signal_and_segment(data::DecodeSignal *signal, uint32_t current_segment)
Definition: model.cpp:217
virtual void on_metadata_object_changed(MetadataObject *obj, MetadataValueType value_type)
Definition: view.cpp:663
virtual QVariant value(MetadataValueType value_type) const
virtual void reset_view_state()
Definition: view.cpp:275
void on_decoder_removed(void *decoder)
Definition: view.cpp:589
void on_table_header_toggled(bool checked)
Definition: view.cpp:653
virtual void restore_settings(QSettings &settings)
Definition: viewbase.cpp:151
void remove_observer(MetadataObjObserverInterface *cb)
virtual void keyPressEvent(QKeyEvent *event) override
Definition: view.cpp:142
void on_view_mode_changed(int index)
Definition: view.cpp:490
it will come up with a session that has the demo device selected That you can get to know the program even when you don t have any hardware to use it you see a list of devices PulseView has recognized If the device you want to use is you can just select it here image::device_selector_dropdown png[] If it s not you ll need to scan for it first Since most serial port and Ethernet devices can t be auto this is usually required for those To do either choose the Connect to Device option from the list or click on the button itself You will see the following you ll need to pick a driver that you want to use In order to do this
Definition: acquisition.txt:14
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 24 >, boost::multiprecision::et_off > Timestamp
Timestamp type providing yoctosecond resolution.
Definition: util.hpp:67
void on_signal_name_changed(const QString &name)
Definition: view.cpp:517
QString name() const
Definition: signalbase.cpp:210
virtual void perform_delayed_view_update()
Definition: view.cpp:702
virtual ViewType get_type() const
Definition: view.cpp:270
virtual QSize minimumSizeHint() const override
Definition: view.cpp:123
void on_decoder_stacked(void *decoder)
Definition: view.cpp:566