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 
23 namespace Cvb
24 {
25 
26 CVB_BEGIN_INLINE_NS
27 
28 namespace UI
29 {
30 
31 class VariantDelegate
32  : public QStyledItemDelegate
33 {
34 
35 Q_OBJECT
36 
37 public:
38 
39 VariantDelegate(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 
49 QWidget* 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 
86 void setEditorData(QWidget * /*editor*/, const QModelIndex & /*index*/) const override
87 {
88  // Do nothing, only override setEditorData function
89 }
90 
91 void 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 
106 void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override
107 {
108  return QStyledItemDelegate::updateEditorGeometry(editor, option, index);
109 }
110 
111 void 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 
133 private:
134 
135 QSignalMapper* finishedMapper_;
136 };
137 
138 
139 
140 
142 
156  : public QTreeView
157 {
158 
159 Q_OBJECT
160 
161 public:
162 
164 
169 explicit PropertyGrid(const NodeMapPtr & nodemap, QWidget *parent = nullptr)
170  : QTreeView(parent)
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 
224 void 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 
241 NodeMapPtr 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 
294 QModelIndexList 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 
344 NodePtr Node(const QModelIndex & index)
345 {
346  return propertyModel_->Item(index)->Node();
347 }
348 
350 
354 void ExpandSearchResult(const QModelIndexList & indexList)
355 {
356  for (int i = 0; i < indexList.size(); i++)
357  ExpandProperty(indexList.at(i));
358 }
359 
361 
365 void CollapseSearchResult(const QModelIndexList & indexList)
366 {
367  for (int i = 0; i < indexList.size(); i++)
368  CollapseProperty(indexList.at(i));
369 }
370 
372 
376 void UpdateProperty(const QModelIndex & index)
377 {
378  propertyModel_->UpdateProperty(index);
379 }
380 
382 
385 void Update()
386 {
387  propertyModel_->Update();
388 }
389 
391 
395 void StartAutoUpdate(int ms)
396 {
397  updateTimer_->start(ms);
398 }
399 
401 
405 {
406  updateTimer_->stop();
407 }
408 
410 
417 {
418  propertyModel_->ResetUpdateLock();
419 }
420 
421 private:
422 
423 void 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 
436 void 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 
448 QString 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 
489 private:
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 
501 CVB_END_INLINE_NS
502 
503 } /* namespace Cvb */
504 
505 
int indexOfSignal(const char *signal) const const
QString & append(QChar ch)
void fillRect(const QRectF &rectangle, const QBrush &brush)
void setSelectionMode(QAbstractItemView::SelectionMode mode)
void StartAutoUpdate(int ms)
Starts the automatic update of the nodes.
Definition: property_grid.hpp:395
void ResetUpdateLock()
Reset the update lock.
Definition: property_grid.hpp:416
void StopAutoUpdate()
Stops the automatic update of the nodes.
Definition: property_grid.hpp:404
void save()
virtual const QMetaObject * metaObject() const const
void Update()
Updates all properties / nodes.
Definition: property_grid.hpp:385
void drawLine(const QLineF &line)
void update()
void ReleaseNodeMap()
Release the nodemap.
Definition: property_grid.hpp:250
QString SearchText()
Returns the search text which is currently set.
Definition: property_grid.hpp:313
QColor SearchResultBackgroundColor()
Returns the search result background color.
Definition: property_grid.hpp:333
NodeMapPtr NodeMap()
Return the nodemap.
Definition: property_grid.hpp:241
const QColor & color() const const
void setExpanded(const QModelIndex &index, bool expanded)
void timeout()
int columnWidth(int column) const const
void UpdateProperty(const QModelIndex &index)
Updates a given property / node.
Definition: property_grid.hpp:376
void setColumnWidth(int column, int width)
Root namespace for the Image Manager interface.
Definition: version.hpp:11
const QBrush & brush(QPalette::ColorGroup group, QPalette::ColorRole role) const const
void resizeColumnToContents(int column)
void setPen(const QColor &color)
QPalette palette()
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const const override
virtual QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const const override
void setItemDelegate(QAbstractItemDelegate *delegate)
View to display a device's nodemap.
Definition: property_grid.hpp:155
void * internalPointer() const const
void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
virtual QVariant data(const QModelIndex &index, int role) const const=0
Visibility
Feature complexity level.
Definition: genapi.hpp:234
QString CvbToQt(const Cvb::String &text) noexcept
Convenience converter for strings.
Definition: ui.hpp:254
void ResetSearch()
Reset the search text.
Definition: property_grid.hpp:303
QModelIndexList Search(const QString &text)
Search for displayed property name.
Definition: property_grid.hpp:294
STL class.
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
virtual void scrollTo(const QModelIndex &index, QAbstractItemView::ScrollHint hint) override
void stop()
void restore()
PropertyGrid(const NodeMapPtr &nodemap, QWidget *parent=nullptr)
Create a property grid.
Definition: property_grid.hpp:169
void ExpandSearchResult(const QModelIndexList &indexList)
Expands all nodes of given QModelIndexList as well as its parents.
Definition: property_grid.hpp:354
const QAbstractItemModel * model() const const
virtual void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const const override
NodePtr Node(const QModelIndex &index)
The node of the given QModelIndex.
Definition: property_grid.hpp:344
virtual void setModel(QAbstractItemModel *model) override
virtual void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const const override
int column() const const
virtual bool setData(const QModelIndex &index, const QVariant &value, int role)
void CollapseSearchResult(const QModelIndexList &indexList)
Collapses all nodes of given QModelIndexList as well as its parents.
Definition: property_grid.hpp:365
void edit(const QModelIndex &index)
void start(int msec)
void clicked(const QModelIndex &index)
void commitData(QWidget *editor)
void SetSearchResultBackgroundColor(QColor color)
Set the search result background color.
Definition: property_grid.hpp:323
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
QString HtmlFormattedDescription(const QModelIndex &index)
Returns an HTML formatted description of given node by QModelIndex.
Definition: property_grid.hpp:282
~PropertyGrid()
Destructor of property grid.
Definition: property_grid.hpp:213
GenApi::Visibility Visibility()
Returns the visibility of the nodemap.
Definition: property_grid.hpp:271
void SetNodeMap(const NodeMapPtr &nodemap)
Set the nodemap and exchanges the model.
Definition: property_grid.hpp:224
void SetVisibility(GenApi::Visibility visibility)
Set the visibility of the nodemap.
Definition: property_grid.hpp:261