44#include <QApplication>
49#include <QItemDelegate>
67 void init(QWidget* parent);
76 return q_ptr->createEditor(property, parent);
85 bool hasValue(QTreeWidgetItem* item)
const;
101 return m_markPropertiesWithoutValue;
114 void updateItem(QTreeWidgetItem* item);
116 QMap<QtBrowserItem*, QTreeWidgetItem*> m_indexToItem;
117 QMap<QTreeWidgetItem*, QtBrowserItem*> m_itemToIndex;
119 QMap<QtBrowserItem*, QColor> m_indexToBackgroundColor;
123 bool m_headerVisible;
126 bool m_markPropertiesWithoutValue;
127 bool m_browserChangedBlocked;
141 m_editorPrivate = editorPrivate;
147 return itemFromIndex(
index);
153 void drawRow(QPainter* painter,
154 const QStyleOptionViewItem&
option,
155 const QModelIndex&
index)
const override;
162 QTreeWidget(parent), m_editorPrivate(0)
164 connect(header(), SIGNAL(sectionDoubleClicked(
int)),
this, SLOT(resizeColumnToContents(
int)));
169 const QStyleOptionViewItem&
option,
170 const QModelIndex&
index)
const
172 QStyleOptionViewItem opt =
option;
173 bool hasValue =
true;
181 hasValue =
property->hasValue();
185 if (!hasValue && m_editorPrivate->markPropertiesWithoutValue())
187 const QColor
c =
option.palette.color(QPalette::Dark);
188 painter->fillRect(
option.rect,
c);
189 opt.palette.setColor(QPalette::AlternateBase,
c);
194 m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(
index));
198 painter->fillRect(
option.rect,
c);
199 opt.palette.setColor(QPalette::AlternateBase,
c.lighter(112));
203 QTreeWidget::drawRow(painter, opt,
index);
205 static_cast<QRgb
>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
207 painter->setPen(QPen(color));
208 painter->drawLine(opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
215 switch (event->key())
220 if (!m_editorPrivate->editedItem())
221 if (
const QTreeWidgetItem* item = currentItem())
222 if (item->columnCount() >= 2 &&
223 ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) ==
224 (Qt::ItemIsEditable | Qt::ItemIsEnabled)))
228 QModelIndex
index = currentIndex();
230 if (
index.column() == 0)
233 setCurrentIndex(
index);
246 QTreeWidget::keyPressEvent(event);
252 QTreeWidget::mousePressEvent(event);
253 QTreeWidgetItem* item = itemAt(event->pos());
257 if ((item != m_editorPrivate->editedItem()) && (event->button() == Qt::LeftButton) &&
258 (header()->logicalIndexAt(event->pos().x()) == 1) &&
259 ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) ==
260 (Qt::ItemIsEditable | Qt::ItemIsEnabled)))
264 else if (!m_editorPrivate->hasValue(item) &&
265 m_editorPrivate->markPropertiesWithoutValue() && !rootIsDecorated())
267 if (event->pos().x() + header()->offset() < 20)
269 item->setExpanded(!item->isExpanded());
281 QItemDelegate(parent),
285 m_disablePainting(false)
292 m_editorPrivate = editorPrivate;
296 const QStyleOptionViewItem&
option,
297 const QModelIndex&
index)
const override;
300 const QStyleOptionViewItem&
option,
301 const QModelIndex&
index)
const override;
303 void paint(QPainter* painter,
304 const QStyleOptionViewItem&
option,
305 const QModelIndex&
index)
const override;
307 QSize
sizeHint(
const QStyleOptionViewItem&
option,
const QModelIndex&
index)
const override;
310 setModelData(QWidget*, QAbstractItemModel*,
const QModelIndex&)
const override
319 bool eventFilter(QObject*
object, QEvent* event)
override;
330 const QStyleOptionViewItem&
option,
332 const QPixmap& pixmap)
const override;
334 const QStyleOptionViewItem&
option,
336 const QString& text)
const override;
339 void slotEditorDestroyed(QObject*
object);
342 int indentation(
const QModelIndex&
index)
const;
344 using EditorToPropertyMap = QMap<QWidget*, QtProperty*>;
345 mutable EditorToPropertyMap m_editorToProperty;
347 using PropertyToEditorMap = QMap<QtProperty*, QWidget*>;
348 mutable PropertyToEditorMap m_propertyToEditor;
350 mutable QTreeWidgetItem* m_editedItem;
351 mutable QWidget* m_editedWidget;
352 mutable bool m_disablePainting;
356QtPropertyEditorDelegate::indentation(
const QModelIndex&
index)
const
358 if (!m_editorPrivate)
366 while (item->parent())
368 item = item->parent();
372 if (m_editorPrivate->treeWidget()->rootIsDecorated())
377 return indent * m_editorPrivate->treeWidget()->indentation();
381QtPropertyEditorDelegate::slotEditorDestroyed(QObject*
object)
383 if (QWidget* w = qobject_cast<QWidget*>(
object))
385 const EditorToPropertyMap::iterator it = m_editorToProperty.find(w);
387 if (it != m_editorToProperty.end())
389 m_propertyToEditor.remove(it.value());
390 m_editorToProperty.erase(it);
393 if (m_editedWidget == w)
404 if (QWidget* w = m_propertyToEditor.value(property, 0))
412 const QStyleOptionViewItem&,
413 const QModelIndex&
index)
const
415 if (
index.column() == 1 && m_editorPrivate)
418 QTreeWidgetItem* item = m_editorPrivate->indexToItem(
index);
420 if (property && item && (item->flags() & Qt::ItemIsEnabled))
422 QWidget* editor = m_editorPrivate->createEditor(property, parent);
426 editor->setAutoFillBackground(
true);
429 editor, SIGNAL(destroyed(QObject*)),
this, SLOT(slotEditorDestroyed(QObject*)));
430 m_propertyToEditor[property] = editor;
431 m_editorToProperty[editor] = property;
433 m_editedWidget = editor;
445 const QStyleOptionViewItem&
option,
446 const QModelIndex&
index)
const
449 editor->setGeometry(
option.rect.adjusted(0, 0, 0, -1));
454 const QStyleOptionViewItem&
option,
455 const QModelIndex&
index)
const
457 bool hasValue =
true;
465 hasValue =
property->hasValue();
469 QStyleOptionViewItem opt =
option;
471 if ((m_editorPrivate &&
index.column() == 0) || !hasValue)
475 if (property && property->isModified())
477 opt.font.setBold(
true);
478 opt.fontMetrics = QFontMetrics(opt.font);
484 if (!hasValue && m_editorPrivate->markPropertiesWithoutValue())
486 c = opt.palette.color(QPalette::Dark);
487 opt.palette.setColor(QPalette::Text, opt.palette.color(QPalette::BrightText));
491 c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(
index));
493 if (
c.isValid() && (opt.features & QStyleOptionViewItemV2::Alternate))
501 painter->fillRect(
option.rect,
c);
504 opt.state &= ~QStyle::State_HasFocus;
506 if (
index.column() == 1)
508 QTreeWidgetItem* item = m_editorPrivate->indexToItem(
index);
510 if (m_editedItem && m_editedItem == item)
512 m_disablePainting =
true;
516 QItemDelegate::paint(painter, opt,
index);
520 m_disablePainting =
false;
523 opt.palette.setCurrentColorGroup(QPalette::Active);
525 static_cast<QRgb
>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
527 painter->setPen(QPen(color));
529 if (!m_editorPrivate || (!m_editorPrivate->lastColumn(
index.column()) && hasValue))
533 painter->drawLine(right,
option.rect.y(), right,
option.rect.bottom());
541 const QStyleOptionViewItem&
option,
543 const QPixmap& pixmap)
const
545 if (m_disablePainting)
550 QItemDelegate::drawDecoration(painter,
option, rect, pixmap);
555 const QStyleOptionViewItem&
option,
557 const QString& text)
const
559 if (m_disablePainting)
564 QItemDelegate::drawDisplay(painter,
option, rect, text);
569 const QModelIndex&
index)
const
571 return QItemDelegate::sizeHint(
option,
index) + QSize(3, 4);
577 if (event->type() == QEvent::FocusOut)
579 QFocusEvent* fe =
static_cast<QFocusEvent*
>(event);
581 if (fe->reason() == Qt::ActiveWindowFocusReason)
587 return QItemDelegate::eventFilter(
object, event);
593 m_headerVisible(true),
596 m_markPropertiesWithoutValue(false),
597 m_browserChangedBlocked(false)
603drawIndicatorIcon(
const QPalette& palette, QStyle* style)
606 pix.fill(Qt::transparent);
607 QStyleOption branchOption;
608 QRect r(QPoint(0, 0), pix.size());
609 branchOption.rect = QRect(2, 2, 9, 9);
610 branchOption.palette = palette;
611 branchOption.state = QStyle::State_Children;
616 style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
619 rc.addPixmap(pix, QIcon::Selected, QIcon::Off);
621 branchOption.state |= QStyle::State_Open;
622 pix.fill(Qt::transparent);
624 style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
627 rc.addPixmap(pix, QIcon::Normal, QIcon::On);
628 rc.addPixmap(pix, QIcon::Selected, QIcon::On);
635 QHBoxLayout* layout =
new QHBoxLayout(parent);
636 layout->setMargin(0);
638 m_treeWidget->setEditorPrivate(
this);
639 m_treeWidget->setIconSize(QSize(18, 18));
640 layout->addWidget(m_treeWidget);
641 parent->setFocusProxy(m_treeWidget);
643 m_treeWidget->setColumnCount(2);
645 labels.append(QCoreApplication::translate(
"QtTreePropertyBrowser",
"Property"));
646 labels.append(QCoreApplication::translate(
"QtTreePropertyBrowser",
"Value"));
647 m_treeWidget->setHeaderLabels(labels);
648 m_treeWidget->setAlternatingRowColors(
true);
649 m_treeWidget->setEditTriggers(QAbstractItemView::EditKeyPressed);
651 m_delegate->setEditorPrivate(
this);
652 m_treeWidget->setItemDelegate(m_delegate);
653 m_treeWidget->header()->setMovable(
false);
654 m_treeWidget->header()->setResizeMode(QHeaderView::Stretch);
656 m_expandIcon = drawIndicatorIcon(q_ptr->palette(), q_ptr->style());
658 QObject::connect(m_treeWidget,
659 SIGNAL(collapsed(
const QModelIndex&)),
662 QObject::connect(m_treeWidget,
663 SIGNAL(expanded(
const QModelIndex&)),
666 QObject::connect(m_treeWidget,
667 SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
675 if (QTreeWidgetItem* treeItem = m_treeWidget->currentItem())
677 return m_itemToIndex.value(treeItem);
686 const bool blocked = block ? m_treeWidget->blockSignals(
true) :
false;
688 if (browserItem == 0)
690 m_treeWidget->setCurrentItem(0);
694 m_treeWidget->setCurrentItem(m_indexToItem.value(browserItem));
699 m_treeWidget->blockSignals(blocked);
706 QTreeWidgetItem* item = m_treeWidget->indexToItem(
index);
720 QTreeWidgetItem* item = m_treeWidget->indexToItem(
index);
721 return m_itemToIndex.value(item);
727 return m_treeWidget->indexToItem(
index);
733 return m_treeWidget->header()->visualIndex(column) == m_treeWidget->columnCount() - 1;
739 Qt::ItemFlags flags = item->flags();
741 if (flags & Qt::ItemIsEnabled)
743 flags &= ~Qt::ItemIsEnabled;
744 item->setFlags(flags);
745 m_delegate->closeEditor(m_itemToIndex[item]->property());
746 const int childCount = item->childCount();
748 for (
int i = 0; i < childCount; i++)
750 QTreeWidgetItem* child = item->child(i);
759 Qt::ItemFlags flags = item->flags();
760 flags |= Qt::ItemIsEnabled;
761 item->setFlags(flags);
762 const int childCount = item->childCount();
764 for (
int i = 0; i < childCount; i++)
766 QTreeWidgetItem* child = item->child(i);
767 QtProperty*
property = m_itemToIndex[child]->property();
769 if (property->isEnabled())
792 QTreeWidgetItem* afterItem = m_indexToItem.value(afterIndex);
793 QTreeWidgetItem* parentItem = m_indexToItem.value(
index->parent());
795 QTreeWidgetItem* newItem = 0;
799 newItem =
new QTreeWidgetItem(parentItem, afterItem);
803 newItem =
new QTreeWidgetItem(m_treeWidget, afterItem);
806 m_itemToIndex[newItem] =
index;
807 m_indexToItem[
index] = newItem;
809 newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
810 m_treeWidget->setItemExpanded(newItem,
true);
818 QTreeWidgetItem* item = m_indexToItem.value(
index);
820 if (m_treeWidget->currentItem() == item)
822 m_treeWidget->setCurrentItem(0);
827 m_indexToItem.remove(
index);
828 m_itemToIndex.remove(item);
829 m_indexToBackgroundColor.remove(
index);
835 QTreeWidgetItem* item = m_indexToItem.value(
index);
841QtTreePropertyBrowserPrivate::updateItem(QTreeWidgetItem* item)
843 QtProperty*
property = m_itemToIndex[item]->property();
846 if (property->hasValue())
848 QString toolTip =
property->toolTip();
850 if (toolTip.isEmpty())
852 toolTip =
property->displayText();
855 item->setToolTip(1, toolTip);
856 item->setIcon(1, property->valueIcon());
857 property->displayText().isEmpty() ? item->setText(1, property->valueText())
858 : item->setText(1, property->displayText());
862 expandIcon = m_expandIcon;
865 item->setIcon(0, expandIcon);
866 item->setFirstColumnSpanned(!property->hasValue());
867 item->setToolTip(0, property->propertyName());
868 item->setStatusTip(0, property->statusTip());
869 item->setWhatsThis(0, property->whatsThis());
870 item->setText(0, property->propertyName());
871 bool wasEnabled = item->flags() & Qt::ItemIsEnabled;
872 bool isEnabled = wasEnabled;
874 if (property->isEnabled())
876 QTreeWidgetItem* parent = item->parent();
878 if (!parent || (parent->flags() & Qt::ItemIsEnabled))
892 if (wasEnabled != isEnabled)
904 m_treeWidget->viewport()->update();
911 const QMap<QtBrowserItem*, QColor>::const_iterator itEnd = m_indexToBackgroundColor.constEnd();
915 QMap<QtBrowserItem*, QColor>::const_iterator it = m_indexToBackgroundColor.constFind(i);
936 emit q_ptr->collapsed(idx);
948 emit q_ptr->expanded(idx);
955 if (!m_browserChangedBlocked && item !=
currentItem())
964 QtBrowserItem* browserItem = newItem ? m_itemToIndex.value(newItem) : 0;
965 m_browserChangedBlocked =
true;
966 q_ptr->setCurrentItem(browserItem);
967 m_browserChangedBlocked =
false;
973 return m_delegate->editedItem();
979 if (QTreeWidgetItem* treeItem = m_indexToItem.value(browserItem, 0))
981 m_treeWidget->setCurrentItem(treeItem, 1);
982 m_treeWidget->editItem(treeItem, 1);
1035 d_ptr->q_ptr =
this;
1066 return d_ptr->m_treeWidget->indentation();
1072 d_ptr->m_treeWidget->setIndentation(i);
1082 return d_ptr->m_treeWidget->rootIsDecorated();
1088 d_ptr->m_treeWidget->setRootIsDecorated(show);
1089 QMapIterator<QTreeWidgetItem*, QtBrowserItem*> it(d_ptr->m_itemToIndex);
1091 while (it.hasNext())
1093 QtProperty*
property = it.next().value()->property();
1095 if (!property->hasValue())
1097 d_ptr->updateItem(it.key());
1110 return d_ptr->m_treeWidget->alternatingRowColors();
1116 d_ptr->m_treeWidget->setAlternatingRowColors(enable);
1117 QMapIterator<QTreeWidgetItem*, QtBrowserItem*> it(d_ptr->m_itemToIndex);
1127 return d_ptr->m_headerVisible;
1133 if (d_ptr->m_headerVisible == visible)
1138 d_ptr->m_headerVisible = visible;
1139 d_ptr->m_treeWidget->header()->setVisible(visible);
1171 return d_ptr->m_resizeMode;
1177 if (d_ptr->m_resizeMode == mode)
1182 d_ptr->m_resizeMode = mode;
1183 QHeaderView::ResizeMode m = QHeaderView::Stretch;
1188 m = QHeaderView::Interactive;
1192 m = QHeaderView::Fixed;
1196 m = QHeaderView::ResizeToContents;
1201 m = QHeaderView::Stretch;
1205 d_ptr->m_treeWidget->header()->setResizeMode(m);
1216 return d_ptr->m_treeWidget->header()->sectionSize(0);
1222 d_ptr->m_treeWidget->header()->resizeSection(0, position);
1234 QTreeWidgetItem* treeItem = d_ptr->m_indexToItem.value(item);
1251 QTreeWidgetItem* treeItem = d_ptr->m_indexToItem.value(item);
1255 return treeItem->isExpanded();
1271 if (
const QTreeWidgetItem* treeItem = d_ptr->m_indexToItem.value(item))
1273 return !treeItem->isHidden();
1289 if (QTreeWidgetItem* treeItem = d_ptr->m_indexToItem.value(item))
1291 treeItem->setHidden(!visible);
1305 if (!d_ptr->m_indexToItem.contains(item))
1310 if (color.isValid())
1312 d_ptr->m_indexToBackgroundColor[item] = color;
1316 d_ptr->m_indexToBackgroundColor.remove(item);
1319 d_ptr->m_treeWidget->viewport()->update();
1331 return d_ptr->m_indexToBackgroundColor.value(item);
1345 return d_ptr->calculatedBackgroundColor(item);
1360 if (d_ptr->m_markPropertiesWithoutValue == mark)
1365 d_ptr->m_markPropertiesWithoutValue = mark;
1366 QMapIterator<QTreeWidgetItem*, QtBrowserItem*> it(d_ptr->m_itemToIndex);
1368 while (it.hasNext())
1370 QtProperty*
property = it.next().value()->property();
1372 if (!property->hasValue())
1374 d_ptr->updateItem(it.key());
1378 d_ptr->m_treeWidget->viewport()->update();
1384 return d_ptr->m_markPropertiesWithoutValue;
1393 d_ptr->propertyInserted(item, afterItem);
1402 d_ptr->propertyRemoved(item);
1411 d_ptr->propertyChanged(item);
1420 d_ptr->editItem(item);
1425#include "moc_qttreepropertybrowser.cpp"
1426#include "qttreepropertybrowser.moc"
QtAbstractPropertyBrowser(QWidget *parent=0)
void currentItemChanged(QtBrowserItem *)
The QtBrowserItem class represents a property in a property browser instance.
QtBrowserItem * parent() const
QtProperty * property() const
void setModelData(QWidget *, QAbstractItemModel *, const QModelIndex &) const override
void closeEditor(QtProperty *property)
void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const override
bool eventFilter(QObject *object, QEvent *event) override
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate)
QtPropertyEditorDelegate(QObject *parent=0)
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
void setEditorData(QWidget *, const QModelIndex &) const override
void drawDisplay(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QString &text) const override
void drawDecoration(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect, const QPixmap &pixmap) const override
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override
QTreeWidgetItem * editedItem() const
QtPropertyEditorView(QWidget *parent=0)
void keyPressEvent(QKeyEvent *event) override
void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate)
void mousePressEvent(QMouseEvent *event) override
QTreeWidgetItem * indexToItem(const QModelIndex &index) const
The QtProperty class encapsulates an instance of a property.
void disableItem(QTreeWidgetItem *item) const
QtBrowserItem * currentItem() const
void slotCollapsed(const QModelIndex &index)
QColor calculatedBackgroundColor(QtBrowserItem *item) const
bool lastColumn(int column) const
QtPropertyEditorView * treeWidget() const
bool markPropertiesWithoutValue() const
void propertyChanged(QtBrowserItem *index)
void propertyRemoved(QtBrowserItem *index)
void editItem(QtBrowserItem *browserItem)
void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex)
void setCurrentItem(QtBrowserItem *browserItem, bool block)
void slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *)
QtTreePropertyBrowserPrivate()
void slotCurrentBrowserItemChanged(QtBrowserItem *item)
void slotExpanded(const QModelIndex &index)
void enableItem(QTreeWidgetItem *item) const
bool hasValue(QTreeWidgetItem *item) const
QTreeWidgetItem * indexToItem(const QModelIndex &index) const
QtBrowserItem * indexToBrowserItem(const QModelIndex &index) const
QWidget * createEditor(QtProperty *property, QWidget *parent) const
QtProperty * indexToProperty(const QModelIndex &index) const
void init(QWidget *parent)
QTreeWidgetItem * editedItem() const
The QtTreePropertyBrowser class provides QTreeWidget based property browser.
void setPropertiesWithoutValueMarked(bool mark)
bool alternatingRowColors
whether to draw the background using alternating colors. By default this property is set to true.
int splitterPosition
the position of the splitter between the colunms.
bool rootIsDecorated
whether to show controls for expanding and collapsing root items.
QtTreePropertyBrowser(QWidget *parent=0)
ResizeMode resizeMode
the resize mode of setions in the header.
int indentation
indentation of the items in the tree view.
QColor calculatedBackgroundColor(QtBrowserItem *item) const
void setRootIsDecorated(bool show)
void setResizeMode(ResizeMode mode)
~QtTreePropertyBrowser() override
bool propertiesWithoutValueMarked
whether to enable or disable marking properties without value.
void setSplitterPosition(int position)
void editItem(QtBrowserItem *item)
void setExpanded(QtBrowserItem *item, bool expanded)
void setItemVisible(QtBrowserItem *item, bool visible)
bool isItemVisible(QtBrowserItem *item) const
void setHeaderVisible(bool visible)
void itemRemoved(QtBrowserItem *item) override
void expanded(QtBrowserItem *item)
bool isExpanded(QtBrowserItem *item) const
bool isHeaderVisible() const
void setIndentation(int i)
QColor backgroundColor(QtBrowserItem *item) const
void setBackgroundColor(QtBrowserItem *item, const QColor &color)
void setAlternatingRowColors(bool enable)
void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) override
void itemChanged(QtBrowserItem *item) override