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