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 bool eventFilter(QObject *object, QEvent *event) override;
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 editor->installEventFilter(const_cast<QtPropertyEditorDelegate *>(this));
260 connect(editor, &QObject::destroyed,
261 this, &QtPropertyEditorDelegate::slotEditorDestroyed);
262 m_editedProperty = property;
263 m_editedItem = item;
264 m_editedWidget = editor;
265 }
266 return editor;
267 }
268 }
269 return nullptr;
270}
271
272// Span the entire area, hiding the value icon to ensure no icon
273// is displayed when for example editing using a check box
275 const QStyleOptionViewItem &option, const QModelIndex &index) const
276{
277 Q_UNUSED(index);
278 editor->setGeometry(option.rect.adjusted(0, 0, 0, -1));
279}
280
281void QtPropertyEditorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
282 const QModelIndex &index) const
283{
284 bool hasValue = true;
285 if (m_editorPrivate) {
286 QtProperty *property = m_editorPrivate->indexToProperty(index);
287 if (property)
288 hasValue = property->hasValue();
289 }
290 QStyleOptionViewItem opt = option;
291 if ((m_editorPrivate && index.column() == 0) || !hasValue) {
292 QtProperty *property = m_editorPrivate->indexToProperty(index);
293 if (property && property->isModified()) {
294 opt.font.setBold(true);
295 opt.fontMetrics = QFontMetrics(opt.font);
296 }
297 }
298 QColor c;
299 if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) {
300 c = opt.palette.color(QPalette::Dark);
301 // Hardcode "white" for Windows/light which is otherwise blue
302 const QColor textColor = isWindows && isLightTheme()
303 ? QColor(Qt::white) : opt.palette.color(QPalette::BrightText);
304 opt.palette.setColor(QPalette::Text, textColor);
305 } else {
306 c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index));
307 if (c.isValid() && (opt.features & QStyleOptionViewItem::Alternate))
308 c = c.lighter(112);
309 }
310 if (c.isValid())
311 painter->fillRect(option.rect, c);
312 opt.state &= ~QStyle::State_HasFocus;
313 QStyledItemDelegate::paint(painter, opt, index);
314
315 opt.palette.setCurrentColorGroup(QPalette::Active);
316 QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
317 painter->save();
318 painter->setPen(QPen(color));
319 if (!m_editorPrivate || (!m_editorPrivate->lastColumn(index.column()) && hasValue)) {
320 int right = (option.direction == Qt::LeftToRight) ? option.rect.right() : option.rect.left();
321 painter->drawLine(right, option.rect.y(), right, option.rect.bottom());
322 }
323 painter->restore();
324}
325
326QSize QtPropertyEditorDelegate::sizeHint(const QStyleOptionViewItem &option,
327 const QModelIndex &index) const
328{
329 return QStyledItemDelegate::sizeHint(option, index) + QSize(3, 4);
330}
331
332bool QtPropertyEditorDelegate::eventFilter(QObject *object, QEvent *event)
333{
334 if (event->type() == QEvent::FocusOut) {
335 QFocusEvent *fe = static_cast<QFocusEvent *>(event);
336 if (fe->reason() == Qt::ActiveWindowFocusReason)
337 return false;
338 }
339 return QStyledItemDelegate::eventFilter(object, event);
340}
341
342// -------- QtTreePropertyBrowserPrivate implementation
343
344// Draw an icon indicating opened/closing branches
345static QIcon drawIndicatorIcon(const QPalette &palette, QStyle *style)
346{
347 QPixmap pix(14, 14);
348 pix.fill(Qt::transparent);
349 QStyleOption branchOption;
350 branchOption.rect = QRect(2, 2, 9, 9); // ### hardcoded in qcommonstyle.cpp
351 branchOption.palette = palette;
352 branchOption.state = QStyle::State_Children;
353
354 QPainter p;
355 // Draw closed state
356 p.begin(&pix);
357 style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
358 p.end();
359 QIcon rc = pix;
360 rc.addPixmap(pix, QIcon::Selected, QIcon::Off);
361 // Draw opened state
362 branchOption.state |= QStyle::State_Open;
363 pix.fill(Qt::transparent);
364 p.begin(&pix);
365 style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
366 p.end();
367
368 rc.addPixmap(pix, QIcon::Normal, QIcon::On);
369 rc.addPixmap(pix, QIcon::Selected, QIcon::On);
370 return rc;
371}
372
373void QtTreePropertyBrowserPrivate::init(QWidget *parent)
374{
375 auto *layout = new QHBoxLayout(parent);
376 layout->setContentsMargins(QMargins());
377 m_treeWidget = new QtPropertyEditorView(parent);
378 m_treeWidget->setEditorPrivate(this);
379 m_treeWidget->setIconSize(QtPropertyBrowserUtils::itemViewIconSize);
380 layout->addWidget(m_treeWidget);
381
382 m_treeWidget->setColumnCount(2);
383 QStringList labels;
384 labels.append(QCoreApplication::translate("QtTreePropertyBrowser", "Property"));
385 labels.append(QCoreApplication::translate("QtTreePropertyBrowser", "Value"));
386 m_treeWidget->setHeaderLabels(labels);
387 m_treeWidget->setAlternatingRowColors(true);
388 m_treeWidget->setEditTriggers(QAbstractItemView::EditKeyPressed);
389 m_delegate = new QtPropertyEditorDelegate(parent);
390 m_delegate->setEditorPrivate(this);
391 m_treeWidget->setItemDelegate(m_delegate);
392 m_treeWidget->header()->setSectionsMovable(false);
393 m_treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch);
394
395 m_expandIcon = drawIndicatorIcon(q_ptr->palette(), q_ptr->style());
396
397 QObject::connect(m_treeWidget, &QTreeView::collapsed,
398 q_ptr, [this](const QModelIndex &index) { slotCollapsed(index); });
399 QObject::connect(m_treeWidget, &QTreeView::expanded,
400 q_ptr, [this](const QModelIndex &index) { slotExpanded(index); });
401 QObject::connect(m_treeWidget, &QTreeWidget::currentItemChanged,
402 q_ptr, [this](QTreeWidgetItem *current, QTreeWidgetItem *previous)
403 { slotCurrentTreeItemChanged(current, previous); });
404}
405
407{
408 if (QTreeWidgetItem *treeItem = m_treeWidget->currentItem())
409 return m_itemToIndex.value(treeItem);
410 return nullptr;
411}
412
414{
415 const bool blocked = block ? m_treeWidget->blockSignals(true) : false;
416 if (browserItem == nullptr)
417 m_treeWidget->setCurrentItem(nullptr);
418 else
419 m_treeWidget->setCurrentItem(m_indexToItem.value(browserItem));
420 if (block)
421 m_treeWidget->blockSignals(blocked);
422}
423
425{
426 QTreeWidgetItem *item = m_treeWidget->indexToItem(index);
427 QtBrowserItem *idx = m_itemToIndex.value(item);
428 if (idx)
429 return idx->property();
430 return nullptr;
431}
432
434{
435 QTreeWidgetItem *item = m_treeWidget->indexToItem(index);
436 return m_itemToIndex.value(item);
437}
438
439QTreeWidgetItem *QtTreePropertyBrowserPrivate::indexToItem(const QModelIndex &index) const
440{
441 return m_treeWidget->indexToItem(index);
442}
443
445{
446 return m_treeWidget->header()->visualIndex(column) == m_treeWidget->columnCount() - 1;
447}
448
449void QtTreePropertyBrowserPrivate::disableItem(QTreeWidgetItem *item) const
450{
451 Qt::ItemFlags flags = item->flags();
452 if (flags & Qt::ItemIsEnabled) {
453 flags &= ~Qt::ItemIsEnabled;
454 item->setFlags(flags);
455 m_delegate->closeEditor(m_itemToIndex[item]->property());
456 const int childCount = item->childCount();
457 for (int i = 0; i < childCount; i++) {
458 QTreeWidgetItem *child = item->child(i);
459 disableItem(child);
460 }
461 }
462}
463
464void QtTreePropertyBrowserPrivate::enableItem(QTreeWidgetItem *item) const
465{
466 Qt::ItemFlags flags = item->flags();
467 flags |= Qt::ItemIsEnabled;
468 item->setFlags(flags);
469 const int childCount = item->childCount();
470 for (int i = 0; i < childCount; i++) {
471 QTreeWidgetItem *child = item->child(i);
472 QtProperty *property = m_itemToIndex[child]->property();
473 if (property->isEnabled()) {
474 enableItem(child);
475 }
476 }
477}
478
479bool QtTreePropertyBrowserPrivate::hasValue(QTreeWidgetItem *item) const
480{
481 QtBrowserItem *browserItem = m_itemToIndex.value(item);
482 if (browserItem)
483 return browserItem->property()->hasValue();
484 return false;
485}
486
488{
489 QTreeWidgetItem *afterItem = m_indexToItem.value(afterIndex);
490 QTreeWidgetItem *parentItem = m_indexToItem.value(index->parent());
491
492 QTreeWidgetItem *newItem = nullptr;
493 if (parentItem) {
494 newItem = new QTreeWidgetItem(parentItem, afterItem);
495 } else {
496 newItem = new QTreeWidgetItem(m_treeWidget, afterItem);
497 }
498 m_itemToIndex[newItem] = index;
499 m_indexToItem[index] = newItem;
500
501 newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
502 newItem->setExpanded(true);
503
504 updateItem(newItem);
505}
506
508{
509 QTreeWidgetItem *item = m_indexToItem.value(index);
510
511 if (m_treeWidget->currentItem() == item) {
512 m_treeWidget->setCurrentItem(nullptr);
513 }
514
515 delete item;
516
517 m_indexToItem.remove(index);
518 m_itemToIndex.remove(item);
519 m_indexToBackgroundColor.remove(index);
520}
521
523{
524 QTreeWidgetItem *item = m_indexToItem.value(index);
525
526 updateItem(item);
527}
528
529void QtTreePropertyBrowserPrivate::updateItem(QTreeWidgetItem *item)
530{
531 QtProperty *property = m_itemToIndex[item]->property();
532 QIcon expandIcon;
533 if (property->hasValue()) {
534 const QString valueToolTip = property->valueToolTip();
535 const QString valueText = property->valueText();
536 item->setToolTip(1, valueToolTip.isEmpty() ? valueText : valueToolTip);
537 item->setIcon(1, property->valueIcon());
538 item->setText(1, valueText);
539 } else if (markPropertiesWithoutValue() && !m_treeWidget->rootIsDecorated()) {
540 expandIcon = m_expandIcon;
541 }
542 item->setIcon(0, expandIcon);
543 item->setFirstColumnSpanned(!property->hasValue());
544 const QString descriptionToolTip = property->descriptionToolTip();
545 const QString propertyName = property->propertyName();
546 item->setToolTip(0, descriptionToolTip.isEmpty() ? propertyName : descriptionToolTip);
547 item->setStatusTip(0, property->statusTip());
548 item->setWhatsThis(0, property->whatsThis());
549 item->setText(0, propertyName);
550 bool wasEnabled = item->flags() & Qt::ItemIsEnabled;
551 bool isEnabled = wasEnabled;
552 if (property->isEnabled()) {
553 QTreeWidgetItem *parent = item->parent();
554 isEnabled = !parent || (parent->flags() & Qt::ItemIsEnabled);
555 } else {
556 isEnabled = false;
557 }
558 if (wasEnabled != isEnabled) {
559 if (isEnabled)
560 enableItem(item);
561 else
562 disableItem(item);
563 }
564 m_treeWidget->viewport()->update();
565}
566
568{
569 QtBrowserItem *i = item;
570 const auto itEnd = m_indexToBackgroundColor.constEnd();
571 while (i) {
572 auto it = m_indexToBackgroundColor.constFind(i);
573 if (it != itEnd)
574 return it.value();
575 i = i->parent();
576 }
577 return {};
578}
579
580void QtTreePropertyBrowserPrivate::slotCollapsed(const QModelIndex &index)
581{
582 QTreeWidgetItem *item = indexToItem(index);
583 QtBrowserItem *idx = m_itemToIndex.value(item);
584 if (item)
585 emit q_ptr->collapsed(idx);
586}
587
588void QtTreePropertyBrowserPrivate::slotExpanded(const QModelIndex &index)
589{
590 QTreeWidgetItem *item = indexToItem(index);
591 QtBrowserItem *idx = m_itemToIndex.value(item);
592 if (item)
593 emit q_ptr->expanded(idx);
594}
595
597{
598 if (!m_browserChangedBlocked && item != currentItem())
599 setCurrentItem(item, true);
600}
601
602void QtTreePropertyBrowserPrivate::slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *)
603{
604 QtBrowserItem *browserItem = newItem ? m_itemToIndex.value(newItem) : 0;
605 m_browserChangedBlocked = true;
606 q_ptr->setCurrentItem(browserItem);
607 m_browserChangedBlocked = false;
608}
609
611{
612 return m_delegate->editedItem();
613}
614
616{
617 if (QTreeWidgetItem *treeItem = m_indexToItem.value(browserItem, nullptr)) {
618 m_treeWidget->setCurrentItem (treeItem, 1);
619 m_treeWidget->editItem(treeItem, 1);
620 }
621}
622
623/*!
624 \class QtTreePropertyBrowser
625 \internal
626 \inmodule QtDesigner
627 \since 4.4
628
629 \brief The QtTreePropertyBrowser class provides QTreeWidget based
630 property browser.
631
632 A property browser is a widget that enables the user to edit a
633 given set of properties. Each property is represented by a label
634 specifying the property's name, and an editing widget (e.g. a line
635 edit or a combobox) holding its value. A property can have zero or
636 more subproperties.
637
638 QtTreePropertyBrowser provides a tree based view for all nested
639 properties, i.e. properties that have subproperties can be in an
640 expanded (subproperties are visible) or collapsed (subproperties
641 are hidden) state. For example:
642
643 \image qttreepropertybrowser.png
644
645 Use the QtAbstractPropertyBrowser API to add, insert and remove
646 properties from an instance of the QtTreePropertyBrowser class.
647 The properties themselves are created and managed by
648 implementations of the QtAbstractPropertyManager class.
649
650 \sa QtGroupBoxPropertyBrowser, QtAbstractPropertyBrowser
651*/
652
653/*!
654 \fn void QtTreePropertyBrowser::collapsed(QtBrowserItem *item)
655
656 This signal is emitted when the \a item is collapsed.
657
658 \sa expanded(), setExpanded()
659*/
660
661/*!
662 \fn void QtTreePropertyBrowser::expanded(QtBrowserItem *item)
663
664 This signal is emitted when the \a item is expanded.
665
666 \sa collapsed(), setExpanded()
667*/
668
669/*!
670 Creates a property browser with the given \a parent.
671*/
672QtTreePropertyBrowser::QtTreePropertyBrowser(QWidget *parent)
673 : QtAbstractPropertyBrowser(parent), d_ptr(new QtTreePropertyBrowserPrivate)
674{
675 d_ptr->q_ptr = this;
676
677 d_ptr->init(this);
678 QObject::connect(this, &QtAbstractPropertyBrowser::currentItemChanged,
679 this, [this](QtBrowserItem *current)
680 { d_ptr->slotCurrentBrowserItemChanged(current); });
681}
682
683/*!
684 Destroys this property browser.
685
686 Note that the properties that were inserted into this browser are
687 \e not destroyed since they may still be used in other
688 browsers. The properties are owned by the manager that created
689 them.
690
691 \sa QtProperty, QtAbstractPropertyManager
692*/
694
695/*!
696 \property QtTreePropertyBrowser::indentation
697 \brief indentation of the items in the tree view.
698*/
700{
701 return d_ptr->m_treeWidget->indentation();
702}
703
705{
706 d_ptr->m_treeWidget->setIndentation(i);
707}
708
709/*!
710 \property QtTreePropertyBrowser::rootIsDecorated
711 \brief whether to show controls for expanding and collapsing root items.
712*/
714{
715 return d_ptr->m_treeWidget->rootIsDecorated();
716}
717
719{
720 d_ptr->m_treeWidget->setRootIsDecorated(show);
721 for (auto it = d_ptr->m_itemToIndex.cbegin(), end = d_ptr->m_itemToIndex.cend(); it != end; ++it) {
722 QtProperty *property = it.value()->property();
723 if (!property->hasValue())
724 d_ptr->updateItem(it.key());
725 }
726}
727
728/*!
729 \property QtTreePropertyBrowser::alternatingRowColors
730 \brief whether to draw the background using alternating colors.
731 By default this property is set to true.
732*/
734{
735 return d_ptr->m_treeWidget->alternatingRowColors();
736}
737
739{
740 d_ptr->m_treeWidget->setAlternatingRowColors(enable);
741}
742
743/*!
744 \property QtTreePropertyBrowser::headerVisible
745 \brief whether to show the header.
746*/
748{
749 return d_ptr->m_headerVisible;
750}
751
753{
754 if (d_ptr->m_headerVisible == visible)
755 return;
756
757 d_ptr->m_headerVisible = visible;
758 d_ptr->m_treeWidget->header()->setVisible(visible);
759}
760
761/*!
762 \enum QtTreePropertyBrowser::ResizeMode
763
764 The resize mode specifies the behavior of the header sections.
765
766 \value Interactive The user can resize the sections.
767 The sections can also be resized programmatically using setSplitterPosition().
768
769 \value Fixed The user cannot resize the section.
770 The section can only be resized programmatically using setSplitterPosition().
771
772 \value Stretch QHeaderView will automatically resize the section to fill the available space.
773 The size cannot be changed by the user or programmatically.
774
775 \value ResizeToContents QHeaderView will automatically resize the section to its optimal
776 size based on the contents of the entire column.
777 The size cannot be changed by the user or programmatically.
778
779 \sa setResizeMode()
780*/
781
782/*!
783 \property QtTreePropertyBrowser::resizeMode
784 \brief the resize mode of setions in the header.
785*/
786
788{
789 return d_ptr->m_resizeMode;
790}
791
792void QtTreePropertyBrowser::setResizeMode(QtTreePropertyBrowser::ResizeMode mode)
793{
794 if (d_ptr->m_resizeMode == mode)
795 return;
796
797 d_ptr->m_resizeMode = mode;
798 QHeaderView::ResizeMode m = QHeaderView::Stretch;
799 switch (mode) {
800 case QtTreePropertyBrowser::Interactive: m = QHeaderView::Interactive; break;
801 case QtTreePropertyBrowser::Fixed: m = QHeaderView::Fixed; break;
802 case QtTreePropertyBrowser::ResizeToContents: m = QHeaderView::ResizeToContents; break;
803 case QtTreePropertyBrowser::Stretch:
804 default: m = QHeaderView::Stretch; break;
805 }
806 d_ptr->m_treeWidget->header()->setSectionResizeMode(m);
807}
808
809/*!
810 \property QtTreePropertyBrowser::splitterPosition
811 \brief the position of the splitter between the colunms.
812*/
813
815{
816 return d_ptr->m_treeWidget->header()->sectionSize(0);
817}
818
820{
821 d_ptr->m_treeWidget->header()->resizeSection(0, position);
822}
823
824/*!
825 Sets the \a item to either collapse or expanded, depending on the value of \a expanded.
826
827 \sa isExpanded(), expanded(), collapsed()
828*/
829
831{
832 QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item);
833 if (treeItem)
834 treeItem->setExpanded(expanded);
835}
836
837/*!
838 Returns true if the \a item is expanded; otherwise returns false.
839
840 \sa setExpanded()
841*/
842
844{
845 QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item);
846 if (treeItem)
847 return treeItem->isExpanded();
848 return false;
849}
850
851/*!
852 Returns true if the \a item is visible; otherwise returns false.
853
854 \sa setItemVisible()
855 \since 4.5
856*/
857
859{
860 if (const QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item))
861 return !treeItem->isHidden();
862 return false;
863}
864
865/*!
866 Sets the \a item to be visible, depending on the value of \a visible.
867
868 \sa isItemVisible()
869 \since 4.5
870*/
871
873{
874 if (QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item))
875 treeItem->setHidden(!visible);
876}
877
878/*!
879 Sets the \a item's background color to \a color. Note that while item's background
880 is rendered every second row is being drawn with alternate color (which is a bit lighter than items \a color)
881
882 \sa backgroundColor(), calculatedBackgroundColor()
883*/
884
886{
887 if (!d_ptr->m_indexToItem.contains(item))
888 return;
889 if (color.isValid())
890 d_ptr->m_indexToBackgroundColor[item] = color;
891 else
892 d_ptr->m_indexToBackgroundColor.remove(item);
893 d_ptr->m_treeWidget->viewport()->update();
894}
895
896/*!
897 Returns the \a item's color. If there is no color set for item it returns invalid color.
898
899 \sa calculatedBackgroundColor(), setBackgroundColor()
900*/
901
903{
904 return d_ptr->m_indexToBackgroundColor.value(item);
905}
906
907/*!
908 Returns the \a item's color. If there is no color set for item it returns parent \a item's
909 color (if there is no color set for parent it returns grandparent's color and so on). In case
910 the color is not set for \a item and it's top level item it returns invalid color.
911
912 \sa backgroundColor(), setBackgroundColor()
913*/
914
916{
917 return d_ptr->calculatedBackgroundColor(item);
918}
919
920/*!
921 \property QtTreePropertyBrowser::propertiesWithoutValueMarked
922 \brief whether to enable or disable marking properties without value.
923
924 When marking is enabled the item's background is rendered in dark color and item's
925 foreground is rendered with light color.
926
927 \sa propertiesWithoutValueMarked()
928*/
930{
931 if (d_ptr->m_markPropertiesWithoutValue == mark)
932 return;
933
934 d_ptr->m_markPropertiesWithoutValue = mark;
935 for (auto it = d_ptr->m_itemToIndex.cbegin(), end = d_ptr->m_itemToIndex.cend(); it != end; ++it) {
936 QtProperty *property = it.value()->property();
937 if (!property->hasValue())
938 d_ptr->updateItem(it.key());
939 }
940 d_ptr->m_treeWidget->viewport()->update();
941}
942
944{
945 return d_ptr->m_markPropertiesWithoutValue;
946}
947
948/*!
949 \reimp
950*/
952{
953 d_ptr->propertyInserted(item, afterItem);
954}
955
956/*!
957 \reimp
958*/
960{
961 d_ptr->propertyRemoved(item);
962}
963
964/*!
965 \reimp
966*/
968{
969 d_ptr->propertyChanged(item);
970}
971
972/*!
973 Sets the current item to \a item and opens the relevant editor for it.
974*/
976{
977 d_ptr->editItem(item);
978}
979
980QT_END_NAMESPACE
981
982#include "moc_qttreepropertybrowser_p.cpp"
983#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.
bool eventFilter(QObject *object, QEvent *event) override
\reimp
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