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

Last change on this file since 561 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 33.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the tools applications of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
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** 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 have questions regarding the use of this file, please contact
37** Nokia 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
55QT_BEGIN_NAMESPACE
56
57class QtPropertyEditorView;
58
59class QtTreePropertyBrowserPrivate
60{
61 QtTreePropertyBrowser *q_ptr;
62 Q_DECLARE_PUBLIC(QtTreePropertyBrowser)
63
64public:
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
98private:
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
117class QtPropertyEditorView : public QTreeWidget
118{
119 Q_OBJECT
120public:
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
129protected:
130 void keyPressEvent(QKeyEvent *event);
131 void mousePressEvent(QMouseEvent *event);
132 void drawRow(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
133
134private:
135 QtTreePropertyBrowserPrivate *m_editorPrivate;
136};
137
138QtPropertyEditorView::QtPropertyEditorView(QWidget *parent) :
139 QTreeWidget(parent),
140 m_editorPrivate(0)
141{
142 connect(header(), SIGNAL(sectionDoubleClicked(int)), this, SLOT(resizeColumnToContents(int)));
143}
144
145void 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
173void 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
199void 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
217class QtPropertyEditorDelegate : public QItemDelegate
218{
219 Q_OBJECT
220public:
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
249private slots:
250 void slotEditorDestroyed(QObject *object);
251
252private:
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
265int 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
281void 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
296void QtPropertyEditorDelegate::closeEditor(QtProperty *property)
297{
298 if (QWidget *w = m_propertyToEditor.value(property, 0))
299 w->deleteLater();
300}
301
302QWidget *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
325void 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
332void 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
374QSize QtPropertyEditorDelegate::sizeHint(const QStyleOptionViewItem &option,
375 const QModelIndex &index) const
376{
377 return QItemDelegate::sizeHint(option, index) + QSize(3, 4);
378}
379
380bool 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
391QtTreePropertyBrowserPrivate::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
402static 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
431void 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(QModelIndex)), q_ptr, SLOT(slotCollapsed(QModelIndex)));
456 QObject::connect(m_treeWidget, SIGNAL(expanded(QModelIndex)), q_ptr, SLOT(slotExpanded(QModelIndex)));
457 QObject::connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)), q_ptr, SLOT(slotCurrentTreeItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)));
458}
459
460QtBrowserItem *QtTreePropertyBrowserPrivate::currentItem() const
461{
462 if (QTreeWidgetItem *treeItem = m_treeWidget->currentItem())
463 return m_itemToIndex.value(treeItem);
464 return 0;
465}
466
467void 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
478QtProperty *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
487QtBrowserItem *QtTreePropertyBrowserPrivate::indexToBrowserItem(const QModelIndex &index) const
488{
489 QTreeWidgetItem *item = m_treeWidget->indexToItem(index);
490 return m_itemToIndex.value(item);
491}
492
493QTreeWidgetItem *QtTreePropertyBrowserPrivate::indexToItem(const QModelIndex &index) const
494{
495 return m_treeWidget->indexToItem(index);
496}
497
498bool QtTreePropertyBrowserPrivate::lastColumn(int column) const
499{
500 return m_treeWidget->header()->visualIndex(column) == m_treeWidget->columnCount() - 1;
501}
502
503void 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
518void 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
533bool 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
541void 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
561void 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
576void QtTreePropertyBrowserPrivate::propertyChanged(QtBrowserItem *index)
577{
578 QTreeWidgetItem *item = m_indexToItem.value(index);
579
580 updateItem(item);
581}
582
583void 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
623QColor 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
636void 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
644void 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
652void QtTreePropertyBrowserPrivate::slotCurrentBrowserItemChanged(QtBrowserItem *item)
653{
654 if (!m_browserChangedBlocked && item != currentItem())
655 setCurrentItem(item, true);
656}
657
658void 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
666QTreeWidgetItem *QtTreePropertyBrowserPrivate::editedItem() const
667{
668 return m_delegate->editedItem();
669}
670
671void 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*/
728QtTreePropertyBrowser::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*/
747QtTreePropertyBrowser::~QtTreePropertyBrowser()
748{
749}
750
751/*!
752 \property QtTreePropertyBrowser::indentation
753 \brief indentation of the items in the tree view.
754*/
755int QtTreePropertyBrowser::indentation() const
756{
757 return d_ptr->m_treeWidget->indentation();
758}
759
760void 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*/
769bool QtTreePropertyBrowser::rootIsDecorated() const
770{
771 return d_ptr->m_treeWidget->rootIsDecorated();
772}
773
774void 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*/
790bool QtTreePropertyBrowser::alternatingRowColors() const
791{
792 return d_ptr->m_treeWidget->alternatingRowColors();
793}
794
795void 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*/
805bool QtTreePropertyBrowser::isHeaderVisible() const
806{
807 return d_ptr->m_headerVisible;
808}
809
810void 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
845QtTreePropertyBrowser::ResizeMode QtTreePropertyBrowser::resizeMode() const
846{
847 return d_ptr->m_resizeMode;
848}
849
850void 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
872int QtTreePropertyBrowser::splitterPosition() const
873{
874 return d_ptr->m_treeWidget->header()->sectionSize(0);
875}
876
877void 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
888void 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
901bool 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
916bool 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
930void 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
943void 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
960QColor 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
973QColor 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*/
987void 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
1002bool QtTreePropertyBrowser::propertiesWithoutValueMarked() const
1003{
1004 return d_ptr->m_markPropertiesWithoutValue;
1005}
1006
1007/*!
1008 \reimp
1009*/
1010void QtTreePropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem)
1011{
1012 d_ptr->propertyInserted(item, afterItem);
1013}
1014
1015/*!
1016 \reimp
1017*/
1018void QtTreePropertyBrowser::itemRemoved(QtBrowserItem *item)
1019{
1020 d_ptr->propertyRemoved(item);
1021}
1022
1023/*!
1024 \reimp
1025*/
1026void 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*/
1034void QtTreePropertyBrowser::editItem(QtBrowserItem *item)
1035{
1036 d_ptr->editItem(item);
1037}
1038
1039QT_END_NAMESPACE
1040
1041#include "moc_qttreepropertybrowser.cpp"
1042#include "qttreepropertybrowser.moc"
Note: See TracBrowser for help on using the repository browser.