]> sigrok.org Git - pulseview.git/blob - pv/views/decoder_output/view.cpp
Connect DecodeSignal and DecoderOutputView
[pulseview.git] / pv / views / decoder_output / view.cpp
1 /*
2  * This file is part of the PulseView project.
3  *
4  * Copyright (C) 2019 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 <QByteArray>
23 #include <QDebug>
24 #include <QLabel>
25 #include <QMenu>
26 #include <QToolBar>
27 #include <QVBoxLayout>
28
29 #include <libsigrokdecode/libsigrokdecode.h>
30
31 #include "view.hpp"
32 #include "QHexView.hpp"
33
34 #include "pv/session.hpp"
35 #include "pv/util.hpp"
36
37 using pv::data::DecodeSignal;
38 using pv::data::SignalBase;
39 using pv::util::TimeUnit;
40 using pv::util::Timestamp;
41
42 using std::numeric_limits;
43 using std::shared_ptr;
44
45 namespace pv {
46 namespace views {
47 namespace decoder_output {
48
49 View::View(Session &session, bool is_main_view, QMainWindow *parent) :
50         ViewBase(session, is_main_view, parent),
51
52         // Note: Place defaults in View::reset_view_state(), not here
53         signal_selector_(new QComboBox()),
54         format_selector_(new QComboBox()),
55         stacked_widget_(new QStackedWidget()),
56         hex_view_(new QHexView()),
57         signal_(nullptr),
58         merged_data_(new QByteArray())
59 {
60         QVBoxLayout *root_layout = new QVBoxLayout(this);
61         root_layout->setContentsMargins(0, 0, 0, 0);
62
63         // Create toolbar
64         QToolBar* toolbar = new QToolBar();
65         toolbar->setContextMenuPolicy(Qt::PreventContextMenu);
66         parent->addToolBar(toolbar);
67
68         // Populate toolbar
69         toolbar->addWidget(new QLabel(tr("Decoder:")));
70         toolbar->addWidget(signal_selector_);
71         toolbar->addSeparator();
72         toolbar->addWidget(new QLabel(tr("Show data as")));
73         toolbar->addWidget(format_selector_);
74
75         // Add format types
76         format_selector_->addItem(tr("Hexdump"), qVariantFromValue(QString("text/hexdump")));
77
78         // Add widget stack
79         root_layout->addWidget(stacked_widget_);
80         stacked_widget_->addWidget(hex_view_);
81         stacked_widget_->setCurrentIndex(0);
82
83         connect(signal_selector_, SIGNAL(currentIndexChanged(int)),
84                 this, SLOT(on_selected_signal_changed(int)));
85
86         hex_view_->setData(merged_data_);
87
88         reset_view_state();
89 }
90
91 View::~View()
92 {
93 }
94
95 ViewType View::get_type() const
96 {
97         return ViewTypeDecoderOutput;
98 }
99
100 void View::reset_view_state()
101 {
102         ViewBase::reset_view_state();
103 }
104
105 void View::clear_signals()
106 {
107         ViewBase::clear_signalbases();
108         signal_ = nullptr;
109 }
110
111 void View::clear_decode_signals()
112 {
113         signal_selector_->clear();
114         format_selector_->setCurrentIndex(0);
115         signal_ = nullptr;
116 }
117
118 void View::add_decode_signal(shared_ptr<data::DecodeSignal> signal)
119 {
120         connect(signal.get(), SIGNAL(name_changed(const QString&)),
121                 this, SLOT(on_signal_name_changed(const QString&)));
122
123         signal_selector_->addItem(signal->name(), QVariant::fromValue((void*)signal.get()));
124 }
125
126 void View::remove_decode_signal(shared_ptr<data::DecodeSignal> signal)
127 {
128         int index = signal_selector_->findData(QVariant::fromValue((void*)signal.get()));
129
130         if (index != -1)
131                 signal_selector_->removeItem(index);
132
133         if (signal.get() == signal_) {
134                 signal_ = nullptr;
135                 update_data();
136         }
137 }
138
139 void View::save_settings(QSettings &settings) const
140 {
141         (void)settings;
142 }
143
144 void View::restore_settings(QSettings &settings)
145 {
146         // Note: It is assumed that this function is only called once,
147         // immediately after restoring a previous session.
148         (void)settings;
149 }
150
151 void View::update_data()
152 {
153         if (!signal_) {
154                 merged_data_->clear();
155                 return;
156         }
157
158         if (signal_->get_binary_data_chunk_count(current_segment_) == 0) {
159                 merged_data_->clear();
160                 return;
161         }
162
163         vector<uint8_t> data;
164         signal_->get_binary_data_chunks_merged(current_segment_, 0,
165                 numeric_limits<uint64_t>::max(), &data);
166
167         merged_data_->resize(data.size());
168         memcpy(merged_data_->data(), data.data(), data.size());
169 }
170
171 void View::on_selected_signal_changed(int index)
172 {
173         if (signal_)
174                 disconnect(signal_, SIGNAL(new_binary_data(unsigned int)));
175
176         signal_ = (DecodeSignal*)signal_selector_->itemData(index).value<void*>();
177         update_data();
178
179         if (signal_)
180                 connect(signal_, SIGNAL(new_binary_data(unsigned int)),
181                         this, SLOT(on_new_binary_data(unsigned int)));
182 }
183
184 void View::on_signal_name_changed(const QString &name)
185 {
186         SignalBase *sb = qobject_cast<SignalBase*>(QObject::sender());
187         assert(sb);
188
189         int index = signal_selector_->findData(QVariant::fromValue(sb));
190         if (index != -1)
191                 signal_selector_->setItemText(index, name);
192 }
193
194 void View::on_new_binary_data(unsigned int segment_id)
195 {
196         if (segment_id == current_segment_)
197                 update_data();
198 }
199
200 } // namespace decoder_output
201 } // namespace views
202 } // namespace pv