Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qtgroupboxpropertybrowser.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5
6#include <QtWidgets/qgridlayout.h>
7#include <QtWidgets/qgroupbox.h>
8#include <QtWidgets/qlabel.h>
9
10#include <QtCore/qhash.h>
11
13
15{
16 QtGroupBoxPropertyBrowser *q_ptr = nullptr;
17 Q_DECLARE_PUBLIC(QtGroupBoxPropertyBrowser)
18public:
19
21
22 void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex);
25 QWidget *createEditor(QtProperty *property, QWidget *parent) const
26 { return q_ptr->createEditor(property, parent); }
27
28 void slotUpdate();
29
31 {
32 QWidget *widget{nullptr}; // can be null
33 QLabel *label{nullptr};
37 QFrame *line{nullptr};
38 WidgetItem *parent{nullptr};
40 };
41private:
42 void updateLater();
43 void updateItem(WidgetItem *item);
44 static void insertRow(QGridLayout *layout, int row);
45 static void removeRow(QGridLayout *layout, int row);
46
47 static bool hasHeader(const WidgetItem *item);
48
49 QHash<QtBrowserItem *, WidgetItem *> m_indexToItem;
50 QHash<WidgetItem *, QtBrowserItem *> m_itemToIndex;
51 QGridLayout *m_mainLayout;
52 QList<WidgetItem *> m_children;
53 QList<WidgetItem *> m_recreateQueue;
54};
55
56void QtGroupBoxPropertyBrowserPrivate::init(QWidget *parent)
57{
58 m_mainLayout = new QGridLayout();
59 parent->setLayout(m_mainLayout);
60 auto *item = new QSpacerItem(0, 0, QSizePolicy::Fixed, QSizePolicy::Expanding);
61 m_mainLayout->addItem(item, 0, 0);
62}
63
65{
66 for (WidgetItem *item : std::as_const(m_recreateQueue)) {
67 WidgetItem *par = item->parent;
68 QWidget *w = nullptr;
69 QGridLayout *l = nullptr;
70 qsizetype oldRow = -1;
71 if (!par) {
72 w = q_ptr;
73 l = m_mainLayout;
74 oldRow = m_children.indexOf(item);
75 } else {
76 w = par->groupBox;
77 l = par->layout;
78 oldRow = par->children.indexOf(item);
79 if (hasHeader(par))
80 oldRow += 2;
81 }
82
83 if (item->widget) {
84 item->widget->setParent(w);
85 } else if (item->widgetLabel) {
86 item->widgetLabel->setParent(w);
87 } else {
88 item->widgetLabel = new QLabel(w);
89 }
90 int span = 1;
91 if (item->widget)
92 l->addWidget(item->widget, oldRow, 1, 1, 1);
93 else if (item->widgetLabel)
94 l->addWidget(item->widgetLabel, oldRow, 1, 1, 1);
95 else
96 span = 2;
97 item->label = new QLabel(w);
98 item->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
99 l->addWidget(item->label, oldRow, 0, 1, span);
100
101 updateItem(item);
102 }
103 m_recreateQueue.clear();
104}
105
106void QtGroupBoxPropertyBrowserPrivate::updateLater()
107{
108 QMetaObject::invokeMethod(q_ptr, [this] { slotUpdate(); }, Qt::QueuedConnection);
109}
110
112{
113 WidgetItem *afterItem = m_indexToItem.value(afterIndex);
114 WidgetItem *parentItem = m_indexToItem.value(index->parent());
115
116 auto *newItem = new WidgetItem();
117 newItem->parent = parentItem;
118
119 QGridLayout *layout = nullptr;
120 QWidget *parentWidget = nullptr;
121 qsizetype row = -1;
122 if (!afterItem) {
123 row = 0;
124 if (parentItem)
125 parentItem->children.insert(0, newItem);
126 else
127 m_children.insert(0, newItem);
128 } else {
129 if (parentItem) {
130 row = parentItem->children.indexOf(afterItem) + 1;
131 parentItem->children.insert(row, newItem);
132 } else {
133 row = m_children.indexOf(afterItem) + 1;
134 m_children.insert(row, newItem);
135 }
136 }
137 if (parentItem && hasHeader(parentItem))
138 row += 2;
139
140 if (!parentItem) {
141 layout = m_mainLayout;
142 parentWidget = q_ptr;
143 } else {
144 if (!parentItem->groupBox) {
145 m_recreateQueue.removeAll(parentItem);
146 WidgetItem *par = parentItem->parent;
147 QWidget *w = nullptr;
148 QGridLayout *l = nullptr;
149 int oldRow = -1;
150 if (!par) {
151 w = q_ptr;
152 l = m_mainLayout;
153 oldRow = m_children.indexOf(parentItem);
154 } else {
155 w = par->groupBox;
156 l = par->layout;
157 oldRow = par->children.indexOf(parentItem);
158 if (hasHeader(par))
159 oldRow += 2;
160 }
161 parentItem->groupBox = new QGroupBox(w);
162 parentItem->layout = new QGridLayout();
163 parentItem->groupBox->setLayout(parentItem->layout);
164 if (parentItem->label) {
165 l->removeWidget(parentItem->label);
166 delete parentItem->label;
167 parentItem->label = nullptr;
168 }
169 if (parentItem->widget) {
170 l->removeWidget(parentItem->widget);
171 parentItem->widget->setParent(parentItem->groupBox);
172 parentItem->layout->addWidget(parentItem->widget, 0, 0, 1, 2);
173 parentItem->line = new QFrame(parentItem->groupBox);
174 } else if (parentItem->widgetLabel) {
175 l->removeWidget(parentItem->widgetLabel);
176 delete parentItem->widgetLabel;
177 parentItem->widgetLabel = nullptr;
178 }
179 if (parentItem->line) {
180 parentItem->line->setFrameShape(QFrame::HLine);
181 parentItem->line->setFrameShadow(QFrame::Sunken);
182 parentItem->layout->addWidget(parentItem->line, 1, 0, 1, 2);
183 }
184 l->addWidget(parentItem->groupBox, oldRow, 0, 1, 2);
185 updateItem(parentItem);
186 }
187 layout = parentItem->layout;
188 parentWidget = parentItem->groupBox;
189 }
190
191 newItem->label = new QLabel(parentWidget);
192 newItem->label->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed));
193 newItem->widget = createEditor(index->property(), parentWidget);
194 if (!newItem->widget)
195 newItem->widgetLabel = new QLabel(parentWidget);
196
197 insertRow(layout, row);
198 int span = 1;
199 if (newItem->widget)
200 layout->addWidget(newItem->widget, row, 1);
201 else if (newItem->widgetLabel)
202 layout->addWidget(newItem->widgetLabel, row, 1);
203 else
204 span = 2;
205 layout->addWidget(newItem->label, row, 0, 1, span);
206
207 m_itemToIndex[newItem] = index;
208 m_indexToItem[index] = newItem;
209
210 updateItem(newItem);
211}
212
214{
215 WidgetItem *item = m_indexToItem.value(index);
216
217 m_indexToItem.remove(index);
218 m_itemToIndex.remove(item);
219
220 WidgetItem *parentItem = item->parent;
221
222 qsizetype row = -1;
223
224 if (parentItem) {
225 row = parentItem->children.indexOf(item);
226 parentItem->children.removeAt(row);
227 if (hasHeader(parentItem))
228 row += 2;
229 } else {
230 row = m_children.indexOf(item);
231 m_children.removeAt(row);
232 }
233
234 delete item->widget;
235 delete item->label;
236 delete item->widgetLabel;
237 delete item->groupBox;
238
239 if (!parentItem) {
240 removeRow(m_mainLayout, row);
241 } else if (!parentItem->children.empty()) {
242 removeRow(parentItem->layout, row);
243 } else {
244 WidgetItem *par = parentItem->parent;
245 QGridLayout *l = (par ? par->layout : m_mainLayout);
246 if (parentItem->widget) {
247 parentItem->widget->hide();
248 parentItem->widget->setParent(nullptr);
249 } else if (parentItem->widgetLabel) {
250 parentItem->widgetLabel->hide();
251 parentItem->widgetLabel->setParent(nullptr);
252 } else {
253 //parentItem->widgetLabel = new QLabel(w);
254 }
255 l->removeWidget(parentItem->groupBox);
256 delete parentItem->groupBox;
257 parentItem->groupBox = nullptr;
258 parentItem->line = nullptr;
259 parentItem->layout = nullptr;
260 if (!m_recreateQueue.contains(parentItem))
261 m_recreateQueue.append(parentItem);
262 updateLater();
263 }
264 m_recreateQueue.removeAll(item);
265
266 delete item;
267}
268
269void QtGroupBoxPropertyBrowserPrivate::insertRow(QGridLayout *layout, int row)
270{
271 QHash<QLayoutItem *, QRect> itemToPos;
272 int idx = 0;
273 while (idx < layout->count()) {
274 int r, c, rs, cs;
275 layout->getItemPosition(idx, &r, &c, &rs, &cs);
276 if (r >= row) {
277 itemToPos[layout->takeAt(idx)] = QRect(r + 1, c, rs, cs);
278 } else {
279 idx++;
280 }
281 }
282
283 for (auto it = itemToPos.cbegin(), icend = itemToPos.cend(); it != icend; ++it) {
284 const QRect r = it.value();
285 layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height());
286 }
287}
288
289void QtGroupBoxPropertyBrowserPrivate::removeRow(QGridLayout *layout, int row)
290{
291 QHash<QLayoutItem *, QRect> itemToPos;
292 int idx = 0;
293 while (idx < layout->count()) {
294 int r, c, rs, cs;
295 layout->getItemPosition(idx, &r, &c, &rs, &cs);
296 if (r > row) {
297 itemToPos[layout->takeAt(idx)] = QRect(r - 1, c, rs, cs);
298 } else {
299 idx++;
300 }
301 }
302
303 for (auto it = itemToPos.cbegin(), icend = itemToPos.cend(); it != icend; ++it) {
304 const QRect r = it.value();
305 layout->addItem(it.key(), r.x(), r.y(), r.width(), r.height());
306 }
307}
308
309bool QtGroupBoxPropertyBrowserPrivate::hasHeader(const WidgetItem *item)
310{
311 return item->widget;
312}
313
315{
316 WidgetItem *item = m_indexToItem.value(index);
317
318 updateItem(item);
319}
320
321void QtGroupBoxPropertyBrowserPrivate::updateItem(WidgetItem *item)
322{
323 QtProperty *property = m_itemToIndex[item]->property();
324 if (item->groupBox) {
325 QFont font = item->groupBox->font();
326 font.setUnderline(property->isModified());
327 item->groupBox->setFont(font);
328 item->groupBox->setTitle(property->propertyName());
329 item->groupBox->setToolTip(property->descriptionToolTip());
330 item->groupBox->setStatusTip(property->statusTip());
331 item->groupBox->setWhatsThis(property->whatsThis());
332 item->groupBox->setEnabled(property->isEnabled());
333 }
334 if (item->label) {
335 QFont font = item->label->font();
336 font.setUnderline(property->isModified());
337 item->label->setFont(font);
338 item->label->setText(property->propertyName());
339 item->label->setToolTip(property->descriptionToolTip());
340 item->label->setStatusTip(property->statusTip());
341 item->label->setWhatsThis(property->whatsThis());
342 item->label->setEnabled(property->isEnabled());
343 }
344 if (item->widgetLabel) {
345 QFont font = item->widgetLabel->font();
346 font.setUnderline(false);
347 item->widgetLabel->setFont(font);
348 item->widgetLabel->setText(property->valueText());
349 item->widgetLabel->setEnabled(property->isEnabled());
350 }
351 if (item->widget) {
352 QFont font = item->widget->font();
353 font.setUnderline(false);
354 item->widget->setFont(font);
355 item->widget->setEnabled(property->isEnabled());
356 const QString valueToolTip = property->valueToolTip();
357 item->widget->setToolTip(valueToolTip.isEmpty() ? property->valueText() : valueToolTip);
358 }
359 //item->setIcon(1, property->valueIcon());
360}
361
362
363
364/*!
365 \class QtGroupBoxPropertyBrowser
366 \internal
367 \inmodule QtDesigner
368 \since 4.4
369
370 \brief The QtGroupBoxPropertyBrowser class provides a QGroupBox
371 based property browser.
372
373 A property browser is a widget that enables the user to edit a
374 given set of properties. Each property is represented by a label
375 specifying the property's name, and an editing widget (e.g. a line
376 edit or a combobox) holding its value. A property can have zero or
377 more subproperties.
378
379 QtGroupBoxPropertyBrowser provides group boxes for all nested
380 properties, i.e. subproperties are enclosed by a group box with
381 the parent property's name as its title. For example:
382
383 \image qtgroupboxpropertybrowser.png
384
385 Use the QtAbstractPropertyBrowser API to add, insert and remove
386 properties from an instance of the QtGroupBoxPropertyBrowser
387 class. The properties themselves are created and managed by
388 implementations of the QtAbstractPropertyManager class.
389
390 \sa QtTreePropertyBrowser, QtAbstractPropertyBrowser
391*/
392
393/*!
394 Creates a property browser with the given \a parent.
395*/
396QtGroupBoxPropertyBrowser::QtGroupBoxPropertyBrowser(QWidget *parent)
397 : QtAbstractPropertyBrowser(parent), d_ptr(new QtGroupBoxPropertyBrowserPrivate)
398{
399 d_ptr->q_ptr = this;
400
401 d_ptr->init(this);
402}
403
404/*!
405 Destroys this property browser.
406
407 Note that the properties that were inserted into this browser are
408 \e not destroyed since they may still be used in other
409 browsers. The properties are owned by the manager that created
410 them.
411
412 \sa QtProperty, QtAbstractPropertyManager
413*/
415{
416 for (auto it = d_ptr->m_itemToIndex.cbegin(), icend = d_ptr->m_itemToIndex.cend(); it != icend; ++it)
417 delete it.key();
418}
419
420/*!
421 \reimp
422*/
424{
425 d_ptr->propertyInserted(item, afterItem);
426}
427
428/*!
429 \reimp
430*/
432{
433 d_ptr->propertyRemoved(item);
434}
435
436/*!
437 \reimp
438*/
440{
441 d_ptr->propertyChanged(item);
442}
443
444QT_END_NAMESPACE
445
446#include "moc_qtgroupboxpropertybrowser_p.cpp"
QtAbstractPropertyBrowser provides a base class for implementing property browsers.
The QtBrowserItem class represents a property in a property browser instance.
void propertyInserted(QtBrowserItem *index, QtBrowserItem *afterIndex)
QWidget * createEditor(QtProperty *property, QWidget *parent) const
The QtGroupBoxPropertyBrowser class provides a QGroupBox based property browser.
~QtGroupBoxPropertyBrowser() override
Destroys this property browser.
void itemChanged(QtBrowserItem *item) override
\reimp
void itemRemoved(QtBrowserItem *item) override
\reimp
void itemInserted(QtBrowserItem *item, QtBrowserItem *afterItem) override
\reimp
The QtProperty class encapsulates an instance of a property.
bool isEnabled() const
Returns whether the property is enabled.
bool isModified() const
Returns whether the property is modified.
Combined button and popup list for selecting options.