tools/shared/qtpropertybrowser/qttreepropertybrowser.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the tools applications of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include "qttreepropertybrowser.h"
       
    43 #include <QtCore/QSet>
       
    44 #include <QtGui/QIcon>
       
    45 #include <QtGui/QTreeWidget>
       
    46 #include <QtGui/QItemDelegate>
       
    47 #include <QtGui/QHBoxLayout>
       
    48 #include <QtGui/QHeaderView>
       
    49 #include <QtGui/QPainter>
       
    50 #include <QtGui/QApplication>
       
    51 #include <QtGui/QFocusEvent>
       
    52 #include <QtGui/QStyle>
       
    53 #include <QtGui/QPalette>
       
    54 
       
    55 QT_BEGIN_NAMESPACE
       
    56 
       
    57 class QtPropertyEditorView;
       
    58 
       
    59 class QtTreePropertyBrowserPrivate
       
    60 {
       
    61     QtTreePropertyBrowser *q_ptr;
       
    62     Q_DECLARE_PUBLIC(QtTreePropertyBrowser)
       
    63 
       
    64 public:
       
    65     QtTreePropertyBrowserPrivate();
       
    66     void init(QWidget *parent);
       
    67 
       
    68     void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex);
       
    69     void propertyRemoved(QtBrowserItem *index);
       
    70     void propertyChanged(QtBrowserItem *index);
       
    71     QWidget *createEditor(QtProperty *property, QWidget *parent) const
       
    72         { return q_ptr->createEditor(property, parent); }
       
    73     QtProperty *indexToProperty(const QModelIndex &index) const;
       
    74     QTreeWidgetItem *indexToItem(const QModelIndex &index) const;
       
    75     QtBrowserItem *indexToBrowserItem(const QModelIndex &index) const;
       
    76     bool lastColumn(int column) const;
       
    77     void disableItem(QTreeWidgetItem *item) const;
       
    78     void enableItem(QTreeWidgetItem *item) const;
       
    79     bool hasValue(QTreeWidgetItem *item) const;
       
    80 
       
    81     void slotCollapsed(const QModelIndex &index);
       
    82     void slotExpanded(const QModelIndex &index);
       
    83 
       
    84     QColor calculatedBackgroundColor(QtBrowserItem *item) const;
       
    85 
       
    86     QtPropertyEditorView *treeWidget() const { return m_treeWidget; }
       
    87     bool markPropertiesWithoutValue() const { return m_markPropertiesWithoutValue; }
       
    88 
       
    89     QtBrowserItem *currentItem() const;
       
    90     void setCurrentItem(QtBrowserItem *browserItem, bool block);
       
    91     void editItem(QtBrowserItem *browserItem);
       
    92 
       
    93     void slotCurrentBrowserItemChanged(QtBrowserItem *item);
       
    94     void slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *);
       
    95 
       
    96     QTreeWidgetItem *editedItem() const;
       
    97 
       
    98 private:
       
    99     void updateItem(QTreeWidgetItem *item);
       
   100 
       
   101     QMap<QtBrowserItem *, QTreeWidgetItem *> m_indexToItem;
       
   102     QMap<QTreeWidgetItem *, QtBrowserItem *> m_itemToIndex;
       
   103 
       
   104     QMap<QtBrowserItem *, QColor> m_indexToBackgroundColor;
       
   105 
       
   106     QtPropertyEditorView *m_treeWidget;
       
   107 
       
   108     bool m_headerVisible;
       
   109     QtTreePropertyBrowser::ResizeMode m_resizeMode;
       
   110     class QtPropertyEditorDelegate *m_delegate;
       
   111     bool m_markPropertiesWithoutValue;
       
   112     bool m_browserChangedBlocked;
       
   113     QIcon m_expandIcon;
       
   114 };
       
   115 
       
   116 // ------------ QtPropertyEditorView
       
   117 class QtPropertyEditorView : public QTreeWidget
       
   118 {
       
   119     Q_OBJECT
       
   120 public:
       
   121     QtPropertyEditorView(QWidget *parent = 0);
       
   122 
       
   123     void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate)
       
   124         { m_editorPrivate = editorPrivate; }
       
   125 
       
   126     QTreeWidgetItem *indexToItem(const QModelIndex &index) const
       
   127         { return itemFromIndex(index); }
       
   128 
       
   129 protected:
       
   130     void keyPressEvent(QKeyEvent *event);
       
   131     void mousePressEvent(QMouseEvent *event);
       
   132     void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
       
   133 
       
   134 private:
       
   135     QtTreePropertyBrowserPrivate *m_editorPrivate;
       
   136 };
       
   137 
       
   138 QtPropertyEditorView::QtPropertyEditorView(QWidget *parent) :
       
   139     QTreeWidget(parent),
       
   140     m_editorPrivate(0)
       
   141 {
       
   142     connect(header(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(resizeColumnToContents(int)));
       
   143 }
       
   144 
       
   145 void QtPropertyEditorView::drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
       
   146 {
       
   147     QStyleOptionViewItemV3 opt = option;
       
   148     bool hasValue = true;
       
   149     if (m_editorPrivate) {
       
   150         QtProperty *property = m_editorPrivate->indexToProperty(index);
       
   151         if (property)
       
   152             hasValue = property->hasValue();
       
   153     }
       
   154     if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) {
       
   155         const QColor c = option.palette.color(QPalette::Dark);
       
   156         painter->fillRect(option.rect, c);
       
   157         opt.palette.setColor(QPalette::AlternateBase, c);
       
   158     } else {
       
   159         const QColor c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index));
       
   160         if (c.isValid()) {
       
   161             painter->fillRect(option.rect, c);
       
   162             opt.palette.setColor(QPalette::AlternateBase, c.lighter(112));
       
   163         }
       
   164     }
       
   165     QTreeWidget::drawRow(painter, opt, index);
       
   166     QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
       
   167     painter->save();
       
   168     painter->setPen(QPen(color));
       
   169     painter->drawLine(opt.rect.x(), opt.rect.bottom(), opt.rect.right(), opt.rect.bottom());
       
   170     painter->restore();
       
   171 }
       
   172 
       
   173 void QtPropertyEditorView::keyPressEvent(QKeyEvent *event)
       
   174 {
       
   175     switch (event->key()) {
       
   176     case Qt::Key_Return:
       
   177     case Qt::Key_Enter:
       
   178     case Qt::Key_Space: // Trigger Edit
       
   179         if (!m_editorPrivate->editedItem())
       
   180             if (const QTreeWidgetItem *item = currentItem())
       
   181                 if (item->columnCount() >= 2 && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) {
       
   182                     event->accept();
       
   183                     // If the current position is at column 0, move to 1.
       
   184                     QModelIndex index = currentIndex();
       
   185                     if (index.column() == 0) {
       
   186                         index = index.sibling(index.row(), 1);
       
   187                         setCurrentIndex(index);
       
   188                     }
       
   189                     edit(index);
       
   190                     return;
       
   191                 }
       
   192         break;
       
   193     default:
       
   194         break;
       
   195     }
       
   196     QTreeWidget::keyPressEvent(event);
       
   197 }
       
   198 
       
   199 void QtPropertyEditorView::mousePressEvent(QMouseEvent *event)
       
   200 {
       
   201     QTreeWidget::mousePressEvent(event);
       
   202     QTreeWidgetItem *item = itemAt(event->pos());
       
   203 
       
   204     if (item) {
       
   205         if ((item != m_editorPrivate->editedItem()) && (event->button() == Qt::LeftButton)
       
   206                 && (header()->logicalIndexAt(event->pos().x()) == 1)
       
   207                 && ((item->flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) {
       
   208             editItem(item, 1);
       
   209         } else if (!m_editorPrivate->hasValue(item) && m_editorPrivate->markPropertiesWithoutValue() && !rootIsDecorated()) {
       
   210             if (event->pos().x() + header()->offset() < 20)
       
   211                 item->setExpanded(!item->isExpanded());
       
   212         }
       
   213     }
       
   214 }
       
   215 
       
   216 // ------------ QtPropertyEditorDelegate
       
   217 class QtPropertyEditorDelegate : public QItemDelegate
       
   218 {
       
   219     Q_OBJECT
       
   220 public:
       
   221     QtPropertyEditorDelegate(QObject *parent = 0)
       
   222         : QItemDelegate(parent), m_editorPrivate(0), m_editedItem(0), m_editedWidget(0)
       
   223         {}
       
   224 
       
   225     void setEditorPrivate(QtTreePropertyBrowserPrivate *editorPrivate)
       
   226         { m_editorPrivate = editorPrivate; }
       
   227 
       
   228     QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
       
   229             const QModelIndex &index) const;
       
   230 
       
   231     void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,
       
   232             const QModelIndex &index) const;
       
   233 
       
   234     void paint(QPainter *painter, const QStyleOptionViewItem &option,
       
   235             const QModelIndex &index) const;
       
   236 
       
   237     QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
       
   238 
       
   239     void setModelData(QWidget *, QAbstractItemModel *,
       
   240             const QModelIndex &) const {}
       
   241 
       
   242     void setEditorData(QWidget *, const QModelIndex &) const {}
       
   243 
       
   244     bool eventFilter(QObject *object, QEvent *event);
       
   245     void closeEditor(QtProperty *property);
       
   246 
       
   247     QTreeWidgetItem *editedItem() const { return m_editedItem; }
       
   248 
       
   249 private slots:
       
   250     void slotEditorDestroyed(QObject *object);
       
   251 
       
   252 private:
       
   253     int indentation(const QModelIndex &index) const;
       
   254 
       
   255     typedef QMap<QWidget *, QtProperty *> EditorToPropertyMap;
       
   256     mutable EditorToPropertyMap m_editorToProperty;
       
   257 
       
   258     typedef QMap<QtProperty *, QWidget *> PropertyToEditorMap;
       
   259     mutable PropertyToEditorMap m_propertyToEditor;
       
   260     QtTreePropertyBrowserPrivate *m_editorPrivate;
       
   261     mutable QTreeWidgetItem *m_editedItem;
       
   262     mutable QWidget *m_editedWidget;
       
   263 };
       
   264 
       
   265 int QtPropertyEditorDelegate::indentation(const QModelIndex &index) const
       
   266 {
       
   267     if (!m_editorPrivate)
       
   268         return 0;
       
   269 
       
   270     QTreeWidgetItem *item = m_editorPrivate->indexToItem(index);
       
   271     int indent = 0;
       
   272     while (item->parent()) {
       
   273         item = item->parent();
       
   274         ++indent;
       
   275     }
       
   276     if (m_editorPrivate->treeWidget()->rootIsDecorated())
       
   277         ++indent;
       
   278     return indent * m_editorPrivate->treeWidget()->indentation();
       
   279 }
       
   280 
       
   281 void QtPropertyEditorDelegate::slotEditorDestroyed(QObject *object)
       
   282 {
       
   283     if (QWidget *w = qobject_cast<QWidget *>(object)) {
       
   284         const EditorToPropertyMap::iterator it = m_editorToProperty.find(w);
       
   285         if (it != m_editorToProperty.end()) {
       
   286             m_propertyToEditor.remove(it.value());
       
   287             m_editorToProperty.erase(it);
       
   288         }
       
   289         if (m_editedWidget == w) {
       
   290             m_editedWidget = 0;
       
   291             m_editedItem = 0;
       
   292         }
       
   293     }
       
   294 }
       
   295 
       
   296 void QtPropertyEditorDelegate::closeEditor(QtProperty *property)
       
   297 {
       
   298     if (QWidget *w = m_propertyToEditor.value(property, 0))
       
   299         w->deleteLater();
       
   300 }
       
   301 
       
   302 QWidget *QtPropertyEditorDelegate::createEditor(QWidget *parent,
       
   303         const QStyleOptionViewItem &, const QModelIndex &index) const
       
   304 {
       
   305     if (index.column() == 1 && m_editorPrivate) {
       
   306         QtProperty *property = m_editorPrivate->indexToProperty(index);
       
   307         QTreeWidgetItem *item = m_editorPrivate->indexToItem(index);
       
   308         if (property && item && (item->flags() & Qt::ItemIsEnabled)) {
       
   309             QWidget *editor = m_editorPrivate->createEditor(property, parent);
       
   310             if (editor) {
       
   311                 editor->setAutoFillBackground(true);
       
   312                 editor->installEventFilter(const_cast<QtPropertyEditorDelegate *>(this));
       
   313                 connect(editor, SIGNAL(destroyed(QObject *)), this, SLOT(slotEditorDestroyed(QObject *)));
       
   314                 m_propertyToEditor[property] = editor;
       
   315                 m_editorToProperty[editor] = property;
       
   316                 m_editedItem = item;
       
   317                 m_editedWidget = editor;
       
   318             }
       
   319             return editor;
       
   320         }
       
   321     }
       
   322     return 0;
       
   323 }
       
   324 
       
   325 void QtPropertyEditorDelegate::updateEditorGeometry(QWidget *editor,
       
   326         const QStyleOptionViewItem &option, const QModelIndex &index) const
       
   327 {
       
   328     Q_UNUSED(index)
       
   329     editor->setGeometry(option.rect.adjusted(0, 0, 0, -1));
       
   330 }
       
   331 
       
   332 void QtPropertyEditorDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
       
   333             const QModelIndex &index) const
       
   334 {
       
   335     bool hasValue = true;
       
   336     if (m_editorPrivate) {
       
   337         QtProperty *property = m_editorPrivate->indexToProperty(index);
       
   338         if (property)
       
   339             hasValue = property->hasValue();
       
   340     }
       
   341     QStyleOptionViewItemV3 opt = option;
       
   342     if ((m_editorPrivate && index.column() == 0) || !hasValue) {
       
   343         QtProperty *property = m_editorPrivate->indexToProperty(index);
       
   344         if (property && property->isModified()) {
       
   345             opt.font.setBold(true);
       
   346             opt.fontMetrics = QFontMetrics(opt.font);
       
   347         }
       
   348     }
       
   349     QColor c;
       
   350     if (!hasValue && m_editorPrivate->markPropertiesWithoutValue()) {
       
   351         c = opt.palette.color(QPalette::Dark);
       
   352         opt.palette.setColor(QPalette::Text, opt.palette.color(QPalette::BrightText));
       
   353     } else {
       
   354         c = m_editorPrivate->calculatedBackgroundColor(m_editorPrivate->indexToBrowserItem(index));
       
   355         if (c.isValid() && (opt.features & QStyleOptionViewItemV2::Alternate))
       
   356             c = c.lighter(112);
       
   357     }
       
   358     if (c.isValid())
       
   359         painter->fillRect(option.rect, c);
       
   360     opt.state &= ~QStyle::State_HasFocus;
       
   361     QItemDelegate::paint(painter, opt, index);
       
   362 
       
   363     opt.palette.setCurrentColorGroup(QPalette::Active);
       
   364     QColor color = static_cast<QRgb>(QApplication::style()->styleHint(QStyle::SH_Table_GridLineColor, &opt));
       
   365     painter->save();
       
   366     painter->setPen(QPen(color));
       
   367     if (!m_editorPrivate || (!m_editorPrivate->lastColumn(index.column()) && hasValue)) {
       
   368         int right = (option.direction == Qt::LeftToRight) ? option.rect.right() : option.rect.left();
       
   369         painter->drawLine(right, option.rect.y(), right, option.rect.bottom());
       
   370     }
       
   371     painter->restore();
       
   372 }
       
   373 
       
   374 QSize QtPropertyEditorDelegate::sizeHint(const QStyleOptionViewItem &option,
       
   375             const QModelIndex &index) const
       
   376 {
       
   377     return QItemDelegate::sizeHint(option, index) + QSize(3, 4);
       
   378 }
       
   379 
       
   380 bool QtPropertyEditorDelegate::eventFilter(QObject *object, QEvent *event)
       
   381 {
       
   382     if (event->type() == QEvent::FocusOut) {
       
   383         QFocusEvent *fe = static_cast<QFocusEvent *>(event);
       
   384         if (fe->reason() == Qt::ActiveWindowFocusReason)
       
   385             return false;
       
   386     }
       
   387     return QItemDelegate::eventFilter(object, event);
       
   388 }
       
   389 
       
   390 //  -------- QtTreePropertyBrowserPrivate implementation
       
   391 QtTreePropertyBrowserPrivate::QtTreePropertyBrowserPrivate() :
       
   392     m_treeWidget(0),
       
   393     m_headerVisible(true),
       
   394     m_resizeMode(QtTreePropertyBrowser::Stretch),
       
   395     m_delegate(0),
       
   396     m_markPropertiesWithoutValue(false),
       
   397     m_browserChangedBlocked(false)
       
   398 {
       
   399 }
       
   400 
       
   401 // Draw an icon indicating opened/closing branches
       
   402 static QIcon drawIndicatorIcon(const QPalette &palette, QStyle *style)
       
   403 {
       
   404     QPixmap pix(14, 14);
       
   405     pix.fill(Qt::transparent);
       
   406     QStyleOption branchOption;
       
   407     QRect r(QPoint(0, 0), pix.size());
       
   408     branchOption.rect = QRect(2, 2, 9, 9); // ### hardcoded in qcommonstyle.cpp
       
   409     branchOption.palette = palette;
       
   410     branchOption.state = QStyle::State_Children;
       
   411 
       
   412     QPainter p;
       
   413     // Draw closed state
       
   414     p.begin(&pix);
       
   415     style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
       
   416     p.end();
       
   417     QIcon rc = pix;
       
   418     rc.addPixmap(pix, QIcon::Selected, QIcon::Off);
       
   419     // Draw opened state
       
   420     branchOption.state |= QStyle::State_Open;
       
   421     pix.fill(Qt::transparent);
       
   422     p.begin(&pix);
       
   423     style->drawPrimitive(QStyle::PE_IndicatorBranch, &branchOption, &p);
       
   424     p.end();
       
   425 
       
   426     rc.addPixmap(pix, QIcon::Normal, QIcon::On);
       
   427     rc.addPixmap(pix, QIcon::Selected, QIcon::On);
       
   428     return rc;
       
   429 }
       
   430 
       
   431 void QtTreePropertyBrowserPrivate::init(QWidget *parent)
       
   432 {
       
   433     QHBoxLayout *layout = new QHBoxLayout(parent);
       
   434     layout->setMargin(0);
       
   435     m_treeWidget = new QtPropertyEditorView(parent);
       
   436     m_treeWidget->setEditorPrivate(this);
       
   437     m_treeWidget->setIconSize(QSize(18, 18));
       
   438     layout->addWidget(m_treeWidget);
       
   439 
       
   440     m_treeWidget->setColumnCount(2);
       
   441     QStringList labels;
       
   442     labels.append(QApplication::translate("QtTreePropertyBrowser", "Property", 0, QApplication::UnicodeUTF8));
       
   443     labels.append(QApplication::translate("QtTreePropertyBrowser", "Value", 0, QApplication::UnicodeUTF8));
       
   444     m_treeWidget->setHeaderLabels(labels);
       
   445     m_treeWidget->setAlternatingRowColors(true);
       
   446     m_treeWidget->setEditTriggers(QAbstractItemView::EditKeyPressed);
       
   447     m_delegate = new QtPropertyEditorDelegate(parent);
       
   448     m_delegate->setEditorPrivate(this);
       
   449     m_treeWidget->setItemDelegate(m_delegate);
       
   450     m_treeWidget->header()->setMovable(false);
       
   451     m_treeWidget->header()->setResizeMode(QHeaderView::Stretch);
       
   452 
       
   453     m_expandIcon = drawIndicatorIcon(q_ptr->palette(), q_ptr->style());
       
   454 
       
   455     QObject::connect(m_treeWidget, SIGNAL(collapsed(const QModelIndex &)), q_ptr, SLOT(slotCollapsed(const QModelIndex &)));
       
   456     QObject::connect(m_treeWidget, SIGNAL(expanded(const QModelIndex &)), q_ptr, SLOT(slotExpanded(const QModelIndex &)));
       
   457     QObject::connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), q_ptr, SLOT(slotCurrentTreeItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
       
   458 }
       
   459 
       
   460 QtBrowserItem *QtTreePropertyBrowserPrivate::currentItem() const
       
   461 {
       
   462     if (QTreeWidgetItem *treeItem = m_treeWidget->currentItem())
       
   463         return m_itemToIndex.value(treeItem);
       
   464     return 0;
       
   465 }
       
   466 
       
   467 void QtTreePropertyBrowserPrivate::setCurrentItem(QtBrowserItem *browserItem, bool block)
       
   468 {
       
   469     const bool blocked = block ? m_treeWidget->blockSignals(true) : false;
       
   470     if (browserItem == 0)
       
   471         m_treeWidget->setCurrentItem(0);
       
   472     else
       
   473         m_treeWidget->setCurrentItem(m_indexToItem.value(browserItem));
       
   474     if (block)
       
   475         m_treeWidget->blockSignals(blocked);
       
   476 }
       
   477 
       
   478 QtProperty *QtTreePropertyBrowserPrivate::indexToProperty(const QModelIndex &index) const
       
   479 {
       
   480     QTreeWidgetItem *item = m_treeWidget->indexToItem(index);
       
   481     QtBrowserItem *idx = m_itemToIndex.value(item);
       
   482     if (idx)
       
   483         return idx->property();
       
   484     return 0;
       
   485 }
       
   486 
       
   487 QtBrowserItem *QtTreePropertyBrowserPrivate::indexToBrowserItem(const QModelIndex &index) const
       
   488 {
       
   489     QTreeWidgetItem *item = m_treeWidget->indexToItem(index);
       
   490     return m_itemToIndex.value(item);
       
   491 }
       
   492 
       
   493 QTreeWidgetItem *QtTreePropertyBrowserPrivate::indexToItem(const QModelIndex &index) const
       
   494 {
       
   495     return m_treeWidget->indexToItem(index);
       
   496 }
       
   497 
       
   498 bool QtTreePropertyBrowserPrivate::lastColumn(int column) const
       
   499 {
       
   500     return m_treeWidget->header()->visualIndex(column) == m_treeWidget->columnCount() - 1;
       
   501 }
       
   502 
       
   503 void QtTreePropertyBrowserPrivate::disableItem(QTreeWidgetItem *item) const
       
   504 {
       
   505     Qt::ItemFlags flags = item->flags();
       
   506     if (flags & Qt::ItemIsEnabled) {
       
   507         flags &= ~Qt::ItemIsEnabled;
       
   508         item->setFlags(flags);
       
   509         m_delegate->closeEditor(m_itemToIndex[item]->property());
       
   510         const int childCount = item->childCount();
       
   511         for (int i = 0; i < childCount; i++) {
       
   512             QTreeWidgetItem *child = item->child(i);
       
   513             disableItem(child);
       
   514         }
       
   515     }
       
   516 }
       
   517 
       
   518 void QtTreePropertyBrowserPrivate::enableItem(QTreeWidgetItem *item) const
       
   519 {
       
   520     Qt::ItemFlags flags = item->flags();
       
   521     flags |= Qt::ItemIsEnabled;
       
   522     item->setFlags(flags);
       
   523     const int childCount = item->childCount();
       
   524     for (int i = 0; i < childCount; i++) {
       
   525         QTreeWidgetItem *child = item->child(i);
       
   526         QtProperty *property = m_itemToIndex[child]->property();
       
   527         if (property->isEnabled()) {
       
   528             enableItem(child);
       
   529         }
       
   530     }
       
   531 }
       
   532 
       
   533 bool QtTreePropertyBrowserPrivate::hasValue(QTreeWidgetItem *item) const
       
   534 {
       
   535     QtBrowserItem *browserItem = m_itemToIndex.value(item);
       
   536     if (browserItem)
       
   537         return browserItem->property()->hasValue();
       
   538     return false;
       
   539 }
       
   540 
       
   541 void QtTreePropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex)
       
   542 {
       
   543     QTreeWidgetItem *afterItem = m_indexToItem.value(afterIndex);
       
   544     QTreeWidgetItem *parentItem = m_indexToItem.value(index->parent());
       
   545 
       
   546     QTreeWidgetItem *newItem = 0;
       
   547     if (parentItem) {
       
   548         newItem = new QTreeWidgetItem(parentItem, afterItem);
       
   549     } else {
       
   550         newItem = new QTreeWidgetItem(m_treeWidget, afterItem);
       
   551     }
       
   552     m_itemToIndex[newItem] = index;
       
   553     m_indexToItem[index] = newItem;
       
   554 
       
   555     newItem->setFlags(newItem->flags() | Qt::ItemIsEditable);
       
   556     m_treeWidget->setItemExpanded(newItem, true);
       
   557 
       
   558     updateItem(newItem);
       
   559 }
       
   560 
       
   561 void QtTreePropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index)
       
   562 {
       
   563     QTreeWidgetItem *item = m_indexToItem.value(index);
       
   564 
       
   565     if (m_treeWidget->currentItem() == item) {
       
   566         m_treeWidget->setCurrentItem(0);
       
   567     }
       
   568 
       
   569     delete item;
       
   570 
       
   571     m_indexToItem.remove(index);
       
   572     m_itemToIndex.remove(item);
       
   573     m_indexToBackgroundColor.remove(index);
       
   574 }
       
   575 
       
   576 void QtTreePropertyBrowserPrivate::propertyChanged(QtBrowserItem *index)
       
   577 {
       
   578     QTreeWidgetItem *item = m_indexToItem.value(index);
       
   579 
       
   580     updateItem(item);
       
   581 }
       
   582 
       
   583 void QtTreePropertyBrowserPrivate::updateItem(QTreeWidgetItem *item)
       
   584 {
       
   585     QtProperty *property = m_itemToIndex[item]->property();
       
   586     QIcon expandIcon;
       
   587     if (property->hasValue()) {
       
   588         QString toolTip = property->toolTip();
       
   589         if (toolTip.isEmpty())
       
   590             toolTip = property->valueText();
       
   591         item->setToolTip(1, toolTip);
       
   592         item->setIcon(1, property->valueIcon());
       
   593         item->setText(1, property->valueText());
       
   594     } else if (markPropertiesWithoutValue() && !m_treeWidget->rootIsDecorated()) {
       
   595         expandIcon = m_expandIcon;
       
   596     }
       
   597     item->setIcon(0, expandIcon);
       
   598     item->setFirstColumnSpanned(!property->hasValue());
       
   599     item->setToolTip(0, property->propertyName());
       
   600     item->setStatusTip(0, property->statusTip());
       
   601     item->setWhatsThis(0, property->whatsThis());
       
   602     item->setText(0, property->propertyName());
       
   603     bool wasEnabled = item->flags() & Qt::ItemIsEnabled;
       
   604     bool isEnabled = wasEnabled;
       
   605     if (property->isEnabled()) {
       
   606         QTreeWidgetItem *parent = item->parent();
       
   607         if (!parent || (parent->flags() & Qt::ItemIsEnabled))
       
   608             isEnabled = true;
       
   609         else
       
   610             isEnabled = false;
       
   611     } else {
       
   612         isEnabled = false;
       
   613     }
       
   614     if (wasEnabled != isEnabled) {
       
   615         if (isEnabled)
       
   616             enableItem(item);
       
   617         else
       
   618             disableItem(item);
       
   619     }
       
   620     m_treeWidget->viewport()->update();
       
   621 }
       
   622 
       
   623 QColor QtTreePropertyBrowserPrivate::calculatedBackgroundColor(QtBrowserItem *item) const
       
   624 {
       
   625     QtBrowserItem *i = item;
       
   626     const QMap<QtBrowserItem *, QColor>::const_iterator itEnd = m_indexToBackgroundColor.constEnd();
       
   627     while (i) {
       
   628         QMap<QtBrowserItem *, QColor>::const_iterator it = m_indexToBackgroundColor.constFind(i);
       
   629         if (it != itEnd)
       
   630             return it.value();
       
   631         i = i->parent();
       
   632     }
       
   633     return QColor();
       
   634 }
       
   635 
       
   636 void QtTreePropertyBrowserPrivate::slotCollapsed(const QModelIndex &index)
       
   637 {
       
   638     QTreeWidgetItem *item = indexToItem(index);
       
   639     QtBrowserItem *idx = m_itemToIndex.value(item);
       
   640     if (item)
       
   641         emit q_ptr->collapsed(idx);
       
   642 }
       
   643 
       
   644 void QtTreePropertyBrowserPrivate::slotExpanded(const QModelIndex &index)
       
   645 {
       
   646     QTreeWidgetItem *item = indexToItem(index);
       
   647     QtBrowserItem *idx = m_itemToIndex.value(item);
       
   648     if (item)
       
   649         emit q_ptr->expanded(idx);
       
   650 }
       
   651 
       
   652 void QtTreePropertyBrowserPrivate::slotCurrentBrowserItemChanged(QtBrowserItem *item)
       
   653 {
       
   654     if (!m_browserChangedBlocked && item != currentItem())
       
   655         setCurrentItem(item, true);
       
   656 }
       
   657 
       
   658 void QtTreePropertyBrowserPrivate::slotCurrentTreeItemChanged(QTreeWidgetItem *newItem, QTreeWidgetItem *)
       
   659 {
       
   660     QtBrowserItem *browserItem = newItem ? m_itemToIndex.value(newItem) : 0;
       
   661     m_browserChangedBlocked = true;
       
   662     q_ptr->setCurrentItem(browserItem);
       
   663     m_browserChangedBlocked = false;
       
   664 }
       
   665 
       
   666 QTreeWidgetItem *QtTreePropertyBrowserPrivate::editedItem() const
       
   667 {
       
   668     return m_delegate->editedItem();
       
   669 }
       
   670 
       
   671 void QtTreePropertyBrowserPrivate::editItem(QtBrowserItem *browserItem)
       
   672 {
       
   673     if (QTreeWidgetItem *treeItem = m_indexToItem.value(browserItem, 0)) {
       
   674         m_treeWidget->setCurrentItem (treeItem, 1);
       
   675         m_treeWidget->editItem(treeItem, 1);
       
   676     }
       
   677 }
       
   678 
       
   679 /*!
       
   680     \class QtTreePropertyBrowser
       
   681     \internal
       
   682     \inmodule QtDesigner
       
   683     \since 4.4
       
   684 
       
   685     \brief The QtTreePropertyBrowser class provides QTreeWidget based
       
   686     property browser.
       
   687 
       
   688     A property browser is a widget that enables the user to edit a
       
   689     given set of properties. Each property is represented by a label
       
   690     specifying the property's name, and an editing widget (e.g. a line
       
   691     edit or a combobox) holding its value. A property can have zero or
       
   692     more subproperties.
       
   693 
       
   694     QtTreePropertyBrowser provides a tree based view for all nested
       
   695     properties, i.e. properties that have subproperties can be in an
       
   696     expanded (subproperties are visible) or collapsed (subproperties
       
   697     are hidden) state. For example:
       
   698 
       
   699     \image qttreepropertybrowser.png
       
   700 
       
   701     Use the QtAbstractPropertyBrowser API to add, insert and remove
       
   702     properties from an instance of the QtTreePropertyBrowser class.
       
   703     The properties themselves are created and managed by
       
   704     implementations of the QtAbstractPropertyManager class.
       
   705 
       
   706     \sa QtGroupBoxPropertyBrowser, QtAbstractPropertyBrowser
       
   707 */
       
   708 
       
   709 /*!
       
   710     \fn void QtTreePropertyBrowser::collapsed(QtBrowserItem *item)
       
   711 
       
   712     This signal is emitted when the \a item is collapsed.
       
   713 
       
   714     \sa expanded(), setExpanded()
       
   715 */
       
   716 
       
   717 /*!
       
   718     \fn void QtTreePropertyBrowser::expanded(QtBrowserItem *item)
       
   719 
       
   720     This signal is emitted when the \a item is expanded.
       
   721 
       
   722     \sa collapsed(), setExpanded()
       
   723 */
       
   724 
       
   725 /*!
       
   726     Creates a property browser with the given \a parent.
       
   727 */
       
   728 QtTreePropertyBrowser::QtTreePropertyBrowser(QWidget *parent)
       
   729     : QtAbstractPropertyBrowser(parent), d_ptr(new QtTreePropertyBrowserPrivate)
       
   730 {
       
   731     d_ptr->q_ptr = this;
       
   732 
       
   733     d_ptr->init(this);
       
   734     connect(this, SIGNAL(currentItemChanged(QtBrowserItem*)), this, SLOT(slotCurrentBrowserItemChanged(QtBrowserItem*)));
       
   735 }
       
   736 
       
   737 /*!
       
   738     Destroys this property browser.
       
   739 
       
   740     Note that the properties that were inserted into this browser are
       
   741     \e not destroyed since they may still be used in other
       
   742     browsers. The properties are owned by the manager that created
       
   743     them.
       
   744 
       
   745     \sa QtProperty, QtAbstractPropertyManager
       
   746 */
       
   747 QtTreePropertyBrowser::~QtTreePropertyBrowser()
       
   748 {
       
   749 }
       
   750 
       
   751 /*!
       
   752     \property QtTreePropertyBrowser::indentation
       
   753     \brief indentation of the items in the tree view.
       
   754 */
       
   755 int QtTreePropertyBrowser::indentation() const
       
   756 {
       
   757     return d_ptr->m_treeWidget->indentation();
       
   758 }
       
   759 
       
   760 void QtTreePropertyBrowser::setIndentation(int i)
       
   761 {
       
   762     d_ptr->m_treeWidget->setIndentation(i);
       
   763 }
       
   764 
       
   765 /*!
       
   766   \property QtTreePropertyBrowser::rootIsDecorated
       
   767   \brief whether to show controls for expanding and collapsing root items.
       
   768 */
       
   769 bool QtTreePropertyBrowser::rootIsDecorated() const
       
   770 {
       
   771     return d_ptr->m_treeWidget->rootIsDecorated();
       
   772 }
       
   773 
       
   774 void QtTreePropertyBrowser::setRootIsDecorated(bool show)
       
   775 {
       
   776     d_ptr->m_treeWidget->setRootIsDecorated(show);
       
   777     QMapIterator<QTreeWidgetItem *, QtBrowserItem *> it(d_ptr->m_itemToIndex);
       
   778     while (it.hasNext()) {
       
   779         QtProperty *property = it.next().value()->property();
       
   780         if (!property->hasValue())
       
   781             d_ptr->updateItem(it.key());
       
   782     }
       
   783 }
       
   784 
       
   785 /*!
       
   786   \property QtTreePropertyBrowser::alternatingRowColors
       
   787   \brief whether to draw the background using alternating colors.
       
   788   By default this property is set to true.
       
   789 */
       
   790 bool QtTreePropertyBrowser::alternatingRowColors() const
       
   791 {
       
   792     return d_ptr->m_treeWidget->alternatingRowColors();
       
   793 }
       
   794 
       
   795 void QtTreePropertyBrowser::setAlternatingRowColors(bool enable)
       
   796 {
       
   797     d_ptr->m_treeWidget->setAlternatingRowColors(enable);
       
   798     QMapIterator<QTreeWidgetItem *, QtBrowserItem *> it(d_ptr->m_itemToIndex);
       
   799 }
       
   800 
       
   801 /*!
       
   802   \property QtTreePropertyBrowser::headerVisible
       
   803   \brief whether to show the header.
       
   804 */
       
   805 bool QtTreePropertyBrowser::isHeaderVisible() const
       
   806 {
       
   807     return d_ptr->m_headerVisible;
       
   808 }
       
   809 
       
   810 void QtTreePropertyBrowser::setHeaderVisible(bool visible)
       
   811 {
       
   812     if (d_ptr->m_headerVisible == visible)
       
   813         return;
       
   814 
       
   815     d_ptr->m_headerVisible = visible;
       
   816     d_ptr->m_treeWidget->header()->setVisible(visible);
       
   817 }
       
   818 
       
   819 /*!
       
   820   \enum QtTreePropertyBrowser::ResizeMode
       
   821 
       
   822   The resize mode specifies the behavior of the header sections.
       
   823 
       
   824   \value Interactive The user can resize the sections.
       
   825   The sections can also be resized programmatically using setSplitterPosition().
       
   826 
       
   827   \value Fixed The user cannot resize the section.
       
   828   The section can only be resized programmatically using setSplitterPosition().
       
   829 
       
   830   \value Stretch QHeaderView will automatically resize the section to fill the available space.
       
   831   The size cannot be changed by the user or programmatically.
       
   832 
       
   833   \value ResizeToContents QHeaderView will automatically resize the section to its optimal
       
   834   size based on the contents of the entire column.
       
   835   The size cannot be changed by the user or programmatically.
       
   836 
       
   837   \sa setResizeMode()
       
   838 */
       
   839 
       
   840 /*!
       
   841     \property QtTreePropertyBrowser::resizeMode
       
   842     \brief the resize mode of setions in the header.
       
   843 */
       
   844 
       
   845 QtTreePropertyBrowser::ResizeMode QtTreePropertyBrowser::resizeMode() const
       
   846 {
       
   847     return d_ptr->m_resizeMode;
       
   848 }
       
   849 
       
   850 void QtTreePropertyBrowser::setResizeMode(QtTreePropertyBrowser::ResizeMode mode)
       
   851 {
       
   852     if (d_ptr->m_resizeMode == mode)
       
   853         return;
       
   854 
       
   855     d_ptr->m_resizeMode = mode;
       
   856     QHeaderView::ResizeMode m = QHeaderView::Stretch;
       
   857     switch (mode) {
       
   858         case QtTreePropertyBrowser::Interactive:      m = QHeaderView::Interactive;      break;
       
   859         case QtTreePropertyBrowser::Fixed:            m = QHeaderView::Fixed;            break;
       
   860         case QtTreePropertyBrowser::ResizeToContents: m = QHeaderView::ResizeToContents; break;
       
   861         case QtTreePropertyBrowser::Stretch:
       
   862         default:                                      m = QHeaderView::Stretch;          break;
       
   863     }
       
   864     d_ptr->m_treeWidget->header()->setResizeMode(m);
       
   865 }
       
   866 
       
   867 /*!
       
   868     \property QtTreePropertyBrowser::splitterPosition
       
   869     \brief the position of the splitter between the colunms.
       
   870 */
       
   871 
       
   872 int QtTreePropertyBrowser::splitterPosition() const
       
   873 {
       
   874     return d_ptr->m_treeWidget->header()->sectionSize(0);
       
   875 }
       
   876 
       
   877 void QtTreePropertyBrowser::setSplitterPosition(int position)
       
   878 {
       
   879     d_ptr->m_treeWidget->header()->resizeSection(0, position);
       
   880 }
       
   881 
       
   882 /*!
       
   883     Sets the \a item to either collapse or expanded, depending on the value of \a expanded.
       
   884 
       
   885     \sa isExpanded(), expanded(), collapsed()
       
   886 */
       
   887 
       
   888 void QtTreePropertyBrowser::setExpanded(QtBrowserItem *item, bool expanded)
       
   889 {
       
   890     QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item);
       
   891     if (treeItem)
       
   892         treeItem->setExpanded(expanded);
       
   893 }
       
   894 
       
   895 /*!
       
   896     Returns true if the \a item is expanded; otherwise returns false.
       
   897 
       
   898     \sa setExpanded()
       
   899 */
       
   900 
       
   901 bool QtTreePropertyBrowser::isExpanded(QtBrowserItem *item) const
       
   902 {
       
   903     QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item);
       
   904     if (treeItem)
       
   905         return treeItem->isExpanded();
       
   906     return false;
       
   907 }
       
   908 
       
   909 /*!
       
   910     Returns true if the \a item is visible; otherwise returns false.
       
   911 
       
   912     \sa setItemVisible()
       
   913     \since 4.5
       
   914 */
       
   915 
       
   916 bool QtTreePropertyBrowser::isItemVisible(QtBrowserItem *item) const
       
   917 {
       
   918     if (const QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item))
       
   919         return !treeItem->isHidden();
       
   920     return false;
       
   921 }
       
   922 
       
   923 /*!
       
   924     Sets the \a item to be visible, depending on the value of \a visible.
       
   925 
       
   926    \sa isItemVisible()
       
   927    \since 4.5
       
   928 */
       
   929 
       
   930 void QtTreePropertyBrowser::setItemVisible(QtBrowserItem *item, bool visible)
       
   931 {
       
   932     if (QTreeWidgetItem *treeItem = d_ptr->m_indexToItem.value(item))
       
   933         treeItem->setHidden(!visible);
       
   934 }
       
   935 
       
   936 /*!
       
   937     Sets the \a item's background color to \a color. Note that while item's background
       
   938     is rendered every second row is being drawn with alternate color (which is a bit lighter than items \a color)
       
   939 
       
   940     \sa backgroundColor(), calculatedBackgroundColor()
       
   941 */
       
   942 
       
   943 void QtTreePropertyBrowser::setBackgroundColor(QtBrowserItem *item, const QColor &color)
       
   944 {
       
   945     if (!d_ptr->m_indexToItem.contains(item))
       
   946         return;
       
   947     if (color.isValid())
       
   948         d_ptr->m_indexToBackgroundColor[item] = color;
       
   949     else
       
   950         d_ptr->m_indexToBackgroundColor.remove(item);
       
   951     d_ptr->m_treeWidget->viewport()->update();
       
   952 }
       
   953 
       
   954 /*!
       
   955     Returns the \a item's color. If there is no color set for item it returns invalid color.
       
   956 
       
   957     \sa calculatedBackgroundColor(), setBackgroundColor()
       
   958 */
       
   959 
       
   960 QColor QtTreePropertyBrowser::backgroundColor(QtBrowserItem *item) const
       
   961 {
       
   962     return d_ptr->m_indexToBackgroundColor.value(item);
       
   963 }
       
   964 
       
   965 /*!
       
   966     Returns the \a item's color. If there is no color set for item it returns parent \a item's
       
   967     color (if there is no color set for parent it returns grandparent's color and so on). In case
       
   968     the color is not set for \a item and it's top level item it returns invalid color.
       
   969 
       
   970     \sa backgroundColor(), setBackgroundColor()
       
   971 */
       
   972 
       
   973 QColor QtTreePropertyBrowser::calculatedBackgroundColor(QtBrowserItem *item) const
       
   974 {
       
   975     return d_ptr->calculatedBackgroundColor(item);
       
   976 }
       
   977 
       
   978 /*!
       
   979     \property QtTreePropertyBrowser::propertiesWithoutValueMarked
       
   980     \brief whether to enable or disable marking properties without value.
       
   981 
       
   982     When marking is enabled the item's background is rendered in dark color and item's
       
   983     foreground is rendered with light color.
       
   984 
       
   985     \sa propertiesWithoutValueMarked()
       
   986 */
       
   987 void QtTreePropertyBrowser::setPropertiesWithoutValueMarked(bool mark)
       
   988 {
       
   989     if (d_ptr->m_markPropertiesWithoutValue == mark)
       
   990         return;
       
   991 
       
   992     d_ptr->m_markPropertiesWithoutValue = mark;
       
   993     QMapIterator<QTreeWidgetItem *, QtBrowserItem *> it(d_ptr->m_itemToIndex);
       
   994     while (it.hasNext()) {
       
   995         QtProperty *property = it.next().value()->property();
       
   996         if (!property->hasValue())
       
   997             d_ptr->updateItem(it.key());
       
   998     }
       
   999     d_ptr->m_treeWidget->viewport()->update();
       
  1000 }
       
  1001 
       
  1002 bool QtTreePropertyBrowser::propertiesWithoutValueMarked() const
       
  1003 {
       
  1004     return d_ptr->m_markPropertiesWithoutValue;
       
  1005 }
       
  1006 
       
  1007 /*!
       
  1008     \reimp
       
  1009 */
       
  1010 void QtTreePropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem)
       
  1011 {
       
  1012     d_ptr->propertyInserted(item, afterItem);
       
  1013 }
       
  1014 
       
  1015 /*!
       
  1016     \reimp
       
  1017 */
       
  1018 void QtTreePropertyBrowser::itemRemoved(QtBrowserItem *item)
       
  1019 {
       
  1020     d_ptr->propertyRemoved(item);
       
  1021 }
       
  1022 
       
  1023 /*!
       
  1024     \reimp
       
  1025 */
       
  1026 void QtTreePropertyBrowser::itemChanged(QtBrowserItem *item)
       
  1027 {
       
  1028     d_ptr->propertyChanged(item);
       
  1029 }
       
  1030 
       
  1031 /*!
       
  1032     Sets the current item to \a item and opens the relevant editor for it.
       
  1033 */
       
  1034 void QtTreePropertyBrowser::editItem(QtBrowserItem *item)
       
  1035 {
       
  1036     d_ptr->editItem(item);
       
  1037 }
       
  1038 
       
  1039 QT_END_NAMESPACE
       
  1040 
       
  1041 #include "moc_qttreepropertybrowser.cpp"
       
  1042 #include "qttreepropertybrowser.moc"