src/gui/kernel/qformlayout.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    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 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    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     Q_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 
       
  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 
       
  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     return i;
       
  1413 }
       
  1414 
       
  1415 /*!
       
  1416     \reimp
       
  1417 */
       
  1418 Qt::Orientations QFormLayout::expandingDirections() const
       
  1419 {
       
  1420     Q_D(const QFormLayout);
       
  1421     QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
       
  1422     e->updateSizes();
       
  1423 
       
  1424     Qt::Orientations o = 0;
       
  1425     if (e->expandHorizontal)
       
  1426         o = Qt::Horizontal;
       
  1427     if (e->expandVertical)
       
  1428         o |= Qt::Vertical;
       
  1429     return o;
       
  1430 }
       
  1431 
       
  1432 /*!
       
  1433     \reimp
       
  1434 */
       
  1435 bool QFormLayout::hasHeightForWidth() const
       
  1436 {
       
  1437     Q_D(const QFormLayout);
       
  1438     QFormLayoutPrivate *e = const_cast<QFormLayoutPrivate *>(d);
       
  1439     e->updateSizes();
       
  1440     return (d->has_hfw || rowWrapPolicy() == WrapLongRows);
       
  1441 }
       
  1442 
       
  1443 /*!
       
  1444     \reimp
       
  1445 */
       
  1446 int QFormLayout::heightForWidth(int width) const
       
  1447 {
       
  1448     Q_D(const QFormLayout);
       
  1449     if (!hasHeightForWidth())
       
  1450         return -1;
       
  1451 
       
  1452     int leftMargin, topMargin, rightMargin, bottomMargin;
       
  1453     getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
       
  1454 
       
  1455     int targetWidth = width - leftMargin - rightMargin;
       
  1456 
       
  1457     if (!d->haveHfwCached(targetWidth)) {
       
  1458         QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
       
  1459         dat->setupVerticalLayoutData(targetWidth);
       
  1460         dat->setupHorizontalLayoutData(targetWidth);
       
  1461         dat->recalcHFW(targetWidth);
       
  1462     }
       
  1463     if (targetWidth == d->sh_width)
       
  1464         return d->hfw_sh_height + topMargin + bottomMargin;
       
  1465     else
       
  1466         return d->hfw_height + topMargin + bottomMargin;
       
  1467 }
       
  1468 
       
  1469 /*!
       
  1470     \reimp
       
  1471 */
       
  1472 void QFormLayout::setGeometry(const QRect &rect)
       
  1473 {
       
  1474     Q_D(QFormLayout);
       
  1475     if (d->dirty || rect != geometry()) {
       
  1476         QRect cr = rect;
       
  1477         int leftMargin, topMargin, rightMargin, bottomMargin;
       
  1478         getContentsMargins(&leftMargin, &topMargin, &rightMargin, &bottomMargin);
       
  1479         cr.adjust(+leftMargin, +topMargin, -rightMargin, -bottomMargin);
       
  1480 
       
  1481         bool hfw = hasHeightForWidth();
       
  1482         d->setupVerticalLayoutData(cr.width());
       
  1483         d->setupHorizontalLayoutData(cr.width());
       
  1484         if (hfw && (!d->haveHfwCached(cr.width()) || d->hfwLayouts.size() != d->vLayoutCount))
       
  1485             d->recalcHFW(cr.width());
       
  1486         if (hfw) {
       
  1487             qGeomCalc(d->hfwLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
       
  1488             d->arrangeWidgets(d->hfwLayouts, cr);
       
  1489         } else {
       
  1490             qGeomCalc(d->vLayouts, 0, d->vLayoutCount, cr.y(), cr.height());
       
  1491             d->arrangeWidgets(d->vLayouts, cr);
       
  1492         }
       
  1493         QLayout::setGeometry(rect);
       
  1494     }
       
  1495 }
       
  1496 
       
  1497 /*!
       
  1498     \reimp
       
  1499 */
       
  1500 QSize QFormLayout::sizeHint() const
       
  1501 {
       
  1502     Q_D(const QFormLayout);
       
  1503     if (!d->prefSize.isValid()) {
       
  1504         QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
       
  1505         dat->calcSizeHints();
       
  1506     }
       
  1507     return d->prefSize;
       
  1508 }
       
  1509 
       
  1510 /*!
       
  1511     \reimp
       
  1512 */
       
  1513 QSize QFormLayout::minimumSize() const
       
  1514 {
       
  1515     // ### fix minimumSize if hfw
       
  1516     Q_D(const QFormLayout);
       
  1517     if (!d->minSize.isValid()) {
       
  1518         QFormLayoutPrivate *dat = const_cast<QFormLayoutPrivate *>(d);
       
  1519         dat->calcSizeHints();
       
  1520     }
       
  1521     return d->minSize;
       
  1522 }
       
  1523 
       
  1524 /*!
       
  1525     \reimp
       
  1526 */
       
  1527 void QFormLayout::invalidate()
       
  1528 {
       
  1529     Q_D(QFormLayout);
       
  1530     d->dirty = true;
       
  1531     d->sizesDirty = true;
       
  1532     d->minSize = QSize();
       
  1533     d->prefSize = QSize();
       
  1534     d->formMaxWidth = -1;
       
  1535     d->hfw_width = -1;
       
  1536     d->sh_width = -1;
       
  1537     d->layoutWidth = -1;
       
  1538     d->hfw_sh_height = -1;
       
  1539     QLayout::invalidate();
       
  1540 }
       
  1541 
       
  1542 /*!
       
  1543     Returns the number of rows in the form.
       
  1544 
       
  1545     \sa QLayout::count()
       
  1546 */
       
  1547 int QFormLayout::rowCount() const
       
  1548 {
       
  1549     Q_D(const QFormLayout);
       
  1550     return d->m_matrix.rowCount();
       
  1551 }
       
  1552 
       
  1553 /*!
       
  1554     Returns the layout item in the given \a row with the specified \a
       
  1555     role (column). Returns 0 if there is no such item.
       
  1556 
       
  1557     \sa QLayout::itemAt(), setItem()
       
  1558 */
       
  1559 QLayoutItem *QFormLayout::itemAt(int row, ItemRole role) const
       
  1560 {
       
  1561     Q_D(const QFormLayout);
       
  1562     if (uint(row) >= uint(d->m_matrix.rowCount()))
       
  1563         return 0;
       
  1564     switch (role) {
       
  1565     case SpanningRole:
       
  1566         if (QFormLayoutItem *item = d->m_matrix(row, 1))
       
  1567             if (item->fullRow)
       
  1568                 return item->item;
       
  1569         break;
       
  1570     case LabelRole:
       
  1571     case FieldRole:
       
  1572         if (QFormLayoutItem *item = d->m_matrix(row, (role == LabelRole) ? 0 : 1))
       
  1573             return item->item;
       
  1574         break;
       
  1575     }
       
  1576     return 0;
       
  1577 }
       
  1578 
       
  1579 /*!
       
  1580     Retrieves the row and role (column) of the item at the specified
       
  1581     \a index. If \a index is out of bounds, *\a rowPtr is set to -1;
       
  1582     otherwise the row is stored in *\a rowPtr and the role is stored
       
  1583     in *\a rolePtr.
       
  1584 
       
  1585     \sa itemAt(), count(), getLayoutPosition(), getWidgetPosition()
       
  1586 */
       
  1587 void QFormLayout::getItemPosition(int index, int *rowPtr, ItemRole *rolePtr) const
       
  1588 {
       
  1589     Q_D(const QFormLayout);
       
  1590     int col = -1;
       
  1591     int row = -1;
       
  1592 
       
  1593     const int storageIndex = storageIndexFromLayoutItem(d->m_matrix, d->m_things.value(index));
       
  1594     if (storageIndex != -1)
       
  1595         QFormLayoutPrivate::ItemMatrix::storageIndexToPosition(storageIndex, &row, &col);
       
  1596 
       
  1597     if (rowPtr)
       
  1598         *rowPtr = row;
       
  1599     if (rolePtr && col != -1) {
       
  1600         const bool spanning = col == 1 && d->m_matrix(row, col)->fullRow;
       
  1601         if (spanning) {
       
  1602             *rolePtr = SpanningRole;
       
  1603         } else {
       
  1604             *rolePtr = ItemRole(col);
       
  1605         }
       
  1606     }
       
  1607 }
       
  1608 
       
  1609 /*!
       
  1610     Retrieves the row and role (column) of the specified child \a
       
  1611     layout. If \a layout is not in the form layout, *\a rowPtr is set
       
  1612     to -1; otherwise the row is stored in *\a rowPtr and the role is stored
       
  1613     in *\a rolePtr.
       
  1614 */
       
  1615 void QFormLayout::getLayoutPosition(QLayout *layout, int *rowPtr, ItemRole *rolePtr) const
       
  1616 {
       
  1617     int n = count();
       
  1618     int index = 0;
       
  1619     while (index < n) {
       
  1620         if (itemAt(index) == layout)
       
  1621             break;
       
  1622         ++index;
       
  1623     }
       
  1624     getItemPosition(index, rowPtr, rolePtr);
       
  1625 }
       
  1626 
       
  1627 /*!
       
  1628     Retrieves the row and role (column) of the specified \a widget in
       
  1629     the layout. If \a widget is not in the layout, *\a rowPtr is set
       
  1630     to -1; otherwise the row is stored in *\a rowPtr and the role is stored
       
  1631     in *\a rolePtr.
       
  1632 
       
  1633     \sa getItemPosition(), itemAt()
       
  1634 */
       
  1635 void QFormLayout::getWidgetPosition(QWidget *widget, int *rowPtr, ItemRole *rolePtr) const
       
  1636 {
       
  1637     getItemPosition(indexOf(widget), rowPtr, rolePtr);
       
  1638 }
       
  1639 
       
  1640 // ### eliminate labelForField()
       
  1641 
       
  1642 /*!
       
  1643     Returns the label associated with the given \a field.
       
  1644 
       
  1645     \sa itemAt()
       
  1646 */
       
  1647 QWidget *QFormLayout::labelForField(QWidget *field) const
       
  1648 {
       
  1649     Q_D(const QFormLayout);
       
  1650 
       
  1651     int row;
       
  1652     ItemRole role;
       
  1653 
       
  1654     getWidgetPosition(field, &row, &role);
       
  1655 
       
  1656     if (row != -1 && role == FieldRole) {
       
  1657         if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
       
  1658             return label->widget();
       
  1659     }
       
  1660     return 0;
       
  1661 }
       
  1662 
       
  1663 /*!
       
  1664     \overload
       
  1665 */
       
  1666 QWidget *QFormLayout::labelForField(QLayout *field) const
       
  1667 {
       
  1668     Q_D(const QFormLayout);
       
  1669 
       
  1670     int row;
       
  1671     ItemRole role;
       
  1672 
       
  1673     getLayoutPosition(field, &row, &role);
       
  1674 
       
  1675     if (row != -1 && role == FieldRole) {
       
  1676         if (QFormLayoutItem *label = d->m_matrix(row, LabelRole))
       
  1677             return label->widget();
       
  1678     }
       
  1679     return 0;
       
  1680 }
       
  1681 
       
  1682 /*!
       
  1683     \property QFormLayout::fieldGrowthPolicy
       
  1684     \brief the way in which the form's fields grow
       
  1685 
       
  1686     The default value depends on the widget or application style. For
       
  1687     QMacStyle, the default is FieldsStayAtSizeHint; for QCommonStyle
       
  1688     derived styles (like Plastique and Windows), the default
       
  1689     is ExpandingFieldsGrow; for Qt Extended styles, the default is
       
  1690     AllNonFixedFieldsGrow.
       
  1691 
       
  1692     If none of the fields can grow and the form is resized, extra
       
  1693     space is distributed according to the current
       
  1694     \l{formAlignment}{form alignment}.
       
  1695 
       
  1696     \sa formAlignment, rowWrapPolicy
       
  1697 */
       
  1698 
       
  1699 void QFormLayout::setFieldGrowthPolicy(FieldGrowthPolicy policy)
       
  1700 {
       
  1701     Q_D(QFormLayout);
       
  1702     if (FieldGrowthPolicy(d->fieldGrowthPolicy) != policy) {
       
  1703         d->fieldGrowthPolicy = policy;
       
  1704         invalidate();
       
  1705     }
       
  1706 }
       
  1707 
       
  1708 QFormLayout::FieldGrowthPolicy QFormLayout::fieldGrowthPolicy() const
       
  1709 {
       
  1710     Q_D(const QFormLayout);
       
  1711     if (d->fieldGrowthPolicy == DefaultFieldGrowthPolicy) {
       
  1712         return QFormLayout::FieldGrowthPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutFieldGrowthPolicy));
       
  1713     } else {
       
  1714         return QFormLayout::FieldGrowthPolicy(d->fieldGrowthPolicy);
       
  1715     }
       
  1716 }
       
  1717 
       
  1718 /*!
       
  1719     \property QFormLayout::rowWrapPolicy
       
  1720     \brief the way in which the form's rows wrap
       
  1721 
       
  1722     The default value depends on the widget or application style. For
       
  1723     Qt Extended styles, the default is WrapLongRows; for the other styles,
       
  1724     the default is DontWrapRows.
       
  1725 
       
  1726     If you want to display each label above its associated field
       
  1727     (instead of next to it), set this property to WrapAllRows.
       
  1728 
       
  1729     \sa fieldGrowthPolicy
       
  1730 */
       
  1731 
       
  1732 void QFormLayout::setRowWrapPolicy(RowWrapPolicy policy)
       
  1733 {
       
  1734     Q_D(QFormLayout);
       
  1735     if (RowWrapPolicy(d->rowWrapPolicy) != policy) {
       
  1736         d->rowWrapPolicy = policy;
       
  1737         invalidate();
       
  1738     }
       
  1739 }
       
  1740 
       
  1741 QFormLayout::RowWrapPolicy QFormLayout::rowWrapPolicy() const
       
  1742 {
       
  1743     Q_D(const QFormLayout);
       
  1744     if (d->rowWrapPolicy == DefaultRowWrapPolicy) {
       
  1745         return QFormLayout::RowWrapPolicy(d->getStyle()->styleHint(QStyle::SH_FormLayoutWrapPolicy));
       
  1746     } else {
       
  1747         return QFormLayout::RowWrapPolicy(d->rowWrapPolicy);
       
  1748     }
       
  1749 }
       
  1750 
       
  1751 /*!
       
  1752     \property QFormLayout::labelAlignment
       
  1753     \brief the horizontal alignment of the labels
       
  1754 
       
  1755     The default value depends on the widget or application style. For
       
  1756     QCommonStyle derived styles, except for QPlastiqueStyle, the
       
  1757     default is Qt::AlignLeft; for the other styles, the default is
       
  1758     Qt::AlignRight.
       
  1759 
       
  1760     \sa formAlignment
       
  1761 */
       
  1762 
       
  1763 void QFormLayout::setLabelAlignment(Qt::Alignment alignment)
       
  1764 {
       
  1765     Q_D(QFormLayout);
       
  1766     if (d->labelAlignment != alignment) {
       
  1767         d->labelAlignment = alignment;
       
  1768         invalidate();
       
  1769     }
       
  1770 }
       
  1771 
       
  1772 Qt::Alignment QFormLayout::labelAlignment() const
       
  1773 {
       
  1774     Q_D(const QFormLayout);
       
  1775     if (!d->labelAlignment) {
       
  1776         return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutLabelAlignment));
       
  1777     } else {
       
  1778         return d->labelAlignment;
       
  1779     }
       
  1780 }
       
  1781 
       
  1782 /*!
       
  1783     \property QFormLayout::formAlignment
       
  1784     \brief the alignment of the form layout's contents within the layout's geometry
       
  1785 
       
  1786     The default value depends on the widget or application style. For
       
  1787     QMacStyle, the default is Qt::AlignHCenter | Qt::AlignTop; for the
       
  1788     other styles, the default is Qt::AlignLeft | Qt::AlignTop.
       
  1789 
       
  1790     \sa labelAlignment, rowWrapPolicy
       
  1791 */
       
  1792 
       
  1793 void QFormLayout::setFormAlignment(Qt::Alignment alignment)
       
  1794 {
       
  1795     Q_D(QFormLayout);
       
  1796     if (d->formAlignment != alignment) {
       
  1797         d->formAlignment = alignment;
       
  1798         invalidate();
       
  1799     }
       
  1800 }
       
  1801 
       
  1802 Qt::Alignment QFormLayout::formAlignment() const
       
  1803 {
       
  1804     Q_D(const QFormLayout);
       
  1805     if (!d->formAlignment) {
       
  1806         return Qt::Alignment(d->getStyle()->styleHint(QStyle::SH_FormLayoutFormAlignment));
       
  1807     } else {
       
  1808         return d->formAlignment;
       
  1809     }
       
  1810 }
       
  1811 
       
  1812 /*!
       
  1813     \property QFormLayout::horizontalSpacing
       
  1814     \brief the spacing between widgets that are laid out side by side
       
  1815 
       
  1816     By default, if no value is explicitly set, the layout's horizontal
       
  1817     spacing is inherited from the parent layout, or from the style settings
       
  1818     for the parent widget.
       
  1819 
       
  1820     \sa verticalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
       
  1821 */
       
  1822 void QFormLayout::setHorizontalSpacing(int spacing)
       
  1823 {
       
  1824     Q_D(QFormLayout);
       
  1825     if (spacing != d->hSpacing) {
       
  1826         d->hSpacing = spacing;
       
  1827         invalidate();
       
  1828     }
       
  1829 }
       
  1830 
       
  1831 int QFormLayout::horizontalSpacing() const
       
  1832 {
       
  1833     Q_D(const QFormLayout);
       
  1834     if (d->hSpacing >= 0) {
       
  1835         return d->hSpacing;
       
  1836     } else {
       
  1837         return qSmartSpacing(this, QStyle::PM_LayoutHorizontalSpacing);
       
  1838     }
       
  1839 }
       
  1840 
       
  1841 /*!
       
  1842     \property QFormLayout::verticalSpacing
       
  1843     \brief the spacing between widgets that are laid out vertically
       
  1844 
       
  1845     By default, if no value is explicitly set, the layout's vertical spacing is
       
  1846     inherited from the parent layout, or from the style settings for the parent
       
  1847     widget.
       
  1848 
       
  1849     \sa horizontalSpacing, QStyle::pixelMetric(), {QStyle::}{PM_LayoutHorizontalSpacing}
       
  1850 */
       
  1851 void QFormLayout::setVerticalSpacing(int spacing)
       
  1852 {
       
  1853     Q_D(QFormLayout);
       
  1854     if (spacing != d->vSpacing) {
       
  1855         d->vSpacing = spacing;
       
  1856         invalidate();
       
  1857     }
       
  1858 }
       
  1859 
       
  1860 int QFormLayout::verticalSpacing() const
       
  1861 {
       
  1862     Q_D(const QFormLayout);
       
  1863     if (d->vSpacing >= 0) {
       
  1864         return d->vSpacing;
       
  1865     } else {
       
  1866         return qSmartSpacing(this, QStyle::PM_LayoutVerticalSpacing);
       
  1867     }
       
  1868 }
       
  1869 
       
  1870 /*!
       
  1871     This function sets both the vertical and horizontal spacing to
       
  1872     \a spacing.
       
  1873 
       
  1874     \sa setVerticalSpacing(), setHorizontalSpacing()
       
  1875 */
       
  1876 void QFormLayout::setSpacing(int spacing)
       
  1877 {
       
  1878     Q_D(QFormLayout);
       
  1879     d->vSpacing = d->hSpacing = spacing;
       
  1880     invalidate();
       
  1881 }
       
  1882 
       
  1883 /*!
       
  1884     If the vertical spacing is equal to the horizontal spacing,
       
  1885     this function returns that value; otherwise it returns -1.
       
  1886 
       
  1887     \sa setSpacing(), verticalSpacing(), horizontalSpacing()
       
  1888 */
       
  1889 int QFormLayout::spacing() const
       
  1890 {
       
  1891     int hSpacing = horizontalSpacing();
       
  1892     if (hSpacing == verticalSpacing()) {
       
  1893         return hSpacing;
       
  1894     } else {
       
  1895         return -1;
       
  1896     }
       
  1897 }
       
  1898 
       
  1899 void QFormLayoutPrivate::arrangeWidgets(const QVector<QLayoutStruct>& layouts, QRect &rect)
       
  1900 {
       
  1901     Q_Q(QFormLayout);
       
  1902 
       
  1903     int i;
       
  1904     const int rr = m_matrix.rowCount();
       
  1905     QWidget *w = q->parentWidget();
       
  1906     Qt::LayoutDirection layoutDirection = w ? w->layoutDirection() : QApplication::layoutDirection();
       
  1907 
       
  1908     Qt::Alignment formAlignment = fixedAlignment(q->formAlignment(), layoutDirection);
       
  1909     int leftOffset = 0;
       
  1910     int delta = rect.width() - formMaxWidth;
       
  1911     if (formAlignment & (Qt::AlignHCenter | Qt::AlignRight) && delta > 0) {
       
  1912         leftOffset = delta;
       
  1913         if (formAlignment & Qt::AlignHCenter)
       
  1914             leftOffset >>= 1;
       
  1915     }
       
  1916 
       
  1917     for (i = 0; i < rr; ++i) {
       
  1918         QFormLayoutItem *label = m_matrix(i, 0);
       
  1919         QFormLayoutItem *field = m_matrix(i, 1);
       
  1920 
       
  1921         if (label) {
       
  1922             int height = layouts.at(label->vLayoutIndex).size;
       
  1923             if ((label->expandingDirections() & Qt::Vertical) == 0) {
       
  1924                 /*
       
  1925                     If the field on the right-hand side is tall,
       
  1926                     we want the label to be top-aligned, but not too
       
  1927                     much. So we introduce a 5 / 4 factor so that it
       
  1928                     gets a few extra pixels at the top.
       
  1929                 */
       
  1930                 height = qMin(height,
       
  1931                               qMin(label->sizeHint.height() * 5 / 4,
       
  1932                                    label->maxSize.height()));
       
  1933             }
       
  1934 
       
  1935             QSize sz(qMin(label->layoutWidth, label->sizeHint.width()), height);
       
  1936             int x = leftOffset + rect.x() + label->layoutPos;
       
  1937             if (fixedAlignment(q->labelAlignment(), layoutDirection) & Qt::AlignRight)
       
  1938                 x += label->layoutWidth - sz.width();
       
  1939             QPoint p(x, layouts.at(label->vLayoutIndex).pos);
       
  1940             // ### expansion & sizepolicy stuff
       
  1941 
       
  1942             label->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
       
  1943         }
       
  1944 
       
  1945         if (field) {
       
  1946             QSize sz(field->layoutWidth, layouts.at(field->vLayoutIndex).size);
       
  1947             QPoint p(field->layoutPos + leftOffset + rect.x(), layouts.at(field->vLayoutIndex).pos);
       
  1948 /*
       
  1949             if ((field->widget() && field->widget()->sizePolicy().horizontalPolicy() & (QSizePolicy::GrowFlag | QSizePolicy::ExpandFlag | QSizePolicy::IgnoreFlag))
       
  1950                 || (field->layout() && sz.width() < field->maxSize.width())) {
       
  1951                 sz.rwidth() = field->layoutWidth;
       
  1952             }
       
  1953 */
       
  1954             if (field->maxSize.isValid())
       
  1955                 sz = sz.boundedTo(field->maxSize);
       
  1956 
       
  1957             field->setGeometry(QStyle::visualRect(layoutDirection, rect, QRect(p, sz)));
       
  1958         }
       
  1959     }
       
  1960 }
       
  1961 
       
  1962 /*!
       
  1963     Sets the widget in the given \a row for the given \a role to \a widget, extending the
       
  1964     layout with empty rows if necessary.
       
  1965 
       
  1966     If the cell is already occupied, the \a widget is not inserted and an error message is
       
  1967     sent to the console.
       
  1968 
       
  1969     \bold{Note:} For most applications, addRow() or insertRow() should be used instead of setWidget().
       
  1970 
       
  1971     \sa setLayout()
       
  1972 */
       
  1973 void QFormLayout::setWidget(int row, ItemRole role, QWidget *widget)
       
  1974 {
       
  1975     Q_D(QFormLayout);
       
  1976     int rowCnt = rowCount();
       
  1977     if (row >= rowCnt)
       
  1978         d->insertRows(rowCnt, row - rowCnt + 1);
       
  1979     d->setWidget(row, role, widget);
       
  1980 }
       
  1981 
       
  1982 /*!
       
  1983     Sets the sub-layout in the given \a row for the given \a role to \a layout, extending the
       
  1984     form layout with empty rows if necessary.
       
  1985 
       
  1986     If the cell is already occupied, the \a layout is not inserted and an error message is
       
  1987     sent to the console.
       
  1988 
       
  1989     \bold{Note:} For most applications, addRow() or insertRow() should be used instead of setLayout().
       
  1990 
       
  1991     \sa setWidget()
       
  1992 */
       
  1993 void QFormLayout::setLayout(int row, ItemRole role, QLayout *layout)
       
  1994 {
       
  1995     Q_D(QFormLayout);
       
  1996     int rowCnt = rowCount();
       
  1997     if (row >= rowCnt)
       
  1998         d->insertRows(rowCnt, row - rowCnt + 1);
       
  1999     d->setLayout(row, role, layout);
       
  2000 }
       
  2001 
       
  2002 /*!
       
  2003     Sets the item in the given \a row for the given \a role to \a item, extending the
       
  2004     layout with empty rows if necessary.
       
  2005 
       
  2006     If the cell is already occupied, the \a item is not inserted and an error message is
       
  2007     sent to the console.
       
  2008     The \a item spans both columns.
       
  2009 
       
  2010     \warning Do not use this function to add child layouts or child
       
  2011     widget items. Use setLayout() or setWidget() instead.
       
  2012 
       
  2013     \sa setLayout()
       
  2014 */
       
  2015 void QFormLayout::setItem(int row, ItemRole role, QLayoutItem *item)
       
  2016 {
       
  2017     Q_D(QFormLayout);
       
  2018     int rowCnt = rowCount();
       
  2019     if (row >= rowCnt)
       
  2020         d->insertRows(rowCnt, row - rowCnt + 1);
       
  2021     d->setItem(row, role, item);
       
  2022 }
       
  2023 
       
  2024 /*!
       
  2025      \internal
       
  2026  */
       
  2027 
       
  2028 void QFormLayout::resetFieldGrowthPolicy()
       
  2029 {
       
  2030     Q_D(QFormLayout);
       
  2031     d->fieldGrowthPolicy = DefaultFieldGrowthPolicy;
       
  2032 }
       
  2033 
       
  2034 /*!
       
  2035      \internal
       
  2036  */
       
  2037 
       
  2038 void QFormLayout::resetRowWrapPolicy()
       
  2039 {
       
  2040     Q_D(QFormLayout);
       
  2041     d->rowWrapPolicy = DefaultRowWrapPolicy;
       
  2042 }
       
  2043 
       
  2044 /*!
       
  2045      \internal
       
  2046  */
       
  2047 
       
  2048 void QFormLayout::resetFormAlignment()
       
  2049 {
       
  2050     Q_D(QFormLayout);
       
  2051     d->formAlignment = 0;
       
  2052 }
       
  2053 
       
  2054 /*!
       
  2055      \internal
       
  2056  */
       
  2057 
       
  2058 void QFormLayout::resetLabelAlignment()
       
  2059 {
       
  2060     Q_D(QFormLayout);
       
  2061     d->labelAlignment = 0;
       
  2062 }
       
  2063 
       
  2064 #if 0
       
  2065 void QFormLayout::dump() const
       
  2066 {
       
  2067     Q_D(const QFormLayout);
       
  2068     for (int i = 0; i < rowCount(); ++i) {
       
  2069         for (int j = 0; j < 2; ++j) {
       
  2070             qDebug("m_matrix(%d, %d) = %p", i, j, d->m_matrix(i, j));
       
  2071         }
       
  2072     }
       
  2073     for (int i = 0; i < d->m_things.count(); ++i)
       
  2074         qDebug("m_things[%d] = %p", i, d->m_things.at(i));
       
  2075 }
       
  2076 #endif
       
  2077 
       
  2078 QT_END_NAMESPACE