tools/designer/src/lib/shared/qlayout_widget.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Designer 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 "qlayout_widget_p.h"
       
    43 #include "qdesigner_utils_p.h"
       
    44 #include "layout_p.h"
       
    45 #include "layoutinfo_p.h"
       
    46 #include "invisible_widget_p.h"
       
    47 #include "qdesigner_widgetitem_p.h"
       
    48 
       
    49 #include <QtDesigner/QDesignerFormWindowInterface>
       
    50 #include <QtDesigner/QExtensionManager>
       
    51 #include <QtDesigner/QDesignerFormEditorInterface>
       
    52 #include <QtDesigner/QDesignerPropertySheetExtension>
       
    53 #include <QtDesigner/QDesignerWidgetFactoryInterface>
       
    54 
       
    55 #include <QtGui/QPainter>
       
    56 #include <QtGui/QHBoxLayout>
       
    57 #include <QtGui/QVBoxLayout>
       
    58 #include <QtGui/QGridLayout>
       
    59 #include <QtGui/QFormLayout>
       
    60 #include <QtGui/qevent.h>
       
    61 
       
    62 #include <QtCore/qdebug.h>
       
    63 #include <QtCore/QtAlgorithms>
       
    64 #include <QtCore/QMap>
       
    65 #include <QtCore/QStack>
       
    66 #include <QtCore/QPair>
       
    67 #include <QtCore/QSet>
       
    68 
       
    69 enum { ShiftValue = 1 };
       
    70 enum { debugLayout = 0 };
       
    71 enum { FormLayoutColumns = 2 };
       
    72 enum { indicatorSize = 2 };
       
    73 // Grid/form Helpers: get info (overloads to make templates work)
       
    74 
       
    75 namespace { // Do not use static, will break HP-UX due to templates
       
    76 
       
    77 QT_USE_NAMESPACE
       
    78 
       
    79 // overloads to make templates over QGridLayout/QFormLayout work
       
    80 inline int gridRowCount(const QGridLayout *gridLayout)
       
    81 {
       
    82     return  gridLayout->rowCount();
       
    83 }
       
    84 
       
    85 inline int gridColumnCount(const QGridLayout *gridLayout)
       
    86 {
       
    87     return  gridLayout->columnCount();
       
    88 }
       
    89 
       
    90 // QGridLayout/QFormLayout Helpers: get item position (overloads to make templates work)
       
    91 inline void getGridItemPosition(QGridLayout *gridLayout, int index,
       
    92     int *row, int *column, int *rowspan, int *colspan)
       
    93 {
       
    94     gridLayout->getItemPosition(index, row, column, rowspan, colspan);
       
    95 }
       
    96 
       
    97 QRect gridItemInfo(QGridLayout *grid, int index)
       
    98 {
       
    99     int row, column, rowSpan, columnSpan;
       
   100     // getItemPosition is not const, grmbl..
       
   101     grid->getItemPosition(index, &row, &column, &rowSpan, &columnSpan);
       
   102     return QRect(column, row, columnSpan, rowSpan);
       
   103 }
       
   104 
       
   105 inline int gridRowCount(const QFormLayout *formLayout)    { return  formLayout->rowCount(); }
       
   106 inline int gridColumnCount(const QFormLayout *) { return FormLayoutColumns; }
       
   107 
       
   108 inline void getGridItemPosition(QFormLayout *formLayout, int index, int *row, int *column, int *rowspan, int *colspan)
       
   109 {
       
   110     qdesigner_internal::getFormLayoutItemPosition(formLayout, index, row, column, rowspan, colspan);
       
   111 }
       
   112 
       
   113 QRect gridItemInfo(const QFormLayout *form, int index)
       
   114 {
       
   115     int row;
       
   116     int column;
       
   117     int colspan;
       
   118     qdesigner_internal::getFormLayoutItemPosition(form, index, &row, &column, 0, &colspan);
       
   119     return QRect(column, row, colspan, 1);
       
   120 }
       
   121 } // namespace anonymous
       
   122 
       
   123 QT_BEGIN_NAMESPACE
       
   124 
       
   125 static const char *objectNameC = "objectName";
       
   126 static const char *sizeConstraintC = "sizeConstraint";
       
   127 
       
   128 /* A padding spacer element that is used to represent an empty form layout cell. It should grow with its cell.
       
   129  * Should not be used on a grid as it causes resizing inconsistencies */
       
   130 namespace qdesigner_internal {
       
   131     class PaddingSpacerItem : public QSpacerItem {
       
   132     public:
       
   133         PaddingSpacerItem() : QSpacerItem(0, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding) {}
       
   134         virtual Qt::Orientations expandingDirections () const { return Qt::Vertical | Qt::Horizontal; }
       
   135     };
       
   136 }
       
   137 
       
   138 static inline QSpacerItem *createGridSpacer()
       
   139 {
       
   140     return new QSpacerItem(0, 0);
       
   141 }
       
   142 
       
   143 static inline QSpacerItem *createFormSpacer()
       
   144 {
       
   145     return new qdesigner_internal::PaddingSpacerItem;
       
   146 }
       
   147 
       
   148 // QGridLayout/QFormLayout Helpers: Debug items of GridLikeLayout
       
   149 template <class GridLikeLayout>
       
   150 static QDebug debugGridLikeLayout(QDebug str, const GridLikeLayout &gl)
       
   151 {
       
   152     const int count = gl.count();
       
   153     str << "Grid: " << gl.objectName() <<   gridRowCount(&gl) << " rows x " <<  gridColumnCount(&gl)
       
   154         << " cols " << count << " items\n";
       
   155     for (int i = 0; i < count; i++) {
       
   156         QLayoutItem *item = gl.itemAt(i);
       
   157         str << "Item " << i << item << item->widget() << gridItemInfo(const_cast<GridLikeLayout *>(&gl), i) << " empty=" << qdesigner_internal::LayoutInfo::isEmptyItem(item) << "\n";
       
   158     }
       
   159     return str;
       
   160 }
       
   161 
       
   162 static inline QDebug operator<<(QDebug str, const QGridLayout &gl) { return debugGridLikeLayout(str, gl); }
       
   163 static inline QDebug operator<<(QDebug str, const QFormLayout &fl) { return debugGridLikeLayout(str, fl); }
       
   164 
       
   165 static inline bool isEmptyFormLayoutRow(const QFormLayout *fl, int row)
       
   166 {
       
   167     // Spanning can never be empty
       
   168     if (fl->itemAt(row, QFormLayout::SpanningRole))
       
   169         return false;
       
   170     return qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::LabelRole)) && qdesigner_internal::LayoutInfo::isEmptyItem(fl->itemAt(row, QFormLayout::FieldRole));
       
   171 }
       
   172 
       
   173 static inline bool canSimplifyFormLayout(const QFormLayout *formLayout, const QRect &restrictionArea)
       
   174 {
       
   175     if (restrictionArea.x() >= FormLayoutColumns)
       
   176         return false;
       
   177     // Try to find empty rows
       
   178     const int bottomCheckRow = qMin(formLayout->rowCount(), restrictionArea.top() + restrictionArea.height());
       
   179     for (int r = restrictionArea.y(); r < bottomCheckRow; r++)
       
   180         if (isEmptyFormLayoutRow(formLayout, r))
       
   181             return true;
       
   182     return false;
       
   183 }
       
   184 
       
   185 // recreate a managed layout (which does not automagically remove
       
   186 // empty rows/columns like grid or form layout) in case it needs to shrink
       
   187 
       
   188 static QLayout *recreateManagedLayout(const QDesignerFormEditorInterface *core, QWidget *w, QLayout *lt)
       
   189 {
       
   190     const qdesigner_internal::LayoutInfo::Type t = qdesigner_internal::LayoutInfo::layoutType(core, lt);
       
   191     qdesigner_internal::LayoutProperties properties;
       
   192     const int mask = properties.fromPropertySheet(core, lt, qdesigner_internal::LayoutProperties::AllProperties);
       
   193     qdesigner_internal::LayoutInfo::deleteLayout(core, w);
       
   194     QLayout *rc = core->widgetFactory()->createLayout(w, 0, t);
       
   195     properties.toPropertySheet(core, rc, mask, true);
       
   196     return rc;
       
   197 }
       
   198 
       
   199 // QGridLayout/QFormLayout Helpers: find an item on a form/grid. Return index
       
   200 template <class GridLikeLayout>
       
   201 int findGridItemAt(GridLikeLayout *gridLayout, int at_row, int at_column)
       
   202 {
       
   203     Q_ASSERT(gridLayout);
       
   204     const int count = gridLayout->count();
       
   205     for (int index = 0; index <  count; index++) {
       
   206         int row, column, rowspan, colspan;
       
   207         getGridItemPosition(gridLayout, index, &row, &column, &rowspan, &colspan);
       
   208         if (at_row >= row && at_row < (row + rowspan)
       
   209             && at_column >= column && at_column < (column + colspan)) {
       
   210             return index;
       
   211         }
       
   212     }
       
   213     return -1;
       
   214 }
       
   215 // QGridLayout/QFormLayout  Helpers: remove dummy spacers on form/grid
       
   216 template <class GridLikeLayout>
       
   217 static bool removeEmptyCellsOnGrid(GridLikeLayout *grid, const QRect &area)
       
   218 {
       
   219     // check if there are any items in the way. Should be only spacers
       
   220     // Unique out items that span rows/columns.
       
   221     QVector<int> indexesToBeRemoved;
       
   222     indexesToBeRemoved.reserve(grid->count());
       
   223     const int rightColumn = area.x() + area.width();
       
   224     const int bottomRow = area.y() + area.height();
       
   225     for (int c = area.x(); c < rightColumn; c++)
       
   226         for (int r = area.y(); r < bottomRow; r++) {
       
   227             const int index = findGridItemAt(grid, r ,c);
       
   228             if (index != -1)
       
   229                 if (QLayoutItem *item = grid->itemAt(index)) {
       
   230                     if (qdesigner_internal::LayoutInfo::isEmptyItem(item)) {
       
   231                         if (indexesToBeRemoved.indexOf(index) == -1)
       
   232                             indexesToBeRemoved.push_back(index);
       
   233                     } else {
       
   234                         return false;
       
   235                     }
       
   236                 }
       
   237         }
       
   238     // remove, starting from last
       
   239     if (!indexesToBeRemoved.empty()) {
       
   240         qStableSort(indexesToBeRemoved.begin(), indexesToBeRemoved.end());
       
   241         for (int i = indexesToBeRemoved.size() - 1; i >= 0; i--)
       
   242             delete grid->takeAt(indexesToBeRemoved[i]);
       
   243     }
       
   244     return true;
       
   245 }
       
   246 
       
   247 namespace qdesigner_internal {
       
   248 // --------- LayoutProperties
       
   249 
       
   250 LayoutProperties::LayoutProperties()
       
   251 {
       
   252     clear();
       
   253 }
       
   254 
       
   255 void LayoutProperties::clear()
       
   256 {
       
   257     qFill(m_margins, m_margins + MarginCount, 0);
       
   258     qFill(m_marginsChanged, m_marginsChanged + MarginCount, false);
       
   259     qFill(m_spacings, m_spacings + SpacingsCount, 0);
       
   260     qFill(m_spacingsChanged, m_spacingsChanged + SpacingsCount, false);
       
   261 
       
   262     m_objectName = QVariant();
       
   263     m_objectNameChanged = false;
       
   264     m_sizeConstraint = QVariant(QLayout::SetDefaultConstraint);
       
   265     m_sizeConstraintChanged = false;
       
   266 
       
   267     m_fieldGrowthPolicyChanged = m_rowWrapPolicyChanged =  m_labelAlignmentChanged = m_formAlignmentChanged = false;
       
   268     m_fieldGrowthPolicy =  m_rowWrapPolicy =  m_formAlignment = QVariant();
       
   269 
       
   270     m_boxStretchChanged = m_gridRowStretchChanged = m_gridColumnStretchChanged = m_gridRowMinimumHeightChanged = false;
       
   271     m_boxStretch = m_gridRowStretch =  m_gridColumnStretch =  m_gridRowMinimumHeight = QVariant();
       
   272 }
       
   273 
       
   274 int LayoutProperties::visibleProperties(const  QLayout *layout)
       
   275 {
       
   276     // Grid like layout have 2 spacings.
       
   277     const bool isFormLayout = qobject_cast<const QFormLayout*>(layout);
       
   278     const bool isGridLike = qobject_cast<const QGridLayout*>(layout) || isFormLayout;
       
   279     int rc = ObjectNameProperty|LeftMarginProperty|TopMarginProperty|RightMarginProperty|BottomMarginProperty|
       
   280              SizeConstraintProperty;
       
   281 
       
   282     rc |= isGridLike ? (HorizSpacingProperty|VertSpacingProperty) : SpacingProperty;
       
   283     if (isFormLayout) {
       
   284         rc |= FieldGrowthPolicyProperty|RowWrapPolicyProperty|LabelAlignmentProperty|FormAlignmentProperty;
       
   285     } else {
       
   286         if (isGridLike) {
       
   287             rc |=  GridRowStretchProperty|GridColumnStretchProperty|GridRowMinimumHeightProperty|GridColumnMinimumWidthProperty;
       
   288         } else {
       
   289             rc |=  BoxStretchProperty;
       
   290         }
       
   291     }
       
   292     return rc;
       
   293 }
       
   294 
       
   295 static const char *marginPropertyNamesC[] = {"leftMargin", "topMargin", "rightMargin", "bottomMargin"};
       
   296 static const char *spacingPropertyNamesC[] = {"spacing", "horizontalSpacing", "verticalSpacing" };
       
   297 static const char *fieldGrowthPolicyPropertyC = "fieldGrowthPolicy";
       
   298 static const char *rowWrapPolicyPropertyC = "rowWrapPolicy";
       
   299 static const char *labelAlignmentPropertyC = "labelAlignment";
       
   300 static const char *formAlignmentPropertyC = "formAlignment";
       
   301 static const char *boxStretchPropertyC = "stretch";
       
   302 static const char *gridRowStretchPropertyC = "rowStretch";
       
   303 static const char *gridColumnStretchPropertyC = "columnStretch";
       
   304 static const char *gridRowMinimumHeightPropertyC = "rowMinimumHeight";
       
   305 static const char *gridColumnMinimumWidthPropertyC = "columnMinimumWidth";
       
   306 
       
   307 static bool intValueFromSheet(const QDesignerPropertySheetExtension *sheet, const QString &name, int *value, bool *changed)
       
   308 {
       
   309     const int sheetIndex = sheet->indexOf(name);
       
   310     if (sheetIndex == -1)
       
   311         return false;
       
   312     *value = sheet->property(sheetIndex).toInt();
       
   313     *changed = sheet->isChanged(sheetIndex);
       
   314     return true;
       
   315 }
       
   316 
       
   317 static void variantPropertyFromSheet(int mask, int flag, const QDesignerPropertySheetExtension *sheet, const QString &name,
       
   318                                      QVariant *value, bool *changed, int *returnMask)
       
   319 {
       
   320     if (mask & flag) {
       
   321         const int sIndex = sheet->indexOf(name);
       
   322         if (sIndex != -1) {
       
   323             *value = sheet->property(sIndex);
       
   324             *changed = sheet->isChanged(sIndex);
       
   325             *returnMask |= flag;
       
   326         }
       
   327     }
       
   328 }
       
   329 
       
   330 int LayoutProperties::fromPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask)
       
   331 {
       
   332     int rc = 0;
       
   333     const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), l);
       
   334     Q_ASSERT(sheet);
       
   335     // name
       
   336     if (mask & ObjectNameProperty) {
       
   337         const int nameIndex = sheet->indexOf(QLatin1String(objectNameC));
       
   338         Q_ASSERT(nameIndex != -1);
       
   339         m_objectName = sheet->property(nameIndex);
       
   340         m_objectNameChanged =  sheet->isChanged(nameIndex);
       
   341         rc |= ObjectNameProperty;
       
   342     }
       
   343     // -- Margins
       
   344     const int marginFlags[MarginCount] = { LeftMarginProperty, TopMarginProperty, RightMarginProperty, BottomMarginProperty};
       
   345     for (int i = 0; i < MarginCount; i++)
       
   346         if (mask & marginFlags[i])
       
   347             if (intValueFromSheet(sheet, QLatin1String(marginPropertyNamesC[i]), m_margins + i, m_marginsChanged + i))
       
   348                 rc |= marginFlags[i];
       
   349 
       
   350     const int spacingFlags[] = { SpacingProperty, HorizSpacingProperty, VertSpacingProperty};
       
   351     for (int i = 0; i < SpacingsCount; i++)
       
   352         if (mask & spacingFlags[i])
       
   353             if (intValueFromSheet(sheet, QLatin1String(spacingPropertyNamesC[i]), m_spacings + i, m_spacingsChanged + i))
       
   354                 rc |= spacingFlags[i];
       
   355     // sizeConstraint, flags
       
   356     variantPropertyFromSheet(mask, SizeConstraintProperty, sheet, QLatin1String(sizeConstraintC), &m_sizeConstraint, &m_sizeConstraintChanged, &rc);
       
   357     variantPropertyFromSheet(mask, FieldGrowthPolicyProperty, sheet, QLatin1String(fieldGrowthPolicyPropertyC), &m_fieldGrowthPolicy, &m_fieldGrowthPolicyChanged, &rc);
       
   358     variantPropertyFromSheet(mask, RowWrapPolicyProperty, sheet, QLatin1String(rowWrapPolicyPropertyC), &m_rowWrapPolicy, &m_rowWrapPolicyChanged, &rc);
       
   359     variantPropertyFromSheet(mask, LabelAlignmentProperty, sheet, QLatin1String(labelAlignmentPropertyC), &m_labelAlignment, &m_labelAlignmentChanged, &rc);
       
   360     variantPropertyFromSheet(mask, FormAlignmentProperty, sheet, QLatin1String(formAlignmentPropertyC), &m_formAlignment, &m_formAlignmentChanged, &rc);
       
   361     variantPropertyFromSheet(mask, BoxStretchProperty, sheet, QLatin1String(boxStretchPropertyC), &m_boxStretch, & m_boxStretchChanged, &rc);
       
   362     variantPropertyFromSheet(mask, GridRowStretchProperty, sheet, QLatin1String(gridRowStretchPropertyC), &m_gridRowStretch, &m_gridRowStretchChanged, &rc);
       
   363     variantPropertyFromSheet(mask, GridColumnStretchProperty, sheet, QLatin1String(gridColumnStretchPropertyC), &m_gridColumnStretch, &m_gridColumnStretchChanged, &rc);
       
   364     variantPropertyFromSheet(mask, GridRowMinimumHeightProperty, sheet, QLatin1String(gridRowMinimumHeightPropertyC), &m_gridRowMinimumHeight, &m_gridRowMinimumHeightChanged, &rc);
       
   365     variantPropertyFromSheet(mask, GridColumnMinimumWidthProperty, sheet, QLatin1String(gridColumnMinimumWidthPropertyC), &m_gridColumnMinimumWidth, &m_gridColumnMinimumWidthChanged, &rc);
       
   366     return rc;
       
   367 }
       
   368 
       
   369 static bool intValueToSheet(QDesignerPropertySheetExtension *sheet, const QString &name, int value, bool changed, bool applyChanged)
       
   370 
       
   371 {
       
   372 
       
   373     const int sheetIndex = sheet->indexOf(name);
       
   374     if (sheetIndex == -1) {
       
   375         qWarning() << " LayoutProperties: Attempt to set property " << name << " that does not exist for the layout.";
       
   376         return false;
       
   377     }
       
   378     sheet->setProperty(sheetIndex, QVariant(value));
       
   379     if (applyChanged)
       
   380         sheet->setChanged(sheetIndex, changed);
       
   381     return true;
       
   382 }
       
   383 
       
   384 static void variantPropertyToSheet(int mask, int flag, bool applyChanged, QDesignerPropertySheetExtension *sheet, const QString &name,
       
   385                                    const QVariant &value, bool changed, int *returnMask)
       
   386 {
       
   387     if (mask & flag) {
       
   388         const int sIndex = sheet->indexOf(name);
       
   389         if (sIndex != -1) {
       
   390             sheet->setProperty(sIndex, value);
       
   391             if (applyChanged)
       
   392                 sheet->setChanged(sIndex, changed);
       
   393             *returnMask |= flag;
       
   394         }
       
   395     }
       
   396 }
       
   397 
       
   398 int LayoutProperties::toPropertySheet(const QDesignerFormEditorInterface *core, QLayout *l, int mask, bool applyChanged) const
       
   399 {
       
   400     int rc = 0;
       
   401     QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(core->extensionManager(), l);
       
   402     Q_ASSERT(sheet);
       
   403     // name
       
   404     if (mask & ObjectNameProperty) {
       
   405         const int nameIndex = sheet->indexOf(QLatin1String(objectNameC));
       
   406         Q_ASSERT(nameIndex != -1);
       
   407         sheet->setProperty(nameIndex, m_objectName);
       
   408         if (applyChanged)
       
   409            sheet->setChanged(nameIndex, m_objectNameChanged);
       
   410         rc |= ObjectNameProperty;
       
   411     }
       
   412     // margins
       
   413     const int marginFlags[MarginCount] = { LeftMarginProperty, TopMarginProperty, RightMarginProperty, BottomMarginProperty};
       
   414     for (int i = 0; i < MarginCount; i++)
       
   415         if (mask & marginFlags[i])
       
   416             if (intValueToSheet(sheet, QLatin1String(marginPropertyNamesC[i]), m_margins[i], m_marginsChanged[i], applyChanged))
       
   417                 rc |= marginFlags[i];
       
   418 
       
   419     const int spacingFlags[] = { SpacingProperty, HorizSpacingProperty, VertSpacingProperty};
       
   420     for (int i = 0; i < SpacingsCount; i++)
       
   421         if (mask & spacingFlags[i])
       
   422             if (intValueToSheet(sheet, QLatin1String(spacingPropertyNamesC[i]), m_spacings[i], m_spacingsChanged[i], applyChanged))
       
   423                 rc |= spacingFlags[i];
       
   424     // sizeConstraint
       
   425     variantPropertyToSheet(mask, SizeConstraintProperty, applyChanged, sheet, QLatin1String(sizeConstraintC), m_sizeConstraint, m_sizeConstraintChanged, &rc);
       
   426     variantPropertyToSheet(mask, FieldGrowthPolicyProperty, applyChanged, sheet, QLatin1String(fieldGrowthPolicyPropertyC), m_fieldGrowthPolicy, &m_fieldGrowthPolicyChanged, &rc);
       
   427     variantPropertyToSheet(mask, RowWrapPolicyProperty, applyChanged, sheet, QLatin1String(rowWrapPolicyPropertyC), m_rowWrapPolicy, m_rowWrapPolicyChanged, &rc);
       
   428     variantPropertyToSheet(mask, LabelAlignmentProperty, applyChanged, sheet, QLatin1String(labelAlignmentPropertyC), m_labelAlignment, m_labelAlignmentChanged, &rc);
       
   429     variantPropertyToSheet(mask, FormAlignmentProperty, applyChanged, sheet, QLatin1String(formAlignmentPropertyC), m_formAlignment, m_formAlignmentChanged, &rc);
       
   430     variantPropertyToSheet(mask, BoxStretchProperty, applyChanged, sheet, QLatin1String(boxStretchPropertyC), m_boxStretch, m_boxStretchChanged, &rc);
       
   431     variantPropertyToSheet(mask, GridRowStretchProperty, applyChanged, sheet, QLatin1String(gridRowStretchPropertyC), m_gridRowStretch, m_gridRowStretchChanged, &rc);
       
   432     variantPropertyToSheet(mask, GridColumnStretchProperty, applyChanged, sheet, QLatin1String(gridColumnStretchPropertyC), m_gridColumnStretch, m_gridColumnStretchChanged, &rc);
       
   433     variantPropertyToSheet(mask, GridRowMinimumHeightProperty, applyChanged, sheet, QLatin1String(gridRowMinimumHeightPropertyC), m_gridRowMinimumHeight, m_gridRowMinimumHeightChanged, &rc);
       
   434     variantPropertyToSheet(mask, GridColumnMinimumWidthProperty, applyChanged, sheet, QLatin1String(gridColumnMinimumWidthPropertyC), m_gridColumnMinimumWidth, m_gridColumnMinimumWidthChanged, &rc);
       
   435     return rc;
       
   436 }
       
   437 
       
   438 // ---------------- LayoutHelper
       
   439 LayoutHelper::LayoutHelper()
       
   440 {
       
   441 }
       
   442 
       
   443 LayoutHelper::~LayoutHelper()
       
   444 {
       
   445 }
       
   446 
       
   447 int LayoutHelper::indexOf(const QLayout *lt, const QWidget *widget)
       
   448 {
       
   449     if (!lt)
       
   450         return -1;
       
   451 
       
   452     const int itemCount = lt->count();
       
   453     for (int i = 0; i < itemCount; i++)
       
   454         if (lt->itemAt(i)->widget() == widget)
       
   455             return i;
       
   456     return -1;
       
   457 }
       
   458 
       
   459 QRect LayoutHelper::itemInfo(QLayout *lt, const QWidget *widget) const
       
   460 {
       
   461     const int index = indexOf(lt, widget);
       
   462     if (index == -1) {
       
   463         qWarning() << "LayoutHelper::itemInfo: " << widget << " not in layout " << lt;
       
   464         return QRect(0, 0, 1, 1);
       
   465     }
       
   466     return itemInfo(lt, index);
       
   467 }
       
   468 
       
   469     // ---------------- BoxLayoutHelper
       
   470     class BoxLayoutHelper : public  LayoutHelper {
       
   471     public:
       
   472         BoxLayoutHelper(const Qt::Orientation orientation) : m_orientation(orientation) {}
       
   473 
       
   474         virtual QRect itemInfo(QLayout *lt, int index) const;
       
   475         virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w);
       
   476         virtual void removeWidget(QLayout *lt, QWidget *widget);
       
   477         virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after);
       
   478 
       
   479         virtual void pushState(const QDesignerFormEditorInterface *, const QWidget *);
       
   480         virtual void popState(const QDesignerFormEditorInterface *, QWidget *);
       
   481 
       
   482         virtual bool canSimplify(const QDesignerFormEditorInterface *, const QWidget *, const QRect &) const { return  false; }
       
   483         virtual void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &) {}
       
   484 
       
   485         // Helper for restoring layout states
       
   486         typedef QVector <QLayoutItem *> LayoutItemVector;
       
   487         static LayoutItemVector disassembleLayout(QLayout *lt);
       
   488         static QLayoutItem *findItemOfWidget(const LayoutItemVector &lv, QWidget *w);
       
   489 
       
   490     private:
       
   491         typedef QVector<QWidget *> BoxLayoutState;
       
   492 
       
   493         static BoxLayoutState state(const QBoxLayout*lt);
       
   494 
       
   495         QStack<BoxLayoutState> m_states;
       
   496         const Qt::Orientation m_orientation;
       
   497     };
       
   498 
       
   499     QRect BoxLayoutHelper::itemInfo(QLayout * /*lt*/, int index) const
       
   500     {
       
   501         return m_orientation == Qt::Horizontal ?  QRect(index, 0, 1, 1) : QRect(0, index, 1, 1);
       
   502     }
       
   503 
       
   504     void BoxLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
       
   505     {
       
   506         QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
       
   507         QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt);
       
   508         Q_ASSERT(boxLayout);
       
   509         boxLayout->insertWidget(m_orientation == Qt::Horizontal ? info.x() : info.y(), w);
       
   510     }
       
   511 
       
   512     void BoxLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
       
   513     {
       
   514         QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt);
       
   515         Q_ASSERT(boxLayout);
       
   516         boxLayout->removeWidget(widget);
       
   517     }
       
   518 
       
   519     void BoxLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
       
   520     {
       
   521         bool ok = false;
       
   522         QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
       
   523         if (QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(lt)) {
       
   524             const int index = boxLayout->indexOf(before);
       
   525             if (index != -1) {
       
   526                 const bool visible = before->isVisible();
       
   527                 delete boxLayout->takeAt(index);
       
   528                 if (visible)
       
   529                     before->hide();
       
   530                 before->setParent(0);
       
   531                 boxLayout->insertWidget(index, after);
       
   532                 ok = true;
       
   533             }
       
   534         }
       
   535         if (!ok)
       
   536             qWarning() << "BoxLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
       
   537     }
       
   538 
       
   539     BoxLayoutHelper::BoxLayoutState BoxLayoutHelper::state(const QBoxLayout*lt)
       
   540     {
       
   541         BoxLayoutState rc;
       
   542         if (const int count = lt->count()) {
       
   543             rc.reserve(count);
       
   544             for (int i = 0; i < count; i++)
       
   545                 if (QWidget *w = lt->itemAt(i)->widget())
       
   546                     rc.push_back(w);
       
   547         }
       
   548         return rc;
       
   549     }
       
   550 
       
   551     void BoxLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *w)
       
   552     {
       
   553         const QBoxLayout *boxLayout = qobject_cast<const QBoxLayout *>(LayoutInfo::managedLayout(core, w));
       
   554         Q_ASSERT(boxLayout);
       
   555         m_states.push(state(boxLayout));
       
   556     }
       
   557 
       
   558     QLayoutItem *BoxLayoutHelper::findItemOfWidget(const LayoutItemVector &lv, QWidget *w)
       
   559     {
       
   560         const LayoutItemVector::const_iterator cend = lv.constEnd();
       
   561         for (LayoutItemVector::const_iterator it = lv.constBegin(); it != cend; ++it)
       
   562             if ( (*it)->widget() == w)
       
   563                 return *it;
       
   564 
       
   565         return 0;
       
   566     }
       
   567 
       
   568     BoxLayoutHelper::LayoutItemVector BoxLayoutHelper::disassembleLayout(QLayout *lt)
       
   569     {
       
   570         // Take items
       
   571         const int count = lt->count();
       
   572         if (count == 0)
       
   573             return LayoutItemVector();
       
   574         LayoutItemVector rc;
       
   575         rc.reserve(count);
       
   576         for (int i = count - 1; i >= 0; i--)
       
   577             rc.push_back(lt->takeAt(i));
       
   578         return rc;
       
   579     }
       
   580 
       
   581     void BoxLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *w)
       
   582     {
       
   583         QBoxLayout *boxLayout = qobject_cast<QBoxLayout *>(LayoutInfo::managedLayout(core, w));
       
   584         Q_ASSERT(boxLayout);
       
   585         const BoxLayoutState savedState = m_states.pop();
       
   586         const BoxLayoutState currentState = state(boxLayout);
       
   587         // Check for equality/empty. Note that this will currently
       
   588         // always trigger as box layouts do not have a state apart from
       
   589         // the order and there is no layout order editor yet.
       
   590         if (savedState == state(boxLayout))
       
   591             return;
       
   592 
       
   593         const int count = savedState.size();
       
   594         Q_ASSERT(count == currentState.size());
       
   595         // Take items and reassemble in saved order
       
   596         const LayoutItemVector items = disassembleLayout(boxLayout);
       
   597         for (int i = 0; i < count; i++) {
       
   598             QLayoutItem *item = findItemOfWidget(items, savedState[i]);
       
   599             Q_ASSERT(item);
       
   600             boxLayout->addItem(item);
       
   601         }
       
   602     }
       
   603 
       
   604     // Grid Layout state. Datatypically store the state of a GridLayout as a map of
       
   605     // widgets to QRect(columns, rows) and size. Used to store the state for undo operations
       
   606     // that do not change the widgets within the layout; also provides some manipulation
       
   607     // functions and ability to apply the state to a layout provided its widgets haven't changed.
       
   608     struct GridLayoutState {
       
   609         GridLayoutState();
       
   610 
       
   611         void fromLayout(QGridLayout *l);
       
   612         void applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const;
       
   613 
       
   614         void insertRow(int row);
       
   615         void insertColumn(int column);
       
   616 
       
   617         bool simplify(const QRect &r, bool testOnly);
       
   618         void removeFreeRow(int row);
       
   619         void removeFreeColumn(int column);
       
   620 
       
   621 
       
   622         // State of a cell in one dimension
       
   623         enum DimensionCellState {
       
   624             Free,
       
   625             Spanned,  // Item spans it
       
   626             Occupied  // Item bordering on it
       
   627         };
       
   628         // Horiontal, Vertical pair of state
       
   629         typedef QPair<DimensionCellState, DimensionCellState> CellState;
       
   630         typedef QVector<CellState> CellStates;
       
   631 
       
   632         // Figure out states of a cell and return as a flat vector of
       
   633         // [column1, column2,...] (address as  row * columnCount + col)
       
   634         static CellStates cellStates(const QList<QRect> &rects, int numRows, int numColumns);
       
   635 
       
   636         typedef QMap<QWidget *, QRect> WidgetItemMap;
       
   637         WidgetItemMap widgetItemMap;
       
   638         int rowCount;
       
   639         int colCount;
       
   640     };
       
   641 
       
   642     static inline bool needsSpacerItem(const GridLayoutState::CellState &cs) {
       
   643         return cs.first == GridLayoutState::Free && cs.second == GridLayoutState::Free;
       
   644     }
       
   645 
       
   646     static inline QDebug operator<<(QDebug str, const GridLayoutState &gs)
       
   647     {
       
   648         str << "GridLayoutState: " <<  gs.rowCount << " rows x " <<  gs.colCount
       
   649             << " cols " << gs.widgetItemMap.size() << " items\n";
       
   650 
       
   651         const GridLayoutState::WidgetItemMap::const_iterator wcend = gs.widgetItemMap.constEnd();
       
   652         for (GridLayoutState::WidgetItemMap::const_iterator it = gs.widgetItemMap.constBegin(); it != wcend; ++it)
       
   653             str << "Item " << it.key() << it.value() << '\n';
       
   654         return str;
       
   655     }
       
   656 
       
   657     GridLayoutState::GridLayoutState() :
       
   658          rowCount(0),
       
   659          colCount(0)
       
   660     {
       
   661     }
       
   662 
       
   663     GridLayoutState::CellStates GridLayoutState::cellStates(const QList<QRect> &rects, int numRows, int numColumns)
       
   664     {
       
   665         CellStates rc = CellStates(numRows * numColumns, CellState(Free, Free));
       
   666         const QList<QRect>::const_iterator rcend = rects.constEnd();
       
   667         for (QList<QRect>::const_iterator it = rects.constBegin(); it != rcend; ++it) {
       
   668             const int leftColumn = it->x();
       
   669             const int topRow = it->y();
       
   670             const int rightColumn = leftColumn + it->width() - 1;
       
   671             const int bottomRow = topRow + it->height() - 1;
       
   672             for (int r = topRow; r <= bottomRow; r++)
       
   673                 for (int c = leftColumn; c <= rightColumn; c++) {
       
   674                     const int flatIndex = r * numColumns + c;
       
   675                     // Bordering horizontally?
       
   676                     DimensionCellState &horizState = rc[flatIndex].first;
       
   677                     if (c == leftColumn || c == rightColumn) {
       
   678                         horizState = Occupied;
       
   679                     } else {
       
   680                         if (horizState < Spanned)
       
   681                             horizState = Spanned;
       
   682                     }
       
   683                     // Bordering vertically?
       
   684                     DimensionCellState &vertState = rc[flatIndex].second;
       
   685                     if (r == topRow || r == bottomRow) {
       
   686                         vertState = Occupied;
       
   687                     } else {
       
   688                         if (vertState < Spanned)
       
   689                             vertState = Spanned;
       
   690                     }
       
   691                 }
       
   692         }
       
   693         if (debugLayout) {
       
   694             qDebug() << "GridLayoutState::cellStates: " << numRows << " x " << numColumns;
       
   695             for (int r = 0; r < numRows; r++)
       
   696                 for (int c = 0; c < numColumns; c++)
       
   697                     qDebug() << "  Row: " << r << " column: " << c <<  rc[r * numColumns + c];
       
   698         }
       
   699         return rc;
       
   700     }
       
   701 
       
   702     void GridLayoutState::fromLayout(QGridLayout *l)
       
   703     {
       
   704         rowCount = l->rowCount();
       
   705         colCount = l->columnCount();
       
   706         const int count = l->count();
       
   707         for (int i = 0; i < count; i++) {
       
   708             QLayoutItem *item = l->itemAt(i);
       
   709             if (!LayoutInfo::isEmptyItem(item))
       
   710                 widgetItemMap.insert(item->widget(), gridItemInfo(l, i));
       
   711         }
       
   712     }
       
   713 
       
   714     void GridLayoutState::applyToLayout(const QDesignerFormEditorInterface *core, QWidget *w) const
       
   715     {
       
   716         typedef QMap<QLayoutItem *, QRect> LayoutItemRectMap;
       
   717         QGridLayout *grid = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, w));
       
   718         Q_ASSERT(grid);
       
   719         if (debugLayout)
       
   720             qDebug() << ">GridLayoutState::applyToLayout" <<  *this << *grid;
       
   721         const bool shrink = grid->rowCount() > rowCount || grid->columnCount() > colCount;
       
   722         // Build a map of existing items to rectangles via widget map, delete spacers
       
   723         LayoutItemRectMap itemMap;
       
   724         while (grid->count()) {
       
   725             QLayoutItem *item = grid->takeAt(0);
       
   726             if (!LayoutInfo::isEmptyItem(item)) {
       
   727                 QWidget *itemWidget = item->widget();
       
   728                 const WidgetItemMap::const_iterator it = widgetItemMap.constFind(itemWidget);
       
   729                 if (it == widgetItemMap.constEnd())
       
   730                     qFatal("GridLayoutState::applyToLayout: Attempt to apply to a layout that has a widget '%s'/'%s' added after saving the state.",
       
   731                            itemWidget->metaObject()->className(), itemWidget->objectName().toUtf8().constData());
       
   732                 itemMap.insert(item, it.value());
       
   733             } else {
       
   734                 delete item;
       
   735             }
       
   736         }
       
   737         Q_ASSERT(itemMap.size() == widgetItemMap.size());
       
   738         // recreate if shrink
       
   739         if (shrink)
       
   740             grid = static_cast<QGridLayout*>(recreateManagedLayout(core, w, grid));
       
   741 
       
   742         // Add widgets items
       
   743         const LayoutItemRectMap::const_iterator icend = itemMap.constEnd();
       
   744         for (LayoutItemRectMap::const_iterator it = itemMap.constBegin(); it != icend; ++it) {
       
   745             const QRect info = it.value();
       
   746             grid->addItem(it.key(), info.y(), info.x(), info.height(), info.width());
       
   747         }
       
   748         // create spacers
       
   749         const CellStates cs = cellStates(itemMap.values(), rowCount, colCount);
       
   750         for (int r = 0; r < rowCount; r++)
       
   751             for (int c = 0; c < colCount; c++)
       
   752                 if (needsSpacerItem(cs[r * colCount  + c]))
       
   753                     grid->addItem(createGridSpacer(), r, c);
       
   754         grid->activate();
       
   755         if (debugLayout)
       
   756             qDebug() << "<GridLayoutState::applyToLayout" <<  *grid;
       
   757     }
       
   758 
       
   759     void GridLayoutState::insertRow(int row)
       
   760     {
       
   761         rowCount++;
       
   762         const WidgetItemMap::iterator iend = widgetItemMap.end();
       
   763         for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) {
       
   764             const int topRow = it.value().y();
       
   765             if (topRow >= row) {
       
   766                 it.value().translate(0, 1);
       
   767             } else {  //Over  it: Does it span it -> widen?
       
   768                 const int rowSpan = it.value().height();
       
   769                 if (rowSpan > 1 && topRow + rowSpan > row)
       
   770                     it.value().setHeight(rowSpan + 1);
       
   771             }
       
   772         }
       
   773     }
       
   774 
       
   775     void GridLayoutState::insertColumn(int column)
       
   776     {
       
   777         colCount++;
       
   778         const WidgetItemMap::iterator iend = widgetItemMap.end();
       
   779         for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) {
       
   780             const int leftColumn = it.value().x();
       
   781             if (leftColumn >= column) {
       
   782                 it.value().translate(1, 0);
       
   783             } else { // Left of it: Does it span it -> widen?
       
   784                 const int colSpan = it.value().width();
       
   785                 if (colSpan  > 1 &&  leftColumn + colSpan > column)
       
   786                     it.value().setWidth(colSpan + 1);
       
   787             }
       
   788         }
       
   789     }
       
   790 
       
   791     // Simplify: Remove empty columns/rows and such ones that are only spanned (shrink
       
   792     // spanning items).
       
   793     // 'AB.C.'           'ABC'
       
   794     // 'DDDD.'     ==>   'DDD'
       
   795     // 'EF.G.'           'EFG'
       
   796     bool GridLayoutState::simplify(const QRect &r, bool testOnly)
       
   797     {
       
   798         // figure out free rows/columns.
       
   799         QVector<bool> occupiedRows(rowCount, false);
       
   800         QVector<bool> occupiedColumns(colCount, false);
       
   801         // Mark everything outside restriction rectangle as occupied
       
   802         const int restrictionLeftColumn = r.x();
       
   803         const int restrictionRightColumn = restrictionLeftColumn + r.width();
       
   804         const int restrictionTopRow = r.y();
       
   805         const int restrictionBottomRow = restrictionTopRow + r.height();
       
   806         if (restrictionLeftColumn > 0 || restrictionRightColumn < colCount ||
       
   807             restrictionTopRow     > 0 || restrictionBottomRow   < rowCount) {
       
   808             for (int r = 0; r <  rowCount; r++)
       
   809                 if (r < restrictionTopRow || r >= restrictionBottomRow)
       
   810                     occupiedRows[r] = true;
       
   811             for (int c = 0; c < colCount; c++)
       
   812                 if (c < restrictionLeftColumn ||  c >= restrictionRightColumn)
       
   813                     occupiedColumns[c] = true;
       
   814         }
       
   815         // figure out free fields and tick off occupied rows and columns
       
   816         const CellStates cs = cellStates(widgetItemMap.values(), rowCount, colCount);
       
   817         for (int r = 0; r < rowCount; r++)
       
   818             for (int c = 0; c < colCount; c++) {
       
   819                 const CellState &state = cs[r * colCount  + c];
       
   820                 if (state.first == Occupied)
       
   821                     occupiedColumns[c] = true;
       
   822                 if (state.second == Occupied)
       
   823                     occupiedRows[r] = true;
       
   824             }
       
   825         // Any free rows/columns?
       
   826         if (occupiedRows.indexOf(false) ==  -1 && occupiedColumns.indexOf(false) == -1)
       
   827             return false;
       
   828         if (testOnly)
       
   829             return true;
       
   830         // remove rows
       
   831         for (int r = rowCount - 1; r >= 0; r--)
       
   832             if (!occupiedRows[r])
       
   833                 removeFreeRow(r);
       
   834         // remove columns
       
   835         for (int c = colCount - 1; c >= 0; c--)
       
   836             if (!occupiedColumns[c])
       
   837                 removeFreeColumn(c);
       
   838         return true;
       
   839     }
       
   840 
       
   841     void GridLayoutState::removeFreeRow(int removeRow)
       
   842     {
       
   843         const WidgetItemMap::iterator iend = widgetItemMap.end();
       
   844         for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) {
       
   845             const int r = it.value().y();
       
   846             Q_ASSERT(r != removeRow); // Free rows only
       
   847             if (r < removeRow) { // Does the item span it? - shrink it
       
   848                 const int rowSpan = it.value().height();
       
   849                 if (rowSpan > 1) {
       
   850                     const int bottomRow = r + rowSpan;
       
   851                     if (bottomRow > removeRow)
       
   852                         it.value().setHeight(rowSpan - 1);
       
   853                 }
       
   854             } else
       
   855                 if (r > removeRow) // Item below it? - move.
       
   856                     it.value().translate(0, -1);
       
   857         }
       
   858         rowCount--;
       
   859     }
       
   860 
       
   861     void GridLayoutState::removeFreeColumn(int removeColumn)
       
   862     {
       
   863         const WidgetItemMap::iterator iend = widgetItemMap.end();
       
   864         for (WidgetItemMap::iterator it = widgetItemMap.begin(); it != iend; ++it) {
       
   865             const int c = it.value().x();
       
   866             Q_ASSERT(c != removeColumn); // Free columns only
       
   867             if (c < removeColumn) { // Does the item span it? - shrink it
       
   868                 const int colSpan = it.value().width();
       
   869                 if (colSpan > 1) {
       
   870                     const int rightColumn = c + colSpan;
       
   871                     if (rightColumn > removeColumn)
       
   872                         it.value().setWidth(colSpan - 1);
       
   873                 }
       
   874             } else
       
   875                 if (c > removeColumn) // Item to the right of it?  - move.
       
   876                     it.value().translate(-1, 0);
       
   877         }
       
   878         colCount--;
       
   879     }
       
   880 
       
   881     // ---------------- GridLayoutHelper
       
   882     class GridLayoutHelper : public  LayoutHelper {
       
   883     public:
       
   884         GridLayoutHelper() {}
       
   885 
       
   886         virtual QRect itemInfo(QLayout *lt, int index) const;
       
   887         virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w);
       
   888         virtual void removeWidget(QLayout *lt, QWidget *widget);
       
   889         virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after);
       
   890 
       
   891         virtual void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout);
       
   892         virtual void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout);
       
   893 
       
   894         virtual bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const;
       
   895         virtual void simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea);
       
   896 
       
   897         static void insertRow(QGridLayout *grid, int row);
       
   898 
       
   899     private:
       
   900         QStack<GridLayoutState> m_states;
       
   901     };
       
   902 
       
   903     void GridLayoutHelper::insertRow(QGridLayout *grid, int row)
       
   904     {
       
   905         GridLayoutState state;
       
   906         state.fromLayout(grid);
       
   907         state.insertRow(row);
       
   908         QDesignerFormWindowInterface *fw = QDesignerFormWindowInterface::findFormWindow(grid);
       
   909         state.applyToLayout(fw->core(), grid->parentWidget());
       
   910     }
       
   911 
       
   912     QRect GridLayoutHelper::itemInfo(QLayout * lt, int index) const
       
   913     {
       
   914         QGridLayout *grid = qobject_cast<QGridLayout *>(lt);
       
   915         Q_ASSERT(grid);
       
   916         return gridItemInfo(grid, index);
       
   917     }
       
   918 
       
   919     void GridLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
       
   920     {
       
   921         QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
       
   922         QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt);
       
   923         Q_ASSERT(gridLayout);
       
   924         // check if there are any items. Should be only spacers, else something is wrong
       
   925         const int row = info.y();
       
   926         int column = info.x();
       
   927         int colSpan = info.width();
       
   928         int rowSpan = info.height();
       
   929         // If not empty: A multiselection was dropped on an empty item, insert row
       
   930         // and spread items along new row
       
   931         if (!removeEmptyCellsOnGrid(gridLayout, info)) {
       
   932             int freeColumn = -1;
       
   933             colSpan = rowSpan = 1;
       
   934             // First look to the right for a free column
       
   935             const int columnCount = gridLayout->columnCount();
       
   936             for (int c = column; c <  columnCount; c++) {
       
   937                 const int idx = findGridItemAt(gridLayout, row, c);
       
   938                 if (idx != -1 && LayoutInfo::isEmptyItem(gridLayout->itemAt(idx))) {
       
   939                     freeColumn = c;
       
   940                     break;
       
   941                 }
       
   942             }
       
   943             if (freeColumn != -1) {
       
   944                 removeEmptyCellsOnGrid(gridLayout, QRect(freeColumn, row, 1, 1));
       
   945                 column = freeColumn;
       
   946             } else {
       
   947                 GridLayoutHelper::insertRow(gridLayout, row);
       
   948                 column = 0;
       
   949             }
       
   950         }
       
   951         gridLayout->addWidget(w, row , column, rowSpan, colSpan);
       
   952     }
       
   953 
       
   954     void GridLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
       
   955     {
       
   956         QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt);
       
   957         Q_ASSERT(gridLayout);
       
   958         const int index = gridLayout->indexOf(widget);
       
   959         if (index == -1) {
       
   960             qWarning() << "GridLayoutHelper::removeWidget : Attempt to remove " << widget <<  " which is not in the layout.";
       
   961             return;
       
   962         }
       
   963         // delete old item and pad with  by spacer items
       
   964         int row, column, rowspan, colspan;
       
   965         gridLayout->getItemPosition(index, &row, &column, &rowspan, &colspan);
       
   966         delete gridLayout->takeAt(index);
       
   967         const int rightColumn = column + colspan;
       
   968         const int bottomRow = row +  rowspan;
       
   969         for (int c = column; c < rightColumn; c++)
       
   970             for (int r = row; r < bottomRow; r++)
       
   971                 gridLayout->addItem(createGridSpacer(), r, c);
       
   972     }
       
   973 
       
   974     void GridLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
       
   975     {
       
   976         bool ok = false;
       
   977         QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
       
   978         if (QGridLayout *gridLayout = qobject_cast<QGridLayout *>(lt)) {
       
   979             const int index = gridLayout->indexOf(before);
       
   980             if (index != -1) {
       
   981                 int row, column, rowSpan, columnSpan;
       
   982                 gridLayout->getItemPosition (index,  &row, &column, &rowSpan, &columnSpan);
       
   983                 const bool visible = before->isVisible();
       
   984                 delete gridLayout->takeAt(index);
       
   985                 if (visible)
       
   986                     before->hide();
       
   987                 before->setParent(0);
       
   988                 gridLayout->addWidget(after, row, column, rowSpan, columnSpan);
       
   989                 ok = true;
       
   990             }
       
   991         }
       
   992         if (!ok)
       
   993             qWarning() << "GridLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
       
   994     }
       
   995 
       
   996     void GridLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout)
       
   997     {
       
   998         QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
       
   999         Q_ASSERT(gridLayout);
       
  1000         GridLayoutState gs;
       
  1001         gs.fromLayout(gridLayout);
       
  1002         m_states.push(gs);
       
  1003     }
       
  1004 
       
  1005     void GridLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout)
       
  1006     {
       
  1007         Q_ASSERT(!m_states.empty());
       
  1008         const GridLayoutState state = m_states.pop();
       
  1009         state.applyToLayout(core, widgetWithManagedLayout);
       
  1010     }
       
  1011 
       
  1012     bool GridLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const
       
  1013     {
       
  1014         QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
       
  1015         Q_ASSERT(gridLayout);
       
  1016         GridLayoutState gs;
       
  1017         gs.fromLayout(gridLayout);
       
  1018         return gs.simplify(restrictionArea, true);
       
  1019     }
       
  1020 
       
  1021     void GridLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea)
       
  1022     {
       
  1023         QGridLayout *gridLayout = qobject_cast<QGridLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
       
  1024         Q_ASSERT(gridLayout);
       
  1025         if (debugLayout)
       
  1026             qDebug() << ">GridLayoutHelper::simplify" <<  *gridLayout;
       
  1027         GridLayoutState gs;
       
  1028         gs.fromLayout(gridLayout);
       
  1029         if (gs.simplify(restrictionArea, false))
       
  1030             gs.applyToLayout(core, widgetWithManagedLayout);
       
  1031         if (debugLayout)
       
  1032             qDebug() << "<GridLayoutHelper::simplify" <<  *gridLayout;
       
  1033    }
       
  1034 
       
  1035     // ---------------- FormLayoutHelper
       
  1036     class FormLayoutHelper : public  LayoutHelper {
       
  1037     public:
       
  1038         typedef QPair<QWidget *, QWidget *> WidgetPair;
       
  1039         typedef QVector<WidgetPair> FormLayoutState;
       
  1040 
       
  1041         FormLayoutHelper() {}
       
  1042 
       
  1043         virtual QRect itemInfo(QLayout *lt, int index) const;
       
  1044         virtual void insertWidget(QLayout *lt, const QRect &info, QWidget *w);
       
  1045         virtual void removeWidget(QLayout *lt, QWidget *widget);
       
  1046         virtual void replaceWidget(QLayout *lt, QWidget *before, QWidget *after);
       
  1047 
       
  1048         virtual void pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout);
       
  1049         virtual void popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout);
       
  1050 
       
  1051         virtual bool canSimplify(const QDesignerFormEditorInterface *core, const QWidget *, const QRect &) const;
       
  1052         virtual void simplify(const QDesignerFormEditorInterface *, QWidget *, const QRect &);
       
  1053 
       
  1054     private:
       
  1055         static FormLayoutState state(const QFormLayout *lt);
       
  1056 
       
  1057         QStack<FormLayoutState> m_states;
       
  1058     };
       
  1059 
       
  1060     QRect FormLayoutHelper::itemInfo(QLayout * lt, int index) const
       
  1061     {
       
  1062         QFormLayout *form = qobject_cast<QFormLayout *>(lt);
       
  1063         Q_ASSERT(form);
       
  1064         int row, column, colspan;
       
  1065         getFormLayoutItemPosition(form, index, &row, &column, 0, &colspan);
       
  1066         return QRect(column, row, colspan, 1);
       
  1067     }
       
  1068 
       
  1069     void FormLayoutHelper::insertWidget(QLayout *lt, const QRect &info, QWidget *w)
       
  1070     {
       
  1071         if (debugLayout)
       
  1072             qDebug() << "FormLayoutHelper::insertWidget:" << w << info;
       
  1073         QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
       
  1074         QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt);
       
  1075         Q_ASSERT(formLayout);
       
  1076         // check if there are any nonspacer items? (Drop on 3rd column or drop of a multiselection
       
  1077         // on an empty item. As the Form layout does not have insert semantics; we need to manually insert a row
       
  1078         const bool insert = !removeEmptyCellsOnGrid(formLayout, info);
       
  1079         formLayoutAddWidget(formLayout, w, info, insert);
       
  1080         QLayoutSupport::createEmptyCells(formLayout);
       
  1081     }
       
  1082 
       
  1083     void FormLayoutHelper::removeWidget(QLayout *lt, QWidget *widget)
       
  1084     {
       
  1085         QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt);
       
  1086         Q_ASSERT(formLayout);
       
  1087         const int index = formLayout->indexOf(widget);
       
  1088         if (index == -1) {
       
  1089             qWarning() << "FormLayoutHelper::removeWidget : Attempt to remove " << widget <<  " which is not in the layout.";
       
  1090             return;
       
  1091         }
       
  1092         // delete old item and pad with  by spacer items
       
  1093         int row, column, colspan;
       
  1094         getFormLayoutItemPosition(formLayout, index, &row, &column, 0, &colspan);
       
  1095         if (debugLayout)
       
  1096             qDebug() << "FormLayoutHelper::removeWidget: #" << index << widget << " at " << row << column <<  colspan;
       
  1097         delete formLayout->takeAt(index);
       
  1098         if (colspan > 1 || column == 0)
       
  1099             formLayout->setItem(row, QFormLayout::LabelRole, createFormSpacer());
       
  1100         if (colspan > 1 || column == 1)
       
  1101             formLayout->setItem(row, QFormLayout::FieldRole, createFormSpacer());
       
  1102     }
       
  1103 
       
  1104     void FormLayoutHelper::replaceWidget(QLayout *lt, QWidget *before, QWidget *after)
       
  1105     {
       
  1106         bool ok = false;
       
  1107         QDesignerWidgetItemInstaller wii; // Make sure we use QDesignerWidgetItem.
       
  1108         if (QFormLayout *formLayout = qobject_cast<QFormLayout *>(lt)) {
       
  1109             const int index = formLayout->indexOf(before);
       
  1110             if (index != -1) {
       
  1111                 int row;
       
  1112                 QFormLayout::ItemRole role;
       
  1113                 formLayout->getItemPosition (index, &row, &role);
       
  1114                 const bool visible = before->isVisible();
       
  1115                 delete formLayout->takeAt(index);
       
  1116                 if (visible)
       
  1117                     before->hide();
       
  1118                 before->setParent(0);
       
  1119                 formLayout->setWidget(row, role, after);
       
  1120                 ok = true;
       
  1121             }
       
  1122         }
       
  1123         if (!ok)
       
  1124             qWarning() << "FormLayoutHelper::replaceWidget : Unable to replace " << before << " by " << after << " in " << lt;
       
  1125     }
       
  1126 
       
  1127     FormLayoutHelper::FormLayoutState FormLayoutHelper::state(const QFormLayout *lt)
       
  1128     {
       
  1129         const int rowCount = lt->rowCount();
       
  1130         if (rowCount == 0)
       
  1131             return FormLayoutState();
       
  1132         FormLayoutState rc(rowCount, WidgetPair(0, 0));
       
  1133         const int count = lt->count();
       
  1134         int row, column, colspan;
       
  1135         for (int i = 0; i < count; i++) {
       
  1136             QLayoutItem *item = lt->itemAt(i);
       
  1137             if (!LayoutInfo::isEmptyItem(item)) {
       
  1138                 QWidget *w = item->widget();
       
  1139                 Q_ASSERT(w);
       
  1140                 getFormLayoutItemPosition(lt, i, &row, &column, 0, &colspan);
       
  1141                 if (colspan > 1 || column == 0)
       
  1142                     rc[row].first = w;
       
  1143                 if (colspan > 1 || column == 1)
       
  1144                     rc[row].second = w;
       
  1145             }
       
  1146         }
       
  1147         if (debugLayout) {
       
  1148             qDebug() << "FormLayoutHelper::state: " << rowCount;
       
  1149             for (int r = 0; r < rowCount; r++)
       
  1150                 qDebug() << "  Row: " << r << rc[r].first << rc[r].second;
       
  1151         }
       
  1152         return rc;
       
  1153     }
       
  1154 
       
  1155     void FormLayoutHelper::pushState(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout)
       
  1156     {
       
  1157         QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
       
  1158         Q_ASSERT(formLayout);
       
  1159         m_states.push(state(formLayout));
       
  1160     }
       
  1161 
       
  1162     void FormLayoutHelper::popState(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout)
       
  1163     {
       
  1164         QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
       
  1165         Q_ASSERT(!m_states.empty() && formLayout);
       
  1166 
       
  1167         const FormLayoutState storedState = m_states.pop();
       
  1168         const FormLayoutState currentState =  state(formLayout);
       
  1169         if (currentState ==  storedState)
       
  1170             return;
       
  1171         const int rowCount = storedState.size();
       
  1172         // clear out, shrink if required, but maintain items via map, pad spacers
       
  1173         const BoxLayoutHelper::LayoutItemVector items = BoxLayoutHelper::disassembleLayout(formLayout);
       
  1174         if (rowCount < formLayout->rowCount())
       
  1175             formLayout = static_cast<QFormLayout*>(recreateManagedLayout(core, widgetWithManagedLayout, formLayout ));
       
  1176         for (int r = 0; r < rowCount; r++) {
       
  1177             QWidget *widgets[FormLayoutColumns] = { storedState[r].first, storedState[r].second };
       
  1178             const bool spanning = widgets[0] != 0 && widgets[0] == widgets[1];
       
  1179             if (spanning) {
       
  1180                 formLayout->setWidget(r, QFormLayout::SpanningRole, widgets[0]);
       
  1181             } else {
       
  1182                 for (int c = 0; c < FormLayoutColumns; c++) {
       
  1183                     const QFormLayout::ItemRole role = c == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole;
       
  1184                     if (widgets[c]) {
       
  1185                         Q_ASSERT(BoxLayoutHelper::findItemOfWidget(items, widgets[c]));
       
  1186                         formLayout->setWidget(r, role, widgets[c]);
       
  1187                     } else {
       
  1188                         formLayout->setItem(r, role, createFormSpacer());
       
  1189                     }
       
  1190                 }
       
  1191             }
       
  1192         }
       
  1193     }
       
  1194 
       
  1195     bool FormLayoutHelper::canSimplify(const QDesignerFormEditorInterface *core, const QWidget *widgetWithManagedLayout, const QRect &restrictionArea) const
       
  1196     {
       
  1197         const QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
       
  1198         Q_ASSERT(formLayout);
       
  1199         return canSimplifyFormLayout(formLayout, restrictionArea);
       
  1200     }
       
  1201 
       
  1202     void FormLayoutHelper::simplify(const QDesignerFormEditorInterface *core, QWidget *widgetWithManagedLayout, const QRect &restrictionArea)
       
  1203     {
       
  1204         typedef QPair<QLayoutItem*, QLayoutItem*> LayoutItemPair;
       
  1205         typedef QVector<LayoutItemPair> LayoutItemPairs;
       
  1206 
       
  1207         QFormLayout *formLayout = qobject_cast<QFormLayout *>(LayoutInfo::managedLayout(core, widgetWithManagedLayout));
       
  1208         Q_ASSERT(formLayout);
       
  1209         if (debugLayout)
       
  1210             qDebug() << "FormLayoutHelper::simplify";
       
  1211         // Transform into vector of item pairs
       
  1212         const int rowCount = formLayout->rowCount();
       
  1213         LayoutItemPairs pairs(rowCount, LayoutItemPair(0, 0));
       
  1214         for (int i =  formLayout->count() - 1; i >= 0; i--) {
       
  1215             int row, col,colspan;
       
  1216             getFormLayoutItemPosition(formLayout, i, &row, &col, 0, &colspan);
       
  1217             if (colspan > 1) {
       
  1218                  pairs[row].first = pairs[row].second = formLayout->takeAt(i);
       
  1219             } else {
       
  1220                 if (col == 0)
       
  1221                     pairs[row].first = formLayout->takeAt(i);
       
  1222                 else
       
  1223                     pairs[row].second = formLayout->takeAt(i);
       
  1224             }
       
  1225         }
       
  1226         // Weed out empty ones
       
  1227         const int bottomCheckRow = qMin(rowCount, restrictionArea.y() + restrictionArea.height());
       
  1228         for (int r = bottomCheckRow - 1; r >= restrictionArea.y(); r--)
       
  1229             if (LayoutInfo::isEmptyItem(pairs[r].first) && LayoutInfo::isEmptyItem(pairs[r].second)) {
       
  1230                 delete pairs[r].first;
       
  1231                 delete pairs[r].second;
       
  1232                 pairs.remove(r);
       
  1233             }
       
  1234         const int simpleRowCount = pairs.size();
       
  1235         if (simpleRowCount < rowCount)
       
  1236             formLayout = static_cast<QFormLayout *>(recreateManagedLayout(core, widgetWithManagedLayout, formLayout));
       
  1237         // repopulate
       
  1238         for (int r = 0; r < simpleRowCount; r++) {
       
  1239             const bool spanning = pairs[r].first == pairs[r].second;
       
  1240             if (spanning) {
       
  1241                 formLayout->setItem(r, QFormLayout::SpanningRole, pairs[r].first);
       
  1242             } else {
       
  1243                 formLayout->setItem(r, QFormLayout::LabelRole, pairs[r].first);
       
  1244                 formLayout->setItem(r, QFormLayout::FieldRole, pairs[r].second);
       
  1245             }
       
  1246         }
       
  1247     }
       
  1248 
       
  1249 LayoutHelper *LayoutHelper::createLayoutHelper(int type)
       
  1250 {
       
  1251     LayoutHelper *rc = 0;
       
  1252     switch (type) {
       
  1253     case LayoutInfo::HBox:
       
  1254         rc = new BoxLayoutHelper(Qt::Horizontal);
       
  1255         break;
       
  1256     case LayoutInfo::VBox:
       
  1257         rc = new BoxLayoutHelper(Qt::Vertical);
       
  1258         break;
       
  1259     case LayoutInfo::Grid:
       
  1260         rc = new GridLayoutHelper;
       
  1261         break;
       
  1262     case LayoutInfo::Form:
       
  1263         return new FormLayoutHelper;
       
  1264      default:
       
  1265         break;
       
  1266     }
       
  1267     Q_ASSERT(rc);
       
  1268     return rc;
       
  1269 }
       
  1270 
       
  1271 // ---- QLayoutSupport (LayoutDecorationExtension)
       
  1272 QLayoutSupport::QLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent)  :
       
  1273       QObject(parent),
       
  1274       m_formWindow(formWindow),
       
  1275       m_helper(helper),
       
  1276       m_widget(widget),
       
  1277       m_currentIndex(-1),
       
  1278       m_currentInsertMode(QDesignerLayoutDecorationExtension::InsertWidgetMode)
       
  1279 {
       
  1280 }
       
  1281 
       
  1282 QLayout * QLayoutSupport::layout() const
       
  1283 {
       
  1284     return LayoutInfo::managedLayout(m_formWindow->core(), m_widget);
       
  1285 }
       
  1286 
       
  1287 void QLayoutSupport::hideIndicator(Indicator i)
       
  1288 {
       
  1289     if (m_indicators[i])
       
  1290         m_indicators[i]->hide();
       
  1291 }
       
  1292 
       
  1293 void QLayoutSupport::showIndicator(Indicator i, const QRect &geometry, const QPalette &p)
       
  1294 {
       
  1295     if (!m_indicators[i])
       
  1296         m_indicators[i] = new qdesigner_internal::InvisibleWidget(m_widget);
       
  1297     QWidget *indicator = m_indicators[i];
       
  1298     indicator->setAutoFillBackground(true);
       
  1299     indicator->setPalette(p);
       
  1300     indicator->setGeometry(geometry);
       
  1301     indicator->show();
       
  1302     indicator->raise();
       
  1303 }
       
  1304 
       
  1305 QLayoutSupport::~QLayoutSupport()
       
  1306 {
       
  1307     delete m_helper;
       
  1308     for (int i = 0; i < NumIndicators; i++)
       
  1309         if (m_indicators[i])
       
  1310             m_indicators[i]->deleteLater();
       
  1311 }
       
  1312 
       
  1313 QGridLayout * QLayoutSupport::gridLayout() const
       
  1314 {
       
  1315     return qobject_cast<QGridLayout*>(LayoutInfo::managedLayout(m_formWindow->core(), m_widget));
       
  1316 }
       
  1317 
       
  1318 QRect QLayoutSupport::itemInfo(int index) const
       
  1319 {
       
  1320     return m_helper->itemInfo(LayoutInfo::managedLayout(m_formWindow->core(), m_widget), index);
       
  1321 }
       
  1322 
       
  1323 void QLayoutSupport::setInsertMode(InsertMode im)
       
  1324 {
       
  1325     m_currentInsertMode = im;
       
  1326 }
       
  1327 
       
  1328 void QLayoutSupport::setCurrentCell(const QPair<int, int> &cell)
       
  1329 {
       
  1330     m_currentCell = cell;
       
  1331 }
       
  1332 
       
  1333 void QLayoutSupport::adjustIndicator(const QPoint &pos, int index)
       
  1334 {
       
  1335     if (index == -1) { // first item goes anywhere
       
  1336         hideIndicator(LeftIndicator);
       
  1337         hideIndicator(TopIndicator);
       
  1338         hideIndicator(RightIndicator);
       
  1339         hideIndicator(BottomIndicator);
       
  1340         return;
       
  1341     }
       
  1342     m_currentIndex = index;
       
  1343     m_currentInsertMode = QDesignerLayoutDecorationExtension::InsertWidgetMode;
       
  1344 
       
  1345     QLayoutItem *item = layout()->itemAt(index);
       
  1346     const QRect g = extendedGeometry(index);
       
  1347     // ### cleanup
       
  1348     if (LayoutInfo::isEmptyItem(item)) {
       
  1349         // Empty grid/form cell. Draw a rectangle
       
  1350         QPalette redPalette;
       
  1351         redPalette.setColor(QPalette::Window, Qt::red);
       
  1352 
       
  1353         showIndicator(LeftIndicator,   QRect(g.x(),     g.y(),      indicatorSize, g.height()), redPalette);
       
  1354         showIndicator(TopIndicator,    QRect(g.x(),     g.y(),      g.width(),     indicatorSize), redPalette);
       
  1355         showIndicator(RightIndicator,  QRect(g.right(), g.y(),      indicatorSize, g.height()), redPalette);
       
  1356         showIndicator(BottomIndicator, QRect(g.x(),     g.bottom(), g.width(),     indicatorSize), redPalette);
       
  1357         setCurrentCellFromIndicatorOnEmptyCell(m_currentIndex);
       
  1358     } else {
       
  1359         // Append/Insert. Draw a bar left/right or above/below
       
  1360         QPalette bluePalette;
       
  1361         bluePalette.setColor(QPalette::Window, Qt::blue);
       
  1362         hideIndicator(LeftIndicator);
       
  1363         hideIndicator(TopIndicator);
       
  1364 
       
  1365         const int fromRight = g.right() - pos.x();
       
  1366         const int fromBottom = g.bottom() - pos.y();
       
  1367 
       
  1368         const int fromLeft = pos.x() - g.x();
       
  1369         const int fromTop = pos.y() - g.y();
       
  1370 
       
  1371         const int fromLeftRight = qMin(fromRight, fromLeft );
       
  1372         const int fromBottomTop = qMin(fromBottom, fromTop);
       
  1373 
       
  1374         const Qt::Orientation indicatorOrientation =  fromLeftRight < fromBottomTop ? Qt::Vertical :  Qt::Horizontal;
       
  1375 
       
  1376         if (supportsIndicatorOrientation(indicatorOrientation)) {
       
  1377             const QRect r(layout()->geometry().topLeft(), layout()->parentWidget()->size());
       
  1378             switch (indicatorOrientation) {
       
  1379             case  Qt::Vertical: {
       
  1380                 hideIndicator(BottomIndicator);
       
  1381                 const bool closeToLeft = fromLeftRight == fromLeft;
       
  1382                 showIndicator(RightIndicator, QRect(closeToLeft ? g.x() : g.right() + 1 - indicatorSize, 0, indicatorSize, r.height()), bluePalette);
       
  1383 
       
  1384                 const int incr = closeToLeft ? 0 : +1;
       
  1385                 setCurrentCellFromIndicator(indicatorOrientation, m_currentIndex, incr);
       
  1386             }
       
  1387             break;
       
  1388             case  Qt::Horizontal: {
       
  1389                 hideIndicator(RightIndicator);
       
  1390                 const bool closeToTop = fromBottomTop == fromTop;
       
  1391                 showIndicator(BottomIndicator, QRect(r.x(), closeToTop ? g.y() : g.bottom() + 1 - indicatorSize, r.width(), indicatorSize), bluePalette);
       
  1392 
       
  1393                 const int incr = closeToTop ? 0 : +1;
       
  1394                 setCurrentCellFromIndicator(indicatorOrientation, m_currentIndex, incr);
       
  1395             }
       
  1396                 break;
       
  1397             }
       
  1398         } else {
       
  1399             hideIndicator(RightIndicator);
       
  1400             hideIndicator(BottomIndicator);
       
  1401         } // can handle indicatorOrientation
       
  1402     }
       
  1403 }
       
  1404 
       
  1405 int QLayoutSupport::indexOf(QLayoutItem *i) const
       
  1406 {
       
  1407     const QLayout *lt = layout();
       
  1408     if (!lt)
       
  1409         return -1;
       
  1410 
       
  1411     int index = 0;
       
  1412 
       
  1413     while (QLayoutItem *item = lt->itemAt(index)) {
       
  1414         if (item == i)
       
  1415             return index;
       
  1416 
       
  1417         ++index;
       
  1418     }
       
  1419 
       
  1420     return -1;
       
  1421 }
       
  1422 
       
  1423 int QLayoutSupport::indexOf(QWidget *widget) const
       
  1424 {
       
  1425     const QLayout *lt = layout();
       
  1426     if (!lt)
       
  1427         return -1;
       
  1428 
       
  1429     int index = 0;
       
  1430     while (QLayoutItem *item = lt->itemAt(index)) {
       
  1431         if (item->widget() == widget)
       
  1432             return index;
       
  1433 
       
  1434         ++index;
       
  1435     }
       
  1436 
       
  1437     return -1;
       
  1438 }
       
  1439 
       
  1440 QList<QWidget*> QLayoutSupport::widgets(QLayout *layout) const
       
  1441 {
       
  1442     if (!layout)
       
  1443         return QList<QWidget*>();
       
  1444 
       
  1445     QList<QWidget*> lst;
       
  1446     int index = 0;
       
  1447     while (QLayoutItem *item = layout->itemAt(index)) {
       
  1448         ++index;
       
  1449 
       
  1450         QWidget *widget = item->widget();
       
  1451         if (widget && formWindow()->isManaged(widget))
       
  1452             lst.append(widget);
       
  1453     }
       
  1454 
       
  1455     return lst;
       
  1456 }
       
  1457 
       
  1458 int QLayoutSupport::findItemAt(QGridLayout *gridLayout, int at_row, int at_column)
       
  1459 {
       
  1460     return findGridItemAt(gridLayout, at_row, at_column);
       
  1461 }
       
  1462 
       
  1463 // Quick check whether simplify should be enabled for grids. May return false positives.
       
  1464 // Note: Calculating the occupied area does not work as spanning items may also be simplified.
       
  1465 
       
  1466 bool QLayoutSupport::canSimplifyQuickCheck(const QGridLayout *gl)
       
  1467 {
       
  1468     if (!gl)
       
  1469         return false;
       
  1470     const int colCount = gl->columnCount();
       
  1471     const int rowCount = gl->rowCount();
       
  1472     if (colCount < 2 || rowCount < 2)
       
  1473         return false;
       
  1474     // try to find a spacer.
       
  1475     const int count = gl->count();
       
  1476     for (int index = 0; index < count; index++)
       
  1477         if (LayoutInfo::isEmptyItem(gl->itemAt(index)))
       
  1478             return true;
       
  1479     return false;
       
  1480 }
       
  1481 
       
  1482 bool QLayoutSupport::canSimplifyQuickCheck(const QFormLayout *fl)
       
  1483 {
       
  1484     return canSimplifyFormLayout(fl, QRect(QPoint(0, 0), QSize(32767, 32767)));
       
  1485 }
       
  1486 
       
  1487 // remove dummy spacers
       
  1488 bool QLayoutSupport::removeEmptyCells(QGridLayout *grid, const QRect &area)
       
  1489 {
       
  1490     return removeEmptyCellsOnGrid(grid, area);
       
  1491 }
       
  1492 
       
  1493 void QLayoutSupport::createEmptyCells(QGridLayout *gridLayout)
       
  1494 {
       
  1495     Q_ASSERT(gridLayout);
       
  1496     GridLayoutState gs;
       
  1497     gs.fromLayout(gridLayout);
       
  1498 
       
  1499     const GridLayoutState::CellStates cs = GridLayoutState::cellStates(gs.widgetItemMap.values(), gs.rowCount, gs.colCount);
       
  1500     for (int c = 0; c < gs.colCount; c++)
       
  1501         for (int r = 0; r < gs.rowCount; r++)
       
  1502             if (needsSpacerItem(cs[r * gs.colCount + c])) {
       
  1503                 const int existingItemIndex = findItemAt(gridLayout, r, c);
       
  1504                 if (existingItemIndex == -1)
       
  1505                     gridLayout->addItem(createGridSpacer(), r, c);
       
  1506             }
       
  1507 }
       
  1508 
       
  1509 bool QLayoutSupport::removeEmptyCells(QFormLayout *formLayout, const QRect &area)
       
  1510 {
       
  1511     return removeEmptyCellsOnGrid(formLayout, area);
       
  1512 }
       
  1513 
       
  1514 void QLayoutSupport::createEmptyCells(QFormLayout *formLayout)
       
  1515 {
       
  1516     // No spanning items here..
       
  1517     if (const int rowCount = formLayout->rowCount())
       
  1518         for (int c = 0; c < FormLayoutColumns; c++)
       
  1519             for (int r = 0; r < rowCount; r++)
       
  1520                 if (findGridItemAt(formLayout, r, c) == -1)
       
  1521                     formLayout->setItem(r, c == 0 ? QFormLayout::LabelRole : QFormLayout::FieldRole, createFormSpacer());
       
  1522 }
       
  1523 
       
  1524 int QLayoutSupport::findItemAt(const QPoint &pos) const
       
  1525 {
       
  1526     if (!layout())
       
  1527         return -1;
       
  1528 
       
  1529     const QLayout *lt = layout();
       
  1530     const int count = lt->count();
       
  1531 
       
  1532     if (count == 0)
       
  1533         return -1;
       
  1534 
       
  1535     int best = -1;
       
  1536     int bestIndex = -1;
       
  1537 
       
  1538     for (int index = 0;  index < count;  index++) {
       
  1539         QLayoutItem *item = lt->itemAt(index);
       
  1540         bool visible = true;
       
  1541         // When dragging widgets within layout, the source widget is invisible and must not be hit
       
  1542         if (const QWidget *w = item->widget())
       
  1543             visible = w->isVisible();
       
  1544         if (visible) {
       
  1545             const QRect g = item->geometry();
       
  1546 
       
  1547             const int dist = (g.center() - pos).manhattanLength();
       
  1548             if (best == -1 || dist < best) {
       
  1549                 best = dist;
       
  1550                 bestIndex = index;
       
  1551             }
       
  1552         }
       
  1553     }
       
  1554     return bestIndex;
       
  1555 }
       
  1556 
       
  1557 // ------------ QBoxLayoutSupport (LayoutDecorationExtension)
       
  1558 namespace {
       
  1559 class QBoxLayoutSupport: public QLayoutSupport
       
  1560 {
       
  1561 public:
       
  1562     QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent = 0);
       
  1563 
       
  1564     virtual void insertWidget(QWidget *widget, const QPair<int, int> &cell);
       
  1565     virtual void removeWidget(QWidget *widget);
       
  1566     virtual void simplify() {}
       
  1567     virtual void insertRow(int /*row*/) {}
       
  1568     virtual void insertColumn(int /*column*/) {}
       
  1569 
       
  1570     virtual int findItemAt(int /*at_row*/, int /*at_column*/) const {    return -1; }
       
  1571 
       
  1572 private:
       
  1573     virtual void setCurrentCellFromIndicatorOnEmptyCell(int index);
       
  1574     virtual void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment);
       
  1575     virtual bool supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const;
       
  1576     virtual QRect extendedGeometry(int index) const;
       
  1577 
       
  1578     const Qt::Orientation m_orientation;
       
  1579 };
       
  1580 
       
  1581 void QBoxLayoutSupport::removeWidget(QWidget *widget)
       
  1582 {
       
  1583     QLayout *lt = layout();
       
  1584     const int index = lt->indexOf(widget);
       
  1585     // Adjust the current cell in case a widget was dragged within the same layout to a position
       
  1586     // of higher index, which happens as follows:
       
  1587     // Drag start: The widget is hidden
       
  1588     // Drop: Current cell is stored, widget is removed and re-added, causing an index offset that needs to be compensated
       
  1589     QPair<int, int> currCell = currentCell();
       
  1590     switch (m_orientation) {
       
  1591     case Qt::Horizontal:
       
  1592         if (currCell.second > 0 && index < currCell.second ) {
       
  1593             currCell.second--;
       
  1594             setCurrentCell(currCell);
       
  1595         }
       
  1596         break;
       
  1597     case Qt::Vertical:
       
  1598         if (currCell.first > 0 && index < currCell.first) {
       
  1599             currCell.first--;
       
  1600             setCurrentCell(currCell);
       
  1601         }
       
  1602         break;
       
  1603     }
       
  1604     helper()->removeWidget(lt, widget);
       
  1605 }
       
  1606 
       
  1607 QBoxLayoutSupport::QBoxLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, Qt::Orientation orientation, QObject *parent) :
       
  1608     QLayoutSupport(formWindow, widget, new BoxLayoutHelper(orientation), parent),
       
  1609     m_orientation(orientation)
       
  1610 {
       
  1611 }
       
  1612 
       
  1613 void QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(int index)
       
  1614 {
       
  1615     qDebug() << "QBoxLayoutSupport::setCurrentCellFromIndicatorOnEmptyCell(): Warning: found a fake spacer inside a vbox layout at " << index;
       
  1616     setCurrentCell(qMakePair(0, 0));
       
  1617 }
       
  1618 
       
  1619 void QBoxLayoutSupport::insertWidget(QWidget *widget, const QPair<int, int> &cell)
       
  1620 {
       
  1621     switch (m_orientation) {
       
  1622     case  Qt::Horizontal:
       
  1623         helper()->insertWidget(layout(), QRect(cell.second, 0, 1, 1), widget);
       
  1624         break;
       
  1625     case  Qt::Vertical:
       
  1626         helper()->insertWidget(layout(), QRect(0, cell.first, 1, 1), widget);
       
  1627         break;
       
  1628     }
       
  1629 }
       
  1630 
       
  1631 void QBoxLayoutSupport::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment)
       
  1632 {
       
  1633     if (m_orientation == Qt::Horizontal && indicatorOrientation == Qt::Vertical) {
       
  1634         setCurrentCell(qMakePair(0, index + increment));
       
  1635     } else if (m_orientation == Qt::Vertical && indicatorOrientation == Qt::Horizontal) {
       
  1636         setCurrentCell(qMakePair(index + increment, 0));
       
  1637     }
       
  1638 }
       
  1639 
       
  1640 bool QBoxLayoutSupport::supportsIndicatorOrientation(Qt::Orientation indicatorOrientation) const
       
  1641 {
       
  1642     return m_orientation != indicatorOrientation;
       
  1643 }
       
  1644 
       
  1645 QRect QBoxLayoutSupport::extendedGeometry(int index) const
       
  1646 {
       
  1647     QLayoutItem *item = layout()->itemAt(index);
       
  1648     // start off with item geometry
       
  1649     QRect g = item->geometry();
       
  1650 
       
  1651     const QRect info = itemInfo(index);
       
  1652 
       
  1653     // On left border: extend to widget border
       
  1654     if (info.x() == 0) {
       
  1655         QPoint topLeft = g.topLeft();
       
  1656         topLeft.rx() = layout()->geometry().left();
       
  1657         g.setTopLeft(topLeft);
       
  1658     }
       
  1659 
       
  1660     // On top border: extend to widget border
       
  1661     if (info.y() == 0) {
       
  1662         QPoint topLeft = g.topLeft();
       
  1663         topLeft.ry() = layout()->geometry().top();
       
  1664         g.setTopLeft(topLeft);
       
  1665     }
       
  1666 
       
  1667     // is this the last item?
       
  1668     const QBoxLayout *box = static_cast<const QBoxLayout*>(layout());
       
  1669     if (index < box->count() -1)
       
  1670         return g; // Nope.
       
  1671 
       
  1672     // extend to widget border
       
  1673     QPoint bottomRight = g.bottomRight();
       
  1674     switch (m_orientation) {
       
  1675     case Qt::Vertical:
       
  1676         bottomRight.ry() = layout()->geometry().bottom();
       
  1677         break;
       
  1678     case Qt::Horizontal:
       
  1679         bottomRight.rx() = layout()->geometry().right();
       
  1680         break;
       
  1681     }
       
  1682     g.setBottomRight(bottomRight);
       
  1683     return g;
       
  1684 }
       
  1685 
       
  1686 // --------------  Base class for QGridLayout-like support classes (LayoutDecorationExtension)
       
  1687 template <class GridLikeLayout>
       
  1688 class GridLikeLayoutSupportBase: public QLayoutSupport
       
  1689 {
       
  1690 public:
       
  1691 
       
  1692     GridLikeLayoutSupportBase(QDesignerFormWindowInterface *formWindow, QWidget *widget, LayoutHelper *helper, QObject *parent = 0) :
       
  1693         QLayoutSupport(formWindow, widget, helper, parent) {}
       
  1694 
       
  1695     void insertWidget(QWidget *widget, const QPair<int, int> &cell);
       
  1696     virtual void removeWidget(QWidget *widget) { helper()->removeWidget(layout(), widget); }
       
  1697     virtual int findItemAt(int row, int column) const;
       
  1698 
       
  1699 protected:
       
  1700     GridLikeLayout *gridLikeLayout() const {
       
  1701         return qobject_cast<GridLikeLayout*>(LayoutInfo::managedLayout(formWindow()->core(), widget()));
       
  1702     }
       
  1703 
       
  1704 private:
       
  1705 
       
  1706     virtual void setCurrentCellFromIndicatorOnEmptyCell(int index);
       
  1707     virtual void setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment);
       
  1708     virtual bool supportsIndicatorOrientation(Qt::Orientation) const { return true; }
       
  1709 
       
  1710     virtual QRect extendedGeometry(int index) const;
       
  1711 
       
  1712     // Overwrite to check the insertion position (if there are limits)
       
  1713     virtual void checkCellForInsertion(int * /*row*/, int * /*col*/) const {}
       
  1714 };
       
  1715 
       
  1716 template <class GridLikeLayout>
       
  1717 void GridLikeLayoutSupportBase<GridLikeLayout>::setCurrentCellFromIndicatorOnEmptyCell(int index)
       
  1718 {
       
  1719     GridLikeLayout *grid = gridLikeLayout();
       
  1720     Q_ASSERT(grid);
       
  1721 
       
  1722     setInsertMode(InsertWidgetMode);
       
  1723     int row, column, rowspan, colspan;
       
  1724 
       
  1725     getGridItemPosition(grid, index, &row, &column, &rowspan, &colspan);
       
  1726     setCurrentCell(qMakePair(row, column));
       
  1727 }
       
  1728 
       
  1729 template <class GridLikeLayout>
       
  1730 void GridLikeLayoutSupportBase<GridLikeLayout>::setCurrentCellFromIndicator(Qt::Orientation indicatorOrientation, int index, int increment) {
       
  1731     const QRect info = itemInfo(index);
       
  1732     switch (indicatorOrientation) {
       
  1733     case Qt::Vertical: {
       
  1734         setInsertMode(InsertColumnMode);
       
  1735         int row = info.top();
       
  1736         int column = increment ? info.right() + 1 : info.left();
       
  1737         checkCellForInsertion(&row, &column);
       
  1738         setCurrentCell(qMakePair(row , column));
       
  1739     }
       
  1740         break;
       
  1741     case Qt::Horizontal: {
       
  1742         setInsertMode(InsertRowMode);
       
  1743         int row = increment ? info.bottom() + 1 : info.top();
       
  1744         int column = info.left();
       
  1745         checkCellForInsertion(&row, &column);
       
  1746         setCurrentCell(qMakePair(row, column));
       
  1747     }
       
  1748         break;
       
  1749     }
       
  1750 }
       
  1751 
       
  1752 template <class GridLikeLayout>
       
  1753 void GridLikeLayoutSupportBase<GridLikeLayout>::insertWidget(QWidget *widget, const QPair<int, int> &cell)
       
  1754 {
       
  1755     helper()->insertWidget(layout(), QRect(cell.second, cell.first, 1, 1), widget);
       
  1756 }
       
  1757 
       
  1758 template <class GridLikeLayout>
       
  1759 int GridLikeLayoutSupportBase<GridLikeLayout>::findItemAt(int at_row, int at_column) const
       
  1760 {
       
  1761     GridLikeLayout *grid = gridLikeLayout();
       
  1762     Q_ASSERT(grid);
       
  1763     return findGridItemAt(grid, at_row, at_column);
       
  1764 }
       
  1765 
       
  1766 template <class GridLikeLayout>
       
  1767 QRect GridLikeLayoutSupportBase<GridLikeLayout>::extendedGeometry(int index) const
       
  1768 {
       
  1769     QLayoutItem *item = layout()->itemAt(index);
       
  1770     // start off with item geometry
       
  1771     QRect g = item->geometry();
       
  1772 
       
  1773     const QRect info = itemInfo(index);
       
  1774 
       
  1775     // On left border: extend to widget border
       
  1776     if (info.x() == 0) {
       
  1777         QPoint topLeft = g.topLeft();
       
  1778         topLeft.rx() = layout()->geometry().left();
       
  1779         g.setTopLeft(topLeft);
       
  1780     }
       
  1781 
       
  1782     // On top border: extend to widget border
       
  1783     if (info.y() == 0) {
       
  1784         QPoint topLeft = g.topLeft();
       
  1785         topLeft.ry() = layout()->geometry().top();
       
  1786         g.setTopLeft(topLeft);
       
  1787     }
       
  1788     const GridLikeLayout *grid = gridLikeLayout();
       
  1789     Q_ASSERT(grid);
       
  1790 
       
  1791     // extend to widget border
       
  1792     QPoint bottomRight = g.bottomRight();
       
  1793     if (gridRowCount(grid) == info.y())
       
  1794         bottomRight.ry() = layout()->geometry().bottom();
       
  1795     if (gridColumnCount(grid) == info.x())
       
  1796         bottomRight.rx() = layout()->geometry().right();
       
  1797     g.setBottomRight(bottomRight);
       
  1798     return g;
       
  1799 }
       
  1800 
       
  1801 // --------------  QGridLayoutSupport (LayoutDecorationExtension)
       
  1802 class QGridLayoutSupport: public GridLikeLayoutSupportBase<QGridLayout>
       
  1803 {
       
  1804 public:
       
  1805 
       
  1806     QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = 0);
       
  1807 
       
  1808     virtual void simplify();
       
  1809     virtual void insertRow(int row);
       
  1810     virtual void insertColumn(int column);
       
  1811 
       
  1812 private:
       
  1813 };
       
  1814 
       
  1815 QGridLayoutSupport::QGridLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) :
       
  1816     GridLikeLayoutSupportBase<QGridLayout>(formWindow, widget, new GridLayoutHelper, parent)
       
  1817 {
       
  1818 }
       
  1819 
       
  1820 void QGridLayoutSupport::insertRow(int row)
       
  1821 {
       
  1822     QGridLayout *grid = gridLayout();
       
  1823     Q_ASSERT(grid);
       
  1824     GridLayoutHelper::insertRow(grid, row);
       
  1825 }
       
  1826 
       
  1827 void QGridLayoutSupport::insertColumn(int column)
       
  1828 {
       
  1829     QGridLayout *grid = gridLayout();
       
  1830     Q_ASSERT(grid);
       
  1831     GridLayoutState state;
       
  1832     state.fromLayout(grid);
       
  1833     state.insertColumn(column);
       
  1834     state.applyToLayout(formWindow()->core(), widget());
       
  1835 }
       
  1836 
       
  1837 void QGridLayoutSupport::simplify()
       
  1838 {
       
  1839     QGridLayout *grid = gridLayout();
       
  1840     Q_ASSERT(grid);
       
  1841     GridLayoutState state;
       
  1842     state.fromLayout(grid);
       
  1843 
       
  1844     const QRect fullArea = QRect(0, 0, state.colCount, state.rowCount);
       
  1845     if (state.simplify(fullArea, false))
       
  1846         state.applyToLayout(formWindow()->core(), widget());
       
  1847 }
       
  1848 
       
  1849 // --------------  QFormLayoutSupport (LayoutDecorationExtension)
       
  1850 class QFormLayoutSupport: public GridLikeLayoutSupportBase<QFormLayout>
       
  1851 {
       
  1852 public:
       
  1853     QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent = 0);
       
  1854 
       
  1855     virtual void simplify() {}
       
  1856     virtual void insertRow(int /*row*/) {}
       
  1857     virtual void insertColumn(int /*column*/) {}
       
  1858 
       
  1859 private:
       
  1860     virtual void checkCellForInsertion(int * row, int *col) const;
       
  1861 };
       
  1862 
       
  1863 QFormLayoutSupport::QFormLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent) :
       
  1864     GridLikeLayoutSupportBase<QFormLayout>(formWindow, widget, new FormLayoutHelper, parent)
       
  1865 {
       
  1866 }
       
  1867 
       
  1868 void QFormLayoutSupport::checkCellForInsertion(int *row, int *col) const
       
  1869 {
       
  1870     if (*col >= FormLayoutColumns) { // Clamp to 2 columns
       
  1871         *col = 1;
       
  1872         (*row)++;
       
  1873     }
       
  1874 }
       
  1875 } //  anonymous namespace
       
  1876 
       
  1877 QLayoutSupport *QLayoutSupport::createLayoutSupport(QDesignerFormWindowInterface *formWindow, QWidget *widget, QObject *parent)
       
  1878 {
       
  1879     const QLayout *layout = LayoutInfo::managedLayout(formWindow->core(), widget);
       
  1880     Q_ASSERT(layout);
       
  1881     QLayoutSupport *rc = 0;
       
  1882     switch (LayoutInfo::layoutType(formWindow->core(), layout)) {
       
  1883     case LayoutInfo::HBox:
       
  1884         rc = new QBoxLayoutSupport(formWindow, widget, Qt::Horizontal, parent);
       
  1885         break;
       
  1886     case LayoutInfo::VBox:
       
  1887         rc = new QBoxLayoutSupport(formWindow, widget, Qt::Vertical, parent);
       
  1888         break;
       
  1889     case LayoutInfo::Grid:
       
  1890         rc = new QGridLayoutSupport(formWindow, widget, parent);
       
  1891         break;
       
  1892     case LayoutInfo::Form:
       
  1893         rc = new QFormLayoutSupport(formWindow, widget, parent);
       
  1894         break;
       
  1895      default:
       
  1896         break;
       
  1897     }
       
  1898     Q_ASSERT(rc);
       
  1899     return rc;
       
  1900 }
       
  1901 } // namespace qdesigner_internal
       
  1902 
       
  1903 // -------------- QLayoutWidget
       
  1904 QLayoutWidget::QLayoutWidget(QDesignerFormWindowInterface *formWindow, QWidget *parent)
       
  1905     : QWidget(parent), m_formWindow(formWindow),
       
  1906       m_leftMargin(0), m_topMargin(0), m_rightMargin(0), m_bottomMargin(0)
       
  1907 {
       
  1908 }
       
  1909 
       
  1910 void QLayoutWidget::paintEvent(QPaintEvent*)
       
  1911 {
       
  1912     if (m_formWindow->currentTool() != 0)
       
  1913         return;
       
  1914 
       
  1915     // only draw red borders if we're editting widgets
       
  1916 
       
  1917     QPainter p(this);
       
  1918 
       
  1919     QMap<int, QMap<int, bool> > excludedRowsForColumn;
       
  1920     QMap<int, QMap<int, bool> > excludedColumnsForRow;
       
  1921 
       
  1922     QLayout *lt = layout();
       
  1923     QGridLayout *grid = qobject_cast<QGridLayout *>(lt);
       
  1924     if (lt) {
       
  1925         if (const int count = lt->count()) {
       
  1926             p.setPen(QPen(QColor(255, 0, 0, 35), 1));
       
  1927             for (int i = 0; i < count; i++) {
       
  1928                 QLayoutItem *item = lt->itemAt(i);
       
  1929                 if (grid) {
       
  1930                     int row, column, rowSpan, columnSpan;
       
  1931                     grid->getItemPosition(i, &row, &column, &rowSpan, &columnSpan);
       
  1932                     QMap<int, bool> rows;
       
  1933                     QMap<int, bool> columns;
       
  1934                     for (int i = rowSpan; i > 1; i--)
       
  1935                         rows[row + i - 2] = true;
       
  1936                     for (int i = columnSpan; i > 1; i--)
       
  1937                         columns[column + i - 2] = true;
       
  1938 
       
  1939                     while (rowSpan > 0) {
       
  1940                         excludedColumnsForRow[row + rowSpan - 1].unite(columns);
       
  1941                         rowSpan--;
       
  1942                     }
       
  1943                     while (columnSpan > 0) {
       
  1944                         excludedRowsForColumn[column + columnSpan - 1].unite(rows);
       
  1945                         columnSpan--;
       
  1946                     }
       
  1947                 }
       
  1948                 if (item->spacerItem()) {
       
  1949                     const QRect geometry = item->geometry();
       
  1950                     if (!geometry.isNull())
       
  1951                         p.drawRect(geometry.adjusted(1, 1, -2, -2));
       
  1952                 }
       
  1953             }
       
  1954         }
       
  1955     }
       
  1956     if (grid) {
       
  1957         p.setPen(QPen(QColor(0, 0x80, 0, 0x80), 1));
       
  1958         const int rowCount = grid->rowCount();
       
  1959         const int columnCount = grid->columnCount();
       
  1960         for (int i = 0; i < rowCount; i++) {
       
  1961             for (int j = 0; j < columnCount; j++) {
       
  1962                 const QRect cellRect = grid->cellRect(i, j);
       
  1963                 if (j < columnCount - 1 && excludedColumnsForRow.value(i).value(j, false) == false) {
       
  1964                     const double y0 = (i == 0)
       
  1965                             ? 0 : (grid->cellRect(i - 1, j).bottom() + cellRect.top()) / 2.0;
       
  1966                     const double y1 = (i == rowCount - 1)
       
  1967                             ? height() - 1 : (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0;
       
  1968                     const double x = (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0;
       
  1969                     p.drawLine(QPointF(x, y0), QPointF(x, y1));
       
  1970                 }
       
  1971                 if (i < rowCount - 1 && excludedRowsForColumn.value(j).value(i, false) == false) {
       
  1972                     const double x0 = (j == 0)
       
  1973                             ? 0 : (grid->cellRect(i, j - 1).right() + cellRect.left()) / 2.0;
       
  1974                     const double x1 = (j == columnCount - 1)
       
  1975                             ? width() - 1 : (cellRect.right() + grid->cellRect(i, j + 1).left()) / 2.0;
       
  1976                     const double y = (cellRect.bottom() + grid->cellRect(i + 1, j).top()) / 2.0;
       
  1977                     p.drawLine(QPointF(x0, y), QPointF(x1, y));
       
  1978                 }
       
  1979             }
       
  1980         }
       
  1981     }
       
  1982     p.setPen(QPen(QColor(255, 0, 0, 128), 1));
       
  1983     p.drawRect(0, 0, width() - 1, height() - 1);
       
  1984 }
       
  1985 
       
  1986 bool QLayoutWidget::event(QEvent *e)
       
  1987 {
       
  1988     switch (e->type()) {
       
  1989         case QEvent::LayoutRequest: {
       
  1990             (void) QWidget::event(e);
       
  1991             // Magic: We are layouted, but the parent is not..
       
  1992             if (layout() && qdesigner_internal::LayoutInfo::layoutType(formWindow()->core(), parentWidget()) == qdesigner_internal::LayoutInfo::NoLayout) {
       
  1993                 resize(layout()->totalMinimumSize().expandedTo(size()));
       
  1994             }
       
  1995 
       
  1996             update();
       
  1997 
       
  1998             return true;
       
  1999         }
       
  2000 
       
  2001         default:
       
  2002             break;
       
  2003     }
       
  2004 
       
  2005     return QWidget::event(e);
       
  2006 }
       
  2007 
       
  2008 int QLayoutWidget::layoutLeftMargin() const
       
  2009 {
       
  2010     if (m_leftMargin < 0 && layout()) {
       
  2011         int margin;
       
  2012         layout()->getContentsMargins(&margin, 0, 0, 0);
       
  2013         return margin;
       
  2014     }
       
  2015     return m_leftMargin;
       
  2016 }
       
  2017 
       
  2018 void QLayoutWidget::setLayoutLeftMargin(int layoutMargin)
       
  2019 {
       
  2020     m_leftMargin = layoutMargin;
       
  2021     if (layout()) {
       
  2022         int newMargin = m_leftMargin;
       
  2023         if (newMargin >= 0 && newMargin < ShiftValue)
       
  2024             newMargin = ShiftValue;
       
  2025         int left, top, right, bottom;
       
  2026         layout()->getContentsMargins(&left, &top, &right, &bottom);
       
  2027         layout()->setContentsMargins(newMargin, top, right, bottom);
       
  2028     }
       
  2029 }
       
  2030 
       
  2031 int QLayoutWidget::layoutTopMargin() const
       
  2032 {
       
  2033     if (m_topMargin < 0 && layout()) {
       
  2034         int margin;
       
  2035         layout()->getContentsMargins(0, &margin, 0, 0);
       
  2036         return margin;
       
  2037     }
       
  2038     return m_topMargin;
       
  2039 }
       
  2040 
       
  2041 void QLayoutWidget::setLayoutTopMargin(int layoutMargin)
       
  2042 {
       
  2043     m_topMargin = layoutMargin;
       
  2044     if (layout()) {
       
  2045         int newMargin = m_topMargin;
       
  2046         if (newMargin >= 0 && newMargin < ShiftValue)
       
  2047             newMargin = ShiftValue;
       
  2048         int left, top, right, bottom;
       
  2049         layout()->getContentsMargins(&left, &top, &right, &bottom);
       
  2050         layout()->setContentsMargins(left, newMargin, right, bottom);
       
  2051     }
       
  2052 }
       
  2053 
       
  2054 int QLayoutWidget::layoutRightMargin() const
       
  2055 {
       
  2056     if (m_rightMargin < 0 && layout()) {
       
  2057         int margin;
       
  2058         layout()->getContentsMargins(0, 0, &margin, 0);
       
  2059         return margin;
       
  2060     }
       
  2061     return m_rightMargin;
       
  2062 }
       
  2063 
       
  2064 void QLayoutWidget::setLayoutRightMargin(int layoutMargin)
       
  2065 {
       
  2066     m_rightMargin = layoutMargin;
       
  2067     if (layout()) {
       
  2068         int newMargin = m_rightMargin;
       
  2069         if (newMargin >= 0 && newMargin < ShiftValue)
       
  2070             newMargin = ShiftValue;
       
  2071         int left, top, right, bottom;
       
  2072         layout()->getContentsMargins(&left, &top, &right, &bottom);
       
  2073         layout()->setContentsMargins(left, top, newMargin, bottom);
       
  2074     }
       
  2075 }
       
  2076 
       
  2077 int QLayoutWidget::layoutBottomMargin() const
       
  2078 {
       
  2079     if (m_bottomMargin < 0 && layout()) {
       
  2080         int margin;
       
  2081         layout()->getContentsMargins(0, 0, 0, &margin);
       
  2082         return margin;
       
  2083     }
       
  2084     return m_bottomMargin;
       
  2085 }
       
  2086 
       
  2087 void QLayoutWidget::setLayoutBottomMargin(int layoutMargin)
       
  2088 {
       
  2089     m_bottomMargin = layoutMargin;
       
  2090     if (layout()) {
       
  2091         int newMargin = m_bottomMargin;
       
  2092         if (newMargin >= 0 && newMargin < ShiftValue)
       
  2093             newMargin = ShiftValue;
       
  2094         int left, top, right, bottom;
       
  2095         layout()->getContentsMargins(&left, &top, &right, &bottom);
       
  2096         layout()->setContentsMargins(left, top, right, newMargin);
       
  2097     }
       
  2098 }
       
  2099 
       
  2100 QT_END_NAMESPACE