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