GCC Code Coverage Report


Directory: ./
File: src/node-property.cpp
Date: 2024-10-14 11:04:13
Exec Total Coverage
Lines: 63 357 17.6%
Branches: 50 776 6.4%

Line Branch Exec Source
1 // Copyright (c) 2018, Joseph Mirabel
2 // Authors: Joseph Mirabel (joseph.mirabel@laas.fr)
3 //
4 // This file is part of gepetto-viewer.
5 // gepetto-viewer is free software: you can redistribute it
6 // and/or modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation, either version
8 // 3 of the License, or (at your option) any later version.
9 //
10 // gepetto-viewer is distributed in the hope that it will be
11 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
12 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Lesser Public License for more details. You should have
14 // received a copy of the GNU Lesser General Public License along with
15 // gepetto-viewer. If not, see <http://www.gnu.org/licenses/>.
16
17 #include <gepetto/viewer/node-property.h>
18
19 #include <QCheckBox>
20 #include <QColorDialog>
21 #include <QComboBox>
22 #include <QDebug>
23 #include <QDoubleSpinBox>
24 #include <QFormLayout>
25 #include <QLabel>
26 #include <QLineEdit>
27 #include <QPushButton>
28 #include <gepetto/gui/dialog/configuration.hh>
29 #include <sstream>
30
31 namespace gepetto {
32 namespace viewer {
33 struct Initializer {
34 1 Initializer() {
35 1 qRegisterMetaType<osgVector2>("osgVector2");
36 1 qRegisterMetaType<osgVector3>("osgVector3");
37 1 qRegisterMetaType<osgVector4>("osgVector4");
38 1 qRegisterMetaType<Configuration>("Configuration");
39 1 }
40 };
41
42 static Initializer initializer;
43
44 template <typename T>
45 inline bool invalidType(const std::string& name, T) {
46 throw std::invalid_argument("Property " + name + " is not of type " +
47 details::property_type<T>::to_string());
48 }
49
50
1/2
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
14 Property::Property(const std::string& name) : QObject(NULL), name_(name) {
51
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 setObjectName(QString::fromStdString(name));
52 14 }
53
54 template <typename T>
55 8 bool check_if_value_changed(Property& prop, const T& v) {
56
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
8 if (!prop.hasReadAccess()) return true;
57 8 T current;
58
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
8 if (!prop.get(current)) return true;
59 8 return current != v;
60 }
61
62 inline QColor qColor(const osgVector4& v) {
63 return QColor::fromRgbF((qreal)v[0], (qreal)v[1], (qreal)v[2], (qreal)v[3]);
64 }
65
66 #define SET_IMPLEMENTATION(v, emit2) \
67 if (!check_if_value_changed(*this, v)) return true; \
68 if (impl_set(v)) { \
69 emit valueChanged(v); \
70 emit2; \
71 return true; \
72 } \
73 return false
74
75 bool Property::set(void) {
76 bool b = impl_set();
77 if (b) {
78 emit valueChanged();
79 }
80 return b;
81 }
82 bool Property::set(const bool& v) { SET_IMPLEMENTATION(v, ); }
83 bool Property::set(const int& v) { SET_IMPLEMENTATION(v, ); }
84 bool Property::set(const float& v) {
85 SET_IMPLEMENTATION(v, emit valueChanged(static_cast<double>(v)));
86 }
87 bool Property::set(const std::string& v) {
88 SET_IMPLEMENTATION(v, emit valueChanged(QString::fromStdString(v)));
89 }
90 bool Property::set(const osgVector2& v) { SET_IMPLEMENTATION(v, ); }
91 bool Property::set(const osgVector3& v) { SET_IMPLEMENTATION(v, ); }
92 bool Property::set(const osgVector4& v) {
93 SET_IMPLEMENTATION(v, emit valueChanged(qColor(v)));
94 }
95
3/4
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 3 times.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
4 bool Property::set(const Configuration& v) { SET_IMPLEMENTATION(v, ); }
96
97 bool Property::get(void) { return impl_get(); }
98 bool Property::get(bool& v) { return impl_get(v); }
99 bool Property::get(int& v) { return impl_get(v); }
100 bool Property::get(float& v) { return impl_get(v); }
101 bool Property::get(std::string& v) { return impl_get(v); }
102 bool Property::get(osgVector2& v) { return impl_get(v); }
103 bool Property::get(osgVector3& v) { return impl_get(v); }
104 bool Property::get(osgVector4& v) { return impl_get(v); }
105 4 bool Property::get(Configuration& v) { return impl_get(v); }
106
107 bool Property::impl_set(void) {
108 throw std::invalid_argument("Property " + name_ + " is not of type void.");
109 }
110 bool Property::impl_set(const bool& v) { return invalidType(name_, v); }
111 bool Property::impl_set(const int& v) { return invalidType(name_, v); }
112 bool Property::impl_set(const float& v) { return invalidType(name_, v); }
113 bool Property::impl_set(const std::string& v) { return invalidType(name_, v); }
114 bool Property::impl_set(const osgVector2& v) { return invalidType(name_, v); }
115 bool Property::impl_set(const osgVector3& v) { return invalidType(name_, v); }
116 bool Property::impl_set(const osgVector4& v) { return invalidType(name_, v); }
117 bool Property::impl_set(const Configuration& v) {
118 return invalidType(name_, v);
119 }
120
121 bool Property::impl_get(void) {
122 throw std::invalid_argument("Property " + name_ + " is not of type void.");
123 }
124 bool Property::impl_get(bool& v) { return invalidType(name_, v); }
125 bool Property::impl_get(int& v) { return invalidType(name_, v); }
126 bool Property::impl_get(float& v) { return invalidType(name_, v); }
127 bool Property::impl_get(std::string& v) { return invalidType(name_, v); }
128 bool Property::impl_get(osgVector2& v) { return invalidType(name_, v); }
129 bool Property::impl_get(osgVector3& v) { return invalidType(name_, v); }
130 bool Property::impl_get(osgVector4& v) { return invalidType(name_, v); }
131 bool Property::impl_get(Configuration& v) { return invalidType(name_, v); }
132
133 bool Property::set(const double& v) { return set(static_cast<float>(v)); }
134
135 bool Property::get(double& v) {
136 float _v = static_cast<float>(v);
137 bool res = get(_v);
138 v = static_cast<double>(_v);
139 return res;
140 }
141
142 bool Property::set(const QString& v) { return set(v.toStdString()); }
143
144 bool Property::get(QString& v) {
145 std::string _v = v.toStdString();
146 bool res = get(_v);
147 v = QString::fromStdString(_v);
148 return res;
149 }
150
151 bool Property::set(const QColor& v) {
152 return set(osgVector4((float)v.redF(), (float)v.greenF(), (float)v.blueF(),
153 (float)v.alphaF()));
154 }
155
156 bool Property::get(QColor& v) {
157 osgVector4 _v((float)v.redF(), (float)v.greenF(), (float)v.blueF(),
158 (float)v.alphaF());
159 bool res = get(_v);
160 v = qColor(_v);
161 return res;
162 }
163
164 QWidget* VoidProperty::guiEditor() {
165 QString toolTip(
166 "Python:\n"
167 " gui.callVoidProperty(nodeName,\"%1\")");
168 QPushButton* button = new QPushButton(objectName());
169 button->setToolTip(toolTip.arg(objectName()));
170 QObject::connect(button, &QAbstractButton::clicked, [this]() { get(); });
171 return button;
172 }
173
174 namespace details {
175 template <typename Scalar, typename QtScalar, typename QtSpinBox>
176 inline void setSpinBoxRange(const Property* prop, QtSpinBox* sb) {
177 const Range<Scalar>* range = dynamic_cast<const Range<Scalar>*>(prop);
178 if (range) {
179 if (range->hasMin()) sb->setMinimum(static_cast<QtScalar>(range->min));
180 if (range->hasMax()) sb->setMaximum(static_cast<QtScalar>(range->max));
181 sb->setSingleStep(static_cast<QtScalar>(range->step));
182 #if QT_VERSION > QT_VERSION_CHECK(5, 12, 0)
183 if (range->adaptiveDecimal)
184 sb->setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
185 #endif
186 }
187 }
188
189 template <>
190 QWidget* buildEditor<bool>(Property* prop) {
191 QString toolTip(
192 "Python:\n"
193 " gui.getBoolProperty(nodeName,\"%1\")\n"
194 " gui.setBoolProperty(nodeName,\"%1\",boolean)");
195 QCheckBox* cb = new QCheckBox;
196 cb->setToolTip(toolTip.arg(prop->objectName()));
197 bool value;
198 /* bool success = */ prop->get(value);
199 cb->setChecked(value);
200 if (prop->hasWriteAccess()) {
201 prop->connect(cb, SIGNAL(toggled(bool)), SLOT(set(bool)),
202 Qt::DirectConnection);
203 cb->connect(prop, SIGNAL(valueChanged(bool)), SLOT(setChecked(bool)),
204 Qt::DirectConnection);
205 } else
206 cb->setEnabled(false);
207 return cb;
208 }
209
210 template <>
211 QWidget* buildEditor<std::string>(Property* prop) {
212 QString toolTip(
213 "Python:\n"
214 " gui.getStringProperty(nodeName,\"%1\")\n"
215 " gui.setStringProperty(nodeName,\"%1\",str)");
216 QLineEdit* le = new QLineEdit;
217 le->setToolTip(toolTip.arg(prop->objectName()));
218 std::string value;
219 /* bool success = */ prop->get(value);
220 le->setText(QString::fromStdString(value));
221 if (prop->hasWriteAccess()) {
222 prop->connect(le, SIGNAL(textChanged(QString)), SLOT(set(QString)),
223 Qt::DirectConnection);
224 le->connect(prop, SIGNAL(valueChanged(QString)), SLOT(setText(QString)),
225 Qt::DirectConnection);
226 } else
227 le->setReadOnly(true);
228 return le;
229 }
230
231 template <>
232 QWidget* buildEditor<float>(Property* prop) {
233 QString toolTip(
234 "Python:\n"
235 " gui.getFloatProperty(nodeName,\"%1\")\n"
236 " gui.setFloatProperty(nodeName,\"%1\",float)");
237 QDoubleSpinBox* dsb = new QDoubleSpinBox;
238 dsb->setObjectName(prop->objectName());
239 dsb->setToolTip(toolTip.arg(prop->objectName()));
240 float value;
241 /* bool success = */ prop->get(value);
242 dsb->setValue(value);
243 if (prop->hasWriteAccess()) {
244 prop->connect(dsb, SIGNAL(valueChanged(double)), SLOT(set(double)),
245 Qt::DirectConnection);
246 dsb->connect(prop, SIGNAL(valueChanged(double)), SLOT(setValue(double)),
247 Qt::DirectConnection);
248 } else
249 dsb->setEnabled(false);
250 setSpinBoxRange<float, double>(prop, dsb);
251 dsb->setDecimals(15);
252 return dsb;
253 }
254
255 template <>
256 QWidget* buildEditor<int>(Property* prop) {
257 QString toolTip(
258 "Python:\n"
259 " gui.getIntProperty(nodeName,\"%1\")\n"
260 " gui.setIntProperty(nodeName,\"%1\",int)");
261 QSpinBox* dsb = new QSpinBox;
262 dsb->setToolTip(toolTip.arg(prop->objectName()));
263 int value;
264 /* bool success = */ prop->get(value);
265 dsb->setValue(value);
266 if (prop->hasWriteAccess()) {
267 prop->connect(dsb, SIGNAL(valueChanged(int)), SLOT(set(int)),
268 Qt::DirectConnection);
269 dsb->connect(prop, SIGNAL(valueChanged(int)), SLOT(setValue(int)),
270 Qt::DirectConnection);
271 } else
272 dsb->setEnabled(false);
273 setSpinBoxRange<int, int>(prop, dsb);
274 return dsb;
275 }
276
277 template <typename VectorType>
278 struct traits {};
279 template <>
280 struct traits<osgVector2> {
281 typedef gui::Vector2Dialog Dialog_t;
282 };
283 template <>
284 struct traits<osgVector3> {
285 typedef gui::Vector3Dialog Dialog_t;
286 };
287 template <>
288 struct traits<osgVector4> {
289 typedef gui::Vector4Dialog Dialog_t;
290 };
291
292 template <typename VectorType>
293 QWidget* buildVectorNEditor(const QString& name, int N, Property* prop) {
294 typedef typename traits<VectorType>::Dialog_t Dialog_t;
295 QString toolTip(
296 "Python:\n"
297 " gui.getVector3Property(nodeName,\"%1\")\n"
298 " gui.setVector3Property(nodeName,\"%1\",int)");
299 QPushButton* button = new QPushButton("Set value");
300 button->setToolTip(toolTip.arg(name));
301
302 /// Vector3 dialog should be opened in a different place
303 Dialog_t* cfgDialog = new Dialog_t(prop);
304 cfgDialog->setValueFromProperty(prop);
305 switch (N) {
306 case 2:
307 prop->connect(cfgDialog, SIGNAL(valueChanged(osgVector2)),
308 SLOT(set(osgVector2)), Qt::DirectConnection);
309 cfgDialog->connect(prop, SIGNAL(valueChanged(osgVector2)),
310 SLOT(set(osgVector2)), Qt::DirectConnection);
311 break;
312 case 3:
313 prop->connect(cfgDialog, SIGNAL(valueChanged(osgVector3)),
314 SLOT(set(osgVector3)), Qt::DirectConnection);
315 cfgDialog->connect(prop, SIGNAL(valueChanged(osgVector3)),
316 SLOT(set(osgVector3)), Qt::DirectConnection);
317 break;
318 case 4:
319 prop->connect(cfgDialog, SIGNAL(valueChanged(osgVector4)),
320 SLOT(set(osgVector4)), Qt::DirectConnection);
321 cfgDialog->connect(prop, SIGNAL(valueChanged(osgVector4)),
322 SLOT(set(osgVector4)), Qt::DirectConnection);
323 break;
324 default:
325 break;
326 }
327 cfgDialog->setProperty("propertyName", name);
328 cfgDialog->connect(button, SIGNAL(clicked()), SLOT(show()));
329
330 return button;
331 }
332
333 template <>
334 QWidget* buildEditor<osgVector2>(Property* prop) {
335 if (!prop->hasWriteAccess()) return NULL;
336 return buildVectorNEditor<osgVector2>(prop->objectName(), 2, prop);
337 }
338
339 template <>
340 QWidget* buildEditor<osgVector3>(Property* prop) {
341 if (!prop->hasWriteAccess()) return NULL;
342 return buildVectorNEditor<osgVector3>(prop->objectName(), 3, prop);
343 }
344
345 QWidget* buildColorEditor(QString& name, Property* prop) {
346 QString toolTip(
347 "Python:\n"
348 " gui.getColorProperty(nodeName,\"%1\")\n"
349 " gui.setColorProperty(nodeName,\"%1\",int)");
350 QColor color;
351 /* bool success = */ prop->get(color);
352
353 QPushButton* button = new QPushButton("Select color");
354 button->setToolTip(toolTip.arg(name));
355 // Set icon for current color value
356
357 /// Color dialog should be opened in a different place
358 QColorDialog* colorDialog = new QColorDialog(color, button);
359 colorDialog->setOption(QColorDialog::ShowAlphaChannel, true);
360 colorDialog->setOption(QColorDialog::NoButtons, true);
361
362 colorDialog->setProperty("propertyName", name);
363 colorDialog->connect(button, SIGNAL(clicked()), SLOT(open()));
364
365 prop->connect(colorDialog, SIGNAL(currentColorChanged(QColor)),
366 SLOT(set(QColor)), Qt::DirectConnection);
367 #if __cplusplus >= 201103L and (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0))
368 QObject::connect(prop, QOverload<const QColor&>::of(&Property::valueChanged),
369 colorDialog, &QColorDialog::setCurrentColor,
370 // SLOT(set(QColor)),
371 Qt::DirectConnection);
372 #endif
373
374 return button;
375 }
376
377 template <>
378 QWidget* buildEditor<osgVector4>(Property* prop) {
379 if (!prop->hasWriteAccess()) return NULL;
380
381 QString name(prop->objectName());
382 if (name.contains("color", Qt::CaseInsensitive))
383 return buildColorEditor(name, prop);
384
385 return buildVectorNEditor<osgVector4>(prop->objectName(), 4, prop);
386 }
387
388 template <>
389 QWidget* buildEditor<Configuration>(Property* prop) {
390 // We could use buildVectorNEditor. The only bad point is that tooltip
391 // which will say setVector3Property instead of setConfigurationProperty...
392 if (!prop->hasWriteAccess()) return NULL;
393
394 QString name(QString::fromStdString(prop->name()));
395 QPushButton* button = new QPushButton("Set transform");
396
397 /// Color dialog should be opened in a different place
398 gui::ConfigurationDialog* cfgDialog = new gui::ConfigurationDialog(prop);
399 cfgDialog->setValueFromProperty(prop);
400 prop->connect(cfgDialog, SIGNAL(valueChanged(Configuration)),
401 SLOT(set(Configuration)), Qt::DirectConnection);
402 cfgDialog->connect(prop, SIGNAL(valueChanged(Configuration)),
403 SLOT(set(Configuration)), Qt::DirectConnection);
404
405 cfgDialog->setProperty("propertyName", name);
406 cfgDialog->connect(button, SIGNAL(clicked()), SLOT(show()));
407
408 return button;
409 }
410 } // namespace details
411
412 int MetaEnum::from_string(const std::string& s) {
413 for (std::size_t i = 0; i < names.size(); ++i)
414 if (s == names[i]) return values[i];
415 throw std::invalid_argument("Unknown name of enum (" + type + "): " + s);
416 }
417 std::string MetaEnum::to_string(const int& v) {
418 for (std::size_t i = 0; i < names.size(); ++i)
419 if (v == values[i]) return names[i];
420 throw std::invalid_argument("Unknown enum value (" + type + ")");
421 }
422
423 1 MetaEnum* visibilityModeEnum() {
424
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 static MetaEnum vm;
425
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (vm.type.size() == 0) {
426 1 vm.type = "VisibilityMode";
427
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 vm.names.push_back("ON");
428
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 vm.values.push_back(VISIBILITY_ON);
429
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 vm.names.push_back("ALWAYS_ON_TOP");
430
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 vm.values.push_back(ALWAYS_ON_TOP);
431
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 vm.names.push_back("OFF");
432
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 vm.values.push_back(VISIBILITY_OFF);
433 }
434 1 return &vm;
435 }
436 1 MetaEnum* wireFrameModeEnum() {
437
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 static MetaEnum wm;
438
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (wm.type.size() == 0) {
439 1 wm.type = "VisibilityMode";
440
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 wm.names.push_back("FILL");
441
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 wm.values.push_back(FILL);
442
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 wm.names.push_back("WIREFRAME");
443
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 wm.values.push_back(WIREFRAME);
444
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 wm.names.push_back("FILL_AND_WIREFRAME");
445
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 wm.values.push_back(FILL_AND_WIREFRAME);
446 }
447 1 return &wm;
448 }
449 1 MetaEnum* lightingModeEnum() {
450
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
1 static MetaEnum lm;
451
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 if (lm.type.size() == 0) {
452 1 lm.type = "LightingMode";
453
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 lm.names.push_back("ON");
454
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 lm.values.push_back(LIGHT_INFLUENCE_ON);
455
2/4
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 lm.names.push_back("OFF");
456
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 lm.values.push_back(LIGHT_INFLUENCE_OFF);
457 }
458 1 return &lm;
459 }
460 MetaEnum* glImmediateModeEnum() {
461 static MetaEnum lm;
462 if (lm.type.size() == 0) {
463 lm.type = "GLImmediateMode";
464 lm.names.push_back("GL_LINES");
465 lm.values.push_back(GL_LINES);
466 lm.names.push_back("GL_POINTS");
467 lm.values.push_back(GL_POINTS);
468 lm.names.push_back("GL_LINE_STRIP");
469 lm.values.push_back(GL_LINE_STRIP);
470 lm.names.push_back("GL_LINE_LOOP");
471 lm.values.push_back(GL_LINE_LOOP);
472 lm.names.push_back("GL_POLYGON");
473 lm.values.push_back(GL_POLYGON);
474 lm.names.push_back("GL_QUADS");
475 lm.values.push_back(GL_QUADS);
476 lm.names.push_back("GL_QUAD_STRIP");
477 lm.values.push_back(GL_QUAD_STRIP);
478 lm.names.push_back("GL_TRIANGLE_STRIP");
479 lm.values.push_back(GL_TRIANGLE_STRIP);
480 lm.names.push_back("GL_TRIANGLES");
481 lm.values.push_back(GL_TRIANGLES);
482 lm.names.push_back("GL_TRIANGLE_FAN");
483 lm.values.push_back(GL_TRIANGLE_FAN);
484 }
485 return &lm;
486 }
487
488 bool EnumProperty::impl_set(const int& value) {
489 const MetaEnum& me = *metaEnum();
490 for (std::size_t i = 0; i < me.values.size(); ++i)
491 if (me.values[i] == value) return IntProperty::impl_set(value);
492 std::ostringstream oss;
493 oss << "Invalid value " << value << " for enum " << me.type
494 << ". "
495 "Possible values are ";
496 for (std::size_t i = 0; i < me.values.size(); ++i)
497 oss << me.names[i] << " (" << me.values[i] << "), ";
498 throw std::invalid_argument(oss.str());
499 return false;
500 }
501
502 bool EnumProperty::impl_set(const std::string& value) {
503 const MetaEnum& me = *metaEnum();
504 for (std::size_t i = 0; i < me.names.size(); ++i)
505 if (me.names[i] == value) return IntProperty::impl_set(me.values[i]);
506 std::ostringstream oss;
507 oss << "Invalid value " << value << " for enum " << me.type
508 << ". "
509 "Possible values are ";
510 for (std::size_t i = 0; i < me.values.size(); ++i)
511 oss << me.names[i] << " (" << me.values[i] << "), ";
512 throw std::invalid_argument(oss.str());
513 return false;
514 }
515
516 bool EnumProperty::impl_get(int& v) { return IntProperty::impl_get(v); }
517
518 bool EnumProperty::impl_get(std::string& str) {
519 int value;
520 if (!IntProperty::impl_get(value)) return false;
521 const MetaEnum& me = *metaEnum();
522 for (std::size_t i = 0; i < me.names.size(); ++i)
523 if (me.values[i] == value) {
524 str = me.names[i];
525 return true;
526 }
527 return false;
528 }
529
530 QWidget* EnumProperty::guiEditor() {
531 QString toolTip(
532 "Python:\n"
533 "As an integer:\n"
534 " gui.getIntProperty(nodeName,\"%1\")\n"
535 " gui.setIntProperty(nodeName,\"%1\",int)\n"
536 "or as a string:\n"
537 " gui.getStringProperty(nodeName,\"%1\")\n"
538 " gui.setStringProperty(nodeName,\"%1\",string)");
539
540 QComboBox* cb = new QComboBox;
541 cb->setToolTip(toolTip.arg(name().c_str()));
542 std::string value;
543 /* bool success = */ get(value);
544 for (unsigned i = 0; i < metaEnum_->values.size(); ++i) {
545 cb->addItem(metaEnum_->names[i].c_str(), metaEnum_->values[i]);
546 if (value == metaEnum_->names[i]) cb->setCurrentIndex(i);
547 }
548 if (hasWriteAccess()) {
549 connect(cb, SIGNAL(currentTextChanged(QString)), SLOT(set(QString)),
550 Qt::DirectConnection);
551 // On Qt4, the combo box will not be updated.
552 #if (QT_VERSION > QT_VERSION_CHECK(5, 0, 0))
553 cb->connect(this, SIGNAL(valueChanged(QString)),
554 SLOT(setCurrentText(QString)), Qt::DirectConnection);
555 #endif
556 } else
557 cb->setEnabled(false);
558 return cb;
559 }
560
561 Property* Properties::property(const std::string& name) const {
562 PropertyMap_t::const_iterator _prop = properties_.find(name);
563 if (_prop == properties_.end())
564 throw std::invalid_argument("Unknown property " + name);
565 return _prop->second.p;
566 }
567
568 bool Properties::hasProperty(const std::string& name) const {
569 PropertyMap_t::const_iterator _prop = properties_.find(name);
570 return (_prop != properties_.end());
571 }
572
573 12 void Properties::addProperty(const PropertyPtr_t& prop) {
574 12 addProperty(prop->name(), prop);
575 12 }
576
577 12 void Properties::addProperty(const std::string& name,
578 const PropertyPtr_t& prop) {
579 12 Wrapper wrapped(prop);
580 std::pair<PropertyMap_t::iterator, bool> res =
581
2/4
✓ Branch 3 taken 12 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
12 properties_.insert(std::make_pair(name, Wrapper(prop)));
582
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (!res.second) res.first->second = prop;
583 12 }
584
585 2 void Properties::addProperty(Property* prop) {
586 2 addProperty(prop->name(), prop);
587 2 }
588
589 2 void Properties::addProperty(const std::string& name, Property* prop) {
590 2 Wrapper wrapped(prop);
591 std::pair<PropertyMap_t::iterator, bool> res =
592
2/4
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
2 properties_.insert(std::make_pair(name, Wrapper(prop)));
593
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!res.second) res.first->second = prop;
594 2 }
595
596 void addPropertyEditor(QFormLayout* l, const std::string& _name,
597 Property* prop) {
598 QString name(QString::fromStdString(_name));
599 QWidget* field = prop->guiEditor();
600 if (field != NULL) {
601 QLabel* label(new QLabel(name + ':'));
602 label->setToolTip(field->toolTip());
603 field->setProperty("propertyName", name);
604 l->addRow(label, field);
605 } else {
606 qDebug() << "Unhandled property" << name << "of type"
607 << prop->type().c_str() << ".";
608 }
609 }
610
611 QWidget* Properties::guiEditor() {
612 QWidget* editor = new QWidget;
613 QFormLayout* l = new QFormLayout(editor);
614
615 for (PropertyMap_t::const_iterator _prop = properties_.begin();
616 _prop != properties_.end(); ++_prop) {
617 if (!_prop->second->hasReadAccess()) continue;
618 addPropertyEditor(l, _prop->first, _prop->second.p);
619 }
620 return editor;
621 }
622 } /* namespace viewer */
623
624 } /* namespace gepetto */
625