source: trunk/tools/shared/qtpropertybrowser/qttreepropertybrowser.cpp@ 109

Last change on this file since 109 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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