source: trunk/tools/shared/qtpropertybrowser/qtbuttonpropertybrowser.cpp@ 158

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

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

File size: 19.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 "qtbuttonpropertybrowser.h"
43#include <QtCore/QSet>
44#include <QtGui/QGridLayout>
45#include <QtGui/QLabel>
46#include <QtCore/QTimer>
47#include <QtCore/QMap>
48#include <QtGui/QToolButton>
49#include <QtGui/QStyle>
50
51#if QT_VERSION >= 0x040400
52QT_BEGIN_NAMESPACE
53#endif
54
55class QtButtonPropertyBrowserPrivate
56{
57 QtButtonPropertyBrowser *q_ptr;
58 Q_DECLARE_PUBLIC(QtButtonPropertyBrowser)
59public:
60
61 void init(QWidget *parent);
62
63 void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex);
64 void propertyRemoved(QtBrowserItem *index);
65 void propertyChanged(QtBrowserItem *index);
66 QWidget *createEditor(QtProperty *property, QWidget *parent) const
67 { return q_ptr->createEditor(property, parent); }
68
69 void slotEditorDestroyed();
70 void slotUpdate();
71 void slotToggled(bool checked);
72
73 struct WidgetItem
74 {
75 WidgetItem() : widget(0), label(0), widgetLabel(0),
76 button(0), container(0), layout(0), /*line(0), */parent(0), expanded(false) { }
77 QWidget *widget; // can be null
78 QLabel *label; // main label with property name
79 QLabel *widgetLabel; // label substitute showing the current value if there is no widget
80 QToolButton *button; // expandable button for items with children
81 QWidget *container; // container which is expanded when the button is clicked
82 QGridLayout *layout; // layout in container
83 WidgetItem *parent;
84 QList<WidgetItem *> children;
85 bool expanded;
86 };
87private:
88 void updateLater();
89 void updateItem(WidgetItem *item);
90 void insertRow(QGridLayout *layout, int row) const;
91 void removeRow(QGridLayout *layout, int row) const;
92 int gridRow(WidgetItem *item) const;
93 int gridSpan(WidgetItem *item) const;
94 void setExpanded(WidgetItem *item, bool expanded);
95 QToolButton *createButton(QWidget *panret = 0) const;
96
97 QMap<QtBrowserItem *, WidgetItem *> m_indexToItem;
98 QMap<WidgetItem *, QtBrowserItem *> m_itemToIndex;
99 QMap<QWidget *, WidgetItem *> m_widgetToItem;
100 QMap<QObject *, WidgetItem *> m_buttonToItem;
101 QGridLayout *m_mainLayout;
102 QList<WidgetItem *> m_children;
103 QList<WidgetItem *> m_recreateQueue;
104};
105
106QToolButton *QtButtonPropertyBrowserPrivate::createButton(QWidget *parent) const
107{
108 QToolButton *button = new QToolButton(parent);
109 button->setCheckable(true);
110 button->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed));
111 button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
112 button->setArrowType(Qt::DownArrow);
113 button->setIconSize(QSize(3, 16));
114 /*
115 QIcon icon;
116 icon.addPixmap(q_ptr->style()->standardPixmap(QStyle::SP_ArrowDown), QIcon::Normal, QIcon::Off);
117 icon.addPixmap(q_ptr->style()->standardPixmap(QStyle::SP_ArrowUp), QIcon::Normal, QIcon::On);
118 button->setIcon(icon);
119 */
120 return button;
121}
122
123int QtButtonPropertyBrowserPrivate::gridRow(WidgetItem *item) const
124{
125 QList<WidgetItem *> siblings;
126 if (item->parent)
127 siblings = item->parent->children;
128 else
129 siblings = m_children;
130
131 int row = 0;
132 QListIterator<WidgetItem *> it(siblings);
133 while (it.hasNext()) {
134 WidgetItem *sibling = it.next();
135 if (sibling == item)
136 return row;
137 row += gridSpan(sibling);
138 }
139 return -1;
140}
141
142int QtButtonPropertyBrowserPrivate::gridSpan(WidgetItem *item) const
143{
144 if (item->container && item->expanded)
145 return 2;
146 return 1;
147}
148
149void QtButtonPropertyBrowserPrivate::init(QWidget *parent)
150{
151 m_mainLayout = new QGridLayout();
152 parent->setLayout(m_mainLayout);
153 QLayoutItem *item = new QSpacerItem(0, 0,
154 QSizePolicy::Fixed, QSizePolicy::Expanding);
155 m_mainLayout->addItem(item, 0, 0);
156}
157
158void QtButtonPropertyBrowserPrivate::slotEditorDestroyed()
159{
160 QWidget *editor = qobject_cast<QWidget *>(q_ptr->sender());
161 if (!editor)
162 return;
163 if (!m_widgetToItem.contains(editor))
164 return;
165 m_widgetToItem[editor]->widget = 0;
166 m_widgetToItem.remove(editor);
167}
168
169void QtButtonPropertyBrowserPrivate::slotUpdate()
170{
171 QListIterator<WidgetItem *> itItem(m_recreateQueue);
172 while (itItem.hasNext()) {
173 WidgetItem *item = itItem.next();
174
175 WidgetItem *parent = item->parent;
176 QWidget *w = 0;
177 QGridLayout *l = 0;
178 const int oldRow = gridRow(item);
179 if (parent) {
180 w = parent->container;
181 l = parent->layout;
182 } else {
183 w = q_ptr;
184 l = m_mainLayout;
185 }
186
187 int span = 1;
188 if (!item->widget && !item->widgetLabel)
189 span = 2;
190 item->label = new QLabel(w);
191 item->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
192 l->addWidget(item->label, oldRow, 0, 1, span);
193
194 updateItem(item);
195 }
196 m_recreateQueue.clear();
197}
198
199void QtButtonPropertyBrowserPrivate::setExpanded(WidgetItem *item, bool expanded)
200{
201 if (item->expanded == expanded)
202 return;
203
204 if (!item->container)
205 return;
206
207 item->expanded = expanded;
208 const int row = gridRow(item);
209 WidgetItem *parent = item->parent;
210 QGridLayout *l = 0;
211 if (parent)
212 l = parent->layout;
213 else
214 l = m_mainLayout;
215
216 if (expanded) {
217 insertRow(l, row + 1);
218 l->addWidget(item->container, row + 1, 0, 1, 2);
219 item->container->show();
220 } else {
221 l->removeWidget(item->container);
222 item->container->hide();
223 removeRow(l, row + 1);
224 }
225
226 item->button->setChecked(expanded);
227 item->button->setArrowType(expanded ? Qt::UpArrow : Qt::DownArrow);
228}
229
230void QtButtonPropertyBrowserPrivate::slotToggled(bool checked)
231{
232 WidgetItem *item = m_buttonToItem.value(q_ptr->sender());
233 if (!item)
234 return;
235
236 setExpanded(item, checked);
237
238 if (checked)
239 emit q_ptr->expanded(m_itemToIndex.value(item));
240 else
241 emit q_ptr->collapsed(m_itemToIndex.value(item));
242}
243
244void QtButtonPropertyBrowserPrivate::updateLater()
245{
246 QTimer::singleShot(0, q_ptr, SLOT(slotUpdate()));
247}
248
249void QtButtonPropertyBrowserPrivate::propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex)
250{
251 WidgetItem *afterItem = m_indexToItem.value(afterIndex);
252 WidgetItem *parentItem = m_indexToItem.value(index->parent());
253
254 WidgetItem *newItem = new WidgetItem();
255 newItem->parent = parentItem;
256
257 QGridLayout *layout = 0;
258 QWidget *parentWidget = 0;
259 int row = -1;
260 if (!afterItem) {
261 row = 0;
262 if (parentItem)
263 parentItem->children.insert(0, newItem);
264 else
265 m_children.insert(0, newItem);
266 } else {
267 row = gridRow(afterItem) + gridSpan(afterItem);
268 if (parentItem)
269 parentItem->children.insert(parentItem->children.indexOf(afterItem) + 1, newItem);
270 else
271 m_children.insert(m_children.indexOf(afterItem) + 1, newItem);
272 }
273
274 if (!parentItem) {
275 layout = m_mainLayout;
276 parentWidget = q_ptr;
277 } else {
278 if (!parentItem->container) {
279 m_recreateQueue.removeAll(parentItem);
280 WidgetItem *grandParent = parentItem->parent;
281 QWidget *w = 0;
282 QGridLayout *l = 0;
283 const int oldRow = gridRow(parentItem);
284 if (grandParent) {
285 w = grandParent->container;
286 l = grandParent->layout;
287 } else {
288 w = q_ptr;
289 l = m_mainLayout;
290 }
291 QFrame *container = new QFrame();
292 container->setFrameShape(QFrame::Panel);
293 container->setFrameShadow(QFrame::Raised);
294 parentItem->container = container;
295 parentItem->button = createButton();
296 m_buttonToItem[parentItem->button] = parentItem;
297 q_ptr->connect(parentItem->button, SIGNAL(toggled(bool)), q_ptr, SLOT(slotToggled(bool)));
298 parentItem->layout = new QGridLayout();
299 container->setLayout(parentItem->layout);
300 if (parentItem->label) {
301 l->removeWidget(parentItem->label);
302 delete parentItem->label;
303 parentItem->label = 0;
304 }
305 int span = 1;
306 if (!parentItem->widget && !parentItem->widgetLabel)
307 span = 2;
308 l->addWidget(parentItem->button, oldRow, 0, 1, span);
309 updateItem(parentItem);
310 }
311 layout = parentItem->layout;
312 parentWidget = parentItem->container;
313 }
314
315 newItem->label = new QLabel(parentWidget);
316 newItem->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
317 newItem->widget = createEditor(index->property(), parentWidget);
318 if (newItem->widget) {
319 QObject::connect(newItem->widget, SIGNAL(destroyed()), q_ptr, SLOT(slotEditorDestroyed()));
320 m_widgetToItem[newItem->widget] = newItem;
321 } else if (index->property()->hasValue()) {
322 newItem->widgetLabel = new QLabel(parentWidget);
323 newItem->widgetLabel->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed));
324 }
325
326 insertRow(layout, row);
327 int span = 1;
328 if (newItem->widget)
329 layout->addWidget(newItem->widget, row, 1);
330 else if (newItem->widgetLabel)
331 layout->addWidget(newItem->widgetLabel, row, 1);
332 else
333 span = 2;
334 layout->addWidget(newItem->label, row, 0, span, 1);
335
336 m_itemToIndex[newItem] = index;
337 m_indexToItem[index] = newItem;
338
339 updateItem(newItem);
340}
341
342void QtButtonPropertyBrowserPrivate::propertyRemoved(QtBrowserItem *index)
343{
344 WidgetItem *item = m_indexToItem.value(index);
345
346 m_indexToItem.remove(index);
347 m_itemToIndex.remove(item);
348
349 WidgetItem *parentItem = item->parent;
350
351 const int row = gridRow(item);
352
353 if (parentItem)
354 parentItem->children.removeAt(parentItem->children.indexOf(item));
355 else
356 m_children.removeAt(m_children.indexOf(item));
357
358 const int colSpan = gridSpan(item);
359
360 m_buttonToItem.remove(item->button);
361
362 if (item->widget)
363 delete item->widget;
364 if (item->label)
365 delete item->label;
366 if (item->widgetLabel)
367 delete item->widgetLabel;
368 if (item->button)
369 delete item->button;
370 if (item->container)
371 delete item->container;
372
373 if (!parentItem) {
374 removeRow(m_mainLayout, row);
375 if (colSpan > 1)
376 removeRow(m_mainLayout, row);
377 } else if (parentItem->children.count() != 0) {
378 removeRow(parentItem->layout, row);
379 if (colSpan > 1)
380 removeRow(parentItem->layout, row);
381 } else {
382 const WidgetItem *grandParent = parentItem->parent;
383 QGridLayout *l = 0;
384 if (grandParent) {
385 l = grandParent->layout;
386 } else {
387 l = m_mainLayout;
388 }
389
390 const int parentRow = gridRow(parentItem);
391 const int parentSpan = gridSpan(parentItem);
392
393 l->removeWidget(parentItem->button);
394 l->removeWidget(parentItem->container);
395 delete parentItem->button;
396 delete parentItem->container;
397 parentItem->button = 0;
398 parentItem->container = 0;
399 parentItem->layout = 0;
400 if (!m_recreateQueue.contains(parentItem))
401 m_recreateQueue.append(parentItem);
402 if (parentSpan > 1)
403 removeRow(l, parentRow + 1);
404
405 updateLater();
406 }
407 m_recreateQueue.removeAll(item);
408
409 delete item;
410}
411
412void QtButtonPropertyBrowserPrivate::insertRow(QGridLayout *layout, int row) const
413{
414 QMap<QLayoutItem *, QRect> itemToPos;
415 int idx = 0;
416 while (idx < layout->count()) {
417 int r, c, rs, cs;
418 layout->getItemPosition(idx, &r, &c, &rs, &cs);
419 if (r >= row) {
420 itemToPos[layout->takeAt(idx)] = QRect(r + 1, c, rs, cs);
421 } else {
422 idx++;
423 }
424 }
425
426 const QMap<QLayoutItem *, QRect>::ConstIterator icend = itemToPos.constEnd();
427 for(QMap<QLayoutItem *, QRect>::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) {
428 const QRect r = it.value();
429 layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height());
430 }
431}
432
433void QtButtonPropertyBrowserPrivate::removeRow(QGridLayout *layout, int row) const
434{
435 QMap<QLayoutItem *, QRect> itemToPos;
436 int idx = 0;
437 while (idx < layout->count()) {
438 int r, c, rs, cs;
439 layout->getItemPosition(idx, &r, &c, &rs, &cs);
440 if (r > row) {
441 itemToPos[layout->takeAt(idx)] = QRect(r - 1, c, rs, cs);
442 } else {
443 idx++;
444 }
445 }
446
447 const QMap<QLayoutItem *, QRect>::ConstIterator icend = itemToPos.constEnd();
448 for(QMap<QLayoutItem *, QRect>::ConstIterator it = itemToPos.constBegin(); it != icend; ++it) {
449 const QRect r = it.value();
450 layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height());
451 }
452}
453
454void QtButtonPropertyBrowserPrivate::propertyChanged(QtBrowserItem *index)
455{
456 WidgetItem *item = m_indexToItem.value(index);
457
458 updateItem(item);
459}
460
461void QtButtonPropertyBrowserPrivate::updateItem(WidgetItem *item)
462{
463 QtProperty *property = m_itemToIndex[item]->property();
464 if (item->button) {
465 QFont font = item->button->font();
466 font.setUnderline(property->isModified());
467 item->button->setFont(font);
468 item->button->setText(property->propertyName());
469 item->button->setToolTip(property->toolTip());
470 item->button->setStatusTip(property->statusTip());
471 item->button->setWhatsThis(property->whatsThis());
472 item->button->setEnabled(property->isEnabled());
473 }
474 if (item->label) {
475 QFont font = item->label->font();
476 font.setUnderline(property->isModified());
477 item->label->setFont(font);
478 item->label->setText(property->propertyName());
479 item->label->setToolTip(property->toolTip());
480 item->label->setStatusTip(property->statusTip());
481 item->label->setWhatsThis(property->whatsThis());
482 item->label->setEnabled(property->isEnabled());
483 }
484 if (item->widgetLabel) {
485 QFont font = item->widgetLabel->font();
486 font.setUnderline(false);
487 item->widgetLabel->setFont(font);
488 item->widgetLabel->setText(property->valueText());
489 item->widgetLabel->setToolTip(property->valueText());
490 item->widgetLabel->setEnabled(property->isEnabled());
491 }
492 if (item->widget) {
493 QFont font = item->widget->font();
494 font.setUnderline(false);
495 item->widget->setFont(font);
496 item->widget->setEnabled(property->isEnabled());
497 item->widget->setToolTip(property->valueText());
498 }
499}
500
501
502
503/*!
504 \class QtButtonPropertyBrowser
505 \internal
506 \inmodule QtDesigner
507 \since 4.4
508
509 \brief The QtButtonPropertyBrowser class provides a drop down QToolButton
510 based property browser.
511
512 A property browser is a widget that enables the user to edit a
513 given set of properties. Each property is represented by a label
514 specifying the property's name, and an editing widget (e.g. a line
515 edit or a combobox) holding its value. A property can have zero or
516 more subproperties.
517
518 QtButtonPropertyBrowser provides drop down button for all nested
519 properties, i.e. subproperties are enclosed by a container associated with
520 the drop down button. The parent property's name is displayed as button text. For example:
521
522 \image qtbuttonpropertybrowser.png
523
524 Use the QtAbstractPropertyBrowser API to add, insert and remove
525 properties from an instance of the QtButtonPropertyBrowser
526 class. The properties themselves are created and managed by
527 implementations of the QtAbstractPropertyManager class.
528
529 \sa QtTreePropertyBrowser, QtAbstractPropertyBrowser
530*/
531
532/*!
533 \fn void QtButtonPropertyBrowser::collapsed(QtBrowserItem *item)
534
535 This signal is emitted when the \a item is collapsed.
536
537 \sa expanded(), setExpanded()
538*/
539
540/*!
541 \fn void QtButtonPropertyBrowser::expanded(QtBrowserItem *item)
542
543 This signal is emitted when the \a item is expanded.
544
545 \sa collapsed(), setExpanded()
546*/
547
548/*!
549 Creates a property browser with the given \a parent.
550*/
551QtButtonPropertyBrowser::QtButtonPropertyBrowser(QWidget *parent)
552 : QtAbstractPropertyBrowser(parent)
553{
554 d_ptr = new QtButtonPropertyBrowserPrivate;
555 d_ptr->q_ptr = this;
556
557 d_ptr->init(this);
558}
559
560/*!
561 Destroys this property browser.
562
563 Note that the properties that were inserted into this browser are
564 \e not destroyed since they may still be used in other
565 browsers. The properties are owned by the manager that created
566 them.
567
568 \sa QtProperty, QtAbstractPropertyManager
569*/
570QtButtonPropertyBrowser::~QtButtonPropertyBrowser()
571{
572 const QMap<QtButtonPropertyBrowserPrivate::WidgetItem *, QtBrowserItem *>::ConstIterator icend = d_ptr->m_itemToIndex.constEnd();
573 for (QMap<QtButtonPropertyBrowserPrivate::WidgetItem *, QtBrowserItem *>::ConstIterator it = d_ptr->m_itemToIndex.constBegin(); it != icend; ++it)
574 delete it.key();
575 delete d_ptr;
576}
577
578/*!
579 \reimp
580*/
581void QtButtonPropertyBrowser::itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem)
582{
583 d_ptr->propertyInserted(item, afterItem);
584}
585
586/*!
587 \reimp
588*/
589void QtButtonPropertyBrowser::itemRemoved(QtBrowserItem *item)
590{
591 d_ptr->propertyRemoved(item);
592}
593
594/*!
595 \reimp
596*/
597void QtButtonPropertyBrowser::itemChanged(QtBrowserItem *item)
598{
599 d_ptr->propertyChanged(item);
600}
601
602/*!
603 Sets the \a item to either collapse or expanded, depending on the value of \a expanded.
604
605 \sa isExpanded(), expanded(), collapsed()
606*/
607
608void QtButtonPropertyBrowser::setExpanded(QtBrowserItem *item, bool expanded)
609{
610 QtButtonPropertyBrowserPrivate::WidgetItem *itm = d_ptr->m_indexToItem.value(item);
611 if (itm)
612 d_ptr->setExpanded(itm, expanded);
613}
614
615/*!
616 Returns true if the \a item is expanded; otherwise returns false.
617
618 \sa setExpanded()
619*/
620
621bool QtButtonPropertyBrowser::isExpanded(QtBrowserItem *item) const
622{
623 QtButtonPropertyBrowserPrivate::WidgetItem *itm = d_ptr->m_indexToItem.value(item);
624 if (itm)
625 return itm->expanded;
626 return false;
627}
628
629#if QT_VERSION >= 0x040400
630QT_END_NAMESPACE
631#endif
632
633#include "moc_qtbuttonpropertybrowser.cpp"
Note: See TracBrowser for help on using the repository browser.