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

Last change on this file since 603 was 561, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.1 sources.

File size: 65.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
37** Nokia 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 layoutWidth(-1), 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 geomanagement
1010
1011
1012 QFormLayout is a convenience layout class that lays out its
1013 children in a two-column form. The left column consists of labels
1014 and the right column consists of "field" widgets (line editors,
1015 spin boxes, etc.).
1016
1017 Traditionally, such two-column form layouts were achieved using
1018 QGridLayout. QFormLayout is a higher-level alternative that
1019 provides the following advantages:
1020
1021 \list
1022 \o \bold{Adherence to the different platform's look and feel guidelines.}
1023
1024 For example, the
1025 \l{Mac OS X Aqua} and KDE guidelines specify that the
1026 labels should be right-aligned, whereas Windows and GNOME
1027 applications normally use left-alignment.
1028
1029 \o \bold{Support for wrapping long rows.}
1030
1031 For devices with small displays, QFormLayout can be set to
1032 \l{WrapLongRows}{wrap long rows}, or even to
1033 \l{WrapAllRows}{wrap all rows}.
1034
1035 \o \bold{Convenient API for creating label--field pairs.}
1036
1037 The addRow() overload that takes a QString and a QWidget *
1038 creates a QLabel behind the scenes and automatically set up
1039 its buddy. We can then write code like this:
1040
1041 \snippet doc/src/snippets/code/src_gui_kernel_qformlayout.cpp 0
1042
1043 Compare this with the following code, written using QGridLayout:
1044
1045 \snippet doc/src/snippets/code/src_gui_kernel_qformlayout.cpp 1
1046 \endlist
1047
1048 The table below shows the default appearance in different styles.
1049
1050 \table
1051 \header
1052 \o QCommonStyle derived styles (except QPlastiqueStyle)
1053 \o QMacStyle
1054 \o QPlastiqueStyle
1055 \o Qt Extended styles
1056 \row
1057 \o \inlineimage qformlayout-win.png
1058 \o \inlineimage qformlayout-mac.png
1059 \o \inlineimage qformlayout-kde.png
1060 \o \inlineimage qformlayout-qpe.png
1061 \row
1062 \o Traditional style used for Windows, GNOME, and earlier
1063 versions of KDE. Labels are left aligned, and expanding
1064 fields grow to fill the available space. (This normally
1065 corresponds to what we would get using a two-column
1066 QGridLayout.)
1067 \o Style based on the
1068 \l{Mac OS X Aqua} guidelines. Labels are right-aligned,
1069 the fields don't grow beyond their size hint, and the
1070 form is horizontally centered.
1071 \o Recommended style for
1072 \l{KDE applications}. Similar to MacStyle, except that the form
1073 is left-aligned and all fields grow to fill the available
1074 space.
1075 \o Default style for Qt Extended styles. Labels are right-aligned,
1076 expanding fields grow to fill the available space, and row
1077 wrapping is enabled for long lines.
1078 \endtable
1079
1080 The form styles can be also be overridden individually by calling
1081 setLabelAlignment(), setFormAlignment(), setFieldGrowthPolicy(),
1082 and setRowWrapPolicy(). For example, to simulate the form layout
1083 appearance of QMacStyle on all platforms, but with left-aligned
1084 labels, you could write:
1085
1086 \snippet doc/src/snippets/code/src_gui_kernel_qformlayout.cpp 2
1087
1088 \sa QGridLayout, QBoxLayout, QStackedLayout
1089*/
1090
1091
1092/*!
1093 \enum QFormLayout::FieldGrowthPolicy
1094
1095 This enum specifies the different policies that can be used to
1096 control the way in which the form's fields grow.
1097
1098 \value FieldsStayAtSizeHint
1099 The fields never grow beyond their
1100 \l{QWidgetItem::sizeHint()}{effective size hint}. This is
1101 the default for QMacStyle.
1102
1103 \value ExpandingFieldsGrow
1104 Fields with an horizontal \l{QSizePolicy}{size policy} of
1105 \l{QSizePolicy::}{Expanding} or
1106 \l{QSizePolicy::}{MinimumExpanding} will grow to fill the
1107 available space. The other fields will not grow beyond
1108 their effective size hint. This is the default policy for
1109 Plastique.
1110
1111 \value AllNonFixedFieldsGrow
1112 All fields with a size policy that allows them to grow
1113 will grow to fill the available space. This is the default
1114 policy for most styles.
1115
1116 \sa fieldGrowthPolicy
1117*/
1118
1119/*!
1120 \enum QFormLayout::RowWrapPolicy
1121
1122 This enum specifies the different policies that can be used to
1123 control the way in which the form's rows wrap.
1124
1125 \value DontWrapRows
1126 Fields are always laid out next to their label. This is
1127 the default policy for all styles except Qt Extended styles
1128 and QS60Style.
1129
1130 \value WrapLongRows
1131 Labels are given enough horizontal space to fit the widest label,
1132 and the rest of the space is given to the fields. If the minimum
1133 size of a field pair is wider than the available space, the field
1134 is wrapped to the next line. This is the default policy for
1135 Qt Extended styles and and QS60Style.
1136
1137 \value WrapAllRows
1138 Fields are always laid out below their label.
1139
1140 \sa rowWrapPolicy
1141*/
1142
1143/*!
1144 \enum QFormLayout::ItemRole
1145
1146 This enum specifies the types of widgets (or other layout items)
1147 that may appear in a row.
1148
1149 \value LabelRole A label widget.
1150 \value FieldRole A field widget.
1151 \value SpanningRole A widget that spans label and field columns.
1152
1153 \sa itemAt(), getItemPosition()
1154*/
1155
1156/*!
1157 Constructs a new form layout with the given \a parent widget.
1158
1159 \sa QWidget::setLayout()
1160*/
1161QFormLayout::QFormLayout(QWidget *parent)
1162 : QLayout(*new QFormLayoutPrivate, 0, parent)
1163{
1164}
1165
1166/*!
1167 Destroys the form layout.
1168*/
1169QFormLayout::~QFormLayout()
1170{
1171 Q_D(QFormLayout);
1172
1173 /*
1174 The clearing and destruction order here is important. We start by clearing
1175 m_things so that QLayout and the rest of the world know that we don't babysit
1176 the layout items anymore and don't care if they are destroyed.
1177 */
1178 d->m_things.clear();
1179 qDeleteAll(d->m_matrix.storage());
1180 d->m_matrix.clear();
1181}
1182
1183/*!
1184 Adds a new row to the bottom of this form layout, with the given
1185 \a label and \a field.
1186
1187 \sa insertRow()
1188*/
1189void QFormLayout::addRow(QWidget *label, QWidget *field)
1190{
1191 insertRow(-1, label, field);
1192}
1193
1194/*!
1195 \overload
1196*/
1197void QFormLayout::addRow(QWidget *label, QLayout *field)
1198{
1199 insertRow(-1, label, field);
1200}
1201
1202/*!
1203 \overload
1204
1205 This overload automatically creates a QLabel behind the scenes
1206 with \a labelText as its text. The \a field is set as the new
1207 QLabel's \l{QLabel::setBuddy()}{buddy}.
1208*/
1209void QFormLayout::addRow(const QString &labelText, QWidget *field)
1210{
1211 insertRow(-1, labelText, field);
1212}
1213
1214/*!
1215 \overload
1216
1217 This overload automatically creates a QLabel behind the scenes
1218 with \a labelText as its text.
1219*/
1220void QFormLayout::addRow(const QString &labelText, QLayout *field)
1221{
1222 insertRow(-1, labelText, field);
1223}
1224
1225/*!
1226 \overload
1227
1228 Adds the specified \a widget at the end of this form layout. The
1229 \a widget spans both columns.
1230*/
1231void QFormLayout::addRow(QWidget *widget)
1232{
1233 insertRow(-1, widget);
1234}
1235
1236/*!
1237 \overload
1238
1239 Adds the specified \a layout at the end of this form layout. The
1240 \a layout spans both columns.
1241*/
1242void QFormLayout::addRow(QLayout *layout)
1243{
1244 insertRow(-1, layout);
1245}
1246
1247/*!
1248 Inserts a new row at position \a row in this form layout, with
1249 the given \a label and \a field. If \a row is out of bounds, the
1250 new row is added at the end.
1251
1252 \sa addRow()
1253*/
1254void QFormLayout::insertRow(int row, QWidget *label, QWidget *field)
1255{
1256 Q_D(QFormLayout);
1257
1258 row = d->insertRow(row);
1259 if (label)
1260 d->setWidget(row, LabelRole, label);
1261 if (field)
1262 d->setWidget(row, FieldRole, field);
1263 invalidate();
1264}
1265
1266/*!
1267 \overload
1268*/
1269void QFormLayout::insertRow(int row, QWidget *label, QLayout *field)
1270{
1271 Q_D(QFormLayout);
1272
1273 row = d->insertRow(row);
1274 if (label)
1275 d->setWidget(row, LabelRole, label);
1276 if (field)
1277 d->setLayout(row, FieldRole, field);
1278 invalidate();
1279}
1280
1281/*!
1282 \overload
1283
1284 This overload automatically creates a QLabel behind the scenes
1285 with \a labelText as its text. The \a field is set as the new
1286 QLabel's \l{QLabel::setBuddy()}{buddy}.
1287*/
1288void QFormLayout::insertRow(int row, const QString &labelText, QWidget *field)
1289{
1290 QLabel *label = 0;
1291 if (!labelText.isEmpty()) {
1292 label = new QLabel(labelText);
1293#ifndef QT_NO_SHORTCUT
1294 label->setBuddy(field);
1295#endif
1296 }
1297 insertRow(row, label, field);
1298}
1299
1300/*!
1301 \overload
1302
1303 This overload automatically creates a QLabel behind the scenes
1304 with \a labelText as its text.
1305*/
1306void QFormLayout::insertRow(int row, const QString &labelText, QLayout *field)
1307{
1308 insertRow(row, labelText.isEmpty() ? 0 : new QLabel(labelText), field);
1309}
1310
1311/*!
1312 \overload
1313
1314 Inserts the specified \a widget at position \a row in this form
1315 layout. The \a widget spans both columns. If \a row is out of
1316 bounds, the widget is added at the end.
1317*/
1318void QFormLayout::insertRow(int row, QWidget *widget)
1319{
1320 Q_D(QFormLayout);
1321
1322 if (!widget) {
1323 qWarning("QFormLayout: Cannot add null field to %s", qPrintable(objectName()));
1324 return;
1325 }
1326
1327 row = d->insertRow(row);
1328 d->setWidget(row, SpanningRole, widget);
1329 invalidate();
1330}
1331
1332/*!
1333 \overload
1334
1335 Inserts the specified \a layout at position \a row in this form
1336 layout. The \a layout spans both columns. If \a row is out of
1337 bounds, the widget is added at the end.
1338*/
1339void QFormLayout::insertRow(int row, QLayout *layout)
1340{
1341 Q_D(QFormLayout);
1342
1343 if (!layout) {
1344 qWarning("QFormLayout: Cannot add null field to %s", qPrintable(objectName()));
1345 return;
1346 }
1347
1348 row = d->insertRow(row);
1349 d->setLayout(row, SpanningRole, layout);
1350 invalidate();
1351}
1352
1353/*!
1354 \reimp
1355*/
1356void QFormLayout::addItem(QLayoutItem *item)
1357{
1358 Q_D(QFormLayout);
1359
1360 int row = d->insertRow(d->m_matrix.rowCount());
1361 d->setItem(row, FieldRole, item);
1362 invalidate();
1363}
1364
1365/*!
1366 \reimp
1367*/
1368int QFormLayout::count() const
1369{
1370 Q_D(const QFormLayout);
1371 return d->m_things.count();
1372}
1373
1374/*!
1375 \reimp
1376*/
1377QLayoutItem *QFormLayout::itemAt(int index) const
1378{
1379 Q_D(const QFormLayout);
1380 if (QFormLayoutItem *formItem = d->m_things.value(index))
1381 return formItem->item;
1382 return 0;
1383}
1384
1385/*!
1386 \reimp
1387*/
1388QLayoutItem *QFormLayout::takeAt(int index)
1389{
1390 Q_D(QFormLayout);
1391
1392 const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index));
1393 if (storageIndex == -1) {
1394 qWarning("QFormLayout::takeAt: Invalid index %d", index);
1395 return 0;
1396 }
1397
1398 int row, col;
1399 QFormLayoutPrivate::ItemMatrix::storageIndexToPosition(storageIndex, &row, &col);
1400 Q_ASSERT(d->m_matrix(row, col));
1401
1402 QFormLayoutItem *item = d->m_matrix(row, col);
1403 Q_ASSERT(item);
1404 d->m_things.removeAt(index);
1405 d->m_matrix(row, col) = 0;
1406
1407 invalidate();
1408
1409 // grab ownership back from the QFormLayoutItem
1410 QLayoutItem *i = item->item;
1411 item->item = 0;
1412 delete item;
1413 return i;
1414}
1415
1416/*!
1417 \reimp
1418*/
1419Qt::Orientations QFormLayout::expandingDirections() const
1420{
1421 Q_D(const QFormLayout);
1422 QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
1423 e->updateSizes();
1424
1425 Qt::Orientations o = 0;
1426 if (e->expandHorizontal)
1427 o = Qt::Horizontal;
1428 if (e->expandVertical)
1429 o |= Qt::Vertical;
1430 return o;
1431}
1432
1433/*!
1434 \reimp
1435*/
1436bool QFormLayout::hasHeightForWidth() const
1437{
1438 Q_D(const QFormLayout);
1439 QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
1440 e->updateSizes();
1441 return (d->has_hfw || rowWrapPolicy() == WrapLongRows);
1442}
1443
1444/*!
1445 \reimp
1446*/
1447int QFormLayout::heightForWidth(int width) const
1448{
1449 Q_D(const QFormLayout);
1450 if (!hasHeightForWidth())
1451 return -1;
1452
1453 int leftMargin, topMargin, rightMargin, bottomMargin;
1454 getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
1455
1456 int targetWidth = width - leftMargin - rightMargin;
1457
1458 if (!d->haveHfwCached(targetWidth)) {
1459 QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1460 dat->setupVerticalLayoutData(targetWidth);
1461 dat->setupHorizontalLayoutData(targetWidth);
1462 dat->recalcHFW(targetWidth);
1463 }
1464 if (targetWidth == d->sh_width)
1465 return d->hfw_sh_height + topMargin + bottomMargin;
1466 else
1467 return d->hfw_height + topMargin + bottomMargin;
1468}
1469
1470/*!
1471 \reimp
1472*/
1473void QFormLayout::setGeometry(const QRect &rect)
1474{
1475 Q_D(QFormLayout);
1476 if (d->dirty || rect != geometry()) {
1477 QRect cr = rect;
1478 int leftMargin, topMargin, rightMargin, bottomMargin;
1479 getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
1480 cr.adjust(+leftMargin, +topMargin, -rightMargin, -bottomMargin);
1481
1482 bool hfw = hasHeightForWidth();
1483 d->setupVerticalLayoutData(cr.width());
1484 d->setupHorizontalLayoutData(cr.width());
1485 if (hfw && (!d->haveHfwCached(cr.width()) || d->hfwLayouts.size() != d->vLayoutCount))
1486 d->recalcHFW(cr.width());
1487 if (hfw) {
1488 qGeomCalc(d->hfwLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
1489 d->arrangeWidgets(d->hfwLayouts, cr);
1490 } else {
1491 qGeomCalc(d->vLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
1492 d->arrangeWidgets(d->vLayouts, cr);
1493 }
1494 QLayout::setGeometry(rect);
1495 }
1496}
1497
1498/*!
1499 \reimp
1500*/
1501QSize QFormLayout::sizeHint() const
1502{
1503 Q_D(const QFormLayout);
1504 if (!d->prefSize.isValid()) {
1505 QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1506 dat->calcSizeHints();
1507 }
1508 return d->prefSize;
1509}
1510
1511/*!
1512 \reimp
1513*/
1514QSize QFormLayout::minimumSize() const
1515{
1516 // ### fix minimumSize if hfw
1517 Q_D(const QFormLayout);
1518 if (!d->minSize.isValid()) {
1519 QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
1520 dat->calcSizeHints();
1521 }
1522 return d->minSize;
1523}
1524
1525/*!
1526 \reimp
1527*/
1528void QFormLayout::invalidate()
1529{
1530 Q_D(QFormLayout);
1531 d->dirty = true;
1532 d->sizesDirty = true;
1533 d->minSize = QSize();
1534 d->prefSize = QSize();
1535 d->formMaxWidth = -1;
1536 d->hfw_width = -1;
1537 d->sh_width = -1;
1538 d->layoutWidth = -1;
1539 d->hfw_sh_height = -1;
1540 QLayout::invalidate();
1541}
1542
1543/*!
1544 Returns the number of rows in the form.
1545
1546 \sa QLayout::count()
1547*/
1548int QFormLayout::rowCount() const
1549{
1550 Q_D(const QFormLayout);
1551 return d->m_matrix.rowCount();
1552}
1553
1554/*!
1555 Returns the layout item in the given \a row with the specified \a
1556 role (column). Returns 0 if there is no such item.
1557
1558 \sa QLayout::itemAt(), setItem()
1559*/
1560QLayoutItem *QFormLayout::itemAt(int row, ItemRole role) const
1561{
1562 Q_D(const QFormLayout);
1563 if (uint(row) >= uint(d->m_matrix.rowCount()))
1564 return 0;
1565 switch (role) {
1566 case SpanningRole:
1567 if (QFormLayoutItem *item = d->m_matrix(row, 1))
1568 if (item->fullRow)
1569 return item->item;
1570 break;
1571 case LabelRole:
1572 case FieldRole:
1573 if (QFormLayoutItem *item = d->m_matrix(row, (role == LabelRole) ? 0 : 1))
1574 return item->item;
1575 break;
1576 }
1577 return 0;
1578}
1579
1580/*!
1581 Retrieves the row and role (column) of the item at the specified
1582 \a index. If \a index is out of bounds, *\a rowPtr is set to -1;
1583 otherwise the row is stored in *\a rowPtr and the role is stored
1584 in *\a rolePtr.
1585
1586 \sa itemAt(), count(), getLayoutPosition(), getWidgetPosition()
1587*/
1588void QFormLayout::getItemPosition(int index, int *rowPtr, ItemRole *rolePtr) const
1589{
1590 Q_D(const QFormLayout);
1591 int col = -1;
1592 int row = -1;
1593
1594 const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index));
1595 if (storageIndex != -1)
1596 QFormLayoutPrivate::ItemMatrix::storageIndexToPosition(storageIndex, &row, &col);
1597
1598 if (rowPtr)
1599 *rowPtr = row;
1600 if (rolePtr && col != -1) {
1601 const bool spanning = col == 1 && d->m_matrix(row, col)->fullRow;
1602 if (spanning) {
1603 *rolePtr = SpanningRole;
1604 } else {
1605 *rolePtr = ItemRole(col);
1606 }
1607 }
1608}
1609
1610/*!
1611 Retrieves the row and role (column) of the specified child \a
1612 layout. If \a layout is not in the form layout, *\a rowPtr is set
1613 to -1; otherwise the row is stored in *\a rowPtr and the role is stored
1614 in *\a rolePtr.
1615*/
1616void QFormLayout::getLayoutPosition(QLayout *layout, int *rowPtr, ItemRole *rolePtr) const
1617{
1618 int n = count();
1619 int index = 0;
1620 while (index < n) {
1621 if (itemAt(index) == layout)
1622 break;
1623 ++index;
1624 }
1625 getItemPosition(index, rowPtr, rolePtr);
1626}
1627
1628/*!
1629 Retrieves the row and role (column) of the specified \a widget in
1630 the layout. If \a widget is not in the layout, *\a rowPtr is set
1631 to -1; otherwise the row is stored in *\a rowPtr and the role is stored
1632 in *\a rolePtr.
1633
1634 \sa getItemPosition(), itemAt()
1635*/
1636void QFormLayout::getWidgetPosition(QWidget *widget, int *rowPtr, ItemRole *rolePtr) const
1637{
1638 getItemPosition(indexOf(widget), rowPtr, rolePtr);
1639}
1640
1641// ### eliminate labelForField()
1642
1643/*!
1644 Returns the label associated with the given \a field.
1645
1646 \sa itemAt()
1647*/
1648QWidget *QFormLayout::labelForField(QWidget *field) const
1649{
1650 Q_D(const QFormLayout);
1651
1652 int row;
1653 ItemRole role;
1654
1655 getWidgetPosition(field, &row, &role);
1656
1657 if (row != -1 && role == FieldRole) {
1658 if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
1659 return label->widget();
1660 }
1661 return 0;
1662}
1663
1664/*!
1665 \overload
1666*/
1667QWidget *QFormLayout::labelForField(QLayout *field) const
1668{
1669 Q_D(const QFormLayout);
1670
1671 int row;
1672 ItemRole role;
1673
1674 getLayoutPosition(field, &row, &role);
1675
1676 if (row != -1 && role == FieldRole) {
1677 if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
1678 return label->widget();
1679 }
1680 return 0;
1681}
1682
1683/*!
1684 \property QFormLayout::fieldGrowthPolicy
1685 \brief the way in which the form's fields grow
1686
1687 The default value depends on the widget or application style. For
1688 QMacStyle, the default is FieldsStayAtSizeHint; for QCommonStyle
1689 derived styles (like Plastique and Windows), the default
1690 is ExpandingFieldsGrow; for Qt Extended styles, the default is
1691 AllNonFixedFieldsGrow.
1692
1693 If none of the fields can grow and the form is resized, extra
1694 space is distributed according to the current
1695 \l{formAlignment}{form alignment}.
1696
1697 \sa formAlignment, rowWrapPolicy
1698*/
1699
1700void QFormLayout::setFieldGrowthPolicy(FieldGrowthPolicy policy)
1701{
1702 Q_D(QFormLayout);
1703 if (FieldGrowthPolicy(d->fieldGrowthPolicy) != policy) {
1704 d->fieldGrowthPolicy = policy;
1705 invalidate();
1706 }
1707}
1708
1709QFormLayout::FieldGrowthPolicy QFormLayout::fieldGrowthPolicy() const
1710{
1711 Q_D(const QFormLayout);
1712 if (d->fieldGrowthPolicy == DefaultFieldGrowthPolicy) {
1713 return QFormLayout::FieldGrowthPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutFieldGrowthPolicy));
1714 } else {
1715 return QFormLayout::FieldGrowthPolicy(d->fieldGrowthPolicy);
1716 }
1717}
1718
1719/*!
1720 \property QFormLayout::rowWrapPolicy
1721 \brief the way in which the form's rows wrap
1722
1723 The default value depends on the widget or application style. For
1724 Qt Extended styles and QS60Style, the default is WrapLongRows;
1725 for the other styles, the default is DontWrapRows.
1726
1727 If you want to display each label above its associated field
1728 (instead of next to it), set this property to WrapAllRows.
1729
1730 \sa fieldGrowthPolicy
1731*/
1732
1733void QFormLayout::setRowWrapPolicy(RowWrapPolicy policy)
1734{
1735 Q_D(QFormLayout);
1736 if (RowWrapPolicy(d->rowWrapPolicy) != policy) {
1737 d->rowWrapPolicy = policy;
1738 invalidate();
1739 }
1740}
1741
1742QFormLayout::RowWrapPolicy QFormLayout::rowWrapPolicy() const
1743{
1744 Q_D(const QFormLayout);
1745 if (d->rowWrapPolicy == DefaultRowWrapPolicy) {
1746 return QFormLayout::RowWrapPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutWrapPolicy));
1747 } else {
1748 return QFormLayout::RowWrapPolicy(d->rowWrapPolicy);
1749 }
1750}
1751
1752/*!
1753 \property QFormLayout::labelAlignment
1754 \brief the horizontal alignment of the labels
1755
1756 The default value depends on the widget or application style. For
1757 QCommonStyle derived styles, except for QPlastiqueStyle, the
1758 default is Qt::AlignLeft; for the other styles, the default is
1759 Qt::AlignRight.
1760
1761 \sa formAlignment
1762*/
1763
1764void QFormLayout::setLabelAlignment(Qt::Alignment alignment)
1765{
1766 Q_D(QFormLayout);
1767 if (d->labelAlignment != alignment) {
1768 d->labelAlignment = alignment;
1769 invalidate();
1770 }
1771}
1772
1773Qt::Alignment QFormLayout::labelAlignment() const
1774{
1775 Q_D(const QFormLayout);
1776 if (!d->labelAlignment) {
1777 return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
1778 } else {
1779 return d->labelAlignment;
1780 }
1781}
1782
1783/*!
1784 \property QFormLayout::formAlignment
1785 \brief the alignment of the form layout's contents within the layout's geometry
1786
1787 The default value depends on the widget or application style. For
1788 QMacStyle, the default is Qt::AlignHCenter | Qt::AlignTop; for the
1789 other styles, the default is Qt::AlignLeft | Qt::AlignTop.
1790
1791 \sa labelAlignment, rowWrapPolicy
1792*/
1793
1794void QFormLayout::setFormAlignment(Qt::Alignment alignment)
1795{
1796 Q_D(QFormLayout);
1797 if (d->formAlignment != alignment) {
1798 d->formAlignment = alignment;
1799 invalidate();
1800 }
1801}
1802
1803Qt::Alignment QFormLayout::formAlignment() const
1804{
1805 Q_D(const QFormLayout);
1806 if (!d->formAlignment) {
1807 return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutFormAlignment));
1808 } else {
1809 return d->formAlignment;
1810 }
1811}
1812
1813/*!
1814 \property QFormLayout::horizontalSpacing
1815 \brief the spacing between widgets that are laid out side by side
1816
1817 By default, if no value is explicitly set, the layout's horizontal
1818 spacing is inherited from the parent layout, or from the style settings
1819 for the parent widget.
1820
1821 \sa verticalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
1822*/
1823void QFormLayout::setHorizontalSpacing(int spacing)
1824{
1825 Q_D(QFormLayout);
1826 if (spacing != d->hSpacing) {
1827 d->hSpacing = spacing;
1828 invalidate();
1829 }
1830}
1831
1832int QFormLayout::horizontalSpacing() const
1833{
1834 Q_D(const QFormLayout);
1835 if (d->hSpacing >= 0) {
1836 return d->hSpacing;
1837 } else {
1838 return qSmartSpacing(this, QStyle::PM_LayoutHorizontalSpacing);
1839 }
1840}
1841
1842/*!
1843 \property QFormLayout::verticalSpacing
1844 \brief the spacing between widgets that are laid out vertically
1845
1846 By default, if no value is explicitly set, the layout's vertical spacing is
1847 inherited from the parent layout, or from the style settings for the parent
1848 widget.
1849
1850 \sa horizontalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
1851*/
1852void QFormLayout::setVerticalSpacing(int spacing)
1853{
1854 Q_D(QFormLayout);
1855 if (spacing != d->vSpacing) {
1856 d->vSpacing = spacing;
1857 invalidate();
1858 }
1859}
1860
1861int QFormLayout::verticalSpacing() const
1862{
1863 Q_D(const QFormLayout);
1864 if (d->vSpacing >= 0) {
1865 return d->vSpacing;
1866 } else {
1867 return qSmartSpacing(this, QStyle::PM_LayoutVerticalSpacing);
1868 }
1869}
1870
1871/*!
1872 This function sets both the vertical and horizontal spacing to
1873 \a spacing.
1874
1875 \sa setVerticalSpacing(), setHorizontalSpacing()
1876*/
1877void QFormLayout::setSpacing(int spacing)
1878{
1879 Q_D(QFormLayout);
1880 d->vSpacing = d->hSpacing = spacing;
1881 invalidate();
1882}
1883
1884/*!
1885 If the vertical spacing is equal to the horizontal spacing,
1886 this function returns that value; otherwise it returns -1.
1887
1888 \sa setSpacing(), verticalSpacing(), horizontalSpacing()
1889*/
1890int QFormLayout::spacing() const
1891{
1892 int hSpacing = horizontalSpacing();
1893 if (hSpacing == verticalSpacing()) {
1894 return hSpacing;
1895 } else {
1896 return -1;
1897 }
1898}
1899
1900void QFormLayoutPrivate::arrangeWidgets(const QVector<QLayoutStruct>& layouts, QRect &rect)
1901{
1902 Q_Q(QFormLayout);
1903
1904 int i;
1905 const int rr = m_matrix.rowCount();
1906 QWidget *w = q->parentWidget();
1907 Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : QApplication::layoutDirection();
1908
1909 Qt::Alignment formAlignment = fixedAlignment(q->formAlignment(), layoutDirection);
1910 int leftOffset = 0;
1911 int delta = rect.width() - formMaxWidth;
1912 if (formAlignment & (Qt::AlignHCenter | Qt::AlignRight) && delta > 0) {
1913 leftOffset = delta;
1914 if (formAlignment & Qt::AlignHCenter)
1915 leftOffset >>= 1;
1916 }
1917
1918 for (i = 0; i < rr; ++i) {
1919 QFormLayoutItem *label = m_matrix(i, 0);
1920 QFormLayoutItem *field = m_matrix(i, 1);
1921
1922 if (label) {
1923 int height = layouts.at(label->vLayoutIndex).size;
1924 if ((label->expandingDirections() & Qt::Vertical) == 0) {
1925 /*
1926 If the field on the right-hand side is tall,
1927 we want the label to be top-aligned, but not too
1928 much. So we introduce a 5 / 4 factor so that it
1929 gets a few extra pixels at the top.
1930 */
1931 height = qMin(height,
1932 qMin(label->sizeHint.height() * 5 / 4,
1933 label->maxSize.height()));
1934 }
1935
1936 QSize sz(qMin(label->layoutWidth, label->sizeHint.width()), height);
1937 int x = leftOffset + rect.x() + label->layoutPos;
1938 if (fixedAlignment(q->labelAlignment(), layoutDirection) & Qt::AlignRight)
1939 x += label->layoutWidth - sz.width();
1940 QPoint p(x, layouts.at(label->vLayoutIndex).pos);
1941 // ### expansion & sizepolicy stuff
1942
1943 label->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
1944 }
1945
1946 if (field) {
1947 QSize sz(field->layoutWidth, layouts.at(field->vLayoutIndex).size);
1948 QPoint p(field->layoutPos + leftOffset + rect.x(), layouts.at(field->vLayoutIndex).pos);
1949/*
1950 if ((field->widget() && field->widget()->sizePolicy().horizontalPolicy() & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag | QSizePolicy::IgnoreFlag))
1951 || (field->layout() && sz.width() < field->maxSize.width())) {
1952 sz.rwidth() = field->layoutWidth;
1953 }
1954*/
1955 if (field->maxSize.isValid())
1956 sz = sz.boundedTo(field->maxSize);
1957
1958 field->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
1959 }
1960 }
1961}
1962
1963/*!
1964 Sets the widget in the given \a row for the given \a role to \a widget, extending the
1965 layout with empty rows if necessary.
1966
1967 If the cell is already occupied, the \a widget is not inserted and an error message is
1968 sent to the console.
1969
1970 \bold{Note:} For most applications, addRow() or insertRow() should be used instead of setWidget().
1971
1972 \sa setLayout()
1973*/
1974void QFormLayout::setWidget(int row, ItemRole role, QWidget *widget)
1975{
1976 Q_D(QFormLayout);
1977 int rowCnt = rowCount();
1978 if (row >= rowCnt)
1979 d->insertRows(rowCnt, row - rowCnt + 1);
1980 d->setWidget(row, role, widget);
1981}
1982
1983/*!
1984 Sets the sub-layout in the given \a row for the given \a role to \a layout, extending the
1985 form layout with empty rows if necessary.
1986
1987 If the cell is already occupied, the \a layout is not inserted and an error message is
1988 sent to the console.
1989
1990 \bold{Note:} For most applications, addRow() or insertRow() should be used instead of setLayout().
1991
1992 \sa setWidget()
1993*/
1994void QFormLayout::setLayout(int row, ItemRole role, QLayout *layout)
1995{
1996 Q_D(QFormLayout);
1997 int rowCnt = rowCount();
1998 if (row >= rowCnt)
1999 d->insertRows(rowCnt, row - rowCnt + 1);
2000 d->setLayout(row, role, layout);
2001}
2002
2003/*!
2004 Sets the item in the given \a row for the given \a role to \a item, extending the
2005 layout with empty rows if necessary.
2006
2007 If the cell is already occupied, the \a item is not inserted and an error message is
2008 sent to the console.
2009 The \a item spans both columns.
2010
2011 \warning Do not use this function to add child layouts or child
2012 widget items. Use setLayout() or setWidget() instead.
2013
2014 \sa setLayout()
2015*/
2016void QFormLayout::setItem(int row, ItemRole role, QLayoutItem *item)
2017{
2018 Q_D(QFormLayout);
2019 int rowCnt = rowCount();
2020 if (row >= rowCnt)
2021 d->insertRows(rowCnt, row - rowCnt + 1);
2022 d->setItem(row, role, item);
2023}
2024
2025/*!
2026 \internal
2027 */
2028
2029void QFormLayout::resetFieldGrowthPolicy()
2030{
2031 Q_D(QFormLayout);
2032 d->fieldGrowthPolicy = DefaultFieldGrowthPolicy;
2033}
2034
2035/*!
2036 \internal
2037 */
2038
2039void QFormLayout::resetRowWrapPolicy()
2040{
2041 Q_D(QFormLayout);
2042 d->rowWrapPolicy = DefaultRowWrapPolicy;
2043}
2044
2045/*!
2046 \internal
2047 */
2048
2049void QFormLayout::resetFormAlignment()
2050{
2051 Q_D(QFormLayout);
2052 d->formAlignment = 0;
2053}
2054
2055/*!
2056 \internal
2057 */
2058
2059void QFormLayout::resetLabelAlignment()
2060{
2061 Q_D(QFormLayout);
2062 d->labelAlignment = 0;
2063}
2064
2065#if 0
2066void QFormLayout::dump() const
2067{
2068 Q_D(const QFormLayout);
2069 for (int i = 0; i < rowCount(); ++i) {
2070 for (int j = 0; j < 2; ++j) {
2071 qDebug("m_matrix(%d, %d) = %p", i, j, d->m_matrix(i, j));
2072 }
2073 }
2074 for (int i = 0; i < d->m_things.count(); ++i)
2075 qDebug("m_things[%d] = %p", i, d->m_things.at(i));
2076}
2077#endif
2078
2079QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.