CVB++ 15.0
property_grid.hpp
1#pragma once
2
3#pragma warning(push)
4#pragma warning(disable : 4800)
5#pragma warning(disable : 4251)
6#pragma warning(disable : 4244)
7#pragma warning(disable : 4127)
8#include <QTreeView>
9#include <QStyledItemDelegate>
10#include <QSignalMapper>
11#include <QPainter>
12#include <QApplication>
13#include <QEvent>
14#include <QTimer>
15#pragma warning(pop)
16
17#include "../global.hpp"
18#include "../genapi/node_map.hpp"
19#include "../genapi/genapi.hpp"
20#include "_detail/detail_property_model.hpp"
21
22namespace Cvb
23{
24
25 CVB_BEGIN_INLINE_NS
26
27 namespace UI
28 {
29
30 class VariantDelegate : public QStyledItemDelegate
31 {
32
33 Q_OBJECT
34
35 public:
36 explicit VariantDelegate(QObject *parent = 0)
37 : QStyledItemDelegate(parent)
38 , finishedMapper_(nullptr)
39 {
40 finishedMapper_ = new QSignalMapper(this); // NOLINT
41 QObject::connect(finishedMapper_, SIGNAL(mapped(QWidget *)), this, SIGNAL(commitData(QWidget *)));
42 QObject::connect(finishedMapper_, SIGNAL(mapped(QWidget *)), this, SIGNAL(closeEditor(QWidget *)));
43 }
44
45 QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
46 const QModelIndex &index) const override
47 {
48 QWidget *editor = 0;
49
50 auto prop = static_cast<UI::Private::Property *>(index.internalPointer());
51 if (prop)
52 {
53 switch (prop->Type())
54 {
55 case UI::Private::Property::PT_Boolean:
56 case UI::Private::Property::PT_Category:
57 case UI::Private::Property::PT_Command:
58 case UI::Private::Property::PT_Enumeration:
59 case UI::Private::Property::PT_Float:
60 case UI::Private::Property::PT_Integer:
61 case UI::Private::Property::PT_String:
62 editor = prop->CreateEditor(parent);
63 if (editor)
64 {
65 if (editor->metaObject()->indexOfSignal("editingFinished()") != -1)
66 {
67 QObject::connect(editor, SIGNAL(editingFinished()), finishedMapper_, SLOT(map()));
68 finishedMapper_->setMapping(editor, editor);
69 }
70 break;
71 }
72 // else
73 // if no editor could be created take default case
74 default:
75 editor = QStyledItemDelegate::createEditor(parent, option, index);
76 }
77 }
78
79 return editor;
80 }
81
82 void setEditorData(QWidget * /*editor*/, const QModelIndex & /*index*/) const override
83 {
84 // Do nothing, only override setEditorData function
85 }
86
87 void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
88 {
89 auto data = index.model()->data(index, Qt::EditRole);
90 if (data.type() == QVariant::UserType)
91 {
92 data = static_cast<UI::Private::Property *>(index.internalPointer())->EditorData(editor);
93 if (data.isValid())
94 {
95 model->setData(index, data, Qt::EditRole);
96 }
97 }
98 else
99 QStyledItemDelegate::setModelData(editor, model, index);
100 }
101
102 void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
103 const QModelIndex &index) const override
104 {
105 return QStyledItemDelegate::updateEditorGeometry(editor, option, index);
106 }
107
108 void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
109 {
110 painter->save();
111 painter->setPen(QColor(Qt::gray));
112
113 auto prop = static_cast<UI::Private::Property *>(index.internalPointer());
114 if (prop->Type() == UI::Private::Property::PT_Category)
115 {
116 painter->fillRect(option.rect,
117 QApplication::palette("QTreeView").brush(QPalette::Normal, QPalette::Button).color());
118 }
119 else
120 {
121 if (index.column() == 0)
122 painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
123 }
124
125 painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
126 painter->restore();
127
128 QStyledItemDelegate::paint(painter, option, index);
129 }
130
131 private:
132 QSignalMapper *finishedMapper_;
133 };
134
136
149 class PropertyGrid : public QTreeView
150 {
151
152 Q_OBJECT
153
154 public:
156
161 explicit PropertyGrid(const NodeMapPtr &nodemap, QWidget *parent = nullptr)
162 : QTreeView(parent)
163 , propertyModel_(nullptr)
164 , updateTimer_(nullptr)
165 {
166 // Allow only single selection and remove editor after focus change
167 setSelectionMode(QAbstractItemView::SingleSelection);
168 setContextMenuPolicy(Qt::CustomContextMenu);
169
170 propertyModel_ = new UI::Private::PropertyModel(); // NOLINT
171
172 try
173 {
174 SetNodeMap(nodemap);
175 }
176 catch (const std::exception &)
177 {
178 delete propertyModel_;
179 throw;
180 }
181
182 // At click create editor (otherwise double click is necessary)
183 QObject::connect(this, QOverload<const QModelIndex &>::of(&PropertyGrid::clicked),
184 [=](const QModelIndex &index) {
185 // Do not call editing on items with no editor (return EmptyEditor())
186 // otherwise error message "edit: editing failed" occurs
187 auto prop = propertyModel_->Property(index);
188 if (prop)
189 {
190 if (!prop->IsReadOnly() && prop->Type() != UI::Private::Property::PT_Boolean)
191 edit(index);
192 }
193 });
194
195 // Init the update timer
196 updateTimer_ = new QTimer(this); // NOLINT(cppcoreguidelines-owning-memory)
197 QObject::connect(updateTimer_, &QTimer::timeout, [=]() { update(); });
198 }
199
200 PropertyGrid(const PropertyGrid &other) = delete;
201 PropertyGrid &operator=(const PropertyGrid &other) = delete;
202 PropertyGrid(PropertyGrid &&other) = delete;
203 PropertyGrid &operator=(PropertyGrid &&other) = delete;
205 {
206 if (propertyModel_)
207 delete propertyModel_;
208 }
209
211
215 void SetNodeMap(const NodeMapPtr &nodemap)
216 {
217 propertyModel_->SetNodeMap(nodemap);
218
219 setModel(propertyModel_);
220 setItemDelegate(new VariantDelegate(this)); // NOLINT(cppcoreguidelines-owning-memory)
221 resizeColumnToContents(0);
222
223 if (columnWidth(0) < maxColumnWidth_)
224 setColumnWidth(0, maxColumnWidth_);
225 }
226
228
233 {
234 return propertyModel_->NodeMap();
235 }
236
238
242 {
243 propertyModel_->RemoveNodeMap();
244 setModel(0);
245 }
246
248
253 {
254 propertyModel_->SetMaxVisibility(visibility);
255 }
256
258
263 {
264 return propertyModel_->MaxVisibility();
265 }
266
268
273 QString HtmlFormattedDescription(const QModelIndex &index)
274 {
275 return HtmlDescription(index);
276 }
277
279
285 QModelIndexList Search(const QString &text)
286 {
287 return propertyModel_->Search(text);
288 }
289
291
295 {
296 propertyModel_->ResetSearch();
297 }
298
300
304 QString SearchText()
305 {
306 return propertyModel_->SearchText();
307 }
308
310
315 {
316 propertyModel_->SetSearchResultBGColor(color);
317 }
318
320
325 {
326 return propertyModel_->SearchResultBGColor();
327 }
328
330
335 NodePtr Node(const QModelIndex &index)
336 {
337 return propertyModel_->Item(index)->Node();
338 }
339
341
345 void ExpandSearchResult(const QModelIndexList &indexList)
346 {
347 for (int i = 0; i < indexList.size(); i++)
348 ExpandProperty(indexList.at(i));
349 }
350
352
356 void CollapseSearchResult(const QModelIndexList &indexList)
357 {
358 for (int i = 0; i < indexList.size(); i++)
359 CollapseProperty(indexList.at(i));
360 }
361
363
367 void UpdateProperty(const QModelIndex &index)
368 {
369 propertyModel_->UpdateProperty(index);
370 }
371
373
376 void Update()
377 {
378 propertyModel_->Update();
379 }
380
382
386 void StartAutoUpdate(int ms)
387 {
388 updateTimer_->start(ms);
389 }
390
392
396 {
397 updateTimer_->stop();
398 }
399
401
408 {
409 propertyModel_->ResetUpdateLock();
410 }
411
412 private:
413 void ExpandProperty(const QModelIndex &index) // NOLINT(misc-no-recursion)
414 {
415 // Expand the node
416 setExpanded(index, true);
417 scrollTo(index);
418
419 // Get the parent node
420 auto parentIndex = propertyModel_->parent(index);
421
422 if (parentIndex != QModelIndex()) // is not root
423 ExpandProperty(parentIndex);
424 }
425
426 void CollapseProperty(const QModelIndex &index) // NOLINT(misc-no-recursion)
427 {
428 // Collapse the node
429 setExpanded(index, false);
430
431 // Get the parent node
432 auto parentIndex = propertyModel_->parent(index);
433
434 if (parentIndex != QModelIndex()) // is not root
435 CollapseProperty(parentIndex);
436 }
437
438 QString HtmlDescription(const QModelIndex &index)
439 {
440 auto prop = propertyModel_->Item(index);
441
442 if (!prop)
443 return QString();
444
445 auto node = prop->Node();
446
447 QString txt = "<b>" + UI::CvbToQt(node->DisplayName()) + " (" + UI::CvbToQt(node->Name()) + ")</b>";
448 if (!node->Description().empty())
449 txt.append("<br>" + UI::CvbToQt(node->Description()));
450
451 txt.append("<br><table>");
452 txt.append("<tr><td><b>Full Name:</b></td><td>" + UI::CvbToQt(node->Name()));
453
454 if (typeid(node) != typeid(CategoryNodePtr))
455 {
456 txt.append("<tr><td><b>Type:</b></td><td>" + UI::CvbToQt(prop->NodeType()) + "</td></tr>");
457 txt.append("<tr><td><b>Access Mode:</b></td><td>" + UI::CvbToQt(prop->NodeAccessMode()) + "</td></tr>");
458 txt.append("<tr><td><b>Visibility:</b></td><td>" + UI::CvbToQt(prop->NodeVisibility()) + "</td></tr>");
459 txt.append("<tr><td><b>Caching Mode:</b></td><td>" + UI::CvbToQt(prop->NodeCachingMode()) + "</td></tr>");
460 if (prop->NodeIsStreamable())
461 txt.append("<tr><td><b>Streamable:</b></td><td>True</td></tr>");
462 else
463 txt.append("<tr><td><b>Streamable:</b></td><td>False</td></tr>");
464 }
465 txt.append("</table>");
466
467 switch (prop->Type())
468 {
469 default:
470 break;
471 case UI::Private::Property::PropertyType::PT_Integer:
472 case UI::Private::Property::PropertyType::PT_Float:
473 case UI::Private::Property::PropertyType::PT_String:
474 case UI::Private::Property::PropertyType::PT_Enumeration:
475 txt.append(prop->HtmlDescription());
476 break;
477 }
478
479 return txt;
480 }
481
482 private:
483 static const int maxColumnWidth_ = 180;
484 UI::Private::PropertyModel *propertyModel_;
485 QTimer *updateTimer_;
486
487 }; /* class PropertyGrid */
488
489 } /* namespace UI */
490
491 CVB_END_INLINE_NS
492
493} /* namespace Cvb */
View to display a device's nodemap.
Definition property_grid.hpp:150
void StopAutoUpdate()
Stops the automatic update of the nodes.
Definition property_grid.hpp:395
NodePtr Node(const QModelIndex &index)
The node of the given QModelIndex.
Definition property_grid.hpp:335
void CollapseSearchResult(const QModelIndexList &indexList)
Collapses all nodes of given QModelIndexList as well as its parents.
Definition property_grid.hpp:356
NodeMapPtr NodeMap()
Return the nodemap.
Definition property_grid.hpp:232
GenApi::Visibility Visibility()
Returns the visibility of the nodemap.
Definition property_grid.hpp:262
void ReleaseNodeMap()
Release the nodemap.
Definition property_grid.hpp:241
void UpdateProperty(const QModelIndex &index)
Updates a given property / node.
Definition property_grid.hpp:367
QString SearchText()
Returns the search text which is currently set.
Definition property_grid.hpp:304
void SetVisibility(GenApi::Visibility visibility)
Set the visibility of the nodemap.
Definition property_grid.hpp:252
QModelIndexList Search(const QString &text)
Search for displayed property name.
Definition property_grid.hpp:285
QColor SearchResultBackgroundColor()
Returns the search result background color.
Definition property_grid.hpp:324
void StartAutoUpdate(int ms)
Starts the automatic update of the nodes.
Definition property_grid.hpp:386
void SetNodeMap(const NodeMapPtr &nodemap)
Set the nodemap and exchanges the model.
Definition property_grid.hpp:215
void ExpandSearchResult(const QModelIndexList &indexList)
Expands all nodes of given QModelIndexList as well as its parents.
Definition property_grid.hpp:345
QString HtmlFormattedDescription(const QModelIndex &index)
Returns an HTML formatted description of given node by QModelIndex.
Definition property_grid.hpp:273
PropertyGrid(const NodeMapPtr &nodemap, QWidget *parent=nullptr)
Create a property grid.
Definition property_grid.hpp:161
void SetSearchResultBackgroundColor(QColor color)
Set the search result background color.
Definition property_grid.hpp:314
void ResetUpdateLock()
Reset the update lock.
Definition property_grid.hpp:407
void ResetSearch()
Reset the search text.
Definition property_grid.hpp:294
void Update()
Updates all properties / nodes.
Definition property_grid.hpp:376
std::shared_ptr< Node > NodePtr
Convenience shared pointer for Node.
Definition genapi.hpp:71
Visibility
Feature complexity level.
Definition genapi.hpp:238
std::shared_ptr< NodeMap > NodeMapPtr
Convenience shared pointer for NodeMap.
Definition genapi.hpp:27
std::shared_ptr< CategoryNode > CategoryNodePtr
Convenience shared pointer for CategoryNode.
Definition genapi.hpp:35
Namespace for user interface components.
Definition decl_image_scene.hpp:39
QString CvbToQt(const Cvb::String &text) noexcept
Convenience converter for strings.
Definition ui.hpp:257
Root namespace for the Image Manager interface.
Definition c_bayer_to_rgb.h:17