qgraphicsanchorlayout_p.cpp

Absolute File Name:/home/qt/qt5_coco/qt5/qtbase/src/widgets/graphicsview/qgraphicsanchorlayout_p.cpp
Source codeSwitch to Preprocessed file
LineSourceCount
1/****************************************************************************-
2**-
3** Copyright (C) 2015 The Qt Company Ltd.-
4** Contact: http://www.qt.io/licensing/-
5**-
6** This file is part of the QtWidgets module of the Qt Toolkit.-
7**-
8** $QT_BEGIN_LICENSE:LGPL21$-
9** Commercial License Usage-
10** Licensees holding valid commercial Qt licenses may use this file in-
11** accordance with the commercial license agreement provided with the-
12** Software or, alternatively, in accordance with the terms contained in-
13** a written agreement between you and The Qt Company. For licensing terms-
14** and conditions see http://www.qt.io/terms-conditions. For further-
15** information use the contact form at http://www.qt.io/contact-us.-
16**-
17** GNU Lesser General Public License Usage-
18** Alternatively, this file may be used under the terms of the GNU Lesser-
19** General Public License version 2.1 or version 3 as published by the Free-
20** Software Foundation and appearing in the file LICENSE.LGPLv21 and-
21** LICENSE.LGPLv3 included in the packaging of this file. Please review the-
22** following information to ensure the GNU Lesser General Public License-
23** requirements will be met: https://www.gnu.org/licenses/lgpl.html and-
24** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.-
25**-
26** As a special exception, The Qt Company gives you certain additional-
27** rights. These rights are described in The Qt Company LGPL Exception-
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.-
29**-
30** $QT_END_LICENSE$-
31**-
32****************************************************************************/-
33-
34#include <QtWidgets/qwidget.h>-
35#include <QtWidgets/qapplication.h>-
36#include <QtCore/qlinkedlist.h>-
37#include <QtCore/qstack.h>-
38-
39#ifdef QT_DEBUG-
40#include <QtCore/qfile.h>-
41#endif-
42-
43#include "qgraphicsanchorlayout_p.h"-
44-
45#ifndef QT_NO_GRAPHICSVIEW-
46QT_BEGIN_NAMESPACE-
47-
48// To ensure that all variables inside the simplex solver are non-negative,-
49// we limit the size of anchors in the interval [-limit, limit]. Then before-
50// sending them to the simplex solver we add "limit" as an offset, so that-
51// they are actually calculated in the interval [0, 2 * limit]-
52// To avoid numerical errors in platforms where we use single precision,-
53// we use a tighter limit for the variables range.-
54const qreal g_offset = (sizeof(qreal) == sizeof(double)) ? QWIDGETSIZE_MAX : QWIDGETSIZE_MAX / 32;-
55-
56QGraphicsAnchorPrivate::QGraphicsAnchorPrivate(int version)-
57 : QObjectPrivate(version), layoutPrivate(0), data(0),-
58 sizePolicy(QSizePolicy::Fixed), preferredSize(0),-
59 hasSize(true)-
60{-
61}
never executed: end of block
0
62-
63QGraphicsAnchorPrivate::~QGraphicsAnchorPrivate()-
64{-
65 if (data) {
dataDescription
TRUEnever evaluated
FALSEnever evaluated
0
66 // The QGraphicsAnchor was already deleted at this moment. We must clean-
67 // the dangling pointer to avoid double deletion in the AnchorData dtor.-
68 data->graphicsAnchor = 0;-
69-
70 layoutPrivate->removeAnchor(data->from, data->to);-
71 }
never executed: end of block
0
72}
never executed: end of block
0
73-
74void QGraphicsAnchorPrivate::setSizePolicy(QSizePolicy::Policy policy)-
75{-
76 if (sizePolicy != policy) {
sizePolicy != policyDescription
TRUEnever evaluated
FALSEnever evaluated
0
77 sizePolicy = policy;-
78 layoutPrivate->q_func()->invalidate();-
79 }
never executed: end of block
0
80}
never executed: end of block
0
81-
82void QGraphicsAnchorPrivate::setSpacing(qreal value)-
83{-
84 if (!data) {
!dataDescription
TRUEnever evaluated
FALSEnever evaluated
0
85 qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");-
86 return;
never executed: return;
0
87 }-
88-
89 if (hasSize && (preferredSize == value))
hasSizeDescription
TRUEnever evaluated
FALSEnever evaluated
(preferredSize == value)Description
TRUEnever evaluated
FALSEnever evaluated
0
90 return;
never executed: return;
0
91-
92 // The anchor has an user-defined size-
93 hasSize = true;-
94 preferredSize = value;-
95-
96 layoutPrivate->q_func()->invalidate();-
97}
never executed: end of block
0
98-
99void QGraphicsAnchorPrivate::unsetSpacing()-
100{-
101 if (!data) {
!dataDescription
TRUEnever evaluated
FALSEnever evaluated
0
102 qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");-
103 return;
never executed: return;
0
104 }-
105-
106 // Return to standard direction-
107 hasSize = false;-
108-
109 layoutPrivate->q_func()->invalidate();-
110}
never executed: end of block
0
111-
112qreal QGraphicsAnchorPrivate::spacing() const-
113{-
114 if (!data) {
!dataDescription
TRUEnever evaluated
FALSEnever evaluated
0
115 qWarning("QGraphicsAnchor::setSpacing: The anchor does not exist.");-
116 return 0;
never executed: return 0;
0
117 }-
118-
119 return preferredSize;
never executed: return preferredSize;
0
120}-
121-
122-
123static void applySizePolicy(QSizePolicy::Policy policy,-
124 qreal minSizeHint, qreal prefSizeHint, qreal maxSizeHint,-
125 qreal *minSize, qreal *prefSize,-
126 qreal *maxSize)-
127{-
128 // minSize, prefSize and maxSize are initialized-
129 // with item's preferred Size: this is QSizePolicy::Fixed.-
130 //-
131 // Then we check each flag to find the resultant QSizePolicy,-
132 // according to the following table:-
133 //-
134 // constant value-
135 // QSizePolicy::Fixed 0-
136 // QSizePolicy::Minimum GrowFlag-
137 // QSizePolicy::Maximum ShrinkFlag-
138 // QSizePolicy::Preferred GrowFlag | ShrinkFlag-
139 // QSizePolicy::Ignored GrowFlag | ShrinkFlag | IgnoreFlag-
140-
141 if (policy & QSizePolicy::ShrinkFlag)
policy & QSize...cy::ShrinkFlagDescription
TRUEnever evaluated
FALSEnever evaluated
0
142 *minSize = minSizeHint;
never executed: *minSize = minSizeHint;
0
143 else-
144 *minSize = prefSizeHint;
never executed: *minSize = prefSizeHint;
0
145-
146 if (policy & QSizePolicy::GrowFlag)
policy & QSizePolicy::GrowFlagDescription
TRUEnever evaluated
FALSEnever evaluated
0
147 *maxSize = maxSizeHint;
never executed: *maxSize = maxSizeHint;
0
148 else-
149 *maxSize = prefSizeHint;
never executed: *maxSize = prefSizeHint;
0
150-
151 // Note that these two initializations are affected by the previous flags-
152 if (policy & QSizePolicy::IgnoreFlag)
policy & QSize...cy::IgnoreFlagDescription
TRUEnever evaluated
FALSEnever evaluated
0
153 *prefSize = *minSize;
never executed: *prefSize = *minSize;
0
154 else-
155 *prefSize = prefSizeHint;
never executed: *prefSize = prefSizeHint;
0
156}-
157-
158AnchorData::~AnchorData()-
159{-
160 if (graphicsAnchor) {
graphicsAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
161 // Remove reference to ourself to avoid double removal in-
162 // QGraphicsAnchorPrivate dtor.-
163 graphicsAnchor->d_func()->data = 0;-
164-
165 delete graphicsAnchor;-
166 }
never executed: end of block
0
167}
never executed: end of block
0
168-
169-
170void AnchorData::refreshSizeHints(const QLayoutStyleInfo *styleInfo)-
171{-
172 QSizePolicy::Policy policy;-
173 qreal minSizeHint;-
174 qreal prefSizeHint;-
175 qreal maxSizeHint;-
176-
177 if (item) {
itemDescription
TRUEnever evaluated
FALSEnever evaluated
0
178 // It is an internal anchor, fetch size information from the item-
179 if (isLayoutAnchor) {
isLayoutAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
180 minSize = 0;-
181 prefSize = 0;-
182 maxSize = QWIDGETSIZE_MAX;-
183 if (isCenterAnchor)
isCenterAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
184 maxSize /= 2;
never executed: maxSize /= 2;
0
185-
186 minPrefSize = prefSize;-
187 maxPrefSize = maxSize;-
188 return;
never executed: return;
0
189 } else {-
190 if (orientation == QGraphicsAnchorLayoutPrivate::Horizontal) {
orientation ==...te::HorizontalDescription
TRUEnever evaluated
FALSEnever evaluated
0
191 policy = item->sizePolicy().horizontalPolicy();-
192 minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).width();-
193 prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).width();-
194 maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).width();-
195 } else {
never executed: end of block
0
196 policy = item->sizePolicy().verticalPolicy();-
197 minSizeHint = item->effectiveSizeHint(Qt::MinimumSize).height();-
198 prefSizeHint = item->effectiveSizeHint(Qt::PreferredSize).height();-
199 maxSizeHint = item->effectiveSizeHint(Qt::MaximumSize).height();-
200 }
never executed: end of block
0
201-
202 if (isCenterAnchor) {
isCenterAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
203 minSizeHint /= 2;-
204 prefSizeHint /= 2;-
205 maxSizeHint /= 2;-
206 }
never executed: end of block
0
207 }
never executed: end of block
0
208 } else {-
209 // It is a user-created anchor, fetch size information from the associated QGraphicsAnchor-
210 Q_ASSERT(graphicsAnchor);-
211 QGraphicsAnchorPrivate *anchorPrivate = graphicsAnchor->d_func();-
212-
213 // Policy, min and max sizes are straightforward-
214 policy = anchorPrivate->sizePolicy;-
215 minSizeHint = 0;-
216 maxSizeHint = QWIDGETSIZE_MAX;-
217-
218 // Preferred Size-
219 if (anchorPrivate->hasSize) {
anchorPrivate->hasSizeDescription
TRUEnever evaluated
FALSEnever evaluated
0
220 // Anchor has user-defined size-
221 prefSizeHint = anchorPrivate->preferredSize;-
222 } else {
never executed: end of block
0
223 // Fetch size information from style-
224 const Qt::Orientation orient = Qt::Orientation(QGraphicsAnchorLayoutPrivate::edgeOrientation(from->m_edge) + 1);-
225 qreal s = styleInfo->defaultSpacing(orient);-
226 if (s < 0) {
s < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
227 QSizePolicy::ControlType controlTypeFrom = from->m_item->sizePolicy().controlType();-
228 QSizePolicy::ControlType controlTypeTo = to->m_item->sizePolicy().controlType();-
229 s = styleInfo->perItemSpacing(controlTypeFrom, controlTypeTo, orient);-
230-
231 // ### Currently we do not support negative anchors inside the graph.-
232 // To avoid those being created by a negative style spacing, we must-
233 // make this test.-
234 if (s < 0)
s < 0Description
TRUEnever evaluated
FALSEnever evaluated
0
235 s = 0;
never executed: s = 0;
0
236 }
never executed: end of block
0
237 prefSizeHint = s;-
238 }
never executed: end of block
0
239 }-
240-
241 // Fill minSize, prefSize and maxSize based on policy and sizeHints-
242 applySizePolicy(policy, minSizeHint, prefSizeHint, maxSizeHint,-
243 &minSize, &prefSize, &maxSize);-
244-
245 minPrefSize = prefSize;-
246 maxPrefSize = maxSize;-
247-
248 // Set the anchor effective sizes to preferred.-
249 //-
250 // Note: The idea here is that all items should remain at their-
251 // preferred size unless where that's impossible. In cases where-
252 // the item is subject to restrictions (anchored to the layout-
253 // edges, for instance), the simplex solver will be run to-
254 // recalculate and override the values we set here.-
255 sizeAtMinimum = prefSize;-
256 sizeAtPreferred = prefSize;-
257 sizeAtMaximum = prefSize;-
258}
never executed: end of block
0
259-
260void ParallelAnchorData::updateChildrenSizes()-
261{-
262 firstEdge->sizeAtMinimum = sizeAtMinimum;-
263 firstEdge->sizeAtPreferred = sizeAtPreferred;-
264 firstEdge->sizeAtMaximum = sizeAtMaximum;-
265-
266 if (secondForward()) {
secondForward()Description
TRUEnever evaluated
FALSEnever evaluated
0
267 secondEdge->sizeAtMinimum = sizeAtMinimum;-
268 secondEdge->sizeAtPreferred = sizeAtPreferred;-
269 secondEdge->sizeAtMaximum = sizeAtMaximum;-
270 } else {
never executed: end of block
0
271 secondEdge->sizeAtMinimum = -sizeAtMinimum;-
272 secondEdge->sizeAtPreferred = -sizeAtPreferred;-
273 secondEdge->sizeAtMaximum = -sizeAtMaximum;-
274 }
never executed: end of block
0
275-
276 firstEdge->updateChildrenSizes();-
277 secondEdge->updateChildrenSizes();-
278}
never executed: end of block
0
279-
280/*-
281 \internal-
282-
283 Initialize the parallel anchor size hints using the sizeHint information from-
284 its children.-
285-
286 Note that parallel groups can lead to unfeasibility, so during calculation, we can-
287 find out one unfeasibility. Because of that this method return boolean. This can't-
288 happen in sequential, so there the method is void.-
289 */-
290bool ParallelAnchorData::calculateSizeHints()-
291{-
292 // Normalize second child sizes.-
293 // A negative anchor of sizes min, minPref, pref, maxPref and max, is equivalent-
294 // to a forward anchor of sizes -max, -maxPref, -pref, -minPref, -min-
295 qreal secondMin;-
296 qreal secondMinPref;-
297 qreal secondPref;-
298 qreal secondMaxPref;-
299 qreal secondMax;-
300-
301 if (secondForward()) {
secondForward()Description
TRUEnever evaluated
FALSEnever evaluated
0
302 secondMin = secondEdge->minSize;-
303 secondMinPref = secondEdge->minPrefSize;-
304 secondPref = secondEdge->prefSize;-
305 secondMaxPref = secondEdge->maxPrefSize;-
306 secondMax = secondEdge->maxSize;-
307 } else {
never executed: end of block
0
308 secondMin = -secondEdge->maxSize;-
309 secondMinPref = -secondEdge->maxPrefSize;-
310 secondPref = -secondEdge->prefSize;-
311 secondMaxPref = -secondEdge->minPrefSize;-
312 secondMax = -secondEdge->minSize;-
313 }
never executed: end of block
0
314-
315 minSize = qMax(firstEdge->minSize, secondMin);-
316 maxSize = qMin(firstEdge->maxSize, secondMax);-
317-
318 // This condition means that the maximum size of one anchor being simplified is smaller than-
319 // the minimum size of the other anchor. The consequence is that there won't be a valid size-
320 // for this parallel setup.-
321 if (minSize > maxSize) {
minSize > maxSizeDescription
TRUEnever evaluated
FALSEnever evaluated
0
322 return false;
never executed: return false;
0
323 }-
324-
325 // Preferred size calculation-
326 // The calculation of preferred size is done as follows:-
327 //-
328 // 1) Check whether one of the child anchors is the layout structural anchor-
329 // If so, we can simply copy the preferred information from the other child,-
330 // after bounding it to our minimum and maximum sizes.-
331 // If not, then we proceed with the actual calculations.-
332 //-
333 // 2) The whole algorithm for preferred size calculation is based on the fact-
334 // that, if a given anchor cannot remain at its preferred size, it'd rather-
335 // grow than shrink.-
336 //-
337 // What happens though is that while this affirmative is true for simple-
338 // anchors, it may not be true for sequential anchors that have one or more-
339 // reversed anchors inside it. That happens because when a sequential anchor-
340 // grows, any reversed anchors inside it may be required to shrink, something-
341 // we try to avoid, as said above.-
342 //-
343 // To overcome this, besides their actual preferred size "prefSize", each anchor-
344 // exports what we call "minPrefSize" and "maxPrefSize". These two values define-
345 // a surrounding interval where, if required to move, the anchor would rather-
346 // remain inside.-
347 //-
348 // For standard anchors, this area simply represents the region between-
349 // prefSize and maxSize, which makes sense since our first affirmation.-
350 // For composed anchors, these values are calculated as to reduce the global-
351 // "damage", that is, to reduce the total deviation and the total amount of-
352 // anchors that had to shrink.-
353-
354 if (firstEdge->isLayoutAnchor) {
firstEdge->isLayoutAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
355 prefSize = qBound(minSize, secondPref, maxSize);-
356 minPrefSize = qBound(minSize, secondMinPref, maxSize);-
357 maxPrefSize = qBound(minSize, secondMaxPref, maxSize);-
358 } else if (secondEdge->isLayoutAnchor) {
never executed: end of block
secondEdge->isLayoutAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
359 prefSize = qBound(minSize, firstEdge->prefSize, maxSize);-
360 minPrefSize = qBound(minSize, firstEdge->minPrefSize, maxSize);-
361 maxPrefSize = qBound(minSize, firstEdge->maxPrefSize, maxSize);-
362 } else {
never executed: end of block
0
363 // Calculate the intersection between the "preferred" regions of each child-
364 const qreal lowerBoundary =-
365 qBound(minSize, qMax(firstEdge->minPrefSize, secondMinPref), maxSize);-
366 const qreal upperBoundary =-
367 qBound(minSize, qMin(firstEdge->maxPrefSize, secondMaxPref), maxSize);-
368 const qreal prefMean =-
369 qBound(minSize, (firstEdge->prefSize + secondPref) / 2, maxSize);-
370-
371 if (lowerBoundary < upperBoundary) {
lowerBoundary < upperBoundaryDescription
TRUEnever evaluated
FALSEnever evaluated
0
372 // If there is an intersection between the two regions, this intersection-
373 // will be used as the preferred region of the parallel anchor itself.-
374 // The preferred size will be the bounded average between the two preferred-
375 // sizes.-
376 prefSize = qBound(lowerBoundary, prefMean, upperBoundary);-
377 minPrefSize = lowerBoundary;-
378 maxPrefSize = upperBoundary;-
379 } else {
never executed: end of block
0
380 // If there is no intersection, we have to attribute "damage" to at least-
381 // one of the children. The minimum total damage is achieved in points-
382 // inside the region that extends from (1) the upper boundary of the lower-
383 // region to (2) the lower boundary of the upper region.-
384 // Then, we expose this region as _our_ preferred region and once again,-
385 // use the bounded average as our preferred size.-
386 prefSize = qBound(upperBoundary, prefMean, lowerBoundary);-
387 minPrefSize = upperBoundary;-
388 maxPrefSize = lowerBoundary;-
389 }
never executed: end of block
0
390 }-
391-
392 // See comment in AnchorData::refreshSizeHints() about sizeAt* values-
393 sizeAtMinimum = prefSize;-
394 sizeAtPreferred = prefSize;-
395 sizeAtMaximum = prefSize;-
396-
397 return true;
never executed: return true;
0
398}-
399-
400/*!-
401 \internal-
402 returns the factor in the interval [-1, 1].-
403 -1 is at Minimum-
404 0 is at Preferred-
405 1 is at Maximum-
406*/-
407static QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> getFactor(qreal value, qreal min,-
408 qreal minPref, qreal pref,-
409 qreal maxPref, qreal max)-
410{-
411 QGraphicsAnchorLayoutPrivate::Interval interval;-
412 qreal lower;-
413 qreal upper;-
414-
415 if (value < minPref) {
value < minPrefDescription
TRUEnever evaluated
FALSEnever evaluated
0
416 interval = QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred;-
417 lower = min;-
418 upper = minPref;-
419 } else if (value < pref) {
never executed: end of block
value < prefDescription
TRUEnever evaluated
FALSEnever evaluated
0
420 interval = QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred;-
421 lower = minPref;-
422 upper = pref;-
423 } else if (value < maxPref) {
never executed: end of block
value < maxPrefDescription
TRUEnever evaluated
FALSEnever evaluated
0
424 interval = QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred;-
425 lower = pref;-
426 upper = maxPref;-
427 } else {
never executed: end of block
0
428 interval = QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum;-
429 lower = maxPref;-
430 upper = max;-
431 }
never executed: end of block
0
432-
433 qreal progress;-
434 if (upper == lower) {
upper == lowerDescription
TRUEnever evaluated
FALSEnever evaluated
0
435 progress = 0;-
436 } else {
never executed: end of block
0
437 progress = (value - lower) / (upper - lower);-
438 }
never executed: end of block
0
439-
440 return qMakePair(interval, progress);
never executed: return qMakePair(interval, progress);
0
441}-
442-
443static qreal interpolate(const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> &factor,-
444 qreal min, qreal minPref, qreal pref, qreal maxPref, qreal max)-
445{-
446 qreal lower = 0;-
447 qreal upper = 0;-
448-
449 switch (factor.first) {-
450 case QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred:
never executed: case QGraphicsAnchorLayoutPrivate::MinimumToMinPreferred:
0
451 lower = min;-
452 upper = minPref;-
453 break;
never executed: break;
0
454 case QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred:
never executed: case QGraphicsAnchorLayoutPrivate::MinPreferredToPreferred:
0
455 lower = minPref;-
456 upper = pref;-
457 break;
never executed: break;
0
458 case QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred:
never executed: case QGraphicsAnchorLayoutPrivate::PreferredToMaxPreferred:
0
459 lower = pref;-
460 upper = maxPref;-
461 break;
never executed: break;
0
462 case QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum:
never executed: case QGraphicsAnchorLayoutPrivate::MaxPreferredToMaximum:
0
463 lower = maxPref;-
464 upper = max;-
465 break;
never executed: break;
0
466 }-
467-
468 return lower + factor.second * (upper - lower);
never executed: return lower + factor.second * (upper - lower);
0
469}-
470-
471void SequentialAnchorData::updateChildrenSizes()-
472{-
473 // Band here refers if the value is in the Minimum To Preferred-
474 // band (the lower band) or the Preferred To Maximum (the upper band).-
475-
476 const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> minFactor =-
477 getFactor(sizeAtMinimum, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);-
478 const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> prefFactor =-
479 getFactor(sizeAtPreferred, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);-
480 const QPair<QGraphicsAnchorLayoutPrivate::Interval, qreal> maxFactor =-
481 getFactor(sizeAtMaximum, minSize, minPrefSize, prefSize, maxPrefSize, maxSize);-
482-
483 // XXX This is not safe if Vertex simplification takes place after the sequential-
484 // anchor is created. In that case, "prev" will be a group-vertex, different from-
485 // "from" or "to", that _contains_ one of them.-
486 AnchorVertex *prev = from;-
487-
488 for (int i = 0; i < m_edges.count(); ++i) {
i < m_edges.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
489 AnchorData *e = m_edges.at(i);-
490-
491 const bool edgeIsForward = (e->from == prev);-
492 if (edgeIsForward) {
edgeIsForwardDescription
TRUEnever evaluated
FALSEnever evaluated
0
493 e->sizeAtMinimum = interpolate(minFactor, e->minSize, e->minPrefSize,-
494 e->prefSize, e->maxPrefSize, e->maxSize);-
495 e->sizeAtPreferred = interpolate(prefFactor, e->minSize, e->minPrefSize,-
496 e->prefSize, e->maxPrefSize, e->maxSize);-
497 e->sizeAtMaximum = interpolate(maxFactor, e->minSize, e->minPrefSize,-
498 e->prefSize, e->maxPrefSize, e->maxSize);-
499 prev = e->to;-
500 } else {
never executed: end of block
0
501 Q_ASSERT(prev == e->to);-
502 e->sizeAtMinimum = interpolate(minFactor, e->maxSize, e->maxPrefSize,-
503 e->prefSize, e->minPrefSize, e->minSize);-
504 e->sizeAtPreferred = interpolate(prefFactor, e->maxSize, e->maxPrefSize,-
505 e->prefSize, e->minPrefSize, e->minSize);-
506 e->sizeAtMaximum = interpolate(maxFactor, e->maxSize, e->maxPrefSize,-
507 e->prefSize, e->minPrefSize, e->minSize);-
508 prev = e->from;-
509 }
never executed: end of block
0
510-
511 e->updateChildrenSizes();-
512 }
never executed: end of block
0
513}
never executed: end of block
0
514-
515void SequentialAnchorData::calculateSizeHints()-
516{-
517 minSize = 0;-
518 prefSize = 0;-
519 maxSize = 0;-
520 minPrefSize = 0;-
521 maxPrefSize = 0;-
522-
523 AnchorVertex *prev = from;-
524-
525 for (int i = 0; i < m_edges.count(); ++i) {
i < m_edges.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
526 AnchorData *edge = m_edges.at(i);-
527-
528 const bool edgeIsForward = (edge->from == prev);-
529 if (edgeIsForward) {
edgeIsForwardDescription
TRUEnever evaluated
FALSEnever evaluated
0
530 minSize += edge->minSize;-
531 prefSize += edge->prefSize;-
532 maxSize += edge->maxSize;-
533 minPrefSize += edge->minPrefSize;-
534 maxPrefSize += edge->maxPrefSize;-
535 prev = edge->to;-
536 } else {
never executed: end of block
0
537 Q_ASSERT(prev == edge->to);-
538 minSize -= edge->maxSize;-
539 prefSize -= edge->prefSize;-
540 maxSize -= edge->minSize;-
541 minPrefSize -= edge->maxPrefSize;-
542 maxPrefSize -= edge->minPrefSize;-
543 prev = edge->from;-
544 }
never executed: end of block
0
545 }-
546-
547 // See comment in AnchorData::refreshSizeHints() about sizeAt* values-
548 sizeAtMinimum = prefSize;-
549 sizeAtPreferred = prefSize;-
550 sizeAtMaximum = prefSize;-
551}
never executed: end of block
0
552-
553#ifdef QT_DEBUG-
554void AnchorData::dump(int indent) {-
555 if (type == Parallel) {
type == ParallelDescription
TRUEnever evaluated
FALSEnever evaluated
0
556 qDebug("%*s type: parallel:", indent, "");-
557 ParallelAnchorData *p = static_cast<ParallelAnchorData *>(this);-
558 p->firstEdge->dump(indent+2);-
559 p->secondEdge->dump(indent+2);-
560 } else if (type == Sequential) {
never executed: end of block
type == SequentialDescription
TRUEnever evaluated
FALSEnever evaluated
0
561 SequentialAnchorData *s = static_cast<SequentialAnchorData *>(this);-
562 int kids = s->m_edges.count();-
563 qDebug("%*s type: sequential(%d):", indent, "", kids);-
564 for (int i = 0; i < kids; ++i) {
i < kidsDescription
TRUEnever evaluated
FALSEnever evaluated
0
565 s->m_edges.at(i)->dump(indent+2);-
566 }
never executed: end of block
0
567 } else {
never executed: end of block
0
568 qDebug("%*s type: Normal:", indent, "");-
569 }
never executed: end of block
0
570}-
571-
572#endif-
573-
574QSimplexConstraint *GraphPath::constraint(const GraphPath &path) const-
575{-
576 // Calculate-
577 QSet<AnchorData *> cPositives;-
578 QSet<AnchorData *> cNegatives;-
579 QSet<AnchorData *> intersection;-
580-
581 cPositives = positives + path.negatives;-
582 cNegatives = negatives + path.positives;-
583-
584 intersection = cPositives & cNegatives;-
585-
586 cPositives -= intersection;-
587 cNegatives -= intersection;-
588-
589 // Fill-
590 QSimplexConstraint *c = new QSimplexConstraint;-
591 QSet<AnchorData *>::iterator i;-
592 for (i = cPositives.begin(); i != cPositives.end(); ++i)
i != cPositives.end()Description
TRUEnever evaluated
FALSEnever evaluated
0
593 c->variables.insert(*i, 1.0);
never executed: c->variables.insert(*i, 1.0);
0
594-
595 for (i = cNegatives.begin(); i != cNegatives.end(); ++i)
i != cNegatives.end()Description
TRUEnever evaluated
FALSEnever evaluated
0
596 c->variables.insert(*i, -1.0);
never executed: c->variables.insert(*i, -1.0);
0
597-
598 return c;
never executed: return c;
0
599}-
600-
601#ifdef QT_DEBUG-
602QString GraphPath::toString() const-
603{-
604 QString string(QLatin1String("Path: "));-
605 foreach(AnchorData *edge, positives)-
606 string += QString::fromLatin1(" (+++) %1").arg(edge->toString());
never executed: string += QString::fromLatin1(" (+++) %1").arg(edge->toString());
0
607-
608 foreach(AnchorData *edge, negatives)-
609 string += QString::fromLatin1(" (---) %1").arg(edge->toString());
never executed: string += QString::fromLatin1(" (---) %1").arg(edge->toString());
0
610-
611 return string;
never executed: return string;
0
612}-
613#endif-
614-
615QGraphicsAnchorLayoutPrivate::QGraphicsAnchorLayoutPrivate()-
616 : calculateGraphCacheDirty(true), styleInfoDirty(true)-
617{-
618 for (int i = 0; i < NOrientations; ++i) {
i < NOrientationsDescription
TRUEnever evaluated
FALSEnever evaluated
0
619 for (int j = 0; j < 3; ++j) {
j < 3Description
TRUEnever evaluated
FALSEnever evaluated
0
620 sizeHints[i][j] = -1;-
621 }
never executed: end of block
0
622 interpolationProgress[i] = -1;-
623-
624 spacings[i] = -1;-
625 graphHasConflicts[i] = false;-
626-
627 layoutFirstVertex[i] = 0;-
628 layoutCentralVertex[i] = 0;-
629 layoutLastVertex[i] = 0;-
630 }
never executed: end of block
0
631}
never executed: end of block
0
632-
633Qt::AnchorPoint QGraphicsAnchorLayoutPrivate::oppositeEdge(Qt::AnchorPoint edge)-
634{-
635 switch (edge) {-
636 case Qt::AnchorLeft:
never executed: case Qt::AnchorLeft:
0
637 edge = Qt::AnchorRight;-
638 break;
never executed: break;
0
639 case Qt::AnchorRight:
never executed: case Qt::AnchorRight:
0
640 edge = Qt::AnchorLeft;-
641 break;
never executed: break;
0
642 case Qt::AnchorTop:
never executed: case Qt::AnchorTop:
0
643 edge = Qt::AnchorBottom;-
644 break;
never executed: break;
0
645 case Qt::AnchorBottom:
never executed: case Qt::AnchorBottom:
0
646 edge = Qt::AnchorTop;-
647 break;
never executed: break;
0
648 default:
never executed: default:
0
649 break;
never executed: break;
0
650 }-
651 return edge;
never executed: return edge;
0
652}-
653-
654-
655/*!-
656 \internal-
657-
658 Adds \a newAnchor to the graph.-
659-
660 Returns the newAnchor itself if it could be added without further changes to the graph. If a-
661 new parallel anchor had to be created, then returns the new parallel anchor. If a parallel anchor-
662 had to be created and it results in an unfeasible setup, \a feasible is set to false, otherwise-
663 true.-
664-
665 Note that in the case a new parallel anchor is created, it might also take over some constraints-
666 from its children anchors.-
667*/-
668AnchorData *QGraphicsAnchorLayoutPrivate::addAnchorMaybeParallel(AnchorData *newAnchor, bool *feasible)-
669{-
670 Orientation orientation = Orientation(newAnchor->orientation);-
671 Graph<AnchorVertex, AnchorData> &g = graph[orientation];-
672 *feasible = true;-
673-
674 // If already exists one anchor where newAnchor is supposed to be, we create a parallel-
675 // anchor.-
676 if (AnchorData *oldAnchor = g.takeEdge(newAnchor->from, newAnchor->to)) {
AnchorData *ol...newAnchor->to)Description
TRUEnever evaluated
FALSEnever evaluated
0
677 ParallelAnchorData *parallel = new ParallelAnchorData(oldAnchor, newAnchor);-
678-
679 // The parallel anchor will "replace" its children anchors in-
680 // every center constraint that they appear.-
681-
682 // ### If the dependent (center) anchors had reference(s) to their constraints, we-
683 // could avoid traversing all the itemCenterConstraints.-
684 QList<QSimplexConstraint *> &constraints = itemCenterConstraints[orientation];-
685-
686 AnchorData *children[2] = { oldAnchor, newAnchor };-
687 QList<QSimplexConstraint *> *childrenConstraints[2] = { &parallel->m_firstConstraints,-
688 &parallel->m_secondConstraints };-
689-
690 for (int i = 0; i < 2; ++i) {
i < 2Description
TRUEnever evaluated
FALSEnever evaluated
0
691 AnchorData *child = children[i];-
692 QList<QSimplexConstraint *> *childConstraints = childrenConstraints[i];-
693-
694 // We need to fix the second child constraints if the parallel group will have the-
695 // opposite direction of the second child anchor. For the point of view of external-
696 // entities, this anchor was reversed. So if at some point we say that the parallel-
697 // has a value of 20, this mean that the second child (when reversed) will be-
698 // assigned -20.-
699 const bool needsReverse = i == 1 && !parallel->secondForward();
i == 1Description
TRUEnever evaluated
FALSEnever evaluated
!parallel->secondForward()Description
TRUEnever evaluated
FALSEnever evaluated
0
700-
701 if (!child->isCenterAnchor)
!child->isCenterAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
702 continue;
never executed: continue;
0
703-
704 parallel->isCenterAnchor = true;-
705-
706 for (int j = 0; j < constraints.count(); ++j) {
j < constraints.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
707 QSimplexConstraint *c = constraints[j];-
708 if (c->variables.contains(child)) {
c->variables.contains(child)Description
TRUEnever evaluated
FALSEnever evaluated
0
709 childConstraints->append(c);-
710 qreal v = c->variables.take(child);-
711 if (needsReverse)
needsReverseDescription
TRUEnever evaluated
FALSEnever evaluated
0
712 v *= -1;
never executed: v *= -1;
0
713 c->variables.insert(parallel, v);-
714 }
never executed: end of block
0
715 }
never executed: end of block
0
716 }
never executed: end of block
0
717-
718 // At this point we can identify that the parallel anchor is not feasible, e.g. one-
719 // anchor minimum size is bigger than the other anchor maximum size.-
720 *feasible = parallel->calculateSizeHints();-
721 newAnchor = parallel;-
722 }
never executed: end of block
0
723-
724 g.createEdge(newAnchor->from, newAnchor->to, newAnchor);-
725 return newAnchor;
never executed: return newAnchor;
0
726}-
727-
728/*!-
729 \internal-
730-
731 Takes the sequence of vertices described by (\a before, \a vertices, \a after) and removes-
732 all anchors connected to the vertices in \a vertices, returning one simplified anchor between-
733 \a before and \a after.-
734-
735 Note that this function doesn't add the created anchor to the graph. This should be done by-
736 the caller.-
737*/-
738static AnchorData *createSequence(Graph<AnchorVertex, AnchorData> *graph,-
739 AnchorVertex *before,-
740 const QVector<AnchorVertex*> &vertices,-
741 AnchorVertex *after)-
742{-
743#if defined(QT_DEBUG) && 0-
744 QString strVertices;-
745 for (int i = 0; i < vertices.count(); ++i) {-
746 strVertices += QString::fromLatin1("%1 - ").arg(vertices.at(i)->toString());-
747 }-
748 QString strPath = QString::fromLatin1("%1 - %2%3").arg(before->toString(), strVertices, after->toString());-
749 qDebug("simplifying [%s] to [%s - %s]", qPrintable(strPath), qPrintable(before->toString()), qPrintable(after->toString()));-
750#endif-
751-
752 AnchorVertex *prev = before;-
753 QVector<AnchorData *> edges;-
754 edges.reserve(vertices.count() + 1);-
755-
756 const int numVertices = vertices.count();-
757 edges.reserve(numVertices + 1);-
758 // Take from the graph, the edges that will be simplificated-
759 for (int i = 0; i < numVertices; ++i) {
i < numVerticesDescription
TRUEnever evaluated
FALSEnever evaluated
0
760 AnchorVertex *next = vertices.at(i);-
761 AnchorData *ad = graph->takeEdge(prev, next);-
762 Q_ASSERT(ad);-
763 edges.append(ad);-
764 prev = next;-
765 }
never executed: end of block
0
766-
767 // Take the last edge (not covered in the loop above)-
768 AnchorData *ad = graph->takeEdge(vertices.last(), after);-
769 Q_ASSERT(ad);-
770 edges.append(ad);-
771-
772 // Create sequence-
773 SequentialAnchorData *sequence = new SequentialAnchorData(vertices, edges);-
774 sequence->from = before;-
775 sequence->to = after;-
776-
777 sequence->calculateSizeHints();-
778-
779 return sequence;
never executed: return sequence;
0
780}-
781-
782/*!-
783 \internal-
784-
785 The purpose of this function is to simplify the graph.-
786 Simplification serves two purposes:-
787 1. Reduce the number of edges in the graph, (thus the number of variables to the equation-
788 solver is reduced, and the solver performs better).-
789 2. Be able to do distribution of sequences of edges more intelligently (esp. with sequential-
790 anchors)-
791-
792 It is essential that it must be possible to restore simplified anchors back to their "original"-
793 form. This is done by restoreSimplifiedAnchor().-
794-
795 There are two types of simplification that can be done:-
796 1. Sequential simplification-
797 Sequential simplification means that all sequences of anchors will be merged into one single-
798 anchor. Only anhcors that points in the same direction will be merged.-
799 2. Parallel simplification-
800 If a simplified sequential anchor is about to be inserted between two vertices in the graph-
801 and there already exist an anchor between those two vertices, a parallel anchor will be-
802 created that serves as a placeholder for the sequential anchor and the anchor that was-
803 already between the two vertices.-
804-
805 The process of simplification can be described as:-
806-
807 1. Simplify all sequences of anchors into one anchor.-
808 If no further simplification was done, go to (3)-
809 - If there already exist an anchor where the sequential anchor is supposed to be inserted,-
810 take that anchor out of the graph-
811 - Then create a parallel anchor that holds the sequential anchor and the anchor just taken-
812 out of the graph.-
813 2. Go to (1)-
814 3. Done-
815-
816 When creating the parallel anchors, the algorithm might identify unfeasible situations. In this-
817 case the simplification process stops and returns \c false. Otherwise returns \c true.-
818*/-
819bool QGraphicsAnchorLayoutPrivate::simplifyGraph(Orientation orientation)-
820{-
821 if (items.isEmpty())
items.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
822 return true;
never executed: return true;
0
823-
824#if defined(QT_DEBUG) && 0-
825 qDebug("Simplifying Graph for %s",-
826 orientation == Horizontal ? "Horizontal" : "Vertical");-
827-
828 static int count = 0;-
829 if (orientation == Horizontal) {-
830 count++;-
831 dumpGraph(QString::fromLatin1("%1-full").arg(count));-
832 }-
833#endif-
834-
835 // Vertex simplification-
836 if (!simplifyVertices(orientation)) {
!simplifyVertices(orientation)Description
TRUEnever evaluated
FALSEnever evaluated
0
837 restoreVertices(orientation);-
838 return false;
never executed: return false;
0
839 }-
840-
841 // Anchor simplification-
842 bool dirty;-
843 bool feasible = true;-
844 do {-
845 dirty = simplifyGraphIteration(orientation, &feasible);-
846 } while (dirty && feasible);
never executed: end of block
dirtyDescription
TRUEnever evaluated
FALSEnever evaluated
feasibleDescription
TRUEnever evaluated
FALSEnever evaluated
0
847-
848 // Note that if we are not feasible, we fallback and make sure that the graph is fully restored-
849 if (!feasible) {
!feasibleDescription
TRUEnever evaluated
FALSEnever evaluated
0
850 restoreSimplifiedGraph(orientation);-
851 restoreVertices(orientation);-
852 return false;
never executed: return false;
0
853 }-
854-
855#if defined(QT_DEBUG) && 0-
856 dumpGraph(QString::fromLatin1("%1-simplified-%2").arg(count).arg(-
857 QString::fromLatin1(orientation == Horizontal ? "Horizontal" : "Vertical")));-
858#endif-
859-
860 return true;
never executed: return true;
0
861}-
862-
863static AnchorVertex *replaceVertex_helper(AnchorData *data, AnchorVertex *oldV, AnchorVertex *newV)-
864{-
865 AnchorVertex *other;-
866 if (data->from == oldV) {
data->from == oldVDescription
TRUEnever evaluated
FALSEnever evaluated
0
867 data->from = newV;-
868 other = data->to;-
869 } else {
never executed: end of block
0
870 data->to = newV;-
871 other = data->from;-
872 }
never executed: end of block
0
873 return other;
never executed: return other;
0
874}-
875-
876bool QGraphicsAnchorLayoutPrivate::replaceVertex(Orientation orientation, AnchorVertex *oldV,-
877 AnchorVertex *newV, const QList<AnchorData *> &edges)-
878{-
879 Graph<AnchorVertex, AnchorData> &g = graph[orientation];-
880 bool feasible = true;-
881-
882 for (int i = 0; i < edges.count(); ++i) {
i < edges.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
883 AnchorData *ad = edges[i];-
884 AnchorVertex *otherV = replaceVertex_helper(ad, oldV, newV);-
885-
886#if defined(QT_DEBUG)-
887 ad->name = QString::fromLatin1("%1 --to--> %2").arg(ad->from->toString()).arg(ad->to->toString());-
888#endif-
889-
890 bool newFeasible;-
891 AnchorData *newAnchor = addAnchorMaybeParallel(ad, &newFeasible);-
892 feasible &= newFeasible;-
893-
894 if (newAnchor != ad) {
newAnchor != adDescription
TRUEnever evaluated
FALSEnever evaluated
0
895 // A parallel was created, we mark that in the list of anchors created by vertex-
896 // simplification. This is needed because we want to restore them in a separate step-
897 // from the restoration of anchor simplification.-
898 anchorsFromSimplifiedVertices[orientation].append(newAnchor);-
899 }
never executed: end of block
0
900-
901 g.takeEdge(oldV, otherV);-
902 }
never executed: end of block
0
903-
904 return feasible;
never executed: return feasible;
0
905}-
906-
907/*!-
908 \internal-
909*/-
910bool QGraphicsAnchorLayoutPrivate::simplifyVertices(Orientation orientation)-
911{-
912 Q_Q(QGraphicsAnchorLayout);-
913 Graph<AnchorVertex, AnchorData> &g = graph[orientation];-
914-
915 // We'll walk through vertices-
916 QStack<AnchorVertex *> stack;-
917 stack.push(layoutFirstVertex[orientation]);-
918 QSet<AnchorVertex *> visited;-
919-
920 while (!stack.isEmpty()) {
!stack.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
921 AnchorVertex *v = stack.pop();-
922 visited.insert(v);-
923-
924 // Each adjacent of 'v' is a possible vertex to be merged. So we traverse all of-
925 // them. Since once a merge is made, we might add new adjacents, and we don't want to-
926 // pass two times through one adjacent. The 'index' is used to track our position.-
927 QList<AnchorVertex *> adjacents = g.adjacentVertices(v);-
928 int index = 0;-
929-
930 while (index < adjacents.count()) {
index < adjacents.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
931 AnchorVertex *next = adjacents.at(index);-
932 index++;-
933-
934 AnchorData *data = g.edgeData(v, next);-
935 const bool bothLayoutVertices = v->m_item == q && next->m_item == q;
v->m_item == qDescription
TRUEnever evaluated
FALSEnever evaluated
next->m_item == qDescription
TRUEnever evaluated
FALSEnever evaluated
0
936 const bool zeroSized = !data->minSize && !data->maxSize;
!data->minSizeDescription
TRUEnever evaluated
FALSEnever evaluated
!data->maxSizeDescription
TRUEnever evaluated
FALSEnever evaluated
0
937-
938 if (!bothLayoutVertices && zeroSized) {
!bothLayoutVerticesDescription
TRUEnever evaluated
FALSEnever evaluated
zeroSizedDescription
TRUEnever evaluated
FALSEnever evaluated
0
939-
940 // Create a new vertex pair, note that we keep a list of those vertices so we can-
941 // easily process them when restoring the graph.-
942 AnchorVertexPair *newV = new AnchorVertexPair(v, next, data);-
943 simplifiedVertices[orientation].append(newV);-
944-
945 // Collect the anchors of both vertices, the new vertex pair will take their place-
946 // in those anchors-
947 const QList<AnchorVertex *> &vAdjacents = g.adjacentVertices(v);-
948 const QList<AnchorVertex *> &nextAdjacents = g.adjacentVertices(next);-
949-
950 for (int i = 0; i < vAdjacents.count(); ++i) {
i < vAdjacents.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
951 AnchorVertex *adjacent = vAdjacents.at(i);-
952 if (adjacent != next) {
adjacent != nextDescription
TRUEnever evaluated
FALSEnever evaluated
0
953 AnchorData *ad = g.edgeData(v, adjacent);-
954 newV->m_firstAnchors.append(ad);-
955 }
never executed: end of block
0
956 }
never executed: end of block
0
957-
958 for (int i = 0; i < nextAdjacents.count(); ++i) {
i < nextAdjacents.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
959 AnchorVertex *adjacent = nextAdjacents.at(i);-
960 if (adjacent != v) {
adjacent != vDescription
TRUEnever evaluated
FALSEnever evaluated
0
961 AnchorData *ad = g.edgeData(next, adjacent);-
962 newV->m_secondAnchors.append(ad);-
963-
964 // We'll also add new vertices to the adjacent list of the new 'v', to be-
965 // created as a vertex pair and replace the current one.-
966 if (!adjacents.contains(adjacent))
!adjacents.contains(adjacent)Description
TRUEnever evaluated
FALSEnever evaluated
0
967 adjacents.append(adjacent);
never executed: adjacents.append(adjacent);
0
968 }
never executed: end of block
0
969 }
never executed: end of block
0
970-
971 // ### merge this loop into the ones that calculated m_firstAnchors/m_secondAnchors?-
972 // Make newV take the place of v and next-
973 bool feasible = replaceVertex(orientation, v, newV, newV->m_firstAnchors);-
974 feasible &= replaceVertex(orientation, next, newV, newV->m_secondAnchors);-
975-
976 // Update the layout vertex information if one of the vertices is a layout vertex.-
977 AnchorVertex *layoutVertex = 0;-
978 if (v->m_item == q)
v->m_item == qDescription
TRUEnever evaluated
FALSEnever evaluated
0
979 layoutVertex = v;
never executed: layoutVertex = v;
0
980 else if (next->m_item == q)
next->m_item == qDescription
TRUEnever evaluated
FALSEnever evaluated
0
981 layoutVertex = next;
never executed: layoutVertex = next;
0
982-
983 if (layoutVertex) {
layoutVertexDescription
TRUEnever evaluated
FALSEnever evaluated
0
984 // Layout vertices always have m_item == q...-
985 newV->m_item = q;-
986 changeLayoutVertex(orientation, layoutVertex, newV);-
987 }
never executed: end of block
0
988-
989 g.takeEdge(v, next);-
990-
991 // If a non-feasibility is found, we leave early and cancel the simplification-
992 if (!feasible)
!feasibleDescription
TRUEnever evaluated
FALSEnever evaluated
0
993 return false;
never executed: return false;
0
994-
995 v = newV;-
996 visited.insert(newV);-
997-
998 } else if (!visited.contains(next) && !stack.contains(next)) {
never executed: end of block
!visited.contains(next)Description
TRUEnever evaluated
FALSEnever evaluated
!stack.contains(next)Description
TRUEnever evaluated
FALSEnever evaluated
0
999 // If the adjacent is not fit for merge and it wasn't visited by the outermost-
1000 // loop, we add it to the stack.-
1001 stack.push(next);-
1002 }
never executed: end of block
0
1003 }
never executed: end of block
0
1004 }
never executed: end of block
0
1005-
1006 return true;
never executed: return true;
0
1007}-
1008-
1009/*!-
1010 \internal-
1011-
1012 One iteration of the simplification algorithm. Returns \c true if another iteration is needed.-
1013-
1014 The algorithm walks the graph in depth-first order, and only collects vertices that has two-
1015 edges connected to it. If the vertex does not have two edges or if it is a layout edge, it-
1016 will take all the previously collected vertices and try to create a simplified sequential-
1017 anchor representing all the previously collected vertices. Once the simplified anchor is-
1018 inserted, the collected list is cleared in order to find the next sequence to simplify.-
1019-
1020 Note that there are some catches to this that are not covered by the above explanation, see-
1021 the function comments for more details.-
1022*/-
1023bool QGraphicsAnchorLayoutPrivate::simplifyGraphIteration(QGraphicsAnchorLayoutPrivate::Orientation orientation,-
1024 bool *feasible)-
1025{-
1026 Q_Q(QGraphicsAnchorLayout);-
1027 Graph<AnchorVertex, AnchorData> &g = graph[orientation];-
1028-
1029 QSet<AnchorVertex *> visited;-
1030 QStack<QPair<AnchorVertex *, AnchorVertex *> > stack;-
1031 stack.push(qMakePair(static_cast<AnchorVertex *>(0), layoutFirstVertex[orientation]));-
1032 QVector<AnchorVertex*> candidates;-
1033-
1034 // Walk depth-first, in the stack we store start of the candidate sequence (beforeSequence)-
1035 // and the vertex to be visited.-
1036 while (!stack.isEmpty()) {
!stack.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
1037 QPair<AnchorVertex *, AnchorVertex *> pair = stack.pop();-
1038 AnchorVertex *beforeSequence = pair.first;-
1039 AnchorVertex *v = pair.second;-
1040-
1041 // The basic idea is to determine whether we found an end of sequence,-
1042 // if that's the case, we stop adding vertices to the candidate list-
1043 // and do a simplification step.-
1044 //-
1045 // A vertex can trigger an end of sequence if-
1046 // (a) it is a layout vertex, we don't simplify away the layout vertices;-
1047 // (b) it does not have exactly 2 adjacents;-
1048 // (c) its next adjacent is already visited (a cycle in the graph).-
1049 // (d) the next anchor is a center anchor.-
1050-
1051 const QList<AnchorVertex *> &adjacents = g.adjacentVertices(v);-
1052 const bool isLayoutVertex = v->m_item == q;-
1053 AnchorVertex *afterSequence = v;-
1054 bool endOfSequence = false;-
1055-
1056 //-
1057 // Identify the end cases.-
1058 //-
1059-
1060 // Identifies cases (a) and (b)-
1061 endOfSequence = isLayoutVertex || adjacents.count() != 2;
isLayoutVertexDescription
TRUEnever evaluated
FALSEnever evaluated
adjacents.count() != 2Description
TRUEnever evaluated
FALSEnever evaluated
0
1062-
1063 if (!endOfSequence) {
!endOfSequenceDescription
TRUEnever evaluated
FALSEnever evaluated
0
1064 // This is a tricky part. We peek at the next vertex to find out whether-
1065 //-
1066 // - we already visited the next vertex (c);-
1067 // - the next anchor is a center (d).-
1068 //-
1069 // Those are needed to identify the remaining end of sequence cases. Note that unlike-
1070 // (a) and (b), we preempt the end of sequence by looking into the next vertex.-
1071-
1072 // Peek at the next vertex-
1073 AnchorVertex *after;-
1074 if (candidates.isEmpty())
candidates.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
1075 after = (beforeSequence == adjacents.last() ? adjacents.first() : adjacents.last());
never executed: after = (beforeSequence == adjacents.last() ? adjacents.first() : adjacents.last());
beforeSequence...jacents.last()Description
TRUEnever evaluated
FALSEnever evaluated
0
1076 else-
1077 after = (candidates.last() == adjacents.last() ? adjacents.first() : adjacents.last());
never executed: after = (candidates.last() == adjacents.last() ? adjacents.first() : adjacents.last());
candidates.las...jacents.last()Description
TRUEnever evaluated
FALSEnever evaluated
0
1078-
1079 // ### At this point we assumed that candidates will not contain 'after', this may not hold-
1080 // when simplifying FLOATing anchors.-
1081 Q_ASSERT(!candidates.contains(after));-
1082-
1083 const AnchorData *data = g.edgeData(v, after);-
1084 Q_ASSERT(data);-
1085 const bool cycleFound = visited.contains(after);-
1086-
1087 // Now cases (c) and (d)...-
1088 endOfSequence = cycleFound || data->isCenterAnchor;
cycleFoundDescription
TRUEnever evaluated
FALSEnever evaluated
data->isCenterAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
1089-
1090 if (!endOfSequence) {
!endOfSequenceDescription
TRUEnever evaluated
FALSEnever evaluated
0
1091 // If it's not an end of sequence, then the vertex didn't trigger neither of the-
1092 // previously three cases, so it can be added to the candidates list.-
1093 candidates.append(v);-
1094 } else if (cycleFound && (beforeSequence != after)) {
never executed: end of block
cycleFoundDescription
TRUEnever evaluated
FALSEnever evaluated
(beforeSequence != after)Description
TRUEnever evaluated
FALSEnever evaluated
0
1095 afterSequence = after;-
1096 candidates.append(v);-
1097 }
never executed: end of block
0
1098 }
never executed: end of block
0
1099-
1100 //-
1101 // Add next non-visited vertices to the stack.-
1102 //-
1103 for (int i = 0; i < adjacents.count(); ++i) {
i < adjacents.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
1104 AnchorVertex *next = adjacents.at(i);-
1105 if (visited.contains(next))
visited.contains(next)Description
TRUEnever evaluated
FALSEnever evaluated
0
1106 continue;
never executed: continue;
0
1107-
1108 // If current vertex is an end of sequence, and it'll reset the candidates list. So-
1109 // the next vertices will build candidates lists with the current vertex as 'before'-
1110 // vertex. If it's not an end of sequence, we keep the original 'before' vertex,-
1111 // since we are keeping the candidates list.-
1112 if (endOfSequence)
endOfSequenceDescription
TRUEnever evaluated
FALSEnever evaluated
0
1113 stack.push(qMakePair(v, next));
never executed: stack.push(qMakePair(v, next));
0
1114 else-
1115 stack.push(qMakePair(beforeSequence, next));
never executed: stack.push(qMakePair(beforeSequence, next));
0
1116 }-
1117-
1118 visited.insert(v);-
1119-
1120 if (!endOfSequence || candidates.isEmpty())
!endOfSequenceDescription
TRUEnever evaluated
FALSEnever evaluated
candidates.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
1121 continue;
never executed: continue;
0
1122-
1123 //-
1124 // Create a sequence for (beforeSequence, candidates, afterSequence).-
1125 //-
1126-
1127 // One restriction we have is to not simplify half of an anchor and let the other half-
1128 // unsimplified. So we remove center edges before and after the sequence.-
1129 const AnchorData *firstAnchor = g.edgeData(beforeSequence, candidates.first());-
1130 if (firstAnchor->isCenterAnchor) {
firstAnchor->isCenterAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
1131 beforeSequence = candidates.first();-
1132 candidates.remove(0);-
1133-
1134 // If there's not candidates to be simplified, leave.-
1135 if (candidates.isEmpty())
candidates.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
1136 continue;
never executed: continue;
0
1137 }
never executed: end of block
0
1138-
1139 const AnchorData *lastAnchor = g.edgeData(candidates.last(), afterSequence);-
1140 if (lastAnchor->isCenterAnchor) {
lastAnchor->isCenterAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
1141 afterSequence = candidates.last();-
1142 candidates.remove(candidates.count() - 1);-
1143-
1144 if (candidates.isEmpty())
candidates.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
1145 continue;
never executed: continue;
0
1146 }
never executed: end of block
0
1147-
1148 //-
1149 // Add the sequence to the graph.-
1150 //-
1151-
1152 AnchorData *sequence = createSequence(&g, beforeSequence, candidates, afterSequence);-
1153-
1154 // If 'beforeSequence' and 'afterSequence' already had an anchor between them, we'll-
1155 // create a parallel anchor between the new sequence and the old anchor.-
1156 bool newFeasible;-
1157 AnchorData *newAnchor = addAnchorMaybeParallel(sequence, &newFeasible);-
1158-
1159 if (!newFeasible) {
!newFeasibleDescription
TRUEnever evaluated
FALSEnever evaluated
0
1160 *feasible = false;-
1161 return false;
never executed: return false;
0
1162 }-
1163-
1164 // When a new parallel anchor is create in the graph, we finish the iteration and return-
1165 // true to indicate a new iteration is needed. This happens because a parallel anchor-
1166 // changes the number of adjacents one vertex has, possibly opening up oportunities for-
1167 // building candidate lists (when adjacents == 2).-
1168 if (newAnchor != sequence)
newAnchor != sequenceDescription
TRUEnever evaluated
FALSEnever evaluated
0
1169 return true;
never executed: return true;
0
1170-
1171 // If there was no parallel simplification, we'll keep walking the graph. So we clear the-
1172 // candidates list to start again.-
1173 candidates.clear();-
1174 }
never executed: end of block
0
1175-
1176 return false;
never executed: return false;
0
1177}-
1178-
1179void QGraphicsAnchorLayoutPrivate::restoreSimplifiedAnchor(AnchorData *edge)-
1180{-
1181#if 0-
1182 static const char *anchortypes[] = {"Normal",-
1183 "Sequential",-
1184 "Parallel"};-
1185 qDebug("Restoring %s edge.", anchortypes[int(edge->type)]);-
1186#endif-
1187-
1188 Graph<AnchorVertex, AnchorData> &g = graph[edge->orientation];-
1189-
1190 if (edge->type == AnchorData::Normal) {
edge->type == ...orData::NormalDescription
TRUEnever evaluated
FALSEnever evaluated
0
1191 g.createEdge(edge->from, edge->to, edge);-
1192-
1193 } else if (edge->type == AnchorData::Sequential) {
never executed: end of block
edge->type == ...ta::SequentialDescription
TRUEnever evaluated
FALSEnever evaluated
0
1194 SequentialAnchorData *sequence = static_cast<SequentialAnchorData *>(edge);-
1195-
1196 for (int i = 0; i < sequence->m_edges.count(); ++i) {
i < sequence->m_edges.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
1197 AnchorData *data = sequence->m_edges.at(i);-
1198 restoreSimplifiedAnchor(data);-
1199 }
never executed: end of block
0
1200-
1201 delete sequence;-
1202-
1203 } else if (edge->type == AnchorData::Parallel) {
never executed: end of block
edge->type == ...Data::ParallelDescription
TRUEnever evaluated
FALSEnever evaluated
0
1204-
1205 // Skip parallel anchors that were created by vertex simplification, they will be processed-
1206 // later, when restoring vertex simplification.-
1207 // ### we could improve this check bit having a bit inside 'edge'-
1208 if (anchorsFromSimplifiedVertices[edge->orientation].contains(edge))
anchorsFromSim...contains(edge)Description
TRUEnever evaluated
FALSEnever evaluated
0
1209 return;
never executed: return;
0
1210-
1211 ParallelAnchorData* parallel = static_cast<ParallelAnchorData*>(edge);-
1212 restoreSimplifiedConstraints(parallel);-
1213-
1214 // ### Because of the way parallel anchors are created in the anchor simplification-
1215 // algorithm, we know that one of these will be a sequence, so it'll be safe if the other-
1216 // anchor create an edge between the same vertices as the parallel.-
1217 Q_ASSERT(parallel->firstEdge->type == AnchorData::Sequential-
1218 || parallel->secondEdge->type == AnchorData::Sequential);-
1219 restoreSimplifiedAnchor(parallel->firstEdge);-
1220 restoreSimplifiedAnchor(parallel->secondEdge);-
1221-
1222 delete parallel;-
1223 }
never executed: end of block
0
1224}
never executed: end of block
0
1225-
1226void QGraphicsAnchorLayoutPrivate::restoreSimplifiedConstraints(ParallelAnchorData *parallel)-
1227{-
1228 if (!parallel->isCenterAnchor)
!parallel->isCenterAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
1229 return;
never executed: return;
0
1230-
1231 for (int i = 0; i < parallel->m_firstConstraints.count(); ++i) {
i < parallel->...raints.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
1232 QSimplexConstraint *c = parallel->m_firstConstraints.at(i);-
1233 qreal v = c->variables[parallel];-
1234 c->variables.remove(parallel);-
1235 c->variables.insert(parallel->firstEdge, v);-
1236 }
never executed: end of block
0
1237-
1238 // When restoring, we might have to revert constraints back. See comments on-
1239 // addAnchorMaybeParallel().-
1240 const bool needsReverse = !parallel->secondForward();-
1241-
1242 for (int i = 0; i < parallel->m_secondConstraints.count(); ++i) {
i < parallel->...raints.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
1243 QSimplexConstraint *c = parallel->m_secondConstraints.at(i);-
1244 qreal v = c->variables[parallel];-
1245 if (needsReverse)
needsReverseDescription
TRUEnever evaluated
FALSEnever evaluated
0
1246 v *= -1;
never executed: v *= -1;
0
1247 c->variables.remove(parallel);-
1248 c->variables.insert(parallel->secondEdge, v);-
1249 }
never executed: end of block
0
1250}
never executed: end of block
0
1251-
1252void QGraphicsAnchorLayoutPrivate::restoreSimplifiedGraph(Orientation orientation)-
1253{-
1254#if 0-
1255 qDebug("Restoring Simplified Graph for %s",-
1256 orientation == Horizontal ? "Horizontal" : "Vertical");-
1257#endif-
1258-
1259 // Restore anchor simplification-
1260 Graph<AnchorVertex, AnchorData> &g = graph[orientation];-
1261 QList<QPair<AnchorVertex*, AnchorVertex*> > connections = g.connections();-
1262 for (int i = 0; i < connections.count(); ++i) {
i < connections.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
1263 AnchorVertex *v1 = connections.at(i).first;-
1264 AnchorVertex *v2 = connections.at(i).second;-
1265 AnchorData *edge = g.edgeData(v1, v2);-
1266-
1267 // We restore only sequential anchors and parallels that were not created by-
1268 // vertex simplification.-
1269 if (edge->type == AnchorData::Sequential
edge->type == ...ta::SequentialDescription
TRUEnever evaluated
FALSEnever evaluated
0
1270 || (edge->type == AnchorData::Parallel &&
edge->type == ...Data::ParallelDescription
TRUEnever evaluated
FALSEnever evaluated
0
1271 !anchorsFromSimplifiedVertices[orientation].contains(edge))) {
!anchorsFromSi...contains(edge)Description
TRUEnever evaluated
FALSEnever evaluated
0
1272-
1273 g.takeEdge(v1, v2);-
1274 restoreSimplifiedAnchor(edge);-
1275 }
never executed: end of block
0
1276 }
never executed: end of block
0
1277-
1278 restoreVertices(orientation);-
1279}
never executed: end of block
0
1280-
1281void QGraphicsAnchorLayoutPrivate::restoreVertices(Orientation orientation)-
1282{-
1283 Q_Q(QGraphicsAnchorLayout);-
1284-
1285 Graph<AnchorVertex, AnchorData> &g = graph[orientation];-
1286 QList<AnchorVertexPair *> &toRestore = simplifiedVertices[orientation];-
1287-
1288 // Since we keep a list of parallel anchors and vertices that were created during vertex-
1289 // simplification, we can now iterate on those lists instead of traversing the graph-
1290 // recursively.-
1291-
1292 // First, restore the constraints changed when we created parallel anchors. Note that this-
1293 // works at this point because the constraints doesn't depend on vertex information and at-
1294 // this point it's always safe to identify whether the second child is forward or backwards.-
1295 // In the next step, we'll change the anchors vertices so that would not be possible anymore.-
1296 QList<AnchorData *> &parallelAnchors = anchorsFromSimplifiedVertices[orientation];-
1297-
1298 for (int i = parallelAnchors.count() - 1; i >= 0; --i) {
i >= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1299 ParallelAnchorData *parallel = static_cast<ParallelAnchorData *>(parallelAnchors.at(i));-
1300 restoreSimplifiedConstraints(parallel);-
1301 }
never executed: end of block
0
1302-
1303 // Then, we will restore the vertices in the inverse order of creation, this way we ensure that-
1304 // the vertex being restored was not wrapped by another simplification.-
1305 for (int i = toRestore.count() - 1; i >= 0; --i) {
i >= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1306 AnchorVertexPair *pair = toRestore.at(i);-
1307 QList<AnchorVertex *> adjacents = g.adjacentVertices(pair);-
1308-
1309 // Restore the removed edge, this will also restore both vertices 'first' and 'second' to-
1310 // the graph structure.-
1311 AnchorVertex *first = pair->m_first;-
1312 AnchorVertex *second = pair->m_second;-
1313 g.createEdge(first, second, pair->m_removedAnchor);-
1314-
1315 // Restore the anchors for the first child vertex-
1316 for (int j = 0; j < pair->m_firstAnchors.count(); ++j) {
j < pair->m_fi...nchors.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
1317 AnchorData *ad = pair->m_firstAnchors.at(j);-
1318 Q_ASSERT(ad->from == pair || ad->to == pair);-
1319-
1320 replaceVertex_helper(ad, pair, first);-
1321 g.createEdge(ad->from, ad->to, ad);-
1322 }
never executed: end of block
0
1323-
1324 // Restore the anchors for the second child vertex-
1325 for (int j = 0; j < pair->m_secondAnchors.count(); ++j) {
j < pair->m_se...nchors.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
1326 AnchorData *ad = pair->m_secondAnchors.at(j);-
1327 Q_ASSERT(ad->from == pair || ad->to == pair);-
1328-
1329 replaceVertex_helper(ad, pair, second);-
1330 g.createEdge(ad->from, ad->to, ad);-
1331 }
never executed: end of block
0
1332-
1333 for (int j = 0; j < adjacents.count(); ++j) {
j < adjacents.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
1334 g.takeEdge(pair, adjacents.at(j));-
1335 }
never executed: end of block
0
1336-
1337 // The pair simplified a layout vertex, so place back the correct vertex in the variable-
1338 // that track layout vertices-
1339 if (pair->m_item == q) {
pair->m_item == qDescription
TRUEnever evaluated
FALSEnever evaluated
0
1340 AnchorVertex *layoutVertex = first->m_item == q ? first : second;
first->m_item == qDescription
TRUEnever evaluated
FALSEnever evaluated
0
1341 Q_ASSERT(layoutVertex->m_item == q);-
1342 changeLayoutVertex(orientation, pair, layoutVertex);-
1343 }
never executed: end of block
0
1344-
1345 delete pair;-
1346 }
never executed: end of block
0
1347 qDeleteAll(parallelAnchors);-
1348 parallelAnchors.clear();-
1349 toRestore.clear();-
1350}
never executed: end of block
0
1351-
1352QGraphicsAnchorLayoutPrivate::Orientation-
1353QGraphicsAnchorLayoutPrivate::edgeOrientation(Qt::AnchorPoint edge)-
1354{-
1355 return edge > Qt::AnchorRight ? Vertical : Horizontal;
never executed: return edge > Qt::AnchorRight ? Vertical : Horizontal;
edge > Qt::AnchorRightDescription
TRUEnever evaluated
FALSEnever evaluated
0
1356}-
1357-
1358/*!-
1359 \internal-
1360-
1361 Create internal anchors to connect the layout edges (Left to Right and-
1362 Top to Bottom).-
1363-
1364 These anchors doesn't have size restrictions, that will be enforced by-
1365 other anchors and items in the layout.-
1366*/-
1367void QGraphicsAnchorLayoutPrivate::createLayoutEdges()-
1368{-
1369 Q_Q(QGraphicsAnchorLayout);-
1370 QGraphicsLayoutItem *layout = q;-
1371-
1372 // Horizontal-
1373 AnchorData *data = new AnchorData;-
1374 addAnchor_helper(layout, Qt::AnchorLeft, layout,-
1375 Qt::AnchorRight, data);-
1376 data->maxSize = QWIDGETSIZE_MAX;-
1377-
1378 // Save a reference to layout vertices-
1379 layoutFirstVertex[Horizontal] = internalVertex(layout, Qt::AnchorLeft);-
1380 layoutCentralVertex[Horizontal] = 0;-
1381 layoutLastVertex[Horizontal] = internalVertex(layout, Qt::AnchorRight);-
1382-
1383 // Vertical-
1384 data = new AnchorData;-
1385 addAnchor_helper(layout, Qt::AnchorTop, layout,-
1386 Qt::AnchorBottom, data);-
1387 data->maxSize = QWIDGETSIZE_MAX;-
1388-
1389 // Save a reference to layout vertices-
1390 layoutFirstVertex[Vertical] = internalVertex(layout, Qt::AnchorTop);-
1391 layoutCentralVertex[Vertical] = 0;-
1392 layoutLastVertex[Vertical] = internalVertex(layout, Qt::AnchorBottom);-
1393}
never executed: end of block
0
1394-
1395void QGraphicsAnchorLayoutPrivate::deleteLayoutEdges()-
1396{-
1397 Q_Q(QGraphicsAnchorLayout);-
1398-
1399 Q_ASSERT(!internalVertex(q, Qt::AnchorHorizontalCenter));-
1400 Q_ASSERT(!internalVertex(q, Qt::AnchorVerticalCenter));-
1401-
1402 removeAnchor_helper(internalVertex(q, Qt::AnchorLeft),-
1403 internalVertex(q, Qt::AnchorRight));-
1404 removeAnchor_helper(internalVertex(q, Qt::AnchorTop),-
1405 internalVertex(q, Qt::AnchorBottom));-
1406}
never executed: end of block
0
1407-
1408void QGraphicsAnchorLayoutPrivate::createItemEdges(QGraphicsLayoutItem *item)-
1409{-
1410 items.append(item);-
1411-
1412 // Create horizontal and vertical internal anchors for the item and-
1413 // refresh its size hint / policy values.-
1414 AnchorData *data = new AnchorData;-
1415 addAnchor_helper(item, Qt::AnchorLeft, item, Qt::AnchorRight, data);-
1416 data->refreshSizeHints();-
1417-
1418 data = new AnchorData;-
1419 addAnchor_helper(item, Qt::AnchorTop, item, Qt::AnchorBottom, data);-
1420 data->refreshSizeHints();-
1421}
never executed: end of block
0
1422-
1423/*!-
1424 \internal-
1425-
1426 By default, each item in the layout is represented internally as-
1427 a single anchor in each direction. For instance, from Left to Right.-
1428-
1429 However, to support anchorage of items to the center of items, we-
1430 must split this internal anchor into two half-anchors. From Left-
1431 to Center and then from Center to Right, with the restriction that-
1432 these anchors must have the same time at all times.-
1433*/-
1434void QGraphicsAnchorLayoutPrivate::createCenterAnchors(-
1435 QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge)-
1436{-
1437 Q_Q(QGraphicsAnchorLayout);-
1438-
1439 Orientation orientation;-
1440 switch (centerEdge) {-
1441 case Qt::AnchorHorizontalCenter:
never executed: case Qt::AnchorHorizontalCenter:
0
1442 orientation = Horizontal;-
1443 break;
never executed: break;
0
1444 case Qt::AnchorVerticalCenter:
never executed: case Qt::AnchorVerticalCenter:
0
1445 orientation = Vertical;-
1446 break;
never executed: break;
0
1447 default:
never executed: default:
0
1448 // Don't create center edges unless needed-
1449 return;
never executed: return;
0
1450 }-
1451-
1452 // Check if vertex already exists-
1453 if (internalVertex(item, centerEdge))
internalVertex...m, centerEdge)Description
TRUEnever evaluated
FALSEnever evaluated
0
1454 return;
never executed: return;
0
1455-
1456 // Orientation code-
1457 Qt::AnchorPoint firstEdge;-
1458 Qt::AnchorPoint lastEdge;-
1459-
1460 if (orientation == Horizontal) {
orientation == HorizontalDescription
TRUEnever evaluated
FALSEnever evaluated
0
1461 firstEdge = Qt::AnchorLeft;-
1462 lastEdge = Qt::AnchorRight;-
1463 } else {
never executed: end of block
0
1464 firstEdge = Qt::AnchorTop;-
1465 lastEdge = Qt::AnchorBottom;-
1466 }
never executed: end of block
0
1467-
1468 AnchorVertex *first = internalVertex(item, firstEdge);-
1469 AnchorVertex *last = internalVertex(item, lastEdge);-
1470 Q_ASSERT(first && last);-
1471-
1472 // Create new anchors-
1473 QSimplexConstraint *c = new QSimplexConstraint;-
1474-
1475 AnchorData *data = new AnchorData;-
1476 c->variables.insert(data, 1.0);-
1477 addAnchor_helper(item, firstEdge, item, centerEdge, data);-
1478 data->isCenterAnchor = true;-
1479 data->dependency = AnchorData::Master;-
1480 data->refreshSizeHints();-
1481-
1482 data = new AnchorData;-
1483 c->variables.insert(data, -1.0);-
1484 addAnchor_helper(item, centerEdge, item, lastEdge, data);-
1485 data->isCenterAnchor = true;-
1486 data->dependency = AnchorData::Slave;-
1487 data->refreshSizeHints();-
1488-
1489 itemCenterConstraints[orientation].append(c);-
1490-
1491 // Remove old one-
1492 removeAnchor_helper(first, last);-
1493-
1494 if (item == q) {
item == qDescription
TRUEnever evaluated
FALSEnever evaluated
0
1495 layoutCentralVertex[orientation] = internalVertex(q, centerEdge);-
1496 }
never executed: end of block
0
1497}
never executed: end of block
0
1498-
1499void QGraphicsAnchorLayoutPrivate::removeCenterAnchors(-
1500 QGraphicsLayoutItem *item, Qt::AnchorPoint centerEdge,-
1501 bool substitute)-
1502{-
1503 Q_Q(QGraphicsAnchorLayout);-
1504-
1505 Orientation orientation;-
1506 switch (centerEdge) {-
1507 case Qt::AnchorHorizontalCenter:
never executed: case Qt::AnchorHorizontalCenter:
0
1508 orientation = Horizontal;-
1509 break;
never executed: break;
0
1510 case Qt::AnchorVerticalCenter:
never executed: case Qt::AnchorVerticalCenter:
0
1511 orientation = Vertical;-
1512 break;
never executed: break;
0
1513 default:
never executed: default:
0
1514 // Don't remove edges that not the center ones-
1515 return;
never executed: return;
0
1516 }-
1517-
1518 // Orientation code-
1519 Qt::AnchorPoint firstEdge;-
1520 Qt::AnchorPoint lastEdge;-
1521-
1522 if (orientation == Horizontal) {
orientation == HorizontalDescription
TRUEnever evaluated
FALSEnever evaluated
0
1523 firstEdge = Qt::AnchorLeft;-
1524 lastEdge = Qt::AnchorRight;-
1525 } else {
never executed: end of block
0
1526 firstEdge = Qt::AnchorTop;-
1527 lastEdge = Qt::AnchorBottom;-
1528 }
never executed: end of block
0
1529-
1530 AnchorVertex *center = internalVertex(item, centerEdge);-
1531 if (!center)
!centerDescription
TRUEnever evaluated
FALSEnever evaluated
0
1532 return;
never executed: return;
0
1533 AnchorVertex *first = internalVertex(item, firstEdge);-
1534-
1535 Q_ASSERT(first);-
1536 Q_ASSERT(center);-
1537-
1538 Graph<AnchorVertex, AnchorData> &g = graph[orientation];-
1539-
1540-
1541 AnchorData *oldData = g.edgeData(first, center);-
1542 // Remove center constraint-
1543 for (int i = itemCenterConstraints[orientation].count() - 1; i >= 0; --i) {
i >= 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1544 if (itemCenterConstraints[orientation].at(i)->variables.contains(oldData)) {
itemCenterCons...tains(oldData)Description
TRUEnever evaluated
FALSEnever evaluated
0
1545 delete itemCenterConstraints[orientation].takeAt(i);-
1546 break;
never executed: break;
0
1547 }-
1548 }
never executed: end of block
0
1549-
1550 if (substitute) {
substituteDescription
TRUEnever evaluated
FALSEnever evaluated
0
1551 // Create the new anchor that should substitute the left-center-right anchors.-
1552 AnchorData *data = new AnchorData;-
1553 addAnchor_helper(item, firstEdge, item, lastEdge, data);-
1554 data->refreshSizeHints();-
1555-
1556 // Remove old anchors-
1557 removeAnchor_helper(first, center);-
1558 removeAnchor_helper(center, internalVertex(item, lastEdge));-
1559-
1560 } else {
never executed: end of block
0
1561 // this is only called from removeAnchors()-
1562 // first, remove all non-internal anchors-
1563 QList<AnchorVertex*> adjacents = g.adjacentVertices(center);-
1564 for (int i = 0; i < adjacents.count(); ++i) {
i < adjacents.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
1565 AnchorVertex *v = adjacents.at(i);-
1566 if (v->m_item != item) {
v->m_item != itemDescription
TRUEnever evaluated
FALSEnever evaluated
0
1567 removeAnchor_helper(center, internalVertex(v->m_item, v->m_edge));-
1568 }
never executed: end of block
0
1569 }
never executed: end of block
0
1570 // when all non-internal anchors is removed it will automatically merge the-
1571 // center anchor into a left-right (or top-bottom) anchor. We must also delete that.-
1572 // by this time, the center vertex is deleted and merged into a non-centered internal anchor-
1573 removeAnchor_helper(first, internalVertex(item, lastEdge));-
1574 }
never executed: end of block
0
1575-
1576 if (item == q) {
item == qDescription
TRUEnever evaluated
FALSEnever evaluated
0
1577 layoutCentralVertex[orientation] = 0;-
1578 }
never executed: end of block
0
1579}
never executed: end of block
0
1580-
1581-
1582void QGraphicsAnchorLayoutPrivate::removeCenterConstraints(QGraphicsLayoutItem *item,-
1583 Orientation orientation)-
1584{-
1585 // Remove the item center constraints associated to this item-
1586 // ### This is a temporary solution. We should probably use a better-
1587 // data structure to hold items and/or their associated constraints-
1588 // so that we can remove those easily-
1589-
1590 AnchorVertex *first = internalVertex(item, orientation == Horizontal ?-
1591 Qt::AnchorLeft :-
1592 Qt::AnchorTop);-
1593 AnchorVertex *center = internalVertex(item, orientation == Horizontal ?-
1594 Qt::AnchorHorizontalCenter :-
1595 Qt::AnchorVerticalCenter);-
1596-
1597 // Skip if no center constraints exist-
1598 if (!center)
!centerDescription
TRUEnever evaluated
FALSEnever evaluated
0
1599 return;
never executed: return;
0
1600-
1601 Q_ASSERT(first);-
1602 AnchorData *internalAnchor = graph[orientation].edgeData(first, center);-
1603-
1604 // Look for our anchor in all item center constraints, then remove it-
1605 for (int i = 0; i < itemCenterConstraints[orientation].size(); ++i) {
i < itemCenter...tation].size()Description
TRUEnever evaluated
FALSEnever evaluated
0
1606 if (itemCenterConstraints[orientation].at(i)->variables.contains(internalAnchor)) {
itemCenterCons...nternalAnchor)Description
TRUEnever evaluated
FALSEnever evaluated
0
1607 delete itemCenterConstraints[orientation].takeAt(i);-
1608 break;
never executed: break;
0
1609 }-
1610 }
never executed: end of block
0
1611}
never executed: end of block
0
1612-
1613/*!-
1614 * \internal-
1615 * Implements the high level "addAnchor" feature. Called by the public API-
1616 * addAnchor method.-
1617 *-
1618 * The optional \a spacing argument defines the size of the anchor. If not provided,-
1619 * the anchor size is either 0 or not-set, depending on type of anchor created (see-
1620 * matrix below).-
1621 *-
1622 * All anchors that remain with size not-set will assume the standard spacing,-
1623 * set either by the layout style or through the "setSpacing" layout API.-
1624 */-
1625QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::addAnchor(QGraphicsLayoutItem *firstItem,-
1626 Qt::AnchorPoint firstEdge,-
1627 QGraphicsLayoutItem *secondItem,-
1628 Qt::AnchorPoint secondEdge,-
1629 qreal *spacing)-
1630{-
1631 Q_Q(QGraphicsAnchorLayout);-
1632 if ((firstItem == 0) || (secondItem == 0)) {
(firstItem == 0)Description
TRUEnever evaluated
FALSEnever evaluated
(secondItem == 0)Description
TRUEnever evaluated
FALSEnever evaluated
0
1633 qWarning("QGraphicsAnchorLayout::addAnchor(): "-
1634 "Cannot anchor NULL items");-
1635 return 0;
never executed: return 0;
0
1636 }-
1637-
1638 if (firstItem == secondItem) {
firstItem == secondItemDescription
TRUEnever evaluated
FALSEnever evaluated
0
1639 qWarning("QGraphicsAnchorLayout::addAnchor(): "-
1640 "Cannot anchor the item to itself");-
1641 return 0;
never executed: return 0;
0
1642 }-
1643-
1644 if (edgeOrientation(secondEdge) != edgeOrientation(firstEdge)) {
edgeOrientatio...ion(firstEdge)Description
TRUEnever evaluated
FALSEnever evaluated
0
1645 qWarning("QGraphicsAnchorLayout::addAnchor(): "-
1646 "Cannot anchor edges of different orientations");-
1647 return 0;
never executed: return 0;
0
1648 }-
1649-
1650 const QGraphicsLayoutItem *parentWidget = q->parentLayoutItem();-
1651 if (firstItem == parentWidget || secondItem == parentWidget) {
firstItem == parentWidgetDescription
TRUEnever evaluated
FALSEnever evaluated
secondItem == parentWidgetDescription
TRUEnever evaluated
FALSEnever evaluated
0
1652 qWarning("QGraphicsAnchorLayout::addAnchor(): "-
1653 "You cannot add the parent of the layout to the layout.");-
1654 return 0;
never executed: return 0;
0
1655 }-
1656-
1657 // In QGraphicsAnchorLayout, items are represented in its internal-
1658 // graph as four anchors that connect:-
1659 // - Left -> HCenter-
1660 // - HCenter-> Right-
1661 // - Top -> VCenter-
1662 // - VCenter -> Bottom-
1663-
1664 // Ensure that the internal anchors have been created for both items.-
1665 if (firstItem != q && !items.contains(firstItem)) {
firstItem != qDescription
TRUEnever evaluated
FALSEnever evaluated
!items.contains(firstItem)Description
TRUEnever evaluated
FALSEnever evaluated
0
1666 createItemEdges(firstItem);-
1667 addChildLayoutItem(firstItem);-
1668 }
never executed: end of block
0
1669 if (secondItem != q && !items.contains(secondItem)) {
secondItem != qDescription
TRUEnever evaluated
FALSEnever evaluated
!items.contains(secondItem)Description
TRUEnever evaluated
FALSEnever evaluated
0
1670 createItemEdges(secondItem);-
1671 addChildLayoutItem(secondItem);-
1672 }
never executed: end of block
0
1673-
1674 // Create center edges if needed-
1675 createCenterAnchors(firstItem, firstEdge);-
1676 createCenterAnchors(secondItem, secondEdge);-
1677-
1678 // Use heuristics to find out what the user meant with this anchor.-
1679 correctEdgeDirection(firstItem, firstEdge, secondItem, secondEdge);-
1680-
1681 AnchorData *data = new AnchorData;-
1682 QGraphicsAnchor *graphicsAnchor = acquireGraphicsAnchor(data);-
1683-
1684 addAnchor_helper(firstItem, firstEdge, secondItem, secondEdge, data);-
1685-
1686 if (spacing) {
spacingDescription
TRUEnever evaluated
FALSEnever evaluated
0
1687 graphicsAnchor->setSpacing(*spacing);-
1688 } else {
never executed: end of block
0
1689 // If firstItem or secondItem is the layout itself, the spacing will default to 0.-
1690 // Otherwise, the following matrix is used (questionmark means that the spacing-
1691 // is queried from the style):-
1692 // from-
1693 // to Left HCenter Right-
1694 // Left 0 0 ?-
1695 // HCenter 0 0 0-
1696 // Right ? 0 0-
1697 if (firstItem == q
firstItem == qDescription
TRUEnever evaluated
FALSEnever evaluated
0
1698 || secondItem == q
secondItem == qDescription
TRUEnever evaluated
FALSEnever evaluated
0
1699 || pickEdge(firstEdge, Horizontal) == Qt::AnchorHorizontalCenter
pickEdge(first...rizontalCenterDescription
TRUEnever evaluated
FALSEnever evaluated
0
1700 || oppositeEdge(firstEdge) != secondEdge) {
oppositeEdge(f... != secondEdgeDescription
TRUEnever evaluated
FALSEnever evaluated
0
1701 graphicsAnchor->setSpacing(0);-
1702 } else {
never executed: end of block
0
1703 graphicsAnchor->unsetSpacing();-
1704 }
never executed: end of block
0
1705 }-
1706-
1707 return graphicsAnchor;
never executed: return graphicsAnchor;
0
1708}-
1709-
1710/*-
1711 \internal-
1712-
1713 This method adds an AnchorData to the internal graph. It is responsible for doing-
1714 the boilerplate part of such task.-
1715-
1716 If another AnchorData exists between the mentioned vertices, it is deleted and-
1717 the new one is inserted.-
1718*/-
1719void QGraphicsAnchorLayoutPrivate::addAnchor_helper(QGraphicsLayoutItem *firstItem,-
1720 Qt::AnchorPoint firstEdge,-
1721 QGraphicsLayoutItem *secondItem,-
1722 Qt::AnchorPoint secondEdge,-
1723 AnchorData *data)-
1724{-
1725 Q_Q(QGraphicsAnchorLayout);-
1726-
1727 const Orientation orientation = edgeOrientation(firstEdge);-
1728-
1729 // Create or increase the reference count for the related vertices.-
1730 AnchorVertex *v1 = addInternalVertex(firstItem, firstEdge);-
1731 AnchorVertex *v2 = addInternalVertex(secondItem, secondEdge);-
1732-
1733 // Remove previous anchor-
1734 if (graph[orientation].edgeData(v1, v2)) {
graph[orientat...geData(v1, v2)Description
TRUEnever evaluated
FALSEnever evaluated
0
1735 removeAnchor_helper(v1, v2);-
1736 }
never executed: end of block
0
1737-
1738 // If its an internal anchor, set the associated item-
1739 if (firstItem == secondItem)
firstItem == secondItemDescription
TRUEnever evaluated
FALSEnever evaluated
0
1740 data->item = firstItem;
never executed: data->item = firstItem;
0
1741-
1742 data->orientation = orientation;-
1743-
1744 // Create a bi-directional edge in the sense it can be transversed both-
1745 // from v1 or v2. "data" however is shared between the two references-
1746 // so we still know that the anchor direction is from 1 to 2.-
1747 data->from = v1;-
1748 data->to = v2;-
1749#ifdef QT_DEBUG-
1750 data->name = QString::fromLatin1("%1 --to--> %2").arg(v1->toString()).arg(v2->toString());-
1751#endif-
1752 // ### bit to track internal anchors, since inside AnchorData methods-
1753 // we don't have access to the 'q' pointer.-
1754 data->isLayoutAnchor = (data->item == q);-
1755-
1756 graph[orientation].createEdge(v1, v2, data);-
1757}
never executed: end of block
0
1758-
1759QGraphicsAnchor *QGraphicsAnchorLayoutPrivate::getAnchor(QGraphicsLayoutItem *firstItem,-
1760 Qt::AnchorPoint firstEdge,-
1761 QGraphicsLayoutItem *secondItem,-
1762 Qt::AnchorPoint secondEdge)-
1763{-
1764 // Do not expose internal anchors-
1765 if (firstItem == secondItem)
firstItem == secondItemDescription
TRUEnever evaluated
FALSEnever evaluated
0
1766 return 0;
never executed: return 0;
0
1767-
1768 const Orientation orientation = edgeOrientation(firstEdge);-
1769 AnchorVertex *v1 = internalVertex(firstItem, firstEdge);-
1770 AnchorVertex *v2 = internalVertex(secondItem, secondEdge);-
1771-
1772 QGraphicsAnchor *graphicsAnchor = 0;-
1773-
1774 AnchorData *data = graph[orientation].edgeData(v1, v2);-
1775 if (data) {
dataDescription
TRUEnever evaluated
FALSEnever evaluated
0
1776 // We could use "acquireGraphicsAnchor" here, but to avoid a regression where-
1777 // an internal anchor was wrongly exposed, I want to ensure no new-
1778 // QGraphicsAnchor instances are created by this call.-
1779 // This assumption must hold because anchors are either user-created (and already-
1780 // have their public object created), or they are internal (and must not reach-
1781 // this point).-
1782 Q_ASSERT(data->graphicsAnchor);-
1783 graphicsAnchor = data->graphicsAnchor;-
1784 }
never executed: end of block
0
1785 return graphicsAnchor;
never executed: return graphicsAnchor;
0
1786}-
1787-
1788/*!-
1789 * \internal-
1790 *-
1791 * Implements the high level "removeAnchor" feature. Called by-
1792 * the QAnchorData destructor.-
1793 */-
1794void QGraphicsAnchorLayoutPrivate::removeAnchor(AnchorVertex *firstVertex,-
1795 AnchorVertex *secondVertex)-
1796{-
1797 Q_Q(QGraphicsAnchorLayout);-
1798-
1799 // Save references to items while it's safe to assume the vertices exist-
1800 QGraphicsLayoutItem *firstItem = firstVertex->m_item;-
1801 QGraphicsLayoutItem *secondItem = secondVertex->m_item;-
1802-
1803 // Delete the anchor (may trigger deletion of center vertices)-
1804 removeAnchor_helper(firstVertex, secondVertex);-
1805-
1806 // Ensure no dangling pointer is left behind-
1807 firstVertex = secondVertex = 0;-
1808-
1809 // Checking if the item stays in the layout or not-
1810 bool keepFirstItem = false;-
1811 bool keepSecondItem = false;-
1812-
1813 QPair<AnchorVertex *, int> v;-
1814 int refcount = -1;-
1815-
1816 if (firstItem != q) {
firstItem != qDescription
TRUEnever evaluated
FALSEnever evaluated
0
1817 for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) {
i <= Qt::AnchorBottomDescription
TRUEnever evaluated
FALSEnever evaluated
0
1818 v = m_vertexList.value(qMakePair(firstItem, static_cast<Qt::AnchorPoint>(i)));-
1819 if (v.first) {
v.firstDescription
TRUEnever evaluated
FALSEnever evaluated
0
1820 if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter)
i == Qt::Ancho...rizontalCenterDescription
TRUEnever evaluated
FALSEnever evaluated
i == Qt::AnchorVerticalCenterDescription
TRUEnever evaluated
FALSEnever evaluated
0
1821 refcount = 2;
never executed: refcount = 2;
0
1822 else-
1823 refcount = 1;
never executed: refcount = 1;
0
1824-
1825 if (v.second > refcount) {
v.second > refcountDescription
TRUEnever evaluated
FALSEnever evaluated
0
1826 keepFirstItem = true;-
1827 break;
never executed: break;
0
1828 }-
1829 }
never executed: end of block
0
1830 }
never executed: end of block
0
1831 } else
never executed: end of block
0
1832 keepFirstItem = true;
never executed: keepFirstItem = true;
0
1833-
1834 if (secondItem != q) {
secondItem != qDescription
TRUEnever evaluated
FALSEnever evaluated
0
1835 for (int i = Qt::AnchorLeft; i <= Qt::AnchorBottom; ++i) {
i <= Qt::AnchorBottomDescription
TRUEnever evaluated
FALSEnever evaluated
0
1836 v = m_vertexList.value(qMakePair(secondItem, static_cast<Qt::AnchorPoint>(i)));-
1837 if (v.first) {
v.firstDescription
TRUEnever evaluated
FALSEnever evaluated
0
1838 if (i == Qt::AnchorHorizontalCenter || i == Qt::AnchorVerticalCenter)
i == Qt::Ancho...rizontalCenterDescription
TRUEnever evaluated
FALSEnever evaluated
i == Qt::AnchorVerticalCenterDescription
TRUEnever evaluated
FALSEnever evaluated
0
1839 refcount = 2;
never executed: refcount = 2;
0
1840 else-
1841 refcount = 1;
never executed: refcount = 1;
0
1842-
1843 if (v.second > refcount) {
v.second > refcountDescription
TRUEnever evaluated
FALSEnever evaluated
0
1844 keepSecondItem = true;-
1845 break;
never executed: break;
0
1846 }-
1847 }
never executed: end of block
0
1848 }
never executed: end of block
0
1849 } else
never executed: end of block
0
1850 keepSecondItem = true;
never executed: keepSecondItem = true;
0
1851-
1852 if (!keepFirstItem)
!keepFirstItemDescription
TRUEnever evaluated
FALSEnever evaluated
0
1853 q->removeAt(items.indexOf(firstItem));
never executed: q->removeAt(items.indexOf(firstItem));
0
1854-
1855 if (!keepSecondItem)
!keepSecondItemDescription
TRUEnever evaluated
FALSEnever evaluated
0
1856 q->removeAt(items.indexOf(secondItem));
never executed: q->removeAt(items.indexOf(secondItem));
0
1857-
1858 // Removing anchors invalidates the layout-
1859 q->invalidate();-
1860}
never executed: end of block
0
1861-
1862/*-
1863 \internal-
1864-
1865 Implements the low level "removeAnchor" feature. Called by-
1866 private methods.-
1867*/-
1868void QGraphicsAnchorLayoutPrivate::removeAnchor_helper(AnchorVertex *v1, AnchorVertex *v2)-
1869{-
1870 Q_ASSERT(v1 && v2);-
1871-
1872 // Remove edge from graph-
1873 const Orientation o = edgeOrientation(v1->m_edge);-
1874 graph[o].removeEdge(v1, v2);-
1875-
1876 // Decrease vertices reference count (may trigger a deletion)-
1877 removeInternalVertex(v1->m_item, v1->m_edge);-
1878 removeInternalVertex(v2->m_item, v2->m_edge);-
1879}
never executed: end of block
0
1880-
1881AnchorVertex *QGraphicsAnchorLayoutPrivate::addInternalVertex(QGraphicsLayoutItem *item,-
1882 Qt::AnchorPoint edge)-
1883{-
1884 QPair<QGraphicsLayoutItem *, Qt::AnchorPoint> pair(item, edge);-
1885 QPair<AnchorVertex *, int> v = m_vertexList.value(pair);-
1886-
1887 if (!v.first) {
!v.firstDescription
TRUEnever evaluated
FALSEnever evaluated
0
1888 Q_ASSERT(v.second == 0);-
1889 v.first = new AnchorVertex(item, edge);-
1890 }
never executed: end of block
0
1891 v.second++;-
1892 m_vertexList.insert(pair, v);-
1893 return v.first;
never executed: return v.first;
0
1894}-
1895-
1896/**-
1897 * \internal-
1898 *-
1899 * returns the AnchorVertex that was dereferenced, also when it was removed.-
1900 * returns 0 if it did not exist.-
1901 */-
1902void QGraphicsAnchorLayoutPrivate::removeInternalVertex(QGraphicsLayoutItem *item,-
1903 Qt::AnchorPoint edge)-
1904{-
1905 QPair<QGraphicsLayoutItem *, Qt::AnchorPoint> pair(item, edge);-
1906 QPair<AnchorVertex *, int> v = m_vertexList.value(pair);-
1907-
1908 if (!v.first) {
!v.firstDescription
TRUEnever evaluated
FALSEnever evaluated
0
1909 qWarning("This item with this edge is not in the graph");-
1910 return;
never executed: return;
0
1911 }-
1912-
1913 v.second--;-
1914 if (v.second == 0) {
v.second == 0Description
TRUEnever evaluated
FALSEnever evaluated
0
1915 // Remove reference and delete vertex-
1916 m_vertexList.remove(pair);-
1917 delete v.first;-
1918 } else {
never executed: end of block
0
1919 // Update reference count-
1920 m_vertexList.insert(pair, v);-
1921-
1922 if ((v.second == 2) &&
(v.second == 2)Description
TRUEnever evaluated
FALSEnever evaluated
0
1923 ((edge == Qt::AnchorHorizontalCenter) ||
(edge == Qt::A...izontalCenter)Description
TRUEnever evaluated
FALSEnever evaluated
0
1924 (edge == Qt::AnchorVerticalCenter))) {
(edge == Qt::A...erticalCenter)Description
TRUEnever evaluated
FALSEnever evaluated
0
1925 removeCenterAnchors(item, edge, true);-
1926 }
never executed: end of block
0
1927 }
never executed: end of block
0
1928}-
1929-
1930void QGraphicsAnchorLayoutPrivate::removeVertex(QGraphicsLayoutItem *item, Qt::AnchorPoint edge)-
1931{-
1932 if (AnchorVertex *v = internalVertex(item, edge)) {
AnchorVertex *...ex(item, edge)Description
TRUEnever evaluated
FALSEnever evaluated
0
1933 Graph<AnchorVertex, AnchorData> &g = graph[edgeOrientation(edge)];-
1934 const QList<AnchorVertex *> allVertices = graph[edgeOrientation(edge)].adjacentVertices(v);-
1935 AnchorVertex *v2;-
1936 foreach (v2, allVertices) {-
1937 g.removeEdge(v, v2);-
1938 removeInternalVertex(item, edge);-
1939 removeInternalVertex(v2->m_item, v2->m_edge);-
1940 }
never executed: end of block
0
1941 }
never executed: end of block
0
1942}
never executed: end of block
0
1943-
1944void QGraphicsAnchorLayoutPrivate::removeAnchors(QGraphicsLayoutItem *item)-
1945{-
1946 // remove the center anchor first!!-
1947 removeCenterAnchors(item, Qt::AnchorHorizontalCenter, false);-
1948 removeVertex(item, Qt::AnchorLeft);-
1949 removeVertex(item, Qt::AnchorRight);-
1950-
1951 removeCenterAnchors(item, Qt::AnchorVerticalCenter, false);-
1952 removeVertex(item, Qt::AnchorTop);-
1953 removeVertex(item, Qt::AnchorBottom);-
1954}
never executed: end of block
0
1955-
1956/*!-
1957 \internal-
1958-
1959 Use heuristics to determine the correct orientation of a given anchor.-
1960-
1961 After API discussions, we decided we would like expressions like-
1962 anchor(A, Left, B, Right) to mean the same as anchor(B, Right, A, Left).-
1963 The problem with this is that anchors could become ambiguous, for-
1964 instance, what does the anchor A, B of size X mean?-
1965-
1966 "pos(B) = pos(A) + X" or "pos(A) = pos(B) + X" ?-
1967-
1968 To keep the API user friendly and at the same time, keep our algorithm-
1969 deterministic, we use an heuristic to determine a direction for each-
1970 added anchor and then keep it. The heuristic is based on the fact-
1971 that people usually avoid overlapping items, therefore:-
1972-
1973 "A, RIGHT to B, LEFT" means that B is to the LEFT of A.-
1974 "B, LEFT to A, RIGHT" is corrected to the above anchor.-
1975-
1976 Special correction is also applied when one of the items is the-
1977 layout. We handle Layout Left as if it was another items's Right-
1978 and Layout Right as another item's Left.-
1979*/-
1980void QGraphicsAnchorLayoutPrivate::correctEdgeDirection(QGraphicsLayoutItem *&firstItem,-
1981 Qt::AnchorPoint &firstEdge,-
1982 QGraphicsLayoutItem *&secondItem,-
1983 Qt::AnchorPoint &secondEdge)-
1984{-
1985 Q_Q(QGraphicsAnchorLayout);-
1986-
1987 if ((firstItem != q) && (secondItem != q)) {
(firstItem != q)Description
TRUEnever evaluated
FALSEnever evaluated
(secondItem != q)Description
TRUEnever evaluated
FALSEnever evaluated
0
1988 // If connection is between widgets (not the layout itself)-
1989 // Ensure that "right-edges" sit to the left of "left-edges".-
1990 if (firstEdge < secondEdge) {
firstEdge < secondEdgeDescription
TRUEnever evaluated
FALSEnever evaluated
0
1991 qSwap(firstItem, secondItem);-
1992 qSwap(firstEdge, secondEdge);-
1993 }
never executed: end of block
0
1994 } else if (firstItem == q) {
never executed: end of block
firstItem == qDescription
TRUEnever evaluated
FALSEnever evaluated
0
1995 // If connection involves the right or bottom of a layout, ensure-
1996 // the layout is the second item.-
1997 if ((firstEdge == Qt::AnchorRight) || (firstEdge == Qt::AnchorBottom)) {
(firstEdge == Qt::AnchorRight)Description
TRUEnever evaluated
FALSEnever evaluated
(firstEdge == ...:AnchorBottom)Description
TRUEnever evaluated
FALSEnever evaluated
0
1998 qSwap(firstItem, secondItem);-
1999 qSwap(firstEdge, secondEdge);-
2000 }
never executed: end of block
0
2001 } else if ((secondEdge != Qt::AnchorRight) && (secondEdge != Qt::AnchorBottom)) {
never executed: end of block
(secondEdge !=...::AnchorRight)Description
TRUEnever evaluated
FALSEnever evaluated
(secondEdge !=...:AnchorBottom)Description
TRUEnever evaluated
FALSEnever evaluated
0
2002 // If connection involves the left, center or top of layout, ensure-
2003 // the layout is the first item.-
2004 qSwap(firstItem, secondItem);-
2005 qSwap(firstEdge, secondEdge);-
2006 }
never executed: end of block
0
2007}
never executed: end of block
0
2008-
2009QLayoutStyleInfo &QGraphicsAnchorLayoutPrivate::styleInfo() const-
2010{-
2011 if (styleInfoDirty) {
styleInfoDirtyDescription
TRUEnever evaluated
FALSEnever evaluated
0
2012 Q_Q(const QGraphicsAnchorLayout);-
2013 //### Fix this if QGV ever gets support for Metal style or different Aqua sizes.-
2014 QWidget *wid = 0;-
2015-
2016 QGraphicsLayoutItem *parent = q->parentLayoutItem();-
2017 while (parent && parent->isLayout()) {
parentDescription
TRUEnever evaluated
FALSEnever evaluated
parent->isLayout()Description
TRUEnever evaluated
FALSEnever evaluated
0
2018 parent = parent->parentLayoutItem();-
2019 }
never executed: end of block
0
2020 QGraphicsWidget *w = 0;-
2021 if (parent) {
parentDescription
TRUEnever evaluated
FALSEnever evaluated
0
2022 QGraphicsItem *parentItem = parent->graphicsItem();-
2023 if (parentItem && parentItem->isWidget())
parentItemDescription
TRUEnever evaluated
FALSEnever evaluated
parentItem->isWidget()Description
TRUEnever evaluated
FALSEnever evaluated
0
2024 w = static_cast<QGraphicsWidget*>(parentItem);
never executed: w = static_cast<QGraphicsWidget*>(parentItem);
0
2025 }
never executed: end of block
0
2026-
2027 QStyle *style = w ? w->style() : QApplication::style();
wDescription
TRUEnever evaluated
FALSEnever evaluated
0
2028 cachedStyleInfo = QLayoutStyleInfo(style, wid);-
2029 cachedStyleInfo.setDefaultSpacing(Qt::Horizontal, spacings[0]);-
2030 cachedStyleInfo.setDefaultSpacing(Qt::Vertical, spacings[1]);-
2031-
2032 styleInfoDirty = false;-
2033 }
never executed: end of block
0
2034 return cachedStyleInfo;
never executed: return cachedStyleInfo;
0
2035}-
2036-
2037/*!-
2038 \internal-
2039-
2040 Called on activation. Uses Linear Programming to define minimum, preferred-
2041 and maximum sizes for the layout. Also calculates the sizes that each item-
2042 should assume when the layout is in one of such situations.-
2043*/-
2044void QGraphicsAnchorLayoutPrivate::calculateGraphs()-
2045{-
2046 if (!calculateGraphCacheDirty)
!calculateGraphCacheDirtyDescription
TRUEnever evaluated
FALSEnever evaluated
0
2047 return;
never executed: return;
0
2048 calculateGraphs(Horizontal);-
2049 calculateGraphs(Vertical);-
2050 calculateGraphCacheDirty = false;-
2051}
never executed: end of block
0
2052-
2053// ### Maybe getGraphParts could return the variables when traversing, at least-
2054// for trunk...-
2055QList<AnchorData *> getVariables(const QList<QSimplexConstraint *> &constraints)-
2056{-
2057 QSet<AnchorData *> variableSet;-
2058 for (int i = 0; i < constraints.count(); ++i) {
i < constraints.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
2059 const QSimplexConstraint *c = constraints.at(i);-
2060 foreach (QSimplexVariable *var, c->variables.keys()) {-
2061 variableSet += static_cast<AnchorData *>(var);-
2062 }
never executed: end of block
0
2063 }
never executed: end of block
0
2064 return variableSet.toList();
never executed: return variableSet.toList();
0
2065}-
2066-
2067/*!-
2068 \internal-
2069-
2070 Calculate graphs is the method that puts together all the helper routines-
2071 so that the AnchorLayout can calculate the sizes of each item.-
2072-
2073 In a nutshell it should do:-
2074-
2075 1) Refresh anchor nominal sizes, that is, the size that each anchor would-
2076 have if no other restrictions applied. This is done by quering the-
2077 layout style and the sizeHints of the items belonging to the layout.-
2078-
2079 2) Simplify the graph by grouping together parallel and sequential anchors-
2080 into "group anchors". These have equivalent minimum, preferred and maximum-
2081 sizeHints as the anchors they replace.-
2082-
2083 3) Check if we got to a trivial case. In some cases, the whole graph can be-
2084 simplified into a single anchor. If so, use this information. If not,-
2085 then call the Simplex solver to calculate the anchors sizes.-
2086-
2087 4) Once the root anchors had its sizes calculated, propagate that to the-
2088 anchors they represent.-
2089*/-
2090void QGraphicsAnchorLayoutPrivate::calculateGraphs(-
2091 QGraphicsAnchorLayoutPrivate::Orientation orientation)-
2092{-
2093#if defined(QT_DEBUG) || defined(QT_BUILD_INTERNAL)-
2094 lastCalculationUsedSimplex[orientation] = false;-
2095#endif-
2096-
2097 static bool simplificationEnabled = qEnvironmentVariableIsEmpty("QT_ANCHORLAYOUT_NO_SIMPLIFICATION");-
2098-
2099 // Reset the nominal sizes of each anchor based on the current item sizes-
2100 refreshAllSizeHints(orientation);-
2101-
2102 // Simplify the graph-
2103 if (simplificationEnabled && !simplifyGraph(orientation)) {
simplificationEnabledDescription
TRUEnever evaluated
FALSEnever evaluated
!simplifyGraph(orientation)Description
TRUEnever evaluated
FALSEnever evaluated
0
2104 qWarning("QGraphicsAnchorLayout: anchor setup is not feasible.");-
2105 graphHasConflicts[orientation] = true;-
2106 return;
never executed: return;
0
2107 }-
2108-
2109 // Traverse all graph edges and store the possible paths to each vertex-
2110 findPaths(orientation);-
2111-
2112 // From the paths calculated above, extract the constraints that the current-
2113 // anchor setup impose, to our Linear Programming problem.-
2114 constraintsFromPaths(orientation);-
2115-
2116 // Split the constraints and anchors into groups that should be fed to the-
2117 // simplex solver independently. Currently we find two groups:-
2118 //-
2119 // 1) The "trunk", that is, the set of anchors (items) that are connected-
2120 // to the two opposite sides of our layout, and thus need to stretch in-
2121 // order to fit in the current layout size.-
2122 //-
2123 // 2) The floating or semi-floating anchors (items) that are those which-
2124 // are connected to only one (or none) of the layout sides, thus are not-
2125 // influenced by the layout size.-
2126 QList<QList<QSimplexConstraint *> > parts = getGraphParts(orientation);-
2127-
2128 // Now run the simplex solver to calculate Minimum, Preferred and Maximum sizes-
2129 // of the "trunk" set of constraints and variables.-
2130 // ### does trunk always exist? empty = trunk is the layout left->center->right-
2131 QList<QSimplexConstraint *> trunkConstraints = parts.at(0);-
2132 QList<AnchorData *> trunkVariables = getVariables(trunkConstraints);-
2133-
2134 // For minimum and maximum, use the path between the two layout sides as the-
2135 // objective function.-
2136 AnchorVertex *v = layoutLastVertex[orientation];-
2137 GraphPath trunkPath = graphPaths[orientation].value(v);-
2138-
2139 bool feasible = calculateTrunk(orientation, trunkPath, trunkConstraints, trunkVariables);-
2140-
2141 // For the other parts that not the trunk, solve only for the preferred size-
2142 // that is the size they will remain at, since they are not stretched by the-
2143 // layout.-
2144-
2145 // Skipping the first (trunk)-
2146 for (int i = 1; i < parts.count(); ++i) {
i < parts.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
2147 if (!feasible)
!feasibleDescription
TRUEnever evaluated
FALSEnever evaluated
0
2148 break;
never executed: break;
0
2149-
2150 QList<QSimplexConstraint *> partConstraints = parts.at(i);-
2151 QList<AnchorData *> partVariables = getVariables(partConstraints);-
2152 Q_ASSERT(!partVariables.isEmpty());-
2153 feasible &= calculateNonTrunk(partConstraints, partVariables);-
2154 }
never executed: end of block
0
2155-
2156 // Propagate the new sizes down the simplified graph, ie. tell the-
2157 // group anchors to set their children anchors sizes.-
2158 updateAnchorSizes(orientation);-
2159-
2160 graphHasConflicts[orientation] = !feasible;-
2161-
2162 // Clean up our data structures. They are not needed anymore since-
2163 // distribution uses just interpolation.-
2164 qDeleteAll(constraints[orientation]);-
2165 constraints[orientation].clear();-
2166 graphPaths[orientation].clear(); // ###-
2167-
2168 if (simplificationEnabled)
simplificationEnabledDescription
TRUEnever evaluated
FALSEnever evaluated
0
2169 restoreSimplifiedGraph(orientation);
never executed: restoreSimplifiedGraph(orientation);
0
2170}
never executed: end of block
0
2171-
2172/*!-
2173 \internal-
2174-
2175 Shift all the constraints by a certain amount. This allows us to deal with negative values in-
2176 the linear program if they are bounded by a certain limit. Functions should be careful to-
2177 call it again with a negative amount, to shift the constraints back.-
2178*/-
2179static void shiftConstraints(const QList<QSimplexConstraint *> &constraints, qreal amount)-
2180{-
2181 for (int i = 0; i < constraints.count(); ++i) {
i < constraints.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
2182 QSimplexConstraint *c = constraints.at(i);-
2183 qreal multiplier = 0;-
2184 foreach (qreal v, c->variables) {-
2185 multiplier += v;-
2186 }
never executed: end of block
0
2187 c->constant += multiplier * amount;-
2188 }
never executed: end of block
0
2189}
never executed: end of block
0
2190-
2191/*!-
2192 \internal-
2193-
2194 Calculate the sizes for all anchors which are part of the trunk. This works-
2195 on top of a (possibly) simplified graph.-
2196*/-
2197bool QGraphicsAnchorLayoutPrivate::calculateTrunk(Orientation orientation, const GraphPath &path,-
2198 const QList<QSimplexConstraint *> &constraints,-
2199 const QList<AnchorData *> &variables)-
2200{-
2201 bool feasible = true;-
2202 bool needsSimplex = !constraints.isEmpty();-
2203-
2204#if 0-
2205 qDebug("Simplex %s for trunk of %s", needsSimplex ? "used" : "NOT used",-
2206 orientation == Horizontal ? "Horizontal" : "Vertical");-
2207#endif-
2208-
2209 if (needsSimplex) {
needsSimplexDescription
TRUEnever evaluated
FALSEnever evaluated
0
2210-
2211 QList<QSimplexConstraint *> sizeHintConstraints = constraintsFromSizeHints(variables);-
2212 QList<QSimplexConstraint *> allConstraints = constraints + sizeHintConstraints;-
2213-
2214 shiftConstraints(allConstraints, g_offset);-
2215-
2216 // Solve min and max size hints-
2217 qreal min, max;-
2218 feasible = solveMinMax(allConstraints, path, &min, &max);-
2219-
2220 if (feasible) {
feasibleDescription
TRUEnever evaluated
FALSEnever evaluated
0
2221 solvePreferred(constraints, variables);-
2222-
2223 // Calculate and set the preferred size for the layout,-
2224 // from the edge sizes that were calculated above.-
2225 qreal pref(0.0);-
2226 foreach (const AnchorData *ad, path.positives) {-
2227 pref += ad->sizeAtPreferred;-
2228 }
never executed: end of block
0
2229 foreach (const AnchorData *ad, path.negatives) {-
2230 pref -= ad->sizeAtPreferred;-
2231 }
never executed: end of block
0
2232-
2233 sizeHints[orientation][Qt::MinimumSize] = min;-
2234 sizeHints[orientation][Qt::PreferredSize] = pref;-
2235 sizeHints[orientation][Qt::MaximumSize] = max;-
2236 }
never executed: end of block
0
2237-
2238 qDeleteAll(sizeHintConstraints);-
2239 shiftConstraints(constraints, -g_offset);-
2240-
2241 } else {
never executed: end of block
0
2242 // No Simplex is necessary because the path was simplified all the way to a single-
2243 // anchor.-
2244 Q_ASSERT(path.positives.count() == 1);-
2245 Q_ASSERT(path.negatives.count() == 0);-
2246-
2247 AnchorData *ad = path.positives.toList()[0];-
2248 ad->sizeAtMinimum = ad->minSize;-
2249 ad->sizeAtPreferred = ad->prefSize;-
2250 ad->sizeAtMaximum = ad->maxSize;-
2251-
2252 sizeHints[orientation][Qt::MinimumSize] = ad->sizeAtMinimum;-
2253 sizeHints[orientation][Qt::PreferredSize] = ad->sizeAtPreferred;-
2254 sizeHints[orientation][Qt::MaximumSize] = ad->sizeAtMaximum;-
2255 }
never executed: end of block
0
2256-
2257#if defined(QT_DEBUG) || defined(QT_BUILD_INTERNAL)-
2258 lastCalculationUsedSimplex[orientation] = needsSimplex;-
2259#endif-
2260-
2261 return feasible;
never executed: return feasible;
0
2262}-
2263-
2264/*!-
2265 \internal-
2266*/-
2267bool QGraphicsAnchorLayoutPrivate::calculateNonTrunk(const QList<QSimplexConstraint *> &constraints,-
2268 const QList<AnchorData *> &variables)-
2269{-
2270 shiftConstraints(constraints, g_offset);-
2271 bool feasible = solvePreferred(constraints, variables);-
2272-
2273 if (feasible) {
feasibleDescription
TRUEnever evaluated
FALSEnever evaluated
0
2274 // Propagate size at preferred to other sizes. Semi-floats always will be-
2275 // in their sizeAtPreferred.-
2276 for (int j = 0; j < variables.count(); ++j) {
j < variables.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
2277 AnchorData *ad = variables.at(j);-
2278 Q_ASSERT(ad);-
2279 ad->sizeAtMinimum = ad->sizeAtPreferred;-
2280 ad->sizeAtMaximum = ad->sizeAtPreferred;-
2281 }
never executed: end of block
0
2282 }
never executed: end of block
0
2283-
2284 shiftConstraints(constraints, -g_offset);-
2285 return feasible;
never executed: return feasible;
0
2286}-
2287-
2288/*!-
2289 \internal-
2290-
2291 Traverse the graph refreshing the size hints. Edges will query their associated-
2292 item or graphicsAnchor for their size hints.-
2293*/-
2294void QGraphicsAnchorLayoutPrivate::refreshAllSizeHints(Orientation orientation)-
2295{-
2296 Graph<AnchorVertex, AnchorData> &g = graph[orientation];-
2297 QList<QPair<AnchorVertex *, AnchorVertex *> > vertices = g.connections();-
2298-
2299 QLayoutStyleInfo styleInf = styleInfo();-
2300 for (int i = 0; i < vertices.count(); ++i) {
i < vertices.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
2301 AnchorData *data = g.edgeData(vertices.at(i).first, vertices.at(i).second);-
2302 data->refreshSizeHints(&styleInf);-
2303 }
never executed: end of block
0
2304}
never executed: end of block
0
2305-
2306/*!-
2307 \internal-
2308-
2309 This method walks the graph using a breadth-first search to find paths-
2310 between the root vertex and each vertex on the graph. The edges-
2311 directions in each path are considered and they are stored as a-
2312 positive edge (left-to-right) or negative edge (right-to-left).-
2313-
2314 The list of paths is used later to generate a list of constraints.-
2315 */-
2316void QGraphicsAnchorLayoutPrivate::findPaths(Orientation orientation)-
2317{-
2318 QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;-
2319-
2320 QSet<AnchorData *> visited;-
2321-
2322 AnchorVertex *root = layoutFirstVertex[orientation];-
2323-
2324 graphPaths[orientation].insert(root, GraphPath());-
2325-
2326 foreach (AnchorVertex *v, graph[orientation].adjacentVertices(root)) {-
2327 queue.enqueue(qMakePair(root, v));-
2328 }
never executed: end of block
0
2329-
2330 while(!queue.isEmpty()) {
!queue.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
2331 QPair<AnchorVertex *, AnchorVertex *> pair = queue.dequeue();-
2332 AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second);-
2333-
2334 if (visited.contains(edge))
visited.contains(edge)Description
TRUEnever evaluated
FALSEnever evaluated
0
2335 continue;
never executed: continue;
0
2336-
2337 visited.insert(edge);-
2338 GraphPath current = graphPaths[orientation].value(pair.first);-
2339-
2340 if (edge->from == pair.first)
edge->from == pair.firstDescription
TRUEnever evaluated
FALSEnever evaluated
0
2341 current.positives.insert(edge);
never executed: current.positives.insert(edge);
0
2342 else-
2343 current.negatives.insert(edge);
never executed: current.negatives.insert(edge);
0
2344-
2345 graphPaths[orientation].insert(pair.second, current);-
2346-
2347 foreach (AnchorVertex *v,-
2348 graph[orientation].adjacentVertices(pair.second)) {-
2349 queue.enqueue(qMakePair(pair.second, v));-
2350 }
never executed: end of block
0
2351 }
never executed: end of block
0
2352-
2353 // We will walk through every reachable items (non-float) store them in a temporary set.-
2354 // We them create a set of all items and subtract the non-floating items from the set in-
2355 // order to get the floating items. The floating items is then stored in m_floatItems-
2356 identifyFloatItems(visited, orientation);-
2357}
never executed: end of block
0
2358-
2359/*!-
2360 \internal-
2361-
2362 Each vertex on the graph that has more than one path to it-
2363 represents a contra int to the sizes of the items in these paths.-
2364-
2365 This method walks the list of paths to each vertex, generate-
2366 the constraints and store them in a list so they can be used later-
2367 by the Simplex solver.-
2368*/-
2369void QGraphicsAnchorLayoutPrivate::constraintsFromPaths(Orientation orientation)-
2370{-
2371 foreach (AnchorVertex *vertex, graphPaths[orientation].uniqueKeys())-
2372 {-
2373 int valueCount = graphPaths[orientation].count(vertex);-
2374 if (valueCount == 1)
valueCount == 1Description
TRUEnever evaluated
FALSEnever evaluated
0
2375 continue;
never executed: continue;
0
2376-
2377 QList<GraphPath> pathsToVertex = graphPaths[orientation].values(vertex);-
2378 for (int i = 1; i < valueCount; ++i) {
i < valueCountDescription
TRUEnever evaluated
FALSEnever evaluated
0
2379 constraints[orientation] += \-
2380 pathsToVertex[0].constraint(pathsToVertex.at(i));-
2381 }
never executed: end of block
0
2382 }
never executed: end of block
0
2383}
never executed: end of block
0
2384-
2385/*!-
2386 \internal-
2387*/-
2388void QGraphicsAnchorLayoutPrivate::updateAnchorSizes(Orientation orientation)-
2389{-
2390 Graph<AnchorVertex, AnchorData> &g = graph[orientation];-
2391 const QList<QPair<AnchorVertex *, AnchorVertex *> > &vertices = g.connections();-
2392-
2393 for (int i = 0; i < vertices.count(); ++i) {
i < vertices.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
2394 AnchorData *ad = g.edgeData(vertices.at(i).first, vertices.at(i).second);-
2395 ad->updateChildrenSizes();-
2396 }
never executed: end of block
0
2397}
never executed: end of block
0
2398-
2399/*!-
2400 \internal-
2401-
2402 Create LP constraints for each anchor based on its minimum and maximum-
2403 sizes, as specified in its size hints-
2404*/-
2405QList<QSimplexConstraint *> QGraphicsAnchorLayoutPrivate::constraintsFromSizeHints(-
2406 const QList<AnchorData *> &anchors)-
2407{-
2408 if (anchors.isEmpty())
anchors.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
2409 return QList<QSimplexConstraint *>();
never executed: return QList<QSimplexConstraint *>();
0
2410-
2411 // Look for the layout edge. That can be either the first half in case the-
2412 // layout is split in two, or the whole layout anchor.-
2413 Orientation orient = Orientation(anchors.first()->orientation);-
2414 AnchorData *layoutEdge = 0;-
2415 if (layoutCentralVertex[orient]) {
layoutCentralVertex[orient]Description
TRUEnever evaluated
FALSEnever evaluated
0
2416 layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutCentralVertex[orient]);-
2417 } else {
never executed: end of block
0
2418 layoutEdge = graph[orient].edgeData(layoutFirstVertex[orient], layoutLastVertex[orient]);-
2419 }
never executed: end of block
0
2420-
2421 // If maxSize is less then "infinite", that means there are other anchors-
2422 // grouped together with this one. We can't ignore its maximum value so we-
2423 // set back the variable to NULL to prevent the continue condition from being-
2424 // satisfied in the loop below.-
2425 const qreal expectedMax = layoutCentralVertex[orient] ? QWIDGETSIZE_MAX / 2 : QWIDGETSIZE_MAX;
layoutCentralVertex[orient]Description
TRUEnever evaluated
FALSEnever evaluated
0
2426 qreal actualMax;-
2427 if (layoutEdge->from == layoutFirstVertex[orient]) {
layoutEdge->fr...Vertex[orient]Description
TRUEnever evaluated
FALSEnever evaluated
0
2428 actualMax = layoutEdge->maxSize;-
2429 } else {
never executed: end of block
0
2430 actualMax = -layoutEdge->minSize;-
2431 }
never executed: end of block
0
2432 if (actualMax != expectedMax) {
actualMax != expectedMaxDescription
TRUEnever evaluated
FALSEnever evaluated
0
2433 layoutEdge = 0;-
2434 }
never executed: end of block
0
2435-
2436 // For each variable, create constraints based on size hints-
2437 QList<QSimplexConstraint *> anchorConstraints;-
2438 bool unboundedProblem = true;-
2439 for (int i = 0; i < anchors.size(); ++i) {
i < anchors.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
2440 AnchorData *ad = anchors.at(i);-
2441-
2442 // Anchors that have their size directly linked to another one don't need constraints-
2443 // For exammple, the second half of an item has exactly the same size as the first half-
2444 // thus constraining the latter is enough.-
2445 if (ad->dependency == AnchorData::Slave)
ad->dependency...horData::SlaveDescription
TRUEnever evaluated
FALSEnever evaluated
0
2446 continue;
never executed: continue;
0
2447-
2448 // To use negative variables inside simplex, we shift them so the minimum negative value is-
2449 // mapped to zero before solving. To make sure that it works, we need to guarantee that the-
2450 // variables are all inside a certain boundary.-
2451 qreal boundedMin = qBound(-g_offset, ad->minSize, g_offset);-
2452 qreal boundedMax = qBound(-g_offset, ad->maxSize, g_offset);-
2453-
2454 if ((boundedMin == boundedMax) || qFuzzyCompare(boundedMin, boundedMax)) {
(boundedMin == boundedMax)Description
TRUEnever evaluated
FALSEnever evaluated
qFuzzyCompare(...n, boundedMax)Description
TRUEnever evaluated
FALSEnever evaluated
0
2455 QSimplexConstraint *c = new QSimplexConstraint;-
2456 c->variables.insert(ad, 1.0);-
2457 c->constant = boundedMin;-
2458 c->ratio = QSimplexConstraint::Equal;-
2459 anchorConstraints += c;-
2460 unboundedProblem = false;-
2461 } else {
never executed: end of block
0
2462 QSimplexConstraint *c = new QSimplexConstraint;-
2463 c->variables.insert(ad, 1.0);-
2464 c->constant = boundedMin;-
2465 c->ratio = QSimplexConstraint::MoreOrEqual;-
2466 anchorConstraints += c;-
2467-
2468 // We avoid adding restrictions to the layout internal anchors. That's-
2469 // to prevent unnecessary fair distribution from happening due to this-
2470 // artificial restriction.-
2471 if (ad == layoutEdge)
ad == layoutEdgeDescription
TRUEnever evaluated
FALSEnever evaluated
0
2472 continue;
never executed: continue;
0
2473-
2474 c = new QSimplexConstraint;-
2475 c->variables.insert(ad, 1.0);-
2476 c->constant = boundedMax;-
2477 c->ratio = QSimplexConstraint::LessOrEqual;-
2478 anchorConstraints += c;-
2479 unboundedProblem = false;-
2480 }
never executed: end of block
0
2481 }-
2482-
2483 // If no upper boundary restriction was added, add one to avoid unbounded problem-
2484 if (unboundedProblem) {
unboundedProblemDescription
TRUEnever evaluated
FALSEnever evaluated
0
2485 QSimplexConstraint *c = new QSimplexConstraint;-
2486 c->variables.insert(layoutEdge, 1.0);-
2487 // The maximum size that the layout can take-
2488 c->constant = g_offset;-
2489 c->ratio = QSimplexConstraint::LessOrEqual;-
2490 anchorConstraints += c;-
2491 }
never executed: end of block
0
2492-
2493 return anchorConstraints;
never executed: return anchorConstraints;
0
2494}-
2495-
2496/*!-
2497 \internal-
2498*/-
2499QList< QList<QSimplexConstraint *> >-
2500QGraphicsAnchorLayoutPrivate::getGraphParts(Orientation orientation)-
2501{-
2502 Q_ASSERT(layoutFirstVertex[orientation] && layoutLastVertex[orientation]);-
2503-
2504 AnchorData *edgeL1 = 0;-
2505 AnchorData *edgeL2 = 0;-
2506-
2507 // The layout may have a single anchor between Left and Right or two half anchors-
2508 // passing through the center-
2509 if (layoutCentralVertex[orientation]) {
layoutCentralV...x[orientation]Description
TRUEnever evaluated
FALSEnever evaluated
0
2510 edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutCentralVertex[orientation]);-
2511 edgeL2 = graph[orientation].edgeData(layoutCentralVertex[orientation], layoutLastVertex[orientation]);-
2512 } else {
never executed: end of block
0
2513 edgeL1 = graph[orientation].edgeData(layoutFirstVertex[orientation], layoutLastVertex[orientation]);-
2514 }
never executed: end of block
0
2515-
2516 QLinkedList<QSimplexConstraint *> remainingConstraints;-
2517 for (int i = 0; i < constraints[orientation].count(); ++i) {
i < constraint...ation].count()Description
TRUEnever evaluated
FALSEnever evaluated
0
2518 remainingConstraints += constraints[orientation].at(i);-
2519 }
never executed: end of block
0
2520 for (int i = 0; i < itemCenterConstraints[orientation].count(); ++i) {
i < itemCenter...ation].count()Description
TRUEnever evaluated
FALSEnever evaluated
0
2521 remainingConstraints += itemCenterConstraints[orientation].at(i);-
2522 }
never executed: end of block
0
2523-
2524 QList<QSimplexConstraint *> trunkConstraints;-
2525 QSet<QSimplexVariable *> trunkVariables;-
2526-
2527 trunkVariables += edgeL1;-
2528 if (edgeL2)
edgeL2Description
TRUEnever evaluated
FALSEnever evaluated
0
2529 trunkVariables += edgeL2;
never executed: trunkVariables += edgeL2;
0
2530-
2531 bool dirty;-
2532 do {-
2533 dirty = false;-
2534-
2535 QLinkedList<QSimplexConstraint *>::iterator it = remainingConstraints.begin();-
2536 while (it != remainingConstraints.end()) {
it != remainin...straints.end()Description
TRUEnever evaluated
FALSEnever evaluated
0
2537 QSimplexConstraint *c = *it;-
2538 bool match = false;-
2539-
2540 // Check if this constraint have some overlap with current-
2541 // trunk variables...-
2542 foreach (QSimplexVariable *ad, trunkVariables) {-
2543 if (c->variables.contains(ad)) {
c->variables.contains(ad)Description
TRUEnever evaluated
FALSEnever evaluated
0
2544 match = true;-
2545 break;
never executed: break;
0
2546 }-
2547 }
never executed: end of block
0
2548-
2549 // If so, we add it to trunk, and erase it from the-
2550 // remaining constraints.-
2551 if (match) {
matchDescription
TRUEnever evaluated
FALSEnever evaluated
0
2552 trunkConstraints += c;-
2553 trunkVariables += QSet<QSimplexVariable *>::fromList(c->variables.keys());-
2554 it = remainingConstraints.erase(it);-
2555 dirty = true;-
2556 } else {
never executed: end of block
0
2557 // Note that we don't erase the constraint if it's not-
2558 // a match, since in a next iteration of a do-while we-
2559 // can pass on it again and it will be a match.-
2560 //-
2561 // For example: if trunk share a variable with-
2562 // remainingConstraints[1] and it shares with-
2563 // remainingConstraints[0], we need a second iteration-
2564 // of the do-while loop to match both.-
2565 ++it;-
2566 }
never executed: end of block
0
2567 }-
2568 } while (dirty);
never executed: end of block
dirtyDescription
TRUEnever evaluated
FALSEnever evaluated
0
2569-
2570 QList< QList<QSimplexConstraint *> > result;-
2571 result += trunkConstraints;-
2572-
2573 if (!remainingConstraints.isEmpty()) {
!remainingCons...ints.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
2574 QList<QSimplexConstraint *> nonTrunkConstraints;-
2575 nonTrunkConstraints.reserve(remainingConstraints.size());-
2576 QLinkedList<QSimplexConstraint *>::iterator it = remainingConstraints.begin();-
2577 while (it != remainingConstraints.end()) {
it != remainin...straints.end()Description
TRUEnever evaluated
FALSEnever evaluated
0
2578 nonTrunkConstraints += *it;-
2579 ++it;-
2580 }
never executed: end of block
0
2581 result += nonTrunkConstraints;-
2582 }
never executed: end of block
0
2583-
2584 return result;
never executed: return result;
0
2585}-
2586-
2587/*!-
2588 \internal-
2589-
2590 Use all visited Anchors on findPaths() so we can identify non-float Items.-
2591*/-
2592void QGraphicsAnchorLayoutPrivate::identifyFloatItems(const QSet<AnchorData *> &visited, Orientation orientation)-
2593{-
2594 QSet<QGraphicsLayoutItem *> nonFloating;-
2595-
2596 foreach (const AnchorData *ad, visited)-
2597 identifyNonFloatItems_helper(ad, &nonFloating);
never executed: identifyNonFloatItems_helper(ad, &nonFloating);
0
2598-
2599 QSet<QGraphicsLayoutItem *> allItems;-
2600 foreach (QGraphicsLayoutItem *item, items)-
2601 allItems.insert(item);
never executed: allItems.insert(item);
0
2602 m_floatItems[orientation] = allItems - nonFloating;-
2603}
never executed: end of block
0
2604-
2605-
2606/*!-
2607 \internal-
2608-
2609 Given an anchor, if it is an internal anchor and Normal we must mark it's item as non-float.-
2610 If the anchor is Sequential or Parallel, we must iterate on its children recursively until we reach-
2611 internal anchors (items).-
2612*/-
2613void QGraphicsAnchorLayoutPrivate::identifyNonFloatItems_helper(const AnchorData *ad, QSet<QGraphicsLayoutItem *> *nonFloatingItemsIdentifiedSoFar)-
2614{-
2615 Q_Q(QGraphicsAnchorLayout);-
2616-
2617 switch(ad->type) {-
2618 case AnchorData::Normal:
never executed: case AnchorData::Normal:
0
2619 if (ad->item && ad->item != q)
ad->itemDescription
TRUEnever evaluated
FALSEnever evaluated
ad->item != qDescription
TRUEnever evaluated
FALSEnever evaluated
0
2620 nonFloatingItemsIdentifiedSoFar->insert(ad->item);
never executed: nonFloatingItemsIdentifiedSoFar->insert(ad->item);
0
2621 break;
never executed: break;
0
2622 case AnchorData::Sequential:
never executed: case AnchorData::Sequential:
0
2623 foreach (const AnchorData *d, static_cast<const SequentialAnchorData *>(ad)->m_edges)-
2624 identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar);
never executed: identifyNonFloatItems_helper(d, nonFloatingItemsIdentifiedSoFar);
0
2625 break;
never executed: break;
0
2626 case AnchorData::Parallel:
never executed: case AnchorData::Parallel:
0
2627 identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->firstEdge, nonFloatingItemsIdentifiedSoFar);-
2628 identifyNonFloatItems_helper(static_cast<const ParallelAnchorData *>(ad)->secondEdge, nonFloatingItemsIdentifiedSoFar);-
2629 break;
never executed: break;
0
2630 }-
2631}
never executed: end of block
0
2632-
2633/*!-
2634 \internal-
2635-
2636 Use the current vertices distance to calculate and set the geometry of-
2637 each item.-
2638*/-
2639void QGraphicsAnchorLayoutPrivate::setItemsGeometries(const QRectF &geom)-
2640{-
2641 Q_Q(QGraphicsAnchorLayout);-
2642 AnchorVertex *firstH, *secondH, *firstV, *secondV;-
2643-
2644 qreal top;-
2645 qreal left;-
2646 qreal right;-
2647-
2648 q->getContentsMargins(&left, &top, &right, 0);-
2649 const Qt::LayoutDirection visualDir = visualDirection();-
2650 if (visualDir == Qt::RightToLeft)
visualDir == Qt::RightToLeftDescription
TRUEnever evaluated
FALSEnever evaluated
0
2651 qSwap(left, right);
never executed: qSwap(left, right);
0
2652-
2653 left += geom.left();-
2654 top += geom.top();-
2655 right = geom.right() - right;-
2656-
2657 foreach (QGraphicsLayoutItem *item, items) {-
2658 QRectF newGeom;-
2659 QSizeF itemPreferredSize = item->effectiveSizeHint(Qt::PreferredSize);-
2660 if (m_floatItems[Horizontal].contains(item)) {
m_floatItems[H...contains(item)Description
TRUEnever evaluated
FALSEnever evaluated
0
2661 newGeom.setLeft(0);-
2662 newGeom.setRight(itemPreferredSize.width());-
2663 } else {
never executed: end of block
0
2664 firstH = internalVertex(item, Qt::AnchorLeft);-
2665 secondH = internalVertex(item, Qt::AnchorRight);-
2666-
2667 if (visualDir == Qt::LeftToRight) {
visualDir == Qt::LeftToRightDescription
TRUEnever evaluated
FALSEnever evaluated
0
2668 newGeom.setLeft(left + firstH->distance);-
2669 newGeom.setRight(left + secondH->distance);-
2670 } else {
never executed: end of block
0
2671 newGeom.setLeft(right - secondH->distance);-
2672 newGeom.setRight(right - firstH->distance);-
2673 }
never executed: end of block
0
2674 }-
2675-
2676 if (m_floatItems[Vertical].contains(item)) {
m_floatItems[V...contains(item)Description
TRUEnever evaluated
FALSEnever evaluated
0
2677 newGeom.setTop(0);-
2678 newGeom.setBottom(itemPreferredSize.height());-
2679 } else {
never executed: end of block
0
2680 firstV = internalVertex(item, Qt::AnchorTop);-
2681 secondV = internalVertex(item, Qt::AnchorBottom);-
2682-
2683 newGeom.setTop(top + firstV->distance);-
2684 newGeom.setBottom(top + secondV->distance);-
2685 }
never executed: end of block
0
2686-
2687 item->setGeometry(newGeom);-
2688 }
never executed: end of block
0
2689}
never executed: end of block
0
2690-
2691/*!-
2692 \internal-
2693-
2694 Calculate the position of each vertex based on the paths to each of-
2695 them as well as the current edges sizes.-
2696*/-
2697void QGraphicsAnchorLayoutPrivate::calculateVertexPositions(-
2698 QGraphicsAnchorLayoutPrivate::Orientation orientation)-
2699{-
2700 QQueue<QPair<AnchorVertex *, AnchorVertex *> > queue;-
2701 QSet<AnchorVertex *> visited;-
2702-
2703 // Get root vertex-
2704 AnchorVertex *root = layoutFirstVertex[orientation];-
2705-
2706 root->distance = 0;-
2707 visited.insert(root);-
2708-
2709 // Add initial edges to the queue-
2710 foreach (AnchorVertex *v, graph[orientation].adjacentVertices(root)) {-
2711 queue.enqueue(qMakePair(root, v));-
2712 }
never executed: end of block
0
2713-
2714 // Do initial calculation required by "interpolateEdge()"-
2715 setupEdgesInterpolation(orientation);-
2716-
2717 // Traverse the graph and calculate vertex positions-
2718 while (!queue.isEmpty()) {
!queue.isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
2719 QPair<AnchorVertex *, AnchorVertex *> pair = queue.dequeue();-
2720 AnchorData *edge = graph[orientation].edgeData(pair.first, pair.second);-
2721-
2722 if (visited.contains(pair.second))
visited.contains(pair.second)Description
TRUEnever evaluated
FALSEnever evaluated
0
2723 continue;
never executed: continue;
0
2724-
2725 visited.insert(pair.second);-
2726 interpolateEdge(pair.first, edge);-
2727-
2728 QList<AnchorVertex *> adjacents = graph[orientation].adjacentVertices(pair.second);-
2729 for (int i = 0; i < adjacents.count(); ++i) {
i < adjacents.count()Description
TRUEnever evaluated
FALSEnever evaluated
0
2730 if (!visited.contains(adjacents.at(i)))
!visited.conta...jacents.at(i))Description
TRUEnever evaluated
FALSEnever evaluated
0
2731 queue.enqueue(qMakePair(pair.second, adjacents.at(i)));
never executed: queue.enqueue(qMakePair(pair.second, adjacents.at(i)));
0
2732 }
never executed: end of block
0
2733 }
never executed: end of block
0
2734}
never executed: end of block
0
2735-
2736/*!-
2737 \internal-
2738-
2739 Calculate interpolation parameters based on current Layout Size.-
2740 Must be called once before calling "interpolateEdgeSize()" for-
2741 the edges.-
2742*/-
2743void QGraphicsAnchorLayoutPrivate::setupEdgesInterpolation(-
2744 Orientation orientation)-
2745{-
2746 Q_Q(QGraphicsAnchorLayout);-
2747-
2748 qreal current;-
2749 current = (orientation == Horizontal) ? q->contentsRect().width() : q->contentsRect().height();
(orientation == Horizontal)Description
TRUEnever evaluated
FALSEnever evaluated
0
2750-
2751 QPair<Interval, qreal> result;-
2752 result = getFactor(current,-
2753 sizeHints[orientation][Qt::MinimumSize],-
2754 sizeHints[orientation][Qt::PreferredSize],-
2755 sizeHints[orientation][Qt::PreferredSize],-
2756 sizeHints[orientation][Qt::PreferredSize],-
2757 sizeHints[orientation][Qt::MaximumSize]);-
2758-
2759 interpolationInterval[orientation] = result.first;-
2760 interpolationProgress[orientation] = result.second;-
2761}
never executed: end of block
0
2762-
2763/*!-
2764 \internal-
2765-
2766 Calculate the current Edge size based on the current Layout size and the-
2767 size the edge is supposed to have when the layout is at its:-
2768-
2769 - minimum size,-
2770 - preferred size,-
2771 - maximum size.-
2772-
2773 These three key values are calculated in advance using linear-
2774 programming (more expensive) or the simplification algorithm, then-
2775 subsequential resizes of the parent layout require a simple-
2776 interpolation.-
2777*/-
2778void QGraphicsAnchorLayoutPrivate::interpolateEdge(AnchorVertex *base, AnchorData *edge)-
2779{-
2780 const Orientation orientation = Orientation(edge->orientation);-
2781 const QPair<Interval, qreal> factor(interpolationInterval[orientation],-
2782 interpolationProgress[orientation]);-
2783-
2784 qreal edgeDistance = interpolate(factor, edge->sizeAtMinimum, edge->sizeAtPreferred,-
2785 edge->sizeAtPreferred, edge->sizeAtPreferred,-
2786 edge->sizeAtMaximum);-
2787-
2788 Q_ASSERT(edge->from == base || edge->to == base);-
2789-
2790 // Calculate the distance for the vertex opposite to the base-
2791 if (edge->from == base) {
edge->from == baseDescription
TRUEnever evaluated
FALSEnever evaluated
0
2792 edge->to->distance = base->distance + edgeDistance;-
2793 } else {
never executed: end of block
0
2794 edge->from->distance = base->distance - edgeDistance;-
2795 }
never executed: end of block
0
2796}-
2797-
2798bool QGraphicsAnchorLayoutPrivate::solveMinMax(const QList<QSimplexConstraint *> &constraints,-
2799 GraphPath path, qreal *min, qreal *max)-
2800{-
2801 QSimplex simplex;-
2802 bool feasible = simplex.setConstraints(constraints);-
2803 if (feasible) {
feasibleDescription
TRUEnever evaluated
FALSEnever evaluated
0
2804 // Obtain the objective constraint-
2805 QSimplexConstraint objective;-
2806 QSet<AnchorData *>::const_iterator iter;-
2807 for (iter = path.positives.constBegin(); iter != path.positives.constEnd(); ++iter)
iter != path.p...ves.constEnd()Description
TRUEnever evaluated
FALSEnever evaluated
0
2808 objective.variables.insert(*iter, 1.0);
never executed: objective.variables.insert(*iter, 1.0);
0
2809-
2810 for (iter = path.negatives.constBegin(); iter != path.negatives.constEnd(); ++iter)
iter != path.n...ves.constEnd()Description
TRUEnever evaluated
FALSEnever evaluated
0
2811 objective.variables.insert(*iter, -1.0);
never executed: objective.variables.insert(*iter, -1.0);
0
2812-
2813 const qreal objectiveOffset = (path.positives.count() - path.negatives.count()) * g_offset;-
2814 simplex.setObjective(&objective);-
2815-
2816 // Calculate minimum values-
2817 *min = simplex.solveMin() - objectiveOffset;-
2818-
2819 // Save sizeAtMinimum results-
2820 QList<AnchorData *> variables = getVariables(constraints);-
2821 for (int i = 0; i < variables.size(); ++i) {
i < variables.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
2822 AnchorData *ad = static_cast<AnchorData *>(variables.at(i));-
2823 ad->sizeAtMinimum = ad->result - g_offset;-
2824 }
never executed: end of block
0
2825-
2826 // Calculate maximum values-
2827 *max = simplex.solveMax() - objectiveOffset;-
2828-
2829 // Save sizeAtMaximum results-
2830 for (int i = 0; i < variables.size(); ++i) {
i < variables.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
2831 AnchorData *ad = static_cast<AnchorData *>(variables.at(i));-
2832 ad->sizeAtMaximum = ad->result - g_offset;-
2833 }
never executed: end of block
0
2834 }
never executed: end of block
0
2835 return feasible;
never executed: return feasible;
0
2836}-
2837-
2838enum slackType { Grower = -1, Shrinker = 1 };-
2839static QPair<QSimplexVariable *, QSimplexConstraint *> createSlack(QSimplexConstraint *sizeConstraint,-
2840 qreal interval, slackType type)-
2841{-
2842 QSimplexVariable *slack = new QSimplexVariable;-
2843 sizeConstraint->variables.insert(slack, type);-
2844-
2845 QSimplexConstraint *limit = new QSimplexConstraint;-
2846 limit->variables.insert(slack, 1.0);-
2847 limit->ratio = QSimplexConstraint::LessOrEqual;-
2848 limit->constant = interval;-
2849-
2850 return qMakePair(slack, limit);
never executed: return qMakePair(slack, limit);
0
2851}-
2852-
2853bool QGraphicsAnchorLayoutPrivate::solvePreferred(const QList<QSimplexConstraint *> &constraints,-
2854 const QList<AnchorData *> &variables)-
2855{-
2856 QList<QSimplexConstraint *> preferredConstraints;-
2857 QList<QSimplexVariable *> preferredVariables;-
2858 QSimplexConstraint objective;-
2859-
2860 // Fill the objective coefficients for this variable. In the-
2861 // end the objective function will be-
2862 //-
2863 // z = n * (A_shrinker_hard + A_grower_hard + B_shrinker_hard + B_grower_hard + ...) +-
2864 // (A_shrinker_soft + A_grower_soft + B_shrinker_soft + B_grower_soft + ...)-
2865 //-
2866 // where n is the number of variables that have-
2867 // slacks. Note that here we use the number of variables-
2868 // as coefficient, this is to mark the "shrinker slack-
2869 // variable" less likely to get value than the "grower-
2870 // slack variable".-
2871-
2872 // This will fill the values for the structural constraints-
2873 // and we now fill the values for the slack constraints (one per variable),-
2874 // which have this form (the constant A_pref was set when creating the slacks):-
2875 //-
2876 // A + A_shrinker_hard + A_shrinker_soft - A_grower_hard - A_grower_soft = A_pref-
2877 //-
2878 for (int i = 0; i < variables.size(); ++i) {
i < variables.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
2879 AnchorData *ad = variables.at(i);-
2880-
2881 // The layout original structure anchors are not relevant in preferred size calculation-
2882 if (ad->isLayoutAnchor)
ad->isLayoutAnchorDescription
TRUEnever evaluated
FALSEnever evaluated
0
2883 continue;
never executed: continue;
0
2884-
2885 // By default, all variables are equal to their preferred size. If they have room to-
2886 // grow or shrink, such flexibility will be added by the additional variables below.-
2887 QSimplexConstraint *sizeConstraint = new QSimplexConstraint;-
2888 preferredConstraints += sizeConstraint;-
2889 sizeConstraint->variables.insert(ad, 1.0);-
2890 sizeConstraint->constant = ad->prefSize + g_offset;-
2891-
2892 // Can easily shrink-
2893 QPair<QSimplexVariable *, QSimplexConstraint *> slack;-
2894 const qreal softShrinkInterval = ad->prefSize - ad->minPrefSize;-
2895 if (softShrinkInterval) {
softShrinkIntervalDescription
TRUEnever evaluated
FALSEnever evaluated
0
2896 slack = createSlack(sizeConstraint, softShrinkInterval, Shrinker);-
2897 preferredVariables += slack.first;-
2898 preferredConstraints += slack.second;-
2899-
2900 // Add to objective with ratio == 1 (soft)-
2901 objective.variables.insert(slack.first, 1.0);-
2902 }
never executed: end of block
0
2903-
2904 // Can easily grow-
2905 const qreal softGrowInterval = ad->maxPrefSize - ad->prefSize;-
2906 if (softGrowInterval) {
softGrowIntervalDescription
TRUEnever evaluated
FALSEnever evaluated
0
2907 slack = createSlack(sizeConstraint, softGrowInterval, Grower);-
2908 preferredVariables += slack.first;-
2909 preferredConstraints += slack.second;-
2910-
2911 // Add to objective with ratio == 1 (soft)-
2912 objective.variables.insert(slack.first, 1.0);-
2913 }
never executed: end of block
0
2914-
2915 // Can shrink if really necessary-
2916 const qreal hardShrinkInterval = ad->minPrefSize - ad->minSize;-
2917 if (hardShrinkInterval) {
hardShrinkIntervalDescription
TRUEnever evaluated
FALSEnever evaluated
0
2918 slack = createSlack(sizeConstraint, hardShrinkInterval, Shrinker);-
2919 preferredVariables += slack.first;-
2920 preferredConstraints += slack.second;-
2921-
2922 // Add to objective with ratio == N (hard)-
2923 objective.variables.insert(slack.first, variables.size());-
2924 }
never executed: end of block
0
2925-
2926 // Can grow if really necessary-
2927 const qreal hardGrowInterval = ad->maxSize - ad->maxPrefSize;-
2928 if (hardGrowInterval) {
hardGrowIntervalDescription
TRUEnever evaluated
FALSEnever evaluated
0
2929 slack = createSlack(sizeConstraint, hardGrowInterval, Grower);-
2930 preferredVariables += slack.first;-
2931 preferredConstraints += slack.second;-
2932-
2933 // Add to objective with ratio == N (hard)-
2934 objective.variables.insert(slack.first, variables.size());-
2935 }
never executed: end of block
0
2936 }
never executed: end of block
0
2937-
2938 QSimplex *simplex = new QSimplex;-
2939 bool feasible = simplex->setConstraints(constraints + preferredConstraints);-
2940 if (feasible) {
feasibleDescription
TRUEnever evaluated
FALSEnever evaluated
0
2941 simplex->setObjective(&objective);-
2942-
2943 // Calculate minimum values-
2944 simplex->solveMin();-
2945-
2946 // Save sizeAtPreferred results-
2947 for (int i = 0; i < variables.size(); ++i) {
i < variables.size()Description
TRUEnever evaluated
FALSEnever evaluated
0
2948 AnchorData *ad = variables.at(i);-
2949 ad->sizeAtPreferred = ad->result - g_offset;-
2950 }
never executed: end of block
0
2951 }
never executed: end of block
0
2952-
2953 // Make sure we delete the simplex solver -before- we delete the-
2954 // constraints used by it.-
2955 delete simplex;-
2956-
2957 // Delete constraints and variables we created.-
2958 qDeleteAll(preferredConstraints);-
2959 qDeleteAll(preferredVariables);-
2960-
2961 return feasible;
never executed: return feasible;
0
2962}-
2963-
2964/*!-
2965 \internal-
2966 Returns \c true if there are no arrangement that satisfies all constraints.-
2967 Otherwise returns \c false.-
2968-
2969 \sa addAnchor()-
2970*/-
2971bool QGraphicsAnchorLayoutPrivate::hasConflicts() const-
2972{-
2973 QGraphicsAnchorLayoutPrivate *that = const_cast<QGraphicsAnchorLayoutPrivate*>(this);-
2974 that->calculateGraphs();-
2975-
2976 bool floatConflict = !m_floatItems[0].isEmpty() || !m_floatItems[1].isEmpty();
!m_floatItems[0].isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
!m_floatItems[1].isEmpty()Description
TRUEnever evaluated
FALSEnever evaluated
0
2977-
2978 return graphHasConflicts[0] || graphHasConflicts[1] || floatConflict;
never executed: return graphHasConflicts[0] || graphHasConflicts[1] || floatConflict;
graphHasConflicts[0]Description
TRUEnever evaluated
FALSEnever evaluated
graphHasConflicts[1]Description
TRUEnever evaluated
FALSEnever evaluated
floatConflictDescription
TRUEnever evaluated
FALSEnever evaluated
0
2979}-
2980-
2981#ifdef QT_DEBUG-
2982void QGraphicsAnchorLayoutPrivate::dumpGraph(const QString &name)-
2983{-
2984 QFile file(QString::fromLatin1("anchorlayout.%1.dot").arg(name));-
2985 if (!file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate))
!file.open(QIO...ice::Truncate)Description
TRUEnever evaluated
FALSEnever evaluated
0
2986 qWarning("Could not write to %s", file.fileName().toLocal8Bit().constData());
never executed: QMessageLogger(__FILE__, 2986, __PRETTY_FUNCTION__).warning("Could not write to %s", file.fileName().toLocal8Bit().constData());
0
2987-
2988 QString str = QString::fromLatin1("digraph anchorlayout {\nnode [shape=\"rect\"]\n%1}");-
2989 QString dotContents = graph[0].serializeToDot();-
2990 dotContents += graph[1].serializeToDot();-
2991 file.write(str.arg(dotContents).toLocal8Bit());-
2992-
2993 file.close();-
2994}
never executed: end of block
0
2995#endif-
2996-
2997QT_END_NAMESPACE-
2998#endif //QT_NO_GRAPHICSVIEW-
Source codeSwitch to Preprocessed file

Generated by Squish Coco Non-Commercial 4.3.0-BETA-master-30-08-2018-4cb69e9