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