CVB++ 14.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
39VariantDelegate(QObject* parent = 0)
41{
42 finishedMapper_ = new QSignalMapper(this);
43 QObject::connect(finishedMapper_, SIGNAL(mapped(QWidget*)), this, SIGNAL(commitData(QWidget*)));
44 QObject::connect(finishedMapper_, SIGNAL(mapped(QWidget*)), this, SIGNAL(closeEditor(QWidget*)));
45}
46
47~VariantDelegate() = default;
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{
172 // Allow only single selection and remove editor after focus change
173 setSelectionMode(QAbstractItemView::SingleSelection);
174 setContextMenuPolicy(Qt::CustomContextMenu);
175
176 propertyModel_ = new UI::Private::PropertyModel();
177
178 try
179 {
180 SetNodeMap(nodemap);
181 }
182 catch (const std::exception&)
183 {
184 delete propertyModel_;
185 throw;
186 }
187
188 // At click create editor (otherwise double click is necessary)
189 QObject::connect(this, QOverload<const QModelIndex &>::of(&PropertyGrid::clicked), [=](const QModelIndex & index)
190 {
191 // Do not call editing on items with no editor (return EmptyEditor())
192 // otherwise error message "edit: editing failed" occurs
193 auto prop = propertyModel_->Property(index);
194 if (prop)
195 {
196 if (!prop->IsReadOnly() && prop->Type() != UI::Private::Property::PT_Boolean)
197 edit(index);
198 }
199 });
200
201 // Init the update timer
202 updateTimer_ = new QTimer(this);
203 QObject::connect(updateTimer_, &QTimer::timeout, [=]()
204 {
205 update();
206 });
207}
208
210
214{
215 if (propertyModel_)
216 delete propertyModel_;
217}
218
220
224void SetNodeMap(const NodeMapPtr & nodemap)
225{
226 propertyModel_->SetNodeMap(nodemap);
227
228 setModel(propertyModel_);
229 setItemDelegate(new VariantDelegate(this));
231
232 if (columnWidth(0) < maxColumnWidth_)
233 setColumnWidth(0, maxColumnWidth_);
234}
235
237
241NodeMapPtr NodeMap()
242{
243 return propertyModel_->NodeMap();
244}
245
247
251{
252 propertyModel_->RemoveNodeMap();
253 setModel(0);
254}
255
257
262{
263 propertyModel_->SetMaxVisibility(visibility);
264}
265
267
272{
273 return propertyModel_->MaxVisibility();
274}
275
277
283{
284 return HtmlDescription(index);
285}
286
288
294QModelIndexList Search(const QString & text)
295{
296 return propertyModel_->Search(text);
297}
298
300
304{
305 propertyModel_->ResetSearch();
306}
307
309
314{
315 return propertyModel_->SearchText();
316}
317
319
324{
325 propertyModel_->SetSearchResultBGColor(color);
326}
327
329
334{
335 return propertyModel_->SearchResultBGColor();
336}
337
339
344NodePtr Node(const QModelIndex & index)
345{
346 return propertyModel_->Item(index)->Node();
347}
348
350
354void ExpandSearchResult(const QModelIndexList & indexList)
355{
356 for (int i = 0; i < indexList.size(); i++)
357 ExpandProperty(indexList.at(i));
358}
359
361
365void CollapseSearchResult(const QModelIndexList & indexList)
366{
367 for (int i = 0; i < indexList.size(); i++)
368 CollapseProperty(indexList.at(i));
369}
370
372
376void UpdateProperty(const QModelIndex & index)
377{
378 propertyModel_->UpdateProperty(index);
379}
380
382
385void Update()
386{
387 propertyModel_->Update();
388}
389
391
395void StartAutoUpdate(int ms)
396{
397 updateTimer_->start(ms);
398}
399
401
405{
406 updateTimer_->stop();
407}
408
410
417{
418 propertyModel_->ResetUpdateLock();
419}
420
421private:
422
423void ExpandProperty(const QModelIndex & index)
424{
425 // Expand the node
426 setExpanded(index, true);
427 scrollTo(index);
428
429 // Get the parent node
430 auto parentIndex = propertyModel_->parent(index);
431
432 if (parentIndex != QModelIndex()) // is not root
433 ExpandProperty(parentIndex);
434}
435
436void CollapseProperty(const QModelIndex & index)
437{
438 // Collapse the node
439 setExpanded(index, false);
440
441 // Get the parent node
442 auto parentIndex = propertyModel_->parent(index);
443
444 if (parentIndex != QModelIndex()) // is not root
445 CollapseProperty(parentIndex);
446}
447
448QString HtmlDescription(const QModelIndex & index)
449{
450 auto prop = propertyModel_->Item(index);
451
452 if (!prop)
453 return QString();
454
455 auto node = prop->Node();
456
457 QString txt = "<b>" + UI::CvbToQt(node->DisplayName()) + " (" + UI::CvbToQt(node->Name()) + ")</b>";
458 if (!node->Description().empty())
459 txt.append("<br>" + UI::CvbToQt(node->Description()));
460
461 txt.append("<br><table>");
462 txt.append("<tr><td><b>Full Name:</b></td><td>" + UI::CvbToQt(node->Name()));
463
464 if (typeid(*node) != typeid(CategoryNode))
465 {
466 txt.append("<tr><td><b>Type:</b></td><td>" + UI::CvbToQt(prop->NodeType()) + "</td></tr>");
467 txt.append("<tr><td><b>Access Mode:</b></td><td>" + UI::CvbToQt(prop->NodeAccessMode()) + "</td></tr>");
468 txt.append("<tr><td><b>Visibility:</b></td><td>" + UI::CvbToQt(prop->NodeVisibility()) + "</td></tr>");
469 txt.append("<tr><td><b>Caching Mode:</b></td><td>" + UI::CvbToQt(prop->NodeCachingMode()) + "</td></tr>");
470 if (prop->NodeIsStreamable())
471 txt.append("<tr><td><b>Streamable:</b></td><td>True</td></tr>");
472 else
473 txt.append("<tr><td><b>Streamable:</b></td><td>False</td></tr>");
474 }
475 txt.append("</table>");
476
477 switch (prop->Type())
478 {
479 case UI::Private::Property::PropertyType::PT_Integer:
480 case UI::Private::Property::PropertyType::PT_Float:
481 case UI::Private::Property::PropertyType::PT_String:
482 case UI::Private::Property::PropertyType::PT_Enumeration:
483 txt.append(prop->HtmlDescription());
484 }
485
486 return txt;
487}
488
489private:
490 static const int maxColumnWidth_ = 180;
491 UI::Private::PropertyModel* propertyModel_;
492 QTimer* updateTimer_;
493
494}; /* class PropertyGrid */
495
496
497
498} /* namespace UI */
499
500
501CVB_END_INLINE_NS
502
503} /* namespace Cvb */
504
505
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:404
NodePtr Node(const QModelIndex &index)
The node of the given QModelIndex.
Definition: property_grid.hpp:344
void CollapseSearchResult(const QModelIndexList &indexList)
Collapses all nodes of given QModelIndexList as well as its parents.
Definition: property_grid.hpp:365
NodeMapPtr NodeMap()
Return the nodemap.
Definition: property_grid.hpp:241
GenApi::Visibility Visibility()
Returns the visibility of the nodemap.
Definition: property_grid.hpp:271
void ReleaseNodeMap()
Release the nodemap.
Definition: property_grid.hpp:250
void UpdateProperty(const QModelIndex &index)
Updates a given property / node.
Definition: property_grid.hpp:376
QString SearchText()
Returns the search text which is currently set.
Definition: property_grid.hpp:313
void SetVisibility(GenApi::Visibility visibility)
Set the visibility of the nodemap.
Definition: property_grid.hpp:261
QModelIndexList Search(const QString &text)
Search for displayed property name.
Definition: property_grid.hpp:294
QColor SearchResultBackgroundColor()
Returns the search result background color.
Definition: property_grid.hpp:333
void StartAutoUpdate(int ms)
Starts the automatic update of the nodes.
Definition: property_grid.hpp:395
void SetNodeMap(const NodeMapPtr &nodemap)
Set the nodemap and exchanges the model.
Definition: property_grid.hpp:224
void ExpandSearchResult(const QModelIndexList &indexList)
Expands all nodes of given QModelIndexList as well as its parents.
Definition: property_grid.hpp:354
QString HtmlFormattedDescription(const QModelIndex &index)
Returns an HTML formatted description of given node by QModelIndex.
Definition: property_grid.hpp:282
PropertyGrid(const NodeMapPtr &nodemap, QWidget *parent=nullptr)
Create a property grid.
Definition: property_grid.hpp:169
~PropertyGrid()
Destructor of property grid.
Definition: property_grid.hpp:213
void SetSearchResultBackgroundColor(QColor color)
Set the search result background color.
Definition: property_grid.hpp:323
void ResetUpdateLock()
Reset the update lock.
Definition: property_grid.hpp:416
void ResetSearch()
Reset the search text.
Definition: property_grid.hpp:303
void Update()
Updates all properties / nodes.
Definition: property_grid.hpp:385
Visibility
Feature complexity level.
Definition: genapi.hpp:235
QString CvbToQt(const Cvb::String &text) noexcept
Convenience converter for strings.
Definition: ui.hpp:254
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()