source: trunk/src/gui/kernel/qformlayout.cpp@ 460

Last change on this file since 460 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 65.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qapplication.h"
43#include "qdebug.h"
44#include "qformlayout.h"
45#include "qlabel.h"
46#include "qlayout_p.h"
47#include "qlayoutengine_p.h"
48#include "qrect.h"
49#include "qvector.h"
50#include "qwidget.h"
51
52QT_BEGIN_NAMESPACE
53
54namespace {
55// Fixed column matrix, stores items as [i11, i12, i21, i22...],
56// with FORTRAN-style index operator(r, c).
57template <class T, int NumColumns>
58class FixedColumnMatrix {
59public:
60 typedef QVector<T> Storage;
61
62 FixedColumnMatrix() { }
63
64 void clear() { m_storage.clear(); }
65
66 const T &operator()(int r, int c) const { return m_storage[r * NumColumns + c]; }
67 T &operator()(int r, int c) { return m_storage[r * NumColumns + c]; }
68
69 int rowCount() const { return m_storage.size() / NumColumns; }
70 void addRow(const T &value);
71 void insertRow(int r, const T &value);
72 void removeRow(int r);
73
74 bool find(const T &value, int *rowPtr, int *colPtr) const ;
75 int count(const T &value) const { return m_storage.count(value); }
76
77 // Hmmpf.. Some things are faster that way.
78 const Storage &storage() const { return m_storage; }
79
80 static void storageIndexToPosition(int idx, int *rowPtr, int *colPtr);
81
82private:
83 Storage m_storage;
84};
85
86template <class T, int NumColumns>
87void FixedColumnMatrix<T, NumColumns>::addRow(const T &value)
88{
89 for (int i = 0; i < NumColumns; ++i)
90 m_storage.append(value);
91}
92
93template <class T, int NumColumns>
94void FixedColumnMatrix<T, NumColumns>::insertRow(int r, const T &value)
95{
96 Q_TYPENAME Storage::iterator it = m_storage.begin();
97 it += r * NumColumns;
98 m_storage.insert(it, NumColumns, value);
99}
100
101template <class T, int NumColumns>
102void FixedColumnMatrix<T, NumColumns>::removeRow(int r)
103{
104 m_storage.remove(r * NumColumns, NumColumns);
105}
106
107template <class T, int NumColumns>
108bool FixedColumnMatrix<T, NumColumns>::find(const T &value, int *rowPtr, int *colPtr) const
109{
110 const int idx = m_storage.indexOf(value);
111 if (idx == -1)
112 return false;
113 storageIndexToPosition(idx, rowPtr, colPtr);
114 return true;
115}
116
117template <class T, int NumColumns>
118void FixedColumnMatrix<T, NumColumns>::storageIndexToPosition(int idx, int *rowPtr, int *colPtr)
119{
120 *rowPtr = idx / NumColumns;
121 *colPtr = idx % NumColumns;
122}
123} // namespace
124
125// special values for unset fields; must not clash with values of FieldGrowthPolicy or
126// RowWrapPolicy
127const uint DefaultFieldGrowthPolicy = 255;
128const uint DefaultRowWrapPolicy = 255;
129
130enum { ColumnCount = 2 };
131
132// -- our data structure for our items
133// This owns the QLayoutItem
134struct QFormLayoutItem
135{
136 QFormLayoutItem(QLayoutItem* i) : item(i), fullRow(false), isHfw(false) { }
137 ~QFormLayoutItem() { delete item; }
138
139 // Wrappers
140 QWidget *widget() const { return item->widget(); }
141 QLayout *layout() const { return item->layout(); }
142
143 bool hasHeightForWidth() const { return item->hasHeightForWidth(); }
144 int heightForWidth(int width) const { return item->heightForWidth(width); }
145 int minimumHeightForWidth(int width) const { return item->minimumHeightForWidth(width); }
146 Qt::Orientations expandingDirections() const { return item->expandingDirections(); }
147 QSizePolicy::ControlTypes controlTypes() const { return item->controlTypes(); }
148 int vStretch() const { return widget() ? widget()->sizePolicy().verticalStretch() : 0; }
149
150 void setGeometry(const QRect& r) { item->setGeometry(r); }
151 QRect geometry() const { return item->geometry(); }
152
153 // For use with FixedColumnMatrix
154 bool operator==(const QFormLayoutItem& other) { return item == other.item; }
155
156 QLayoutItem *item;
157 bool fullRow;
158
159 // set by updateSizes
160 bool isHfw;
161 QSize minSize;
162 QSize sizeHint;
163 QSize maxSize;
164
165 // also set by updateSizes
166 int sbsHSpace; // only used for side by side, for the field item only (not label)
167 int vSpace; // This is the spacing to the item in the row above
168
169 // set by setupVerticalLayoutData
170 bool sideBySide;
171 int vLayoutIndex;
172
173 // set by setupHorizontalLayoutData
174 int layoutPos;
175 int layoutWidth;
176};
177
178class QFormLayoutPrivate : public QLayoutPrivate
179{
180 Q_DECLARE_PUBLIC(QFormLayout)
181
182public:
183 typedef FixedColumnMatrix<QFormLayoutItem *, ColumnCount> ItemMatrix;
184
185 QFormLayoutPrivate();
186 ~QFormLayoutPrivate() { }
187
188 int insertRow(int row);
189 void insertRows(int row, int count);
190 void setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item);
191 void setLayout(int row, QFormLayout::ItemRole role, QLayout *layout);
192 void setWidget(int row, QFormLayout::ItemRole role, QWidget *widget);
193
194 void arrangeWidgets(const QVector<QLayoutStruct>& layouts, QRect &rect);
195
196 void updateSizes();
197
198 void setupVerticalLayoutData(int width);
199 void setupHorizontalLayoutData(int width);
200
201 QStyle* getStyle() const;
202
203 inline bool haveHfwCached(int width) const
204 {
205 return (hfw_width == width) || (width == sh_width && hfw_sh_height >= 0);
206 }
207
208 void recalcHFW(int w);
209 void setupHfwLayoutData();
210
211 uint fieldGrowthPolicy : 8;
212 uint rowWrapPolicy : 8;
213 uint has_hfw : 2;
214 uint dirty : 2; // have we laid out yet?
215 uint sizesDirty : 2; // have we (not) gathered layout item sizes?
216 uint expandVertical : 1; // Do we expand vertically?
217 uint expandHorizontal : 1; // Do we expand horizonally?
218 Qt::Alignment labelAlignment;
219 Qt::Alignment formAlignment;
220
221 ItemMatrix m_matrix;
222 QList<QFormLayoutItem *> m_things;
223
224 int layoutWidth; // the last width that we called setupVerticalLayoutData on (for vLayouts)
225
226 int hfw_width; // the last width we calculated HFW for
227 int hfw_height; // what that height was
228 int hfw_minheight; // what that minheight was
229
230 int hfw_sh_height; // the hfw for sh_width
231 int hfw_sh_minheight; // the minhfw for sh_width
232
233 int min_width; // the width that gets turned into minSize (from updateSizes)
234 int sh_width; // the width that gets turned into prefSize (from updateSizes)
235 int thresh_width; // the width that we start splitting label/field pairs at (from updateSizes)
236 QSize minSize;
237 QSize prefSize;
238 int formMaxWidth;
239 void calcSizeHints();
240
241 QVector<QLayoutStruct> vLayouts; // set by setupVerticalLayoutData;
242 int vLayoutCount; // Number of rows we calculated in setupVerticalLayoutData
243 int maxLabelWidth; // the label width we calculated in setupVerticalLayoutData
244
245 QVector<QLayoutStruct> hfwLayouts;
246
247 int hSpacing;
248 int vSpacing;
249};
250
251QFormLayoutPrivate::QFormLayoutPrivate()
252 : fieldGrowthPolicy(DefaultFieldGrowthPolicy),
253 rowWrapPolicy(DefaultRowWrapPolicy), has_hfw(false), dirty(true), sizesDirty(true),
254 expandVertical(0), expandHorizontal(0), labelAlignment(0), formAlignment(0),
255 hfw_width(-1), hfw_sh_height(-1), min_width(-1),
256 sh_width(-1), thresh_width(QLAYOUTSIZE_MAX), hSpacing(-1), vSpacing(-1)
257{
258}
259
260static Qt::Alignment fixedAlignment(Qt::Alignment alignment, Qt::LayoutDirection layoutDirection)
261{
262 if (layoutDirection == Qt::RightToLeft && alignment & Qt::AlignAbsolute) {
263 // swap left and right, and eliminate absolute flag
264 return Qt::Alignment((alignment & ~(Qt::AlignLeft | Qt::AlignRight | Qt::AlignAbsolute))
265 | ((alignment & Qt::AlignRight) ? Qt::AlignLeft : 0)
266 | ((alignment & Qt::AlignLeft) ? Qt::AlignRight : 0));
267 } else {
268 return alignment & ~Qt::AlignAbsolute;
269 }
270}
271
272static int storageIndexFromLayoutItem(const QFormLayoutPrivate::ItemMatrix &m,
273 QFormLayoutItem *item)
274{
275 if (item) {
276 return m.storage().indexOf(item);
277 } else {
278 return -1;
279 }
280}
281
282static void updateFormLayoutItem(QFormLayoutItem *item, int userVSpacing,
283 QFormLayout::FieldGrowthPolicy fieldGrowthPolicy,
284 bool fullRow)
285{
286 item->minSize = item->item->minimumSize();
287 item->sizeHint = item->item->sizeHint();
288 item->maxSize = item->item->maximumSize();
289
290 if (!fullRow && (fieldGrowthPolicy == QFormLayout::FieldsStayAtSizeHint
291 || (fieldGrowthPolicy == QFormLayout::ExpandingFieldsGrow
292 && !(item->item->expandingDirections() & Qt::Horizontal))))
293 item->maxSize.setWidth(item->sizeHint.width());
294
295 item->isHfw = item->item->hasHeightForWidth();
296 item->vSpace = userVSpacing;
297}
298
299/*
300 Iterate over all the controls and gather their size information
301 (min, sizeHint and max). Also work out what the spacing between
302 pairs of controls should be, and figure out the min and sizeHint
303 widths.
304*/
305void QFormLayoutPrivate::updateSizes()
306{
307 Q_Q(QFormLayout);
308
309 if (sizesDirty) {
310 QFormLayout::RowWrapPolicy wrapPolicy = q->rowWrapPolicy();
311 bool wrapAllRows = (wrapPolicy == QFormLayout::WrapAllRows);
312 bool dontWrapRows = (wrapPolicy == QFormLayout::DontWrapRows);
313 int rr = m_matrix.rowCount();
314
315 has_hfw = false;
316
317 // If any control can expand, so can this layout
318 // Wrapping doesn't affect expansion, though, just the minsize
319 bool expandH = false;
320 bool expandV = false;
321
322 QFormLayoutItem *prevLbl = 0;
323 QFormLayoutItem *prevFld = 0;
324
325 QWidget *parent = q->parentWidget();
326 QStyle *style = parent ? parent->style() : 0;
327
328 int userVSpacing = q->verticalSpacing();
329 int userHSpacing = wrapAllRows ? 0 : q->horizontalSpacing();
330
331 int maxMinLblWidth = 0;
332 int maxMinFldWidth = 0; // field with label
333 int maxMinIfldWidth = 0; // independent field
334
335 int maxShLblWidth = 0;
336 int maxShFldWidth = 0;
337 int maxShIfldWidth = 0;
338
339 for (int i = 0; i < rr; ++i) {
340 QFormLayoutItem *label = m_matrix(i, 0);
341 QFormLayoutItem *field = m_matrix(i, 1);
342
343 // Skip empty rows
344 if (!label && !field)
345 continue;
346
347 if (label) {
348 updateFormLayoutItem(label, userVSpacing, q->fieldGrowthPolicy(), false);
349 if (label->isHfw)
350 has_hfw = true;
351 Qt::Orientations o = label->expandingDirections();
352
353 if (o & Qt::Vertical)
354 expandV = true;
355 if (o & Qt::Horizontal)
356 expandH = true;
357 }
358 if (field) {
359 updateFormLayoutItem(field, userVSpacing, q->fieldGrowthPolicy(), !label && field->fullRow);
360 field->sbsHSpace = (!label && field->fullRow) ? 0 : userHSpacing;
361 if (field->isHfw)
362 has_hfw = true;
363
364 Qt::Orientations o = field->expandingDirections();
365
366 if (o & Qt::Vertical)
367 expandV = true;
368 if (o & Qt::Horizontal)
369 expandH = true;
370 }
371
372 // See if we need to calculate default spacings
373 if ((userHSpacing < 0 || userVSpacing < 0) && style) {
374 QSizePolicy::ControlTypes lbltypes =
375 QSizePolicy::ControlTypes(label ? label->controlTypes() : QSizePolicy::DefaultType);
376 QSizePolicy::ControlTypes fldtypes =
377 QSizePolicy::ControlTypes(field ? field->controlTypes() : QSizePolicy::DefaultType);
378
379 // VSpacing
380 if (userVSpacing < 0) {
381 if (wrapAllRows) {
382 // label spacing is to a previous item
383 QFormLayoutItem *lbltop = prevFld ? prevFld : prevLbl;
384 // field spacing is to the label (or a previous item)
385 QFormLayoutItem *fldtop = label ? label : lbltop;
386 QSizePolicy::ControlTypes lbltoptypes =
387 QSizePolicy::ControlTypes(lbltop ? lbltop->controlTypes() : QSizePolicy::DefaultType);
388 QSizePolicy::ControlTypes fldtoptypes =
389 QSizePolicy::ControlTypes(fldtop ? fldtop->controlTypes() : QSizePolicy::DefaultType);
390 if (label && lbltop)
391 label->vSpace = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, 0, parent);
392 if (field && fldtop)
393 field->vSpace = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, 0, parent);
394 } else {
395 // Side by side.. we have to also consider the spacings to empty cells, which can strangely be more than
396 // non empty cells..
397 QFormLayoutItem *lbltop = prevLbl ? prevLbl : prevFld;
398 QFormLayoutItem *fldtop = prevFld;
399 QSizePolicy::ControlTypes lbltoptypes =
400 QSizePolicy::ControlTypes(lbltop ? lbltop->controlTypes() : QSizePolicy::DefaultType);
401 QSizePolicy::ControlTypes fldtoptypes =
402 QSizePolicy::ControlTypes(fldtop ? fldtop->controlTypes() : QSizePolicy::DefaultType);
403
404 // To be compatible to QGridLayout, we have to compare solitary labels & fields with both predecessors
405 if (label) {
406 if (!field) {
407 int lblspacing = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, 0, parent);
408 int fldspacing = style->combinedLayoutSpacing(fldtoptypes, lbltypes, Qt::Vertical, 0, parent);
409 label->vSpace = qMax(lblspacing, fldspacing);
410 } else
411 label->vSpace = style->combinedLayoutSpacing(lbltoptypes, lbltypes, Qt::Vertical, 0, parent);
412 }
413
414 if (field) {
415 // check spacing against both the previous label and field
416 if (!label) {
417 int lblspacing = style->combinedLayoutSpacing(lbltoptypes, fldtypes, Qt::Vertical, 0, parent);
418 int fldspacing = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, 0, parent);
419 field->vSpace = qMax(lblspacing, fldspacing);
420 } else
421 field->vSpace = style->combinedLayoutSpacing(fldtoptypes, fldtypes, Qt::Vertical, 0, parent);
422 }
423 }
424 }
425
426 // HSpacing
427 // hard-coded the left and right control types so that all the rows have the same
428 // inter-column spacing (otherwise the right column isn't always left aligned)
429 if (userHSpacing < 0 && !wrapAllRows && (label || !field->fullRow) && field)
430 field->sbsHSpace = style->combinedLayoutSpacing(QSizePolicy::Label, QSizePolicy::LineEdit, Qt::Horizontal, 0, parent);
431 }
432
433 // Now update our min/sizehint widths
434 // We choose to put the spacing in the field side in sbs, so
435 // the right edge of the labels will align, but fields may
436 // be a little ragged.. since different controls may have
437 // different appearances, a slight raggedness in the left
438 // edges of fields can be tolerated.
439 // (Note - field->sbsHSpace is 0 for WrapAllRows mode)
440 if (label) {
441 maxMinLblWidth = qMax(maxMinLblWidth, label->minSize.width());
442 maxShLblWidth = qMax(maxShLblWidth, label->sizeHint.width());
443 if (field) {
444 maxMinFldWidth = qMax(maxMinFldWidth, field->minSize.width() + field->sbsHSpace);
445 maxShFldWidth = qMax(maxShFldWidth, field->sizeHint.width() + field->sbsHSpace);
446 }
447 } else if (field) {
448 maxMinIfldWidth = qMax(maxMinIfldWidth, field->minSize.width());
449 maxShIfldWidth = qMax(maxShIfldWidth, field->sizeHint.width());
450 }
451
452 prevLbl = label;
453 prevFld = field;
454 }
455
456 // Now, finally update the min/sizeHint widths
457 if (wrapAllRows) {
458 sh_width = qMax(maxShLblWidth, qMax(maxShIfldWidth, maxShFldWidth));
459 min_width = qMax(maxMinLblWidth, qMax(maxMinIfldWidth, maxMinFldWidth));
460 // in two line, we don't care as much about the threshold width
461 thresh_width = 0;
462 } else if (dontWrapRows) {
463 // This is just the max widths glommed together
464 sh_width = qMax(maxShLblWidth + maxShFldWidth, maxShIfldWidth);
465 min_width = qMax(maxMinLblWidth + maxMinFldWidth, maxMinIfldWidth);
466 thresh_width = QWIDGETSIZE_MAX;
467 } else {
468 // This is just the max widths glommed together
469 sh_width = qMax(maxShLblWidth + maxShFldWidth, maxShIfldWidth);
470 // min width needs to be the min when everything is wrapped,
471 // otherwise we'll never get set with a width that causes wrapping
472 min_width = qMax(maxMinLblWidth, qMax(maxMinIfldWidth, maxMinFldWidth));
473 // We split a pair at label sh + field min (### for now..)
474 thresh_width = maxShLblWidth + maxMinFldWidth;
475 }
476
477 // Update the expansions
478 expandVertical = expandV;
479 expandHorizontal = expandH;
480 }
481 sizesDirty = false;
482}
483
484void QFormLayoutPrivate::recalcHFW(int w)
485{
486 setupHfwLayoutData();
487
488 int h = 0;
489 int mh = 0;
490
491 for (int r = 0; r < vLayoutCount; ++r) {
492 int spacing = hfwLayouts.at(r).spacing;
493 h += hfwLayouts.at(r).sizeHint + spacing;
494 mh += hfwLayouts.at(r).minimumSize + spacing;
495 }
496
497 if (sh_width > 0 && sh_width == w) {
498 hfw_sh_height = qMin(QLAYOUTSIZE_MAX, h);
499 hfw_sh_minheight = qMin(QLAYOUTSIZE_MAX, mh);
500 } else {
501 hfw_width = w;
502 hfw_height = qMin(QLAYOUTSIZE_MAX, h);
503 hfw_minheight = qMin(QLAYOUTSIZE_MAX, mh);
504 }
505}
506
507void QFormLayoutPrivate::setupHfwLayoutData()
508{
509 // setupVerticalLayoutData must be called before this
510 // setupHorizontalLayoutData must also be called before this
511 // copies non hfw data into hfw
512 // then updates size and min
513
514
515 // Note: QGridLayout doesn't call minimumHeightForWidth,
516 // but instead uses heightForWidth for both min and sizeHint.
517 // For the common case where minimumHeightForWidth just calls
518 // heightForWidth, we do the calculation twice, which can be
519 // very expensive for word wrapped QLabels/QTextEdits, for example.
520 // So we just use heightForWidth as well.
521 int i;
522 int rr = m_matrix.rowCount();
523
524 hfwLayouts.clear();
525 hfwLayouts.resize(vLayoutCount);
526 for (i = 0; i < vLayoutCount; ++i)
527 hfwLayouts[i] = vLayouts.at(i);
528
529 for (i = 0; i < rr; ++i) {
530 QFormLayoutItem *label = m_matrix(i, 0);
531 QFormLayoutItem *field = m_matrix(i, 1);
532
533 if (label) {
534 if (label->isHfw) {
535 // We don't check sideBySide here, since a label is only
536 // ever side by side with its field
537 int hfw = label->heightForWidth(label->layoutWidth);
538 hfwLayouts[label->vLayoutIndex].minimumSize = hfw;
539 hfwLayouts[label->vLayoutIndex].sizeHint = hfw;
540 } else {
541 // Reset these here, so the field can do a qMax below (the previous value may have
542 // been the fields non-hfw values, which are often larger than hfw)
543 hfwLayouts[label->vLayoutIndex].sizeHint = label->sizeHint.height();
544 hfwLayouts[label->vLayoutIndex].minimumSize = label->minSize.height();
545 }
546 }
547
548 if (field) {
549 int hfw = field->isHfw ? field->heightForWidth(field->layoutWidth) : 0;
550 int h = field->isHfw ? hfw : field->sizeHint.height();
551 int mh = field->isHfw ? hfw : field->minSize.height();
552
553 if (field->sideBySide) {
554 int oh = hfwLayouts.at(field->vLayoutIndex).sizeHint;
555 int omh = hfwLayouts.at(field->vLayoutIndex).minimumSize;
556
557 hfwLayouts[field->vLayoutIndex].sizeHint = qMax(h, oh);
558 hfwLayouts[field->vLayoutIndex].minimumSize = qMax(mh, omh);
559 } else {
560 hfwLayouts[field->vLayoutIndex].sizeHint = h;
561 hfwLayouts[field->vLayoutIndex].minimumSize = mh;
562 }
563 }
564 }
565}
566
567/*
568 Given up to four items involved in a vertical spacing calculation
569 (two rows * two columns), return the max vertical spacing for the
570 row containing item1 (which may also include item2)
571 We assume parent and item1 are not null.
572
573 If a particular row is split, then the spacings for that row and
574 the following row are affected, and this function should be
575 called with recalculate = true for both rows (note: only rows with both
576 a label and a field can be split).
577
578 In particular:
579
580 1) the split label's row vspace needs to be changed to qMax(label/prevLabel, label/prevField)
581 [call with item1 = label, item2 = null, prevItem1 & prevItem2 as before]
582 2) the split field's row vspace needs to be changed to the label/field spacing
583 [call with item1 = field, item2 = null, prevItem1 = label, prevItem2 = null]
584
585 [if the next row has one item, 'item']
586 3a) the following row's vspace needs to be changed to item/field spacing (would
587 previously been the qMax(item/label, item/field) spacings)
588 [call with item1 = item, item2 = null, prevItem1 = field, prevItem2 = null]
589
590 [if the next row has two items, 'label2' and 'field2']
591 3b) the following row's vspace needs to be changed to be qMax(field/label2, field/field2) spacing
592 [call with item1 = label2, item2 = field2, prevItem1 = field, prevItem2 = null]
593
594 In the (common) non split case, we can just use the precalculated vspace (possibly qMaxed between
595 label and field).
596
597 If recalculate is true, we expect:
598 - parent != null
599 - item1 != null
600 - item2 can be null
601 - prevItem1 can be null
602 - if item2 is not null, prevItem2 will be null (e.g. steps 1 or 3 above)
603 - if prevItem1 is null, prevItem2 will be null
604*/
605static inline int spacingHelper(QWidget* parent, QStyle *style, int userVSpacing, bool recalculate, QFormLayoutItem* item1, QFormLayoutItem* item2, QFormLayoutItem* prevItem1, QFormLayoutItem *prevItem2)
606{
607 int spacing = userVSpacing;
608 if (spacing < 0) {
609 if (!recalculate) {
610 if (item1)
611 spacing = item1->vSpace;
612 if (item2)
613 spacing = qMax(spacing, item2->vSpace);
614 } else {
615 if (style && prevItem1) {
616 QSizePolicy::ControlTypes itemtypes =
617 QSizePolicy::ControlTypes(item1 ? item1->controlTypes() : QSizePolicy::DefaultType);
618 int spacing2 = 0;
619
620 spacing = style->combinedLayoutSpacing(itemtypes, prevItem1->controlTypes(), Qt::Vertical, 0, parent);
621
622 // At most of one of item2 and prevItem2 will be nonnull
623 if (item2)
624 spacing2 = style->combinedLayoutSpacing(item2->controlTypes(), prevItem1->controlTypes(), Qt::Vertical, 0, parent);
625 else if (prevItem2)
626 spacing2 = style->combinedLayoutSpacing(itemtypes, prevItem2->controlTypes(), Qt::Vertical, 0, parent);
627
628 spacing = qMax(spacing, spacing2);
629 }
630 }
631 } else {
632 if (prevItem1) {
633 QWidget *wid = prevItem1->item->widget();
634 if (wid)
635 spacing = qMax(spacing, prevItem1->geometry().top() - wid->geometry().top() );
636 }
637 if (prevItem2) {
638 QWidget *wid = prevItem2->item->widget();
639 if (wid)
640 spacing = qMax(spacing, prevItem2->geometry().top() - wid->geometry().top() );
641 }
642 }
643 return spacing;
644}
645
646static inline void initLayoutStruct(QLayoutStruct& sl, QFormLayoutItem* item)
647{
648 sl.init(item->vStretch(), item->minSize.height());
649 sl.sizeHint = item->sizeHint.height();
650 sl.maximumSize = item->maxSize.height();
651 sl.expansive = (item->expandingDirections() & Qt::Vertical);
652 sl.empty = false;
653}
654
655void QFormLayoutPrivate::setupVerticalLayoutData(int width)
656{
657 Q_Q(QFormLayout);
658
659 // Early out if we have no changes that would cause a change in vertical layout
660 if ((width == layoutWidth || (width >= thresh_width && layoutWidth >= thresh_width)) && !dirty && !sizesDirty)
661 return;
662
663 layoutWidth = width;
664
665 int rr = m_matrix.rowCount();
666 int vidx = 1;
667 QFormLayout::RowWrapPolicy rowWrapPolicy = q->rowWrapPolicy();
668 bool wrapAllRows = (rowWrapPolicy == QFormLayout::WrapAllRows);
669 bool addTopBottomStretch = true;
670
671 vLayouts.clear();
672 vLayouts.resize((2 * rr) + 2); // a max, some may be unused
673
674 QStyle *style = 0;
675
676 int userVSpacing = q->verticalSpacing();
677
678 if (userVSpacing < 0) {
679 if (QWidget *widget = q->parentWidget())
680 style = widget->style();
681 }
682
683 // make sure our sizes are up to date
684 updateSizes();
685
686 // Grab the widest label width here
687 // This might be different from the value computed during
688 // sizeHint/minSize, since we don't count label/field pairs that
689 // are split.
690 maxLabelWidth = 0;
691 if (!wrapAllRows) {
692 for (int i = 0; i < rr; ++i) {
693 const QFormLayoutItem *label = m_matrix(i, 0);
694 const QFormLayoutItem *field = m_matrix(i, 1);
695 if (label && (label->sizeHint.width() + (field ? field->minSize.width() : 0) <= width))
696 maxLabelWidth = qMax(maxLabelWidth, label->sizeHint.width());
697 }
698 } else {
699 maxLabelWidth = width;
700 }
701
702 QFormLayoutItem *prevItem1 = 0;
703 QFormLayoutItem *prevItem2 = 0;
704 bool prevRowSplit = false;
705
706 for (int i = 0; i < rr; ++i) {
707 QFormLayoutItem *label = m_matrix(i, 0);
708 QFormLayoutItem *field = m_matrix(i, 1);
709
710 // Totally ignore empty rows...
711 if (!label && !field)
712 continue;
713
714 QSize min1;
715 QSize min2;
716 QSize sh1;
717 QSize sh2;
718 if (label) {
719 min1 = label->minSize;
720 sh1 = label->sizeHint;
721 }
722 if (field) {
723 min2 = field->minSize;
724 sh2 = field->sizeHint;
725 }
726
727 // In separate lines, we make a vLayout for everything that isn't null
728 // in side by side, we only separate label/field if we're going to wrap it
729 bool splitSideBySide = (rowWrapPolicy == QFormLayout::WrapLongRows)
730 && ((maxLabelWidth < sh1.width()) || (width < (maxLabelWidth + min2.width())));
731
732 if (wrapAllRows || splitSideBySide) {
733 if (label) {
734 initLayoutStruct(vLayouts[vidx], label);
735
736 if (vidx > 1)
737 vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, splitSideBySide || prevRowSplit, label, 0, prevItem1, prevItem2);
738
739 label->vLayoutIndex = vidx;
740 label->sideBySide = false;
741
742 prevItem1 = label;
743 prevItem2 = 0;
744
745 if (vLayouts[vidx].stretch > 0)
746 addTopBottomStretch = false;
747
748 ++vidx;
749 }
750
751 if (field) {
752 initLayoutStruct(vLayouts[vidx], field);
753
754 if (vidx > 1)
755 vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, splitSideBySide || prevRowSplit, field, 0, prevItem1, prevItem2);
756
757 field->vLayoutIndex = vidx;
758 field->sideBySide = false;
759
760 prevItem1 = field;
761 prevItem2 = 0;
762
763 if (vLayouts[vidx].stretch > 0)
764 addTopBottomStretch = false;
765
766 ++vidx;
767 }
768
769 prevRowSplit = splitSideBySide;
770 } else {
771 // we're in side by side mode, and we have enough space to do that
772 QSize max1(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
773 QSize max2(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
774
775 int stretch1 = 0;
776 int stretch2 = 0;
777 bool expanding = false;
778
779 if (label) {
780 max1 = label->maxSize;
781 if (label->expandingDirections() & Qt::Vertical)
782 expanding = true;
783
784 label->sideBySide = (field != 0);
785 label->vLayoutIndex = vidx;
786 stretch1 = label->vStretch();
787 }
788
789 if (field) {
790 max2 = field->maxSize;
791 if (field->expandingDirections() & Qt::Vertical)
792 expanding = true;
793
794 field->sideBySide = (label || !field->fullRow);
795 field->vLayoutIndex = vidx;
796 stretch2 = field->vStretch();
797 }
798
799 vLayouts[vidx].init(qMax(stretch1, stretch2), qMax(min1.height(), min2.height()));
800 vLayouts[vidx].sizeHint = qMax(sh1.height(), sh2.height());
801 vLayouts[vidx].maximumSize = qMin(max1.height(), max2.height());
802 vLayouts[vidx].expansive = expanding || (vLayouts[vidx].stretch > 0);
803 vLayouts[vidx].empty = false;
804
805 if (vLayouts[vidx].stretch > 0)
806 addTopBottomStretch = false;
807
808 if (vidx > 1)
809 vLayouts[vidx - 1].spacing = spacingHelper(q->parentWidget(), style, userVSpacing, prevRowSplit, label, field, prevItem1, prevItem2);
810
811 if (label) {
812 prevItem1 = label;
813 prevItem2 = field;
814 } else {
815 prevItem1 = field;
816 prevItem2 = 0;
817 }
818
819 prevRowSplit = false;
820 ++vidx;
821 }
822 }
823
824 if (addTopBottomStretch) {
825 Qt::Alignment formAlignment = q->formAlignment();
826
827 if (!(formAlignment & Qt::AlignBottom)) {
828 // AlignTop (default if unspecified) or AlignVCenter: We add a stretch at the bottom
829 vLayouts[vidx].init(1, 0);
830 vLayouts[vidx].expansive = true;
831 ++vidx;
832 }
833
834 if (formAlignment & (Qt::AlignVCenter | Qt::AlignBottom)) {
835 // AlignVCenter or AlignBottom: We add a stretch at the top
836 vLayouts[0].init(1, 0);
837 vLayouts[0].expansive = true;
838 } else {
839 vLayouts[0].init(0, 0);
840 }
841 } else {
842 vLayouts[0].init(0, 0);
843 }
844
845 vLayoutCount = vidx;
846 dirty = false;
847}
848
849void QFormLayoutPrivate::setupHorizontalLayoutData(int width)
850{
851 Q_Q(QFormLayout);
852
853 // requires setupVerticalLayoutData to be called first
854
855 int fieldMaxWidth = 0;
856
857 int rr = m_matrix.rowCount();
858 bool wrapAllRows = (q->rowWrapPolicy() == QFormLayout::WrapAllRows);
859
860 for (int i = 0; i < rr; ++i) {
861 QFormLayoutItem *label = m_matrix(i, 0);
862 QFormLayoutItem *field = m_matrix(i, 1);
863
864 // Totally ignore empty rows...
865 if (!label && !field)
866 continue;
867
868 if (label) {
869 // if there is a field, and we're side by side, we use maxLabelWidth
870 // otherwise we just use the sizehint
871 label->layoutWidth = (field && label->sideBySide) ? maxLabelWidth : label->sizeHint.width();
872 label->layoutPos = 0;
873 }
874
875 if (field) {
876 // This is the default amount allotted to fields in sbs
877 int fldwidth = width - maxLabelWidth - field->sbsHSpace;
878
879 // If we've split a row, we still decide to align
880 // the field with all the other field if it will fit
881 // Fields in sbs mode get the remnants of the maxLabelWidth
882 if (!field->sideBySide) {
883 if (wrapAllRows || (!label && field->fullRow) || field->sizeHint.width() > fldwidth) {
884 field->layoutWidth = width;
885 field->layoutPos = 0;
886 } else {
887 field->layoutWidth = fldwidth;
888 field->layoutPos = width - fldwidth;
889 }
890 } else {
891 // We're sbs, so we should have a label
892 field->layoutWidth = fldwidth;
893 field->layoutPos = width - fldwidth;
894 }
895
896 fieldMaxWidth = qMax(fieldMaxWidth, field->maxSize.width());
897 }
898 }
899
900 formMaxWidth = maxLabelWidth + fieldMaxWidth;
901}
902
903void QFormLayoutPrivate::calcSizeHints()
904{
905 Q_Q(QFormLayout);
906
907 int leftMargin, topMargin, rightMargin, bottomMargin;
908 q->getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
909
910 updateSizes();
911 setupVerticalLayoutData(QLAYOUTSIZE_MAX);
912 // Don't need to call setupHorizontal here
913
914 int h = topMargin + bottomMargin;
915 int mh = topMargin + bottomMargin;
916
917 // The following are set in updateSizes
918 int w = sh_width + leftMargin + rightMargin;
919 int mw = min_width + leftMargin + rightMargin;
920
921 for (int i = 0; i < vLayoutCount; ++i) {
922 int spacing = vLayouts.at(i).spacing;
923 h += vLayouts.at(i).sizeHint + spacing;
924 mh += vLayouts.at(i).minimumSize + spacing;
925 }
926
927 minSize.rwidth() = qMin(mw, QLAYOUTSIZE_MAX);
928 minSize.rheight() = qMin(mh, QLAYOUTSIZE_MAX);
929 prefSize.rwidth() = qMin(w, QLAYOUTSIZE_MAX);
930 prefSize.rheight() = qMin(h, QLAYOUTSIZE_MAX);
931}
932
933int QFormLayoutPrivate::insertRow(int row)
934{
935 int rowCnt = m_matrix.rowCount();
936 if (uint(row) > uint(rowCnt))
937 row = rowCnt;
938
939 insertRows(row, 1);
940 return row;
941}
942
943void QFormLayoutPrivate::insertRows(int row, int count)
944{
945 while (count > 0) {
946 m_matrix.insertRow(row, 0);
947 --count;
948 }
949}
950
951void QFormLayoutPrivate::setItem(int row, QFormLayout::ItemRole role, QLayoutItem *item)
952{
953 const bool fullRow = role == QFormLayout::SpanningRole;
954 const int column = role == QFormLayout::SpanningRole ? 1 : static_cast<int>(role);
955 if (uint(row) >= uint(m_matrix.rowCount()) || uint(column) > 1U) {
956 qWarning("QFormLayoutPrivate::setItem: Invalid cell (%d, %d)", row, column);
957 return;
958 }
959
960 if (!item)
961 return;
962
963 if (m_matrix(row, column)) {
964 qWarning("QFormLayoutPrivate::setItem: Cell (%d, %d) already occupied", row, column);
965 return;
966 }
967
968 QFormLayoutItem *i = new QFormLayoutItem(item);
969 i->fullRow = fullRow;
970 m_matrix(row, column) = i;
971
972 m_things.append(i);
973}
974
975void QFormLayoutPrivate::setLayout(int row, QFormLayout::ItemRole role, QLayout *layout)
976{
977 if (layout) {
978 Q_Q(QFormLayout);
979 q->addChildLayout(layout);
980 setItem(row, role, layout);
981 }
982}
983
984void QFormLayoutPrivate::setWidget(int row, QFormLayout::ItemRole role, QWidget *widget)
985{
986 if (widget) {
987 Q_Q(QFormLayout);
988 q->addChildWidget(widget);
989 setItem(row, role, QLayoutPrivate::createWidgetItem(q, widget));
990 }
991}
992
993QStyle* QFormLayoutPrivate::getStyle() const
994{
995 Q_Q(const QFormLayout);
996
997 // ### cache
998 if (QWidget *parentWidget = q->parentWidget())
999 return parentWidget->style();
1000 else
1001 return QApplication::style();
1002}
1003
1004/*!
1005 \class QFormLayout
1006 \since 4.4
1007 \brief The QFormLayout class manages forms of input widgets and their associated labels.
1008
1009 \ingroup appearance
1010 \ingroup geomanagement
1011
1012 \mainclass
1013
1014 QFormLayout is a convenience layout class that lays out its
1015 children in a two-column form. The left column consists of labels
1016 and the right column consists of "field" widgets (line editors,
1017 spin boxes, etc.).
1018
1019 Traditionally, such two-column form layouts were achieved using
1020 QGridLayout. QFormLayout is a higher-level alternative that
1021 provides the following advantages:
1022
1023 \list
1024 \o \bold{Adherence to the different platform's look and feel guidelines.}
1025
1026 For example, the
1027 \l{Mac OS X Aqua} and KDE guidelines specify that the
1028 labels should be right-aligned, whereas Windows and GNOME
1029 applications normally use left-alignment.
1030
1031 \o \bold{Support for wrapping long rows.}
1032
1033 For devices with small displays, QFormLayout can be set to
1034 \l{WrapLongRows}{wrap long rows}, or even to
1035 \l{WrapAllRows}{wrap all rows}.
1036
1037 \o \bold{Convenient API for creating label--field pairs.}
1038
1039 The addRow() overload that takes a QString and a QWidget *
1040 creates a QLabel behind the scenes and automatically set up
1041 its buddy. We can then write code like this:
1042
1043 \snippet doc/src/snippets/code/src_gui_kernel_qformlayout.cpp 0
1044
1045 Compare this with the following code, written using QGridLayout:
1046
1047 \snippet doc/src/snippets/code/src_gui_kernel_qformlayout.cpp 1
1048 \endlist
1049
1050 The table below shows the default appearance in different styles.
1051
1052 \table
1053 \header
1054 \o QCommonStyle derived styles (except QPlastiqueStyle)
1055 \o QMacStyle
1056 \o QPlastiqueStyle
1057 \o Qt Extended styles
1058 \row
1059 \o \inlineimage qformlayout-win.png
1060 \o \inlineimage qformlayout-mac.png
1061 \o \inlineimage qformlayout-kde.png
1062 \o \inlineimage qformlayout-qpe.png
1063 \row
1064 \o Traditional style used for Windows, GNOME, and earlier
1065 versions of KDE. Labels are left aligned, and expanding
1066 fields grow to fill the available space. (This normally
1067 corresponds to what we would get using a two-column
1068 QGridLayout.)
1069 \o Style based on the
1070 \l{Mac OS X Aqua} guidelines. Labels are right-aligned,
1071 the fields don't grow beyond their size hint, and the
1072 form is horizontally centered.
1073 \o Recommended style for
1074 \l{KDE applications}. Similar to MacStyle, except that the form
1075 is left-aligned and all fields grow to fill the available
1076 space.
1077 \o Default style for Qt Extended styles. Labels are right-aligned,
1078 expanding fields grow to fill the available space, and row
1079 wrapping is enabled for long lines.
1080 \endtable
1081
1082 The form styles can be also be overridden individually by calling
1083 setLabelAlignment(), setFormAlignment(), setFieldGrowthPolicy(),
1084 and setRowWrapPolicy(). For example, to simulate the form layout
1085 appearance of QMacStyle on all platforms, but with left-aligned
1086 labels, you could write:
1087
1088 \snippet doc/src/snippets/code/src_gui_kernel_qformlayout.cpp 2
1089
1090 \sa QGridLayout, QBoxLayout, QStackedLayout
1091*/
1092
1093
1094/*!
1095 \enum QFormLayout::FieldGrowthPolicy
1096
1097 This enum specifies the different policies that can be used to
1098 control the way in which the form's fields grow.
1099
1100 \value FieldsStayAtSizeHint
1101 The fields never grow beyond their
1102 \l{QWidgetItem::sizeHint()}{effective size hint}. This is
1103 the default for QMacStyle.
1104
1105 \value ExpandingFieldsGrow
1106 Fields with an horizontal \l{QSizePolicy}{size policy} of
1107 \l{QSizePolicy::}{Expanding} or
1108 \l{QSizePolicy::}{MinimumExpanding} will grow to fill the
1109 available space. The other fields will not grow beyond
1110 their effective size hint. This is the default policy for
1111 Plastique.
1112
1113 \value AllNonFixedFieldsGrow
1114 All fields with a size policy that allows them to grow
1115 will grow to fill the available space. This is the default
1116 policy for most styles.
1117
1118 \sa fieldGrowthPolicy
1119*/
1120
1121/*!
1122 \enum QFormLayout::RowWrapPolicy
1123
1124 This enum specifies the different policies that can be used to
1125 control the way in which the form's rows wrap.
1126
1127 \value DontWrapRows
1128 Fields are always laid out next to their label. This is
1129 the default policy for all styles except Qt Extended styles.
1130
1131 \value WrapLongRows
1132 Labels are given enough horizontal space to fit the widest label,
1133 and the rest of the space is given to the fields. If the minimum
1134 size of a field pair is wider than the available space, the field
1135 is wrapped to the next line. This is the default policy for
1136 Qt Extended styles.
1137
1138 \value WrapAllRows
1139 Fields are always laid out below their label.
1140
1141 \sa rowWrapPolicy
1142*/
1143
1144/*!
1145 \enum QFormLayout::ItemRole
1146
1147 This enum specifies the types of widgets (or other layout items)
1148 that may appear in a row.
1149
1150 \value LabelRole A label widget.
1151 \value FieldRole A field widget.
1152 \value SpanningRole A widget that spans label and field columns.
1153
1154 \sa itemAt(), getItemPosition()
1155*/
1156
1157/*!
1158 Constructs a new form layout with the given \a parent widget.
1159
1160 \sa QWidget::setLayout()
1161*/
1162QFormLayout::QFormLayout(QWidget *parent)
1163 : QLayout(*new QFormLayoutPrivate, 0, parent)
1164{
1165}
1166
1167/*!
1168 Destroys the form layout.
1169*/
1170QFormLayout::~QFormLayout()
1171{
1172 Q_D(QFormLayout);
1173
1174 /*
1175 The clearing and destruction order here is important. We start by clearing
1176 m_things so that QLayout and the rest of the world know that we don't babysit
1177 the layout items anymore and don't care if they are destroyed.
1178 */
1179 d->m_things.clear();
1180 qDeleteAll(d->m_matrix.storage());
1181 d->m_matrix.clear();
1182}
1183
1184/*!
1185 Adds a new row to the bottom of this form layout, with the given
1186 \a label and \a field.
1187
1188 \sa insertRow()
1189*/
1190void QFormLayout::addRow(QWidget *label, QWidget *field)
1191{
1192 insertRow(-1, label, field);
1193}
1194
1195/*!
1196 \overload
1197*/
1198void QFormLayout::addRow(QWidget *label, QLayout *field)
1199{
1200 insertRow(-1, label, field);
1201}
1202
1203/*!
1204 \overload
1205
1206 This overload automatically creates a QLabel behind the scenes
1207 with \a labelText as its text. The \a field is set as the new
1208 QLabel's \l{QLabel::setBuddy()}{buddy}.
1209*/
1210void QFormLayout::addRow(const QString &labelText, QWidget *field)
1211{
1212 insertRow(-1, labelText, field);
1213}
1214
1215/*!
1216 \overload
1217
1218 This overload automatically creates a QLabel behind the scenes
1219 with \a labelText as its text.
1220*/
1221void QFormLayout::addRow(const QString &labelText, QLayout *field)
1222{
1223 insertRow(-1, labelText, field);
1224}
1225
1226/*!
1227 \overload
1228
1229 Adds the specified \a widget at the end of this form layout. The
1230 \a widget spans both columns.
1231*/
1232void QFormLayout::addRow(QWidget *widget)
1233{
1234 insertRow(-1, widget);
1235}
1236
1237/*!
1238 \overload
1239
1240 Adds the specified \a layout at the end of this form layout. The
1241 \a layout spans both columns.
1242*/
1243void QFormLayout::addRow(QLayout *layout)
1244{
1245 insertRow(-1, layout);
1246}
1247
1248/*!
1249 Inserts a new row at position \a row in this form layout, with
1250 the given \a label and \a field. If \a row is out of bounds, the
1251 new row is added at the end.
1252
1253 \sa addRow()
1254*/
1255void QFormLayout::insertRow(int row, QWidget *label, QWidget *field)
1256{
1257 Q_D(QFormLayout);
1258
1259 row = d->insertRow(row);
1260 if (label)
1261 d->setWidget(row, LabelRole, label);
1262 if (field)
1263 d->setWidget(row, FieldRole, field);
1264 invalidate();
1265}
1266
1267/*!
1268 \overload
1269*/
1270void QFormLayout::insertRow(int row, QWidget *label, QLayout *field)
1271{
1272 Q_D(QFormLayout);
1273
1274 row = d->insertRow(row);
1275 if (label)
1276 d->setWidget(row, LabelRole, label);
1277 if (field)
1278 d->setLayout(row, FieldRole, field);
1279 invalidate();
1280}
1281
1282/*!
1283 \overload
1284
1285 This overload automatically creates a QLabel behind the scenes
1286 with \a labelText as its text. The \a field is set as the new
1287 QLabel's \l{QLabel::setBuddy()}{buddy}.
1288*/
1289void QFormLayout::insertRow(int row, const QString &labelText, QWidget *field)
1290{
1291 QLabel *label = 0;
1292 if (!labelText.isEmpty()) {
1293 label = new QLabel(labelText);
1294#ifndef QT_NO_SHORTCUT
1295 label->setBuddy(field);
1296#endif
1297 }
1298 insertRow(row, label, field);
1299}
1300
1301/*!
1302 \overload
1303
1304 This overload automatically creates a QLabel behind the scenes
1305 with \a labelText as its text.
1306*/
1307void QFormLayout::insertRow(int row, const QString &labelText, QLayout *field)
1308{
1309 insertRow(row, labelText.isEmpty() ? 0 : new QLabel(labelText), field);
1310}
1311
1312/*!
1313 \overload
1314
1315 Inserts the specified \a widget at position \a row in this form
1316 layout. The \a widget spans both columns. If \a row is out of
1317 bounds, the widget is added at the end.
1318*/
1319void QFormLayout::insertRow(int row, QWidget *widget)
1320{
1321 Q_D(QFormLayout);
1322
1323 if (!widget) {
1324 qWarning("QFormLayout: Cannot add null field to %s", qPrintable(objectName()));
1325 return;
1326 }
1327
1328 row = d->insertRow(row);
1329 d->setWidget(row, SpanningRole, widget);
1330 invalidate();
1331}
1332
1333/*!
1334 \overload
1335
1336 Inserts the specified \a layout at position \a row in this form
1337 layout. The \a layout spans both columns. If \a row is out of
1338 bounds, the widget is added at the end.
1339*/
1340void QFormLayout::insertRow(int row, QLayout *layout)
1341{
1342 Q_D(QFormLayout);
1343
1344 if (!layout) {
1345 qWarning("QFormLayout: Cannot add null field to %s", qPrintable(objectName()));
1346 return;
1347 }
1348
1349 row = d->insertRow(row);
1350 d->setLayout(row, SpanningRole, layout);
1351 invalidate();
1352}
1353
1354/*!
1355 \reimp
1356*/
1357void QFormLayout::addItem(QLayoutItem *item)
1358{
1359 Q_D(QFormLayout);
1360
1361 int row = d->insertRow(d->m_matrix.rowCount());
1362 d->setItem(row, FieldRole, item);
1363 invalidate();
1364}
1365
1366/*!
1367 \reimp
1368*/
1369int QFormLayout::count() const
1370{
1371 Q_D(const QFormLayout);
1372 return d->m_things.count();
1373}
1374
1375/*!
1376 \reimp
1377*/
1378QLayoutItem *QFormLayout::itemAt(int index) const
1379{
1380 Q_D(const QFormLayout);
1381 if (QFormLayoutItem *formItem = d->m_things.value(index))
1382 return formItem->item;
1383 return 0;
1384}
1385
1386/*!
1387 \reimp
1388*/
1389QLayoutItem *QFormLayout::takeAt(int index)
1390{
1391 Q_D(QFormLayout);
1392
1393 const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index));
1394 if (storageIndex == -1) {
1395 qWarning("QFormLayout::takeAt: Invalid index %d", index);
1396 return 0;
1397 }
1398
1399 int row, col;
1400 QFormLayoutPrivate::ItemMatrix::storageIndexToPosition(storageIndex, &row, &col);
1401 Q_ASSERT(d->m_matrix(row, col));
1402
1403 QFormLayoutItem *item = d->m_matrix(row, col);
1404 Q_ASSERT(item);
1405 d->m_things.removeAt(index);
1406 d->m_matrix(row, col) = 0;
1407
1408 invalidate();
1409
1410 // grab ownership back from the QFormLayoutItem
1411 QLayoutItem *i = item->item;
1412 item->item = 0;
1413 delete item;
1414 return i;
1415}
1416
1417/*!
1418 \reimp
1419*/
1420Qt::Orientations QFormLayout::expandingDirections() const
1421{
1422 Q_D(const QFormLayout);
1423 QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
1424 e->updateSizes();
1425
1426 Qt::Orientations o = 0;
1427 if (e->expandHorizontal)
1428 o = Qt::Horizontal;
1429 if (e->expandVertical)
1430 o |= Qt::Vertical;
1431 return o;
1432}
1433
1434/*!
1435 \reimp
1436*/
1437bool QFormLayout::hasHeightForWidth() const
1438{
1439 Q_D(const QFormLayout);
1440 QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
1441 e->updateSizes();
1442 return (d->has_hfw || rowWrapPolicy() == WrapLongRows);
1443}
1444
1445/*!
1446 \reimp
1447*/
1448int QFormLayout::heightForWidth(int width) const
1449{
1450 Q_D(const QFormLayout);
1451 if (!hasHeightForWidth())
1452 return -1;
1453
1454 int leftMargin, topMargin, rightMargin, bottomMargin;
1455 getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
1456
1457 int targetWidth = width - leftMargin - rightMargin;
1458
1459 if (!d->haveHfwCached(targetWidth)) {
1460 QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1461 dat->setupVerticalLayoutData(targetWidth);
1462 dat->setupHorizontalLayoutData(targetWidth);
1463 dat->recalcHFW(targetWidth);
1464 }
1465 if (targetWidth == d->sh_width)
1466 return d->hfw_sh_height + topMargin + bottomMargin;
1467 else
1468 return d->hfw_height + topMargin + bottomMargin;
1469}
1470
1471/*!
1472 \reimp
1473*/
1474void QFormLayout::setGeometry(const QRect &rect)
1475{
1476 Q_D(QFormLayout);
1477 if (d->dirty || rect != geometry()) {
1478 QRect cr = rect;
1479 int leftMargin, topMargin, rightMargin, bottomMargin;
1480 getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
1481 cr.adjust(+leftMargin, +topMargin, -rightMargin, -bottomMargin);
1482
1483 bool hfw = hasHeightForWidth();
1484 d->setupVerticalLayoutData(cr.width());
1485 d->setupHorizontalLayoutData(cr.width());
1486 if (hfw && (!d->haveHfwCached(cr.width()) || d->hfwLayouts.size() != d->vLayoutCount))
1487 d->recalcHFW(cr.width());
1488 if (hfw) {
1489 qGeomCalc(d->hfwLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
1490 d->arrangeWidgets(d->hfwLayouts, cr);
1491 } else {
1492 qGeomCalc(d->vLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
1493 d->arrangeWidgets(d->vLayouts, cr);
1494 }
1495 QLayout::setGeometry(rect);
1496 }
1497}
1498
1499/*!
1500 \reimp
1501*/
1502QSize QFormLayout::sizeHint() const
1503{
1504 Q_D(const QFormLayout);
1505 if (!d->prefSize.isValid()) {
1506 QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1507 dat->calcSizeHints();
1508 }
1509 return d->prefSize;
1510}
1511
1512/*!
1513 \reimp
1514*/
1515QSize QFormLayout::minimumSize() const
1516{
1517 // ### fix minimumSize if hfw
1518 Q_D(const QFormLayout);
1519 if (!d->minSize.isValid()) {
1520 QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1521 dat->calcSizeHints();
1522 }
1523 return d->minSize;
1524}
1525
1526/*!
1527 \reimp
1528*/
1529void QFormLayout::invalidate()
1530{
1531 Q_D(QFormLayout);
1532 d->dirty = true;
1533 d->sizesDirty = true;
1534 d->minSize = QSize();
1535 d->prefSize = QSize();
1536 d->formMaxWidth = -1;
1537 d->hfw_width = -1;
1538 d->sh_width = -1;
1539 d->layoutWidth = -1;
1540 d->hfw_sh_height = -1;
1541 QLayout::invalidate();
1542}
1543
1544/*!
1545 Returns the number of rows in the form.
1546
1547 \sa QLayout::count()
1548*/
1549int QFormLayout::rowCount() const
1550{
1551 Q_D(const QFormLayout);
1552 return d->m_matrix.rowCount();
1553}
1554
1555/*!
1556 Returns the layout item in the given \a row with the specified \a
1557 role (column). Returns 0 if there is no such item.
1558
1559 \sa QLayout::itemAt(), setItem()
1560*/
1561QLayoutItem *QFormLayout::itemAt(int row, ItemRole role) const
1562{
1563 Q_D(const QFormLayout);
1564 if (uint(row) >= uint(d->m_matrix.rowCount()))
1565 return 0;
1566 switch (role) {
1567 case SpanningRole:
1568 if (QFormLayoutItem *item = d->m_matrix(row, 1))
1569 if (item->fullRow)
1570 return item->item;
1571 break;
1572 case LabelRole:
1573 case FieldRole:
1574 if (QFormLayoutItem *item = d->m_matrix(row, (role == LabelRole) ? 0 : 1))
1575 return item->item;
1576 break;
1577 }
1578 return 0;
1579}
1580
1581/*!
1582 Retrieves the row and role (column) of the item at the specified
1583 \a index. If \a index is out of bounds, *\a rowPtr is set to -1;
1584 otherwise the row is stored in *\a rowPtr and the role is stored
1585 in *\a rolePtr.
1586
1587 \sa itemAt(), count(), getLayoutPosition(), getWidgetPosition()
1588*/
1589void QFormLayout::getItemPosition(int index, int *rowPtr, ItemRole *rolePtr) const
1590{
1591 Q_D(const QFormLayout);
1592 int col = -1;
1593 int row = -1;
1594
1595 const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index));
1596 if (storageIndex != -1)
1597 QFormLayoutPrivate::ItemMatrix::storageIndexToPosition(storageIndex, &row, &col);
1598
1599 if (rowPtr)
1600 *rowPtr = row;
1601 if (rolePtr && col != -1) {
1602 const bool spanning = col == 1 && d->m_matrix(row, col)->fullRow;
1603 if (spanning) {
1604 *rolePtr = SpanningRole;
1605 } else {
1606 *rolePtr = ItemRole(col);
1607 }
1608 }
1609}
1610
1611/*!
1612 Retrieves the row and role (column) of the specified child \a
1613 layout. If \a layout is not in the form layout, *\a rowPtr is set
1614 to -1; otherwise the row is stored in *\a rowPtr and the role is stored
1615 in *\a rolePtr.
1616*/
1617void QFormLayout::getLayoutPosition(QLayout *layout, int *rowPtr, ItemRole *rolePtr) const
1618{
1619 int n = count();
1620 int index = 0;
1621 while (index < n) {
1622 if (itemAt(index) == layout)
1623 break;
1624 ++index;
1625 }
1626 getItemPosition(index, rowPtr, rolePtr);
1627}
1628
1629/*!
1630 Retrieves the row and role (column) of the specified \a widget in
1631 the layout. If \a widget is not in the layout, *\a rowPtr is set
1632 to -1; otherwise the row is stored in *\a rowPtr and the role is stored
1633 in *\a rolePtr.
1634
1635 \sa getItemPosition(), itemAt()
1636*/
1637void QFormLayout::getWidgetPosition(QWidget *widget, int *rowPtr, ItemRole *rolePtr) const
1638{
1639 getItemPosition(indexOf(widget), rowPtr, rolePtr);
1640}
1641
1642// ### eliminate labelForField()
1643
1644/*!
1645 Returns the label associated with the given \a field.
1646
1647 \sa itemAt()
1648*/
1649QWidget *QFormLayout::labelForField(QWidget *field) const
1650{
1651 Q_D(const QFormLayout);
1652
1653 int row;
1654 ItemRole role;
1655
1656 getWidgetPosition(field, &row, &role);
1657
1658 if (row != -1 && role == FieldRole) {
1659 if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
1660 return label->widget();
1661 }
1662 return 0;
1663}
1664
1665/*!
1666 \overload
1667*/
1668QWidget *QFormLayout::labelForField(QLayout *field) const
1669{
1670 Q_D(const QFormLayout);
1671
1672 int row;
1673 ItemRole role;
1674
1675 getLayoutPosition(field, &row, &role);
1676
1677 if (row != -1 && role == FieldRole) {
1678 if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
1679 return label->widget();
1680 }
1681 return 0;
1682}
1683
1684/*!
1685 \property QFormLayout::fieldGrowthPolicy
1686 \brief the way in which the form's fields grow
1687
1688 The default value depends on the widget or application style. For
1689 QMacStyle, the default is FieldsStayAtSizeHint; for QCommonStyle
1690 derived styles (like Plastique and Windows), the default
1691 is ExpandingFieldsGrow; for Qt Extended styles, the default is
1692 AllNonFixedFieldsGrow.
1693
1694 If none of the fields can grow and the form is resized, extra
1695 space is distributed according to the current
1696 \l{formAlignment}{form alignment}.
1697
1698 \sa formAlignment, rowWrapPolicy
1699*/
1700
1701void QFormLayout::setFieldGrowthPolicy(FieldGrowthPolicy policy)
1702{
1703 Q_D(QFormLayout);
1704 if (FieldGrowthPolicy(d->fieldGrowthPolicy) != policy) {
1705 d->fieldGrowthPolicy = policy;
1706 invalidate();
1707 }
1708}
1709
1710QFormLayout::FieldGrowthPolicy QFormLayout::fieldGrowthPolicy() const
1711{
1712 Q_D(const QFormLayout);
1713 if (d->fieldGrowthPolicy == DefaultFieldGrowthPolicy) {
1714 return QFormLayout::FieldGrowthPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutFieldGrowthPolicy));
1715 } else {
1716 return QFormLayout::FieldGrowthPolicy(d->fieldGrowthPolicy);
1717 }
1718}
1719
1720/*!
1721 \property QFormLayout::rowWrapPolicy
1722 \brief the way in which the form's rows wrap
1723
1724 The default value depends on the widget or application style. For
1725 Qt Extended styles, the default is WrapLongRows; for the other styles,
1726 the default is DontWrapRows.
1727
1728 If you want to display each label above its associated field
1729 (instead of next to it), set this property to WrapAllRows.
1730
1731 \sa fieldGrowthPolicy
1732*/
1733
1734void QFormLayout::setRowWrapPolicy(RowWrapPolicy policy)
1735{
1736 Q_D(QFormLayout);
1737 if (RowWrapPolicy(d->rowWrapPolicy) != policy) {
1738 d->rowWrapPolicy = policy;
1739 invalidate();
1740 }
1741}
1742
1743QFormLayout::RowWrapPolicy QFormLayout::rowWrapPolicy() const
1744{
1745 Q_D(const QFormLayout);
1746 if (d->rowWrapPolicy == DefaultRowWrapPolicy) {
1747 return QFormLayout::RowWrapPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutWrapPolicy));
1748 } else {
1749 return QFormLayout::RowWrapPolicy(d->rowWrapPolicy);
1750 }
1751}
1752
1753/*!
1754 \property QFormLayout::labelAlignment
1755 \brief the horizontal alignment of the labels
1756
1757 The default value depends on the widget or application style. For
1758 QCommonStyle derived styles, except for QPlastiqueStyle, the
1759 default is Qt::AlignLeft; for the other styles, the default is
1760 Qt::AlignRight.
1761
1762 \sa formAlignment
1763*/
1764
1765void QFormLayout::setLabelAlignment(Qt::Alignment alignment)
1766{
1767 Q_D(QFormLayout);
1768 if (d->labelAlignment != alignment) {
1769 d->labelAlignment = alignment;
1770 invalidate();
1771 }
1772}
1773
1774Qt::Alignment QFormLayout::labelAlignment() const
1775{
1776 Q_D(const QFormLayout);
1777 if (!d->labelAlignment) {
1778 return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
1779 } else {
1780 return d->labelAlignment;
1781 }
1782}
1783
1784/*!
1785 \property QFormLayout::formAlignment
1786 \brief the alignment of the form layout's contents within the layout's geometry
1787
1788 The default value depends on the widget or application style. For
1789 QMacStyle, the default is Qt::AlignHCenter | Qt::AlignTop; for the
1790 other styles, the default is Qt::AlignLeft | Qt::AlignTop.
1791
1792 \sa labelAlignment, rowWrapPolicy
1793*/
1794
1795void QFormLayout::setFormAlignment(Qt::Alignment alignment)
1796{
1797 Q_D(QFormLayout);
1798 if (d->formAlignment != alignment) {
1799 d->formAlignment = alignment;
1800 invalidate();
1801 }
1802}
1803
1804Qt::Alignment QFormLayout::formAlignment() const
1805{
1806 Q_D(const QFormLayout);
1807 if (!d->formAlignment) {
1808 return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutFormAlignment));
1809 } else {
1810 return d->formAlignment;
1811 }
1812}
1813
1814/*!
1815 \property QFormLayout::horizontalSpacing
1816 \brief the spacing between widgets that are laid out side by side
1817
1818 By default, if no value is explicitly set, the layout's horizontal
1819 spacing is inherited from the parent layout, or from the style settings
1820 for the parent widget.
1821
1822 \sa verticalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
1823*/
1824void QFormLayout::setHorizontalSpacing(int spacing)
1825{
1826 Q_D(QFormLayout);
1827 if (spacing != d->hSpacing) {
1828 d->hSpacing = spacing;
1829 invalidate();
1830 }
1831}
1832
1833int QFormLayout::horizontalSpacing() const
1834{
1835 Q_D(const QFormLayout);
1836 if (d->hSpacing >= 0) {
1837 return d->hSpacing;
1838 } else {
1839 return qSmartSpacing(this, QStyle::PM_LayoutHorizontalSpacing);
1840 }
1841}
1842
1843/*!
1844 \property QFormLayout::verticalSpacing
1845 \brief the spacing between widgets that are laid out vertically
1846
1847 By default, if no value is explicitly set, the layout's vertical spacing is
1848 inherited from the parent layout, or from the style settings for the parent
1849 widget.
1850
1851 \sa horizontalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
1852*/
1853void QFormLayout::setVerticalSpacing(int spacing)
1854{
1855 Q_D(QFormLayout);
1856 if (spacing != d->vSpacing) {
1857 d->vSpacing = spacing;
1858 invalidate();
1859 }
1860}
1861
1862int QFormLayout::verticalSpacing() const
1863{
1864 Q_D(const QFormLayout);
1865 if (d->vSpacing >= 0) {
1866 return d->vSpacing;
1867 } else {
1868 return qSmartSpacing(this, QStyle::PM_LayoutVerticalSpacing);
1869 }
1870}
1871
1872/*!
1873 This function sets both the vertical and horizontal spacing to
1874 \a spacing.
1875
1876 \sa setVerticalSpacing(), setHorizontalSpacing()
1877*/
1878void QFormLayout::setSpacing(int spacing)
1879{
1880 Q_D(QFormLayout);
1881 d->vSpacing = d->hSpacing = spacing;
1882 invalidate();
1883}
1884
1885/*!
1886 If the vertical spacing is equal to the horizontal spacing,
1887 this function returns that value; otherwise it returns -1.
1888
1889 \sa setSpacing(), verticalSpacing(), horizontalSpacing()
1890*/
1891int QFormLayout::spacing() const
1892{
1893 int hSpacing = horizontalSpacing();
1894 if (hSpacing == verticalSpacing()) {
1895 return hSpacing;
1896 } else {
1897 return -1;
1898 }
1899}
1900
1901void QFormLayoutPrivate::arrangeWidgets(const QVector<QLayoutStruct>& layouts, QRect &rect)
1902{
1903 Q_Q(QFormLayout);
1904
1905 int i;
1906 const int rr = m_matrix.rowCount();
1907 QWidget *w = q->parentWidget();
1908 Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : QApplication::layoutDirection();
1909
1910 Qt::Alignment formAlignment = fixedAlignment(q->formAlignment(), layoutDirection);
1911 int leftOffset = 0;
1912 int delta = rect.width() - formMaxWidth;
1913 if (formAlignment & (Qt::AlignHCenter | Qt::AlignRight) && delta > 0) {
1914 leftOffset = delta;
1915 if (formAlignment & Qt::AlignHCenter)
1916 leftOffset >>= 1;
1917 }
1918
1919 for (i = 0; i < rr; ++i) {
1920 QFormLayoutItem *label = m_matrix(i, 0);
1921 QFormLayoutItem *field = m_matrix(i, 1);
1922
1923 if (label) {
1924 int height = layouts.at(label->vLayoutIndex).size;
1925 if ((label->expandingDirections() & Qt::Vertical) == 0) {
1926 /*
1927 If the field on the right-hand side is tall,
1928 we want the label to be top-aligned, but not too
1929 much. So we introduce a 5 / 4 factor so that it
1930 gets a few extra pixels at the top.
1931 */
1932 height = qMin(height,
1933 qMin(label->sizeHint.height() * 5 / 4,
1934 label->maxSize.height()));
1935 }
1936
1937 QSize sz(qMin(label->layoutWidth, label->sizeHint.width()), height);
1938 int x = leftOffset + rect.x() + label->layoutPos;
1939 if (fixedAlignment(q->labelAlignment(), layoutDirection) & Qt::AlignRight)
1940 x += label->layoutWidth - sz.width();
1941 QPoint p(x, layouts.at(label->vLayoutIndex).pos);
1942 // ### expansion & sizepolicy stuff
1943
1944 label->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
1945 }
1946
1947 if (field) {
1948 QSize sz(field->layoutWidth, layouts.at(field->vLayoutIndex).size);
1949 QPoint p(field->layoutPos + leftOffset + rect.x(), layouts.at(field->vLayoutIndex).pos);
1950/*
1951 if ((field->widget() && field->widget()->sizePolicy().horizontalPolicy() & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag | QSizePolicy::IgnoreFlag))
1952 || (field->layout() && sz.width() < field->maxSize.width())) {
1953 sz.rwidth() = field->layoutWidth;
1954 }
1955*/
1956 if (field->maxSize.isValid())
1957 sz = sz.boundedTo(field->maxSize);
1958
1959 field->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
1960 }
1961 }
1962}
1963
1964/*!
1965 Sets the widget in the given \a row for the given \a role to \a widget, extending the
1966 layout with empty rows if necessary.
1967
1968 If the cell is already occupied, the \a widget is not inserted and an error message is
1969 sent to the console.
1970
1971 \bold{Note:} For most applications, addRow() or insertRow() should be used instead of setWidget().
1972
1973 \sa setLayout()
1974*/
1975void QFormLayout::setWidget(int row, ItemRole role, QWidget *widget)
1976{
1977 Q_D(QFormLayout);
1978 int rowCnt = rowCount();
1979 if (row >= rowCnt)
1980 d->insertRows(rowCnt, row - rowCnt + 1);
1981 d->setWidget(row, role, widget);
1982}
1983
1984/*!
1985 Sets the sub-layout in the given \a row for the given \a role to \a layout, extending the
1986 form layout with empty rows if necessary.
1987
1988 If the cell is already occupied, the \a layout is not inserted and an error message is
1989 sent to the console.
1990
1991 \bold{Note:} For most applications, addRow() or insertRow() should be used instead of setLayout().
1992
1993 \sa setWidget()
1994*/
1995void QFormLayout::setLayout(int row, ItemRole role, QLayout *layout)
1996{
1997 Q_D(QFormLayout);
1998 int rowCnt = rowCount();
1999 if (row >= rowCnt)
2000 d->insertRows(rowCnt, row - rowCnt + 1);
2001 d->setLayout(row, role, layout);
2002}
2003
2004/*!
2005 Sets the item in the given \a row for the given \a role to \a item, extending the
2006 layout with empty rows if necessary.
2007
2008 If the cell is already occupied, the \a item is not inserted and an error message is
2009 sent to the console.
2010 The \a item spans both columns.
2011
2012 \warning Do not use this function to add child layouts or child
2013 widget items. Use setLayout() or setWidget() instead.
2014
2015 \sa setLayout()
2016*/
2017void QFormLayout::setItem(int row, ItemRole role, QLayoutItem *item)
2018{
2019 Q_D(QFormLayout);
2020 int rowCnt = rowCount();
2021 if (row >= rowCnt)
2022 d->insertRows(rowCnt, row - rowCnt + 1);
2023 d->setItem(row, role, item);
2024}
2025
2026/*!
2027 \internal
2028 */
2029
2030void QFormLayout::resetFieldGrowthPolicy()
2031{
2032 Q_D(QFormLayout);
2033 d->fieldGrowthPolicy = DefaultFieldGrowthPolicy;
2034}
2035
2036/*!
2037 \internal
2038 */
2039
2040void QFormLayout::resetRowWrapPolicy()
2041{
2042 Q_D(QFormLayout);
2043 d->rowWrapPolicy = DefaultRowWrapPolicy;
2044}
2045
2046/*!
2047 \internal
2048 */
2049
2050void QFormLayout::resetFormAlignment()
2051{
2052 Q_D(QFormLayout);
2053 d->formAlignment = 0;
2054}
2055
2056/*!
2057 \internal
2058 */
2059
2060void QFormLayout::resetLabelAlignment()
2061{
2062 Q_D(QFormLayout);
2063 d->labelAlignment = 0;
2064}
2065
2066#if 0
2067void QFormLayout::dump() const
2068{
2069 Q_D(const QFormLayout);
2070 for (int i = 0; i < rowCount(); ++i) {
2071 for (int j = 0; j < 2; ++j) {
2072 qDebug("m_matrix(%d, %d) = %p", i, j, d->m_matrix(i, j));
2073 }
2074 }
2075 for (int i = 0; i < d->m_things.count(); ++i)
2076 qDebug("m_things[%d] = %p", i, d->m_things.at(i));
2077}
2078#endif
2079
2080QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.