22 #include <QApplication> 24 #include <QFileDialog> 25 #include <QFontMetrics> 26 #include <QHeaderView> 29 #include <QMessageBox> 31 #include <QVBoxLayout> 33 #include <libsigrokdecode/libsigrokdecode.h> 47 using std::make_shared;
49 using std::shared_ptr;
53 namespace tabular_decoder {
56 "CSV, commas escaped",
62 "Show all and focus on newest",
63 "Show visible in main view" 69 range_filtering_enabled_(false)
74 const QModelIndex &sourceParent)
const 77 assert(sourceModel() !=
nullptr);
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();
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();
98 const bool entirely_outside_of_range = left_of_range || right_of_range;
100 result = !entirely_outside_of_range;
125 QSize size(QTableView::sizeHint());
128 for (
int i = 0; i < horizontalHeader()->count(); i++)
129 if (!horizontalHeader()->isSectionHidden(i))
130 width += horizontalHeader()->sectionSize(i);
132 size.setWidth(width + (horizontalHeader()->count() * 1));
139 return minimumSizeHint();
144 if ((event->key() == Qt::Key_Return) || (event->key() == Qt::Key_Enter))
145 activatedByKey(currentIndex());
147 QTableView::keyPressEvent(event);
152 ViewBase(session, is_main_view, parent),
156 decoder_selector_(new QComboBox()),
157 hide_hidden_cb_(new QCheckBox()),
158 view_mode_selector_(new QComboBox()),
160 save_action_(new QAction(
this)),
166 QVBoxLayout *root_layout =
new QVBoxLayout(
this);
167 root_layout->setContentsMargins(0, 0, 0, 0);
172 toolbar->setContextMenuPolicy(Qt::PreventContextMenu);
173 parent->addToolBar(toolbar);
176 toolbar->addWidget(
new QLabel(tr(
"Decoder:")));
178 toolbar->addSeparator();
180 toolbar->addSeparator();
182 toolbar->addSeparator();
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));
208 save_action_->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_S));
213 QMenu *save_menu =
new QMenu();
214 connect(save_menu, SIGNAL(triggered(QAction*)),
218 QAction *
const action = save_menu->addAction(tr(SaveTypeNames[i]));
219 action->setData(QVariant::fromValue(i));
224 save_button_->setPopupMode(QToolButton::MenuButtonPopup);
230 table_view_->setSelectionBehavior(QAbstractItemView::SelectRows);
231 table_view_->setSelectionMode(QAbstractItemView::ContiguousSelection);
238 const int font_height = QFontMetrics(QApplication::font()).height();
239 table_view_->verticalHeader()->setDefaultSectionSize((font_height * 5) / 4);
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);
247 table_view_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
250 connect(
table_view_, SIGNAL(clicked(
const QModelIndex&)),
252 connect(
table_view_, SIGNAL(doubleClicked(
const QModelIndex&)),
254 connect(
table_view_, SIGNAL(activatedByKey(
const QModelIndex&)),
256 connect(
table_view_->horizontalHeader(), SIGNAL(customContextMenuRequested(
const QPoint&)),
272 return ViewTypeTabularDecoder;
284 ViewBase::clear_decode_signals();
292 ViewBase::add_decode_signal(signal);
294 connect(signal.get(), SIGNAL(name_changed(
const QString&)),
300 connect(signal.get(), SIGNAL(decoder_stacked(
void*)),
302 connect(signal.get(), SIGNAL(decoder_removed(
void*)),
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()));
316 for (
const shared_ptr<Decoder>& dec : signal->decoder_stack()) {
323 ViewBase::remove_decode_signal(signal);
344 if (settings.contains(
"view_mode"))
347 if (settings.contains(
"hide_hidden"))
372 const bool save_all = !
table_view_->selectionModel()->hasSelection();
375 const QString dir = settings.value(
"MainWindow/SaveDirectory").toString();
377 const QString file_name = QFileDialog::getSaveFileName(
378 parent_, tr(
"Save Annotations as CSV"), dir, tr(
"CSV Files (*.csv);;Text Files (*.txt);;All Files (*)"));
380 if (file_name.isEmpty())
383 QFile
file(file_name);
384 if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
385 QTextStream out_stream(&file);
391 for (
int i = 0; i <
table_view_->horizontalHeader()->count(); i++) {
392 int column =
table_view_->horizontalHeader()->logicalIndex(i);
394 if (
table_view_->horizontalHeader()->isSectionHidden(column))
397 const QString title =
filter_proxy_model_->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString();
402 out_stream <<
'"' << title <<
'"';
404 if (i < (
table_view_->horizontalHeader()->count() - 1))
407 out_stream <<
'\r' <<
'\n';
410 QModelIndexList selected_rows =
table_view_->selectionModel()->selectedRows();
412 for (
int i = 0; i < selected_rows.size(); i++) {
413 const int row = selected_rows.at(i).row();
416 for (
int c = 0; c <
table_view_->horizontalHeader()->count(); c++) {
417 const int column =
table_view_->horizontalHeader()->logicalIndex(c);
419 if (
table_view_->horizontalHeader()->isSectionHidden(column))
426 out_stream << s.replace(
",",
"\\,");
428 out_stream <<
'"' << s.replace(
"\"",
"\"\"") <<
'"';
430 if (c < (
table_view_->horizontalHeader()->count() - 1))
434 out_stream <<
'\r' <<
'\n';
437 if (out_stream.status() == QTextStream::Ok) {
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);
455 disconnect(
signal_, SIGNAL(color_changed(QColor)));
456 disconnect(
signal_, SIGNAL(new_annotations()));
457 disconnect(
signal_, SIGNAL(decode_reset()));
465 for (
const shared_ptr<DecodeSignal>& ds : decode_signals_)
466 for (
const shared_ptr<Decoder>& dec : ds->decoder_stack())
505 max((int64_t)0, end_sample));
513 QAbstractItemView::PositionAtBottom);
529 if (!stack.empty()) {
530 shared_ptr<Decoder>& dec = stack.at(0);
552 QAbstractItemView::PositionAtBottom);
573 for (
const shared_ptr<DecodeSignal>& ds : decode_signals_)
574 for (
const shared_ptr<Decoder>& dec : ds->decoder_stack())
580 const shared_ptr<Decoder>& dec = signal->
decoder_stack().at(0);
605 save_type = action->data().toInt();
632 QMenu* menu =
new QMenu(
this);
634 for (
int i = 0; i <
table_view_->horizontalHeader()->count(); i++) {
635 int column =
table_view_->horizontalHeader()->logicalIndex(i);
637 const QString title =
639 QAction* action =
new QAction(title,
this);
641 action->setCheckable(
true);
642 action->setChecked(!
table_view_->horizontalHeader()->isSectionHidden(column));
643 action->setData(column);
647 menu->addAction(action);
650 menu->popup(
table_view_->horizontalHeader()->viewport()->mapToGlobal(pos));
655 QAction* action = qobject_cast<QAction*>(QObject::sender());
658 const int column = action->data().toInt();
660 table_view_->horizontalHeader()->setSectionHidden(column, !checked);
677 max((int64_t)0, end_sample));
681 QModelIndex first_visible_idx =
683 QModelIndex last_visible_idx =
686 if (first_visible_idx.isValid()) {
687 const QModelIndex first_highlighted_idx =
693 table_view_->scrollTo(idx, QAbstractItemView::EnsureVisible);
uint64_t range_end_sample_
QModelIndex index(int row, int column, const QModelIndex &parent_idx=QModelIndex()) const override
void on_table_item_clicked(const QModelIndex &index)
View(Session &session, bool is_main_view=false, QMainWindow *parent=nullptr)
void on_hide_hidden_changed(bool checked)
const vector< shared_ptr< Decoder > > & decoder_stack() const
void on_table_item_double_clicked(const QModelIndex &index)
virtual void add_decode_signal(shared_ptr< data::DecodeSignal > signal)
QTimer delayed_view_updater_
void save_data_as_csv(unsigned int save_type) const
virtual void save_settings(QSettings &settings) const
QComboBox * view_mode_selector_
QCheckBox * hide_hidden_cb_
const char * ViewModeNames[ViewModeCount]
void enable_range_filtering(bool value)
QToolButton * save_button_
virtual void save_settings(QSettings &settings) const
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
T value(details::expression_node< T > *n)
uint64_t start_sample() const
uint64_t end_sample() const
virtual void clear_decode_signals()
void on_selected_decoder_changed(int index)
void set_hide_hidden(bool hide_hidden)
uint32_t current_segment_
The ID of the currently displayed segment.
bool range_filtering_enabled_
MetadataObjManager * metadata_obj_manager()
CustomFilterProxyModel * filter_proxy_model_
QModelIndex update_highlighted_rows(QModelIndex first, QModelIndex last, int64_t sample_num)
T max(const T v0, const T v1)
uint8_t first_hidden_column() const
int rowCount(const QModelIndex &parent_idx=QModelIndex()) const override
CustomTableView * table_view_
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
const char * SaveTypeNames[SaveTypeCount]
void on_signal_color_changed(const QColor &color)
virtual void remove_decode_signal(shared_ptr< data::DecodeSignal > signal)
uint64_t range_start_sample_
data::DecodeSignal * signal_
int columnCount(const QModelIndex &parent_idx=QModelIndex()) const override
void on_actionSave_triggered(QAction *action=nullptr)
void on_new_annotations()
AnnotationCollectionModel * model_
virtual void restore_settings(QSettings &settings)
const data::decode::Decoder * decoder_
shared_ptr< views::ViewBase > main_view() const
virtual void reset_view_state()
void set_sample_range(uint64_t start_sample, uint64_t end_sample)
void on_table_header_requested(const QPoint &pos)
void set_signal_and_segment(data::DecodeSignal *signal, uint32_t current_segment)
virtual void on_metadata_object_changed(MetadataObject *obj, MetadataValueType value_type)
CustomFilterProxyModel(QObject *parent=0)
QComboBox * decoder_selector_
virtual void reset_view_state()
void on_decoder_removed(void *decoder)
void on_table_header_toggled(bool checked)
virtual void restore_settings(QSettings &settings)
virtual void keyPressEvent(QKeyEvent *event) override
void on_view_mode_changed(int index)
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
boost::multiprecision::number< boost::multiprecision::cpp_dec_float< 24 >, boost::multiprecision::et_off > Timestamp
Timestamp type providing yoctosecond resolution.
void on_signal_name_changed(const QString &name)
virtual void perform_delayed_view_update()
virtual ViewType get_type() const
virtual QSize minimumSizeHint() const override
void on_decoder_stacked(void *decoder)