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
22
23namespace Cvb
24{
25
26CVB_BEGIN_INLINE_NS
27
28namespace UI
29{
30
31class VariantDelegate
32 : public QStyledItemDelegate
33{
34
35Q_OBJECT
36
37public:
38
39explicit VariantDelegate(QObject* parent = 0)
41 , finishedMapper_(nullptr)
42{
43 finishedMapper_ = new QSignalMapper(this); // NOLINT
44 QObject::connect(finishedMapper_, SIGNAL(mapped(QWidget*)), this, SIGNAL(commitData(QWidget*)));
45 QObject::connect(finishedMapper_, SIGNAL(mapped(QWidget*)), this, SIGNAL(closeEditor(QWidget*)));
46}
47
48
49QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
50{
51 QWidget* editor = 0;
52
53 auto prop = static_cast<UI::Private::Property*>(index.internalPointer());
54 if (prop)
55 {
56 switch (prop->Type())
57 {
58 case UI::Private::Property::PT_Boolean:
59 case UI::Private::Property::PT_Category:
60 case UI::Private::Property::PT_Command:
61 case UI::Private::Property::PT_Enumeration:
62 case UI::Private::Property::PT_Float:
63 case UI::Private::Property::PT_Integer:
64 case UI::Private::Property::PT_String:
65 editor = prop->CreateEditor(parent);
66 if (editor)
67 {
68 if (editor->metaObject()->indexOfSignal("editingFinished()") != -1)
69 {
70 QObject::connect(editor, SIGNAL(editingFinished()), finishedMapper_, SLOT(map()));
71 finishedMapper_->setMapping(editor, editor);
72 }
73 break;
74 }
75 // else
76 // if no editor could be created take default case
77 default:
78 editor = QStyledItemDelegate::createEditor(parent, option, index);
79 }
80 }
81
82 return editor;
83}
84
85
86void setEditorData(QWidget * /*editor*/, const QModelIndex & /*index*/) const override
87{
88 // Do nothing, only override setEditorData function
89}
90
91void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override
92{
93 auto data = index.model()->data(index, Qt::EditRole);
94 if (data.type() == QVariant::UserType)
95 {
96 data = static_cast<UI::Private::Property*>(index.internalPointer())->EditorData(editor);
97 if (data.isValid())
98 {
99 model->setData(index, data, Qt::EditRole);
100 }
101 }
102 else
103 QStyledItemDelegate::setModelData(editor, model, index);
104}
105
106void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override
107{
108 return QStyledItemDelegate::updateEditorGeometry(editor, option, index);
109}
110
111void paint(QPainter *painter, const QStyleOptionViewItem & option, const QModelIndex & index) const override
112{
113 painter->save();
114 painter->setPen(QColor(Qt::gray));
115
116 auto prop = static_cast<UI::Private::Property*>(index.internalPointer());
117 if (prop->Type() == UI::Private::Property::PT_Category)
118 {
119 painter->fillRect(option.rect, QApplication::palette("QTreeView").brush(QPalette::Normal, QPalette::Button).color());
120 }
121 else
122 {
123 if (index.column() == 0)
124 painter->drawLine(option.rect.topRight(), option.rect.bottomRight());
125 }
126
127 painter->drawLine(option.rect.bottomLeft(), option.rect.bottomRight());
128 painter->restore();
129
130 QStyledItemDelegate::paint(painter, option, index);
131}
132
133private:
134
135QSignalMapper* finishedMapper_;
136};
137
138
139
140
142
156 : public QTreeView
157{
158
159Q_OBJECT
160
161public:
162
164
169explicit PropertyGrid(const NodeMapPtr & nodemap, QWidget *parent = nullptr)
171 , propertyModel_(nullptr)
172 , updateTimer_(nullptr)
173{
174 // Allow only single selection and remove editor after focus change
175 setSelectionMode(QAbstractItemView::SingleSelection);
176 setContextMenuPolicy(Qt::CustomContextMenu);
177
178 propertyModel_ = new UI::Private::PropertyModel(); // NOLINT
179
180 try
181 {
182 SetNodeMap(nodemap);
183 }
184 catch (const std::exception&)
185 {
186 delete propertyModel_;
187 throw;
188 }
189
190 // At click create editor (otherwise double click is necessary)
191 QObject::connect(this, QOverload<const QModelIndex &>::of(&PropertyGrid::clicked), [=](const QModelIndex & index)
192 {
193 // Do not call editing on items with no editor (return EmptyEditor())
194 // otherwise error message "edit: editing failed" occurs
195 auto prop = propertyModel_->Property(index);
196 if (prop)
197 {
198 if (!prop->IsReadOnly() && prop->Type() != UI::Private::Property::PT_Boolean)
199 edit(index);
200 }
201 });
202
203 // Init the update timer
204 updateTimer_ = new QTimer(this); // NOLINT(cppcoreguidelines-owning-memory)
205 QObject::connect(updateTimer_, &QTimer::timeout, [=]()
206 {
207 update();
208 });
209}
210
211
212PropertyGrid(const PropertyGrid& other) = delete;
213PropertyGrid& operator=(const PropertyGrid& other) = delete;
214PropertyGrid(PropertyGrid&& other) = delete;
215PropertyGrid& operator=(PropertyGrid&& other) = delete;
217{
218 if (propertyModel_)
219 delete propertyModel_;
220}
221
223
227void SetNodeMap(const NodeMapPtr & nodemap)
228{
229 propertyModel_->SetNodeMap(nodemap);
230
231 setModel(propertyModel_);
232 setItemDelegate(new VariantDelegate(this)); // NOLINT(cppcoreguidelines-owning-memory)
234
235 if (columnWidth(0) < maxColumnWidth_)
236 setColumnWidth(0, maxColumnWidth_);
237}
238
240
244NodeMapPtr NodeMap()
245{
246 return propertyModel_->NodeMap();
247}
248
250
254{
255 propertyModel_->RemoveNodeMap();
256 setModel(0);
257}
258
260
265{
266 propertyModel_->SetMaxVisibility(visibility);
267}
268
270
275{
276 return propertyModel_->MaxVisibility();
277}
278
280
286{
287 return HtmlDescription(index);
288}
289
291
297QModelIndexList Search(const QString & text)
298{
299 return propertyModel_->Search(text);
300}
301
303
307{
308 propertyModel_->ResetSearch();
309}
310
312
317{
318 return propertyModel_->SearchText();
319}
320
322
327{
328 propertyModel_->SetSearchResultBGColor(color);
329}
330
332
337{
338 return propertyModel_->SearchResultBGColor();
339}
340
342
347NodePtr Node(const QModelIndex & index)
348{
349 return propertyModel_->Item(index)->Node();
350}
351
353
357void ExpandSearchResult(const QModelIndexList & indexList)
358{
359 for (int i = 0; i < indexList.size(); i++)
360 ExpandProperty(indexList.at(i));
361}
362
364
368void CollapseSearchResult(const QModelIndexList & indexList)
369{
370 for (int i = 0; i < indexList.size(); i++)
371 CollapseProperty(indexList.at(i));
372}
373
375
379void UpdateProperty(const QModelIndex & index)
380{
381 propertyModel_->UpdateProperty(index);
382}
383
385
388void Update()
389{
390 propertyModel_->Update();
391}
392
394
398void StartAutoUpdate(int ms)
399{
400 updateTimer_->start(ms);
401}
402
404
408{
409 updateTimer_->stop();
410}
411
413
420{
421 propertyModel_->ResetUpdateLock();
422}
423
424private:
425
426void ExpandProperty(const QModelIndex & index) // NOLINT(misc-no-recursion)
427{
428 // Expand the node
429 setExpanded(index, true);
430 scrollTo(index);
431
432 // Get the parent node
433 auto parentIndex = propertyModel_->parent(index);
434
435 if (parentIndex != QModelIndex()) // is not root
436 ExpandProperty(parentIndex);
437}
438
439void CollapseProperty(const QModelIndex & index) // NOLINT(misc-no-recursion)
440{
441 // Collapse the node
442 setExpanded(index, false);
443
444 // Get the parent node
445 auto parentIndex = propertyModel_->parent(index);
446
447 if (parentIndex != QModelIndex()) // is not root
448 CollapseProperty(parentIndex);
449}
450
451QString HtmlDescription(const QModelIndex & index)
452{
453 auto prop = propertyModel_->Item(index);
454
455 if (!prop)
456 return QString();
457
458 auto node = prop->Node();
459
460 QString txt = "<b>" + UI::CvbToQt(node->DisplayName()) + " (" + UI::CvbToQt(node->Name()) + ")</b>";
461 if (!node->Description().empty())
462 txt.append("<br>" + UI::CvbToQt(node->Description()));
463
464 txt.append("<br><table>");
465 txt.append("<tr><td><b>Full Name:</b></td><td>" + UI::CvbToQt(node->Name()));
466
467 if (typeid(node) != typeid(CategoryNodePtr))
468 {
469 txt.append("<tr><td><b>Type:</b></td><td>" + UI::CvbToQt(prop->NodeType()) + "</td></tr>");
470 txt.append("<tr><td><b>Access Mode:</b></td><td>" + UI::CvbToQt(prop->NodeAccessMode()) + "</td></tr>");
471 txt.append("<tr><td><b>Visibility:</b></td><td>" + UI::CvbToQt(prop->NodeVisibility()) + "</td></tr>");
472 txt.append("<tr><td><b>Caching Mode:</b></td><td>" + UI::CvbToQt(prop->NodeCachingMode()) + "</td></tr>");
473 if (prop->NodeIsStreamable())
474 txt.append("<tr><td><b>Streamable:</b></td><td>True</td></tr>");
475 else
476 txt.append("<tr><td><b>Streamable:</b></td><td>False</td></tr>");
477 }
478 txt.append("</table>");
479
480 switch (prop->Type())
481 {
482 default:
483 break;
484 case UI::Private::Property::PropertyType::PT_Integer:
485 case UI::Private::Property::PropertyType::PT_Float:
486 case UI::Private::Property::PropertyType::PT_String:
487 case UI::Private::Property::PropertyType::PT_Enumeration:
488 txt.append(prop->HtmlDescription());
489 break;
490 }
491
492 return txt;
493}
494
495private:
496 static const int maxColumnWidth_ = 180;
497 UI::Private::PropertyModel* propertyModel_;
498 QTimer* updateTimer_;
499
500}; /* class PropertyGrid */
501
502
503
504} /* namespace UI */
505
506
507CVB_END_INLINE_NS
508
509} /* namespace Cvb */
510
511
View to display a device's nodemap.
Definition: property_grid.hpp:157
void StopAutoUpdate()
Stops the automatic update of the nodes.
Definition: property_grid.hpp:407
NodePtr Node(const QModelIndex &index)
The node of the given QModelIndex.
Definition: property_grid.hpp:347
void CollapseSearchResult(const QModelIndexList &indexList)
Collapses all nodes of given QModelIndexList as well as its parents.
Definition: property_grid.hpp:368
NodeMapPtr NodeMap()
Return the nodemap.
Definition: property_grid.hpp:244
GenApi::Visibility Visibility()
Returns the visibility of the nodemap.
Definition: property_grid.hpp:274
void ReleaseNodeMap()
Release the nodemap.
Definition: property_grid.hpp:253
void UpdateProperty(const QModelIndex &index)
Updates a given property / node.
Definition: property_grid.hpp:379
QString SearchText()
Returns the search text which is currently set.
Definition: property_grid.hpp:316
void SetVisibility(GenApi::Visibility visibility)
Set the visibility of the nodemap.
Definition: property_grid.hpp:264
QModelIndexList Search(const QString &text)
Search for displayed property name.
Definition: property_grid.hpp:297
QColor SearchResultBackgroundColor()
Returns the search result background color.
Definition: property_grid.hpp:336
void StartAutoUpdate(int ms)
Starts the automatic update of the nodes.
Definition: property_grid.hpp:398
void SetNodeMap(const NodeMapPtr &nodemap)
Set the nodemap and exchanges the model.
Definition: property_grid.hpp:227
void ExpandSearchResult(const QModelIndexList &indexList)
Expands all nodes of given QModelIndexList as well as its parents.
Definition: property_grid.hpp:357
QString HtmlFormattedDescription(const QModelIndex &index)
Returns an HTML formatted description of given node by QModelIndex.
Definition: property_grid.hpp:285
PropertyGrid(const NodeMapPtr &nodemap, QWidget *parent=nullptr)
Create a property grid.
Definition: property_grid.hpp:169
void SetSearchResultBackgroundColor(QColor color)
Set the search result background color.
Definition: property_grid.hpp:326
void ResetUpdateLock()
Reset the update lock.
Definition: property_grid.hpp:419
void ResetSearch()
Reset the search text.
Definition: property_grid.hpp:306
void Update()
Updates all properties / nodes.
Definition: property_grid.hpp:388
Visibility
Feature complexity level.
Definition: genapi.hpp:235
QString CvbToQt(const Cvb::String &text) noexcept
Convenience converter for strings.
Definition: ui.hpp:253
Root namespace for the Image Manager interface.
Definition: c_barcode.h:24
void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
void commitData(QWidget *editor)
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
void clicked(const QModelIndex &index)
void edit(const QModelIndex &index)
void setSelectionMode(QAbstractItemView::SelectionMode mode)
void setItemDelegate(QAbstractItemDelegate *delegate)
const QColor & color() const const
QPalette palette()
int indexOfSignal(const char *signal) const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
void drawLine(const QLineF &line)
void fillRect(const QRectF &rectangle, const QBrush &brush)
void restore()
void save()
void setPen(const QColor &color)
const QBrush & brush(QPalette::ColorGroup group, QPalette::ColorRole role) const const
QString & append(QChar ch)
virtual QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const const override
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const const override
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const const override
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const const override
void start(int msec)
void stop()
void timeout()
int columnWidth(int column) const const
void resizeColumnToContents(int column)
virtual void scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint hint) override
void setColumnWidth(int column, int width)
void setExpanded(const QModelIndex &index, bool expanded)
virtual void setModel(QAbstractItemModel *model) override
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
virtual const QMetaObject * metaObject() const const
void update()