1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the Qt Solutions component.
7 **
8 ** $QT_BEGIN_LICENSE:BSD$
9 ** You may use this file under the terms of the BSD license as follows:
10 **
11 ** "Redistribution and use in source and binary forms, with or without
12 ** modification, are permitted provided that the following conditions are
13 ** met:
14 **   * Redistributions of source code must retain the above copyright
15 **     notice, this list of conditions and the following disclaimer.
16 **   * Redistributions in binary form must reproduce the above copyright
17 **     notice, this list of conditions and the following disclaimer in
18 **     the documentation and/or other materials provided with the
19 **     distribution.
20 **   * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
21 **     of its contributors may be used to endorse or promote products derived
22 **     from this software without specific prior written permission.
23 **
24 **
25 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
36 **
37 ** $QT_END_LICENSE$
38 **
39 ****************************************************************************/
40 
41 
42 #include "qttreepropertybrowser.h"
43 #include <QSet>
44 #include <QIcon>
45 #include <QTreeWidget>
46 #include <QItemDelegate>
47 #include <QHBoxLayout>
48 #include <QHeaderView>
49 #include <QPainter>
50 #include <QApplication>
51 #include <QFocusEvent>
52 #include <QStyle>
53 #include <QPalette>
54 #include <QScreen>
55 
56 #ifndef Q_OS_MAC
defaultDpiScale()57 static qreal defaultDpiScale()
58 {
59     if (const QScreen *screen = QGuiApplication::primaryScreen())
60         return screen->logicalDotsPerInchX() / 96.0;
61     return 1.0;
62 }
63 #endif
64 
dpiScaled(qreal value)65 static qreal dpiScaled(qreal value)
66 {
67 #ifdef Q_OS_MAC
68     // On mac the DPI is always 72 so we should not scale it
69     return value;
70 #else
71     static const qreal scale = defaultDpiScale();
72     return value * scale;
73 #endif
74 }
75 
dpiScaled(QSize value)76 static QSize dpiScaled(QSize value)
77 {
78     return QSize(qRound(dpiScaled(value.width())),
79                  qRound(dpiScaled(value.height())));
80 }
81 
82 
83 #if QT_VERSION >= 0x040400
84 QT_BEGIN_NAMESPACE
85 #endif
86 
87 class QtPropertyEditorView;
88 
89 class QtTreePropertyBrowserPrivate
90 {
91     QtTreePropertyBrowser *q_ptr;
92     Q_DECLARE_PUBLIC(QtTreePropertyBrowser)
93 
94 public:
95     QtTreePropertyBrowserPrivate();
96     void init(QWidget *parent);
97 
98     void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex);
99     void propertyRemoved(QtBrowserItem *index);
100     void propertyChanged(QtBrowserItem *index);
createEditor(QtProperty * property,QWidget * parent) const101     QWidget *createEditor(QtProperty *property, QWidget *parent) const
102         { return q_ptr->createEditor(property, parent); }
103     QtProperty *indexToProperty(const QModelIndex &index) const;
104     QTreeWidgetItem *indexToItem(const QModelIndex &index) const;
105     QtBrowserItem *indexToBrowserItem(const QModelIndex &index) const;
106     bool lastColumn(int column) const;
107     void disableItem(QTreeWidgetItem *item) const;
108     void enableItem(QTreeWidgetItem *item) const;
109     bool hasValue(QTreeWidgetItem *item) const;
110 
111     void slotCollapsed(const QModelIndex &index);
112     void slotExpanded(const QModelIndex &index);
113 
114     QColor calculatedBackgroundColor(QtBrowserItem *item) const;
115 
treeWidget() const116     QtPropertyEditorView *treeWidget() const { return m_treeWidget; }
markPropertiesWithoutValue() const117     bool markPropertiesWithoutValue() const { return m_markPropertiesWithoutValue; }
118 
119     QtBrowserItem *currentItem() const;
120     void setCurrentItem(QtBrowserItem *browserItem, bool block);
121     void editItem(QtBrowserItem *browserItem);
122 
123     QList<QtBrowserItem*> selectedItems() const;
124 
125     void slotCurrentBrowserItemChanged(QtBrowserItem *item);
126     void slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *);
127     void slotItemSelectionChanged();
128 
129     QTreeWidgetItem *editedItem() const;
130     QtBrowserItem *editedBrowserItem() const;
131 
132 private:
133     void updateItem(QTreeWidgetItem *item);
134 
135     QMap<QtBrowserItem *, QTreeWidgetItem *> m_indexToItem;
136     QMap<QTreeWidgetItem *, QtBrowserItem *> m_itemToIndex;
137 
138     QMap<QtBrowserItem *, QColor> m_indexToBackgroundColor;
139 
140     QtPropertyEditorView *m_treeWidget;
141 
142     bool m_headerVisible;
143     bool m_allowMultiSelection;
144     QtTreePropertyBrowser::ResizeMode m_resizeMode;
145     class QtPropertyEditorDelegate *m_delegate;
146     bool m_markPropertiesWithoutValue;
147     bool m_browserChangedBlocked;
148     QIcon m_expandIcon;
149 };
150 
151 // ------------ QtPropertyEditorView
152 class QtPropertyEditorView : public QTreeWidget
153 {
154     Q_OBJECT
155 public:
156     explicit QtPropertyEditorView(QWidget *parent = 0);
157 
setEditorPrivate(QtTreePropertyBrowserPrivate * editorPrivate)158     void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate)
159         { m_editorPrivate = editorPrivate; }
160 
indexToItem(const QModelIndex & index) const161     QTreeWidgetItem *indexToItem(const QModelIndex &index) const
162         { return itemFromIndex(index); }
163 
164 protected:
165     void keyPressEvent(QKeyEvent *event);
166     void mousePressEvent(QMouseEvent *event);
167     void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
168 
169 private:
170     QtTreePropertyBrowserPrivate *m_editorPrivate;
171 };
172 
QtPropertyEditorView(QWidget * parent)173 QtPropertyEditorView::QtPropertyEditorView(QWidget *parent) :
174     QTreeWidget(parent),
175     m_editorPrivate(0)
176 {
177     setUniformRowHeights(true);
178     connect(header(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(resizeColumnToContents(int)));
179 }
180 
drawRow(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const181 void QtPropertyEditorView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
182 {
183     QStyleOptionViewItem opt = option;
184     bool hasValue = true;
185     if (m_editorPrivate) {
186         QtProperty *property = m_editorPrivate->indexToProperty(index);
187         if (property)
188             hasValue = property->hasValue();
189     }
190     if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) {
191         const QColor c = option.palette.color(QPalette::Dark);
192         painter->fillRect(option.rect, c);
193         opt.palette.setColor(QPalette::AlternateBase, c);
194     } else {
195         const QColor c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index));
196         if (c.isValid()) {
197             painter->fillRect(option.rect, c);
198             opt.palette.setColor(QPalette::AlternateBase, c.lighter(112));
199         }
200     }
201     QTreeWidget::drawRow(painter, opt, index);
202     QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
203     painter->save();
204     painter->setPen(QPen(color));
205     painter->drawLine(opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
206     painter->restore();
207 }
208 
keyPressEvent(QKeyEvent * event)209 void QtPropertyEditorView::keyPressEvent(QKeyEvent *event)
210 {
211     switch (event->key()) {
212     case Qt::Key_Return:
213     case Qt::Key_Enter:
214     case Qt::Key_Space: // Trigger Edit
215         if (!m_editorPrivate->editedItem())
216             if (const QTreeWidgetItem *item = currentItem())
217                 if (item->columnCount() >= 2 && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) {
218                     event->accept();
219                     // If the current position is at column 0, move to 1.
220                     QModelIndex index = currentIndex();
221                     if (index.column() == 0) {
222                         index = index.sibling(index.row(), 1);
223                         setCurrentIndex(index);
224                     }
225                     edit(index);
226                     return;
227                 }
228         break;
229     default:
230         break;
231     }
232     QTreeWidget::keyPressEvent(event);
233 }
234 
mousePressEvent(QMouseEvent * event)235 void QtPropertyEditorView::mousePressEvent(QMouseEvent *event)
236 {
237     QTreeWidget::mousePressEvent(event);
238     QTreeWidgetItem *item = itemAt(event->pos());
239 
240     if (item) {
241         if ((item != m_editorPrivate->editedItem()) && (event->button() == Qt::LeftButton)
242                 && (header()->logicalIndexAt(event->pos().x()) == 1)
243                 && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) {
244             editItem(item, 1);
245         } else if (!m_editorPrivate->hasValue(item) && m_editorPrivate->markPropertiesWithoutValue() && !rootIsDecorated()) {
246             if (event->pos().x() + header()->offset() < 20)
247                 item->setExpanded(!item->isExpanded());
248         }
249     }
250 }
251 
252 // ------------ QtPropertyEditorDelegate
253 class QtPropertyEditorDelegate : public QItemDelegate
254 {
255     Q_OBJECT
256 public:
QtPropertyEditorDelegate(QObject * parent=0)257     explicit QtPropertyEditorDelegate(QObject *parent = 0)
258         : QItemDelegate(parent), m_editorPrivate(0), m_editedItem(0), m_editedWidget(0), m_disablePainting(false)
259     {}
260 
setEditorPrivate(QtTreePropertyBrowserPrivate * editorPrivate)261     void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate)
262     { m_editorPrivate = editorPrivate; }
263 
264     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
265             const QModelIndex &index) const;
266 
267     void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
268             const QModelIndex &index) const;
269 
270     void paint(QPainter *painter, const QStyleOptionViewItem &option,
271             const QModelIndex &index) const;
272 
273     QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
274 
setModelData(QWidget *,QAbstractItemModel *,const QModelIndex &) const275     void setModelData(QWidget *, QAbstractItemModel *,
276             const QModelIndex &) const {}
277 
setEditorData(QWidget *,const QModelIndex &) const278     void setEditorData(QWidget *, const QModelIndex &) const {}
279 
280     bool eventFilter(QObject *object, QEvent *event);
281     void closeEditor(QtProperty *property);
282 
editedItem() const283     QTreeWidgetItem *editedItem() const { return m_editedItem; }
284 
285 protected:
286 
287     void drawDecoration(QPainter *painter, const QStyleOptionViewItem &option,
288             const QRect &rect, const QPixmap &pixmap) const;
289     void drawDisplay(QPainter *painter, const QStyleOptionViewItem &option,
290             const QRect &rect, const QString &text) const;
291 
292 private slots:
293     void slotEditorDestroyed(QObject *object);
294 
295 private:
296     int indentation(const QModelIndex &index) const;
297 
298     typedef QMap<QWidget *, QtProperty *> EditorToPropertyMap;
299     mutable EditorToPropertyMap m_editorToProperty;
300 
301     typedef QMap<QtProperty *, QWidget *> PropertyToEditorMap;
302     mutable PropertyToEditorMap m_propertyToEditor;
303     QtTreePropertyBrowserPrivate *m_editorPrivate;
304     mutable QTreeWidgetItem *m_editedItem;
305     mutable QWidget *m_editedWidget;
306     mutable bool m_disablePainting;
307 };
308 
indentation(const QModelIndex & index) const309 int QtPropertyEditorDelegate::indentation(const QModelIndex &index) const
310 {
311     if (!m_editorPrivate)
312         return 0;
313 
314     QTreeWidgetItem *item = m_editorPrivate->indexToItem(index);
315     int indent = 0;
316     while (item->parent()) {
317         item = item->parent();
318         ++indent;
319     }
320     if (m_editorPrivate->treeWidget()->rootIsDecorated())
321         ++indent;
322     return indent * m_editorPrivate->treeWidget()->indentation();
323 }
324 
slotEditorDestroyed(QObject * object)325 void QtPropertyEditorDelegate::slotEditorDestroyed(QObject *object)
326 {
327     if (QWidget *w = qobject_cast<QWidget *>(object)) {
328         const EditorToPropertyMap::iterator it = m_editorToProperty.find(w);
329         if (it != m_editorToProperty.end()) {
330             m_propertyToEditor.remove(it.value());
331             m_editorToProperty.erase(it);
332         }
333         if (m_editedWidget == w) {
334             m_editedWidget = 0;
335             m_editedItem = 0;
336         }
337     }
338 }
339 
closeEditor(QtProperty * property)340 void QtPropertyEditorDelegate::closeEditor(QtProperty *property)
341 {
342     if (QWidget *w = m_propertyToEditor.value(property, 0))
343         w->deleteLater();
344 }
345 
createEditor(QWidget * parent,const QStyleOptionViewItem &,const QModelIndex & index) const346 QWidget *QtPropertyEditorDelegate::createEditor(QWidget *parent,
347         const QStyleOptionViewItem &, const QModelIndex &index) const
348 {
349     if (index.column() == 1 && m_editorPrivate) {
350         QtProperty *property = m_editorPrivate->indexToProperty(index);
351         QTreeWidgetItem *item = m_editorPrivate->indexToItem(index);
352         if (property && item && (item->flags() & Qt::ItemIsEnabled)) {
353             QWidget *editor = m_editorPrivate->createEditor(property, parent);
354             if (editor) {
355                 editor->setAutoFillBackground(true);
356                 editor->installEventFilter(const_cast<QtPropertyEditorDelegate *>(this));
357                 connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *)));
358                 m_propertyToEditor[property] = editor;
359                 m_editorToProperty[editor] = property;
360                 m_editedItem = item;
361                 m_editedWidget = editor;
362             }
363             return editor;
364         }
365     }
366     return 0;
367 }
368 
updateEditorGeometry(QWidget * editor,const QStyleOptionViewItem & option,const QModelIndex & index) const369 void QtPropertyEditorDelegate::updateEditorGeometry(QWidget *editor,
370         const QStyleOptionViewItem &option, const QModelIndex &index) const
371 {
372     Q_UNUSED(index)
373     editor->setGeometry(option.rect.adjusted(0, 0, 0, -1));
374 }
375 
paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const376 void QtPropertyEditorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
377             const QModelIndex &index) const
378 {
379     bool hasValue = true;
380     if (m_editorPrivate) {
381         QtProperty *property = m_editorPrivate->indexToProperty(index);
382         if (property)
383             hasValue = property->hasValue();
384     }
385     QStyleOptionViewItem opt = option;
386     if ((m_editorPrivate && index.column() == 0) || !hasValue) {
387         QtProperty *property = m_editorPrivate->indexToProperty(index);
388         if (property && property->isModified()) {
389             opt.font.setBold(true);
390             opt.fontMetrics = QFontMetrics(opt.font);
391         }
392     }
393     QColor c;
394     if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) {
395         c = opt.palette.color(QPalette::Dark);
396         opt.palette.setColor(QPalette::Text, opt.palette.color(QPalette::BrightText));
397     } else {
398         c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index));
399         if (c.isValid() && (opt.features & QStyleOptionViewItem::Alternate))
400             c = c.lighter(112);
401     }
402     if (c.isValid())
403         painter->fillRect(option.rect, c);
404     opt.state &= ~QStyle::State_HasFocus;
405     if (index.column() == 1) {
406         QTreeWidgetItem *item = m_editorPrivate->indexToItem(index);
407         if (m_editedItem && m_editedItem == item)
408             m_disablePainting = true;
409     }
410     QItemDelegate::paint(painter, opt, index);
411     if (option.type)
412     m_disablePainting = false;
413 
414     opt.palette.setCurrentColorGroup(QPalette::Active);
415     QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
416     painter->save();
417     painter->setPen(QPen(color));
418     if (!m_editorPrivate || (!m_editorPrivate->lastColumn(index.column()) && hasValue)) {
419         int right = (option.direction == Qt::LeftToRight) ? option.rect.right() : option.rect.left();
420         painter->drawLine(right, option.rect.y(), right, option.rect.bottom());
421     }
422     painter->restore();
423 }
424 
drawDecoration(QPainter * painter,const QStyleOptionViewItem & option,const QRect & rect,const QPixmap & pixmap) const425 void QtPropertyEditorDelegate::drawDecoration(QPainter *painter, const QStyleOptionViewItem &option,
426             const QRect &rect, const QPixmap &pixmap) const
427 {
428     if (m_disablePainting)
429         return;
430 
431     QItemDelegate::drawDecoration(painter, option, rect, pixmap);
432 }
433 
drawDisplay(QPainter * painter,const QStyleOptionViewItem & option,const QRect & rect,const QString & text) const434 void QtPropertyEditorDelegate::drawDisplay(QPainter *painter, const QStyleOptionViewItem &option,
435             const QRect &rect, const QString &text) const
436 {
437     if (m_disablePainting)
438         return;
439 
440     QItemDelegate::drawDisplay(painter, option, rect, text);
441 }
442 
sizeHint(const QStyleOptionViewItem & option,const QModelIndex & index) const443 QSize QtPropertyEditorDelegate::sizeHint(const QStyleOptionViewItem &option,
444             const QModelIndex &index) const
445 {
446     return QItemDelegate::sizeHint(option, index) + dpiScaled(QSize(3, 4));
447 }
448 
eventFilter(QObject * object,QEvent * event)449 bool QtPropertyEditorDelegate::eventFilter(QObject *object, QEvent *event)
450 {
451     if (event->type() == QEvent::FocusOut) {
452         QFocusEvent *fe = static_cast<QFocusEvent *>(event);
453         if (fe->reason() == Qt::ActiveWindowFocusReason)
454             return false;
455     }
456     return QItemDelegate::eventFilter(object, event);
457 }
458 
459 //  -------- QtTreePropertyBrowserPrivate implementation
QtTreePropertyBrowserPrivate()460 QtTreePropertyBrowserPrivate::QtTreePropertyBrowserPrivate() :
461     m_treeWidget(0),
462     m_headerVisible(true),
463     m_allowMultiSelection(false),
464     m_resizeMode(QtTreePropertyBrowser::Stretch),
465     m_delegate(0),
466     m_markPropertiesWithoutValue(false),
467     m_browserChangedBlocked(false)
468 {
469 }
470 
471 // Draw an icon indicating opened/closing branches
drawIndicatorIcon(const QPalette & palette,QStyle * style)472 static QIcon drawIndicatorIcon(const QPalette &palette, QStyle *style)
473 {
474     QPixmap pix(14, 14);
475     pix.fill(Qt::transparent);
476     QStyleOption branchOption;
477     QRect r(QPoint(0, 0), pix.size());
478     branchOption.rect = QRect(2, 2, 9, 9); // ### hardcoded in qcommonstyle.cpp
479     branchOption.palette = palette;
480     branchOption.state = QStyle::State_Children;
481 
482     QPainter p;
483     // Draw closed state
484     p.begin(&pix);
485     style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
486     p.end();
487     QIcon rc = pix;
488     rc.addPixmap(pix, QIcon::Selected, QIcon::Off);
489     // Draw opened state
490     branchOption.state |= QStyle::State_Open;
491     pix.fill(Qt::transparent);
492     p.begin(&pix);
493     style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
494     p.end();
495 
496     rc.addPixmap(pix, QIcon::Normal, QIcon::On);
497     rc.addPixmap(pix, QIcon::Selected, QIcon::On);
498     return rc;
499 }
500 
init(QWidget * parent)501 void QtTreePropertyBrowserPrivate::init(QWidget *parent)
502 {
503     QHBoxLayout *layout = new QHBoxLayout(parent);
504     layout->setContentsMargins(0, 0, 0, 0);
505     m_treeWidget = new QtPropertyEditorView(parent);
506     m_treeWidget->setEditorPrivate(this);
507     m_treeWidget->setIconSize(QSize(18, 18));
508     layout->addWidget(m_treeWidget);
509     parent->setFocusProxy(m_treeWidget);
510 
511     m_treeWidget->setColumnCount(2);
512     QStringList labels;
513     labels.append(QCoreApplication::translate("QtTreePropertyBrowser", "Property"));
514     labels.append(QCoreApplication::translate("QtTreePropertyBrowser", "Value"));
515     m_treeWidget->setHeaderLabels(labels);
516     m_treeWidget->setAlternatingRowColors(true);
517     m_treeWidget->setEditTriggers(QAbstractItemView::EditKeyPressed);
518     m_delegate = new QtPropertyEditorDelegate(parent);
519     m_delegate->setEditorPrivate(this);
520     m_treeWidget->setItemDelegate(m_delegate);
521 #if QT_VERSION >= 0x050000
522     m_treeWidget->header()->setSectionsMovable(false);
523     m_treeWidget->header()->setSectionResizeMode(QHeaderView::Stretch);
524 #else
525     m_treeWidget->header()->setMovable(false);
526     m_treeWidget->header()->setResizeMode(QHeaderView::Stretch);
527 #endif
528 
529     m_expandIcon = drawIndicatorIcon(q_ptr->palette(), q_ptr->style());
530 
531     QObject::connect(m_treeWidget, SIGNAL(collapsed(const QModelIndex &)), q_ptr, SLOT(slotCollapsed(const QModelIndex &)));
532     QObject::connect(m_treeWidget, SIGNAL(expanded(const QModelIndex &)), q_ptr, SLOT(slotExpanded(const QModelIndex &)));
533     QObject::connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), q_ptr, SLOT(slotCurrentTreeItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
534     QObject::connect(m_treeWidget, SIGNAL(itemSelectionChanged()), q_ptr, SLOT(slotItemSelectionChanged()));
535 }
536 
currentItem() const537 QtBrowserItem *QtTreePropertyBrowserPrivate::currentItem() const
538 {
539     if (QTreeWidgetItem *treeItem = m_treeWidget->currentItem())
540         return m_itemToIndex.value(treeItem);
541     return 0;
542 }
543 
setCurrentItem(QtBrowserItem * browserItem,bool block)544 void QtTreePropertyBrowserPrivate::setCurrentItem(QtBrowserItem *browserItem, bool block)
545 {
546     const bool blocked = block ? m_treeWidget->blockSignals(true) : false;
547     if (browserItem == 0)
548         m_treeWidget->setCurrentItem(0);
549     else
550         m_treeWidget->setCurrentItem(m_indexToItem.value(browserItem));
551     if (block)
552         m_treeWidget->blockSignals(blocked);
553 }
554 
indexToProperty(const QModelIndex & index) const555 QtProperty *QtTreePropertyBrowserPrivate::indexToProperty(const QModelIndex &index) const
556 {
557     QTreeWidgetItem *item = m_treeWidget->indexToItem(index);
558     QtBrowserItem *idx = m_itemToIndex.value(item);
559     if (idx)
560         return idx->property();
561     return 0;
562 }
563 
indexToBrowserItem(const QModelIndex & index) const564 QtBrowserItem *QtTreePropertyBrowserPrivate::indexToBrowserItem(const QModelIndex &index) const
565 {
566     QTreeWidgetItem *item = m_treeWidget->indexToItem(index);
567     return m_itemToIndex.value(item);
568 }
569 
indexToItem(const QModelIndex & index) const570 QTreeWidgetItem *QtTreePropertyBrowserPrivate::indexToItem(const QModelIndex &index) const
571 {
572     return m_treeWidget->indexToItem(index);
573 }
574 
lastColumn(int column) const575 bool QtTreePropertyBrowserPrivate::lastColumn(int column) const
576 {
577     return m_treeWidget->header()->visualIndex(column) == m_treeWidget->columnCount() - 1;
578 }
579 
disableItem(QTreeWidgetItem * item) const580 void QtTreePropertyBrowserPrivate::disableItem(QTreeWidgetItem *item) const
581 {
582     Qt::ItemFlags flags = item->flags();
583     if (flags & Qt::ItemIsEnabled) {
584         flags &= ~Qt::ItemIsEnabled;
585         item->setFlags(flags);
586         m_delegate->closeEditor(m_itemToIndex[item]->property());
587         const int childCount = item->childCount();
588         for (int i = 0; i < childCount; i++) {
589             QTreeWidgetItem *child = item->child(i);
590             disableItem(child);
591         }
592     }
593 }
594 
enableItem(QTreeWidgetItem * item) const595 void QtTreePropertyBrowserPrivate::enableItem(QTreeWidgetItem *item) const
596 {
597     Qt::ItemFlags flags = item->flags();
598     flags |= Qt::ItemIsEnabled;
599     item->setFlags(flags);
600     const int childCount = item->childCount();
601     for (int i = 0; i < childCount; i++) {
602         QTreeWidgetItem *child = item->child(i);
603         QtProperty *property = m_itemToIndex[child]->property();
604         if (property->isEnabled()) {
605             enableItem(child);
606         }
607     }
608 }
609 
hasValue(QTreeWidgetItem * item) const610 bool QtTreePropertyBrowserPrivate::hasValue(QTreeWidgetItem *item) const
611 {
612     QtBrowserItem *browserItem = m_itemToIndex.value(item);
613     if (browserItem)
614         return browserItem->property()->hasValue();
615     return false;
616 }
617 
propertyInserted(QtBrowserItem * index,QtBrowserItem * afterIndex)618 void QtTreePropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex)
619 {
620     QTreeWidgetItem *afterItem = m_indexToItem.value(afterIndex);
621     QTreeWidgetItem *parentItem = m_indexToItem.value(index->parent());
622 
623     QTreeWidgetItem *newItem = 0;
624     if (parentItem) {
625         newItem = new QTreeWidgetItem(parentItem, afterItem);
626     } else {
627         newItem = new QTreeWidgetItem(m_treeWidget, afterItem);
628     }
629     m_itemToIndex[newItem] = index;
630     m_indexToItem[index] = newItem;
631 
632     newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
633     newItem->setExpanded(true);
634 
635     updateItem(newItem);
636 }
637 
propertyRemoved(QtBrowserItem * index)638 void QtTreePropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index)
639 {
640     QTreeWidgetItem *item = m_indexToItem.value(index);
641 
642     if (m_treeWidget->currentItem() == item) {
643         m_treeWidget->setCurrentItem(0);
644     }
645 
646     delete item;
647 
648     m_indexToItem.remove(index);
649     m_itemToIndex.remove(item);
650     m_indexToBackgroundColor.remove(index);
651 }
652 
propertyChanged(QtBrowserItem * index)653 void QtTreePropertyBrowserPrivate::propertyChanged(QtBrowserItem *index)
654 {
655     QTreeWidgetItem *item = m_indexToItem.value(index);
656 
657     updateItem(item);
658 }
659 
updateItem(QTreeWidgetItem * item)660 void QtTreePropertyBrowserPrivate::updateItem(QTreeWidgetItem *item)
661 {
662     QtProperty *property = m_itemToIndex[item]->property();
663 
664     if (property->nameColor().isValid())
665         item->setForeground(0, QBrush(property->nameColor()));
666     if (property->valueColor().isValid())
667         item->setForeground(1, QBrush(property->valueColor()));
668 
669     QIcon expandIcon;
670     if (property->hasValue()) {
671         QString toolTip = property->toolTip();
672         if (toolTip.isEmpty())
673             toolTip = property->displayText();
674         item->setToolTip(1, toolTip);
675         item->setIcon(1, property->valueIcon());
676         property->displayText().isEmpty() ? item->setText(1, property->valueText()) : item->setText(1, property->displayText());
677     } else if (markPropertiesWithoutValue() && !m_treeWidget->rootIsDecorated()) {
678         expandIcon = m_expandIcon;
679     }
680     item->setIcon(0, expandIcon);
681     item->setFirstColumnSpanned(!property->hasValue());
682     item->setToolTip(0, property->propertyName());
683     item->setStatusTip(0, property->statusTip());
684     item->setWhatsThis(0, property->whatsThis());
685     item->setText(0, property->propertyName());
686     bool wasEnabled = item->flags() & Qt::ItemIsEnabled;
687     bool isEnabled = wasEnabled;
688     if (property->isEnabled()) {
689         QTreeWidgetItem *parent = item->parent();
690         if (!parent || (parent->flags() & Qt::ItemIsEnabled))
691             isEnabled = true;
692         else
693             isEnabled = false;
694     } else {
695         isEnabled = false;
696     }
697     if (wasEnabled != isEnabled) {
698         if (isEnabled)
699             enableItem(item);
700         else
701             disableItem(item);
702     }
703     m_treeWidget->viewport()->update();
704 }
705 
calculatedBackgroundColor(QtBrowserItem * item) const706 QColor QtTreePropertyBrowserPrivate::calculatedBackgroundColor(QtBrowserItem *item) const
707 {
708     QtBrowserItem *i = item;
709     const QMap<QtBrowserItem *, QColor>::const_iterator itEnd = m_indexToBackgroundColor.constEnd();
710     while (i) {
711         QMap<QtBrowserItem *, QColor>::const_iterator it = m_indexToBackgroundColor.constFind(i);
712         if (it != itEnd)
713             return it.value();
714         i = i->parent();
715     }
716     return QColor();
717 }
718 
slotCollapsed(const QModelIndex & index)719 void QtTreePropertyBrowserPrivate::slotCollapsed(const QModelIndex &index)
720 {
721     QTreeWidgetItem *item = indexToItem(index);
722     QtBrowserItem *idx = m_itemToIndex.value(item);
723     if (item)
724         emit q_ptr->collapsed(idx);
725 }
726 
slotExpanded(const QModelIndex & index)727 void QtTreePropertyBrowserPrivate::slotExpanded(const QModelIndex &index)
728 {
729     QTreeWidgetItem *item = indexToItem(index);
730     QtBrowserItem *idx = m_itemToIndex.value(item);
731     if (item)
732         emit q_ptr->expanded(idx);
733 }
734 
slotCurrentBrowserItemChanged(QtBrowserItem * item)735 void QtTreePropertyBrowserPrivate::slotCurrentBrowserItemChanged(QtBrowserItem *item)
736 {
737     if (!m_browserChangedBlocked && item != currentItem())
738         setCurrentItem(item, true);
739 }
740 
slotCurrentTreeItemChanged(QTreeWidgetItem * newItem,QTreeWidgetItem *)741 void QtTreePropertyBrowserPrivate::slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *)
742 {
743     QtBrowserItem *browserItem = newItem ? m_itemToIndex.value(newItem) : 0;
744     m_browserChangedBlocked = true;
745     q_ptr->setCurrentItem(browserItem);
746     m_browserChangedBlocked = false;
747 }
748 
slotItemSelectionChanged()749 void QtTreePropertyBrowserPrivate::slotItemSelectionChanged()
750 {
751     emit q_ptr->selectedItemsChanged();
752 }
753 
editedItem() const754 QTreeWidgetItem *QtTreePropertyBrowserPrivate::editedItem() const
755 {
756     return m_delegate->editedItem();
757 }
758 
editedBrowserItem() const759 QtBrowserItem *QtTreePropertyBrowserPrivate::editedBrowserItem() const
760 {
761     return m_itemToIndex.value(editedItem());
762 }
763 
editItem(QtBrowserItem * browserItem)764 void QtTreePropertyBrowserPrivate::editItem(QtBrowserItem *browserItem)
765 {
766     if (QTreeWidgetItem *treeItem = m_indexToItem.value(browserItem, 0)) {
767         m_treeWidget->setCurrentItem (treeItem, 1);
768         m_treeWidget->editItem(treeItem, 1);
769     }
770 }
771 
selectedItems() const772 QList<QtBrowserItem *> QtTreePropertyBrowserPrivate::selectedItems() const
773 {
774     const QList<QTreeWidgetItem*> selectedTreeItems = m_treeWidget->selectedItems();
775     QList<QtBrowserItem*> browserItems;
776 
777     for (QTreeWidgetItem *treeItem : selectedTreeItems)
778         if (QtBrowserItem *browserItem = m_itemToIndex.value(treeItem, 0))
779             browserItems.append(browserItem);
780 
781     return browserItems;
782 }
783 
784 /*!
785     \class QtTreePropertyBrowser
786 
787     \brief The QtTreePropertyBrowser class provides QTreeWidget based
788     property browser.
789 
790     A property browser is a widget that enables the user to edit a
791     given set of properties. Each property is represented by a label
792     specifying the property's name, and an editing widget (e.g. a line
793     edit or a combobox) holding its value. A property can have zero or
794     more subproperties.
795 
796     QtTreePropertyBrowser provides a tree based view for all nested
797     properties, i.e. properties that have subproperties can be in an
798     expanded (subproperties are visible) or collapsed (subproperties
799     are hidden) state. For example:
800 
801     \image qttreepropertybrowser.png
802 
803     Use the QtAbstractPropertyBrowser API to add, insert and remove
804     properties from an instance of the QtTreePropertyBrowser class.
805     The properties themselves are created and managed by
806     implementations of the QtAbstractPropertyManager class.
807 
808     \sa QtGroupBoxPropertyBrowser, QtAbstractPropertyBrowser
809 */
810 
811 /*!
812     \fn void QtTreePropertyBrowser::collapsed(QtBrowserItem *item)
813 
814     This signal is emitted when the \a item is collapsed.
815 
816     \sa expanded(), setExpanded()
817 */
818 
819 /*!
820     \fn void QtTreePropertyBrowser::expanded(QtBrowserItem *item)
821 
822     This signal is emitted when the \a item is expanded.
823 
824     \sa collapsed(), setExpanded()
825 */
826 
827 /*!
828     Creates a property browser with the given \a parent.
829 */
QtTreePropertyBrowser(QWidget * parent)830 QtTreePropertyBrowser::QtTreePropertyBrowser(QWidget *parent)
831     : QtAbstractPropertyBrowser(parent)
832 {
833     d_ptr = new QtTreePropertyBrowserPrivate;
834     d_ptr->q_ptr = this;
835 
836     d_ptr->init(this);
837     connect(this, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentBrowserItemChanged(QtBrowserItem*)));
838 }
839 
840 /*!
841     Destroys this property browser.
842 
843     Note that the properties that were inserted into this browser are
844     \e not destroyed since they may still be used in other
845     browsers. The properties are owned by the manager that created
846     them.
847 
848     \sa QtProperty, QtAbstractPropertyManager
849 */
~QtTreePropertyBrowser()850 QtTreePropertyBrowser::~QtTreePropertyBrowser()
851 {
852     delete d_ptr;
853 }
854 
855 /*!
856     \property QtTreePropertyBrowser::indentation
857     \brief indentation of the items in the tree view.
858 */
indentation() const859 int QtTreePropertyBrowser::indentation() const
860 {
861     return d_ptr->m_treeWidget->indentation();
862 }
863 
setIndentation(int i)864 void QtTreePropertyBrowser::setIndentation(int i)
865 {
866     d_ptr->m_treeWidget->setIndentation(i);
867 }
868 
869 /*!
870   \property QtTreePropertyBrowser::rootIsDecorated
871   \brief whether to show controls for expanding and collapsing root items.
872 */
rootIsDecorated() const873 bool QtTreePropertyBrowser::rootIsDecorated() const
874 {
875     return d_ptr->m_treeWidget->rootIsDecorated();
876 }
877 
setRootIsDecorated(bool show)878 void QtTreePropertyBrowser::setRootIsDecorated(bool show)
879 {
880     d_ptr->m_treeWidget->setRootIsDecorated(show);
881     QMapIterator<QTreeWidgetItem *, QtBrowserItem *> it(d_ptr->m_itemToIndex);
882     while (it.hasNext()) {
883         QtProperty *property = it.next().value()->property();
884         if (!property->hasValue())
885             d_ptr->updateItem(it.key());
886     }
887 }
888 
889 /*!
890   \property QtTreePropertyBrowser::alternatingRowColors
891   \brief whether to draw the background using alternating colors.
892   By default this property is set to true.
893 */
alternatingRowColors() const894 bool QtTreePropertyBrowser::alternatingRowColors() const
895 {
896     return d_ptr->m_treeWidget->alternatingRowColors();
897 }
898 
setAlternatingRowColors(bool enable)899 void QtTreePropertyBrowser::setAlternatingRowColors(bool enable)
900 {
901     d_ptr->m_treeWidget->setAlternatingRowColors(enable);
902     QMapIterator<QTreeWidgetItem *, QtBrowserItem *> it(d_ptr->m_itemToIndex);
903 }
904 
905 /*!
906   \property QtTreePropertyBrowser::headerVisible
907   \brief whether to show the header.
908 */
isHeaderVisible() const909 bool QtTreePropertyBrowser::isHeaderVisible() const
910 {
911     return d_ptr->m_headerVisible;
912 }
913 
setHeaderVisible(bool visible)914 void QtTreePropertyBrowser::setHeaderVisible(bool visible)
915 {
916     if (d_ptr->m_headerVisible == visible)
917         return;
918 
919     d_ptr->m_headerVisible = visible;
920     d_ptr->m_treeWidget->header()->setVisible(visible);
921 }
922 
923 /*!
924   \property QtTreePropertyBrowser::allowMultiSelection
925   \brief whether to allow multiple selection items.
926 */
allowMultiSelection() const927 bool QtTreePropertyBrowser::allowMultiSelection() const
928 {
929     return d_ptr->m_allowMultiSelection;
930 }
931 
setAllowMultiSelection(bool multiSelection)932 void QtTreePropertyBrowser::setAllowMultiSelection(bool multiSelection)
933 {
934     if (d_ptr->m_allowMultiSelection == multiSelection)
935         return;
936 
937     d_ptr->m_allowMultiSelection = multiSelection;
938     d_ptr->m_treeWidget->setSelectionMode(multiSelection ? QAbstractItemView::ExtendedSelection
939                                                          : QAbstractItemView::SingleSelection);
940 }
941 
942 /*!
943   \enum QtTreePropertyBrowser::ResizeMode
944 
945   The resize mode specifies the behavior of the header sections.
946 
947   \value Interactive The user can resize the sections.
948   The sections can also be resized programmatically using setSplitterPosition().
949 
950   \value Fixed The user cannot resize the section.
951   The section can only be resized programmatically using setSplitterPosition().
952 
953   \value Stretch QHeaderView will automatically resize the section to fill the available space.
954   The size cannot be changed by the user or programmatically.
955 
956   \value ResizeToContents QHeaderView will automatically resize the section to its optimal
957   size based on the contents of the entire column.
958   The size cannot be changed by the user or programmatically.
959 
960   \sa setResizeMode()
961 */
962 
963 /*!
964     \property QtTreePropertyBrowser::resizeMode
965     \brief the resize mode of setions in the header.
966 */
967 
resizeMode() const968 QtTreePropertyBrowser::ResizeMode QtTreePropertyBrowser::resizeMode() const
969 {
970     return d_ptr->m_resizeMode;
971 }
972 
setResizeMode(QtTreePropertyBrowser::ResizeMode mode)973 void QtTreePropertyBrowser::setResizeMode(QtTreePropertyBrowser::ResizeMode mode)
974 {
975     if (d_ptr->m_resizeMode == mode)
976         return;
977 
978     d_ptr->m_resizeMode = mode;
979     QHeaderView::ResizeMode m = QHeaderView::Stretch;
980     switch (mode) {
981         case QtTreePropertyBrowser::Interactive:      m = QHeaderView::Interactive;      break;
982         case QtTreePropertyBrowser::Fixed:            m = QHeaderView::Fixed;            break;
983         case QtTreePropertyBrowser::ResizeToContents: m = QHeaderView::ResizeToContents; break;
984         case QtTreePropertyBrowser::Stretch:
985         default:                                      m = QHeaderView::Stretch;          break;
986     }
987 #if QT_VERSION >= 0x050000
988     d_ptr->m_treeWidget->header()->setSectionResizeMode(m);
989 #else
990     d_ptr->m_treeWidget->header()->setResizeMode(m);
991 #endif
992 }
993 
994 /*!
995     \property QtTreePropertyBrowser::splitterPosition
996     \brief the position of the splitter between the colunms.
997 */
998 
splitterPosition() const999 int QtTreePropertyBrowser::splitterPosition() const
1000 {
1001     return d_ptr->m_treeWidget->header()->sectionSize(0);
1002 }
1003 
setSplitterPosition(int position)1004 void QtTreePropertyBrowser::setSplitterPosition(int position)
1005 {
1006     d_ptr->m_treeWidget->header()->resizeSection(0, position);
1007 }
1008 
1009 /*!
1010     Sets the \a item to either collapse or expanded, depending on the value of \a expanded.
1011 
1012     \sa isExpanded(), expanded(), collapsed()
1013 */
1014 
setExpanded(QtBrowserItem * item,bool expanded)1015 void QtTreePropertyBrowser::setExpanded(QtBrowserItem *item, bool expanded)
1016 {
1017     QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item);
1018     if (treeItem)
1019         treeItem->setExpanded(expanded);
1020 }
1021 
1022 /*!
1023     Returns true if the \a item is expanded; otherwise returns false.
1024 
1025     \sa setExpanded()
1026 */
1027 
isExpanded(QtBrowserItem * item) const1028 bool QtTreePropertyBrowser::isExpanded(QtBrowserItem *item) const
1029 {
1030     QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item);
1031     if (treeItem)
1032         return treeItem->isExpanded();
1033     return false;
1034 }
1035 
1036 /*!
1037     Returns true if the \a item is visible; otherwise returns false.
1038 
1039     \sa setItemVisible()
1040     \since 4.5
1041 */
1042 
isItemVisible(QtBrowserItem * item) const1043 bool QtTreePropertyBrowser::isItemVisible(QtBrowserItem *item) const
1044 {
1045     if (const QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item))
1046         return !treeItem->isHidden();
1047     return false;
1048 }
1049 
1050 /*!
1051     Sets the \a item to be visible, depending on the value of \a visible.
1052 
1053    \sa isItemVisible()
1054    \since 4.5
1055 */
1056 
setItemVisible(QtBrowserItem * item,bool visible)1057 void QtTreePropertyBrowser::setItemVisible(QtBrowserItem *item, bool visible)
1058 {
1059     if (QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item))
1060         treeItem->setHidden(!visible);
1061 }
1062 
1063 /*!
1064     Sets the \a item's background color to \a color. Note that while item's background
1065     is rendered every second row is being drawn with alternate color (which is a bit lighter than items \a color)
1066 
1067     \sa backgroundColor(), calculatedBackgroundColor()
1068 */
1069 
setBackgroundColor(QtBrowserItem * item,const QColor & color)1070 void QtTreePropertyBrowser::setBackgroundColor(QtBrowserItem *item, const QColor &color)
1071 {
1072     if (!d_ptr->m_indexToItem.contains(item))
1073         return;
1074     if (color.isValid())
1075         d_ptr->m_indexToBackgroundColor[item] = color;
1076     else
1077         d_ptr->m_indexToBackgroundColor.remove(item);
1078     d_ptr->m_treeWidget->viewport()->update();
1079 }
1080 
1081 /*!
1082     Returns the \a item's color. If there is no color set for item it returns invalid color.
1083 
1084     \sa calculatedBackgroundColor(), setBackgroundColor()
1085 */
1086 
backgroundColor(QtBrowserItem * item) const1087 QColor QtTreePropertyBrowser::backgroundColor(QtBrowserItem *item) const
1088 {
1089     return d_ptr->m_indexToBackgroundColor.value(item);
1090 }
1091 
1092 /*!
1093     Returns the \a item's color. If there is no color set for item it returns parent \a item's
1094     color (if there is no color set for parent it returns grandparent's color and so on). In case
1095     the color is not set for \a item and it's top level item it returns invalid color.
1096 
1097     \sa backgroundColor(), setBackgroundColor()
1098 */
1099 
calculatedBackgroundColor(QtBrowserItem * item) const1100 QColor QtTreePropertyBrowser::calculatedBackgroundColor(QtBrowserItem *item) const
1101 {
1102     return d_ptr->calculatedBackgroundColor(item);
1103 }
1104 
1105 /*!
1106     \property QtTreePropertyBrowser::propertiesWithoutValueMarked
1107     \brief whether to enable or disable marking properties without value.
1108 
1109     When marking is enabled the item's background is rendered in dark color and item's
1110     foreground is rendered with light color.
1111 
1112     \sa propertiesWithoutValueMarked()
1113 */
setPropertiesWithoutValueMarked(bool mark)1114 void QtTreePropertyBrowser::setPropertiesWithoutValueMarked(bool mark)
1115 {
1116     if (d_ptr->m_markPropertiesWithoutValue == mark)
1117         return;
1118 
1119     d_ptr->m_markPropertiesWithoutValue = mark;
1120     QMapIterator<QTreeWidgetItem *, QtBrowserItem *> it(d_ptr->m_itemToIndex);
1121     while (it.hasNext()) {
1122         QtProperty *property = it.next().value()->property();
1123         if (!property->hasValue())
1124             d_ptr->updateItem(it.key());
1125     }
1126     d_ptr->m_treeWidget->viewport()->update();
1127 }
1128 
propertiesWithoutValueMarked() const1129 bool QtTreePropertyBrowser::propertiesWithoutValueMarked() const
1130 {
1131     return d_ptr->m_markPropertiesWithoutValue;
1132 }
1133 
1134 /*!
1135     \reimp
1136 */
itemInserted(QtBrowserItem * item,QtBrowserItem * afterItem)1137 void QtTreePropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem)
1138 {
1139     d_ptr->propertyInserted(item, afterItem);
1140 }
1141 
1142 /*!
1143     \reimp
1144 */
itemRemoved(QtBrowserItem * item)1145 void QtTreePropertyBrowser::itemRemoved(QtBrowserItem *item)
1146 {
1147     d_ptr->propertyRemoved(item);
1148 }
1149 
1150 /*!
1151     \reimp
1152 */
itemChanged(QtBrowserItem * item)1153 void QtTreePropertyBrowser::itemChanged(QtBrowserItem *item)
1154 {
1155     d_ptr->propertyChanged(item);
1156 }
1157 
1158 /*!
1159     Sets the current item to \a item and opens the relevant editor for it.
1160 */
editItem(QtBrowserItem * item)1161 void QtTreePropertyBrowser::editItem(QtBrowserItem *item)
1162 {
1163     d_ptr->editItem(item);
1164 }
1165 
1166 /*!
1167     Returns the current item being edited, if any.
1168 */
editedItem() const1169 QtBrowserItem *QtTreePropertyBrowser::editedItem() const
1170 {
1171     return d_ptr->editedBrowserItem();
1172 }
1173 
1174 /*!
1175     Returns the selected items.
1176 
1177     \sa setAllowMultiSelection()
1178 */
selectedItems() const1179 QList<QtBrowserItem *> QtTreePropertyBrowser::selectedItems() const
1180 {
1181     return d_ptr->selectedItems();
1182 }
1183 
1184 #if QT_VERSION >= 0x040400
1185 QT_END_NAMESPACE
1186 #endif
1187 
1188 #include "moc_qttreepropertybrowser.cpp"
1189 #include "qttreepropertybrowser.moc"
1190