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