1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Designer of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "layoutinfo_p.h"
30
31#include <QtDesigner/abstractformeditor.h>
32#include <QtDesigner/container.h>
33#include <QtDesigner/abstractmetadatabase.h>
34#include <QtDesigner/qextensionmanager.h>
35
36#include <QtWidgets/qboxlayout.h>
37#include <QtWidgets/qformlayout.h>
38#include <QtWidgets/qsplitter.h>
39#include <QtCore/qdebug.h>
40#include <QtCore/qhash.h>
41#include <QtCore/qrect.h>
42
43QT_BEGIN_NAMESPACE
44
45namespace qdesigner_internal {
46/*!
47 \overload
48*/
49LayoutInfo::Type LayoutInfo::layoutType(const QDesignerFormEditorInterface *core, const QLayout *layout)
50{
51 Q_UNUSED(core);
52 if (!layout)
53 return NoLayout;
54 if (qobject_cast<const QHBoxLayout*>(object: layout))
55 return HBox;
56 if (qobject_cast<const QVBoxLayout*>(object: layout))
57 return VBox;
58 if (qobject_cast<const QGridLayout*>(object: layout))
59 return Grid;
60 if (qobject_cast<const QFormLayout*>(object: layout))
61 return Form;
62 return UnknownLayout;
63}
64
65static const QHash<QString, LayoutInfo::Type> &layoutNameTypeMap()
66{
67 static QHash<QString, LayoutInfo::Type> nameTypeMap;
68 if (nameTypeMap.isEmpty()) {
69 nameTypeMap.insert(QStringLiteral("QVBoxLayout"), avalue: LayoutInfo::VBox);
70 nameTypeMap.insert(QStringLiteral("QHBoxLayout"), avalue: LayoutInfo::HBox);
71 nameTypeMap.insert(QStringLiteral("QGridLayout"), avalue: LayoutInfo::Grid);
72 nameTypeMap.insert(QStringLiteral("QFormLayout"), avalue: LayoutInfo::Form);
73 }
74 return nameTypeMap;
75}
76
77LayoutInfo::Type LayoutInfo::layoutType(const QString &typeName)
78{
79 return layoutNameTypeMap().value(akey: typeName, adefaultValue: NoLayout);
80}
81
82QString LayoutInfo::layoutName(Type t)
83{
84 return layoutNameTypeMap().key(avalue: t);
85}
86
87/*!
88 \overload
89*/
90LayoutInfo::Type LayoutInfo::layoutType(const QDesignerFormEditorInterface *core, const QWidget *w)
91{
92 if (const QSplitter *splitter = qobject_cast<const QSplitter *>(object: w))
93 return splitter->orientation() == Qt::Horizontal ? HSplitter : VSplitter;
94 return layoutType(core, layout: w->layout());
95}
96
97LayoutInfo::Type LayoutInfo::managedLayoutType(const QDesignerFormEditorInterface *core,
98 const QWidget *w,
99 QLayout **ptrToLayout)
100{
101 if (ptrToLayout)
102 *ptrToLayout = nullptr;
103 if (const QSplitter *splitter = qobject_cast<const QSplitter *>(object: w))
104 return splitter->orientation() == Qt::Horizontal ? HSplitter : VSplitter;
105 QLayout *layout = managedLayout(core, widget: w);
106 if (!layout)
107 return NoLayout;
108 if (ptrToLayout)
109 *ptrToLayout = layout;
110 return layoutType(core, layout);
111}
112
113QWidget *LayoutInfo::layoutParent(const QDesignerFormEditorInterface *core, QLayout *layout)
114{
115 Q_UNUSED(core);
116
117 QObject *o = layout;
118 while (o) {
119 if (QWidget *widget = qobject_cast<QWidget*>(o))
120 return widget;
121
122 o = o->parent();
123 }
124 return nullptr;
125}
126
127void LayoutInfo::deleteLayout(const QDesignerFormEditorInterface *core, QWidget *widget)
128{
129 if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(manager: core->extensionManager(), object: widget))
130 widget = container->widget(index: container->currentIndex());
131
132 Q_ASSERT(widget != nullptr);
133
134 QLayout *layout = managedLayout(core, widget);
135
136 if (layout == nullptr || core->metaDataBase()->item(object: layout) != nullptr) {
137 delete layout;
138 widget->updateGeometry();
139 return;
140 }
141
142 qDebug() << "trying to delete an unmanaged layout:" << "widget:" << widget << "layout:" << layout;
143}
144
145LayoutInfo::Type LayoutInfo::laidoutWidgetType(const QDesignerFormEditorInterface *core,
146 QWidget *widget,
147 bool *isManaged,
148 QLayout **ptrToLayout)
149{
150 if (isManaged)
151 *isManaged = false;
152 if (ptrToLayout)
153 *ptrToLayout = nullptr;
154
155 QWidget *parent = widget->parentWidget();
156 if (!parent)
157 return NoLayout;
158
159 // 1) Splitter
160 if (QSplitter *splitter = qobject_cast<QSplitter*>(object: parent)) {
161 if (isManaged)
162 *isManaged = core->metaDataBase()->item(object: splitter);
163 return splitter->orientation() == Qt::Horizontal ? HSplitter : VSplitter;
164 }
165
166 // 2) Layout of parent
167 QLayout *parentLayout = parent->layout();
168 if (!parentLayout)
169 return NoLayout;
170
171 if (parentLayout->indexOf(widget) != -1) {
172 if (isManaged)
173 *isManaged = core->metaDataBase()->item(object: parentLayout);
174 if (ptrToLayout)
175 *ptrToLayout = parentLayout;
176 return layoutType(core, layout: parentLayout);
177 }
178
179 // 3) Some child layout (see below comment about Q3GroupBox)
180 const auto childLayouts = parentLayout->findChildren<QLayout*>();
181 if (childLayouts.isEmpty())
182 return NoLayout;
183 for (QLayout *layout : childLayouts) {
184 if (layout->indexOf(widget) != -1) {
185 if (isManaged)
186 *isManaged = core->metaDataBase()->item(object: layout);
187 if (ptrToLayout)
188 *ptrToLayout = layout;
189 return layoutType(core, layout);
190 }
191 }
192
193 return NoLayout;
194}
195
196QLayout *LayoutInfo::internalLayout(const QWidget *widget)
197{
198 return widget->layout();
199}
200
201
202QLayout *LayoutInfo::managedLayout(const QDesignerFormEditorInterface *core, const QWidget *widget)
203{
204 if (widget == nullptr)
205 return nullptr;
206
207 QLayout *layout = widget->layout();
208 if (!layout)
209 return nullptr;
210
211 return managedLayout(core, layout);
212}
213
214QLayout *LayoutInfo::managedLayout(const QDesignerFormEditorInterface *core, QLayout *layout)
215{
216 QDesignerMetaDataBaseInterface *metaDataBase = core->metaDataBase();
217
218 if (!metaDataBase)
219 return layout;
220 /* This code exists mainly for the Q3GroupBox class, for which
221 * widget->layout() returns an internal VBoxLayout. */
222 const QDesignerMetaDataBaseItemInterface *item = metaDataBase->item(object: layout);
223 if (item == nullptr) {
224 layout = layout->findChild<QLayout*>();
225 item = metaDataBase->item(object: layout);
226 }
227 if (!item)
228 return nullptr;
229 return layout;
230}
231
232// Is it a a dummy grid placeholder created by Designer?
233bool LayoutInfo::isEmptyItem(QLayoutItem *item)
234{
235 if (item == nullptr) {
236 qDebug() << "** WARNING Zero-item passed on to isEmptyItem(). This indicates a layout inconsistency.";
237 return true;
238 }
239 return item->spacerItem() != nullptr;
240}
241
242QDESIGNER_SHARED_EXPORT void getFormLayoutItemPosition(const QFormLayout *formLayout, int index, int *rowPtr, int *columnPtr, int *rowspanPtr, int *colspanPtr)
243{
244 int row;
245 QFormLayout::ItemRole role;
246 formLayout->getItemPosition(index, rowPtr: &row, rolePtr: &role);
247 const int columnspan = role == QFormLayout::SpanningRole ? 2 : 1;
248 const int column = (columnspan > 1 || role == QFormLayout::LabelRole) ? 0 : 1;
249 if (rowPtr)
250 *rowPtr = row;
251 if (columnPtr)
252 *columnPtr = column;
253 if (rowspanPtr)
254 *rowspanPtr = 1;
255 if (colspanPtr)
256 *colspanPtr = columnspan;
257}
258
259static inline QFormLayout::ItemRole formLayoutRole(int column, int colspan)
260{
261 if (colspan > 1)
262 return QFormLayout::SpanningRole;
263 return column == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole;
264}
265
266QDESIGNER_SHARED_EXPORT void formLayoutAddWidget(QFormLayout *formLayout, QWidget *w, const QRect &r, bool insert)
267{
268 // Consistent API galore...
269 if (insert) {
270 const bool spanning = r.width() > 1;
271 if (spanning) {
272 formLayout->insertRow(row: r.y(), widget: w);
273 } else {
274 QWidget *label = nullptr;
275 QWidget *field = nullptr;
276 if (r.x() == 0) {
277 label = w;
278 } else {
279 field = w;
280 }
281 formLayout->insertRow(row: r.y(), label, field);
282 }
283 } else {
284 formLayout->setWidget(row: r.y(), role: formLayoutRole(column: r.x(), colspan: r.width()), widget: w);
285 }
286}
287
288} // namespace qdesigner_internal
289
290QT_END_NAMESPACE
291

source code of qttools/src/designer/src/lib/shared/layoutinfo.cpp