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"