Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qttreepropertybrowser.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
7
8#include <QtWidgets/qapplication.h>
9#include <QtWidgets/qboxlayout.h>
10#include <QtWidgets/qheaderview.h>
11#include <QtWidgets/qstyle.h>
12#include <QtWidgets/qstyleditemdelegate.h>
13#include <QtWidgets/qtreewidget.h>
14
15#include <QtGui/qevent.h>
16#include <QtGui/qicon.h>
17#include <QtGui/qpainter.h>
18#include <QtGui/qpalette.h>
19#include <QtGui/qstylehints.h>
20
21#include <QtCore/qhash.h>
22#include <QtCore/qoperatingsystemversion.h>
23
25
26using namespace Qt::StringLiterals;
27
28static constexpr bool isWindows = QOperatingSystemVersion::currentType() == QOperatingSystemVersion::Windows;
29
30static inline bool isLightTheme()
31{
32 return QGuiApplication::styleHints()->colorScheme() != Qt::ColorScheme::Dark;
33}
34
36
38{
39 QtTreePropertyBrowser *q_ptr = nullptr;
40 Q_DECLARE_PUBLIC(QtTreePropertyBrowser)
41
42public:
44
45 void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex);
48 QWidget *createEditor(QtProperty *property, QWidget *parent) const
49 { return q_ptr->createEditor(property, parent); }
50 QtProperty *indexToProperty(const QModelIndex &index) const;
51 QTreeWidgetItem *indexToItem(const QModelIndex &index) const;
52 QtBrowserItem *indexToBrowserItem(const QModelIndex &index) const;
53 bool lastColumn(int column) const;
54 void disableItem(QTreeWidgetItem *item) const;
55 void enableItem(QTreeWidgetItem *item) const;
56 bool hasValue(QTreeWidgetItem *item) const;
57
58 void slotCollapsed(const QModelIndex &index);
59 void slotExpanded(const QModelIndex &index);
60
62
63 QtPropertyEditorView *treeWidget() const { return m_treeWidget; }
64 bool markPropertiesWithoutValue() const { return m_markPropertiesWithoutValue; }
65
67 void setCurrentItem(QtBrowserItem *browserItem, bool block);
68 void editItem(QtBrowserItem *browserItem);
69
71 void slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *);
72
73 QTreeWidgetItem *editedItem() const;
74
75private:
76 void updateItem(QTreeWidgetItem *item);
77
78 QHash<QtBrowserItem *, QTreeWidgetItem *> m_indexToItem;
79 QHash<QTreeWidgetItem *, QtBrowserItem *> m_itemToIndex;
80
81 QHash<QtBrowserItem *, QColor> m_indexToBackgroundColor;
82
83 QtPropertyEditorView *m_treeWidget = nullptr;
84
85 bool m_headerVisible = true;
86 QtTreePropertyBrowser::ResizeMode m_resizeMode = QtTreePropertyBrowser::Stretch;
87 class QtPropertyEditorDelegate *m_delegate = nullptr;
88 bool m_markPropertiesWithoutValue = false;
89 bool m_browserChangedBlocked = false;
90 QIcon m_expandIcon;
91};
92
93// ------------ QtPropertyEditorView
95{
97public:
99
101 { m_editorPrivate = editorPrivate; }
102
103 QTreeWidgetItem *indexToItem(const QModelIndex &index) const
104 { return itemFromIndex(index); }
105
106protected:
107 void keyPressEvent(QKeyEvent *event) override;
108 void mousePressEvent(QMouseEvent *event) override;
109 void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
110
111private:
112 QtTreePropertyBrowserPrivate *m_editorPrivate = nullptr;
113};
114
115QtPropertyEditorView::QtPropertyEditorView(QWidget *parent) :
116 QTreeWidget(parent)
117{
118 connect(header(), &QHeaderView::sectionDoubleClicked, this, &QTreeView::resizeColumnToContents);
119}
120
121void QtPropertyEditorView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
122{
123 QStyleOptionViewItem opt = option;
124 bool hasValue = true;
125 if (m_editorPrivate) {
126 QtProperty *property = m_editorPrivate->indexToProperty(index);
127 if (property)
128 hasValue = property->hasValue();
129 }
130 if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) {
131 const QColor c = option.palette.color(QPalette::Dark);
132 painter->fillRect(option.rect, c);
133 opt.palette.setColor(QPalette::AlternateBase, c);
134 } else {
135 const QColor c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index));
136 if (c.isValid()) {
137 painter->fillRect(option.rect, c);
138 opt.palette.setColor(QPalette::AlternateBase, c.lighter(112));
139 }
140 }
141 QTreeWidget::drawRow(painter, opt, index);
142 QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
143 painter->save();
144 painter->setPen(QPen(color));
145 painter->drawLine(opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
146 painter->restore();
147}
148
149void QtPropertyEditorView::keyPressEvent(QKeyEvent *event)
150{
151 switch (event->key()) {
152 case Qt::Key_Return:
153 case Qt::Key_Enter:
154 case Qt::Key_Space: // Trigger Edit
155 if (!m_editorPrivate->editedItem())
156 if (const QTreeWidgetItem *item = currentItem())
157 if (item->columnCount() >= 2 && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) {
158 event->accept();
159 // If the current position is at column 0, move to 1.
160 QModelIndex index = currentIndex();
161 if (index.column() == 0) {
162 index = index.sibling(index.row(), 1);
163 setCurrentIndex(index);
164 }
165 edit(index);
166 return;
167 }
168 break;
169 default:
170 break;
171 }
172 QTreeWidget::keyPressEvent(event);
173}
174
175void QtPropertyEditorView::mousePressEvent(QMouseEvent *event)
176{
177 QTreeWidget::mousePressEvent(event);
178 QTreeWidgetItem *item = itemAt(event->position().toPoint());
179
180 if (item) {
181 if ((item != m_editorPrivate->editedItem()) && (event->button() == Qt::LeftButton)
182 && (header()->logicalIndexAt(event->position().toPoint().x()) == 1)
183 && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) {
184 editItem(item, 1);
185 } else if (!m_editorPrivate->hasValue(item) && m_editorPrivate->markPropertiesWithoutValue() && !rootIsDecorated()) {
186 if (event->position().toPoint().x() + header()->offset() < 20)
187 item->setExpanded(!item->isExpanded());
188 }
189 }
190}
191
192// ------------ QtPropertyEditorDelegate
194{
196public:
198
200 { m_editorPrivate = editorPrivate; }
201
202 QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
203 const QModelIndex &index) const override;
204
205 void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
206 const QModelIndex &index) const override;
207
208 void paint(QPainter *painter, const QStyleOptionViewItem &option,
209 const QModelIndex &index) const override;
210
211 QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
212
213 void setModelData(QWidget *, QAbstractItemModel *,
214 const QModelIndex &) const override {}
215
216 void setEditorData(QWidget *, const QModelIndex &) const override {}
217
218 void closeEditor(QtProperty *property);
219
220 QTreeWidgetItem *editedItem() const { return m_editedItem; }
221
222private slots:
224
225private:
226 QtTreePropertyBrowserPrivate *m_editorPrivate = nullptr;
227 mutable QTreeWidgetItem *m_editedItem = nullptr;
228 mutable QWidget *m_editedWidget = nullptr;
229 mutable QtProperty *m_editedProperty = nullptr;
230};
231
232void QtPropertyEditorDelegate::slotEditorDestroyed(QObject *object)
233{
234 if (m_editedWidget == object) {
235 m_editedWidget = nullptr;
236 m_editedItem = nullptr;
237 m_editedProperty = nullptr;
238 }
239}
240
242{
243 if (property == m_editedProperty)
244 m_editedWidget->deleteLater();
245}
246
248 const QStyleOptionViewItem &, const QModelIndex &index) const
249{
250 if (index.column() == 1 && m_editorPrivate) {
251 QtProperty *property = m_editorPrivate->indexToProperty(index);
252 QTreeWidgetItem *item = m_editorPrivate->indexToItem(index);
253 if (property && item && (item->flags() & Qt::ItemIsEnabled)) {
254 QWidget *editor = m_editorPrivate->createEditor(property, parent);
255 if (editor) {
256 editor->setAutoFillBackground(true);
257 if (editor->palette().color(editor->backgroundRole()) == Qt::transparent)
258 editor->setBackgroundRole(QPalette::Window);
259 connect(editor, &QObject::destroyed,
260 this, &QtPropertyEditorDelegate::slotEditorDestroyed);
261 m_editedProperty = property;
262 m_editedItem = item;
263 m_editedWidget = editor;
264 }
265 return editor;
266 }
267 }
268 return nullptr;
269}
270
271// Span the entire area, hiding the value icon to ensure no icon
272// is displayed when for example editing using a check box
274 const QStyleOptionViewItem &option, const QModelIndex &index) const
275{
276 Q_UNUSED(index);
277 editor->setGeometry(option.rect.adjusted(0, 0, 0, -1));
278}
279
280void QtPropertyEditorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
281 const QModelIndex &index) const
282{
283 bool hasValue = true;
284 if (m_editorPrivate) {
285 QtProperty *property = m_editorPrivate->indexToProperty(index);
286 if (property)
287 hasValue = property->hasValue();
288 }
289 QStyleOptionViewItem opt = option;
290 if ((m_editorPrivate && index.column() == 0) || !hasValue) {
291 QtProperty *property = m_editorPrivate->indexToProperty(index);
292 if (property && property->isModified()) {
293 opt.font.setBold(true);
294 opt.fontMetrics = QFontMetrics(opt.font);
295 }
296 }
297 QColor c;
298 if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) {
299 c = opt.palette.color(QPalette::Dark);
300 // Hardcode "white" for Windows/light which is otherwise blue
301 const QColor textColor = isWindows && isLightTheme()
302 ? QColor(Qt::white) : opt.palette.color(QPalette::BrightText);
303 opt.palette.setColor(QPalette::Text, textColor);
304 } else {
305 c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index));
306 if (c.isValid() && (opt.features & QStyleOptionViewItem::Alternate))
307 c = c.lighter(112);
308 }
309 if (c.isValid())
310 painter->fillRect(option.rect, c);
311 opt.state &= ~QStyle::State_HasFocus;
312 QStyledItemDelegate::paint(painter, opt, index);
313
314 opt.palette.setCurrentColorGroup(QPalette::Active);
315 QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
316 painter->save();
317 painter->setPen(QPen(color));
318 if (!m_editorPrivate || (!m_editorPrivate->lastColumn(index.column()) && hasValue)) {
319 int right = (option.direction == Qt::LeftToRight) ? option.rect.right() : option.rect.left();
320 painter->drawLine(right, option.rect.y(), right, option.rect.bottom());
321 }
322 painter->restore();
323}
324
325QSize QtPropertyEditorDelegate::sizeHint(const QStyleOptionViewItem &option,
326 const QModelIndex &index) const
327{
328 return QStyledItemDelegate::sizeHint(option, index) + QSize(3, 4);
329}
330
331// -------- QtTreePropertyBrowserPrivate implementation
332
333// Draw an icon indicating opened/closing branches
334static QIcon drawIndicatorIcon(const QPalette &palette, QStyle *style)
335{
336 QPixmap pix(14, 14);
337 pix.fill(Qt::transparent);
338 QStyleOption branchOption;
339 branchOption.rect = QRect(2, 2, 9, 9); // ### hardcoded in qcommonstyle.cpp
340 branchOption.palette = palette;
341 branchOption.state = QStyle::State_Children;
342
343 QPainter p;
344 // Draw closed state
345 p.begin(&pix);
346 style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
347 p.end();
348 QIcon rc = pix;
349 rc.addPixmap(pix, QIcon::Selected, QIcon::Off);
350 // Draw opened state
351 branchOption.state |= QStyle::State_Open;
352 pix.fill(Qt::transparent);
353 p.begin(&pix);
354 style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
355 p.end();
356
357 rc.addPixmap(pix, QIcon::Normal, QIcon::On);
358 rc.addPixmap(pix, QIcon::Selected, QIcon::On);
359 return rc;
360}
361
362void QtTreePropertyBrowserPrivate::init(QWidget *parent)
363{
364 auto *layout = new QHBoxLayout(parent);
365 layout->setContentsMargins(QMargins());
366 m_treeWidget = new QtPropertyEditorView(parent);
367 m_treeWidget->setEditorPrivate(this);
368 m_treeWidget->setIconSize(QtPropertyBrowserUtils::itemViewIconSize);
369 layout->addWidget(m_treeWidget);
370
371 m_treeWidget->setColumnCount(2);
372 QStringList labels;
373 labels.append(QCoreApplication::translate("QtTreePropertyBrowser", "Property"));
374 labels.append(QCoreApplication::translate("QtTreePropertyBrowser", "Value"));
375 m_treeWidget->setHeaderLabels(labels);
376 m_treeWidget->setAlternatingRowColors(true);
377 m_treeWidget->setEditTriggers(QAbstractItemView::EditKeyPressed);
378 m_delegate = new QtPropertyEditorDelegate(parent);
379 m_delegate->setEditorPrivate(this);
380 m_treeWidget->setItemDelegate(m_delegate);
381 m_treeWidget->header()->setSectionsMovable(false);
382 m_treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch);
383
384 m_expandIcon = drawIndicatorIcon(q_ptr->palette(), q_ptr->style());
385
386 QObject::connect(m_treeWidget, &QTreeView::collapsed,
387 q_ptr, [this](const QModelIndex &index) { slotCollapsed(index); });
388 QObject::connect(m_treeWidget, &QTreeView::expanded,
389 q_ptr, [this](const QModelIndex &index) { slotExpanded(index); });
390 QObject::connect(m_treeWidget, &QTreeWidget::currentItemChanged,
391 q_ptr, [this](QTreeWidgetItem *current, QTreeWidgetItem *previous)
392 { slotCurrentTreeItemChanged(current, previous); });
393}
394
396{
397 if (QTreeWidgetItem *treeItem = m_treeWidget->currentItem())
398 return m_itemToIndex.value(treeItem);
399 return nullptr;
400}
401
403{
404 const bool blocked = block ? m_treeWidget->blockSignals(true) : false;
405 if (browserItem == nullptr)
406 m_treeWidget->setCurrentItem(nullptr);
407 else
408 m_treeWidget->setCurrentItem(m_indexToItem.value(browserItem));
409 if (block)
410 m_treeWidget->blockSignals(blocked);
411}
412
414{
415 QTreeWidgetItem *item = m_treeWidget->indexToItem(index);
416 QtBrowserItem *idx = m_itemToIndex.value(item);
417 if (idx)
418 return idx->property();
419 return nullptr;
420}
421
423{
424 QTreeWidgetItem *item = m_treeWidget->indexToItem(index);
425 return m_itemToIndex.value(item);
426}
427
428QTreeWidgetItem *QtTreePropertyBrowserPrivate::indexToItem(const QModelIndex &index) const
429{
430 return m_treeWidget->indexToItem(index);
431}
432
434{
435 return m_treeWidget->header()->visualIndex(column) == m_treeWidget->columnCount() - 1;
436}
437
438void QtTreePropertyBrowserPrivate::disableItem(QTreeWidgetItem *item) const
439{
440 Qt::ItemFlags flags = item->flags();
441 if (flags & Qt::ItemIsEnabled) {
442 flags &= ~Qt::ItemIsEnabled;
443 item->setFlags(flags);
444 m_delegate->closeEditor(m_itemToIndex[item]->property());
445 const int childCount = item->childCount();
446 for (int i = 0; i < childCount; i++) {
447 QTreeWidgetItem *child = item->child(i);
448 disableItem(child);
449 }
450 }
451}
452
453void QtTreePropertyBrowserPrivate::enableItem(QTreeWidgetItem *item) const
454{
455 Qt::ItemFlags flags = item->flags();
456 flags |= Qt::ItemIsEnabled;
457 item->setFlags(flags);
458 const int childCount = item->childCount();
459 for (int i = 0; i < childCount; i++) {
460 QTreeWidgetItem *child = item->child(i);
461 QtProperty *property = m_itemToIndex[child]->property();
462 if (property->isEnabled()) {
463 enableItem(child);
464 }
465 }
466}
467
468bool QtTreePropertyBrowserPrivate::hasValue(QTreeWidgetItem *item) const
469{
470 QtBrowserItem *browserItem = m_itemToIndex.value(item);
471 if (browserItem)
472 return browserItem->property()->hasValue();
473 return false;
474}
475
477{
478 QTreeWidgetItem *afterItem = m_indexToItem.value(afterIndex);
479 QTreeWidgetItem *parentItem = m_indexToItem.value(index->parent());
480
481 QTreeWidgetItem *newItem = nullptr;
482 if (parentItem) {
483 newItem = new QTreeWidgetItem(parentItem, afterItem);
484 } else {
485 newItem = new QTreeWidgetItem(m_treeWidget, afterItem);
486 }
487 m_itemToIndex[newItem] = index;
488 m_indexToItem[index] = newItem;
489
490 newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
491 newItem->setExpanded(true);
492
493 updateItem(newItem);
494}
495
497{
498 QTreeWidgetItem *item = m_indexToItem.value(index);
499
500 if (m_treeWidget->currentItem() == item) {
501 m_treeWidget->setCurrentItem(nullptr);
502 }
503
504 delete item;
505
506 m_indexToItem.remove(index);
507 m_itemToIndex.remove(item);
508 m_indexToBackgroundColor.remove(index);
509}
510
512{
513 QTreeWidgetItem *item = m_indexToItem.value(index);
514
515 updateItem(item);
516}
517
518void QtTreePropertyBrowserPrivate::updateItem(QTreeWidgetItem *item)
519{
520 QtProperty *property = m_itemToIndex[item]->property();
521 QIcon expandIcon;
522 if (property->hasValue()) {
523 const QString valueToolTip = property->valueToolTip();
524 const QString valueText = property->valueText();
525 item->setToolTip(1, valueToolTip.isEmpty() ? valueText : valueToolTip);
526 item->setIcon(1, property->valueIcon());
527 item->setText(1, valueText);
528 } else if (markPropertiesWithoutValue() && !m_treeWidget->rootIsDecorated()) {
529 expandIcon = m_expandIcon;
530 }
531 item->setIcon(0, expandIcon);
532 item->setFirstColumnSpanned(!property->hasValue());
533 const QString descriptionToolTip = property->descriptionToolTip();
534 const QString propertyName = property->propertyName();
535 item->setToolTip(0, descriptionToolTip.isEmpty() ? propertyName : descriptionToolTip);
536 item->setStatusTip(0, property->statusTip());
537 item->setWhatsThis(0, property->whatsThis());
538 item->setText(0, propertyName);
539 bool wasEnabled = item->flags() & Qt::ItemIsEnabled;
540 bool isEnabled = wasEnabled;
541 if (property->isEnabled()) {
542 QTreeWidgetItem *parent = item->parent();
543 isEnabled = !parent || (parent->flags() & Qt::ItemIsEnabled);
544 } else {
545 isEnabled = false;
546 }
547 if (wasEnabled != isEnabled) {
548 if (isEnabled)
549 enableItem(item);
550 else
551 disableItem(item);
552 }
553 m_treeWidget->viewport()->update();
554}
555
557{
558 QtBrowserItem *i = item;
559 const auto itEnd = m_indexToBackgroundColor.constEnd();
560 while (i) {
561 auto it = m_indexToBackgroundColor.constFind(i);
562 if (it != itEnd)
563 return it.value();
564 i = i->parent();
565 }
566 return {};
567}
568
569void QtTreePropertyBrowserPrivate::slotCollapsed(const QModelIndex &index)
570{
571 QTreeWidgetItem *item = indexToItem(index);
572 QtBrowserItem *idx = m_itemToIndex.value(item);
573 if (item)
574 emit q_ptr->collapsed(idx);
575}
576
577void QtTreePropertyBrowserPrivate::slotExpanded(const QModelIndex &index)
578{
579 QTreeWidgetItem *item = indexToItem(index);
580 QtBrowserItem *idx = m_itemToIndex.value(item);
581 if (item)
582 emit q_ptr->expanded(idx);
583}
584
586{
587 if (!m_browserChangedBlocked && item != currentItem())
588 setCurrentItem(item, true);
589}
590
591void QtTreePropertyBrowserPrivate::slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *)
592{
593 QtBrowserItem *browserItem = newItem ? m_itemToIndex.value(newItem) : 0;
594 m_browserChangedBlocked = true;
595 q_ptr->setCurrentItem(browserItem);
596 m_browserChangedBlocked = false;
597}
598
600{
601 return m_delegate->editedItem();
602}
603
605{
606 if (QTreeWidgetItem *treeItem = m_indexToItem.value(browserItem, nullptr)) {
607 m_treeWidget->setCurrentItem (treeItem, 1);
608 m_treeWidget->editItem(treeItem, 1);
609 }
610}
611
612/*!
613 \class QtTreePropertyBrowser
614 \internal
615 \inmodule QtDesigner
616 \since 4.4
617
618 \brief The QtTreePropertyBrowser class provides QTreeWidget based
619 property browser.
620
621 A property browser is a widget that enables the user to edit a
622 given set of properties. Each property is represented by a label
623 specifying the property's name, and an editing widget (e.g. a line
624 edit or a combobox) holding its value. A property can have zero or
625 more subproperties.
626
627 QtTreePropertyBrowser provides a tree based view for all nested
628 properties, i.e. properties that have subproperties can be in an
629 expanded (subproperties are visible) or collapsed (subproperties
630 are hidden) state. For example:
631
632 \image qttreepropertybrowser.png
633
634 Use the QtAbstractPropertyBrowser API to add, insert and remove
635 properties from an instance of the QtTreePropertyBrowser class.
636 The properties themselves are created and managed by
637 implementations of the QtAbstractPropertyManager class.
638
639 \sa QtGroupBoxPropertyBrowser, QtAbstractPropertyBrowser
640*/
641
642/*!
643 \fn void QtTreePropertyBrowser::collapsed(QtBrowserItem *item)
644
645 This signal is emitted when the \a item is collapsed.
646
647 \sa expanded(), setExpanded()
648*/
649
650/*!
651 \fn void QtTreePropertyBrowser::expanded(QtBrowserItem *item)
652
653 This signal is emitted when the \a item is expanded.
654
655 \sa collapsed(), setExpanded()
656*/
657
658/*!
659 Creates a property browser with the given \a parent.
660*/
661QtTreePropertyBrowser::QtTreePropertyBrowser(QWidget *parent)
662 : QtAbstractPropertyBrowser(parent), d_ptr(new QtTreePropertyBrowserPrivate)
663{
664 d_ptr->q_ptr = this;
665
666 d_ptr->init(this);
667 QObject::connect(this, &QtAbstractPropertyBrowser::currentItemChanged,
668 this, [this](QtBrowserItem *current)
669 { d_ptr->slotCurrentBrowserItemChanged(current); });
670}
671
672/*!
673 Destroys this property browser.
674
675 Note that the properties that were inserted into this browser are
676 \e not destroyed since they may still be used in other
677 browsers. The properties are owned by the manager that created
678 them.
679
680 \sa QtProperty, QtAbstractPropertyManager
681*/
683
684/*!
685 \property QtTreePropertyBrowser::indentation
686 \brief indentation of the items in the tree view.
687*/
689{
690 return d_ptr->m_treeWidget->indentation();
691}
692
694{
695 d_ptr->m_treeWidget->setIndentation(i);
696}
697
698/*!
699 \property QtTreePropertyBrowser::rootIsDecorated
700 \brief whether to show controls for expanding and collapsing root items.
701*/
703{
704 return d_ptr->m_treeWidget->rootIsDecorated();
705}
706
708{
709 d_ptr->m_treeWidget->setRootIsDecorated(show);
710 for (auto it = d_ptr->m_itemToIndex.cbegin(), end = d_ptr->m_itemToIndex.cend(); it != end; ++it) {
711 QtProperty *property = it.value()->property();
712 if (!property->hasValue())
713 d_ptr->updateItem(it.key());
714 }
715}
716
717/*!
718 \property QtTreePropertyBrowser::alternatingRowColors
719 \brief whether to draw the background using alternating colors.
720 By default this property is set to true.
721*/
723{
724 return d_ptr->m_treeWidget->alternatingRowColors();
725}
726
728{
729 d_ptr->m_treeWidget->setAlternatingRowColors(enable);
730}
731
732/*!
733 \property QtTreePropertyBrowser::headerVisible
734 \brief whether to show the header.
735*/
737{
738 return d_ptr->m_headerVisible;
739}
740
742{
743 if (d_ptr->m_headerVisible == visible)
744 return;
745
746 d_ptr->m_headerVisible = visible;
747 d_ptr->m_treeWidget->header()->setVisible(visible);
748}
749
750/*!
751 \enum QtTreePropertyBrowser::ResizeMode
752
753 The resize mode specifies the behavior of the header sections.
754
755 \value Interactive The user can resize the sections.
756 The sections can also be resized programmatically using setSplitterPosition().
757
758 \value Fixed The user cannot resize the section.
759 The section can only be resized programmatically using setSplitterPosition().
760
761 \value Stretch QHeaderView will automatically resize the section to fill the available space.
762 The size cannot be changed by the user or programmatically.
763
764 \value ResizeToContents QHeaderView will automatically resize the section to its optimal
765 size based on the contents of the entire column.
766 The size cannot be changed by the user or programmatically.
767
768 \sa setResizeMode()
769*/
770
771/*!
772 \property QtTreePropertyBrowser::resizeMode
773 \brief the resize mode of setions in the header.
774*/
775
777{
778 return d_ptr->m_resizeMode;
779}
780
781void QtTreePropertyBrowser::setResizeMode(QtTreePropertyBrowser::ResizeMode mode)
782{
783 if (d_ptr->m_resizeMode == mode)
784 return;
785
786 d_ptr->m_resizeMode = mode;
787 QHeaderView::ResizeMode m = QHeaderView::Stretch;
788 switch (mode) {
789 case QtTreePropertyBrowser::Interactive: m = QHeaderView::Interactive; break;
790 case QtTreePropertyBrowser::Fixed: m = QHeaderView::Fixed; break;
791 case QtTreePropertyBrowser::ResizeToContents: m = QHeaderView::ResizeToContents; break;
792 case QtTreePropertyBrowser::Stretch:
793 default: m = QHeaderView::Stretch; break;
794 }
795 d_ptr->m_treeWidget->header()->setSectionResizeMode(m);
796}
797
798/*!
799 \property QtTreePropertyBrowser::splitterPosition
800 \brief the position of the splitter between the colunms.
801*/
802
804{
805 return d_ptr->m_treeWidget->header()->sectionSize(0);
806}
807
809{
810 d_ptr->m_treeWidget->header()->resizeSection(0, position);
811}
812
813/*!
814 Sets the \a item to either collapse or expanded, depending on the value of \a expanded.
815
816 \sa isExpanded(), expanded(), collapsed()
817*/
818
820{
821 QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item);
822 if (treeItem)
823 treeItem->setExpanded(expanded);
824}
825
826/*!
827 Returns true if the \a item is expanded; otherwise returns false.
828
829 \sa setExpanded()
830*/
831
833{
834 QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item);
835 if (treeItem)
836 return treeItem->isExpanded();
837 return false;
838}
839
840/*!
841 Returns true if the \a item is visible; otherwise returns false.
842
843 \sa setItemVisible()
844 \since 4.5
845*/
846
848{
849 if (const QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item))
850 return !treeItem->isHidden();
851 return false;
852}
853
854/*!
855 Sets the \a item to be visible, depending on the value of \a visible.
856
857 \sa isItemVisible()
858 \since 4.5
859*/
860
862{
863 if (QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item))
864 treeItem->setHidden(!visible);
865}
866
867/*!
868 Sets the \a item's background color to \a color. Note that while item's background
869 is rendered every second row is being drawn with alternate color (which is a bit lighter than items \a color)
870
871 \sa backgroundColor(), calculatedBackgroundColor()
872*/
873
875{
876 if (!d_ptr->m_indexToItem.contains(item))
877 return;
878 if (color.isValid())
879 d_ptr->m_indexToBackgroundColor[item] = color;
880 else
881 d_ptr->m_indexToBackgroundColor.remove(item);
882 d_ptr->m_treeWidget->viewport()->update();
883}
884
885/*!
886 Returns the \a item's color. If there is no color set for item it returns invalid color.
887
888 \sa calculatedBackgroundColor(), setBackgroundColor()
889*/
890
892{
893 return d_ptr->m_indexToBackgroundColor.value(item);
894}
895
896/*!
897 Returns the \a item's color. If there is no color set for item it returns parent \a item's
898 color (if there is no color set for parent it returns grandparent's color and so on). In case
899 the color is not set for \a item and it's top level item it returns invalid color.
900
901 \sa backgroundColor(), setBackgroundColor()
902*/
903
905{
906 return d_ptr->calculatedBackgroundColor(item);
907}
908
909/*!
910 \property QtTreePropertyBrowser::propertiesWithoutValueMarked
911 \brief whether to enable or disable marking properties without value.
912
913 When marking is enabled the item's background is rendered in dark color and item's
914 foreground is rendered with light color.
915
916 \sa propertiesWithoutValueMarked()
917*/
919{
920 if (d_ptr->m_markPropertiesWithoutValue == mark)
921 return;
922
923 d_ptr->m_markPropertiesWithoutValue = mark;
924 for (auto it = d_ptr->m_itemToIndex.cbegin(), end = d_ptr->m_itemToIndex.cend(); it != end; ++it) {
925 QtProperty *property = it.value()->property();
926 if (!property->hasValue())
927 d_ptr->updateItem(it.key());
928 }
929 d_ptr->m_treeWidget->viewport()->update();
930}
931
933{
934 return d_ptr->m_markPropertiesWithoutValue;
935}
936
937/*!
938 \reimp
939*/
941{
942 d_ptr->propertyInserted(item, afterItem);
943}
944
945/*!
946 \reimp
947*/
949{
950 d_ptr->propertyRemoved(item);
951}
952
953/*!
954 \reimp
955*/
957{
958 d_ptr->propertyChanged(item);
959}
960
961/*!
962 Sets the current item to \a item and opens the relevant editor for it.
963*/
965{
966 d_ptr->editItem(item);
967}
968
969QT_END_NAMESPACE
970
971#include "moc_qttreepropertybrowser_p.cpp"
972#include "qttreepropertybrowser.moc"
QtAbstractPropertyBrowser provides a base class for implementing property browsers.
void setCurrentItem(QtBrowserItem *)
Sets the current item in the property browser to item.
The QtBrowserItem class represents a property in a property browser instance.
QtProperty * property() const
Returns the property which is accosiated with this item.
QtBrowserItem * parent() const
Returns the parent item of this item.
void closeEditor(QtProperty *property)
void setEditorData(QWidget *, const QModelIndex &) const override
Sets the data to be displayed and edited by the editor from the data model item specified by the mode...
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Updates the editor for the item specified by index according to the style option given.
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
Returns the size needed by the delegate to display the item specified by index, taking into account t...
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Renders the delegate using the given painter and style option for the item specified by index.
void setModelData(QWidget *, QAbstractItemModel *, const QModelIndex &) const override
Gets data from the editor widget and stores it in the specified model at the item index.
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Returns the widget used to edit the item specified by index for editing.
void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate)
QTreeWidgetItem * editedItem() const
QTreeWidgetItem * indexToItem(const QModelIndex &index) const
void keyPressEvent(QKeyEvent *event) override
void mousePressEvent(QMouseEvent *event) override
void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Draws the row in the tree view that contains the model item index, using the painter given.
void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate)
The QtProperty class encapsulates an instance of a property.
bool isEnabled() const
Returns whether the property is enabled.
bool hasValue() const
Returns whether the property has a value.
bool isModified() const
Returns whether the property is modified.
void enableItem(QTreeWidgetItem *item) const
QWidget * createEditor(QtProperty *property, QWidget *parent) const
void setCurrentItem(QtBrowserItem *browserItem, bool block)
QColor calculatedBackgroundColor(QtBrowserItem *item) const
QtProperty * indexToProperty(const QModelIndex &index) const
void slotCurrentBrowserItemChanged(QtBrowserItem *item)
void propertyChanged(QtBrowserItem *index)
bool hasValue(QTreeWidgetItem *item) const
void slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *)
QTreeWidgetItem * indexToItem(const QModelIndex &index) const
void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex)
void editItem(QtBrowserItem *browserItem)
QTreeWidgetItem * editedItem() const
void slotCollapsed(const QModelIndex &index)
QtBrowserItem * indexToBrowserItem(const QModelIndex &index) const
void slotExpanded(const QModelIndex &index)
void disableItem(QTreeWidgetItem *item) const
QtPropertyEditorView * treeWidget() const
void propertyRemoved(QtBrowserItem *index)
The QtTreePropertyBrowser class provides QTreeWidget based property browser.
QColor calculatedBackgroundColor(QtBrowserItem *item) const
Returns the item's color.
~QtTreePropertyBrowser() override
Destroys this property browser.
void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) override
\reimp
bool isExpanded(QtBrowserItem *item) const
Returns true if the item is expanded; otherwise returns false.
void editItem(QtBrowserItem *item)
Sets the current item to item and opens the relevant editor for it.
void setItemVisible(QtBrowserItem *item, bool visible)
Sets the item to be visible, depending on the value of visible.
void setExpanded(QtBrowserItem *item, bool expanded)
Sets the item to either collapse or expanded, depending on the value of expanded.
void setBackgroundColor(QtBrowserItem *item, QColor color)
Sets the item's background color to color.
void itemChanged(QtBrowserItem *item) override
\reimp
void itemRemoved(QtBrowserItem *item) override
\reimp
QColor backgroundColor(QtBrowserItem *item) const
Returns the item's color.
void setHeaderVisible(bool visible)
void setAlternatingRowColors(bool enable)
bool isItemVisible(QtBrowserItem *item) const
Returns true if the item is visible; otherwise returns false.
void setSplitterPosition(int position)
void setPropertiesWithoutValueMarked(bool mark)
Combined button and popup list for selecting options.
static QIcon drawIndicatorIcon(const QPalette &palette, QStyle *style)
static bool isLightTheme()
static constexpr bool isWindows