~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to src/widgets/kernel/qformlayout.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

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