File indexing completed on 2024-05-12 04:35:13

0001 /****************************************************************************
0002 **
0003 ** Copyright (C) 2016 The Qt Company Ltd.
0004 ** Contact: https://www.qt.io/licensing/
0005 **
0006 ** This file is part of the tools applications of the Qt Toolkit.
0007 **
0008 ** $QT_BEGIN_LICENSE:LGPL$
0009 ** Commercial License Usage
0010 ** Licensees holding valid commercial Qt licenses may use this file in
0011 ** accordance with the commercial license agreement provided with the
0012 ** Software or, alternatively, in accordance with the terms contained in
0013 ** a written agreement between you and The Qt Company. For licensing terms
0014 ** and conditions see https://www.qt.io/terms-conditions. For further
0015 ** information use the contact form at https://www.qt.io/contact-us.
0016 **
0017 ** GNU Lesser General Public License Usage
0018 ** Alternatively, this file may be used under the terms of the GNU Lesser
0019 ** General Public License version 3 as published by the Free Software
0020 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
0021 ** packaging of this file. Please review the following information to
0022 ** ensure the GNU Lesser General Public License version 3 requirements
0023 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
0024 **
0025 ** GNU General Public License Usage
0026 ** Alternatively, this file may be used under the terms of the GNU
0027 ** General Public License version 2.0 or (at your option) the GNU General
0028 ** Public license version 3 or any later version approved by the KDE Free
0029 ** Qt Foundation. The licenses are as published by the Free Software
0030 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
0031 ** included in the packaging of this file. Please review the following
0032 ** information to ensure the GNU General Public License requirements will
0033 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
0034 ** https://www.gnu.org/licenses/gpl-3.0.html.
0035 **
0036 ** $QT_END_LICENSE$
0037 **
0038 ****************************************************************************/
0039 
0040 #include "qttreepropertybrowser.h"
0041 #include <QtCore/QSet>
0042 #include <QtGui/QIcon>
0043 #include <QtWidgets/QTreeWidget>
0044 #include <QtWidgets/QItemDelegate>
0045 #include <QtWidgets/QHBoxLayout>
0046 #include <QtWidgets/QHeaderView>
0047 #include <QtGui/QPainter>
0048 #include <QtWidgets/QApplication>
0049 #include <QtGui/QFocusEvent>
0050 #include <QtWidgets/QStyle>
0051 #include <QtGui/QPalette>
0052 
0053 QT_BEGIN_NAMESPACE
0054 
0055 class QtPropertyEditorView;
0056 
0057 class QtTreePropertyBrowserPrivate
0058 {
0059     QtTreePropertyBrowser *q_ptr;
0060     Q_DECLARE_PUBLIC(QtTreePropertyBrowser)
0061 
0062 public:
0063     QtTreePropertyBrowserPrivate();
0064     void init(QWidget *parent);
0065 
0066     void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex);
0067     void propertyRemoved(QtBrowserItem *index);
0068     void propertyChanged(QtBrowserItem *index);
0069     QWidget *createEditor(QtProperty *property, QWidget *parent) const
0070         { return q_ptr->createEditor(property, parent); }
0071     QtProperty *indexToProperty(const QModelIndex &index) const;
0072     QTreeWidgetItem *indexToItem(const QModelIndex &index) const;
0073     QtBrowserItem *indexToBrowserItem(const QModelIndex &index) const;
0074     bool lastColumn(int column) const;
0075     void disableItem(QTreeWidgetItem *item) const;
0076     void enableItem(QTreeWidgetItem *item) const;
0077     bool hasValue(QTreeWidgetItem *item) const;
0078 
0079     void slotCollapsed(const QModelIndex &index);
0080     void slotExpanded(const QModelIndex &index);
0081 
0082     QColor calculatedBackgroundColor(QtBrowserItem *item) const;
0083 
0084     QtPropertyEditorView *treeWidget() const { return m_treeWidget; }
0085     bool markPropertiesWithoutValue() const { return m_markPropertiesWithoutValue; }
0086 
0087     QtBrowserItem *currentItem() const;
0088     void setCurrentItem(QtBrowserItem *browserItem, bool block);
0089     void editItem(QtBrowserItem *browserItem);
0090 
0091     void slotCurrentBrowserItemChanged(QtBrowserItem *item);
0092     void slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *);
0093 
0094     QTreeWidgetItem *editedItem() const;
0095 
0096 private:
0097     void updateItem(QTreeWidgetItem *item);
0098 
0099     QMap<QtBrowserItem *, QTreeWidgetItem *> m_indexToItem;
0100     QMap<QTreeWidgetItem *, QtBrowserItem *> m_itemToIndex;
0101 
0102     QMap<QtBrowserItem *, QColor> m_indexToBackgroundColor;
0103 
0104     QtPropertyEditorView *m_treeWidget;
0105 
0106     bool m_headerVisible;
0107     QtTreePropertyBrowser::ResizeMode m_resizeMode;
0108     class QtPropertyEditorDelegate *m_delegate;
0109     bool m_markPropertiesWithoutValue;
0110     bool m_browserChangedBlocked;
0111     QIcon m_expandIcon;
0112 };
0113 
0114 // ------------ QtPropertyEditorView
0115 class QtPropertyEditorView : public QTreeWidget
0116 {
0117     Q_OBJECT
0118 public:
0119     QtPropertyEditorView(QWidget *parent = 0);
0120 
0121     void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate)
0122         { m_editorPrivate = editorPrivate; }
0123 
0124     QTreeWidgetItem *indexToItem(const QModelIndex &index) const
0125         { return itemFromIndex(index); }
0126 
0127 protected:
0128     void keyPressEvent(QKeyEvent *event);
0129     void mousePressEvent(QMouseEvent *event);
0130     void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
0131 
0132 private:
0133     QtTreePropertyBrowserPrivate *m_editorPrivate;
0134 };
0135 
0136 QtPropertyEditorView::QtPropertyEditorView(QWidget *parent) :
0137     QTreeWidget(parent),
0138     m_editorPrivate(0)
0139 {
0140     connect(header(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(resizeColumnToContents(int)));
0141 }
0142 
0143 void QtPropertyEditorView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
0144 {
0145     QStyleOptionViewItem opt = option;
0146     bool hasValue = true;
0147     if (m_editorPrivate) {
0148         QtProperty *property = m_editorPrivate->indexToProperty(index);
0149         if (property)
0150             hasValue = property->hasValue();
0151     }
0152     if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) {
0153         const QColor c = option.palette.color(QPalette::Dark);
0154         painter->fillRect(option.rect, c);
0155         opt.palette.setColor(QPalette::AlternateBase, c);
0156     } else {
0157         const QColor c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index));
0158         if (c.isValid()) {
0159             painter->fillRect(option.rect, c);
0160             opt.palette.setColor(QPalette::AlternateBase, c.lighter(112));
0161         }
0162     }
0163     QTreeWidget::drawRow(painter, opt, index);
0164     QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
0165     painter->save();
0166     painter->setPen(QPen(color));
0167     painter->drawLine(opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
0168     painter->restore();
0169 }
0170 
0171 void QtPropertyEditorView::keyPressEvent(QKeyEvent *event)
0172 {
0173     switch (event->key()) {
0174     case Qt::Key_Return:
0175     case Qt::Key_Enter:
0176     case Qt::Key_Space: // Trigger Edit
0177         if (!m_editorPrivate->editedItem())
0178             if (const QTreeWidgetItem *item = currentItem())
0179                 if (item->columnCount() >= 2 && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) {
0180                     event->accept();
0181                     // If the current position is at column 0, move to 1.
0182                     QModelIndex index = currentIndex();
0183                     if (index.column() == 0) {
0184                         index = index.sibling(index.row(), 1);
0185                         setCurrentIndex(index);
0186                     }
0187                     edit(index);
0188                     return;
0189                 }
0190         break;
0191     default:
0192         break;
0193     }
0194     QTreeWidget::keyPressEvent(event);
0195 }
0196 
0197 void QtPropertyEditorView::mousePressEvent(QMouseEvent *event)
0198 {
0199     QTreeWidget::mousePressEvent(event);
0200     QTreeWidgetItem *item = itemAt(event->pos());
0201 
0202     if (item) {
0203         if ((item != m_editorPrivate->editedItem()) && (event->button() == Qt::LeftButton)
0204                 && (header()->logicalIndexAt(event->pos().x()) == 1)
0205                 && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) {
0206             editItem(item, 1);
0207         } else if (!m_editorPrivate->hasValue(item) && m_editorPrivate->markPropertiesWithoutValue() && !rootIsDecorated()) {
0208             if (event->pos().x() + header()->offset() < 20)
0209                 item->setExpanded(!item->isExpanded());
0210         }
0211     }
0212 }
0213 
0214 // ------------ QtPropertyEditorDelegate
0215 class QtPropertyEditorDelegate : public QItemDelegate
0216 {
0217     Q_OBJECT
0218 public:
0219     QtPropertyEditorDelegate(QObject *parent = 0)
0220         : QItemDelegate(parent), m_editorPrivate(0), m_editedItem(0), m_editedWidget(0)
0221         {}
0222 
0223     void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate)
0224         { m_editorPrivate = editorPrivate; }
0225 
0226     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
0227             const QModelIndex &index) const;
0228 
0229     void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
0230             const QModelIndex &index) const;
0231 
0232     void paint(QPainter *painter, const QStyleOptionViewItem &option,
0233             const QModelIndex &index) const;
0234 
0235     QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
0236 
0237     void setModelData(QWidget *, QAbstractItemModel *,
0238             const QModelIndex &) const {}
0239 
0240     void setEditorData(QWidget *, const QModelIndex &) const {}
0241 
0242     bool eventFilter(QObject *object, QEvent *event);
0243     void closeEditor(QtProperty *property);
0244 
0245     QTreeWidgetItem *editedItem() const { return m_editedItem; }
0246 
0247 private Q_SLOTS:
0248     void slotEditorDestroyed(QObject *object);
0249 
0250 private:
0251     int indentation(const QModelIndex &index) const;
0252 
0253     typedef QMap<QWidget *, QtProperty *> EditorToPropertyMap;
0254     mutable EditorToPropertyMap m_editorToProperty;
0255 
0256     typedef QMap<QtProperty *, QWidget *> PropertyToEditorMap;
0257     mutable PropertyToEditorMap m_propertyToEditor;
0258     QtTreePropertyBrowserPrivate *m_editorPrivate;
0259     mutable QTreeWidgetItem *m_editedItem;
0260     mutable QWidget *m_editedWidget;
0261 };
0262 
0263 int QtPropertyEditorDelegate::indentation(const QModelIndex &index) const
0264 {
0265     if (!m_editorPrivate)
0266         return 0;
0267 
0268     QTreeWidgetItem *item = m_editorPrivate->indexToItem(index);
0269     int indent = 0;
0270     while (item->parent()) {
0271         item = item->parent();
0272         ++indent;
0273     }
0274     if (m_editorPrivate->treeWidget()->rootIsDecorated())
0275         ++indent;
0276     return indent * m_editorPrivate->treeWidget()->indentation();
0277 }
0278 
0279 void QtPropertyEditorDelegate::slotEditorDestroyed(QObject *object)
0280 {
0281     if (QWidget *w = qobject_cast<QWidget *>(object)) {
0282         const EditorToPropertyMap::iterator it = m_editorToProperty.find(w);
0283         if (it != m_editorToProperty.end()) {
0284             m_propertyToEditor.remove(it.value());
0285             m_editorToProperty.erase(it);
0286         }
0287         if (m_editedWidget == w) {
0288             m_editedWidget = 0;
0289             m_editedItem = 0;
0290         }
0291     }
0292 }
0293 
0294 void QtPropertyEditorDelegate::closeEditor(QtProperty *property)
0295 {
0296     if (QWidget *w = m_propertyToEditor.value(property, 0))
0297         w->deleteLater();
0298 }
0299 
0300 QWidget *QtPropertyEditorDelegate::createEditor(QWidget *parent,
0301         const QStyleOptionViewItem &, const QModelIndex &index) const
0302 {
0303     if (index.column() == 1 && m_editorPrivate) {
0304         QtProperty *property = m_editorPrivate->indexToProperty(index);
0305         QTreeWidgetItem *item = m_editorPrivate->indexToItem(index);
0306         if (property && item && (item->flags() & Qt::ItemIsEnabled)) {
0307             QWidget *editor = m_editorPrivate->createEditor(property, parent);
0308             if (editor) {
0309                 editor->setAutoFillBackground(true);
0310                 editor->installEventFilter(const_cast<QtPropertyEditorDelegate *>(this));
0311                 connect(editor, SIGNAL(destroyed(QObject*)), this, SLOT(slotEditorDestroyed(QObject*)));
0312                 m_propertyToEditor[property] = editor;
0313                 m_editorToProperty[editor] = property;
0314                 m_editedItem = item;
0315                 m_editedWidget = editor;
0316             }
0317             return editor;
0318         }
0319     }
0320     return 0;
0321 }
0322 
0323 void QtPropertyEditorDelegate::updateEditorGeometry(QWidget *editor,
0324         const QStyleOptionViewItem &option, const QModelIndex &index) const
0325 {
0326     Q_UNUSED(index)
0327     editor->setGeometry(option.rect.adjusted(0, 0, 0, -1));
0328 }
0329 
0330 void QtPropertyEditorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
0331             const QModelIndex &index) const
0332 {
0333     bool hasValue = true;
0334     if (m_editorPrivate) {
0335         QtProperty *property = m_editorPrivate->indexToProperty(index);
0336         if (property)
0337             hasValue = property->hasValue();
0338     }
0339     QStyleOptionViewItem opt = option;
0340     if ((m_editorPrivate && index.column() == 0) || !hasValue) {
0341         QtProperty *property = m_editorPrivate->indexToProperty(index);
0342         if (property && property->isModified()) {
0343             opt.font.setBold(true);
0344             opt.fontMetrics = QFontMetrics(opt.font);
0345         }
0346     }
0347     QColor c;
0348     if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) {
0349         c = opt.palette.color(QPalette::Dark);
0350         opt.palette.setColor(QPalette::Text, opt.palette.color(QPalette::BrightText));
0351     } else {
0352         c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index));
0353         if (c.isValid() && (opt.features & QStyleOptionViewItem::Alternate))
0354             c = c.lighter(112);
0355     }
0356     if (c.isValid())
0357         painter->fillRect(option.rect, c);
0358     opt.state &= ~QStyle::State_HasFocus;
0359     QItemDelegate::paint(painter, opt, index);
0360 
0361     opt.palette.setCurrentColorGroup(QPalette::Active);
0362     QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
0363     painter->save();
0364     painter->setPen(QPen(color));
0365     if (!m_editorPrivate || (!m_editorPrivate->lastColumn(index.column()) && hasValue)) {
0366         int right = (option.direction == Qt::LeftToRight) ? option.rect.right() : option.rect.left();
0367         painter->drawLine(right, option.rect.y(), right, option.rect.bottom());
0368     }
0369     painter->restore();
0370 }
0371 
0372 QSize QtPropertyEditorDelegate::sizeHint(const QStyleOptionViewItem &option,
0373             const QModelIndex &index) const
0374 {
0375     return QItemDelegate::sizeHint(option, index) + QSize(3, 4);
0376 }
0377 
0378 bool QtPropertyEditorDelegate::eventFilter(QObject *object, QEvent *event)
0379 {
0380     if (event->type() == QEvent::FocusOut) {
0381         QFocusEvent *fe = static_cast<QFocusEvent *>(event);
0382         if (fe->reason() == Qt::ActiveWindowFocusReason)
0383             return false;
0384     }
0385     return QItemDelegate::eventFilter(object, event);
0386 }
0387 
0388 //  -------- QtTreePropertyBrowserPrivate implementation
0389 QtTreePropertyBrowserPrivate::QtTreePropertyBrowserPrivate() :
0390     m_treeWidget(0),
0391     m_headerVisible(true),
0392     m_resizeMode(QtTreePropertyBrowser::Stretch),
0393     m_delegate(0),
0394     m_markPropertiesWithoutValue(false),
0395     m_browserChangedBlocked(false)
0396 {
0397 }
0398 
0399 // Draw an icon indicating opened/closing branches
0400 static QIcon drawIndicatorIcon(const QPalette &palette, QStyle *style)
0401 {
0402     QPixmap pix(14, 14);
0403     pix.fill(Qt::transparent);
0404     QStyleOption branchOption;
0405     branchOption.rect = QRect(2, 2, 9, 9); // ### hardcoded in qcommonstyle.cpp
0406     branchOption.palette = palette;
0407     branchOption.state = QStyle::State_Children;
0408 
0409     QPainter p;
0410     // Draw closed state
0411     p.begin(&pix);
0412     style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
0413     p.end();
0414     QIcon rc = pix;
0415     rc.addPixmap(pix, QIcon::Selected, QIcon::Off);
0416     // Draw opened state
0417     branchOption.state |= QStyle::State_Open;
0418     pix.fill(Qt::transparent);
0419     p.begin(&pix);
0420     style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
0421     p.end();
0422 
0423     rc.addPixmap(pix, QIcon::Normal, QIcon::On);
0424     rc.addPixmap(pix, QIcon::Selected, QIcon::On);
0425     return rc;
0426 }
0427 
0428 void QtTreePropertyBrowserPrivate::init(QWidget *parent)
0429 {
0430     QHBoxLayout *layout = new QHBoxLayout(parent);
0431     layout->setContentsMargins(0, 0, 0, 0);
0432     m_treeWidget = new QtPropertyEditorView(parent);
0433     m_treeWidget->setEditorPrivate(this);
0434     m_treeWidget->setIconSize(QSize(18, 18));
0435     layout->addWidget(m_treeWidget);
0436 
0437     m_treeWidget->setColumnCount(2);
0438     QStringList labels;
0439     labels.append(QCoreApplication::translate("QtTreePropertyBrowser", "Property"));
0440     labels.append(QCoreApplication::translate("QtTreePropertyBrowser", "Value"));
0441     m_treeWidget->setHeaderLabels(labels);
0442     m_treeWidget->setAlternatingRowColors(true);
0443     m_treeWidget->setEditTriggers(QAbstractItemView::EditKeyPressed);
0444     m_delegate = new QtPropertyEditorDelegate(parent);
0445     m_delegate->setEditorPrivate(this);
0446     m_treeWidget->setItemDelegate(m_delegate);
0447     m_treeWidget->header()->setSectionsMovable(false);
0448     m_treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch);
0449 
0450     m_expandIcon = drawIndicatorIcon(q_ptr->palette(), q_ptr->style());
0451 
0452     QObject::connect(m_treeWidget, SIGNAL(collapsed(QModelIndex)), q_ptr, SLOT(slotCollapsed(QModelIndex)));
0453     QObject::connect(m_treeWidget, SIGNAL(expanded(QModelIndex)), q_ptr, SLOT(slotExpanded(QModelIndex)));
0454     QObject::connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), q_ptr, SLOT(slotCurrentTreeItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
0455 }
0456 
0457 QtBrowserItem *QtTreePropertyBrowserPrivate::currentItem() const
0458 {
0459     if (QTreeWidgetItem *treeItem = m_treeWidget->currentItem())
0460         return m_itemToIndex.value(treeItem);
0461     return 0;
0462 }
0463 
0464 void QtTreePropertyBrowserPrivate::setCurrentItem(QtBrowserItem *browserItem, bool block)
0465 {
0466     const bool blocked = block ? m_treeWidget->blockSignals(true) : false;
0467     if (browserItem == 0)
0468         m_treeWidget->setCurrentItem(0);
0469     else
0470         m_treeWidget->setCurrentItem(m_indexToItem.value(browserItem));
0471     if (block)
0472         m_treeWidget->blockSignals(blocked);
0473 }
0474 
0475 QtProperty *QtTreePropertyBrowserPrivate::indexToProperty(const QModelIndex &index) const
0476 {
0477     QTreeWidgetItem *item = m_treeWidget->indexToItem(index);
0478     QtBrowserItem *idx = m_itemToIndex.value(item);
0479     if (idx)
0480         return idx->property();
0481     return 0;
0482 }
0483 
0484 QtBrowserItem *QtTreePropertyBrowserPrivate::indexToBrowserItem(const QModelIndex &index) const
0485 {
0486     QTreeWidgetItem *item = m_treeWidget->indexToItem(index);
0487     return m_itemToIndex.value(item);
0488 }
0489 
0490 QTreeWidgetItem *QtTreePropertyBrowserPrivate::indexToItem(const QModelIndex &index) const
0491 {
0492     return m_treeWidget->indexToItem(index);
0493 }
0494 
0495 bool QtTreePropertyBrowserPrivate::lastColumn(int column) const
0496 {
0497     return m_treeWidget->header()->visualIndex(column) == m_treeWidget->columnCount() - 1;
0498 }
0499 
0500 void QtTreePropertyBrowserPrivate::disableItem(QTreeWidgetItem *item) const
0501 {
0502     Qt::ItemFlags flags = item->flags();
0503     if (flags & Qt::ItemIsEnabled) {
0504         flags &= ~Qt::ItemIsEnabled;
0505         item->setFlags(flags);
0506         m_delegate->closeEditor(m_itemToIndex[item]->property());
0507         const int childCount = item->childCount();
0508         for (int i = 0; i < childCount; i++) {
0509             QTreeWidgetItem *child = item->child(i);
0510             disableItem(child);
0511         }
0512     }
0513 }
0514 
0515 void QtTreePropertyBrowserPrivate::enableItem(QTreeWidgetItem *item) const
0516 {
0517     Qt::ItemFlags flags = item->flags();
0518     flags |= Qt::ItemIsEnabled;
0519     item->setFlags(flags);
0520     const int childCount = item->childCount();
0521     for (int i = 0; i < childCount; i++) {
0522         QTreeWidgetItem *child = item->child(i);
0523         QtProperty *property = m_itemToIndex[child]->property();
0524         if (property->isEnabled()) {
0525             enableItem(child);
0526         }
0527     }
0528 }
0529 
0530 bool QtTreePropertyBrowserPrivate::hasValue(QTreeWidgetItem *item) const
0531 {
0532     QtBrowserItem *browserItem = m_itemToIndex.value(item);
0533     if (browserItem)
0534         return browserItem->property()->hasValue();
0535     return false;
0536 }
0537 
0538 void QtTreePropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex)
0539 {
0540     QTreeWidgetItem *afterItem = m_indexToItem.value(afterIndex);
0541     QTreeWidgetItem *parentItem = m_indexToItem.value(index->parent());
0542 
0543     QTreeWidgetItem *newItem = 0;
0544     if (parentItem) {
0545         newItem = new QTreeWidgetItem(parentItem, afterItem);
0546     } else {
0547         newItem = new QTreeWidgetItem(m_treeWidget, afterItem);
0548     }
0549     m_itemToIndex[newItem] = index;
0550     m_indexToItem[index] = newItem;
0551 
0552     newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
0553     newItem->setExpanded(true);
0554 
0555     updateItem(newItem);
0556 }
0557 
0558 void QtTreePropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index)
0559 {
0560     QTreeWidgetItem *item = m_indexToItem.value(index);
0561 
0562     if (m_treeWidget->currentItem() == item) {
0563         m_treeWidget->setCurrentItem(0);
0564     }
0565 
0566     delete item;
0567 
0568     m_indexToItem.remove(index);
0569     m_itemToIndex.remove(item);
0570     m_indexToBackgroundColor.remove(index);
0571 }
0572 
0573 void QtTreePropertyBrowserPrivate::propertyChanged(QtBrowserItem *index)
0574 {
0575     QTreeWidgetItem *item = m_indexToItem.value(index);
0576 
0577     updateItem(item);
0578 }
0579 
0580 void QtTreePropertyBrowserPrivate::updateItem(QTreeWidgetItem *item)
0581 {
0582     QtProperty *property = m_itemToIndex[item]->property();
0583     QIcon expandIcon;
0584     if (property->hasValue()) {
0585         const QString valueToolTip = property->valueToolTip();
0586         const QString valueText = property->valueText();
0587         item->setToolTip(1, valueToolTip.isEmpty() ? valueText : valueToolTip);
0588         item->setIcon(1, property->valueIcon());
0589         item->setText(1, valueText);
0590     } else if (markPropertiesWithoutValue() && !m_treeWidget->rootIsDecorated()) {
0591         expandIcon = m_expandIcon;
0592     }
0593     item->setIcon(0, expandIcon);
0594     item->setFirstColumnSpanned(!property->hasValue());
0595     const QString descriptionToolTip  = property->descriptionToolTip();
0596     const QString propertyName = property->propertyName();
0597     item->setToolTip(0, descriptionToolTip.isEmpty() ? propertyName : descriptionToolTip);
0598     item->setStatusTip(0, property->statusTip());
0599     item->setWhatsThis(0, property->whatsThis());
0600     item->setText(0, propertyName);
0601     bool wasEnabled = item->flags() & Qt::ItemIsEnabled;
0602     bool isEnabled = wasEnabled;
0603     if (property->isEnabled()) {
0604         QTreeWidgetItem *parent = item->parent();
0605         if (!parent || (parent->flags() & Qt::ItemIsEnabled))
0606             isEnabled = true;
0607         else
0608             isEnabled = false;
0609     } else {
0610         isEnabled = false;
0611     }
0612     if (wasEnabled != isEnabled) {
0613         if (isEnabled)
0614             enableItem(item);
0615         else
0616             disableItem(item);
0617     }
0618     m_treeWidget->viewport()->update();
0619 }
0620 
0621 QColor QtTreePropertyBrowserPrivate::calculatedBackgroundColor(QtBrowserItem *item) const
0622 {
0623     QtBrowserItem *i = item;
0624     const QMap<QtBrowserItem *, QColor>::const_iterator itEnd = m_indexToBackgroundColor.constEnd();
0625     while (i) {
0626         QMap<QtBrowserItem *, QColor>::const_iterator it = m_indexToBackgroundColor.constFind(i);
0627         if (it != itEnd)
0628             return it.value();
0629         i = i->parent();
0630     }
0631     return QColor();
0632 }
0633 
0634 void QtTreePropertyBrowserPrivate::slotCollapsed(const QModelIndex &index)
0635 {
0636     QTreeWidgetItem *item = indexToItem(index);
0637     QtBrowserItem *idx = m_itemToIndex.value(item);
0638     if (item)
0639         Q_EMIT q_ptr->collapsed(idx);
0640 }
0641 
0642 void QtTreePropertyBrowserPrivate::slotExpanded(const QModelIndex &index)
0643 {
0644     QTreeWidgetItem *item = indexToItem(index);
0645     QtBrowserItem *idx = m_itemToIndex.value(item);
0646     if (item)
0647         Q_EMIT q_ptr->expanded(idx);
0648 }
0649 
0650 void QtTreePropertyBrowserPrivate::slotCurrentBrowserItemChanged(QtBrowserItem *item)
0651 {
0652     if (!m_browserChangedBlocked && item != currentItem())
0653         setCurrentItem(item, true);
0654 }
0655 
0656 void QtTreePropertyBrowserPrivate::slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *)
0657 {
0658     QtBrowserItem *browserItem = newItem ? m_itemToIndex.value(newItem) : 0;
0659     m_browserChangedBlocked = true;
0660     q_ptr->setCurrentItem(browserItem);
0661     m_browserChangedBlocked = false;
0662 }
0663 
0664 QTreeWidgetItem *QtTreePropertyBrowserPrivate::editedItem() const
0665 {
0666     return m_delegate->editedItem();
0667 }
0668 
0669 void QtTreePropertyBrowserPrivate::editItem(QtBrowserItem *browserItem)
0670 {
0671     if (QTreeWidgetItem *treeItem = m_indexToItem.value(browserItem, 0)) {
0672         m_treeWidget->setCurrentItem (treeItem, 1);
0673         m_treeWidget->editItem(treeItem, 1);
0674     }
0675 }
0676 
0677 /*!
0678     \class QtTreePropertyBrowser
0679     \internal
0680     \inmodule QtDesigner
0681     \since 4.4
0682 
0683     \brief The QtTreePropertyBrowser class provides QTreeWidget based
0684     property browser.
0685 
0686     A property browser is a widget that enables the user to edit a
0687     given set of properties. Each property is represented by a label
0688     specifying the property's name, and an editing widget (e.g. a line
0689     edit or a combobox) holding its value. A property can have zero or
0690     more subproperties.
0691 
0692     QtTreePropertyBrowser provides a tree based view for all nested
0693     properties, i.e. properties that have subproperties can be in an
0694     expanded (subproperties are visible) or collapsed (subproperties
0695     are hidden) state. For example:
0696 
0697     \image qttreepropertybrowser.png
0698 
0699     Use the QtAbstractPropertyBrowser API to add, insert and remove
0700     properties from an instance of the QtTreePropertyBrowser class.
0701     The properties themselves are created and managed by
0702     implementations of the QtAbstractPropertyManager class.
0703 
0704     \sa QtGroupBoxPropertyBrowser, QtAbstractPropertyBrowser
0705 */
0706 
0707 /*!
0708     \fn void QtTreePropertyBrowser::collapsed(QtBrowserItem *item)
0709 
0710     This signal is emitted when the \a item is collapsed.
0711 
0712     \sa expanded(), setExpanded()
0713 */
0714 
0715 /*!
0716     \fn void QtTreePropertyBrowser::expanded(QtBrowserItem *item)
0717 
0718     This signal is emitted when the \a item is expanded.
0719 
0720     \sa collapsed(), setExpanded()
0721 */
0722 
0723 /*!
0724     Creates a property browser with the given \a parent.
0725 */
0726 QtTreePropertyBrowser::QtTreePropertyBrowser(QWidget *parent)
0727     : QtAbstractPropertyBrowser(parent), d_ptr(new QtTreePropertyBrowserPrivate)
0728 {
0729     d_ptr->q_ptr = this;
0730 
0731     d_ptr->init(this);
0732     connect(this, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentBrowserItemChanged(QtBrowserItem*)));
0733 }
0734 
0735 /*!
0736     Destroys this property browser.
0737 
0738     Note that the properties that were inserted into this browser are
0739     \e not destroyed since they may still be used in other
0740     browsers. The properties are owned by the manager that created
0741     them.
0742 
0743     \sa QtProperty, QtAbstractPropertyManager
0744 */
0745 QtTreePropertyBrowser::~QtTreePropertyBrowser()
0746 {
0747 }
0748 
0749 /*!
0750     \property QtTreePropertyBrowser::indentation
0751     \brief indentation of the items in the tree view.
0752 */
0753 int QtTreePropertyBrowser::indentation() const
0754 {
0755     return d_ptr->m_treeWidget->indentation();
0756 }
0757 
0758 void QtTreePropertyBrowser::setIndentation(int i)
0759 {
0760     d_ptr->m_treeWidget->setIndentation(i);
0761 }
0762 
0763 /*!
0764   \property QtTreePropertyBrowser::rootIsDecorated
0765   \brief whether to show controls for expanding and collapsing root items.
0766 */
0767 bool QtTreePropertyBrowser::rootIsDecorated() const
0768 {
0769     return d_ptr->m_treeWidget->rootIsDecorated();
0770 }
0771 
0772 void QtTreePropertyBrowser::setRootIsDecorated(bool show)
0773 {
0774     d_ptr->m_treeWidget->setRootIsDecorated(show);
0775     for (auto it = d_ptr->m_itemToIndex.cbegin(), end = d_ptr->m_itemToIndex.cend(); it != end; ++it) {
0776         QtProperty *property = it.value()->property();
0777         if (!property->hasValue())
0778             d_ptr->updateItem(it.key());
0779     }
0780 }
0781 
0782 /*!
0783   \property QtTreePropertyBrowser::alternatingRowColors
0784   \brief whether to draw the background using alternating colors.
0785   By default this property is set to true.
0786 */
0787 bool QtTreePropertyBrowser::alternatingRowColors() const
0788 {
0789     return d_ptr->m_treeWidget->alternatingRowColors();
0790 }
0791 
0792 void QtTreePropertyBrowser::setAlternatingRowColors(bool enable)
0793 {
0794     d_ptr->m_treeWidget->setAlternatingRowColors(enable);
0795 }
0796 
0797 /*!
0798   \property QtTreePropertyBrowser::headerVisible
0799   \brief whether to show the header.
0800 */
0801 bool QtTreePropertyBrowser::isHeaderVisible() const
0802 {
0803     return d_ptr->m_headerVisible;
0804 }
0805 
0806 void QtTreePropertyBrowser::setHeaderVisible(bool visible)
0807 {
0808     if (d_ptr->m_headerVisible == visible)
0809         return;
0810 
0811     d_ptr->m_headerVisible = visible;
0812     d_ptr->m_treeWidget->header()->setVisible(visible);
0813 }
0814 
0815 /*!
0816   \enum QtTreePropertyBrowser::ResizeMode
0817 
0818   The resize mode specifies the behavior of the header sections.
0819 
0820   \value Interactive The user can resize the sections.
0821   The sections can also be resized programmatically using setSplitterPosition().
0822 
0823   \value Fixed The user cannot resize the section.
0824   The section can only be resized programmatically using setSplitterPosition().
0825 
0826   \value Stretch QHeaderView will automatically resize the section to fill the available space.
0827   The size cannot be changed by the user or programmatically.
0828 
0829   \value ResizeToContents QHeaderView will automatically resize the section to its optimal
0830   size based on the contents of the entire column.
0831   The size cannot be changed by the user or programmatically.
0832 
0833   \sa setResizeMode()
0834 */
0835 
0836 /*!
0837     \property QtTreePropertyBrowser::resizeMode
0838     \brief the resize mode of setions in the header.
0839 */
0840 
0841 QtTreePropertyBrowser::ResizeMode QtTreePropertyBrowser::resizeMode() const
0842 {
0843     return d_ptr->m_resizeMode;
0844 }
0845 
0846 void QtTreePropertyBrowser::setResizeMode(QtTreePropertyBrowser::ResizeMode mode)
0847 {
0848     if (d_ptr->m_resizeMode == mode)
0849         return;
0850 
0851     d_ptr->m_resizeMode = mode;
0852     QHeaderView::ResizeMode m = QHeaderView::Stretch;
0853     switch (mode) {
0854         case QtTreePropertyBrowser::Interactive:      m = QHeaderView::Interactive;      break;
0855         case QtTreePropertyBrowser::Fixed:            m = QHeaderView::Fixed;            break;
0856         case QtTreePropertyBrowser::ResizeToContents: m = QHeaderView::ResizeToContents; break;
0857         case QtTreePropertyBrowser::Stretch:
0858         default:                                      m = QHeaderView::Stretch;          break;
0859     }
0860     d_ptr->m_treeWidget->header()->setSectionResizeMode(m);
0861 }
0862 
0863 /*!
0864     \property QtTreePropertyBrowser::splitterPosition
0865     \brief the position of the splitter between the colunms.
0866 */
0867 
0868 int QtTreePropertyBrowser::splitterPosition() const
0869 {
0870     return d_ptr->m_treeWidget->header()->sectionSize(0);
0871 }
0872 
0873 void QtTreePropertyBrowser::setSplitterPosition(int position)
0874 {
0875     d_ptr->m_treeWidget->header()->resizeSection(0, position);
0876 }
0877 
0878 /*!
0879     Sets the \a item to either collapse or expanded, depending on the value of \a expanded.
0880 
0881     \sa isExpanded(), expanded(), collapsed()
0882 */
0883 
0884 void QtTreePropertyBrowser::setExpanded(QtBrowserItem *item, bool expanded)
0885 {
0886     QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item);
0887     if (treeItem)
0888         treeItem->setExpanded(expanded);
0889 }
0890 
0891 /*!
0892     Returns true if the \a item is expanded; otherwise returns false.
0893 
0894     \sa setExpanded()
0895 */
0896 
0897 bool QtTreePropertyBrowser::isExpanded(QtBrowserItem *item) const
0898 {
0899     QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item);
0900     if (treeItem)
0901         return treeItem->isExpanded();
0902     return false;
0903 }
0904 
0905 /*!
0906     Returns true if the \a item is visible; otherwise returns false.
0907 
0908     \sa setItemVisible()
0909     \since 4.5
0910 */
0911 
0912 bool QtTreePropertyBrowser::isItemVisible(QtBrowserItem *item) const
0913 {
0914     if (const QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item))
0915         return !treeItem->isHidden();
0916     return false;
0917 }
0918 
0919 /*!
0920     Sets the \a item to be visible, depending on the value of \a visible.
0921 
0922    \sa isItemVisible()
0923    \since 4.5
0924 */
0925 
0926 void QtTreePropertyBrowser::setItemVisible(QtBrowserItem *item, bool visible)
0927 {
0928     if (QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item))
0929         treeItem->setHidden(!visible);
0930 }
0931 
0932 /*!
0933     Sets the \a item's background color to \a color. Note that while item's background
0934     is rendered every second row is being drawn with alternate color (which is a bit lighter than items \a color)
0935 
0936     \sa backgroundColor(), calculatedBackgroundColor()
0937 */
0938 
0939 void QtTreePropertyBrowser::setBackgroundColor(QtBrowserItem *item, const QColor &color)
0940 {
0941     if (!d_ptr->m_indexToItem.contains(item))
0942         return;
0943     if (color.isValid())
0944         d_ptr->m_indexToBackgroundColor[item] = color;
0945     else
0946         d_ptr->m_indexToBackgroundColor.remove(item);
0947     d_ptr->m_treeWidget->viewport()->update();
0948 }
0949 
0950 /*!
0951     Returns the \a item's color. If there is no color set for item it returns invalid color.
0952 
0953     \sa calculatedBackgroundColor(), setBackgroundColor()
0954 */
0955 
0956 QColor QtTreePropertyBrowser::backgroundColor(QtBrowserItem *item) const
0957 {
0958     return d_ptr->m_indexToBackgroundColor.value(item);
0959 }
0960 
0961 /*!
0962     Returns the \a item's color. If there is no color set for item it returns parent \a item's
0963     color (if there is no color set for parent it returns grandparent's color and so on). In case
0964     the color is not set for \a item and it's top level item it returns invalid color.
0965 
0966     \sa backgroundColor(), setBackgroundColor()
0967 */
0968 
0969 QColor QtTreePropertyBrowser::calculatedBackgroundColor(QtBrowserItem *item) const
0970 {
0971     return d_ptr->calculatedBackgroundColor(item);
0972 }
0973 
0974 /*!
0975     \property QtTreePropertyBrowser::propertiesWithoutValueMarked
0976     \brief whether to enable or disable marking properties without value.
0977 
0978     When marking is enabled the item's background is rendered in dark color and item's
0979     foreground is rendered with light color.
0980 
0981     \sa propertiesWithoutValueMarked()
0982 */
0983 void QtTreePropertyBrowser::setPropertiesWithoutValueMarked(bool mark)
0984 {
0985     if (d_ptr->m_markPropertiesWithoutValue == mark)
0986         return;
0987 
0988     d_ptr->m_markPropertiesWithoutValue = mark;
0989     for (auto it = d_ptr->m_itemToIndex.cbegin(), end = d_ptr->m_itemToIndex.cend(); it != end; ++it) {
0990         QtProperty *property = it.value()->property();
0991         if (!property->hasValue())
0992             d_ptr->updateItem(it.key());
0993     }
0994     d_ptr->m_treeWidget->viewport()->update();
0995 }
0996 
0997 bool QtTreePropertyBrowser::propertiesWithoutValueMarked() const
0998 {
0999     return d_ptr->m_markPropertiesWithoutValue;
1000 }
1001 
1002 /*!
1003     \reimp
1004 */
1005 void QtTreePropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem)
1006 {
1007     d_ptr->propertyInserted(item, afterItem);
1008 }
1009 
1010 /*!
1011     \reimp
1012 */
1013 void QtTreePropertyBrowser::itemRemoved(QtBrowserItem *item)
1014 {
1015     d_ptr->propertyRemoved(item);
1016 }
1017 
1018 /*!
1019     \reimp
1020 */
1021 void QtTreePropertyBrowser::itemChanged(QtBrowserItem *item)
1022 {
1023     d_ptr->propertyChanged(item);
1024 }
1025 
1026 /*!
1027     Sets the current item to \a item and opens the relevant editor for it.
1028 */
1029 void QtTreePropertyBrowser::editItem(QtBrowserItem *item)
1030 {
1031     d_ptr->editItem(item);
1032 }
1033 
1034 QT_END_NAMESPACE
1035 
1036 #include "moc_qttreepropertybrowser.cpp"
1037 #include "qttreepropertybrowser.moc"