src/gui/graphicsview/qgraphicsanchorlayout_p.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtGui module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QtGui/qwidget.h>
       
    43 #include <QtCore/qlinkedlist.h>
       
    44 #include <QtCore/qstack.h>
       
    45 
       
    46 #ifdef QT_DEBUG
       
    47 #include <QtCore/qfile.h>
       
    48 #endif
       
    49 
       
    50 #include "qgraphicsanchorlayout_p.h"
       
    51 
       
    52 QT_BEGIN_NAMESPACE
       
    53 
       
    54 
       
    55 QGraphicsAnchorPrivate::QGraphicsAnchorPrivate(int version)
       
    56     : QObjectPrivate(version), layoutPrivate(0), data(0),
       
    57       sizePolicy(QSizePolicy::Fixed)
       
    58 {
       
    59 }
       
    60 
       
    61 QGraphicsAnchorPrivate::~QGraphicsAnchorPrivate()
       
    62 {
       
    63     layoutPrivate->removeAnchor(data->from, data->to);
       
    64 }
       
    65 
       
    66 void QGraphicsAnchorPrivate::setSizePolicy(QSizePolicy::Policy policy)
       
    67 {
       
    68     if (sizePolicy != policy) {
       
    69         sizePolicy = policy;
       
    70         layoutPrivate->q_func()->invalidate();
       
    71     }
       
    72 }
       
    73 
       
    74 void QGraphicsAnchorPrivate::setSpacing(qreal value)
       
    75 {
       
    76     if (data) {
       
    77         layoutPrivate->setAnchorSize(data, &value);
       
    78     } else {
       
    79         qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
       
    80     }
       
    81 }
       
    82 
       
    83 void QGraphicsAnchorPrivate::unsetSpacing()
       
    84 {
       
    85     if (data) {
       
    86         layoutPrivate->setAnchorSize(data, 0);
       
    87     } else {
       
    88         qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
       
    89     }
       
    90 }
       
    91 
       
    92 qreal QGraphicsAnchorPrivate::spacing() const
       
    93 {
       
    94     qreal size = 0;
       
    95     if (data) {
       
    96         layoutPrivate->anchorSize(data, 0, &size, 0);
       
    97     } else {
       
    98         qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");
       
    99     }
       
   100     return size;
       
   101 }
       
   102 
       
   103 
       
   104 static void internalSizeHints(QSizePolicy::Policy policy,
       
   105                               qreal minSizeHint, qreal prefSizeHint, qreal maxSizeHint,
       
   106                               qreal *minSize, qreal *prefSize,
       
   107                               qreal *expSize, qreal *maxSize)
       
   108 {
       
   109     // minSize, prefSize and maxSize are initialized
       
   110     // with item's preferred Size: this is QSizePolicy::Fixed.
       
   111     //
       
   112     // Then we check each flag to find the resultant QSizePolicy,
       
   113     // according to the following table:
       
   114     //
       
   115     //      constant               value
       
   116     // QSizePolicy::Fixed            0
       
   117     // QSizePolicy::Minimum       GrowFlag
       
   118     // QSizePolicy::Maximum       ShrinkFlag
       
   119     // QSizePolicy::Preferred     GrowFlag | ShrinkFlag
       
   120     // QSizePolicy::Ignored       GrowFlag | ShrinkFlag | IgnoreFlag
       
   121 
       
   122     if (policy & QSizePolicy::ShrinkFlag)
       
   123         *minSize = minSizeHint;
       
   124     else
       
   125         *minSize = prefSizeHint;
       
   126 
       
   127     if (policy & QSizePolicy::GrowFlag)
       
   128         *maxSize = maxSizeHint;
       
   129     else
       
   130         *maxSize = prefSizeHint;
       
   131 
       
   132     // Note that these two initializations are affected by the previous flags
       
   133     if (policy & QSizePolicy::IgnoreFlag)
       
   134         *prefSize = *minSize;
       
   135     else
       
   136         *prefSize = prefSizeHint;
       
   137 
       
   138     if (policy & QSizePolicy::ExpandFlag)
       
   139         *expSize = *maxSize;
       
   140     else
       
   141         *expSize = *prefSize;
       
   142 }
       
   143 
       
   144 void AnchorData::refreshSizeHints(qreal effectiveSpacing)
       
   145 {
       
   146     const bool isInternalAnchor = from->m_item == to->m_item;
       
   147 
       
   148     QSizePolicy::Policy policy;
       
   149     qreal minSizeHint;
       
   150     qreal prefSizeHint;
       
   151     qreal maxSizeHint;
       
   152 
       
   153     if (isInternalAnchor) {
       
   154         const QGraphicsAnchorLayoutPrivate::Orientation orient =
       
   155             QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge);
       
   156         const Qt::AnchorPoint centerEdge =
       
   157             QGraphicsAnchorLayoutPrivate::pickEdge(Qt::AnchorHorizontalCenter, orient);
       
   158         bool hasCenter = (from->m_edge == centerEdge || to->m_edge == centerEdge);
       
   159 
       
   160         if (isLayoutAnchor) {
       
   161             minSize = 0;
       
   162             prefSize = 0;
       
   163             expSize = 0;
       
   164             maxSize = QWIDGETSIZE_MAX;
       
   165             if (hasCenter)
       
   166                 maxSize /= 2;
       
   167             return;
       
   168         } else {
       
   169 
       
   170             QGraphicsLayoutItem *item = from->m_item;
       
   171             if (orient == QGraphicsAnchorLayoutPrivate::Horizontal) {
       
   172                 policy = item->sizePolicy().horizontalPolicy();
       
   173                 minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width();
       
   174                 prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width();
       
   175                 maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width();
       
   176             } else {
       
   177                 policy = item->sizePolicy().verticalPolicy();
       
   178                 minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height();
       
   179                 prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height();
       
   180                 maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height();
       
   181             }
       
   182 
       
   183             if (hasCenter) {
       
   184                 minSizeHint /= 2;
       
   185                 prefSizeHint /= 2;
       
   186                 maxSizeHint /= 2;
       
   187             }
       
   188         }
       
   189     } else {
       
   190         Q_ASSERT(graphicsAnchor);
       
   191         policy = graphicsAnchor->sizePolicy();
       
   192         minSizeHint = 0;
       
   193         if (hasSize) {
       
   194             // One can only configure the preferred size of a normal anchor. Their minimum and
       
   195             // maximum "size hints" are always 0 and QWIDGETSIZE_MAX, correspondingly. However,
       
   196             // their effective size hints might be narrowed down due to their size policies.
       
   197             prefSizeHint = prefSize;
       
   198         } else {
       
   199             prefSizeHint = effectiveSpacing;
       
   200         }
       
   201         maxSizeHint = QWIDGETSIZE_MAX;
       
   202     }
       
   203     internalSizeHints(policy, minSizeHint, prefSizeHint, maxSizeHint, 
       
   204                       &minSize, &prefSize, &expSize, &maxSize);
       
   205 
       
   206     // Set the anchor effective sizes to preferred.
       
   207     //
       
   208     // Note: The idea here is that all items should remain at their
       
   209     // preferred size unless where that's impossible.  In cases where
       
   210     // the item is subject to restrictions (anchored to the layout
       
   211     // edges, for instance), the simplex solver will be run to
       
   212     // recalculate and override the values we set here.
       
   213     sizeAtMinimum = prefSize;
       
   214     sizeAtPreferred = prefSize;
       
   215     sizeAtExpanding = prefSize;
       
   216     sizeAtMaximum = prefSize;
       
   217 }
       
   218 
       
   219 void ParallelAnchorData::updateChildrenSizes()
       
   220 {
       
   221     firstEdge->sizeAtMinimum = secondEdge->sizeAtMinimum = sizeAtMinimum;
       
   222     firstEdge->sizeAtPreferred = secondEdge->sizeAtPreferred = sizeAtPreferred;
       
   223     firstEdge->sizeAtExpanding = secondEdge->sizeAtExpanding = sizeAtExpanding;
       
   224     firstEdge->sizeAtMaximum = secondEdge->sizeAtMaximum = sizeAtMaximum;
       
   225 
       
   226     firstEdge->updateChildrenSizes();
       
   227     secondEdge->updateChildrenSizes();
       
   228 }
       
   229 
       
   230 void ParallelAnchorData::refreshSizeHints(qreal effectiveSpacing)
       
   231 {
       
   232     refreshSizeHints_helper(effectiveSpacing);
       
   233 }
       
   234 
       
   235 void ParallelAnchorData::refreshSizeHints_helper(qreal effectiveSpacing,
       
   236                                                  bool refreshChildren)
       
   237 {
       
   238     if (refreshChildren) {
       
   239         firstEdge->refreshSizeHints(effectiveSpacing);
       
   240         secondEdge->refreshSizeHints(effectiveSpacing);
       
   241     }
       
   242 
       
   243     // ### should we warn if the parallel connection is invalid?
       
   244     // e.g. 1-2-3 with 10-20-30, the minimum of the latter is
       
   245     // bigger than the maximum of the former.
       
   246 
       
   247     minSize = qMax(firstEdge->minSize, secondEdge->minSize);
       
   248     maxSize = qMin(firstEdge->maxSize, secondEdge->maxSize);
       
   249 
       
   250     expSize = qMax(firstEdge->expSize, secondEdge->expSize);
       
   251     expSize = qMin(expSize, maxSize);
       
   252 
       
   253     prefSize = qMax(firstEdge->prefSize, secondEdge->prefSize);
       
   254     prefSize = qMin(prefSize, expSize);
       
   255 
       
   256     // See comment in AnchorData::refreshSizeHints() about sizeAt* values
       
   257     sizeAtMinimum = prefSize;
       
   258     sizeAtPreferred = prefSize;
       
   259     sizeAtExpanding = prefSize;
       
   260     sizeAtMaximum = prefSize;
       
   261 }
       
   262 
       
   263 /*!
       
   264     \internal
       
   265     returns the factor in the interval [-1, 1].
       
   266     -1 is at Minimum
       
   267      0 is at Preferred
       
   268      1 is at Maximum
       
   269 */
       
   270 static QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> getFactor(qreal value, qreal min,
       
   271                                                                       qreal pref, qreal exp,
       
   272                                                                       qreal max)
       
   273 {
       
   274     QGraphicsAnchorLayoutPrivate::Interval interval;
       
   275     qreal lower;
       
   276     qreal upper;
       
   277 
       
   278     if (value < pref) {
       
   279         interval = QGraphicsAnchorLayoutPrivate::MinToPreferred;
       
   280         lower = min;
       
   281         upper = pref;
       
   282     } else if (value < exp) {
       
   283         interval = QGraphicsAnchorLayoutPrivate::PreferredToExpanding;
       
   284         lower = pref;
       
   285         upper = exp;
       
   286     } else {
       
   287         interval = QGraphicsAnchorLayoutPrivate::ExpandingToMax;
       
   288         lower = exp;
       
   289         upper = max;
       
   290     }
       
   291 
       
   292     qreal progress;
       
   293     if (upper == lower) {
       
   294         progress = 0;
       
   295     } else {
       
   296         progress = (value - lower) / (upper - lower);
       
   297     }
       
   298 
       
   299     return qMakePair(interval, progress);
       
   300 }
       
   301 
       
   302 static qreal interpolate(const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> &factor,
       
   303                          qreal min, qreal pref,
       
   304                          qreal exp, qreal max)
       
   305 {
       
   306     qreal lower;
       
   307     qreal upper;
       
   308 
       
   309     switch (factor.first) {
       
   310     case QGraphicsAnchorLayoutPrivate::MinToPreferred:
       
   311         lower = min;
       
   312         upper = pref;
       
   313         break;
       
   314     case QGraphicsAnchorLayoutPrivate::PreferredToExpanding:
       
   315         lower = pref;
       
   316         upper = exp;
       
   317         break;
       
   318     case QGraphicsAnchorLayoutPrivate::ExpandingToMax:
       
   319         lower = exp;
       
   320         upper = max;
       
   321         break;
       
   322     }
       
   323 
       
   324     return lower + factor.second * (upper - lower);
       
   325 }
       
   326 
       
   327 void SequentialAnchorData::updateChildrenSizes()
       
   328 {
       
   329     // ### REMOVE ME
       
   330     // ### check whether we are guarantee to get those or we need to warn stuff at this
       
   331     // point.
       
   332     Q_ASSERT(sizeAtMinimum > minSize || qFuzzyCompare(sizeAtMinimum, minSize));
       
   333     Q_ASSERT(sizeAtMinimum < maxSize || qFuzzyCompare(sizeAtMinimum, maxSize));
       
   334     Q_ASSERT(sizeAtPreferred > minSize || qFuzzyCompare(sizeAtPreferred, minSize));
       
   335     Q_ASSERT(sizeAtPreferred < maxSize || qFuzzyCompare(sizeAtPreferred, maxSize));
       
   336     Q_ASSERT(sizeAtExpanding > minSize || qFuzzyCompare(sizeAtExpanding, minSize));
       
   337     Q_ASSERT(sizeAtExpanding < maxSize || qFuzzyCompare(sizeAtExpanding, maxSize));
       
   338     Q_ASSERT(sizeAtMaximum > minSize || qFuzzyCompare(sizeAtMaximum, minSize));
       
   339     Q_ASSERT(sizeAtMaximum < maxSize || qFuzzyCompare(sizeAtMaximum, maxSize));
       
   340 
       
   341     // Band here refers if the value is in the Minimum To Preferred
       
   342     // band (the lower band) or the Preferred To Maximum (the upper band).
       
   343 
       
   344     const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> minFactor =
       
   345         getFactor(sizeAtMinimum, minSize, prefSize, expSize, maxSize);
       
   346     const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> prefFactor =
       
   347         getFactor(sizeAtPreferred, minSize, prefSize, expSize, maxSize);
       
   348     const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> expFactor =
       
   349         getFactor(sizeAtExpanding, minSize, prefSize, expSize, maxSize);
       
   350     const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> maxFactor =
       
   351         getFactor(sizeAtMaximum, minSize, prefSize, expSize, maxSize);
       
   352 
       
   353     for (int i = 0; i < m_edges.count(); ++i) {
       
   354         AnchorData *e = m_edges.at(i);
       
   355 
       
   356         e->sizeAtMinimum = interpolate(minFactor, e->minSize, e->prefSize, e->expSize, e->maxSize);
       
   357         e->sizeAtPreferred = interpolate(prefFactor, e->minSize, e->prefSize, e->expSize, e->maxSize);
       
   358         e->sizeAtExpanding = interpolate(expFactor, e->minSize, e->prefSize, e->expSize, e->maxSize);
       
   359         e->sizeAtMaximum = interpolate(maxFactor, e->minSize, e->prefSize, e->expSize, e->maxSize);
       
   360 
       
   361         e->updateChildrenSizes();
       
   362     }
       
   363 }
       
   364 
       
   365 void SequentialAnchorData::refreshSizeHints(qreal effectiveSpacing)
       
   366 {
       
   367     refreshSizeHints_helper(effectiveSpacing);
       
   368 }
       
   369 
       
   370 void SequentialAnchorData::refreshSizeHints_helper(qreal effectiveSpacing,
       
   371                                                    bool refreshChildren)
       
   372 {
       
   373     minSize = 0;
       
   374     prefSize = 0;
       
   375     expSize = 0;
       
   376     maxSize = 0;
       
   377 
       
   378     for (int i = 0; i < m_edges.count(); ++i) {
       
   379         AnchorData *edge = m_edges.at(i);
       
   380 
       
   381         // If it's the case refresh children information first
       
   382         if (refreshChildren)
       
   383             edge->refreshSizeHints(effectiveSpacing);
       
   384 
       
   385         minSize += edge->minSize;
       
   386         prefSize += edge->prefSize;
       
   387         expSize += edge->expSize;
       
   388         maxSize += edge->maxSize;
       
   389     }
       
   390 
       
   391     // See comment in AnchorData::refreshSizeHints() about sizeAt* values
       
   392     sizeAtMinimum = prefSize;
       
   393     sizeAtPreferred = prefSize;
       
   394     sizeAtExpanding = prefSize;
       
   395     sizeAtMaximum = prefSize;
       
   396 }
       
   397 
       
   398 #ifdef QT_DEBUG
       
   399 void AnchorData::dump(int indent) {
       
   400     if (type == Parallel) {
       
   401         qDebug("%*s type: parallel:", indent, "");
       
   402         ParallelAnchorData *p = static_cast<ParallelAnchorData *>(this);
       
   403         p->firstEdge->dump(indent+2);
       
   404         p->secondEdge->dump(indent+2);
       
   405     } else if (type == Sequential) {
       
   406         SequentialAnchorData *s = static_cast<SequentialAnchorData *>(this);
       
   407         int kids = s->m_edges.count();
       
   408         qDebug("%*s type: sequential(%d):", indent, "", kids);
       
   409         for (int i = 0; i < kids; ++i) {
       
   410             s->m_edges.at(i)->dump(indent+2);
       
   411         }
       
   412     } else {
       
   413         qDebug("%*s type: Normal:", indent, "");
       
   414     }
       
   415 }
       
   416 
       
   417 #endif
       
   418 
       
   419 QSimplexConstraint *GraphPath::constraint(const GraphPath &path) const
       
   420 {
       
   421     // Calculate
       
   422     QSet<AnchorData *> cPositives;
       
   423     QSet<AnchorData *> cNegatives;
       
   424     QSet<AnchorData *> intersection;
       
   425 
       
   426     cPositives = positives + path.negatives;
       
   427     cNegatives = negatives + path.positives;
       
   428 
       
   429     intersection = cPositives & cNegatives;
       
   430 
       
   431     cPositives -= intersection;
       
   432     cNegatives -= intersection;
       
   433 
       
   434     // Fill
       
   435     QSimplexConstraint *c = new QSimplexConstraint;
       
   436     QSet<AnchorData *>::iterator i;
       
   437     for (i = cPositives.begin(); i != cPositives.end(); ++i)
       
   438         c->variables.insert(*i, 1.0);
       
   439 
       
   440     for (i = cNegatives.begin(); i != cNegatives.end(); ++i)
       
   441         c->variables.insert(*i, -1.0);
       
   442 
       
   443     return c;
       
   444 }
       
   445 
       
   446 #ifdef QT_DEBUG
       
   447 QString GraphPath::toString() const
       
   448 {
       
   449     QString string(QLatin1String("Path: "));
       
   450     foreach(AnchorData *edge, positives)
       
   451         string += QString::fromAscii(" (+++) %1").arg(edge->toString());
       
   452 
       
   453     foreach(AnchorData *edge, negatives)
       
   454         string += QString::fromAscii(" (---) %1").arg(edge->toString());
       
   455 
       
   456     return string;
       
   457 }
       
   458 #endif
       
   459 
       
   460 QGraphicsAnchorLayoutPrivate::QGraphicsAnchorLayoutPrivate()
       
   461     : calculateGraphCacheDirty(1)
       
   462 {
       
   463     for (int i = 0; i < NOrientations; ++i) {
       
   464         for (int j = 0; j < 3; ++j) {
       
   465             sizeHints[i][j] = -1;
       
   466         }
       
   467         sizeAtExpanding[i] = -1;
       
   468         interpolationProgress[i] = -1;
       
   469 
       
   470         spacings[i] = -1;
       
   471         graphSimplified[i] = false;
       
   472         graphHasConflicts[i] = false;
       
   473     }
       
   474 }
       
   475 
       
   476 Qt::AnchorPoint QGraphicsAnchorLayoutPrivate::oppositeEdge(Qt::AnchorPoint edge)
       
   477 {
       
   478     switch (edge) {
       
   479     case Qt::AnchorLeft:
       
   480         edge = Qt::AnchorRight;
       
   481         break;
       
   482     case Qt::AnchorRight:
       
   483         edge = Qt::AnchorLeft;
       
   484         break;
       
   485     case Qt::AnchorTop:
       
   486         edge = Qt::AnchorBottom;
       
   487         break;
       
   488     case Qt::AnchorBottom:
       
   489         edge = Qt::AnchorTop;
       
   490         break;
       
   491     default:
       
   492         break;
       
   493     }
       
   494     return edge;
       
   495 }
       
   496 
       
   497 
       
   498 /*!
       
   499  * \internal
       
   500  *
       
   501  * helper function in order to avoid overflowing anchor sizes
       
   502  * the returned size will never be larger than FLT_MAX
       
   503  *
       
   504  */
       
   505 inline static qreal checkAdd(qreal a, qreal b)
       
   506 {
       
   507     if (FLT_MAX - b  < a)
       
   508         return FLT_MAX;
       
   509     return a + b;
       
   510 }
       
   511 
       
   512 /*!
       
   513  * \internal
       
   514  *
       
   515  * Takes the sequence of vertices described by (\a before, \a vertices, \a after) and replaces
       
   516  * all anchors connected to the vertices in \a vertices with one simplified anchor between
       
   517  * \a before and \a after. The simplified anchor will be a placeholder for all the previous
       
   518  * anchors between \a before and \a after, and can be restored back to the anchors it is a
       
   519  * placeholder for.
       
   520  */
       
   521 static bool simplifySequentialChunk(Graph<AnchorVertex, AnchorData> *graph,
       
   522                                     AnchorVertex *before,
       
   523                                     const QVector<AnchorVertex*> &vertices,
       
   524                                     AnchorVertex *after)
       
   525 {
       
   526     AnchorData *data = graph->edgeData(before, vertices.first());
       
   527     Q_ASSERT(data);
       
   528 
       
   529     const bool forward = (before == data->from);
       
   530     QVector<AnchorVertex *> orderedVertices;
       
   531 
       
   532     if (forward) {
       
   533         orderedVertices = vertices;
       
   534     } else {
       
   535         qSwap(before, after);
       
   536         for (int i = vertices.count() - 1; i >= 0; --i)
       
   537             orderedVertices.append(vertices.at(i));
       
   538     }
       
   539 
       
   540 #if defined(QT_DEBUG) && 0
       
   541     QString strVertices;
       
   542     for (int i = 0; i < orderedVertices.count(); ++i) {
       
   543         strVertices += QString::fromAscii("%1 - ").arg(orderedVertices.at(i)->toString());
       
   544     }
       
   545     QString strPath = QString::fromAscii("%1 - %2%3").arg(before->toString(), strVertices, after->toString());
       
   546     qDebug("simplifying [%s] to [%s - %s]", qPrintable(strPath), qPrintable(before->toString()), qPrintable(after->toString()));
       
   547 #endif
       
   548 
       
   549     SequentialAnchorData *sequence = new SequentialAnchorData;
       
   550     AnchorVertex *prev = before;
       
   551 
       
   552     for (int i = 0; i <= orderedVertices.count(); ++i) {
       
   553         AnchorVertex *next = (i < orderedVertices.count()) ? orderedVertices.at(i) : after;
       
   554         AnchorData *ad = graph->takeEdge(prev, next);
       
   555         Q_ASSERT(ad);
       
   556         sequence->m_edges.append(ad);
       
   557         prev = next;
       
   558     }
       
   559 
       
   560     sequence->setVertices(orderedVertices);
       
   561     sequence->from = before;
       
   562     sequence->to = after;
       
   563 
       
   564     sequence->refreshSizeHints_helper(0, false);
       
   565 
       
   566     // Note that since layout 'edges' can't be simplified away from
       
   567     // the graph, it's safe to assume that if there's a layout
       
   568     // 'edge', it'll be in the boundaries of the sequence.
       
   569     sequence->isLayoutAnchor = (sequence->m_edges.first()->isLayoutAnchor
       
   570                                 || sequence->m_edges.last()->isLayoutAnchor);
       
   571 
       
   572     AnchorData *newAnchor = sequence;
       
   573     if (AnchorData *oldAnchor = graph->takeEdge(before, after)) {
       
   574         ParallelAnchorData *parallel = new ParallelAnchorData(oldAnchor, sequence);
       
   575         parallel->isLayoutAnchor = (oldAnchor->isLayoutAnchor
       
   576                                      || sequence->isLayoutAnchor);
       
   577         parallel->refreshSizeHints_helper(0, false);
       
   578         newAnchor = parallel;
       
   579     }
       
   580     graph->createEdge(before, after, newAnchor);
       
   581 
       
   582     // True if we created a parallel anchor
       
   583     return newAnchor != sequence;
       
   584 }
       
   585 
       
   586 /*!
       
   587    \internal
       
   588 
       
   589    The purpose of this function is to simplify the graph.
       
   590    Simplification serves two purposes:
       
   591    1. Reduce the number of edges in the graph, (thus the number of variables to the equation
       
   592       solver is reduced, and the solver performs better).
       
   593    2. Be able to do distribution of sequences of edges more intelligently (esp. with sequential
       
   594       anchors)
       
   595 
       
   596    It is essential that it must be possible to restore simplified anchors back to their "original"
       
   597    form. This is done by restoreSimplifiedAnchor().
       
   598 
       
   599    There are two types of simplification that can be done:
       
   600    1. Sequential simplification
       
   601       Sequential simplification means that all sequences of anchors will be merged into one single
       
   602       anchor. Only anhcors that points in the same direction will be merged.
       
   603    2. Parallel simplification
       
   604       If a simplified sequential anchor is about to be inserted between two vertices in the graph
       
   605       and there already exist an anchor between those two vertices, a parallel anchor will be
       
   606       created that serves as a placeholder for the sequential anchor and the anchor that was
       
   607       already between the two vertices.
       
   608 
       
   609    The process of simplification can be described as:
       
   610 
       
   611    1. Simplify all sequences of anchors into one anchor.
       
   612       If no further simplification was done, go to (3)
       
   613       - If there already exist an anchor where the sequential anchor is supposed to be inserted,
       
   614         take that anchor out of the graph
       
   615       - Then create a parallel anchor that holds the sequential anchor and the anchor just taken
       
   616         out of the graph.
       
   617    2. Go to (1)
       
   618    3. Done
       
   619 
       
   620 */
       
   621 void QGraphicsAnchorLayoutPrivate::simplifyGraph(Orientation orientation)
       
   622 {
       
   623     static bool noSimplification = !qgetenv("QT_ANCHORLAYOUT_NO_SIMPLIFICATION").isEmpty();
       
   624     if (noSimplification || items.isEmpty())
       
   625         return;
       
   626 
       
   627     if (graphSimplified[orientation])
       
   628         return;
       
   629     graphSimplified[orientation] = true;
       
   630 
       
   631 #if 0
       
   632     qDebug("Simplifying Graph for %s",
       
   633            orientation == Horizontal ? "Horizontal" : "Vertical");
       
   634 #endif
       
   635 
       
   636     if (!graph[orientation].rootVertex())
       
   637         return;
       
   638 
       
   639     bool dirty;
       
   640     do {
       
   641         dirty = simplifyGraphIteration(orientation);
       
   642     } while (dirty);
       
   643 }
       
   644 
       
   645 /*!
       
   646     \internal
       
   647 
       
   648     One iteration of the simplification algorithm. Returns true if another iteration is needed.
       
   649 
       
   650     The algorithm walks the graph in depth-first order, and only collects vertices that has two
       
   651     edges connected to it.  If the vertex does not have two edges or if it is a layout edge, it
       
   652     will take all the previously collected vertices and try to create a simplified sequential
       
   653     anchor representing all the previously collected vertices.  Once the simplified anchor is
       
   654     inserted, the collected list is cleared in order to find the next sequence to simplify.
       
   655 
       
   656     Note that there are some catches to this that are not covered by the above explanation, see
       
   657     the function comments for more details.
       
   658 */
       
   659 bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutPrivate::Orientation orientation)
       
   660 {
       
   661     Q_Q(QGraphicsAnchorLayout);
       
   662     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
       
   663 
       
   664     QSet<AnchorVertex *> visited;
       
   665     QStack<QPair<AnchorVertex *, AnchorVertex *> > stack;
       
   666     stack.push(qMakePair(static_cast<AnchorVertex *>(0), g.rootVertex()));
       
   667     QVector<AnchorVertex*> candidates;
       
   668     bool candidatesForward;
       
   669 
       
   670     const Qt::AnchorPoint centerEdge = pickEdge(Qt::AnchorHorizontalCenter, orientation);
       
   671 
       
   672     // Walk depth-first, in the stack we store start of the candidate sequence (beforeSequence)
       
   673     // and the vertex to be visited.
       
   674     while (!stack.isEmpty()) {
       
   675         QPair<AnchorVertex *, AnchorVertex *> pair = stack.pop();
       
   676         AnchorVertex *beforeSequence = pair.first;
       
   677         AnchorVertex *v = pair.second;
       
   678 
       
   679         // The basic idea is to determine whether we found an end of sequence,
       
   680         // if that's the case, we stop adding vertices to the candidate list
       
   681         // and do a simplification step.
       
   682         //
       
   683         // A vertex can trigger an end of sequence if
       
   684         // (a) it is a layout vertex, we don't simplify away the layout vertices;
       
   685         // (b) it does not have exactly 2 adjacents;
       
   686         // (c) it will change the direction of the sequence;
       
   687         // (d) its next adjacent is already visited (a cycle in the graph).
       
   688 
       
   689         const QList<AnchorVertex *> &adjacents = g.adjacentVertices(v);
       
   690         const bool isLayoutVertex = v->m_item == q;
       
   691         AnchorVertex *afterSequence = v;
       
   692         bool endOfSequence = false;
       
   693 
       
   694         //
       
   695         // Identify the end cases.
       
   696         //
       
   697 
       
   698         // Identifies cases (a) and (b)
       
   699         endOfSequence = isLayoutVertex || adjacents.count() != 2;
       
   700 
       
   701         if (!endOfSequence) {
       
   702             // If this is the first vertice, determine what is the direction to use for this
       
   703             // sequence.
       
   704             if (candidates.isEmpty()) {
       
   705                 const AnchorData *data = g.edgeData(beforeSequence, v);
       
   706                 Q_ASSERT(data);
       
   707                 candidatesForward = (beforeSequence == data->from);
       
   708             }
       
   709 
       
   710             // This is a tricky part. We peek at the next vertex to find out
       
   711             //
       
   712             // - whether the edge from this vertex to the next vertex has the same direction;
       
   713             // - whether we already visited the next vertex.
       
   714             //
       
   715             // Those are needed to identify (c) and (d). Note that unlike (a) and (b), we preempt
       
   716             // the end of sequence by looking into the next vertex.
       
   717 
       
   718             // Peek at the next vertex
       
   719             AnchorVertex *after;
       
   720             if (candidates.isEmpty())
       
   721                 after = (beforeSequence == adjacents.last() ? adjacents.first() : adjacents.last());
       
   722             else
       
   723                 after = (candidates.last() == adjacents.last() ? adjacents.first() : adjacents.last());
       
   724 
       
   725             // ### At this point we assumed that candidates will not contain 'after', this may not hold
       
   726             // when simplifying FLOATing anchors.
       
   727             Q_ASSERT(!candidates.contains(after));
       
   728 
       
   729             const AnchorData *data = g.edgeData(v, after);
       
   730             Q_ASSERT(data);
       
   731             const bool willChangeDirection = (candidatesForward != (v == data->from));
       
   732             const bool cycleFound = visited.contains(after);
       
   733 
       
   734             // Now cases (c) and (d)...
       
   735             endOfSequence = willChangeDirection || cycleFound;
       
   736 
       
   737             if (endOfSequence) {
       
   738                 if (!willChangeDirection) {
       
   739                     // If the direction will not change, we can add the current vertex to the
       
   740                     // candidates list and we know that 'after' can be used as afterSequence.
       
   741                     candidates.append(v);
       
   742                     afterSequence = after;
       
   743                 }
       
   744             } else {
       
   745                 // If it's not an end of sequence, then the vertex didn't trigger neither of the
       
   746                 // previously four cases, so it can be added to the candidates list.
       
   747                 candidates.append(v);
       
   748             }
       
   749         }
       
   750 
       
   751         //
       
   752         // Add next non-visited vertices to the stack.
       
   753         //
       
   754         for (int i = 0; i < adjacents.count(); ++i) {
       
   755             AnchorVertex *next = adjacents.at(i);
       
   756             if (visited.contains(next))
       
   757                 continue;
       
   758 
       
   759             // If current vertex is an end of sequence, and it'll reset the candidates list. So
       
   760             // the next vertices will build candidates lists with the current vertex as 'before'
       
   761             // vertex. If it's not an end of sequence, we keep the original 'before' vertex,
       
   762             // since we are keeping the candidates list.
       
   763             if (endOfSequence)
       
   764                 stack.push(qMakePair(v, next));
       
   765             else
       
   766                 stack.push(qMakePair(beforeSequence, next));
       
   767         }
       
   768 
       
   769         visited.insert(v);
       
   770 
       
   771         if (!endOfSequence || candidates.isEmpty())
       
   772             continue;
       
   773 
       
   774         //
       
   775         // Create a sequence for (beforeSequence, candidates, afterSequence).
       
   776         //
       
   777 
       
   778         // One restriction we have is to not simplify half of an anchor and let the other half
       
   779         // unsimplified. So we remove center edges before and after the sequence.
       
   780         if (beforeSequence->m_edge == centerEdge && beforeSequence->m_item == candidates.first()->m_item) {
       
   781             beforeSequence = candidates.first();
       
   782             candidates.remove(0);
       
   783 
       
   784             // If there's not candidates to be simplified, leave.
       
   785             if (candidates.isEmpty())
       
   786                 continue;
       
   787         }
       
   788 
       
   789         if (afterSequence->m_edge == centerEdge && afterSequence->m_item == candidates.last()->m_item) {
       
   790             afterSequence = candidates.last();
       
   791             candidates.remove(candidates.count() - 1);
       
   792 
       
   793             if (candidates.isEmpty())
       
   794                 continue;
       
   795         }
       
   796 
       
   797         // This function will remove the candidates from the graph and create one edge between
       
   798         // beforeSequence and afterSequence. This function returns true if the sequential
       
   799         // simplification also caused a parallel simplification to be created. In this case we end
       
   800         // the iteration and start again (since all the visited state we have may be outdated).
       
   801         if (simplifySequentialChunk(&g, beforeSequence, candidates, afterSequence))
       
   802             return true;
       
   803 
       
   804         // If there was no parallel simplification, we'll keep walking the graph. So we clear the
       
   805         // candidates list to start again.
       
   806         candidates.clear();
       
   807     }
       
   808 
       
   809     return false;
       
   810 }
       
   811 
       
   812 static void restoreSimplifiedAnchor(Graph<AnchorVertex, AnchorData> &g,
       
   813                                     AnchorData *edge,
       
   814                                     AnchorVertex *before,
       
   815                                     AnchorVertex *after)
       
   816 {
       
   817     Q_ASSERT(edge->type != AnchorData::Normal);
       
   818 #if 0
       
   819     static const char *anchortypes[] = {"Normal",
       
   820                                         "Sequential",
       
   821                                         "Parallel"};
       
   822     qDebug("Restoring %s edge.", anchortypes[int(edge->type)]);
       
   823 #endif
       
   824     if (edge->type == AnchorData::Sequential) {
       
   825         SequentialAnchorData* seqEdge = static_cast<SequentialAnchorData*>(edge);
       
   826         // restore the sequential anchor
       
   827         AnchorVertex *prev = before;
       
   828         AnchorVertex *last = after;
       
   829         if (edge->from != prev)
       
   830             qSwap(last, prev);
       
   831 
       
   832         for (int i = 0; i < seqEdge->m_edges.count(); ++i) {
       
   833             AnchorVertex *v1 = (i < seqEdge->m_children.count()) ? seqEdge->m_children.at(i) : last;
       
   834             AnchorData *data = seqEdge->m_edges.at(i);
       
   835             if (data->type != AnchorData::Normal) {
       
   836                 restoreSimplifiedAnchor(g, data, prev, v1);
       
   837             } else {
       
   838                 g.createEdge(prev, v1, data);
       
   839             }
       
   840             prev = v1;
       
   841         }
       
   842     } else if (edge->type == AnchorData::Parallel) {
       
   843         ParallelAnchorData* parallelEdge = static_cast<ParallelAnchorData*>(edge);
       
   844         AnchorData *parallelEdges[2] = {parallelEdge->firstEdge,
       
   845                                         parallelEdge->secondEdge};
       
   846         for (int i = 0; i < 2; ++i) {
       
   847             AnchorData *data = parallelEdges[i];
       
   848             if (data->type == AnchorData::Normal) {
       
   849                 g.createEdge(before, after, data);
       
   850             } else {
       
   851                 restoreSimplifiedAnchor(g, data, before, after);
       
   852             }
       
   853         }
       
   854     }
       
   855 }
       
   856 
       
   857 void QGraphicsAnchorLayoutPrivate::restoreSimplifiedGraph(Orientation orientation)
       
   858 {
       
   859     if (!graphSimplified[orientation])
       
   860         return;
       
   861     graphSimplified[orientation] = false;
       
   862 
       
   863 #if 0
       
   864     qDebug("Restoring Simplified Graph for %s",
       
   865            orientation == Horizontal ? "Horizontal" : "Vertical");
       
   866 #endif
       
   867 
       
   868     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
       
   869 
       
   870     QList<QPair<AnchorVertex*, AnchorVertex*> > connections = g.connections();
       
   871     for (int i = 0; i < connections.count(); ++i) {
       
   872         AnchorVertex *v1 = connections.at(i).first;
       
   873         AnchorVertex *v2 = connections.at(i).second;
       
   874         AnchorData *edge = g.edgeData(v1, v2);
       
   875         if (edge->type != AnchorData::Normal) {
       
   876             AnchorData *oldEdge = g.takeEdge(v1, v2);
       
   877             restoreSimplifiedAnchor(g, edge, v1, v2);
       
   878             delete oldEdge;
       
   879         }
       
   880     }
       
   881 }
       
   882 
       
   883 QGraphicsAnchorLayoutPrivate::Orientation
       
   884 QGraphicsAnchorLayoutPrivate::edgeOrientation(Qt::AnchorPoint edge)
       
   885 {
       
   886     return edge > Qt::AnchorRight ? Vertical : Horizontal;
       
   887 }
       
   888 
       
   889 /*!
       
   890   \internal
       
   891 
       
   892   Create internal anchors to connect the layout edges (Left to Right and
       
   893   Top to Bottom).
       
   894 
       
   895   These anchors doesn't have size restrictions, that will be enforced by
       
   896   other anchors and items in the layout.
       
   897 */
       
   898 void QGraphicsAnchorLayoutPrivate::createLayoutEdges()
       
   899 {
       
   900     Q_Q(QGraphicsAnchorLayout);
       
   901     QGraphicsLayoutItem *layout = q;
       
   902 
       
   903     // Horizontal
       
   904     AnchorData *data = new AnchorData;
       
   905     addAnchor_helper(layout, Qt::AnchorLeft, layout,
       
   906                      Qt::AnchorRight, data);
       
   907     data->maxSize = QWIDGETSIZE_MAX;
       
   908     data->skipInPreferred = 1;
       
   909 
       
   910     // Set the Layout Left edge as the root of the horizontal graph.
       
   911     AnchorVertex *v = internalVertex(layout, Qt::AnchorLeft);
       
   912     graph[Horizontal].setRootVertex(v);
       
   913 
       
   914     // Vertical
       
   915     data = new AnchorData;
       
   916     addAnchor_helper(layout, Qt::AnchorTop, layout,
       
   917                      Qt::AnchorBottom, data);
       
   918     data->maxSize = QWIDGETSIZE_MAX;
       
   919     data->skipInPreferred = 1;
       
   920 
       
   921     // Set the Layout Top edge as the root of the vertical graph.
       
   922     v = internalVertex(layout, Qt::AnchorTop);
       
   923     graph[Vertical].setRootVertex(v);
       
   924 }
       
   925 
       
   926 void QGraphicsAnchorLayoutPrivate::deleteLayoutEdges()
       
   927 {
       
   928     Q_Q(QGraphicsAnchorLayout);
       
   929 
       
   930     Q_ASSERT(internalVertex(q, Qt::AnchorHorizontalCenter) == NULL);
       
   931     Q_ASSERT(internalVertex(q, Qt::AnchorVerticalCenter) == NULL);
       
   932 
       
   933     removeAnchor_helper(internalVertex(q, Qt::AnchorLeft),
       
   934                         internalVertex(q, Qt::AnchorRight));
       
   935     removeAnchor_helper(internalVertex(q, Qt::AnchorTop),
       
   936                         internalVertex(q, Qt::AnchorBottom));
       
   937 }
       
   938 
       
   939 void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item)
       
   940 {
       
   941     Q_ASSERT(!graphSimplified[Horizontal] && !graphSimplified[Vertical]);
       
   942 
       
   943     items.append(item);
       
   944 
       
   945     // Create horizontal and vertical internal anchors for the item and
       
   946     // refresh its size hint / policy values.
       
   947     AnchorData *data = new AnchorData;
       
   948     addAnchor_helper(item, Qt::AnchorLeft, item, Qt::AnchorRight, data);
       
   949     data->refreshSizeHints(0); // 0 = effectiveSpacing, will not be used
       
   950 
       
   951     data = new AnchorData;
       
   952     addAnchor_helper(item, Qt::AnchorTop, item, Qt::AnchorBottom, data);
       
   953     data->refreshSizeHints(0); // 0 = effectiveSpacing, will not be used
       
   954 }
       
   955 
       
   956 /*!
       
   957   \internal
       
   958 
       
   959   By default, each item in the layout is represented internally as
       
   960   a single anchor in each direction. For instance, from Left to Right.
       
   961 
       
   962   However, to support anchorage of items to the center of items, we
       
   963   must split this internal anchor into two half-anchors. From Left
       
   964   to Center and then from Center to Right, with the restriction that
       
   965   these anchors must have the same time at all times.
       
   966 */
       
   967 void QGraphicsAnchorLayoutPrivate::createCenterAnchors(
       
   968     QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge)
       
   969 {
       
   970     Orientation orientation;
       
   971     switch (centerEdge) {
       
   972     case Qt::AnchorHorizontalCenter:
       
   973         orientation = Horizontal;
       
   974         break;
       
   975     case Qt::AnchorVerticalCenter:
       
   976         orientation = Vertical;
       
   977         break;
       
   978     default:
       
   979         // Don't create center edges unless needed
       
   980         return;
       
   981     }
       
   982 
       
   983     Q_ASSERT(!graphSimplified[orientation]);
       
   984 
       
   985     // Check if vertex already exists
       
   986     if (internalVertex(item, centerEdge))
       
   987         return;
       
   988 
       
   989     // Orientation code
       
   990     Qt::AnchorPoint firstEdge;
       
   991     Qt::AnchorPoint lastEdge;
       
   992 
       
   993     if (orientation == Horizontal) {
       
   994         firstEdge = Qt::AnchorLeft;
       
   995         lastEdge = Qt::AnchorRight;
       
   996     } else {
       
   997         firstEdge = Qt::AnchorTop;
       
   998         lastEdge = Qt::AnchorBottom;
       
   999     }
       
  1000 
       
  1001     AnchorVertex *first = internalVertex(item, firstEdge);
       
  1002     AnchorVertex *last = internalVertex(item, lastEdge);
       
  1003     Q_ASSERT(first && last);
       
  1004 
       
  1005     // Create new anchors
       
  1006     QSimplexConstraint *c = new QSimplexConstraint;
       
  1007 
       
  1008     AnchorData *data = new AnchorData;
       
  1009     c->variables.insert(data, 1.0);
       
  1010     addAnchor_helper(item, firstEdge, item, centerEdge, data);
       
  1011     data->refreshSizeHints(0);
       
  1012 
       
  1013     data = new AnchorData;
       
  1014     c->variables.insert(data, -1.0);
       
  1015     addAnchor_helper(item, centerEdge, item, lastEdge, data);
       
  1016     data->refreshSizeHints(0);
       
  1017 
       
  1018     itemCenterConstraints[orientation].append(c);
       
  1019 
       
  1020     // Remove old one
       
  1021     removeAnchor_helper(first, last);
       
  1022 }
       
  1023 
       
  1024 void QGraphicsAnchorLayoutPrivate::removeCenterAnchors(
       
  1025     QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge,
       
  1026     bool substitute)
       
  1027 {
       
  1028     Orientation orientation;
       
  1029     switch (centerEdge) {
       
  1030     case Qt::AnchorHorizontalCenter:
       
  1031         orientation = Horizontal;
       
  1032         break;
       
  1033     case Qt::AnchorVerticalCenter:
       
  1034         orientation = Vertical;
       
  1035         break;
       
  1036     default:
       
  1037         // Don't remove edges that not the center ones
       
  1038         return;
       
  1039     }
       
  1040 
       
  1041     Q_ASSERT(!graphSimplified[orientation]);
       
  1042 
       
  1043     // Orientation code
       
  1044     Qt::AnchorPoint firstEdge;
       
  1045     Qt::AnchorPoint lastEdge;
       
  1046 
       
  1047     if (orientation == Horizontal) {
       
  1048         firstEdge = Qt::AnchorLeft;
       
  1049         lastEdge = Qt::AnchorRight;
       
  1050     } else {
       
  1051         firstEdge = Qt::AnchorTop;
       
  1052         lastEdge = Qt::AnchorBottom;
       
  1053     }
       
  1054 
       
  1055     AnchorVertex *center = internalVertex(item, centerEdge);
       
  1056     if (!center)
       
  1057         return;
       
  1058     AnchorVertex *first = internalVertex(item, firstEdge);
       
  1059 
       
  1060     Q_ASSERT(first);
       
  1061     Q_ASSERT(center);
       
  1062 
       
  1063     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
       
  1064 
       
  1065 
       
  1066     AnchorData *oldData = g.edgeData(first, center);
       
  1067     // Remove center constraint
       
  1068     for (int i = itemCenterConstraints[orientation].count() - 1; i >= 0; --i) {
       
  1069         if (itemCenterConstraints[orientation][i]->variables.contains(oldData)) {
       
  1070             delete itemCenterConstraints[orientation].takeAt(i);
       
  1071             break;
       
  1072         }
       
  1073     }
       
  1074 
       
  1075     if (substitute) {
       
  1076         // Create the new anchor that should substitute the left-center-right anchors.
       
  1077         AnchorData *data = new AnchorData;
       
  1078         addAnchor_helper(item, firstEdge, item, lastEdge, data);
       
  1079         data->refreshSizeHints(0);
       
  1080 
       
  1081         // Remove old anchors
       
  1082         removeAnchor_helper(first, center);
       
  1083         removeAnchor_helper(center, internalVertex(item, lastEdge));
       
  1084 
       
  1085     } else {
       
  1086         // this is only called from removeAnchors()
       
  1087         // first, remove all non-internal anchors
       
  1088         QList<AnchorVertex*> adjacents = g.adjacentVertices(center);
       
  1089         for (int i = 0; i < adjacents.count(); ++i) {
       
  1090             AnchorVertex *v = adjacents.at(i);
       
  1091             if (v->m_item != item) {
       
  1092                 removeAnchor_helper(center, internalVertex(v->m_item, v->m_edge));
       
  1093             }
       
  1094         }
       
  1095         // when all non-internal anchors is removed it will automatically merge the
       
  1096         // center anchor into a left-right (or top-bottom) anchor. We must also delete that.
       
  1097         // by this time, the center vertex is deleted and merged into a non-centered internal anchor
       
  1098         removeAnchor_helper(first, internalVertex(item, lastEdge));
       
  1099     }
       
  1100 }
       
  1101 
       
  1102 
       
  1103 void QGraphicsAnchorLayoutPrivate::removeCenterConstraints(QGraphicsLayoutItem *item,
       
  1104                                                            Orientation orientation)
       
  1105 {
       
  1106     Q_ASSERT(!graphSimplified[orientation]);
       
  1107 
       
  1108     // Remove the item center constraints associated to this item
       
  1109     // ### This is a temporary solution. We should probably use a better
       
  1110     // data structure to hold items and/or their associated constraints
       
  1111     // so that we can remove those easily
       
  1112 
       
  1113     AnchorVertex *first = internalVertex(item, orientation == Horizontal ?
       
  1114                                        Qt::AnchorLeft :
       
  1115                                        Qt::AnchorTop);
       
  1116     AnchorVertex *center = internalVertex(item, orientation == Horizontal ?
       
  1117                                         Qt::AnchorHorizontalCenter :
       
  1118                                         Qt::AnchorVerticalCenter);
       
  1119 
       
  1120     // Skip if no center constraints exist
       
  1121     if (!center)
       
  1122         return;
       
  1123 
       
  1124     Q_ASSERT(first);
       
  1125     AnchorData *internalAnchor = graph[orientation].edgeData(first, center);
       
  1126 
       
  1127     // Look for our anchor in all item center constraints, then remove it
       
  1128     for (int i = 0; i < itemCenterConstraints[orientation].size(); ++i) {
       
  1129         if (itemCenterConstraints[orientation][i]->variables.contains(internalAnchor)) {
       
  1130             delete itemCenterConstraints[orientation].takeAt(i);
       
  1131             break;
       
  1132         }
       
  1133     }
       
  1134 }
       
  1135 
       
  1136 /*!
       
  1137  * \internal
       
  1138  *
       
  1139  * Helper function that is called from the anchor functions in the public API.
       
  1140  * If \a spacing is 0, it will pick up the spacing defined by the style.
       
  1141  */
       
  1142 QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *firstItem,
       
  1143                                                       Qt::AnchorPoint firstEdge,
       
  1144                                                       QGraphicsLayoutItem *secondItem,
       
  1145                                                       Qt::AnchorPoint secondEdge,
       
  1146                                                       qreal *spacing)
       
  1147 {
       
  1148     Q_Q(QGraphicsAnchorLayout);
       
  1149     if ((firstItem == 0) || (secondItem == 0)) {
       
  1150         qWarning("QGraphicsAnchorLayout::addAnchor(): "
       
  1151                  "Cannot anchor NULL items");
       
  1152         return 0;
       
  1153     }
       
  1154 
       
  1155     if (firstItem == secondItem) {
       
  1156         qWarning("QGraphicsAnchorLayout::addAnchor(): "
       
  1157                  "Cannot anchor the item to itself");
       
  1158         return 0;
       
  1159     }
       
  1160 
       
  1161     if (edgeOrientation(secondEdge) != edgeOrientation(firstEdge)) {
       
  1162         qWarning("QGraphicsAnchorLayout::addAnchor(): "
       
  1163                  "Cannot anchor edges of different orientations");
       
  1164         return 0;
       
  1165     }
       
  1166 
       
  1167     // Guarantee that the graph is no simplified when adding this anchor,
       
  1168     // anchor manipulation always happen in the full graph
       
  1169     restoreSimplifiedGraph(edgeOrientation(firstEdge));
       
  1170 
       
  1171     // In QGraphicsAnchorLayout, items are represented in its internal
       
  1172     // graph as four anchors that connect:
       
  1173     //  - Left -> HCenter
       
  1174     //  - HCenter-> Right
       
  1175     //  - Top -> VCenter
       
  1176     //  - VCenter -> Bottom
       
  1177 
       
  1178     // Ensure that the internal anchors have been created for both items.
       
  1179     if (firstItem != q && !items.contains(firstItem)) {
       
  1180         restoreSimplifiedGraph(edgeOrientation(firstEdge) == Horizontal ? Vertical : Horizontal);
       
  1181         createItemEdges(firstItem);
       
  1182         addChildLayoutItem(firstItem);
       
  1183     }
       
  1184     if (secondItem != q && !items.contains(secondItem)) {
       
  1185         restoreSimplifiedGraph(edgeOrientation(firstEdge) == Horizontal ? Vertical : Horizontal);
       
  1186         createItemEdges(secondItem);
       
  1187         addChildLayoutItem(secondItem);
       
  1188     }
       
  1189 
       
  1190     // Create center edges if needed
       
  1191     createCenterAnchors(firstItem, firstEdge);
       
  1192     createCenterAnchors(secondItem, secondEdge);
       
  1193 
       
  1194     // Use heuristics to find out what the user meant with this anchor.
       
  1195     correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge);
       
  1196 
       
  1197     AnchorData *data = new AnchorData;
       
  1198     if (!spacing) {
       
  1199         // If firstItem or secondItem is the layout itself, the spacing will default to 0.
       
  1200         // Otherwise, the following matrix is used (questionmark means that the spacing
       
  1201         // is queried from the style):
       
  1202         //                from
       
  1203         //  to      Left    HCenter Right
       
  1204         //  Left    0       0       ?
       
  1205         //  HCenter 0       0       0
       
  1206         //  Right   ?       0       0
       
  1207         if (firstItem == q
       
  1208             || secondItem == q
       
  1209             || pickEdge(firstEdge, Horizontal) == Qt::AnchorHorizontalCenter
       
  1210             || oppositeEdge(firstEdge) != secondEdge) {
       
  1211             data->setPreferredSize(0);
       
  1212         } else {
       
  1213             data->unsetSize();
       
  1214         }
       
  1215         addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data);
       
  1216 
       
  1217     } else if (*spacing >= 0) {
       
  1218         data->setPreferredSize(*spacing);
       
  1219         addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data);
       
  1220 
       
  1221     } else {
       
  1222         data->setPreferredSize(-*spacing);
       
  1223         addAnchor_helper(secondItem, secondEdge, firstItem, firstEdge, data);
       
  1224     }
       
  1225 
       
  1226     return acquireGraphicsAnchor(data);
       
  1227 }
       
  1228 
       
  1229 void QGraphicsAnchorLayoutPrivate::addAnchor_helper(QGraphicsLayoutItem *firstItem,
       
  1230                                              Qt::AnchorPoint firstEdge,
       
  1231                                              QGraphicsLayoutItem *secondItem,
       
  1232                                              Qt::AnchorPoint secondEdge,
       
  1233                                              AnchorData *data)
       
  1234 {
       
  1235     Q_Q(QGraphicsAnchorLayout);
       
  1236 
       
  1237     // Guarantee that the graph is no simplified when adding this anchor,
       
  1238     // anchor manipulation always happen in the full graph
       
  1239     restoreSimplifiedGraph(edgeOrientation(firstEdge));
       
  1240 
       
  1241     // Is the Vertex (firstItem, firstEdge) already represented in our
       
  1242     // internal structure?
       
  1243     AnchorVertex *v1 = addInternalVertex(firstItem, firstEdge);
       
  1244     AnchorVertex *v2 = addInternalVertex(secondItem, secondEdge);
       
  1245 
       
  1246     // Remove previous anchor
       
  1247     // ### Could we update the existing edgeData rather than creating a new one?
       
  1248     if (graph[edgeOrientation(firstEdge)].edgeData(v1, v2)) {
       
  1249         removeAnchor_helper(v1, v2);
       
  1250     }
       
  1251 
       
  1252     // Create a bi-directional edge in the sense it can be transversed both
       
  1253     // from v1 or v2. "data" however is shared between the two references
       
  1254     // so we still know that the anchor direction is from 1 to 2.
       
  1255     data->from = v1;
       
  1256     data->to = v2;
       
  1257 #ifdef QT_DEBUG
       
  1258     data->name = QString::fromAscii("%1 --to--> %2").arg(v1->toString()).arg(v2->toString());
       
  1259 #endif
       
  1260     // Keep track of anchors that are connected to the layout 'edges'
       
  1261     data->isLayoutAnchor = (v1->m_item == q || v2->m_item == q);
       
  1262 
       
  1263     graph[edgeOrientation(firstEdge)].createEdge(v1, v2, data);
       
  1264 }
       
  1265 
       
  1266 QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::getAnchor(QGraphicsLayoutItem *firstItem,
       
  1267                                                          Qt::AnchorPoint firstEdge,
       
  1268                                                          QGraphicsLayoutItem *secondItem,
       
  1269                                                          Qt::AnchorPoint secondEdge)
       
  1270 {
       
  1271     Orientation orient = edgeOrientation(firstEdge);
       
  1272     restoreSimplifiedGraph(orient);
       
  1273 
       
  1274     AnchorVertex *v1 = internalVertex(firstItem, firstEdge);
       
  1275     AnchorVertex *v2 = internalVertex(secondItem, secondEdge);
       
  1276 
       
  1277     QGraphicsAnchor *graphicsAnchor = 0;
       
  1278 
       
  1279     AnchorData *data = graph[orient].edgeData(v1, v2);
       
  1280     if (data)
       
  1281         graphicsAnchor = acquireGraphicsAnchor(data);
       
  1282     return graphicsAnchor;
       
  1283 }
       
  1284 
       
  1285 /*!
       
  1286  * \internal
       
  1287  *
       
  1288  * Implements the high level "removeAnchor" feature. Called by
       
  1289  * the QAnchorData destructor.
       
  1290  */
       
  1291 void QGraphicsAnchorLayoutPrivate::removeAnchor(AnchorVertex *firstVertex,
       
  1292                                                 AnchorVertex *secondVertex)
       
  1293 {
       
  1294     Q_Q(QGraphicsAnchorLayout);
       
  1295 
       
  1296     // Actually delete the anchor
       
  1297     removeAnchor_helper(firstVertex, secondVertex);
       
  1298 
       
  1299     QGraphicsLayoutItem *firstItem = firstVertex->m_item;
       
  1300     QGraphicsLayoutItem *secondItem = secondVertex->m_item;
       
  1301 
       
  1302     // Checking if the item stays in the layout or not
       
  1303     bool keepFirstItem = false;
       
  1304     bool keepSecondItem = false;
       
  1305 
       
  1306     QPair<AnchorVertex *, int> v;
       
  1307     int refcount = -1;
       
  1308 
       
  1309     if (firstItem != q) {
       
  1310         for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) {
       
  1311             v = m_vertexList.value(qMakePair(firstItem, static_cast<Qt::AnchorPoint>(i)));
       
  1312             if (v.first) {
       
  1313                 if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter)
       
  1314                     refcount = 2;
       
  1315                 else
       
  1316                     refcount = 1;
       
  1317 
       
  1318                 if (v.second > refcount) {
       
  1319                     keepFirstItem = true;
       
  1320                     break;
       
  1321                 }
       
  1322             }
       
  1323         }
       
  1324     } else
       
  1325         keepFirstItem = true;
       
  1326 
       
  1327     if (secondItem != q) {
       
  1328         for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) {
       
  1329             v = m_vertexList.value(qMakePair(secondItem, static_cast<Qt::AnchorPoint>(i)));
       
  1330             if (v.first) {
       
  1331                 if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter)
       
  1332                     refcount = 2;
       
  1333                 else
       
  1334                     refcount = 1;
       
  1335 
       
  1336                 if (v.second > refcount) {
       
  1337                     keepSecondItem = true;
       
  1338                     break;
       
  1339                 }
       
  1340             }
       
  1341         }
       
  1342     } else
       
  1343         keepSecondItem = true;
       
  1344 
       
  1345     if (!keepFirstItem)
       
  1346         q->removeAt(items.indexOf(firstItem));
       
  1347 
       
  1348     if (!keepSecondItem)
       
  1349         q->removeAt(items.indexOf(secondItem));
       
  1350 
       
  1351     // Removing anchors invalidates the layout
       
  1352     q->invalidate();
       
  1353 }
       
  1354 
       
  1355 /*
       
  1356   \internal
       
  1357 
       
  1358   Implements the low level "removeAnchor" feature. Called by
       
  1359   private methods.
       
  1360 */
       
  1361 void QGraphicsAnchorLayoutPrivate::removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2)
       
  1362 {
       
  1363     Q_ASSERT(v1 && v2);
       
  1364     // Guarantee that the graph is no simplified when removing this anchor,
       
  1365     // anchor manipulation always happen in the full graph
       
  1366     Orientation o = edgeOrientation(v1->m_edge);
       
  1367     restoreSimplifiedGraph(o);
       
  1368 
       
  1369     // Remove edge from graph
       
  1370     graph[o].removeEdge(v1, v2);
       
  1371 
       
  1372     // Decrease vertices reference count (may trigger a deletion)
       
  1373     removeInternalVertex(v1->m_item, v1->m_edge);
       
  1374     removeInternalVertex(v2->m_item, v2->m_edge);
       
  1375 }
       
  1376 
       
  1377 /*!
       
  1378     \internal
       
  1379     Only called from outside. (calls invalidate())
       
  1380 */
       
  1381 void QGraphicsAnchorLayoutPrivate::setAnchorSize(AnchorData *data, const qreal *anchorSize)
       
  1382 {
       
  1383     Q_Q(QGraphicsAnchorLayout);
       
  1384     // ### we can avoid restoration if we really want to, but we would have to
       
  1385     // search recursively through all composite anchors
       
  1386     Q_ASSERT(data);
       
  1387     restoreSimplifiedGraph(edgeOrientation(data->from->m_edge));
       
  1388 
       
  1389     QGraphicsLayoutItem *firstItem = data->from->m_item;
       
  1390     QGraphicsLayoutItem *secondItem = data->to->m_item;
       
  1391     Qt::AnchorPoint firstEdge = data->from->m_edge;
       
  1392     Qt::AnchorPoint secondEdge = data->to->m_edge;
       
  1393 
       
  1394     // Use heuristics to find out what the user meant with this anchor.
       
  1395     correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge);
       
  1396     if (data->from->m_item != firstItem)
       
  1397         qSwap(data->from, data->to);
       
  1398 
       
  1399     if (anchorSize) {
       
  1400         // ### The current implementation makes "setAnchorSize" behavior
       
  1401         //     dependent on the argument order for cases where we have
       
  1402         //     no heuristic. Ie. two widgets, same anchor point.
       
  1403 
       
  1404         // We cannot have negative sizes inside the graph. This would cause
       
  1405         // the simplex solver to fail because all simplex variables are
       
  1406         // positive by definition.
       
  1407         // "negative spacing" is handled by inverting the standard item order.
       
  1408         if (*anchorSize >= 0) {
       
  1409             data->setPreferredSize(*anchorSize);
       
  1410         } else {
       
  1411             data->setPreferredSize(-*anchorSize);
       
  1412             qSwap(data->from, data->to);
       
  1413         }
       
  1414     } else {
       
  1415         data->unsetSize();
       
  1416     }
       
  1417     q->invalidate();
       
  1418 }
       
  1419 
       
  1420 void QGraphicsAnchorLayoutPrivate::anchorSize(const AnchorData *data,
       
  1421                                               qreal *minSize,
       
  1422                                               qreal *prefSize,
       
  1423                                               qreal *maxSize) const
       
  1424 {
       
  1425     Q_ASSERT(minSize || prefSize || maxSize);
       
  1426     Q_ASSERT(data);
       
  1427     QGraphicsAnchorLayoutPrivate *that = const_cast<QGraphicsAnchorLayoutPrivate *>(this);
       
  1428     that->restoreSimplifiedGraph(edgeOrientation(data->from->m_edge));
       
  1429 
       
  1430     if (minSize)
       
  1431         *minSize = data->minSize;
       
  1432     if (prefSize)
       
  1433         *prefSize = data->prefSize;
       
  1434     if (maxSize)
       
  1435         *maxSize = data->maxSize;
       
  1436 }
       
  1437 
       
  1438 AnchorVertex *QGraphicsAnchorLayoutPrivate::addInternalVertex(QGraphicsLayoutItem *item,
       
  1439                                                               Qt::AnchorPoint edge)
       
  1440 {
       
  1441     QPair<QGraphicsLayoutItem *, Qt::AnchorPoint> pair(item, edge);
       
  1442     QPair<AnchorVertex *, int> v = m_vertexList.value(pair);
       
  1443 
       
  1444     if (!v.first) {
       
  1445         Q_ASSERT(v.second == 0);
       
  1446         v.first = new AnchorVertex(item, edge);
       
  1447     }
       
  1448     v.second++;
       
  1449     m_vertexList.insert(pair, v);
       
  1450     return v.first;
       
  1451 }
       
  1452 
       
  1453 /**
       
  1454  * \internal
       
  1455  *
       
  1456  * returns the AnchorVertex that was dereferenced, also when it was removed.
       
  1457  * returns 0 if it did not exist.
       
  1458  */
       
  1459 void QGraphicsAnchorLayoutPrivate::removeInternalVertex(QGraphicsLayoutItem *item,
       
  1460                                                         Qt::AnchorPoint edge)
       
  1461 {
       
  1462     QPair<QGraphicsLayoutItem *, Qt::AnchorPoint> pair(item, edge);
       
  1463     QPair<AnchorVertex *, int> v = m_vertexList.value(pair);
       
  1464 
       
  1465     if (!v.first) {
       
  1466         qWarning("This item with this edge is not in the graph");
       
  1467         return;
       
  1468     }
       
  1469 
       
  1470     v.second--;
       
  1471     if (v.second == 0) {
       
  1472         // Remove reference and delete vertex
       
  1473         m_vertexList.remove(pair);
       
  1474         delete v.first;
       
  1475     } else {
       
  1476         // Update reference count
       
  1477         m_vertexList.insert(pair, v);
       
  1478 
       
  1479         if ((v.second == 2) &&
       
  1480             ((edge == Qt::AnchorHorizontalCenter) ||
       
  1481              (edge == Qt::AnchorVerticalCenter))) {
       
  1482             removeCenterAnchors(item, edge, true);
       
  1483         }
       
  1484     }
       
  1485 }
       
  1486 
       
  1487 void QGraphicsAnchorLayoutPrivate::removeVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge)
       
  1488 {
       
  1489     if (AnchorVertex *v = internalVertex(item, edge)) {
       
  1490         Graph<AnchorVertex, AnchorData> &g = graph[edgeOrientation(edge)];
       
  1491         const QList<AnchorVertex *> allVertices = graph[edgeOrientation(edge)].adjacentVertices(v);
       
  1492         AnchorVertex *v2;
       
  1493         foreach (v2, allVertices) {
       
  1494             g.removeEdge(v, v2);
       
  1495             removeInternalVertex(item, edge);
       
  1496             removeInternalVertex(v2->m_item, v2->m_edge);
       
  1497         }
       
  1498     }
       
  1499 }
       
  1500 
       
  1501 void QGraphicsAnchorLayoutPrivate::removeAnchors(QGraphicsLayoutItem *item)
       
  1502 {
       
  1503     Q_ASSERT(!graphSimplified[Horizontal] && !graphSimplified[Vertical]);
       
  1504 
       
  1505     // remove the center anchor first!!
       
  1506     removeCenterAnchors(item, Qt::AnchorHorizontalCenter, false);
       
  1507     removeVertex(item, Qt::AnchorLeft);
       
  1508     removeVertex(item, Qt::AnchorRight);
       
  1509 
       
  1510     removeCenterAnchors(item, Qt::AnchorVerticalCenter, false);
       
  1511     removeVertex(item, Qt::AnchorTop);
       
  1512     removeVertex(item, Qt::AnchorBottom);
       
  1513 }
       
  1514 
       
  1515 /*!
       
  1516   \internal
       
  1517 
       
  1518   Use heuristics to determine the correct orientation of a given anchor.
       
  1519 
       
  1520   After API discussions, we decided we would like expressions like
       
  1521   anchor(A, Left, B, Right) to mean the same as anchor(B, Right, A, Left).
       
  1522   The problem with this is that anchors could become ambiguous, for
       
  1523   instance, what does the anchor A, B of size X mean?
       
  1524 
       
  1525      "pos(B) = pos(A) + X"  or  "pos(A) = pos(B) + X" ?
       
  1526 
       
  1527   To keep the API user friendly and at the same time, keep our algorithm
       
  1528   deterministic, we use an heuristic to determine a direction for each
       
  1529   added anchor and then keep it. The heuristic is based on the fact
       
  1530   that people usually avoid overlapping items, therefore:
       
  1531 
       
  1532      "A, RIGHT to B, LEFT" means that B is to the LEFT of A.
       
  1533      "B, LEFT to A, RIGHT" is corrected to the above anchor.
       
  1534 
       
  1535   Special correction is also applied when one of the items is the
       
  1536   layout. We handle Layout Left as if it was another items's Right
       
  1537   and Layout Right as another item's Left.
       
  1538 */
       
  1539 void QGraphicsAnchorLayoutPrivate::correctEdgeDirection(QGraphicsLayoutItem *&firstItem,
       
  1540                                                         Qt::AnchorPoint &firstEdge,
       
  1541                                                         QGraphicsLayoutItem *&secondItem,
       
  1542                                                         Qt::AnchorPoint &secondEdge)
       
  1543 {
       
  1544     Q_Q(QGraphicsAnchorLayout);
       
  1545 
       
  1546     if ((firstItem != q) && (secondItem != q)) {
       
  1547         // If connection is between widgets (not the layout itself)
       
  1548         // Ensure that "right-edges" sit to the left of "left-edges".
       
  1549         if (firstEdge < secondEdge) {
       
  1550             qSwap(firstItem, secondItem);
       
  1551             qSwap(firstEdge, secondEdge);
       
  1552         }
       
  1553     } else if (firstItem == q) {
       
  1554         // If connection involves the right or bottom of a layout, ensure
       
  1555         // the layout is the second item.
       
  1556         if ((firstEdge == Qt::AnchorRight) || (firstEdge == Qt::AnchorBottom)) {
       
  1557             qSwap(firstItem, secondItem);
       
  1558             qSwap(firstEdge, secondEdge);
       
  1559         }
       
  1560     } else if ((secondEdge != Qt::AnchorRight) && (secondEdge != Qt::AnchorBottom)) {
       
  1561         // If connection involves the left, center or top of layout, ensure
       
  1562         // the layout is the first item.
       
  1563         qSwap(firstItem, secondItem);
       
  1564         qSwap(firstEdge, secondEdge);
       
  1565     }
       
  1566 }
       
  1567 
       
  1568 qreal QGraphicsAnchorLayoutPrivate::effectiveSpacing(Orientation orientation) const
       
  1569 {
       
  1570     Q_Q(const QGraphicsAnchorLayout);
       
  1571     qreal s = spacings[orientation];
       
  1572     if (s < 0) {
       
  1573         // ### make sure behaviour is the same as in QGraphicsGridLayout
       
  1574         QGraphicsLayoutItem *parent = q->parentLayoutItem();
       
  1575         while (parent && parent->isLayout()) {
       
  1576             parent = parent->parentLayoutItem();
       
  1577         }
       
  1578         if (parent) {
       
  1579             QGraphicsItem *parentItem = parent->graphicsItem();
       
  1580             if (parentItem && parentItem->isWidget()) {
       
  1581                 QGraphicsWidget *w = static_cast<QGraphicsWidget*>(parentItem);
       
  1582                 s = w->style()->pixelMetric(orientation == Horizontal
       
  1583                                             ? QStyle::PM_LayoutHorizontalSpacing
       
  1584                                             : QStyle::PM_LayoutVerticalSpacing);
       
  1585             }
       
  1586         }
       
  1587     }
       
  1588 
       
  1589     // ### Currently we do not support negative anchors inside the graph.
       
  1590     // To avoid those being created by a negative style spacing, we must
       
  1591     // make this test.
       
  1592     if (s < 0)
       
  1593         s = 0;
       
  1594 
       
  1595     return s;
       
  1596 }
       
  1597 
       
  1598 /*!
       
  1599   \internal
       
  1600 
       
  1601   Called on activation. Uses Linear Programming to define minimum, preferred
       
  1602   and maximum sizes for the layout. Also calculates the sizes that each item
       
  1603   should assume when the layout is in one of such situations.
       
  1604 */
       
  1605 void QGraphicsAnchorLayoutPrivate::calculateGraphs()
       
  1606 {
       
  1607     if (!calculateGraphCacheDirty)
       
  1608         return;
       
  1609 
       
  1610 #if defined(QT_DEBUG) && 0
       
  1611     static int count = 0;
       
  1612     count++;
       
  1613     dumpGraph(QString::fromAscii("%1-before").arg(count));
       
  1614 #endif
       
  1615 
       
  1616     calculateGraphs(Horizontal);
       
  1617     calculateGraphs(Vertical);
       
  1618 
       
  1619 #if defined(QT_DEBUG) && 0
       
  1620     dumpGraph(QString::fromAscii("%1-after").arg(count));
       
  1621 #endif
       
  1622 
       
  1623     calculateGraphCacheDirty = 0;
       
  1624 }
       
  1625 
       
  1626 // ### Maybe getGraphParts could return the variables when traversing, at least
       
  1627 // for trunk...
       
  1628 QList<AnchorData *> getVariables(QList<QSimplexConstraint *> constraints)
       
  1629 {
       
  1630     QSet<AnchorData *> variableSet;
       
  1631     for (int i = 0; i < constraints.count(); ++i) {
       
  1632         const QSimplexConstraint *c = constraints[i];
       
  1633         foreach (QSimplexVariable *var, c->variables.keys()) {
       
  1634             variableSet += static_cast<AnchorData *>(var);
       
  1635         }
       
  1636     }
       
  1637     return variableSet.toList();
       
  1638 }
       
  1639 
       
  1640 /*!
       
  1641   \internal
       
  1642 
       
  1643   Calculate graphs is the method that puts together all the helper routines
       
  1644   so that the AnchorLayout can calculate the sizes of each item.
       
  1645 
       
  1646   In a nutshell it should do:
       
  1647 
       
  1648   1) Update anchor nominal sizes, that is, the size that each anchor would
       
  1649      have if no other restrictions applied. This is done by quering the
       
  1650      layout style and the sizeHints of the items belonging to the layout.
       
  1651 
       
  1652   2) Simplify the graph by grouping together parallel and sequential anchors
       
  1653      into "group anchors". These have equivalent minimum, preferred and maximum
       
  1654      sizeHints as the anchors they replace.
       
  1655 
       
  1656   3) Check if we got to a trivial case. In some cases, the whole graph can be
       
  1657      simplified into a single anchor. If so, use this information. If not,
       
  1658      then call the Simplex solver to calculate the anchors sizes.
       
  1659 
       
  1660   4) Once the root anchors had its sizes calculated, propagate that to the
       
  1661      anchors they represent.
       
  1662 */
       
  1663 void QGraphicsAnchorLayoutPrivate::calculateGraphs(
       
  1664     QGraphicsAnchorLayoutPrivate::Orientation orientation)
       
  1665 {
       
  1666     Q_Q(QGraphicsAnchorLayout);
       
  1667 
       
  1668     // Simplify the graph
       
  1669     simplifyGraph(orientation);
       
  1670 
       
  1671     // Reset the nominal sizes of each anchor based on the current item sizes
       
  1672     setAnchorSizeHintsFromItems(orientation);
       
  1673 
       
  1674     // Traverse all graph edges and store the possible paths to each vertex
       
  1675     findPaths(orientation);
       
  1676 
       
  1677     // From the paths calculated above, extract the constraints that the current
       
  1678     // anchor setup impose, to our Linear Programming problem.
       
  1679     constraintsFromPaths(orientation);
       
  1680 
       
  1681     // Split the constraints and anchors into groups that should be fed to the
       
  1682     // simplex solver independently. Currently we find two groups:
       
  1683     //
       
  1684     //  1) The "trunk", that is, the set of anchors (items) that are connected
       
  1685     //     to the two opposite sides of our layout, and thus need to stretch in
       
  1686     //     order to fit in the current layout size.
       
  1687     //
       
  1688     //  2) The floating or semi-floating anchors (items) that are those which
       
  1689     //     are connected to only one (or none) of the layout sides, thus are not
       
  1690     //     influenced by the layout size.
       
  1691     QList<QList<QSimplexConstraint *> > parts = getGraphParts(orientation);
       
  1692 
       
  1693     // Now run the simplex solver to calculate Minimum, Preferred and Maximum sizes
       
  1694     // of the "trunk" set of constraints and variables.
       
  1695     // ### does trunk always exist? empty = trunk is the layout left->center->right
       
  1696     QList<QSimplexConstraint *> trunkConstraints = parts[0];
       
  1697     QList<AnchorData *> trunkVariables = getVariables(trunkConstraints);
       
  1698 
       
  1699     // For minimum and maximum, use the path between the two layout sides as the
       
  1700     // objective function.
       
  1701     AnchorVertex *v = internalVertex(q, pickEdge(Qt::AnchorRight, orientation));
       
  1702     GraphPath trunkPath = graphPaths[orientation].value(v);
       
  1703 
       
  1704     bool feasible = calculateTrunk(orientation, trunkPath, trunkConstraints, trunkVariables);
       
  1705 
       
  1706     // For the other parts that not the trunk, solve only for the preferred size
       
  1707     // that is the size they will remain at, since they are not stretched by the
       
  1708     // layout.
       
  1709 
       
  1710     // Skipping the first (trunk)
       
  1711     for (int i = 1; i < parts.count(); ++i) {
       
  1712         if (!feasible)
       
  1713             break;
       
  1714 
       
  1715         QList<QSimplexConstraint *> partConstraints = parts[i];
       
  1716         QList<AnchorData *> partVariables = getVariables(partConstraints);
       
  1717         Q_ASSERT(!partVariables.isEmpty());
       
  1718         feasible &= calculateNonTrunk(partConstraints, partVariables);
       
  1719     }
       
  1720 
       
  1721     // Propagate the new sizes down the simplified graph, ie. tell the
       
  1722     // group anchors to set their children anchors sizes.
       
  1723     updateAnchorSizes(orientation);
       
  1724 
       
  1725     graphHasConflicts[orientation] = !feasible;
       
  1726 
       
  1727     // Clean up our data structures. They are not needed anymore since
       
  1728     // distribution uses just interpolation.
       
  1729     qDeleteAll(constraints[orientation]);
       
  1730     constraints[orientation].clear();
       
  1731     graphPaths[orientation].clear(); // ###
       
  1732 }
       
  1733 
       
  1734 /*!
       
  1735     \internal
       
  1736 
       
  1737     Calculate the sizes for all anchors which are part of the trunk. This works
       
  1738     on top of a (possibly) simplified graph.
       
  1739 */
       
  1740 bool QGraphicsAnchorLayoutPrivate::calculateTrunk(Orientation orientation, const GraphPath &path,
       
  1741                                                   const QList<QSimplexConstraint *> &constraints,
       
  1742                                                   const QList<AnchorData *> &variables)
       
  1743 {
       
  1744     bool feasible = true;
       
  1745     bool needsSimplex = !constraints.isEmpty();
       
  1746 
       
  1747 #if 0
       
  1748     qDebug("Simplex %s for trunk of %s", needsSimplex ? "used" : "NOT used",
       
  1749            orientation == Horizontal ? "Horizontal" : "Vertical");
       
  1750 #endif
       
  1751 
       
  1752     if (needsSimplex) {
       
  1753 
       
  1754         QList<QSimplexConstraint *> sizeHintConstraints = constraintsFromSizeHints(variables);
       
  1755         QList<QSimplexConstraint *> allConstraints = constraints + sizeHintConstraints;
       
  1756 
       
  1757         // Solve min and max size hints
       
  1758         qreal min, max;
       
  1759         feasible = solveMinMax(allConstraints, path, &min, &max);
       
  1760 
       
  1761         if (feasible) {
       
  1762             solvePreferred(allConstraints, variables);
       
  1763 
       
  1764             // Note that we don't include the sizeHintConstraints, since they
       
  1765             // have a different logic for solveExpanding().
       
  1766             solveExpanding(constraints, variables);
       
  1767 
       
  1768             // Calculate and set the preferred and expanding sizes for the layout,
       
  1769             // from the edge sizes that were calculated above.
       
  1770             qreal pref(0.0);
       
  1771             qreal expanding(0.0);
       
  1772             foreach (const AnchorData *ad, path.positives) {
       
  1773                 pref += ad->sizeAtPreferred;
       
  1774                 expanding += ad->sizeAtExpanding;
       
  1775             }
       
  1776             foreach (const AnchorData *ad, path.negatives) {
       
  1777                 pref -= ad->sizeAtPreferred;
       
  1778                 expanding -= ad->sizeAtExpanding;
       
  1779             }
       
  1780 
       
  1781             sizeHints[orientation][Qt::MinimumSize] = min;
       
  1782             sizeHints[orientation][Qt::PreferredSize] = pref;
       
  1783             sizeHints[orientation][Qt::MaximumSize] = max;
       
  1784             sizeAtExpanding[orientation] = expanding;
       
  1785         }
       
  1786 
       
  1787         qDeleteAll(sizeHintConstraints);
       
  1788 
       
  1789     } else {
       
  1790         // No Simplex is necessary because the path was simplified all the way to a single
       
  1791         // anchor.
       
  1792         Q_ASSERT(path.positives.count() == 1);
       
  1793         Q_ASSERT(path.negatives.count() == 0);
       
  1794 
       
  1795         AnchorData *ad = path.positives.toList()[0];
       
  1796         ad->sizeAtMinimum = ad->minSize;
       
  1797         ad->sizeAtPreferred = ad->prefSize;
       
  1798         ad->sizeAtExpanding = ad->expSize;
       
  1799         ad->sizeAtMaximum = ad->maxSize;
       
  1800 
       
  1801         sizeHints[orientation][Qt::MinimumSize] = ad->sizeAtMinimum;
       
  1802         sizeHints[orientation][Qt::PreferredSize] = ad->sizeAtPreferred;
       
  1803         sizeHints[orientation][Qt::MaximumSize] = ad->sizeAtMaximum;
       
  1804         sizeAtExpanding[orientation] = ad->sizeAtExpanding;
       
  1805     }
       
  1806 
       
  1807 #if defined(QT_DEBUG) || defined(Q_AUTOTEST_EXPORT)
       
  1808     lastCalculationUsedSimplex[orientation] = needsSimplex;
       
  1809 #endif
       
  1810 
       
  1811     return feasible;
       
  1812 }
       
  1813 
       
  1814 /*!
       
  1815     \internal
       
  1816 */
       
  1817 bool QGraphicsAnchorLayoutPrivate::calculateNonTrunk(const QList<QSimplexConstraint *> &constraints,
       
  1818                                                      const QList<AnchorData *> &variables)
       
  1819 {
       
  1820     QList<QSimplexConstraint *> sizeHintConstraints = constraintsFromSizeHints(variables);
       
  1821     bool feasible = solvePreferred(constraints + sizeHintConstraints, variables);
       
  1822 
       
  1823     if (feasible) {
       
  1824         // Propagate size at preferred to other sizes. Semi-floats always will be
       
  1825         // in their sizeAtPreferred.
       
  1826         for (int j = 0; j < variables.count(); ++j) {
       
  1827             AnchorData *ad = variables[j];
       
  1828             Q_ASSERT(ad);
       
  1829             ad->sizeAtMinimum = ad->sizeAtPreferred;
       
  1830             ad->sizeAtExpanding = ad->sizeAtPreferred;
       
  1831             ad->sizeAtMaximum = ad->sizeAtPreferred;
       
  1832         }
       
  1833     }
       
  1834 
       
  1835     qDeleteAll(sizeHintConstraints);
       
  1836     return feasible;
       
  1837 }
       
  1838 
       
  1839 /*!
       
  1840   \internal
       
  1841 
       
  1842   For graph edges ("anchors") that represent items, this method updates their
       
  1843   intrinsic size restrictions, based on the item size hints.
       
  1844 */
       
  1845 void QGraphicsAnchorLayoutPrivate::setAnchorSizeHintsFromItems(Orientation orientation)
       
  1846 {
       
  1847     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
       
  1848     QList<QPair<AnchorVertex *, AnchorVertex *> > vertices = g.connections();
       
  1849 
       
  1850     qreal spacing = effectiveSpacing(orientation);
       
  1851 
       
  1852     for (int i = 0; i < vertices.count(); ++i) {
       
  1853         AnchorData *data = g.edgeData(vertices.at(i).first, vertices.at(i).second);;
       
  1854         Q_ASSERT(data->from && data->to);
       
  1855         data->refreshSizeHints(spacing);
       
  1856     }
       
  1857 }
       
  1858 
       
  1859 /*!
       
  1860   \internal
       
  1861 
       
  1862   This method walks the graph using a breadth-first search to find paths
       
  1863   between the root vertex and each vertex on the graph. The edges
       
  1864   directions in each path are considered and they are stored as a
       
  1865   positive edge (left-to-right) or negative edge (right-to-left).
       
  1866 
       
  1867   The list of paths is used later to generate a list of constraints.
       
  1868  */
       
  1869 void QGraphicsAnchorLayoutPrivate::findPaths(Orientation orientation)
       
  1870 {
       
  1871     QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;
       
  1872 
       
  1873     QSet<AnchorData *> visited;
       
  1874 
       
  1875     AnchorVertex *root = graph[orientation].rootVertex();
       
  1876 
       
  1877     graphPaths[orientation].insert(root, GraphPath());
       
  1878 
       
  1879     foreach (AnchorVertex *v, graph[orientation].adjacentVertices(root)) {
       
  1880         queue.enqueue(qMakePair(root, v));
       
  1881     }
       
  1882 
       
  1883     while(!queue.isEmpty()) {
       
  1884         QPair<AnchorVertex *, AnchorVertex *>  pair = queue.dequeue();
       
  1885         AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second);
       
  1886 
       
  1887         if (visited.contains(edge))
       
  1888             continue;
       
  1889 
       
  1890         visited.insert(edge);
       
  1891         GraphPath current = graphPaths[orientation].value(pair.first);
       
  1892 
       
  1893         if (edge->from == pair.first)
       
  1894             current.positives.insert(edge);
       
  1895         else
       
  1896             current.negatives.insert(edge);
       
  1897 
       
  1898         graphPaths[orientation].insert(pair.second, current);
       
  1899 
       
  1900         foreach (AnchorVertex *v,
       
  1901                 graph[orientation].adjacentVertices(pair.second)) {
       
  1902             queue.enqueue(qMakePair(pair.second, v));
       
  1903         }
       
  1904     }
       
  1905 
       
  1906     // We will walk through every reachable items (non-float) store them in a temporary set.
       
  1907     // We them create a set of all items and subtract the non-floating items from the set in
       
  1908     // order to get the floating items. The floating items is then stored in m_floatItems
       
  1909     identifyFloatItems(visited, orientation);
       
  1910 }
       
  1911 
       
  1912 /*!
       
  1913   \internal
       
  1914 
       
  1915   Each vertex on the graph that has more than one path to it
       
  1916   represents a contra int to the sizes of the items in these paths.
       
  1917 
       
  1918   This method walks the list of paths to each vertex, generate
       
  1919   the constraints and store them in a list so they can be used later
       
  1920   by the Simplex solver.
       
  1921 */
       
  1922 void QGraphicsAnchorLayoutPrivate::constraintsFromPaths(Orientation orientation)
       
  1923 {
       
  1924     foreach (AnchorVertex *vertex, graphPaths[orientation].uniqueKeys())
       
  1925     {
       
  1926         int valueCount = graphPaths[orientation].count(vertex);
       
  1927         if (valueCount == 1)
       
  1928             continue;
       
  1929 
       
  1930         QList<GraphPath> pathsToVertex = graphPaths[orientation].values(vertex);
       
  1931         for (int i = 1; i < valueCount; ++i) {
       
  1932             constraints[orientation] += \
       
  1933                 pathsToVertex[0].constraint(pathsToVertex[i]);
       
  1934         }
       
  1935     }
       
  1936 }
       
  1937 
       
  1938 /*!
       
  1939   \internal
       
  1940 */
       
  1941 void QGraphicsAnchorLayoutPrivate::updateAnchorSizes(Orientation orientation)
       
  1942 {
       
  1943     Graph<AnchorVertex, AnchorData> &g = graph[orientation];
       
  1944     const QList<QPair<AnchorVertex *, AnchorVertex *> > &vertices = g.connections();
       
  1945 
       
  1946     for (int i = 0; i < vertices.count(); ++i) {
       
  1947         AnchorData *ad = g.edgeData(vertices.at(i).first, vertices.at(i).second);
       
  1948         ad->updateChildrenSizes();
       
  1949     }
       
  1950 }
       
  1951 
       
  1952 /*!
       
  1953   \internal
       
  1954 
       
  1955   Create LP constraints for each anchor based on its minimum and maximum
       
  1956   sizes, as specified in its size hints
       
  1957 */
       
  1958 QList<QSimplexConstraint *> QGraphicsAnchorLayoutPrivate::constraintsFromSizeHints(
       
  1959     const QList<AnchorData *> &anchors)
       
  1960 {
       
  1961     QList<QSimplexConstraint *> anchorConstraints;
       
  1962     for (int i = 0; i < anchors.size(); ++i) {
       
  1963         QSimplexConstraint *c = new QSimplexConstraint;
       
  1964         c->variables.insert(anchors[i], 1.0);
       
  1965         c->constant = anchors[i]->minSize;
       
  1966         c->ratio = QSimplexConstraint::MoreOrEqual;
       
  1967         anchorConstraints += c;
       
  1968 
       
  1969         c = new QSimplexConstraint;
       
  1970         c->variables.insert(anchors[i], 1.0);
       
  1971         c->constant = anchors[i]->maxSize;
       
  1972         c->ratio = QSimplexConstraint::LessOrEqual;
       
  1973         anchorConstraints += c;
       
  1974     }
       
  1975 
       
  1976     return anchorConstraints;
       
  1977 }
       
  1978 
       
  1979 /*!
       
  1980   \internal
       
  1981 */
       
  1982 QList< QList<QSimplexConstraint *> >
       
  1983 QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation)
       
  1984 {
       
  1985     Q_Q(QGraphicsAnchorLayout);
       
  1986 
       
  1987     // Find layout vertices and edges for the current orientation.
       
  1988     AnchorVertex *layoutFirstVertex = \
       
  1989         internalVertex(q, pickEdge(Qt::AnchorLeft, orientation));
       
  1990 
       
  1991     AnchorVertex *layoutCentralVertex = \
       
  1992         internalVertex(q, pickEdge(Qt::AnchorHorizontalCenter, orientation));
       
  1993 
       
  1994     AnchorVertex *layoutLastVertex = \
       
  1995         internalVertex(q, pickEdge(Qt::AnchorRight, orientation));
       
  1996 
       
  1997     Q_ASSERT(layoutFirstVertex && layoutLastVertex);
       
  1998 
       
  1999     AnchorData *edgeL1 = NULL;
       
  2000     AnchorData *edgeL2 = NULL;
       
  2001 
       
  2002     // The layout may have a single anchor between Left and Right or two half anchors
       
  2003     // passing through the center
       
  2004     if (layoutCentralVertex) {
       
  2005         edgeL1 = graph[orientation].edgeData(layoutFirstVertex, layoutCentralVertex);
       
  2006         edgeL2 = graph[orientation].edgeData(layoutCentralVertex, layoutLastVertex);
       
  2007     } else {
       
  2008         edgeL1 = graph[orientation].edgeData(layoutFirstVertex, layoutLastVertex);
       
  2009     }
       
  2010 
       
  2011     QLinkedList<QSimplexConstraint *> remainingConstraints;
       
  2012     for (int i = 0; i < constraints[orientation].count(); ++i) {
       
  2013         remainingConstraints += constraints[orientation][i];
       
  2014     }
       
  2015     for (int i = 0; i < itemCenterConstraints[orientation].count(); ++i) {
       
  2016         remainingConstraints += itemCenterConstraints[orientation][i];
       
  2017     }
       
  2018 
       
  2019     QList<QSimplexConstraint *> trunkConstraints;
       
  2020     QSet<QSimplexVariable *> trunkVariables;
       
  2021 
       
  2022     trunkVariables += edgeL1;
       
  2023     if (edgeL2)
       
  2024         trunkVariables += edgeL2;
       
  2025 
       
  2026     bool dirty;
       
  2027     do {
       
  2028         dirty = false;
       
  2029 
       
  2030         QLinkedList<QSimplexConstraint *>::iterator it = remainingConstraints.begin();
       
  2031         while (it != remainingConstraints.end()) {
       
  2032             QSimplexConstraint *c = *it;
       
  2033             bool match = false;
       
  2034 
       
  2035             // Check if this constraint have some overlap with current
       
  2036             // trunk variables...
       
  2037             foreach (QSimplexVariable *ad, trunkVariables) {
       
  2038                 if (c->variables.contains(ad)) {
       
  2039                     match = true;
       
  2040                     break;
       
  2041                 }
       
  2042             }
       
  2043 
       
  2044             // If so, we add it to trunk, and erase it from the
       
  2045             // remaining constraints.
       
  2046             if (match) {
       
  2047                 trunkConstraints += c;
       
  2048                 trunkVariables += QSet<QSimplexVariable *>::fromList(c->variables.keys());
       
  2049                 it = remainingConstraints.erase(it);
       
  2050                 dirty = true;
       
  2051             } else {
       
  2052                 // Note that we don't erase the constraint if it's not
       
  2053                 // a match, since in a next iteration of a do-while we
       
  2054                 // can pass on it again and it will be a match.
       
  2055                 //
       
  2056                 // For example: if trunk share a variable with
       
  2057                 // remainingConstraints[1] and it shares with
       
  2058                 // remainingConstraints[0], we need a second iteration
       
  2059                 // of the do-while loop to match both.
       
  2060                 ++it;
       
  2061             }
       
  2062         }
       
  2063     } while (dirty);
       
  2064 
       
  2065     QList< QList<QSimplexConstraint *> > result;
       
  2066     result += trunkConstraints;
       
  2067 
       
  2068     if (!remainingConstraints.isEmpty()) {
       
  2069         QList<QSimplexConstraint *> nonTrunkConstraints;
       
  2070         QLinkedList<QSimplexConstraint *>::iterator it = remainingConstraints.begin();
       
  2071         while (it != remainingConstraints.end()) {
       
  2072             nonTrunkConstraints += *it;
       
  2073             ++it;
       
  2074         }
       
  2075         result += nonTrunkConstraints;
       
  2076     }
       
  2077 
       
  2078     return result;
       
  2079 }
       
  2080 
       
  2081 /*!
       
  2082  \internal
       
  2083 
       
  2084   Use all visited Anchors on findPaths() so we can identify non-float Items.
       
  2085 */
       
  2086 void QGraphicsAnchorLayoutPrivate::identifyFloatItems(const QSet<AnchorData *> &visited, Orientation orientation)
       
  2087 {
       
  2088     QSet<QGraphicsLayoutItem *> nonFloating;
       
  2089 
       
  2090     foreach (const AnchorData *ad, visited)
       
  2091         identifyNonFloatItems_helper(ad, &nonFloating);
       
  2092 
       
  2093     QSet<QGraphicsLayoutItem *> allItems;
       
  2094     foreach (QGraphicsLayoutItem *item, items)
       
  2095         allItems.insert(item);
       
  2096     m_floatItems[orientation] = allItems - nonFloating;
       
  2097 }
       
  2098 
       
  2099 
       
  2100 /*!
       
  2101  \internal
       
  2102 
       
  2103   Given an anchor, if it is an internal anchor and Normal we must mark it's item as non-float.
       
  2104   If the anchor is Sequential or Parallel, we must iterate on its children recursively until we reach
       
  2105   internal anchors (items).
       
  2106 */
       
  2107 void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems_helper(const AnchorData *ad, QSet<QGraphicsLayoutItem *> *nonFloatingItemsIdentifiedSoFar)
       
  2108 {
       
  2109     Q_Q(QGraphicsAnchorLayout);
       
  2110 
       
  2111     switch(ad->type) {
       
  2112     case AnchorData::Normal:
       
  2113         if (ad->from->m_item == ad->to->m_item && ad->to->m_item != q)
       
  2114             nonFloatingItemsIdentifiedSoFar->insert(ad->to->m_item);
       
  2115         break;
       
  2116     case AnchorData::Sequential:
       
  2117         foreach (const AnchorData *d, static_cast<const SequentialAnchorData *>(ad)->m_edges)
       
  2118             identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar);
       
  2119         break;
       
  2120     case AnchorData::Parallel:
       
  2121         identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->firstEdge, nonFloatingItemsIdentifiedSoFar);
       
  2122         identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->secondEdge, nonFloatingItemsIdentifiedSoFar);
       
  2123         break;
       
  2124     }
       
  2125 }
       
  2126 
       
  2127 /*!
       
  2128   \internal
       
  2129 
       
  2130   Use the current vertices distance to calculate and set the geometry of
       
  2131   each item.
       
  2132 */
       
  2133 void QGraphicsAnchorLayoutPrivate::setItemsGeometries(const QRectF &geom)
       
  2134 {
       
  2135     Q_Q(QGraphicsAnchorLayout);
       
  2136     AnchorVertex *firstH, *secondH, *firstV, *secondV;
       
  2137 
       
  2138     qreal top;
       
  2139     qreal left;
       
  2140     qreal right;
       
  2141 
       
  2142     q->getContentsMargins(&left, &top, &right, 0);
       
  2143     const Qt::LayoutDirection visualDir = visualDirection();
       
  2144     if (visualDir == Qt::RightToLeft)
       
  2145         qSwap(left, right);
       
  2146 
       
  2147     left += geom.left();
       
  2148     top += geom.top();
       
  2149     right = geom.right() - right;
       
  2150 
       
  2151     foreach (QGraphicsLayoutItem *item, items) {
       
  2152         QRectF newGeom;
       
  2153         QSizeF itemPreferredSize = item->effectiveSizeHint(Qt::PreferredSize);
       
  2154         if (m_floatItems[Horizontal].contains(item)) {
       
  2155             newGeom.setLeft(0);
       
  2156             newGeom.setRight(itemPreferredSize.width());
       
  2157         } else {
       
  2158             firstH = internalVertex(item, Qt::AnchorLeft);
       
  2159             secondH = internalVertex(item, Qt::AnchorRight);
       
  2160 
       
  2161             if (visualDir == Qt::LeftToRight) {
       
  2162                 newGeom.setLeft(left + firstH->distance);
       
  2163                 newGeom.setRight(left + secondH->distance);
       
  2164             } else {
       
  2165                 newGeom.setLeft(right - secondH->distance);
       
  2166                 newGeom.setRight(right - firstH->distance);
       
  2167             }
       
  2168         }
       
  2169 
       
  2170         if (m_floatItems[Vertical].contains(item)) {
       
  2171             newGeom.setTop(0);
       
  2172             newGeom.setBottom(itemPreferredSize.height());
       
  2173         } else {
       
  2174             firstV = internalVertex(item, Qt::AnchorTop);
       
  2175             secondV = internalVertex(item, Qt::AnchorBottom);
       
  2176 
       
  2177             newGeom.setTop(top + firstV->distance);
       
  2178             newGeom.setBottom(top + secondV->distance);
       
  2179         }
       
  2180 
       
  2181         item->setGeometry(newGeom);
       
  2182     }
       
  2183 }
       
  2184 
       
  2185 /*!
       
  2186   \internal
       
  2187 
       
  2188   Calculate the position of each vertex based on the paths to each of
       
  2189   them as well as the current edges sizes.
       
  2190 */
       
  2191 void QGraphicsAnchorLayoutPrivate::calculateVertexPositions(
       
  2192     QGraphicsAnchorLayoutPrivate::Orientation orientation)
       
  2193 {
       
  2194     QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;
       
  2195     QSet<AnchorVertex *> visited;
       
  2196 
       
  2197     // Get root vertex
       
  2198     AnchorVertex *root = graph[orientation].rootVertex();
       
  2199 
       
  2200     root->distance = 0;
       
  2201     visited.insert(root);
       
  2202 
       
  2203     // Add initial edges to the queue
       
  2204     foreach (AnchorVertex *v, graph[orientation].adjacentVertices(root)) {
       
  2205         queue.enqueue(qMakePair(root, v));
       
  2206     }
       
  2207 
       
  2208     // Do initial calculation required by "interpolateEdge()"
       
  2209     setupEdgesInterpolation(orientation);
       
  2210 
       
  2211     // Traverse the graph and calculate vertex positions, we need to
       
  2212     // visit all pairs since each of them could have a sequential
       
  2213     // anchor inside, which hides more vertices.
       
  2214     while (!queue.isEmpty()) {
       
  2215         QPair<AnchorVertex *, AnchorVertex *> pair = queue.dequeue();
       
  2216         AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second);
       
  2217 
       
  2218         // Both vertices were interpolated, and the anchor itself can't have other
       
  2219         // anchors inside (it's not a complex anchor).
       
  2220         if (edge->type == AnchorData::Normal && visited.contains(pair.second))
       
  2221             continue;
       
  2222 
       
  2223         visited.insert(pair.second);
       
  2224         interpolateEdge(pair.first, edge, orientation);
       
  2225 
       
  2226         QList<AnchorVertex *> adjacents = graph[orientation].adjacentVertices(pair.second);
       
  2227         for (int i = 0; i < adjacents.count(); ++i) {
       
  2228             if (!visited.contains(adjacents.at(i)))
       
  2229                 queue.enqueue(qMakePair(pair.second, adjacents.at(i)));
       
  2230         }
       
  2231     }
       
  2232 }
       
  2233 
       
  2234 /*!
       
  2235   \internal
       
  2236 
       
  2237   Calculate interpolation parameters based on current Layout Size.
       
  2238   Must be called once before calling "interpolateEdgeSize()" for
       
  2239   the edges.
       
  2240 */
       
  2241 void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation(
       
  2242     Orientation orientation)
       
  2243 {
       
  2244     Q_Q(QGraphicsAnchorLayout);
       
  2245 
       
  2246     qreal current;
       
  2247     current = (orientation == Horizontal) ? q->contentsRect().width() : q->contentsRect().height();
       
  2248 
       
  2249     QPair<Interval, qreal> result;
       
  2250     result = getFactor(current,
       
  2251                        sizeHints[orientation][Qt::MinimumSize],
       
  2252                        sizeHints[orientation][Qt::PreferredSize],
       
  2253                        sizeAtExpanding[orientation],
       
  2254                        sizeHints[orientation][Qt::MaximumSize]);
       
  2255 
       
  2256     interpolationInterval[orientation] = result.first;
       
  2257     interpolationProgress[orientation] = result.second;
       
  2258 }
       
  2259 
       
  2260 /*!
       
  2261   \internal
       
  2262 
       
  2263   Calculate the current Edge size based on the current Layout size and the
       
  2264   size the edge is supposed to have when the layout is at its:
       
  2265 
       
  2266    - minimum size,
       
  2267    - preferred size,
       
  2268    - size when all expanding anchors are expanded,
       
  2269    - maximum size.
       
  2270 
       
  2271    These three key values are calculated in advance using linear
       
  2272    programming (more expensive) or the simplification algorithm, then
       
  2273    subsequential resizes of the parent layout require a simple
       
  2274    interpolation.
       
  2275 
       
  2276    If the edge is sequential or parallel, it's possible to have more
       
  2277    vertices to be initalized, so it calls specialized functions that
       
  2278    will recurse back to interpolateEdge().
       
  2279  */
       
  2280 void QGraphicsAnchorLayoutPrivate::interpolateEdge(AnchorVertex *base,
       
  2281                                                    AnchorData *edge,
       
  2282                                                    Orientation orientation)
       
  2283 {
       
  2284     const QPair<Interval, qreal> factor(interpolationInterval[orientation],
       
  2285                                         interpolationProgress[orientation]);
       
  2286 
       
  2287     qreal edgeDistance = interpolate(factor, edge->sizeAtMinimum, edge->sizeAtPreferred,
       
  2288                                      edge->sizeAtExpanding, edge->sizeAtMaximum);
       
  2289 
       
  2290     Q_ASSERT(edge->from == base || edge->to == base);
       
  2291 
       
  2292     if (edge->from == base)
       
  2293         edge->to->distance = base->distance + edgeDistance;
       
  2294     else
       
  2295         edge->from->distance = base->distance - edgeDistance;
       
  2296 
       
  2297     // Process child anchors
       
  2298     if (edge->type == AnchorData::Sequential)
       
  2299         interpolateSequentialEdges(edge->from,
       
  2300                                    static_cast<SequentialAnchorData *>(edge),
       
  2301                                    orientation);
       
  2302     else if (edge->type == AnchorData::Parallel)
       
  2303         interpolateParallelEdges(edge->from,
       
  2304                                  static_cast<ParallelAnchorData *>(edge),
       
  2305                                  orientation);
       
  2306 }
       
  2307 
       
  2308 void QGraphicsAnchorLayoutPrivate::interpolateParallelEdges(
       
  2309     AnchorVertex *base, ParallelAnchorData *data, Orientation orientation)
       
  2310 {
       
  2311     // In parallels the boundary vertices are already calculate, we
       
  2312     // just need to look for sequential groups inside, because only
       
  2313     // them may have new vertices associated.
       
  2314 
       
  2315     // First edge
       
  2316     if (data->firstEdge->type == AnchorData::Sequential)
       
  2317         interpolateSequentialEdges(base,
       
  2318                                    static_cast<SequentialAnchorData *>(data->firstEdge),
       
  2319                                    orientation);
       
  2320     else if (data->firstEdge->type == AnchorData::Parallel)
       
  2321         interpolateParallelEdges(base,
       
  2322                                  static_cast<ParallelAnchorData *>(data->firstEdge),
       
  2323                                  orientation);
       
  2324 
       
  2325     // Second edge
       
  2326     if (data->secondEdge->type == AnchorData::Sequential)
       
  2327         interpolateSequentialEdges(base,
       
  2328                                    static_cast<SequentialAnchorData *>(data->secondEdge),
       
  2329                                    orientation);
       
  2330     else if (data->secondEdge->type == AnchorData::Parallel)
       
  2331         interpolateParallelEdges(base,
       
  2332                                  static_cast<ParallelAnchorData *>(data->secondEdge),
       
  2333                                  orientation);
       
  2334 }
       
  2335 
       
  2336 void QGraphicsAnchorLayoutPrivate::interpolateSequentialEdges(
       
  2337     AnchorVertex *base, SequentialAnchorData *data, Orientation orientation)
       
  2338 {
       
  2339     AnchorVertex *prev = base;
       
  2340 
       
  2341     // ### I'm not sure whether this assumption is safe. If not,
       
  2342     // consider that m_edges.last() could be used instead (so
       
  2343     // at(0) would be the one to be treated specially).
       
  2344     Q_ASSERT(base == data->m_edges.at(0)->to || base == data->m_edges.at(0)->from);
       
  2345 
       
  2346     // Skip the last
       
  2347     for (int i = 0; i < data->m_edges.count() - 1; ++i) {
       
  2348         AnchorData *child = data->m_edges.at(i);
       
  2349         interpolateEdge(prev, child, orientation);
       
  2350         prev = child->to;
       
  2351     }
       
  2352 
       
  2353     // Treat the last specially, since we already calculated it's end
       
  2354     // vertex, so it's only interesting if it's a complex one
       
  2355     if (data->m_edges.last()->type != AnchorData::Normal)
       
  2356         interpolateEdge(prev, data->m_edges.last(), orientation);
       
  2357 }
       
  2358 
       
  2359 bool QGraphicsAnchorLayoutPrivate::solveMinMax(const QList<QSimplexConstraint *> &constraints,
       
  2360                                                GraphPath path, qreal *min, qreal *max)
       
  2361 {
       
  2362     QSimplex simplex;
       
  2363     bool feasible = simplex.setConstraints(constraints);
       
  2364     if (feasible) {
       
  2365         // Obtain the objective constraint
       
  2366         QSimplexConstraint objective;
       
  2367         QSet<AnchorData *>::const_iterator iter;
       
  2368         for (iter = path.positives.constBegin(); iter != path.positives.constEnd(); ++iter)
       
  2369             objective.variables.insert(*iter, 1.0);
       
  2370 
       
  2371         for (iter = path.negatives.constBegin(); iter != path.negatives.constEnd(); ++iter)
       
  2372             objective.variables.insert(*iter, -1.0);
       
  2373 
       
  2374         simplex.setObjective(&objective);
       
  2375 
       
  2376         // Calculate minimum values
       
  2377         *min = simplex.solveMin();
       
  2378 
       
  2379         // Save sizeAtMinimum results
       
  2380         QList<QSimplexVariable *> variables = simplex.constraintsVariables();
       
  2381         for (int i = 0; i < variables.size(); ++i) {
       
  2382             AnchorData *ad = static_cast<AnchorData *>(variables[i]);
       
  2383             Q_ASSERT(ad->result >= ad->minSize || qFuzzyCompare(ad->result, ad->minSize));
       
  2384             ad->sizeAtMinimum = ad->result;
       
  2385         }
       
  2386 
       
  2387         // Calculate maximum values
       
  2388         *max = simplex.solveMax();
       
  2389 
       
  2390         // Save sizeAtMaximum results
       
  2391         for (int i = 0; i < variables.size(); ++i) {
       
  2392             AnchorData *ad = static_cast<AnchorData *>(variables[i]);
       
  2393             Q_ASSERT(ad->result <= ad->maxSize || qFuzzyCompare(ad->result, ad->maxSize));
       
  2394             ad->sizeAtMaximum = ad->result;
       
  2395         }
       
  2396     }
       
  2397     return feasible;
       
  2398 }
       
  2399 
       
  2400 bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint *> &constraints,
       
  2401                                                   const QList<AnchorData *> &variables)
       
  2402 {
       
  2403     QList<QSimplexConstraint *> preferredConstraints;
       
  2404     QList<QSimplexVariable *> preferredVariables;
       
  2405     QSimplexConstraint objective;
       
  2406 
       
  2407     // Fill the objective coefficients for this variable. In the
       
  2408     // end the objective function will be
       
  2409     //
       
  2410     //     z = n * (A_shrink + B_shrink + ...) + (A_grower + B_grower + ...)
       
  2411     //
       
  2412     // where n is the number of variables that have
       
  2413     // slacks. Note that here we use the number of variables
       
  2414     // as coefficient, this is to mark the "shrinker slack
       
  2415     // variable" less likely to get value than the "grower
       
  2416     // slack variable".
       
  2417 
       
  2418     // This will fill the values for the structural constraints
       
  2419     // and we now fill the values for the slack constraints (one per variable),
       
  2420     // which have this form (the constant A_pref was set when creating the slacks):
       
  2421     //
       
  2422     //      A + A_shrinker - A_grower = A_pref
       
  2423     //
       
  2424     for (int i = 0; i < variables.size(); ++i) {
       
  2425         AnchorData *ad = variables[i];
       
  2426         if (ad->skipInPreferred)
       
  2427             continue;
       
  2428 
       
  2429         QSimplexVariable *grower = new QSimplexVariable;
       
  2430         QSimplexVariable *shrinker = new QSimplexVariable;
       
  2431         QSimplexConstraint *c = new QSimplexConstraint;
       
  2432         c->variables.insert(ad, 1.0);
       
  2433         c->variables.insert(shrinker, 1.0);
       
  2434         c->variables.insert(grower, -1.0);
       
  2435         c->constant = ad->prefSize;
       
  2436 
       
  2437         preferredConstraints += c;
       
  2438         preferredVariables += grower;
       
  2439         preferredVariables += shrinker;
       
  2440 
       
  2441         objective.variables.insert(grower, 1.0);
       
  2442         objective.variables.insert(shrinker, variables.size());
       
  2443     }
       
  2444 
       
  2445 
       
  2446     QSimplex *simplex = new QSimplex;
       
  2447     bool feasible = simplex->setConstraints(constraints + preferredConstraints);
       
  2448     if (feasible) {
       
  2449         simplex->setObjective(&objective);
       
  2450 
       
  2451         // Calculate minimum values
       
  2452         simplex->solveMin();
       
  2453 
       
  2454         // Save sizeAtPreferred results
       
  2455         for (int i = 0; i < variables.size(); ++i) {
       
  2456             AnchorData *ad = variables[i];
       
  2457             ad->sizeAtPreferred = ad->result;
       
  2458         }
       
  2459 
       
  2460         // Make sure we delete the simplex solver -before- we delete the
       
  2461         // constraints used by it.
       
  2462         delete simplex;
       
  2463     }
       
  2464     // Delete constraints and variables we created.
       
  2465     qDeleteAll(preferredConstraints);
       
  2466     qDeleteAll(preferredVariables);
       
  2467 
       
  2468     return feasible;
       
  2469 }
       
  2470 
       
  2471 /*!
       
  2472     \internal
       
  2473     Calculate the "expanding" keyframe
       
  2474 
       
  2475     This new keyframe sits between the already existing sizeAtPreferred and
       
  2476     sizeAtMaximum keyframes. Its goal is to modify the interpolation between
       
  2477     the latter as to respect the "expanding" size policy of some anchors.
       
  2478 
       
  2479     Previously all items would be subject to a linear interpolation between
       
  2480     sizeAtPreferred and sizeAtMaximum values. This will change now, the
       
  2481     expanding anchors will change their size before the others. To calculate
       
  2482     this keyframe we use the following logic:
       
  2483 
       
  2484     1) Ask each anchor for their desired expanding size (ad->expSize), this
       
  2485     value depends on the anchor expanding property in the following way:
       
  2486 
       
  2487     - Expanding normal anchors want to grow towards their maximum size
       
  2488     - Non-expanding normal anchors want to remain at their preferred size.
       
  2489     - Sequential anchors wants to grow towards a size that is calculated by:
       
  2490         summarizing it's child anchors, where it will use preferred size for non-expanding anchors
       
  2491         and maximum size for expanding anchors.
       
  2492     - Parallel anchors want to grow towards the smallest maximum size of all the expanding anchors.
       
  2493 
       
  2494     2) Clamp their desired values to the value they assume in the neighbour
       
  2495     keyframes (sizeAtPreferred and sizeAtExpanding)
       
  2496 
       
  2497     3) Run simplex with a setup that ensures the following:
       
  2498 
       
  2499       a. Anchors will change their value from their sizeAtPreferred towards
       
  2500          their sizeAtMaximum as much as required to ensure that ALL anchors
       
  2501          reach their respective "desired" expanding sizes.
       
  2502 
       
  2503       b. No anchors will change their value beyond what is NEEDED to satisfy
       
  2504          the requirement above.
       
  2505 
       
  2506     The final result is that, at the "expanding" keyframe expanding anchors
       
  2507     will grow and take with them all anchors that are parallel to them.
       
  2508     However, non-expanding anchors will remain at their preferred size unless
       
  2509     they are forced to grow by a parallel expanding anchor.
       
  2510 
       
  2511     Note: For anchors where the sizeAtPreferred is bigger than sizeAtMaximum,
       
  2512           the visual effect when the layout grows from its preferred size is
       
  2513           the following: Expanding anchors will keep their size while non
       
  2514           expanding ones will shrink. Only after non-expanding anchors have
       
  2515           shrinked all the way, the expanding anchors will start to shrink too.
       
  2516 */
       
  2517 void QGraphicsAnchorLayoutPrivate::solveExpanding(const QList<QSimplexConstraint *> &constraints,
       
  2518                                                   const QList<AnchorData *> &variables)
       
  2519 {
       
  2520     QList<QSimplexConstraint *> itemConstraints;
       
  2521     QSimplexConstraint *objective = new QSimplexConstraint;
       
  2522     bool hasExpanding = false;
       
  2523 
       
  2524     // Construct the simplex constraints and objective
       
  2525     for (int i = 0; i < variables.size(); ++i) {
       
  2526         // For each anchor
       
  2527         AnchorData *ad = variables[i];
       
  2528 
       
  2529         // Clamp the desired expanding size
       
  2530         qreal upperBoundary = qMax(ad->sizeAtPreferred, ad->sizeAtMaximum);
       
  2531         qreal lowerBoundary = qMin(ad->sizeAtPreferred, ad->sizeAtMaximum);
       
  2532         qreal boundedExpSize = qBound(lowerBoundary, ad->expSize, upperBoundary);
       
  2533 
       
  2534         // Expanding anchors are those that want to move from their preferred size
       
  2535         if (boundedExpSize != ad->sizeAtPreferred)
       
  2536             hasExpanding = true;
       
  2537 
       
  2538         // Lock anchor between boundedExpSize and sizeAtMaximum (ensure 3.a)
       
  2539         if (boundedExpSize == ad->sizeAtMaximum) {
       
  2540             // The interval has only one possible value, we can use an "Equal"
       
  2541             // constraint and don't need to add this variable to the objective.
       
  2542             QSimplexConstraint *itemC = new QSimplexConstraint;
       
  2543             itemC->ratio = QSimplexConstraint::Equal;
       
  2544             itemC->variables.insert(ad, 1.0);
       
  2545             itemC->constant = boundedExpSize;
       
  2546             itemConstraints << itemC;
       
  2547         } else {
       
  2548             // Add MoreOrEqual and LessOrEqual constraints.
       
  2549             QSimplexConstraint *itemC = new QSimplexConstraint;
       
  2550             itemC->ratio = QSimplexConstraint::MoreOrEqual;
       
  2551             itemC->variables.insert(ad, 1.0);
       
  2552             itemC->constant = qMin(boundedExpSize, ad->sizeAtMaximum);
       
  2553             itemConstraints << itemC;
       
  2554 
       
  2555             itemC = new QSimplexConstraint;
       
  2556             itemC->ratio = QSimplexConstraint::LessOrEqual;
       
  2557             itemC->variables.insert(ad, 1.0);
       
  2558             itemC->constant = qMax(boundedExpSize, ad->sizeAtMaximum);
       
  2559             itemConstraints << itemC;
       
  2560 
       
  2561             // Create objective to avoid the anchors from moving away from
       
  2562             // the preferred size more than the needed amount. (ensure 3.b)
       
  2563             // The objective function is the distance between sizeAtPreferred
       
  2564             // and sizeAtExpanding, it will be minimized.
       
  2565             if (ad->sizeAtExpanding < ad->sizeAtMaximum) {
       
  2566                 // Try to shrink this variable towards its sizeAtPreferred value
       
  2567                 objective->variables.insert(ad, 1.0);
       
  2568             } else {
       
  2569                 // Try to grow this variable towards its sizeAtPreferred value
       
  2570                 objective->variables.insert(ad, -1.0);
       
  2571             }
       
  2572         }
       
  2573     }
       
  2574 
       
  2575     // Solve
       
  2576     if (hasExpanding == false) {
       
  2577         // If no anchors are expanding, we don't need to run the simplex
       
  2578         // Set all variables to their preferred size
       
  2579         for (int i = 0; i < variables.size(); ++i) {
       
  2580             variables[i]->sizeAtExpanding = variables[i]->sizeAtPreferred;
       
  2581         }
       
  2582     } else {
       
  2583         // Run simplex
       
  2584         QSimplex simplex;
       
  2585 
       
  2586         // Satisfy expanding (3.a)
       
  2587         bool feasible = simplex.setConstraints(constraints + itemConstraints);
       
  2588         Q_ASSERT(feasible);
       
  2589 
       
  2590         // Reduce damage (3.b)
       
  2591         simplex.setObjective(objective);
       
  2592         simplex.solveMin();
       
  2593 
       
  2594         // Collect results
       
  2595         for (int i = 0; i < variables.size(); ++i) {
       
  2596             variables[i]->sizeAtExpanding = variables[i]->result;
       
  2597         }
       
  2598     }
       
  2599 
       
  2600     delete objective;
       
  2601     qDeleteAll(itemConstraints);
       
  2602 }
       
  2603 
       
  2604 /*!
       
  2605     \internal
       
  2606     Returns true if there are no arrangement that satisfies all constraints.
       
  2607     Otherwise returns false.
       
  2608 
       
  2609     \sa addAnchor()
       
  2610 */
       
  2611 bool QGraphicsAnchorLayoutPrivate::hasConflicts() const
       
  2612 {
       
  2613     QGraphicsAnchorLayoutPrivate *that = const_cast<QGraphicsAnchorLayoutPrivate*>(this);
       
  2614     that->calculateGraphs();
       
  2615 
       
  2616     bool floatConflict = !m_floatItems[0].isEmpty() || !m_floatItems[1].isEmpty();
       
  2617 
       
  2618     return graphHasConflicts[0] || graphHasConflicts[1] || floatConflict;
       
  2619 }
       
  2620 
       
  2621 #ifdef QT_DEBUG
       
  2622 void QGraphicsAnchorLayoutPrivate::dumpGraph(const QString &name)
       
  2623 {
       
  2624     QFile file(QString::fromAscii("anchorlayout.%1.dot").arg(name));
       
  2625     if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
       
  2626         qWarning("Could not write to %s", file.fileName().toLocal8Bit().constData());
       
  2627 
       
  2628     QString str = QString::fromAscii("digraph anchorlayout {\nnode [shape=\"rect\"]\n%1}");
       
  2629     QString dotContents = graph[0].serializeToDot();
       
  2630     dotContents += graph[1].serializeToDot();
       
  2631     file.write(str.arg(dotContents).toLocal8Bit());
       
  2632 
       
  2633     file.close();
       
  2634 }
       
  2635 #endif
       
  2636 
       
  2637 QT_END_NAMESPACE