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 "layout_p.h"
30 #include "qdesigner_utils_p.h"
31 #include "qlayout_widget_p.h"
32 #include "spacer_widget_p.h"
33 #include "layoutdecoration.h"
34 #include "widgetfactory_p.h"
35 #include "qdesigner_widgetitem_p.h"
36 
37 #include <QtDesigner/abstractformeditor.h>
38 #include <QtDesigner/abstractformwindow.h>
39 #include <QtDesigner/container.h>
40 #include <QtDesigner/qextensionmanager.h>
41 #include <QtDesigner/propertysheet.h>
42 #include <QtDesigner/abstractwidgetdatabase.h>
43 #include <QtDesigner/abstractmetadatabase.h>
44 
45 #include <QtCore/qdebug.h>
46 #include <QtCore/qvector.h>
47 
48 #include <QtGui/qevent.h>
49 #include <QtWidgets/qgridlayout.h>
50 #include <QtGui/qpainter.h>
51 #include <QtGui/qbitmap.h>
52 #include <QtWidgets/qsplitter.h>
53 #include <QtWidgets/qmainwindow.h>
54 #include <QtWidgets/qapplication.h>
55 #include <QtWidgets/qscrollarea.h>
56 #include <QtWidgets/qformlayout.h>
57 #include <QtWidgets/qlabel.h>
58 #include <QtWidgets/qwizard.h>
59 #include <QtCore/qdebug.h>
60 #include <QtCore/qset.h>
61 
62 #include <algorithm>
63 
64 QT_BEGIN_NAMESPACE
65 
66 enum { FormLayoutColumns = 2 };
67 
68 namespace qdesigner_internal {
69 
70 /* The wizard has a policy of setting a size policy of its external children
71  * according to the page being expanding or not (in the latter case, the
72  * page will be pushed to the top). When setting/breaking layouts, this needs
73  * to be updated, which happens via a fake style change event. */
74 
75 void updateWizardLayout(QWidget *layoutBase);
76 
77 class FriendlyWizardPage : public  QWizardPage {
78     friend void updateWizardLayout(QWidget *);
79 };
80 
updateWizardLayout(QWidget * layoutBase)81 void updateWizardLayout(QWidget *layoutBase)
82 {
83     if (QWizardPage *wizardPage = qobject_cast<QWizardPage*>(layoutBase))
84         if (QWizard *wizard = static_cast<FriendlyWizardPage*>(wizardPage)->wizard()) {
85             QEvent event(QEvent::StyleChange);
86             QApplication::sendEvent(wizard, &event);
87         }
88 }
89 
90 /*!
91   \class qdesigner_internal::Layout
92   \brief Baseclass for layouting widgets in the Designer (Helper for Layout commands)
93   \internal
94 
95   Classes derived from this abstract base class are used for layouting
96   operations in the Designer (creating/breaking layouts).
97 
98   Instances live in the Layout/BreakLayout commands.
99 */
100 
101 /*!  \a p specifies the parent of the layoutBase \a lb. The parent
102   might be changed in setup(). If the layoutBase is a
103   container, the parent and the layoutBase are the same. Also they
104   always have to be a widget known to the designer (e.g. in the case
105   of the tabwidget parent and layoutBase are the tabwidget and not the
106   page which actually gets laid out. For actual usage the correct
107   widget is found later by Layout.)
108  */
109 
Layout(const QWidgetList & wl,QWidget * p,QDesignerFormWindowInterface * fw,QWidget * lb,LayoutInfo::Type layoutType)110 Layout::Layout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb, LayoutInfo::Type layoutType) :
111     m_widgets(wl),
112     m_parentWidget(p),
113     m_layoutBase(lb),
114     m_formWindow(fw),
115     m_layoutType(layoutType),
116     m_reparentLayoutWidget(true),
117     m_isBreak(false)
118 {
119     if (m_layoutBase)
120         m_oldGeometry = m_layoutBase->geometry();
121 }
122 
123 Layout::~Layout() = default;
124 
125 /*!  The widget list we got in the constructor might contain too much
126   widgets (like widgets with different parents, already laid out
127   widgets, etc.). Here we set up the list and so the only the "best"
128   widgets get laid out.
129 */
130 
setup()131 void Layout::setup()
132 {
133     m_startPoint = QPoint(32767, 32767);
134 
135     // Go through all widgets of the list we got. As we can only
136     // layout widgets which have the same parent, we first do some
137     // sorting which means create a list for each parent containing
138     // its child here. After that we keep working on the list of
139     // children which has the most entries.
140     // Widgets which are already laid out are thrown away here too
141 
142     QMultiMap<QWidget*, QWidget*> lists;
143     for (QWidget *w : qAsConst(m_widgets)) {
144         QWidget *p = w->parentWidget();
145 
146         if (p && LayoutInfo::layoutType(m_formWindow->core(), p) != LayoutInfo::NoLayout
147                 && m_formWindow->core()->metaDataBase()->item(p->layout()) != nullptr)
148             continue;
149 
150         lists.insert(p, w);
151     }
152 
153     QWidgetList lastList;
154     const QWidgetList &parents = lists.keys();
155     for (QWidget *p : parents) {
156         if (lists.count(p) > lastList.count())
157             lastList = lists.values(p);
158     }
159 
160 
161     // If we found no list (because no widget did fit at all) or the
162     // best list has only one entry and we do not layout a container,
163     // we leave here.
164     QDesignerWidgetDataBaseInterface *widgetDataBase = m_formWindow->core()->widgetDataBase();
165     if (lastList.count() < 2 &&
166                         (!m_layoutBase ||
167                           (!widgetDataBase->isContainer(m_layoutBase, false) &&
168                             m_layoutBase != m_formWindow->mainContainer()))
169                        ) {
170         m_widgets.clear();
171         m_startPoint = QPoint(0, 0);
172         return;
173     }
174 
175     // Now we have a new and clean widget list, which makes sense
176     // to layout
177     m_widgets = lastList;
178     // Also use the only correct parent later, so store it
179 
180     Q_ASSERT(m_widgets.isEmpty() == false);
181 
182     m_parentWidget = m_formWindow->core()->widgetFactory()->widgetOfContainer(m_widgets.first()->parentWidget());
183     // Now calculate the position where the layout-meta-widget should
184     // be placed and connect to widgetDestroyed() signals of the
185     // widgets to get informed if one gets deleted to be able to
186     // handle that and do not crash in this case
187     for (QWidget *w : qAsConst(m_widgets)) {
188         connect(w, &QObject::destroyed, this, &Layout::widgetDestroyed);
189         m_startPoint = QPoint(qMin(m_startPoint.x(), w->x()), qMin(m_startPoint.y(), w->y()));
190         const QRect rc(w->geometry());
191 
192         m_geometries.insert(w, rc);
193         // Change the Z-order, as saving/loading uses the Z-order for
194         // writing/creating widgets and this has to be the same as in
195         // the layout. Else saving + loading will give different results
196         w->raise();
197     }
198 
199     sort();
200 }
201 
widgetDestroyed()202 void Layout::widgetDestroyed()
203 {
204     if (QWidget *w = qobject_cast<QWidget *>(sender())) {
205         m_widgets.removeAt(m_widgets.indexOf(w));
206         m_geometries.remove(w);
207     }
208 }
209 
prepareLayout(bool & needMove,bool & needReparent)210 bool Layout::prepareLayout(bool &needMove, bool &needReparent)
211 {
212     for (QWidget *widget : qAsConst(m_widgets))
213         widget->raise();
214 
215     needMove = !m_layoutBase;
216     needReparent = needMove || (m_reparentLayoutWidget && qobject_cast<QLayoutWidget*>(m_layoutBase)) || qobject_cast<QSplitter*>(m_layoutBase);
217 
218     QDesignerWidgetFactoryInterface *widgetFactory = m_formWindow->core()->widgetFactory();
219     QDesignerMetaDataBaseInterface *metaDataBase = m_formWindow->core()->metaDataBase();
220 
221     if (m_layoutBase == nullptr) {
222         const bool useSplitter = m_layoutType == LayoutInfo::HSplitter || m_layoutType == LayoutInfo::VSplitter;
223         const QString baseWidgetClassName = useSplitter ? QLatin1String("QSplitter") : QLatin1String("QLayoutWidget");
224         m_layoutBase = widgetFactory->createWidget(baseWidgetClassName, widgetFactory->containerOfWidget(m_parentWidget));
225         if (useSplitter) {
226             m_layoutBase->setObjectName(QStringLiteral("splitter"));
227             m_formWindow->ensureUniqueObjectName(m_layoutBase);
228         }
229     } else {
230         LayoutInfo::deleteLayout(m_formWindow->core(), m_layoutBase);
231     }
232 
233     metaDataBase->add(m_layoutBase);
234 
235     Q_ASSERT(m_layoutBase->layout() == nullptr || metaDataBase->item(m_layoutBase->layout()) == nullptr);
236 
237     return true;
238 }
239 
isMainContainer(QDesignerFormWindowInterface * fw,const QWidget * w)240 static bool isMainContainer(QDesignerFormWindowInterface *fw, const QWidget *w)
241 {
242     return w && (w == fw || w == fw->mainContainer());
243 }
244 
isPageOfContainerWidget(QDesignerFormWindowInterface * fw,QWidget * widget)245 static bool isPageOfContainerWidget(QDesignerFormWindowInterface *fw, QWidget *widget)
246 {
247     QDesignerContainerExtension *c = qt_extension<QDesignerContainerExtension*>(
248             fw->core()->extensionManager(), widget->parentWidget());
249 
250     if (c != nullptr) {
251         for (int i = 0; i<c->count(); ++i) {
252             if (widget == c->widget(i))
253                 return true;
254         }
255     }
256 
257     return false;
258 }
finishLayout(bool needMove,QLayout * layout)259 void Layout::finishLayout(bool needMove, QLayout *layout)
260 {
261     if (m_parentWidget == m_layoutBase) {
262         QWidget *widget = m_layoutBase;
263         m_oldGeometry = widget->geometry();
264 
265         bool done = false;
266         while (!isMainContainer(m_formWindow, widget) && !done) {
267             if (!m_formWindow->isManaged(widget)) {
268                 widget = widget->parentWidget();
269                 continue;
270             }
271             if (LayoutInfo::isWidgetLaidout(m_formWindow->core(), widget)) {
272                 widget = widget->parentWidget();
273                 continue;
274             }
275             if (isPageOfContainerWidget(m_formWindow, widget)) {
276                 widget = widget->parentWidget();
277                 continue;
278             }
279             if (widget->parentWidget()) {
280                 QScrollArea *area = qobject_cast<QScrollArea*>(widget->parentWidget()->parentWidget());
281                 if (area && area->widget() == widget) {
282                     widget = area;
283                     continue;
284                 }
285             }
286 
287             done = true;
288         }
289         updateWizardLayout(m_layoutBase);
290         QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
291         // We don't want to resize the form window
292         if (!Utils::isCentralWidget(m_formWindow, widget))
293             widget->adjustSize();
294 
295         return;
296     }
297 
298     if (needMove)
299         m_layoutBase->move(m_startPoint);
300 
301     const QRect g(m_layoutBase->pos(), m_layoutBase->size());
302 
303     if (LayoutInfo::layoutType(m_formWindow->core(), m_layoutBase->parentWidget()) == LayoutInfo::NoLayout && !m_isBreak)
304         m_layoutBase->adjustSize();
305     else if (m_isBreak)
306         m_layoutBase->setGeometry(m_oldGeometry);
307 
308     m_oldGeometry = g;
309     if (layout)
310         layout->invalidate();
311     m_layoutBase->show();
312 
313     if (qobject_cast<QLayoutWidget*>(m_layoutBase) || qobject_cast<QSplitter*>(m_layoutBase)) {
314         m_formWindow->clearSelection(false);
315         m_formWindow->manageWidget(m_layoutBase);
316         m_formWindow->selectWidget(m_layoutBase);
317     }
318 }
319 
undoLayout()320 void Layout::undoLayout()
321 {
322     if (!m_widgets.count())
323         return;
324 
325     m_formWindow->selectWidget(m_layoutBase, false);
326 
327     QDesignerWidgetFactoryInterface *widgetFactory = m_formWindow->core()->widgetFactory();
328     for (auto it = m_geometries.cbegin(), end = m_geometries.cend(); it != end; ++it) {
329         if (!it.key())
330             continue;
331 
332         QWidget* w = it.key();
333         const QRect rc = it.value();
334 
335         const bool showIt = w->isVisibleTo(m_formWindow);
336         QWidget *container = widgetFactory->containerOfWidget(m_parentWidget);
337 
338         // ### remove widget here
339         QWidget *parentWidget = w->parentWidget();
340         QDesignerFormEditorInterface *core = m_formWindow->core();
341         QDesignerLayoutDecorationExtension *deco = qt_extension<QDesignerLayoutDecorationExtension*>(core->extensionManager(), parentWidget);
342 
343         if (deco)
344             deco->removeWidget(w);
345 
346         w->setParent(container);
347         w->setGeometry(rc);
348 
349         if (showIt)
350             w->show();
351     }
352 
353     LayoutInfo::deleteLayout(m_formWindow->core(), m_layoutBase);
354 
355     if (m_parentWidget != m_layoutBase && !qobject_cast<QMainWindow*>(m_layoutBase)) {
356         m_formWindow->unmanageWidget(m_layoutBase);
357         m_layoutBase->hide();
358     } else {
359         QMainWindow *mw = qobject_cast<QMainWindow*>(m_formWindow->mainContainer());
360         if (m_layoutBase != m_formWindow->mainContainer() &&
361                     (!mw || mw->centralWidget() != m_layoutBase))
362             m_layoutBase->setGeometry(m_oldGeometry);
363     }
364 }
365 
breakLayout()366 void Layout::breakLayout()
367 {
368     typedef QMap<QWidget *, QRect> WidgetRectMap;
369     WidgetRectMap rects;
370     /* Store the geometry of the widgets. The idea is to give the user space
371      * to rearrange them, so, we do a adjustSize() on them, unless they want
372      * to grow (expanding widgets like QTextEdit), in which the geometry is
373      * preserved. Note that historically, geometries were re-applied
374      * only after breaking splitters. */
375     for (QWidget *w : qAsConst(m_widgets)) {
376         const QRect geom = w->geometry();
377         const QSize sizeHint = w->sizeHint();
378         const bool restoreGeometry = sizeHint.isEmpty() || sizeHint.width() > geom.width() || sizeHint.height() > geom.height();
379         rects.insert(w, restoreGeometry ? w->geometry() : QRect(geom.topLeft(), QSize()));
380     }
381     const QPoint m_layoutBasePos = m_layoutBase->pos();
382     QDesignerWidgetDataBaseInterface *widgetDataBase = m_formWindow->core()->widgetDataBase();
383 
384     LayoutInfo::deleteLayout(m_formWindow->core(), m_layoutBase);
385 
386     const bool needReparent = (m_reparentLayoutWidget && qobject_cast<QLayoutWidget*>(m_layoutBase)) ||
387                         qobject_cast<QSplitter*>(m_layoutBase)     ||
388                         (!widgetDataBase->isContainer(m_layoutBase, false) &&
389                           m_layoutBase != m_formWindow->mainContainer());
390     const bool add = m_geometries.isEmpty();
391 
392     for (auto it = rects.cbegin(), end = rects.cend(); it != end; ++it) {
393         QWidget *w = it.key();
394         if (needReparent) {
395             w->setParent(m_layoutBase->parentWidget(), {});
396             w->move(m_layoutBasePos + it.value().topLeft());
397             w->show();
398         }
399 
400         const QRect oldGeometry = it.value();
401         if (oldGeometry.isEmpty()) {
402             w->adjustSize();
403         } else {
404             w->resize(oldGeometry.size());
405         }
406 
407         if (add)
408             m_geometries.insert(w, QRect(w->pos(), w->size()));
409     }
410 
411     if (needReparent) {
412         m_layoutBase->hide();
413         m_parentWidget = m_layoutBase->parentWidget();
414         m_formWindow->unmanageWidget(m_layoutBase);
415     } else {
416         m_parentWidget = m_layoutBase;
417     }
418     updateWizardLayout(m_layoutBase);
419 
420     if (!m_widgets.isEmpty() && m_widgets.first() && m_widgets.first()->isVisibleTo(m_formWindow))
421         m_formWindow->selectWidget(m_widgets.first());
422     else
423         m_formWindow->selectWidget(m_formWindow);
424 }
425 
suggestLayoutName(const char * className)426 static QString suggestLayoutName(const char *className)
427 {
428     // Legacy
429     if (!qstrcmp(className, "QHBoxLayout"))
430         return QStringLiteral("horizontalLayout");
431     if (!qstrcmp(className, "QVBoxLayout"))
432         return QStringLiteral("verticalLayout");
433     if (!qstrcmp(className, "QGridLayout"))
434         return QStringLiteral("gridLayout");
435 
436     return qtify(QString::fromUtf8(className));
437 }
createLayout(int type)438 QLayout *Layout::createLayout(int type)
439 {
440     Q_ASSERT(m_layoutType != LayoutInfo::HSplitter && m_layoutType != LayoutInfo::VSplitter);
441     QLayout *layout = m_formWindow->core()->widgetFactory()->createLayout(m_layoutBase, nullptr, type);
442     // set a name
443     layout->setObjectName(suggestLayoutName(layout->metaObject()->className()));
444     m_formWindow->ensureUniqueObjectName(layout);
445     // QLayoutWidget
446     QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(m_formWindow->core()->extensionManager(), layout);
447     if (sheet && qobject_cast<QLayoutWidget*>(m_layoutBase)) {
448         sheet->setProperty(sheet->indexOf(QStringLiteral("leftMargin")), 0);
449         sheet->setProperty(sheet->indexOf(QStringLiteral("topMargin")), 0);
450         sheet->setProperty(sheet->indexOf(QStringLiteral("rightMargin")), 0);
451         sheet->setProperty(sheet->indexOf(QStringLiteral("bottomMargin")), 0);
452     }
453     return layout;
454 }
455 
reparentToLayoutBase(QWidget * w)456 void Layout::reparentToLayoutBase(QWidget *w)
457 {
458     if (w->parent() != m_layoutBase) {
459         w->setParent(m_layoutBase, {});
460         w->move(QPoint(0,0));
461     }
462 }
463 
464 namespace { // within qdesigner_internal
465 
466 // ----- PositionSortPredicate: Predicate to be usable as LessThan function to sort widgets by position
467 class PositionSortPredicate {
468 public:
PositionSortPredicate(Qt::Orientation orientation)469     PositionSortPredicate(Qt::Orientation orientation) : m_orientation(orientation) {}
operator ()(const QWidget * w1,const QWidget * w2)470     bool operator()(const QWidget* w1, const QWidget* w2) {
471         return m_orientation == Qt::Horizontal ? w1->x() < w2->x() : w1->y() < w2->y();
472     }
473     private:
474     const Qt::Orientation m_orientation;
475 };
476 
477 // -------- BoxLayout
478 class BoxLayout : public Layout
479 {
480 public:
481     BoxLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb,
482               Qt::Orientation orientation);
483 
484     void doLayout() override;
485     void sort() override;
486 
487 private:
488     const Qt::Orientation m_orientation;
489 };
490 
BoxLayout(const QWidgetList & wl,QWidget * p,QDesignerFormWindowInterface * fw,QWidget * lb,Qt::Orientation orientation)491 BoxLayout::BoxLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb,
492                      Qt::Orientation orientation)  :
493     Layout(wl, p, fw, lb, orientation == Qt::Horizontal ? LayoutInfo::HBox : LayoutInfo::VBox),
494     m_orientation(orientation)
495 {
496 }
497 
sort()498 void BoxLayout::sort()
499 {
500     QWidgetList wl = widgets();
501     std::stable_sort(wl.begin(), wl.end(), PositionSortPredicate(m_orientation));
502     setWidgets(wl);
503 }
504 
doLayout()505 void BoxLayout::doLayout()
506 {
507     bool needMove, needReparent;
508     if (!prepareLayout(needMove, needReparent))
509         return;
510 
511     QBoxLayout *layout = static_cast<QBoxLayout *>(createLayout(m_orientation == Qt::Horizontal ? LayoutInfo::HBox : LayoutInfo::VBox));
512 
513     QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
514 
515     const  QWidgetList::const_iterator cend = widgets().constEnd();
516     for (QWidgetList::const_iterator it =  widgets().constBegin(); it != cend; ++it) {
517         QWidget *w = *it;
518         if (needReparent)
519             reparentToLayoutBase(w);
520 
521         if (const Spacer *spacer = qobject_cast<const Spacer*>(w))
522             layout->addWidget(w, 0, spacer->alignment());
523         else
524             layout->addWidget(w);
525         w->show();
526     }
527     finishLayout(needMove, layout);
528 }
529 
530 // --------  SplitterLayout
531 class SplitterLayout : public Layout
532 {
533 public:
534     SplitterLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb,
535                    Qt::Orientation orientation);
536 
537     void doLayout() override;
538     void sort() override;
539 
540 private:
541     const Qt::Orientation m_orientation;
542 };
543 
SplitterLayout(const QWidgetList & wl,QWidget * p,QDesignerFormWindowInterface * fw,QWidget * lb,Qt::Orientation orientation)544 SplitterLayout::SplitterLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb,
545                                Qt::Orientation orientation) :
546     Layout(wl, p, fw, lb, orientation == Qt::Horizontal ? LayoutInfo::HSplitter : LayoutInfo::VSplitter),
547     m_orientation(orientation)
548 {
549 }
550 
sort()551 void SplitterLayout::sort()
552 {
553     QWidgetList wl = widgets();
554     std::stable_sort(wl.begin(), wl.end(), PositionSortPredicate(m_orientation));
555     setWidgets(wl);
556 }
557 
doLayout()558 void SplitterLayout::doLayout()
559 {
560     bool needMove, needReparent;
561     if (!prepareLayout(needMove, needReparent))
562         return;
563 
564     QSplitter *splitter = qobject_cast<QSplitter*>(layoutBaseWidget());
565     Q_ASSERT(splitter != nullptr);
566 
567 
568     const  QWidgetList::const_iterator cend = widgets().constEnd();
569     for (QWidgetList::const_iterator it =  widgets().constBegin(); it != cend; ++it) {
570         QWidget *w = *it;
571         if (needReparent)
572             reparentToLayoutBase(w);
573         splitter->addWidget(w);
574         w->show();
575     }
576 
577     splitter->setOrientation(m_orientation);
578     finishLayout(needMove);
579 }
580 
581 //  ---------- Grid: Helper for laying out grids
582 
583 class Grid
584 {
585     Q_DISABLE_COPY_MOVE(Grid);
586 public:
587     enum Mode {
588         GridLayout, // Arbitrary size/supports span
589         FormLayout  // 2-column/no span
590     };
591 
592     Grid(Mode mode);
593     void resize(int nrows, int ncols);
594 
595     ~Grid();
596 
cell(int row,int col) const597     QWidget* cell(int row, int col) const { return m_cells[ row * m_ncols + col]; }
598 
599     void setCells(const QRect &c, QWidget* w);
600 
empty() const601     bool empty() const  { return !m_nrows || !m_ncols; }
numRows() const602     int numRows() const { return m_nrows; }
numCols() const603     int numCols() const { return m_ncols; }
604 
605     void simplify();
606     bool locateWidget(QWidget* w, int& row, int& col, int& rowspan, int& colspan) const;
607 
608 private:
setCell(int row,int col,QWidget * w)609     void setCell(int row, int col, QWidget* w) { m_cells[ row * m_ncols + col] = w; }
610     void shrink();
611     void reallocFormLayout();
612     int countRow(int r, int c) const;
613     int countCol(int r, int c) const;
614     void setRow(int r, int c, QWidget* w, int count);
615     void setCol(int r, int c, QWidget* w, int count);
616     bool isWidgetStartCol(int c) const;
617     bool isWidgetEndCol(int c) const;
618     bool isWidgetStartRow(int r) const;
619     bool isWidgetEndRow(int r) const;
620     bool isWidgetTopLeft(int r, int c) const;
621     void extendLeft();
622     void extendRight();
623     void extendUp();
624     void extendDown();
625     bool shrinkFormLayoutSpans();
626 
627     const Mode m_mode;
628     int m_nrows;
629     int m_ncols;
630 
631     QWidget** m_cells; // widget matrix w11, w12, w21...
632 };
633 
Grid(Mode mode)634 Grid::Grid(Mode mode) :
635     m_mode(mode),
636     m_nrows(0),
637     m_ncols(0),
638     m_cells(nullptr)
639 {
640 }
641 
~Grid()642 Grid::~Grid()
643 {
644     delete [] m_cells;
645 }
646 
resize(int nrows,int ncols)647 void Grid::resize(int nrows, int ncols)
648 {
649     delete [] m_cells;
650     m_cells = nullptr;
651     m_nrows = nrows;
652     m_ncols = ncols;
653     if (const int allocSize = m_nrows * m_ncols) {
654         m_cells = new QWidget*[allocSize];
655         std::fill(m_cells, m_cells + allocSize, nullptr);
656     }
657 }
658 
setCells(const QRect & c,QWidget * w)659 void Grid::setCells(const QRect &c, QWidget* w)
660 {
661     const int bottom = c.top() + c.height();
662     const int width =  c.width();
663 
664     for (int r = c.top(); r < bottom; r++) {
665         QWidget **pos = m_cells + r * m_ncols + c.left();
666         std::fill(pos, pos + width, w);
667     }
668 }
669 
countRow(int r,int c) const670 int Grid::countRow(int r, int c) const
671 {
672     QWidget* w = cell(r, c);
673     int i = c + 1;
674     while (i < m_ncols && cell(r, i) == w)
675         i++;
676     return i - c;
677 }
678 
countCol(int r,int c) const679 int Grid::countCol(int r, int c) const
680 {
681     QWidget* w = cell(r, c);
682     int i = r + 1;
683     while (i < m_nrows && cell(i, c) == w)
684         i++;
685     return i - r;
686 }
687 
setCol(int r,int c,QWidget * w,int count)688 void Grid::setCol(int r, int c, QWidget* w, int count)
689 {
690     for (int i = 0; i < count; i++)
691         setCell(r + i, c, w);
692 }
693 
setRow(int r,int c,QWidget * w,int count)694 void Grid::setRow(int r, int c, QWidget* w, int count)
695 {
696     for (int i = 0; i < count; i++)
697         setCell(r, c + i, w);
698 }
699 
isWidgetStartCol(int c) const700 bool Grid::isWidgetStartCol(int c) const
701 {
702     for (int r = 0; r < m_nrows; r++) {
703         if (cell(r, c) && ((c==0) || (cell(r, c)  != cell(r, c-1)))) {
704             return true;
705         }
706     }
707     return false;
708 }
709 
isWidgetEndCol(int c) const710 bool Grid::isWidgetEndCol(int c) const
711 {
712     for (int r = 0; r < m_nrows; r++) {
713         if (cell(r, c) && ((c == m_ncols-1) || (cell(r, c) != cell(r, c+1))))
714             return true;
715     }
716     return false;
717 }
718 
isWidgetStartRow(int r) const719 bool Grid::isWidgetStartRow(int r) const
720 {
721     for ( int c = 0; c < m_ncols; c++) {
722         if (cell(r, c) && ((r==0) || (cell(r, c) != cell(r-1, c))))
723             return true;
724     }
725     return false;
726 }
727 
isWidgetEndRow(int r) const728 bool Grid::isWidgetEndRow(int r) const
729 {
730     for (int c = 0; c < m_ncols; c++) {
731         if (cell(r, c) && ((r == m_nrows-1) || (cell(r, c) != cell(r+1, c))))
732             return true;
733     }
734     return false;
735 }
736 
737 
isWidgetTopLeft(int r,int c) const738 bool Grid::isWidgetTopLeft(int r, int c) const
739 {
740     QWidget* w = cell(r, c);
741     if (!w)
742         return false;
743     return (!r || cell(r-1, c) != w) && (!c || cell(r, c-1) != w);
744 }
745 
extendLeft()746 void Grid::extendLeft()
747 {
748     for (int c = 1; c < m_ncols; c++) {
749         for (int r = 0; r < m_nrows; r++) {
750             QWidget* w = cell(r, c);
751             if (!w)
752                 continue;
753 
754             const int cc = countCol(r, c);
755             int stretch = 0;
756             for (int i = c-1; i >= 0; i--) {
757                 if (cell(r, i))
758                     break;
759                 if (countCol(r, i) < cc)
760                     break;
761                 if (isWidgetEndCol(i))
762                     break;
763                 if (isWidgetStartCol(i)) {
764                     stretch = c - i;
765                     break;
766                 }
767             }
768             if (stretch) {
769                 for (int i = 0; i < stretch; i++)
770                     setCol(r, c-i-1, w, cc);
771             }
772         }
773     }
774 }
775 
776 
extendRight()777 void Grid::extendRight()
778 {
779     for (int c = m_ncols - 2; c >= 0; c--) {
780         for (int r = 0; r < m_nrows; r++) {
781             QWidget* w = cell(r, c);
782             if (!w)
783                 continue;
784             const int cc = countCol(r, c);
785             int stretch = 0;
786             for (int i = c+1; i < m_ncols; i++) {
787                 if (cell(r, i))
788                     break;
789                 if (countCol(r, i) < cc)
790                     break;
791                 if (isWidgetStartCol(i))
792                     break;
793                 if (isWidgetEndCol(i)) {
794                     stretch = i - c;
795                     break;
796                 }
797             }
798             if (stretch) {
799                 for (int i = 0; i < stretch; i++)
800                     setCol(r, c+i+1, w, cc);
801             }
802         }
803     }
804 
805 }
806 
extendUp()807 void Grid::extendUp()
808 {
809     for (int r = 1; r < m_nrows; r++) {
810         for (int c = 0; c < m_ncols; c++) {
811             QWidget* w = cell(r, c);
812             if (!w)
813                 continue;
814             const int cr = countRow(r, c);
815             int stretch = 0;
816             for (int i = r-1; i >= 0; i--) {
817                 if (cell(i, c))
818                     break;
819                 if (countRow(i, c) < cr)
820                     break;
821                 if (isWidgetEndRow(i))
822                     break;
823                 if (isWidgetStartRow(i)) {
824                     stretch = r - i;
825                     break;
826                 }
827             }
828             if (stretch) {
829                 for (int i = 0; i < stretch; i++)
830                     setRow(r-i-1, c, w, cr);
831             }
832         }
833     }
834 }
835 
extendDown()836 void Grid::extendDown()
837 {
838     for (int r = m_nrows - 2; r >= 0; r--) {
839         for (int c = 0; c < m_ncols; c++) {
840             QWidget* w = cell(r, c);
841             if (!w)
842                 continue;
843             const int cr = countRow(r, c);
844             int stretch = 0;
845             for (int i = r+1; i < m_nrows; i++) {
846                 if (cell(i, c))
847                     break;
848                 if (countRow(i, c) < cr)
849                     break;
850                 if (isWidgetStartRow(i))
851                     break;
852                 if (isWidgetEndRow(i)) {
853                     stretch = i - r;
854                     break;
855                 }
856             }
857             if (stretch) {
858                 for (int i = 0; i < stretch; i++)
859                     setRow(r+i+1, c, w, cr);
860             }
861         }
862     }
863 }
864 
simplify()865 void Grid::simplify()
866 {
867     switch (m_mode) {
868     case GridLayout:
869         // Grid: Extend all widgets to occupy most space and delete
870         // rows/columns that are not bordering on a widget
871         extendLeft();
872         extendRight();
873         extendUp();
874         extendDown();
875         shrink();
876         break;
877     case FormLayout:
878         // Form: First treat it as a grid to get the same behaviour
879         // regarding spanning and shrinking. Then restrict the span to
880         // the horizontal span possible in the form, simplify again
881         // and spread the widgets over a 2-column layout
882         extendLeft();
883         extendRight();
884         extendUp();
885         extendDown();
886         shrink();
887         if (shrinkFormLayoutSpans())
888             shrink();
889         reallocFormLayout();
890         break;
891     }
892 
893 }
894 
shrink()895 void Grid::shrink()
896 {
897     //  tick off the occupied cols/rows (bordering on widget edges)
898     QVector<bool> columns(m_ncols, false);
899     QVector<bool> rows(m_nrows, false);
900 
901     for (int c = 0; c < m_ncols; c++)
902         for (int r = 0; r < m_nrows; r++)
903             if (isWidgetTopLeft(r, c))
904                 rows[r] = columns[c] = true;
905 
906     // remove empty cols/rows
907     const int simplifiedNCols = columns.count(true);
908     const int simplifiedNRows = rows.count(true);
909     if (simplifiedNCols ==  m_ncols && simplifiedNRows == m_nrows)
910         return;
911     // reallocate and copy omitting the empty cells
912     QWidget **simplifiedCells = new QWidget*[simplifiedNCols * simplifiedNRows];
913     std::fill(simplifiedCells, simplifiedCells + simplifiedNCols * simplifiedNRows, nullptr);
914     QWidget **simplifiedPtr = simplifiedCells;
915 
916     for (int r = 0; r < m_nrows; r++)
917         if (rows[r])
918             for (int c = 0; c < m_ncols; c++)
919                 if (columns[c]) {
920                     if (QWidget *w = cell(r, c))
921                         *simplifiedPtr = w;
922                     simplifiedPtr++;
923                 }
924     Q_ASSERT(simplifiedPtr == simplifiedCells + simplifiedNCols * simplifiedNRows);
925     delete [] m_cells;
926     m_cells = simplifiedCells;
927     m_nrows = simplifiedNRows;
928     m_ncols = simplifiedNCols;
929 }
930 
shrinkFormLayoutSpans()931 bool Grid::shrinkFormLayoutSpans()
932 {
933     bool shrunk = false;
934     using WidgetSet = QSet<QWidget *>;
935     // Determine unique set of widgets
936     WidgetSet widgets;
937     QWidget **end =  m_cells + m_ncols * m_nrows;
938     for (QWidget **wptr = m_cells; wptr < end; wptr++)
939         if (QWidget *w = *wptr)
940             widgets.insert(w);
941     // Restrict the widget span: max horizontal span at column 0: 2, anything else: 1
942     const int maxRowSpan = 1;
943     const WidgetSet::const_iterator cend = widgets.constEnd();
944     for (WidgetSet::const_iterator it = widgets.constBegin(); it != cend ; ++it) {
945         QWidget *w = *it;
946         int row, col,  rowspan, colspan;
947         if (!locateWidget(w, row, col, rowspan, colspan)) {
948             qDebug("ooops, widget '%s' does not fit in layout", w->objectName().toUtf8().constData());
949             row = col = rowspan = colspan = 0;
950         }
951         const int maxColSpan = col == 0 ? 2 : 1;
952         const int newColSpan = qMin(colspan, maxColSpan);
953         const int newRowSpan = qMin(rowspan, maxRowSpan);
954         if (newColSpan != colspan || newRowSpan != rowspan) {
955             // in case like this:
956             // W1 W1
957             // W1 W2
958             // do:
959             // W1 0
960             // 0  W2
961             for (int i = row; i < row + rowspan - 1; i++)
962                 for (int j = col; j < col + colspan - 1; j++)
963                     if (i > row + newColSpan - 1 || j > col + newRowSpan - 1)
964                         if (cell(i, j) == w)
965                             setCell(i, j, nullptr);
966             shrunk = true;
967         }
968     }
969     return shrunk;
970 }
971 
reallocFormLayout()972 void Grid::reallocFormLayout()
973 {
974     // Columns matching? -> happy!
975     if (m_ncols == FormLayoutColumns)
976         return;
977 
978     // If there are offset columns (starting past the field column),
979     // move them to the left and squeeze them. This also prevents the
980     // following reallocation from creating empty form rows.
981     int pastRightWidgetCount = 0;
982     if (m_ncols > FormLayoutColumns) {
983         for (int r = 0; r < m_nrows; r++) {
984             // Try to find a column where the form columns are empty and
985             // there are widgets further to the right.
986             if (cell(r, 0) == nullptr && cell(r, 1) == nullptr) {
987                 int sourceCol = FormLayoutColumns;
988                 QWidget *firstWidget = nullptr;
989                 for ( ; sourceCol < m_ncols; sourceCol++)
990                     if (QWidget *w = cell(r, sourceCol)) {
991                         firstWidget = w;
992                         break;
993                     }
994                 if (firstWidget) {
995                     // Move/squeeze. Copy to beginning of column if it is a label, else field
996                     int targetCol = qobject_cast<QLabel*>(firstWidget) ? 0 : 1;
997                     for ( ; sourceCol < m_ncols; sourceCol++)
998                         if (QWidget *w = cell(r, sourceCol))
999                             setCell(r,  targetCol++, w);
1000                     // Pad with zero
1001                     for ( ; targetCol < m_ncols; targetCol++)
1002                         setCell(r, targetCol, nullptr);
1003                 }
1004             }
1005             // Any protruding widgets left on that row?
1006             for (int c = FormLayoutColumns; c < m_ncols; c++)
1007                 if (cell(r, c))
1008                     pastRightWidgetCount++;
1009         }
1010     }
1011     // Reallocate with 2 columns. Just insert the protruding ones as fields.
1012     const int formNRows = m_nrows + pastRightWidgetCount;
1013     QWidget **formCells = new QWidget*[FormLayoutColumns * formNRows];
1014     std::fill(formCells, formCells + FormLayoutColumns * formNRows, nullptr);
1015     QWidget **formPtr = formCells;
1016     const int matchingColumns = qMin(m_ncols, static_cast<int>(FormLayoutColumns));
1017     for (int r = 0; r < m_nrows; r++) {
1018         int c = 0;
1019         for ( ; c < matchingColumns; c++)               // Just copy over matching columns
1020              *formPtr++ = cell(r, c);
1021         formPtr += FormLayoutColumns - matchingColumns; // In case old format was 1 column
1022         // protruding widgets: Insert as single-field rows
1023         for ( ; c < m_ncols; c++)
1024             if (QWidget *w = cell(r, c)) {
1025                 formPtr++;
1026                 *formPtr++ = w;
1027             }
1028     }
1029     Q_ASSERT(formPtr == formCells + FormLayoutColumns * formNRows);
1030     delete [] m_cells;
1031     m_cells = formCells;
1032     m_nrows = formNRows;
1033     m_ncols = FormLayoutColumns;
1034 }
1035 
locateWidget(QWidget * w,int & row,int & col,int & rowspan,int & colspan) const1036 bool Grid::locateWidget(QWidget *w, int &row, int &col, int &rowspan, int &colspan) const
1037 {
1038     const int end = m_nrows * m_ncols;
1039     const int startIndex = std::find(m_cells, m_cells + end, w) - m_cells;
1040     if (startIndex == end)
1041         return false;
1042 
1043     row = startIndex / m_ncols;
1044     col = startIndex % m_ncols;
1045     for (rowspan = 1; row + rowspan < m_nrows && cell(row + rowspan, col) == w; rowspan++) {}
1046     for (colspan = 1; col + colspan < m_ncols && cell(row, col + colspan) == w; colspan++) {}
1047     return true;
1048 }
1049 
1050 // QGridLayout/QFormLayout Helpers: get item position/add item (overloads to make templates work)
1051 
addWidgetToGrid(QGridLayout * lt,QWidget * widget,int row,int column,int rowSpan,int columnSpan,Qt::Alignment alignment)1052 void addWidgetToGrid(QGridLayout *lt, QWidget * widget, int row, int column, int rowSpan, int columnSpan, Qt::Alignment alignment)
1053 {
1054     lt->addWidget(widget, row, column, rowSpan, columnSpan, alignment);
1055 }
1056 
addWidgetToGrid(QFormLayout * lt,QWidget * widget,int row,int column,int,int columnSpan,Qt::Alignment)1057 inline void addWidgetToGrid(QFormLayout *lt, QWidget * widget, int row, int column, int, int columnSpan, Qt::Alignment)
1058 {
1059     formLayoutAddWidget(lt, widget, QRect(column, row,  columnSpan, 1), false);
1060 }
1061 
1062 // ----------- Base template for grid like layouts
1063 template <class GridLikeLayout, int LayoutType, int GridMode>
1064 class GridLayout : public Layout
1065 {
1066 public:
1067     GridLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb);
1068 
1069     void doLayout() override;
sort()1070     void sort() override { setWidgets(buildGrid(widgets())); }
1071 
1072 protected:
1073     QWidgetList buildGrid(const QWidgetList &);
1074     Grid m_grid;
1075 };
1076 
1077 template <class GridLikeLayout, int LayoutType, int GridMode>
GridLayout(const QWidgetList & wl,QWidget * p,QDesignerFormWindowInterface * fw,QWidget * lb)1078 GridLayout<GridLikeLayout, LayoutType, GridMode>::GridLayout(const QWidgetList &wl, QWidget *p, QDesignerFormWindowInterface *fw, QWidget *lb) :
1079     Layout(wl, p, fw, lb, LayoutInfo::Grid),
1080     m_grid(static_cast<Grid::Mode>(GridMode))
1081 {
1082 }
1083 
1084 template <class GridLikeLayout, int LayoutType, int GridMode>
doLayout()1085 void GridLayout<GridLikeLayout, LayoutType, GridMode>::doLayout()
1086 {
1087     bool needMove, needReparent;
1088     if (!prepareLayout(needMove, needReparent))
1089         return;
1090 
1091     GridLikeLayout *layout =  static_cast<GridLikeLayout *>(createLayout(LayoutType));
1092 
1093     if (!m_grid.empty())
1094         sort();
1095 
1096     QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
1097 
1098     const  QWidgetList::const_iterator cend = widgets().constEnd();
1099     for (QWidgetList::const_iterator it =  widgets().constBegin(); it != cend; ++it) {
1100         QWidget *w = *it;
1101         int r = 0, c = 0, rs = 0, cs = 0;
1102 
1103         if (m_grid.locateWidget(w, r, c, rs, cs)) {
1104             if (needReparent)
1105                 reparentToLayoutBase(w);
1106 
1107             Qt::Alignment alignment;
1108             if (const Spacer *spacer = qobject_cast<const Spacer*>(w))
1109                 alignment = spacer->alignment();
1110 
1111             addWidgetToGrid(layout, w, r, c, rs, cs, alignment);
1112 
1113             w->show();
1114         } else {
1115             qDebug("ooops, widget '%s' does not fit in layout", w->objectName().toUtf8().constData());
1116         }
1117     }
1118 
1119     QLayoutSupport::createEmptyCells(layout);
1120 
1121     finishLayout(needMove, layout);
1122 }
1123 
1124 // Remove duplicate entries (Remove next, if equal to current)
removeIntVecDuplicates(QVector<int> & v)1125 void removeIntVecDuplicates(QVector<int> &v)
1126 {
1127     if (v.size() < 2)
1128         return;
1129 
1130     for (QVector<int>::iterator current = v.begin() ; (current != v.end()) && ((current+1) != v.end()) ; )
1131         if ( *current == *(current+1) )
1132             v.erase(current+1);
1133         else
1134             ++current;
1135 }
1136 
1137 // Ensure a non-zero size for a widget geometry (squeezed spacers)
expandGeometry(const QRect & rect)1138 inline QRect expandGeometry(const QRect &rect)
1139 {
1140     return rect.isEmpty() ? QRect(rect.topLeft(), rect.size().expandedTo(QSize(1, 1))) : rect;
1141 }
1142 
1143 template <class GridLikeLayout, int LayoutType, int GridMode>
buildGrid(const QWidgetList & widgetList)1144 QWidgetList GridLayout<GridLikeLayout, LayoutType, GridMode>::buildGrid(const QWidgetList &widgetList)
1145 {
1146     if (widgetList.isEmpty())
1147         return QWidgetList();
1148 
1149     // Pixel to cell conversion:
1150     // By keeping a list of start'n'stop values (x & y) for each widget,
1151     // it is possible to create a very small grid of cells to represent
1152     // the widget layout.
1153     // -----------------------------------------------------------------
1154 
1155     // We need a list of both start and stop values for x- & y-axis
1156     const int widgetCount = widgetList.size();
1157     QVector<int> x( widgetCount * 2 );
1158     QVector<int> y( widgetCount * 2 );
1159 
1160     // Using push_back would look nicer, but operator[] is much faster
1161     int index  = 0;
1162     for (int i = 0; i < widgetCount; ++i) {
1163         const QRect widgetPos = expandGeometry(widgetList.at(i)->geometry());
1164         x[index]   = widgetPos.left();
1165         x[index+1] = widgetPos.right();
1166         y[index]   = widgetPos.top();
1167         y[index+1] = widgetPos.bottom();
1168         index += 2;
1169     }
1170 
1171     std::sort(x.begin(), x.end());
1172     std::sort(y.begin(), y.end());
1173 
1174     // Remove duplicate x entries (Remove next, if equal to current)
1175     removeIntVecDuplicates(x);
1176     removeIntVecDuplicates(y);
1177 
1178     // Note that left == right and top == bottom for size 1 items; reserve
1179     // enough space
1180     m_grid.resize(y.size(), x.size());
1181 
1182     const  QWidgetList::const_iterator cend = widgetList.constEnd();
1183     for (QWidgetList::const_iterator it = widgetList.constBegin(); it != cend; ++it) {
1184         QWidget *w = *it;
1185         // Mark the cells in the grid that contains a widget
1186         const QRect widgetPos = expandGeometry(w->geometry());
1187         QRect c(0, 0, 0, 0); // rect of columns/rows
1188 
1189         // From left til right (not including)
1190         const int leftIdx = x.indexOf(widgetPos.left());
1191         Q_ASSERT(leftIdx != -1);
1192         c.setLeft(leftIdx);
1193         c.setRight(leftIdx);
1194         for (int cw=leftIdx; cw<x.size(); cw++)
1195             if (x[cw] <  widgetPos.right())
1196                 c.setRight(cw);
1197             else
1198                 break;
1199         // From top til bottom (not including)
1200         const int topIdx = y.indexOf(widgetPos.top());
1201         Q_ASSERT(topIdx != -1);
1202         c.setTop(topIdx);
1203         c.setBottom(topIdx);
1204         for (int ch=topIdx; ch<y.size(); ch++)
1205             if (y[ch] <  widgetPos.bottom())
1206                 c.setBottom(ch);
1207             else
1208                 break;
1209         m_grid.setCells(c, w); // Mark cellblock
1210     }
1211 
1212     m_grid.simplify();
1213 
1214     QWidgetList ordered;
1215     for (int i = 0; i < m_grid.numRows(); i++)
1216         for (int j = 0; j < m_grid.numCols(); j++) {
1217             QWidget *w = m_grid.cell(i, j);
1218             if (w && !ordered.contains(w))
1219                 ordered.append(w);
1220         }
1221     return ordered;
1222 }
1223 } // anonymous
1224 
createLayout(const QWidgetList & widgets,QWidget * parentWidget,QDesignerFormWindowInterface * fw,QWidget * layoutBase,LayoutInfo::Type layoutType)1225 Layout* Layout::createLayout(const QWidgetList &widgets,  QWidget *parentWidget,
1226                              QDesignerFormWindowInterface *fw,
1227                              QWidget *layoutBase, LayoutInfo::Type layoutType)
1228 {
1229     switch (layoutType) {
1230     case LayoutInfo::Grid:
1231         return new GridLayout<QGridLayout, LayoutInfo::Grid, Grid::GridLayout>(widgets, parentWidget, fw, layoutBase);
1232     case LayoutInfo::HBox:
1233     case LayoutInfo::VBox: {
1234         const Qt::Orientation orientation = layoutType == LayoutInfo::HBox ? Qt::Horizontal : Qt::Vertical;
1235         return new BoxLayout(widgets, parentWidget, fw, layoutBase, orientation);
1236     }
1237     case LayoutInfo::HSplitter:
1238     case LayoutInfo::VSplitter: {
1239         const Qt::Orientation orientation = layoutType == LayoutInfo::HSplitter ? Qt::Horizontal : Qt::Vertical;
1240         return new SplitterLayout(widgets, parentWidget, fw, layoutBase, orientation);
1241     }
1242     case LayoutInfo::Form:
1243         return new GridLayout<QFormLayout, LayoutInfo::Form, Grid::FormLayout>(widgets, parentWidget, fw, layoutBase);
1244     default:
1245         break;
1246     }
1247     Q_ASSERT(0);
1248     return nullptr;
1249 }
1250 
1251 } // namespace qdesigner_internal
1252 
1253 QT_END_NAMESPACE
1254