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 
43 QT_BEGIN_NAMESPACE
44 
45 namespace qdesigner_internal {
46 /*!
47   \overload
48 */
layoutType(const QDesignerFormEditorInterface * core,const QLayout * layout)49 LayoutInfo::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*>(layout))
55         return HBox;
56     if (qobject_cast<const QVBoxLayout*>(layout))
57         return VBox;
58     if (qobject_cast<const QGridLayout*>(layout))
59         return Grid;
60     if (qobject_cast<const QFormLayout*>(layout))
61        return Form;
62     return UnknownLayout;
63 }
64 
layoutNameTypeMap()65 static const QHash<QString, LayoutInfo::Type> &layoutNameTypeMap()
66 {
67     static QHash<QString, LayoutInfo::Type> nameTypeMap;
68     if (nameTypeMap.isEmpty()) {
69         nameTypeMap.insert(QStringLiteral("QVBoxLayout"), LayoutInfo::VBox);
70         nameTypeMap.insert(QStringLiteral("QHBoxLayout"), LayoutInfo::HBox);
71         nameTypeMap.insert(QStringLiteral("QGridLayout"), LayoutInfo::Grid);
72         nameTypeMap.insert(QStringLiteral("QFormLayout"), LayoutInfo::Form);
73     }
74     return nameTypeMap;
75 }
76 
layoutType(const QString & typeName)77 LayoutInfo::Type LayoutInfo::layoutType(const QString &typeName)
78 {
79     return layoutNameTypeMap().value(typeName, NoLayout);
80 }
81 
layoutName(Type t)82 QString LayoutInfo::layoutName(Type t)
83 {
84     return layoutNameTypeMap().key(t);
85 }
86 
87 /*!
88   \overload
89 */
layoutType(const QDesignerFormEditorInterface * core,const QWidget * w)90 LayoutInfo::Type LayoutInfo::layoutType(const QDesignerFormEditorInterface *core, const QWidget *w)
91 {
92     if (const QSplitter *splitter = qobject_cast<const QSplitter *>(w))
93         return  splitter->orientation() == Qt::Horizontal ? HSplitter : VSplitter;
94     return layoutType(core, w->layout());
95 }
96 
managedLayoutType(const QDesignerFormEditorInterface * core,const QWidget * w,QLayout ** ptrToLayout)97 LayoutInfo::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 *>(w))
104         return  splitter->orientation() == Qt::Horizontal ? HSplitter : VSplitter;
105     QLayout *layout = managedLayout(core, w);
106     if (!layout)
107         return NoLayout;
108     if (ptrToLayout)
109         *ptrToLayout = layout;
110     return layoutType(core, layout);
111 }
112 
layoutParent(const QDesignerFormEditorInterface * core,QLayout * layout)113 QWidget *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 
deleteLayout(const QDesignerFormEditorInterface * core,QWidget * widget)127 void LayoutInfo::deleteLayout(const QDesignerFormEditorInterface *core, QWidget *widget)
128 {
129     if (QDesignerContainerExtension *container = qt_extension<QDesignerContainerExtension*>(core->extensionManager(), widget))
130         widget = container->widget(container->currentIndex());
131 
132     Q_ASSERT(widget != nullptr);
133 
134     QLayout *layout = managedLayout(core, widget);
135 
136     if (layout == nullptr || core->metaDataBase()->item(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 
laidoutWidgetType(const QDesignerFormEditorInterface * core,QWidget * widget,bool * isManaged,QLayout ** ptrToLayout)145 LayoutInfo::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*>(parent)) {
161         if (isManaged)
162             *isManaged = core->metaDataBase()->item(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(parentLayout);
174         if (ptrToLayout)
175             *ptrToLayout = parentLayout;
176         return layoutType(core, 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(layout);
187             if (ptrToLayout)
188                 *ptrToLayout = layout;
189             return layoutType(core, layout);
190         }
191     }
192 
193     return NoLayout;
194 }
195 
internalLayout(const QWidget * widget)196 QLayout *LayoutInfo::internalLayout(const QWidget *widget)
197 {
198     return widget->layout();
199 }
200 
201 
managedLayout(const QDesignerFormEditorInterface * core,const QWidget * widget)202 QLayout *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 
managedLayout(const QDesignerFormEditorInterface * core,QLayout * layout)214 QLayout *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(layout);
223     if (item == nullptr) {
224         layout = layout->findChild<QLayout*>();
225         item = metaDataBase->item(layout);
226     }
227     if (!item)
228         return nullptr;
229     return layout;
230 }
231 
232 // Is it a a dummy grid placeholder created by Designer?
isEmptyItem(QLayoutItem * item)233 bool 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 
getFormLayoutItemPosition(const QFormLayout * formLayout,int index,int * rowPtr,int * columnPtr,int * rowspanPtr,int * colspanPtr)242 QDESIGNER_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, &row, &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 
formLayoutRole(int column,int colspan)259 static 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 
formLayoutAddWidget(QFormLayout * formLayout,QWidget * w,const QRect & r,bool insert)266 QDESIGNER_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(r.y(), 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(r.y(), label, field);
282         }
283     } else {
284         formLayout->setWidget(r.y(), formLayoutRole(r.x(), r.width()), w);
285     }
286 }
287 
288 } // namespace qdesigner_internal
289 
290 QT_END_NAMESPACE
291