]> sigrok.org Git - pulseview.git/blob - pv/prop/int.cpp
Fix #1035 by checking for exceptions when accessing config
[pulseview.git] / pv / prop / int.cpp
1 /*
2  * This file is part of the PulseView project.
3  *
4  * Copyright (C) 2013 Joel Holdsworth <joel@airwebreathe.org.uk>
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 <cassert>
21 #include <cstdint>
22
23 #include <QDebug>
24 #include <QSpinBox>
25
26 #include <libsigrokcxx/libsigrokcxx.hpp>
27
28 #include "int.hpp"
29
30 using boost::optional;
31 using std::max;
32 using std::min;
33 using std::pair;
34
35 namespace pv {
36 namespace prop {
37
38 Int::Int(QString name,
39         QString desc,
40         QString suffix,
41         optional< pair<int64_t, int64_t> > range,
42         Getter getter,
43         Setter setter) :
44         Property(name, desc, getter, setter),
45         suffix_(suffix),
46         range_(range),
47         spin_box_(nullptr)
48 {
49 }
50
51 QWidget* Int::get_widget(QWidget *parent, bool auto_commit)
52 {
53         int64_t range_min = 0;
54         uint64_t range_max = 0;
55
56         if (spin_box_)
57                 return spin_box_;
58
59         if (!getter_)
60                 return nullptr;
61
62         try {
63                 value_ = getter_();
64         } catch (const sigrok::Error &e) {
65                 qWarning() << tr("Querying config key %1 resulted in %2").arg(name_, e.what());
66                 return nullptr;
67         }
68
69         GVariant *value = value_.gobj();
70         if (!value)
71                 return nullptr;
72
73         spin_box_ = new QSpinBox(parent);
74         spin_box_->setSuffix(suffix_);
75
76         const GVariantType *const type = g_variant_get_type(value);
77         assert(type);
78
79         if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTE)) {
80                 range_min = 0, range_max = UINT8_MAX;
81         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT16)) {
82                 range_min = INT16_MIN, range_max = INT16_MAX;
83         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16)) {
84                 range_min = 0, range_max = UINT16_MAX;
85         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32)) {
86                 range_min = INT32_MIN, range_max = INT32_MAX;
87         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32)) {
88                 range_min = 0, range_max = UINT32_MAX;
89         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64)) {
90                 range_min = INT64_MIN, range_max = INT64_MAX;
91         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64)) {
92                 range_min = 0, range_max = UINT64_MAX;
93         } else {
94                 // Unexpected value type.
95                 assert(false);
96         }
97
98         // @todo sigrok supports 64-bit quantities, but Qt does not have a
99         // standard widget to allow the values to be modified over the full
100         // 64-bit range on 32-bit machines. To solve the issue we need a
101         // custom widget.
102
103         range_min = max(range_min, (int64_t)INT_MIN);
104         range_max = min(range_max, (uint64_t)INT_MAX);
105
106         if (range_)
107                 spin_box_->setRange((int)range_->first, (int)range_->second);
108         else
109                 spin_box_->setRange((int)range_min, (int)range_max);
110
111         update_widget();
112
113         if (auto_commit)
114                 connect(spin_box_, SIGNAL(valueChanged(int)),
115                         this, SLOT(on_value_changed(int)));
116
117         return spin_box_;
118 }
119
120 void Int::update_widget()
121 {
122         if (!spin_box_)
123                 return;
124
125         try {
126                 value_ = getter_();
127         } catch (const sigrok::Error &e) {
128                 qWarning() << tr("Querying config key %1 resulted in %2").arg(name_, e.what());
129                 return;
130         }
131
132         GVariant *value = value_.gobj();
133         assert(value);
134
135         const GVariantType *const type = g_variant_get_type(value);
136         assert(type);
137
138         int64_t int_val = 0;
139
140         if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTE)) {
141                 int_val = g_variant_get_byte(value);
142         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT16)) {
143                 int_val = g_variant_get_int16(value);
144         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16)) {
145                 int_val = g_variant_get_uint16(value);
146         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32)) {
147                 int_val = g_variant_get_int32(value);
148         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32)) {
149                 int_val = g_variant_get_uint32(value);
150         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64)) {
151                 int_val = g_variant_get_int64(value);
152         } else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64)) {
153                 int_val = g_variant_get_uint64(value);
154         } else {
155                 // Unexpected value type.
156                 assert(false);
157         }
158
159         spin_box_->setValue((int)int_val);
160 }
161
162 void Int::commit()
163 {
164         assert(setter_);
165
166         if (!spin_box_)
167                 return;
168
169         GVariant *new_value = nullptr;
170         const GVariantType *const type = g_variant_get_type(value_.gobj());
171         assert(type);
172
173         if (g_variant_type_equal(type, G_VARIANT_TYPE_BYTE))
174                 new_value = g_variant_new_byte(spin_box_->value());
175         else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT16))
176                 new_value = g_variant_new_int16(spin_box_->value());
177         else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT16))
178                 new_value = g_variant_new_uint16(spin_box_->value());
179         else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT32))
180                 new_value = g_variant_new_int32(spin_box_->value());
181         else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT32))
182                 new_value = g_variant_new_uint32(spin_box_->value());
183         else if (g_variant_type_equal(type, G_VARIANT_TYPE_INT64))
184                 new_value = g_variant_new_int64(spin_box_->value());
185         else if (g_variant_type_equal(type, G_VARIANT_TYPE_UINT64))
186                 new_value = g_variant_new_uint64(spin_box_->value());
187         else {
188                 // Unexpected value type.
189                 assert(false);
190         }
191
192         assert(new_value);
193
194         value_ = Glib::VariantBase(new_value);
195
196         setter_(value_);
197 }
198
199 void Int::on_value_changed(int)
200 {
201         commit();
202 }
203
204 }  // namespace prop
205 }  // namespace pv