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