44 #include <QApplication>
45 #include <QFocusEvent>
46 #include <QHBoxLayout>
47 #include <QHeaderView>
49 #include <QItemDelegate>
54 #include <QTreeWidget>
67 void init(QWidget* 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;
187 const QColor
c =
option.palette.color(QPalette::Dark);
188 painter->fillRect(
option.rect,
c);
189 opt.palette.setColor(QPalette::AlternateBase,
c);
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())
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) &&
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;
356 QtPropertyEditorDelegate::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();
381 QtPropertyEditorDelegate::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)
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;
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);
486 c = opt.palette.color(QPalette::Dark);
487 opt.palette.setColor(QPalette::Text, opt.palette.color(QPalette::BrightText));
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)
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)
603 drawIndicatorIcon(
const QPalette& palette, QStyle* style)
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;
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);
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);
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);
721 return m_itemToIndex.value(item);
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);
841 QtTreePropertyBrowserPrivate::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);
955 if (!m_browserChangedBlocked && item !=
currentItem())
964 QtBrowserItem* browserItem = newItem ? m_itemToIndex.value(newItem) : 0;
965 m_browserChangedBlocked =
true;
967 m_browserChangedBlocked =
false;
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);
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;
1425 #include "moc_qttreepropertybrowser.cpp"
1426 #include "qttreepropertybrowser.moc"