1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the test suite of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
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 https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
21 | ** included in the packaging of this file. Please review the following |
22 | ** information to ensure the GNU General Public License requirements will |
23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
24 | ** |
25 | ** $QT_END_LICENSE$ |
26 | ** |
27 | ****************************************************************************/ |
28 | |
29 | |
30 | #include <QtTest/QtTest> |
31 | #include <qlayout.h> |
32 | #include <qapplication.h> |
33 | #include <qwidget.h> |
34 | #include <qproxystyle.h> |
35 | #include <qsizepolicy.h> |
36 | //#include <QtGui> |
37 | |
38 | #include <QtWidgets/QLabel> |
39 | #include <QtWidgets/QLineEdit> |
40 | #include <QtWidgets/QRadioButton> |
41 | #include <QStyleFactory> |
42 | #include <QSharedPointer> |
43 | |
44 | #include <QtTest/private/qtesthelpers_p.h> |
45 | |
46 | using namespace QTestPrivate; |
47 | |
48 | class tst_QGridLayout : public QObject |
49 | { |
50 | Q_OBJECT |
51 | |
52 | private slots: |
53 | void cleanup(); |
54 | void getItemPosition(); |
55 | void itemAtPosition(); |
56 | void badDistributionBug(); |
57 | void setMinAndMaxSize(); |
58 | void spacingAndSpacers(); |
59 | |
60 | void spacingsAndMargins(); |
61 | void spacingsAndMargins_data(); |
62 | void minMaxSize_data(); |
63 | void minMaxSize(); |
64 | |
65 | void styleDependentSpacingsAndMargins_data(); |
66 | void styleDependentSpacingsAndMargins(); |
67 | void layoutSpacing_data(); |
68 | void layoutSpacing(); |
69 | void spacing(); |
70 | void spacerWithSpacing(); |
71 | void contentsRect(); |
72 | void distributeMultiCell(); |
73 | |
74 | void taskQTBUG_27420_takeAtShouldUnparentLayout(); |
75 | void taskQTBUG_40609_addingWidgetToItsOwnLayout(); |
76 | void taskQTBUG_40609_addingLayoutToItself(); |
77 | void taskQTBUG_52357_spacingWhenItemIsHidden(); |
78 | void taskQTBUG_91261_itemIndexRange(); |
79 | void replaceWidget(); |
80 | void dontCrashWhenExtendsToEnd(); |
81 | }; |
82 | |
83 | static inline int visibleTopLevelWidgetCount() |
84 | { |
85 | int result= 0; |
86 | foreach (const QWidget *topLevel, QApplication::topLevelWidgets()) { |
87 | if (topLevel->isVisible()) |
88 | ++result; |
89 | } |
90 | return result; |
91 | } |
92 | |
93 | void tst_QGridLayout::cleanup() |
94 | { |
95 | // Verify that no visible top levels are leaked. Cannot check for |
96 | // topLevelWidgets().isEmpty() here since the data driven test layoutSpacing() |
97 | // will appear to "leak" top levels due to it creating widgets in the test data. |
98 | QCOMPARE(visibleTopLevelWidgetCount(), 0); |
99 | } |
100 | |
101 | class ItemTestWidget : public QWidget { |
102 | public: |
103 | ItemTestWidget(); |
104 | |
105 | QGridLayout *testLayout; |
106 | QWidget *w1; |
107 | QWidget *w2; |
108 | QWidget *w3; |
109 | QSpacerItem *sp; |
110 | }; |
111 | |
112 | ItemTestWidget::ItemTestWidget() |
113 | : testLayout(new QGridLayout(this)) |
114 | , w1(new QWidget(this)) |
115 | , w2(new QWidget(this)) |
116 | , w3(new QWidget(this)) |
117 | , sp(new QSpacerItem(4, 4)) |
118 | { |
119 | setObjectName("testWidget" ); |
120 | setWindowTitle(QTest::currentTestFunction()); |
121 | |
122 | w1->setPalette(QPalette(Qt::red)); |
123 | testLayout->addWidget(w1, row: 0, column: 0); |
124 | |
125 | testLayout->addWidget(w2, row: 1, column: 1, rowSpan: 2, columnSpan: 2); |
126 | w2->setPalette(QPalette(Qt::green)); |
127 | |
128 | testLayout->addWidget(w3, row: 0, column: 1, rowSpan: 1, columnSpan: 2); |
129 | w3->setPalette(QPalette(Qt::blue)); |
130 | |
131 | testLayout->addItem(item: sp, row: 1, column: 3, rowSpan: 2, columnSpan: 1); |
132 | } |
133 | |
134 | void tst_QGridLayout::getItemPosition() |
135 | { |
136 | ItemTestWidget testWidget; |
137 | testWidget.resize(w: 200, h: 200); |
138 | testWidget.show(); |
139 | |
140 | QLayoutItem *item; |
141 | int counter = 0; |
142 | |
143 | bool seenW1 = false; |
144 | bool seenW2 = false; |
145 | bool seenW3 = false; |
146 | bool seenSpacer = false; |
147 | |
148 | while ((item = testWidget.testLayout->itemAt(index: counter))) { |
149 | QWidget *w = item->widget(); |
150 | int r,c,rs,cs; |
151 | testWidget.testLayout->getItemPosition(idx: counter, row: &r, column: &c, rowSpan: &rs, columnSpan: &cs); |
152 | |
153 | // qDebug() << "item" << counter << "has" <<r << c << rs << cs; |
154 | |
155 | if (w == testWidget.w1) { |
156 | QVERIFY(!seenW1); |
157 | seenW1 = true; |
158 | QCOMPARE(r, 0); |
159 | QCOMPARE(c, 0); |
160 | QCOMPARE(rs, 1); |
161 | QCOMPARE(cs, 1); |
162 | } else if (w == testWidget.w2) { |
163 | QVERIFY(!seenW2); |
164 | seenW2 = true; |
165 | QCOMPARE(r, 1); |
166 | QCOMPARE(c, 1); |
167 | QCOMPARE(rs, 2); |
168 | QCOMPARE(cs, 2); |
169 | } else if (w == testWidget.w3) { |
170 | QVERIFY(!seenW3); |
171 | seenW3 = true; |
172 | QCOMPARE(r, 0); |
173 | QCOMPARE(c, 1); |
174 | QCOMPARE(rs, 1); |
175 | QCOMPARE(cs, 2); |
176 | } else { |
177 | QVERIFY(!w); |
178 | QVERIFY(!seenSpacer); |
179 | seenSpacer = true; |
180 | QCOMPARE(r, 1); |
181 | QCOMPARE(c, 3); |
182 | QCOMPARE(rs, 2); |
183 | QCOMPARE(cs, 1); |
184 | } |
185 | ++counter; |
186 | } |
187 | QCOMPARE(counter, 4); |
188 | QVERIFY(seenW1); |
189 | QVERIFY(seenW2); |
190 | QVERIFY(seenW3); |
191 | QVERIFY(seenSpacer); |
192 | } |
193 | |
194 | void tst_QGridLayout::itemAtPosition() |
195 | { |
196 | ItemTestWidget testWidget; |
197 | testWidget.resize(w: 200, h: 200); |
198 | testWidget.show(); |
199 | |
200 | void *table[4][5] = { |
201 | { testWidget.w1, testWidget.w3,testWidget.w3, 0, 0 }, |
202 | { 0, testWidget.w2, testWidget.w2, testWidget.sp, 0 }, |
203 | { 0, testWidget.w2, testWidget.w2, testWidget.sp, 0 }, |
204 | { 0, 0, 0, 0, 0 } |
205 | }; |
206 | |
207 | for (int row = 0; row < 4; ++row) { |
208 | for (int col = 0; col < 5; ++col) { |
209 | QLayoutItem *item = testWidget.testLayout->itemAtPosition(row, column: col); |
210 | QVERIFY(item == table[row][col] |
211 | || (item && item->widget() == table[row][col])); |
212 | } |
213 | } |
214 | } |
215 | |
216 | #include "ui_sortdialog.h" |
217 | |
218 | void tst_QGridLayout::badDistributionBug() |
219 | { |
220 | QDialog dialog; |
221 | Ui::SortDialog ui; |
222 | ui.setupUi(&dialog); |
223 | ui.gridLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0); |
224 | ui.gridLayout->setSpacing(0); |
225 | ui.vboxLayout->setContentsMargins(left: 0, top: 0, right: 0, bottom: 0); |
226 | ui.vboxLayout->setSpacing(0); |
227 | ui.okButton->setFixedHeight(20); |
228 | ui.moreButton->setFixedHeight(20); |
229 | ui.primaryGroupBox->setAttribute(Qt::WA_LayoutUsesWidgetRect); |
230 | ui.primaryGroupBox->setFixedHeight(200); |
231 | |
232 | QSize minSize = dialog.layout()->minimumSize(); |
233 | QCOMPARE(minSize.height(), 200); |
234 | } |
235 | |
236 | void tst_QGridLayout::setMinAndMaxSize() |
237 | { |
238 | QWidget widget; |
239 | setFrameless(&widget); |
240 | QGridLayout layout(&widget); |
241 | layout.setContentsMargins(left: 0, top: 0, right: 0, bottom: 0); |
242 | layout.setSpacing(0); |
243 | layout.setSizeConstraint(QLayout::SetMinAndMaxSize); |
244 | widget.show(); |
245 | |
246 | QWidget leftChild; |
247 | leftChild.setPalette(QPalette(Qt::red)); |
248 | leftChild.setMinimumSize(minw: 100, minh: 100); |
249 | leftChild.setMaximumSize(maxw: 200, maxh: 200); |
250 | layout.addWidget(&leftChild, row: 0, column: 0); |
251 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
252 | QCOMPARE(widget.minimumSize(), leftChild.minimumSize()); |
253 | QCOMPARE(widget.maximumSize(), leftChild.maximumSize()); |
254 | |
255 | QWidget rightChild; |
256 | rightChild.setPalette(QPalette(Qt::green)); |
257 | rightChild.setMinimumSize(minw: 100, minh: 100); |
258 | rightChild.setMaximumSize(maxw: 200, maxh: 200); |
259 | layout.addWidget(&rightChild, row: 0, column: 2); |
260 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
261 | |
262 | QCOMPARE(widget.minimumWidth(), |
263 | leftChild.minimumWidth() + rightChild.minimumWidth()); |
264 | QCOMPARE(widget.minimumHeight(), |
265 | qMax(leftChild.minimumHeight(), rightChild.minimumHeight())); |
266 | QCOMPARE(widget.maximumWidth(), |
267 | leftChild.maximumWidth() + rightChild.maximumWidth()); |
268 | QCOMPARE(widget.maximumHeight(), |
269 | qMax(leftChild.maximumHeight(), rightChild.maximumHeight())); |
270 | |
271 | |
272 | static const int colMin = 100; |
273 | layout.setColumnMinimumWidth(column: 1, minSize: colMin); |
274 | QCOMPARE(layout.columnMinimumWidth(1), colMin); |
275 | |
276 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
277 | QCOMPARE(widget.minimumWidth(), |
278 | leftChild.minimumWidth() + rightChild.minimumWidth() + colMin); |
279 | QCOMPARE(widget.maximumWidth(), |
280 | leftChild.maximumWidth() + rightChild.maximumWidth() + colMin); |
281 | QCOMPARE(widget.minimumHeight(), |
282 | qMax(leftChild.minimumHeight(), rightChild.minimumHeight())); |
283 | QCOMPARE(widget.maximumHeight(), |
284 | qMax(leftChild.maximumHeight(), rightChild.maximumHeight())); |
285 | |
286 | |
287 | |
288 | layout.setColumnStretch(column: 1,stretch: 1); |
289 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
290 | QCOMPARE(widget.minimumWidth(), |
291 | leftChild.minimumWidth() + rightChild.minimumWidth() + colMin); |
292 | QCOMPARE(widget.maximumWidth(), QLAYOUTSIZE_MAX); |
293 | QCOMPARE(widget.minimumHeight(), |
294 | qMax(leftChild.minimumHeight(), rightChild.minimumHeight())); |
295 | QCOMPARE(widget.maximumHeight(), |
296 | qMax(leftChild.maximumHeight(), rightChild.maximumHeight())); |
297 | |
298 | |
299 | |
300 | layout.setColumnStretch(column: 1,stretch: 0); |
301 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
302 | QCOMPARE(widget.minimumWidth(), |
303 | leftChild.minimumWidth() + rightChild.minimumWidth() + colMin); |
304 | QCOMPARE(widget.maximumWidth(), |
305 | leftChild.maximumWidth() + rightChild.maximumWidth() + colMin); |
306 | QCOMPARE(widget.minimumHeight(), |
307 | qMax(leftChild.minimumHeight(), rightChild.minimumHeight())); |
308 | QCOMPARE(widget.maximumHeight(), |
309 | qMax(leftChild.maximumHeight(), rightChild.maximumHeight())); |
310 | |
311 | |
312 | |
313 | layout.setColumnMinimumWidth(column: 1, minSize: 0); |
314 | |
315 | static const int spacerS = 250; |
316 | QSpacerItem *spacer = new QSpacerItem(spacerS, spacerS); |
317 | layout.addItem(item: spacer, row: 0, column: 1); |
318 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
319 | |
320 | QCOMPARE(widget.minimumWidth(), |
321 | leftChild.minimumWidth() + rightChild.minimumWidth() + spacerS); |
322 | QCOMPARE(widget.maximumWidth(), QLAYOUTSIZE_MAX); |
323 | QCOMPARE(widget.minimumHeight(), |
324 | qMax(qMax(leftChild.minimumHeight(), rightChild.minimumHeight()), spacerS)); |
325 | QCOMPARE(widget.maximumHeight(), |
326 | qMax(leftChild.maximumHeight(), rightChild.maximumHeight())); |
327 | |
328 | |
329 | spacer->changeSize(w: spacerS, h: spacerS, hData: QSizePolicy::Fixed, vData: QSizePolicy::Minimum); |
330 | layout.invalidate(); |
331 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
332 | QCOMPARE(widget.minimumWidth(), |
333 | leftChild.minimumWidth() + rightChild.minimumWidth() + spacerS); |
334 | QCOMPARE(widget.maximumWidth(), |
335 | leftChild.maximumWidth() + rightChild.maximumWidth() + spacerS); |
336 | |
337 | |
338 | layout.removeItem(spacer); |
339 | delete spacer; |
340 | spacer = nullptr; |
341 | |
342 | rightChild.hide(); |
343 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
344 | QCOMPARE(widget.minimumSize(), leftChild.minimumSize()); |
345 | QCOMPARE(widget.maximumSize(), leftChild.maximumSize()); |
346 | |
347 | rightChild.show(); |
348 | layout.removeWidget(w: &rightChild); |
349 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
350 | QCOMPARE(widget.minimumSize(), leftChild.minimumSize()); |
351 | QCOMPARE(widget.maximumSize(), leftChild.maximumSize()); |
352 | |
353 | QWidget bottomChild(&widget); |
354 | bottomChild.setPalette(QPalette(Qt::green)); |
355 | bottomChild.setMinimumSize(minw: 100, minh: 100); |
356 | bottomChild.setMaximumSize(maxw: 200, maxh: 200); |
357 | layout.addWidget(&bottomChild, row: 1, column: 0); |
358 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
359 | |
360 | QCOMPARE(widget.minimumHeight(), |
361 | leftChild.minimumHeight() + bottomChild.minimumHeight()); |
362 | QCOMPARE(widget.minimumWidth(), |
363 | qMax(leftChild.minimumWidth(), bottomChild.minimumWidth())); |
364 | QCOMPARE(widget.maximumHeight(), |
365 | leftChild.maximumHeight() + bottomChild.maximumHeight()); |
366 | QCOMPARE(widget.maximumWidth(), |
367 | qMax(leftChild.maximumWidth(), bottomChild.maximumWidth())); |
368 | |
369 | bottomChild.hide(); |
370 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
371 | QCOMPARE(widget.minimumSize(), leftChild.minimumSize()); |
372 | QCOMPARE(widget.maximumSize(), leftChild.maximumSize()); |
373 | |
374 | bottomChild.show(); |
375 | layout.removeWidget(w: &bottomChild); |
376 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
377 | QCOMPARE(widget.minimumSize(), leftChild.minimumSize()); |
378 | QCOMPARE(widget.maximumSize(), leftChild.maximumSize()); |
379 | } |
380 | |
381 | |
382 | class SizeHinter : public QWidget |
383 | { |
384 | public: |
385 | SizeHinter(const QSize &s, QWidget *parent = 0) |
386 | : QWidget(parent), sh(s) { } |
387 | SizeHinter(int w, int h, QWidget *parent = 0) |
388 | : QWidget(parent), sh(QSize(w,h)) {} |
389 | void setSizeHint(QSize s) { sh = s; } |
390 | QSize sizeHint() const { return sh; } |
391 | private: |
392 | QSize sh; |
393 | }; |
394 | |
395 | void tst_QGridLayout::spacingAndSpacers() |
396 | { |
397 | QWidget widget; |
398 | setFrameless(&widget); |
399 | QGridLayout layout(&widget); |
400 | layout.setContentsMargins(left: 0, top: 0, right: 0, bottom: 0); |
401 | layout.setSpacing(0); |
402 | widget.show(); |
403 | |
404 | QSize expectedSizeHint; |
405 | |
406 | SizeHinter leftChild(100,100); |
407 | leftChild.setPalette(QPalette(Qt::red)); |
408 | layout.addWidget(&leftChild, row: 0, column: 0); |
409 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
410 | expectedSizeHint = leftChild.sizeHint(); |
411 | QCOMPARE(widget.sizeHint(), expectedSizeHint); |
412 | |
413 | |
414 | SizeHinter rightChild(200,100); |
415 | rightChild.setPalette(QPalette(Qt::green)); |
416 | layout.addWidget(&rightChild, row: 0, column: 2); |
417 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
418 | QCOMPARE(rightChild.sizeHint(), QSize(200,100)); |
419 | |
420 | expectedSizeHint += QSize(rightChild.sizeHint().width(), 0); |
421 | QCOMPARE(widget.sizeHint(), expectedSizeHint); |
422 | |
423 | layout.setColumnMinimumWidth(column: 1, minSize: 100); |
424 | widget.adjustSize(); |
425 | expectedSizeHint += QSize(100,0); |
426 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
427 | QCOMPARE(widget.sizeHint(), expectedSizeHint); |
428 | |
429 | rightChild.hide(); |
430 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
431 | expectedSizeHint -= QSize(rightChild.sizeHint().width(), 0); |
432 | QCOMPARE(widget.sizeHint(), expectedSizeHint); |
433 | |
434 | |
435 | layout.setColumnMinimumWidth(column: 1, minSize: 0); |
436 | expectedSizeHint -= QSize(100, 0); |
437 | QCOMPARE(widget.sizeHint(), expectedSizeHint); |
438 | |
439 | rightChild.show(); |
440 | |
441 | layout.removeWidget(w: &rightChild); |
442 | QApplication::sendPostedEvents(receiver: 0, event_type: 0); |
443 | QCOMPARE(widget.sizeHint(), expectedSizeHint); |
444 | } |
445 | |
446 | |
447 | class Qt42Style : public QProxyStyle |
448 | { |
449 | Q_OBJECT |
450 | public: |
451 | Qt42Style() : QProxyStyle(QStyleFactory::create("windows" )) |
452 | { |
453 | spacing = 6; |
454 | margin = 9; |
455 | margin_toplevel = 11; |
456 | } |
457 | |
458 | virtual int pixelMetric(PixelMetric metric, const QStyleOption * option = 0, |
459 | const QWidget * widget = 0 ) const; |
460 | |
461 | int spacing; |
462 | int margin; |
463 | int margin_toplevel; |
464 | |
465 | }; |
466 | |
467 | int Qt42Style::pixelMetric(PixelMetric metric, const QStyleOption * option /*= 0*/, |
468 | const QWidget * widget /*= 0*/ ) const |
469 | { |
470 | switch (metric) { |
471 | case PM_DefaultLayoutSpacing: |
472 | return spacing; |
473 | break; |
474 | case PM_DefaultTopLevelMargin: |
475 | return margin_toplevel; |
476 | break; |
477 | case PM_DefaultChildMargin: |
478 | return margin; |
479 | break; |
480 | default: |
481 | break; |
482 | } |
483 | return QProxyStyle::pixelMetric(metric, option, widget); |
484 | } |
485 | |
486 | |
487 | typedef QList<QPoint> PointList; |
488 | |
489 | |
490 | class SizeHinterFrame : public QLabel |
491 | { |
492 | public: |
493 | SizeHinterFrame(QWidget *parent = 0) |
494 | : QLabel(parent) |
495 | { |
496 | init(numPixels: -1); |
497 | } |
498 | |
499 | SizeHinterFrame(const QSize &s, int numPixels = -1) |
500 | : QLabel(0), sh(s) { |
501 | init(numPixels); |
502 | } |
503 | |
504 | |
505 | SizeHinterFrame(int w, int h) |
506 | : QLabel(0), sh(QSize(w,h)) |
507 | { |
508 | init(numPixels: -1); |
509 | } |
510 | |
511 | void setSizeHint(const QSize &s) { sh = s; } |
512 | QSize sizeHint() const { return sh; } |
513 | void setMinimumSizeHint(const QSize &s) { msh = s; } |
514 | QSize minimumSizeHint() const { return msh; } |
515 | |
516 | virtual int heightForWidth(int width) const; |
517 | |
518 | void setNumberOfPixels(int numPixels) { |
519 | m_numPixels = numPixels; |
520 | QSizePolicy sp = sizePolicy(); |
521 | sp.setHeightForWidth(m_numPixels != -1); |
522 | setSizePolicy(sp); |
523 | } |
524 | private: |
525 | void init(int numPixels = -1){ |
526 | setText(QLatin1Char('(') + QString::number(sh.width()) |
527 | + QLatin1Char(',') + QString::number(sh.height()) + QLatin1Char(')')); |
528 | setFrameStyle(QFrame::Box | QFrame::Plain); |
529 | setNumberOfPixels(numPixels); |
530 | } |
531 | private: |
532 | QSize sh; |
533 | QSize msh; |
534 | int m_numPixels; |
535 | }; |
536 | |
537 | int SizeHinterFrame::heightForWidth(int width) const |
538 | { |
539 | // Special hack if m_numPixels == -2 then we report that we are heightForWidth aware, but we |
540 | // return sizeHint().width() so that it should be laid out as if we had't any hfw. |
541 | // This enables us to run the tests twice and to see if we get the same results with hfw as without hfw. |
542 | if (m_numPixels == -2) { |
543 | return sizeHint().height(); |
544 | } |
545 | if (m_numPixels == -1 || width == 0) return -1; |
546 | // this widget should always cover the same amount of pixels (provided that we don't get any rounding errors) |
547 | return (m_numPixels)/width; |
548 | } |
549 | |
550 | void tst_QGridLayout::spacingsAndMargins_data() |
551 | { |
552 | // input |
553 | QTest::addColumn<int>(name: "columns" ); |
554 | QTest::addColumn<int>(name: "rows" ); |
555 | QTest::addColumn<QSize>(name: "sizehint" ); |
556 | // expected |
557 | QTest::addColumn<PointList>(name: "expectedpositions" ); |
558 | |
559 | int child_offset_y = 11 + 100 + 6 + 9 ; |
560 | QTest::newRow(dataTag: "1x1 grid" ) << 1 << 1 << QSize(100, 100) |
561 | << (PointList() // toplevel |
562 | << QPoint( 11, 11) |
563 | // children |
564 | << QPoint( 20, child_offset_y) |
565 | ); |
566 | |
567 | QTest::newRow(dataTag: "2x1 grid" ) << 2 << 1 << QSize(100, 100) |
568 | << (PointList() // toplevel |
569 | << QPoint( 11, 11) |
570 | << QPoint( 11 + 100 + 6, 11) |
571 | // children |
572 | << QPoint( 20, child_offset_y) |
573 | << QPoint( 20 + 100 + 6, child_offset_y) |
574 | ); |
575 | |
576 | QTest::newRow(dataTag: "3x1 grid" ) << 3 << 1 << QSize(100, 100) |
577 | << (PointList() // toplevel |
578 | << QPoint( 11, 11) |
579 | << QPoint( 11 + 100 + 6, 11) |
580 | << QPoint( 11 + 100 + 6 + 100 + 6, 11) |
581 | // children |
582 | << QPoint( 20, child_offset_y) |
583 | << QPoint( 20 + 100 + 6, child_offset_y) |
584 | << QPoint( 20 + 100 + 6 + 100 + 6, child_offset_y) |
585 | ); |
586 | |
587 | child_offset_y = 11 + 9 + 100 + 6 + 100 + 6; |
588 | QTest::newRow(dataTag: "1x2 grid" ) << 1 << 2 << QSize(100, 100) |
589 | << (PointList() // toplevel |
590 | << QPoint( 11, 11) |
591 | << QPoint( 11, 11 + 100 + 6) |
592 | // children |
593 | << QPoint( 20, child_offset_y) |
594 | << QPoint( 20, child_offset_y + 100 + 6) |
595 | ); |
596 | child_offset_y = 11 + 9 + 100 + 6 + 100 + 6 + 100 + 6; |
597 | QTest::newRow(dataTag: "1x3 grid" ) << 1 << 3 << QSize(100, 100) |
598 | << (PointList() // toplevel |
599 | << QPoint( 11, 11) |
600 | << QPoint( 11, 11 + 100 + 6) |
601 | << QPoint( 11, 11 + 100 + 6 + 100 + 6) |
602 | // children |
603 | << QPoint( 20, child_offset_y) |
604 | << QPoint( 20, child_offset_y + 100 + 6) |
605 | << QPoint( 20, child_offset_y + 100 + 6 + 100 + 6) |
606 | ); |
607 | |
608 | child_offset_y = 11 + 9 + 100 + 6 + 100 + 6; |
609 | QTest::newRow(dataTag: "2x2 grid" ) << 2 << 2 << QSize(100, 100) |
610 | << (PointList() // toplevel |
611 | << QPoint( 11, 11) |
612 | << QPoint( 11 + 100 + 6, 11) |
613 | << QPoint( 11, 11 + 100 + 6) |
614 | << QPoint( 11 + 100 + 6, 11 + 100 + 6) |
615 | // children |
616 | << QPoint( 20, child_offset_y) |
617 | << QPoint( 20 + 100 + 6, child_offset_y) |
618 | << QPoint( 20, child_offset_y + 100 + 6) |
619 | << QPoint( 20 + 100 + 6, child_offset_y + 100 + 6) |
620 | ); |
621 | } |
622 | |
623 | void tst_QGridLayout::spacingsAndMargins() |
624 | { |
625 | /* |
626 | The test tests a gridlayout as a child of a top-level widget, |
627 | and then a gridlayout as a child of a non-toplevel widget. |
628 | |
629 | The expectedpositions should then contain the list of widget positions in the |
630 | first gridlayout, then followed by a list of widget positions in the second gridlayout. |
631 | */ |
632 | QFETCH(int, columns); |
633 | QFETCH(int, rows); |
634 | QFETCH(QSize, sizehint); |
635 | QFETCH(PointList, expectedpositions); |
636 | |
637 | |
638 | QApplication::setStyle(new Qt42Style); |
639 | QWidget toplevel; |
640 | setFrameless(&toplevel); |
641 | |
642 | QVBoxLayout vbox(&toplevel); |
643 | QGridLayout grid1; |
644 | vbox.addLayout(layout: &grid1); |
645 | |
646 | // a layout with a top-level parent widget |
647 | QList<QPointer<SizeHinterFrame> > sizehinters; |
648 | for (int i = 0; i < rows; ++i) { |
649 | for (int j = 0; j < columns; ++j) { |
650 | SizeHinterFrame *sh = new SizeHinterFrame(sizehint); |
651 | sh->setMinimumSizeHint(sizehint); |
652 | sizehinters.append(t: sh); |
653 | grid1.addWidget(sh, row: i, column: j); |
654 | } |
655 | } |
656 | |
657 | // Add the child widget |
658 | QWidget widget; |
659 | vbox.addWidget(&widget); |
660 | QGridLayout grid2; |
661 | widget.setLayout(&grid2); |
662 | // add a layout to the child widget |
663 | for (int i = 0; i < rows; ++i) { |
664 | for (int j = 0; j < columns; ++j) { |
665 | SizeHinterFrame *sh = new SizeHinterFrame(sizehint); |
666 | sh->setMinimumSizeHint(sizehint); |
667 | sizehinters.append(t: sh); |
668 | grid2.addWidget(sh, row: i, column: j); |
669 | } |
670 | } |
671 | |
672 | grid1.setColumnStretch(column: columns-1, stretch: 1); |
673 | grid1.setRowStretch(row: rows-1, stretch: 1); |
674 | toplevel.showNormal(); |
675 | toplevel.adjustSize(); |
676 | QApplication::processEvents(); |
677 | QVERIFY(QTest::qWaitForWindowExposed(&toplevel)); |
678 | |
679 | QSize topsize = toplevel.size(); |
680 | QSize minimumsize = vbox.totalMinimumSize(); |
681 | |
682 | if (topsize.width() < minimumsize.width() || topsize.height() < minimumsize.height()) |
683 | QSKIP("The screen is too small to run this test case" ); |
684 | |
685 | // We are relying on the order here... |
686 | for (int pi = 0; pi < sizehinters.count(); ++pi) { |
687 | QPoint pt = sizehinters.at(i: pi)->mapTo(&toplevel, QPoint(0, 0)); |
688 | QCOMPARE(pt, expectedpositions.at(pi)); |
689 | } |
690 | } |
691 | |
692 | |
693 | |
694 | |
695 | struct SizeInfo { |
696 | SizeInfo(const QPoint &expected, const QSize &sh, const QSize &minimumSize = QSize(), |
697 | const QSize &maximumSize = QSize(), int numPixelsToCover = -1) |
698 | { |
699 | expectedPos = expected; |
700 | sizeHint = sh; |
701 | minSize = minimumSize; |
702 | maxSize = maximumSize; |
703 | hfwNumPixels = numPixelsToCover; |
704 | } |
705 | |
706 | SizeInfo(const QRect &expected, const QSize &sh, const QSize &minimumSize = QSize(), |
707 | const QSize &maximumSize = QSize(), int numPixelsToCover = -1) |
708 | { |
709 | expectedPos = expected.topLeft(); |
710 | expectedSize = expected.size(); |
711 | sizeHint = sh; |
712 | minSize = minimumSize; |
713 | maxSize = maximumSize; |
714 | hfwNumPixels = numPixelsToCover; |
715 | } |
716 | SizeInfo(const SizeInfo& other) { |
717 | (*this)=other; |
718 | } |
719 | |
720 | SizeInfo &operator=(const SizeInfo& other) { |
721 | expectedPos = other.expectedPos; |
722 | expectedSize = other.expectedSize; |
723 | sizeHint = other.sizeHint; |
724 | minSize = other.minSize; |
725 | maxSize = other.maxSize; |
726 | hfwNumPixels = other.hfwNumPixels; |
727 | return (*this); |
728 | } |
729 | |
730 | QPoint expectedPos; |
731 | QSize expectedSize; |
732 | QSize sizeHint; |
733 | QSize minSize; |
734 | QSize maxSize; |
735 | int hfwNumPixels; |
736 | }; |
737 | |
738 | |
739 | typedef QList<SizeInfo> SizeInfoList; |
740 | Q_DECLARE_METATYPE(SizeInfoList) |
741 | |
742 | |
743 | void tst_QGridLayout::minMaxSize_data() |
744 | { |
745 | // input |
746 | QTest::addColumn<QString>(name: "stylename" ); |
747 | QTest::addColumn<int>(name: "columns" ); |
748 | QTest::addColumn<int>(name: "rows" ); |
749 | QTest::addColumn<int>(name: "sizePolicy" ); |
750 | QTest::addColumn<QSize>(name: "fixedSize" ); |
751 | //input and expected output |
752 | QTest::addColumn<SizeInfoList>(name: "sizeinfos" ); |
753 | |
754 | QTest::newRow(dataTag: "3x1 grid, extend to minimumSize" ) << QString() << 3 << 1 |
755 | << int(QSizePolicy::Minimum) << QSize(152, 50) << (SizeInfoList() |
756 | << SizeInfo(QRect(10, 10, 43, 30), QSize( 75, 75), QSize(0,0)) |
757 | << SizeInfo(QRect(10 + 45, 10, 43, 30), QSize(75, 75), QSize( 0, 0)) |
758 | << SizeInfo(QRect(10 + 45 + 44, 10, 42, 30), QSize(75, 75), QSize( 0, 0)) |
759 | ); |
760 | |
761 | QTest::newRow(dataTag: "1x1 grid, extend to minimumSize" ) << QString() << 1 << 1 |
762 | << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() |
763 | << SizeInfo(QPoint(10, 10), QSize( 90, 90), QSize(100,100)) |
764 | ); |
765 | QTest::newRow(dataTag: "2x1 grid, extend to minimumSize" ) << QString() << 2 << 1 |
766 | << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() |
767 | << SizeInfo(QPoint(10, 10), QSize( 90, 90), QSize(100,100)) |
768 | << SizeInfo(QPoint(10 + 100 + 1, 10), QSize( 90, 90)) |
769 | ); |
770 | QTest::newRow(dataTag: "2x1 grid, extend to minimumSize, windows" ) << QString::fromLatin1(str: "windows" ) << 2 << 1 |
771 | << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() |
772 | << SizeInfo(QPoint(11, 11), QSize( 90, 90), QSize(100,100)) |
773 | << SizeInfo(QPoint(11 + 100 + 6, 11), QSize( 90, 90)) |
774 | ); |
775 | QTest::newRow(dataTag: "1x2 grid, extend to minimumSize" ) << QString() << 1 << 2 |
776 | << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() |
777 | << SizeInfo(QPoint(10, 10), QSize( 90, 90), QSize(100,100)) |
778 | << SizeInfo(QPoint(10, 10 + 100 + 1), QSize( 90, 90)) |
779 | ); |
780 | QTest::newRow(dataTag: "2x1 grid, crop to maximumSize" ) << QString() << 2 << 1 |
781 | << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() |
782 | << SizeInfo(QPoint(10, 10), QSize(110,110), QSize(), QSize(100, 100)) |
783 | << SizeInfo(QPoint(10 + 100 + 1, 10), QSize( 90, 90)) |
784 | ); |
785 | QTest::newRow(dataTag: "1x2 grid, crop to maximumSize" ) << QString() << 1 << 2 |
786 | << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() |
787 | << SizeInfo(QPoint(10, 10), QSize(110,110), QSize(), QSize(100, 100)) |
788 | << SizeInfo(QPoint(10, 10 + 100 + 1), QSize( 90, 90)) |
789 | ); |
790 | QTest::newRow(dataTag: "1x3 grid, heightForWidth" ) << QString() << 1 << 3 |
791 | << int(QSizePolicy::Preferred) << QSize() << (SizeInfoList() |
792 | << SizeInfo(QPoint(10, 10), QSize(), QSize(200,100), QSize()) |
793 | << SizeInfo(QPoint(10, 10 + 100 + 1), QSize(100,100), QSize(), QSize(), 100*100) |
794 | << SizeInfo(QPoint(10, 10 + 100 + 1 + 50 + 1), QSize(100,100), QSize(), QSize(100, 100)) |
795 | ); |
796 | } |
797 | |
798 | void tst_QGridLayout::minMaxSize() |
799 | { |
800 | /* |
801 | The test tests a gridlayout as a child of a top-level widget |
802 | */ |
803 | // input |
804 | QFETCH(QString, stylename); |
805 | QFETCH(int, columns); |
806 | QFETCH(int, rows); |
807 | QFETCH(int, sizePolicy); |
808 | QFETCH(QSize, fixedSize); |
809 | //input and expected output |
810 | QFETCH(SizeInfoList, sizeinfos); |
811 | |
812 | QStyle *style = 0; |
813 | if (stylename.isEmpty()) { |
814 | Qt42Style *s = new Qt42Style; |
815 | s->margin_toplevel = 10; |
816 | s->margin = 5; |
817 | s->spacing = 1; |
818 | style = static_cast<QStyle *>(s); |
819 | }else{ |
820 | style = QStyleFactory::create(stylename); |
821 | if (!style) { |
822 | QSKIP( qPrintable(QString::fromLatin1("Qt has been compiled without style: %1" ).arg(stylename))); |
823 | } |
824 | } |
825 | QApplication::setStyle(style); |
826 | QWidget toplevel; |
827 | toplevel.setWindowTitle(QLatin1String(QTest::currentTestFunction()) |
828 | + QLatin1Char(' ') + QLatin1String(QTest::currentDataTag())); |
829 | setFrameless(&toplevel); |
830 | QGridLayout *grid = new QGridLayout; |
831 | if (fixedSize.isValid()) { |
832 | toplevel.setFixedSize(fixedSize); |
833 | } else { |
834 | toplevel.setMinimumSize(QSize(0,0)); |
835 | toplevel.setMaximumSize(QSize(QWIDGETSIZE_MAX,QWIDGETSIZE_MAX)); |
836 | } |
837 | // Do a two-pass one using the real testdata, the other pass enables heightForWidth |
838 | // on the widget, but the heightForWidth() function just return sizeHint().width() |
839 | for (int pass = 0; pass < 2; ++pass) { |
840 | toplevel.hide(); |
841 | QApplication::processEvents(); |
842 | QTest::qWait(ms: 20); |
843 | // Test if removeItem uninitializes data properly |
844 | while (grid->count()) { |
845 | QLayoutItem *item = grid->itemAt(index: 0); |
846 | grid->removeItem(item); |
847 | delete item->widget(); |
848 | delete item; |
849 | } |
850 | toplevel.setLayout(grid); |
851 | |
852 | // a layout with a top-level parent widget |
853 | QList<QPointer<SizeHinterFrame> > sizehinters; |
854 | for (int i = 0; i < rows; ++i) { |
855 | for (int j = 0; j < columns; ++j) { |
856 | SizeInfo si = sizeinfos.at(i: sizehinters.count()); |
857 | int numpixels = si.hfwNumPixels; |
858 | if (pass == 1 && numpixels == -1) |
859 | numpixels = -2; //### yuk, (and don't fake it if it already tests sizehint) |
860 | SizeHinterFrame *sh = new SizeHinterFrame(si.sizeHint, numpixels); |
861 | QSizePolicy sp = sh->sizePolicy(); |
862 | sp.setHorizontalPolicy((QSizePolicy::Policy)sizePolicy); |
863 | sh->setSizePolicy(sp); |
864 | sh->setParent(&toplevel); |
865 | if (si.minSize.isValid()) |
866 | sh->setMinimumSize(si.minSize); |
867 | if (si.maxSize.isValid()) |
868 | sh->setMaximumSize(si.maxSize); |
869 | sizehinters.append(t: sh); |
870 | grid->addWidget(sh, row: i, column: j); |
871 | } |
872 | } |
873 | |
874 | toplevel.show(); |
875 | QVERIFY(QTest::qWaitForWindowExposed(&toplevel)); |
876 | toplevel.adjustSize(); |
877 | QTest::qWait(ms: 240); // wait for the implicit adjustSize |
878 | // If the following fails we might have to wait longer. |
879 | // If that does not help there is likely a problem with the implicit adjustSize in show() |
880 | if (!fixedSize.isValid()) { |
881 | // Note that this can fail if the desktop has large fonts on windows. |
882 | QTRY_COMPARE(toplevel.size(), toplevel.sizeHint()); |
883 | } |
884 | // We are relying on the order here... |
885 | for (int pi = 0; pi < sizehinters.count(); ++pi) { |
886 | QPoint pt = sizehinters.at(i: pi)->mapTo(&toplevel, QPoint(0, 0)); |
887 | QCOMPARE(pt, sizeinfos.at(pi).expectedPos); |
888 | } |
889 | } |
890 | } |
891 | |
892 | |
893 | class CustomLayoutStyle : public QProxyStyle |
894 | { |
895 | Q_OBJECT |
896 | public: |
897 | CustomLayoutStyle() : QProxyStyle(QStyleFactory::create("windows" )) |
898 | { |
899 | hspacing = 5; |
900 | vspacing = 10; |
901 | reimplementSubelementRect = false; |
902 | } |
903 | |
904 | virtual int pixelMetric(PixelMetric metric, const QStyleOption * option = 0, |
905 | const QWidget * widget = 0 ) const; |
906 | virtual QRect subElementRect(SubElement sr, const QStyleOption *opt, |
907 | const QWidget *widget) const; |
908 | |
909 | int hspacing; |
910 | int vspacing; |
911 | bool reimplementSubelementRect; |
912 | |
913 | int layoutSpacing(QSizePolicy::ControlType control1, |
914 | QSizePolicy::ControlType control2, |
915 | Qt::Orientation orientation, |
916 | const QStyleOption *option = 0, |
917 | const QWidget *widget = 0) const; |
918 | |
919 | }; |
920 | |
921 | QRect CustomLayoutStyle::subElementRect(SubElement sr, const QStyleOption *opt, |
922 | const QWidget *widget) const |
923 | { |
924 | QRect rect; |
925 | if (reimplementSubelementRect) { |
926 | switch (sr) { |
927 | case SE_FrameLayoutItem: |
928 | rect = opt->rect; |
929 | rect.adjust(dx1: +4, dy1: +9, dx2: -4, dy2: 0); // The hspacing=5 and vspacing=10, so we keep it safe. |
930 | break; |
931 | case SE_GroupBoxLayoutItem: |
932 | rect = opt->rect.adjusted(xp1: 0, yp1: +10, xp2: 0, yp2: 0); |
933 | break; |
934 | default: |
935 | break; |
936 | } |
937 | } |
938 | if (rect.isNull()) |
939 | rect = QProxyStyle::subElementRect(element: sr, option: opt, widget); |
940 | return rect; |
941 | } |
942 | |
943 | #define CT1(c) CT2(c, c) |
944 | #define CT2(c1, c2) ((uint)c1 << 16) | (uint)c2 |
945 | |
946 | int CustomLayoutStyle::layoutSpacing(QSizePolicy::ControlType control1, |
947 | QSizePolicy::ControlType control2, |
948 | Qt::Orientation orientation, |
949 | const QStyleOption * /*option = 0*/, |
950 | const QWidget * /*widget = 0*/) const |
951 | { |
952 | if (orientation == Qt::Horizontal) { |
953 | switch (CT2(control1, control2)) { |
954 | case CT1(QSizePolicy::PushButton): |
955 | return 2; |
956 | break; |
957 | } |
958 | return 5; |
959 | } else { |
960 | switch (CT2(control1, control2)) { |
961 | case CT1(QSizePolicy::RadioButton): |
962 | return 2; |
963 | break; |
964 | |
965 | } |
966 | return 10; |
967 | } |
968 | } |
969 | |
970 | int CustomLayoutStyle::pixelMetric(PixelMetric metric, const QStyleOption * option /*= 0*/, |
971 | const QWidget * widget /*= 0*/ ) const |
972 | { |
973 | switch (metric) { |
974 | case PM_LayoutLeftMargin: |
975 | return 0; |
976 | break; |
977 | case PM_LayoutTopMargin: |
978 | return 3; |
979 | break; |
980 | case PM_LayoutRightMargin: |
981 | return 6; |
982 | break; |
983 | case PM_LayoutBottomMargin: |
984 | return 9; |
985 | break; |
986 | case PM_LayoutHorizontalSpacing: |
987 | return hspacing; |
988 | case PM_LayoutVerticalSpacing: |
989 | return vspacing; |
990 | break; |
991 | default: |
992 | break; |
993 | } |
994 | return QProxyStyle::pixelMetric(metric, option, widget); |
995 | } |
996 | |
997 | void tst_QGridLayout::styleDependentSpacingsAndMargins_data() |
998 | { |
999 | // input |
1000 | QTest::addColumn<int>(name: "columns" ); |
1001 | QTest::addColumn<int>(name: "rows" ); |
1002 | QTest::addColumn<QSize>(name: "sizehint" ); |
1003 | // expected |
1004 | QTest::addColumn<PointList>(name: "expectedpositions" ); |
1005 | |
1006 | QTest::newRow(dataTag: "1x1 grid" ) << 1 << 1 << QSize(100, 100) |
1007 | << (PointList() << QPoint(0, 3) ); |
1008 | QTest::newRow(dataTag: "2x1 grid" ) << 2 << 1 << QSize(100, 100) |
1009 | << (PointList() << QPoint(0, 3) |
1010 | << QPoint(0+100+5, 3)); |
1011 | QTest::newRow(dataTag: "3x1 grid" ) << 3 << 1 << QSize(100, 100) |
1012 | << (PointList() << QPoint(0, 3) |
1013 | << QPoint(0+100+5, 3) |
1014 | << QPoint(0 + 2*105, 3)); |
1015 | QTest::newRow(dataTag: "1x2 grid" ) << 1 << 2 << QSize(100, 100) |
1016 | << (PointList() << QPoint(0, 3) |
1017 | << QPoint(0, 3+100+10)); |
1018 | QTest::newRow(dataTag: "1x3 grid" ) << 1 << 3 << QSize(100, 100) |
1019 | << (PointList() << QPoint(0, 3) |
1020 | << QPoint(0, 3+100+10) |
1021 | << QPoint(0, 3+2*110)); |
1022 | QTest::newRow(dataTag: "2x2 grid" ) << 2 << 2 << QSize(100, 100) |
1023 | << (PointList() << QPoint(0, 3) << QPoint(0+100+5, 3) |
1024 | << QPoint(0, 3+100+10) << QPoint(0+100+5, 3+100+10)); |
1025 | } |
1026 | |
1027 | |
1028 | void tst_QGridLayout::styleDependentSpacingsAndMargins() |
1029 | { |
1030 | QFETCH(int, columns); |
1031 | QFETCH(int, rows); |
1032 | QFETCH(QSize, sizehint); |
1033 | QFETCH(PointList, expectedpositions); |
1034 | |
1035 | QApplication::setStyle(new CustomLayoutStyle()); |
1036 | QWidget widget; |
1037 | setFrameless(&widget); |
1038 | QGridLayout layout(&widget); |
1039 | QList<QPointer<SizeHinterFrame> > sizehinters; |
1040 | for (int i = 0; i < rows; ++i) { |
1041 | for (int j = 0; j < columns; ++j) { |
1042 | SizeHinterFrame *sh = new SizeHinterFrame(sizehint); |
1043 | sh->setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed)); |
1044 | sh->setParent(&widget); |
1045 | sizehinters.append(t: sh); |
1046 | layout.addWidget(sh, row: i, column: j); |
1047 | } |
1048 | } |
1049 | layout.setColumnStretch(column: columns, stretch: 1); |
1050 | layout.setRowStretch(row: rows, stretch: 1); |
1051 | widget.show(); |
1052 | widget.adjustSize(); |
1053 | QApplication::processEvents(); |
1054 | |
1055 | for (int pi = 0; pi < expectedpositions.count(); ++pi) { |
1056 | QCOMPARE(sizehinters.at(pi)->pos(), expectedpositions.at(pi)); |
1057 | } |
1058 | } |
1059 | |
1060 | void tst_QGridLayout::layoutSpacing_data() |
1061 | { |
1062 | QTest::addColumn<QWidget*>(name: "widget" ); |
1063 | // expected |
1064 | QTest::addColumn<PointList>(name: "expectedpositions" ); |
1065 | QTest::addColumn<int>(name: "hSpacing" ); |
1066 | QTest::addColumn<int>(name: "vSpacing" ); |
1067 | QTest::addColumn<bool>(name: "customSubElementRect" ); |
1068 | |
1069 | CustomLayoutStyle *style = new CustomLayoutStyle(); |
1070 | { |
1071 | // If the layoutSpacing is negative, the layouting code will call |
1072 | // layoutSpacing() |
1073 | style->hspacing = -1; |
1074 | style->vspacing = -1; |
1075 | style->reimplementSubelementRect = false; |
1076 | QApplication::setStyle(style); |
1077 | QWidget *w = new QWidget(); |
1078 | setFrameless(w); |
1079 | QVBoxLayout *layout = new QVBoxLayout(); |
1080 | QRadioButton *rb1 = new QRadioButton(QLatin1String("Radio 1" ), w); |
1081 | QRadioButton *rb2 = new QRadioButton(QLatin1String("Radio 2" ), w); |
1082 | QRadioButton *rb3 = new QRadioButton(QLatin1String("Radio 3" ), w); |
1083 | layout->addWidget(rb1, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1084 | layout->addWidget(rb2, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1085 | layout->addWidget(rb3, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1086 | |
1087 | QPushButton *b1 = new QPushButton(QLatin1String("Push 1" ), w); |
1088 | QPushButton *b2 = new QPushButton(QLatin1String("Push 2" ), w); |
1089 | QPushButton *b3 = new QPushButton(QLatin1String("Push 3" ), w); |
1090 | layout->addWidget(b1, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1091 | layout->addWidget(b2, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1092 | layout->addWidget(b3, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1093 | |
1094 | layout->addStretch(stretch: 1); |
1095 | w->setLayout(layout); |
1096 | int rh = rb1->sizeHint().height(); |
1097 | int ph = b1->sizeHint().height(); |
1098 | QTest::newRow(dataTag: "1x6, radio + push buttons" ) |
1099 | << w << (PointList() |
1100 | << QPoint(0, 3) |
1101 | << QPoint(0, 3 + rh + 2) |
1102 | << QPoint(0, 3 + 2*(rh + 2)) |
1103 | << QPoint(0, 3 + 2*(rh + 2) + (rh + 10)) |
1104 | << QPoint(0, 3 + 2*(rh + 2) + (rh + 10 + ph + 10)) |
1105 | << QPoint(0, 3 + 2*(rh + 2) + rh + 10 + 2*(ph + 10))) |
1106 | << style->hspacing << style->vspacing << style->reimplementSubelementRect; |
1107 | } |
1108 | |
1109 | { |
1110 | style->hspacing = -1; |
1111 | style->vspacing = -1; |
1112 | style->reimplementSubelementRect = false; |
1113 | QApplication::setStyle(style); |
1114 | QWidget *w = new QWidget(); |
1115 | setFrameless(w); |
1116 | QHBoxLayout *layout = new QHBoxLayout(); |
1117 | QLineEdit *le1 = new QLineEdit(w); |
1118 | QLineEdit *le2 = new QLineEdit(w); |
1119 | QLineEdit *le3 = new QLineEdit(w); |
1120 | layout->addWidget(le1, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1121 | layout->addWidget(le2, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1122 | layout->addWidget(le3, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1123 | |
1124 | QPushButton *b1 = new QPushButton(QLatin1String("Push 1" ), w); |
1125 | QPushButton *b2 = new QPushButton(QLatin1String("Push 2" ), w); |
1126 | QPushButton *b3 = new QPushButton(QLatin1String("Push 3" ), w); |
1127 | layout->addWidget(b1, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1128 | layout->addWidget(b2, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1129 | layout->addWidget(b3, stretch: 0, alignment: Qt::AlignTop | Qt::AlignLeft); |
1130 | |
1131 | layout->addStretch(stretch: 1); |
1132 | w->setLayout(layout); |
1133 | int lw = le1->sizeHint().width(); |
1134 | int pw = b1->sizeHint().width(); |
1135 | QTest::newRow(dataTag: "6x1, line edit + push buttons" ) |
1136 | << w << (PointList() |
1137 | << QPoint(0, 3) |
1138 | << QPoint(0 + lw + 5, 3) |
1139 | << QPoint(0 + 2*(lw + 5), 3) |
1140 | << QPoint(0 + 3*(lw + 5), 3) |
1141 | << QPoint(0 + 3*(lw + 5) + 1*(pw + 2), 3) |
1142 | << QPoint(0 + 3*(lw + 5) + 2*(pw + 2), 3)) |
1143 | << style->hspacing << style->vspacing << style->reimplementSubelementRect; |
1144 | } |
1145 | |
1146 | |
1147 | { |
1148 | style->hspacing = 5; |
1149 | style->vspacing = 10; |
1150 | style->reimplementSubelementRect = true; |
1151 | QApplication::setStyle(style); |
1152 | QWidget *w = new QWidget(); |
1153 | setFrameless(w); |
1154 | QVBoxLayout *layout = new QVBoxLayout(); |
1155 | QPushButton *pb1 = new QPushButton(QLatin1String("Push 1" ), w); |
1156 | |
1157 | QGroupBox *g1 = new QGroupBox(QLatin1String("GroupBox 1" ), w); |
1158 | |
1159 | QRadioButton *rb = new QRadioButton(QLatin1String("Radio 1" ), g1); |
1160 | QVBoxLayout *g1layout = new QVBoxLayout(); |
1161 | g1layout->addWidget(rb); |
1162 | g1->setLayout(g1layout); |
1163 | |
1164 | QPushButton *pb3 = new QPushButton(QLatin1String("Push 3" ), w); |
1165 | |
1166 | layout->addWidget(pb1); |
1167 | layout->addWidget(g1 ); |
1168 | layout->addWidget(pb3); |
1169 | |
1170 | w->setLayout(layout); |
1171 | QSize psh = pb1->sizeHint(); |
1172 | QSize gsh = g1->sizeHint(); |
1173 | |
1174 | QTest::newRow(dataTag: "subElementRect1" ) |
1175 | << w << (PointList() |
1176 | << QPoint(0, 3) |
1177 | << QPoint(0, 3 + psh.height() + 10 - 10) |
1178 | << QPoint(0, 3 + psh.height() + 10 - 10 + gsh.height() + 10) |
1179 | ) |
1180 | << style->hspacing << style->vspacing << style->reimplementSubelementRect; |
1181 | } |
1182 | |
1183 | |
1184 | { |
1185 | style->hspacing = 5; |
1186 | style->vspacing = 10; |
1187 | style->reimplementSubelementRect = true; |
1188 | QApplication::setStyle(style); |
1189 | QWidget *w = new QWidget(); |
1190 | QFont font; |
1191 | font.setPixelSize(10); |
1192 | w->setFont(font); |
1193 | setFrameless(w); |
1194 | QGridLayout *layout = new QGridLayout(); |
1195 | QPushButton *pb1 = new QPushButton(QLatin1String("Push 1" ), w); |
1196 | QPushButton *pb2 = new QPushButton(QLatin1String("Push 2" ), w); |
1197 | QPushButton *pb3 = new QPushButton(QLatin1String("Push 3" ), w); |
1198 | QPushButton *pb4 = new QPushButton(QLatin1String("Push 4" ), w); |
1199 | |
1200 | layout->addWidget(pb1, row: 0, column: 0); |
1201 | layout->addWidget(pb2, row: 0, column: 1); |
1202 | layout->addWidget(pb3, row: 0, column: 2); |
1203 | layout->addWidget(pb4, row: 1, column: 0, Qt::AlignTop); |
1204 | |
1205 | |
1206 | QFrame *f1 = new QFrame(w); |
1207 | f1->setFrameStyle(QFrame::Box | QFrame::Plain); |
1208 | f1->setMinimumSize(minw: 100, minh: 20); |
1209 | f1->setSizePolicy(hor: QSizePolicy::Expanding, ver: QSizePolicy::Fixed); |
1210 | |
1211 | layout->addWidget(f1, row: 1, column: 1, Qt::AlignTop); |
1212 | |
1213 | |
1214 | QPushButton *pb6 = new QPushButton(QLatin1String("Push 6" ), w); |
1215 | QPushButton *pb7 = new QPushButton(QLatin1String("Push 7" ), w); |
1216 | QPushButton *pb8 = new QPushButton(QLatin1String("Push 8" ), w); |
1217 | QPushButton *pb9 = new QPushButton(QLatin1String("Push 9" ), w); |
1218 | layout->addWidget(pb6, row: 1, column: 2, Qt::AlignTop); |
1219 | layout->addWidget(pb7, row: 2, column: 0, Qt::AlignTop); |
1220 | layout->addWidget(pb8, row: 2, column: 1, Qt::AlignTop); |
1221 | layout->addWidget(pb9, row: 2, column: 2, Qt::AlignTop); |
1222 | |
1223 | layout->setColumnStretch(column: 2, stretch: 1); |
1224 | layout->setRowStretch(row: 2, stretch: 1); |
1225 | w->setLayout(layout); |
1226 | int c[3]; |
1227 | c[0] = pb1->sizeHint().width(); |
1228 | c[1] = f1->minimumSize().width() - 2*4; |
1229 | c[2] = pb3->sizeHint().width(); |
1230 | |
1231 | int r[3]; |
1232 | r[0] = pb1->sizeHint().height(); |
1233 | r[1] = pb4->sizeHint().height(); |
1234 | r[2] = pb7->sizeHint().height(); |
1235 | |
1236 | |
1237 | QTest::newRow(dataTag: "subElementRect2" ) |
1238 | << w << (PointList() |
1239 | << QPoint(0, 3) |
1240 | << QPoint(0 + c[0] + 5, 3) |
1241 | << QPoint(0 + c[0] + 5 + c[1] + 5, 3) |
1242 | |
1243 | << QPoint(0, 3 + r[0] + 10) |
1244 | << QPoint(0 + c[0] + 5 - 4, 3 + r[0] + 10 - 9) |
1245 | << QPoint(0 + c[0] + 5 + c[1] + 5, 3 + r[0] + 10) |
1246 | |
1247 | << QPoint(0, 3 + r[0] + 10 + r[1] + 10) |
1248 | << QPoint(0 + c[0] + 5, 3 + r[0] + 10 + r[1] + 10) |
1249 | << QPoint(0 + c[0] + 5 + c[1] + 5, 3 + r[0] + 10 + r[1] + 10) |
1250 | |
1251 | ) |
1252 | << style->hspacing << style->vspacing << style->reimplementSubelementRect; |
1253 | } |
1254 | |
1255 | { |
1256 | style->hspacing = 5; |
1257 | style->vspacing = 10; |
1258 | style->reimplementSubelementRect = true; |
1259 | QApplication::setStyle(style); |
1260 | QWidget *w = new QWidget(); |
1261 | setFrameless(w); |
1262 | QVBoxLayout *layout = new QVBoxLayout(); |
1263 | QPushButton *pb1 = new QPushButton(QLatin1String("Push 1" ), w); |
1264 | |
1265 | QGroupBox *g1 = new QGroupBox(QLatin1String("GroupBox 1" ), w); |
1266 | |
1267 | QRadioButton *rb = new QRadioButton(QLatin1String("Radio 1" ), g1); |
1268 | QVBoxLayout *g1layout = new QVBoxLayout(); |
1269 | g1layout->addWidget(rb); |
1270 | g1->setLayout(g1layout); |
1271 | |
1272 | QPushButton *pb3 = new QPushButton(QLatin1String("Push 3" ), w); |
1273 | |
1274 | pb1->setAttribute(Qt::WA_LayoutUsesWidgetRect, on: true); |
1275 | g1->setAttribute(Qt::WA_LayoutUsesWidgetRect, on: true); |
1276 | pb3->setAttribute(Qt::WA_LayoutUsesWidgetRect, on: true); |
1277 | layout->addWidget(pb1); |
1278 | layout->addWidget(g1 ); |
1279 | layout->addWidget(pb3); |
1280 | |
1281 | w->setLayout(layout); |
1282 | QSize psh = pb1->sizeHint(); |
1283 | QSize gsh = g1->sizeHint(); |
1284 | |
1285 | QTest::newRow(dataTag: "subElementRect1, use widgetRect" ) |
1286 | << w << (PointList() |
1287 | << QPoint(0, 3) |
1288 | << QPoint(0, 3 + psh.height() + 10) |
1289 | << QPoint(0, 3 + psh.height() + 10 + gsh.height() + 10) |
1290 | ) |
1291 | << style->hspacing << style->vspacing << style->reimplementSubelementRect; |
1292 | } |
1293 | |
1294 | |
1295 | { |
1296 | style->hspacing = 5; |
1297 | style->vspacing = 10; |
1298 | style->reimplementSubelementRect = true; |
1299 | QApplication::setStyle(style); |
1300 | QWidget *w = new QWidget(); |
1301 | setFrameless(w); |
1302 | QVBoxLayout *layout = new QVBoxLayout(); |
1303 | QPushButton *pb1 = new QPushButton(QLatin1String("Push 1" ), w); |
1304 | |
1305 | QGroupBox *g1 = new QGroupBox(QLatin1String("GroupBox 1" ), w); |
1306 | |
1307 | QRadioButton *rb = new QRadioButton(QLatin1String("Radio 1" ), g1); |
1308 | QVBoxLayout *g1layout = new QVBoxLayout(); |
1309 | g1layout->addWidget(rb); |
1310 | g1->setLayout(g1layout); |
1311 | |
1312 | QPushButton *pb3 = new QPushButton(QLatin1String("Push 3" ), w); |
1313 | |
1314 | pb1->setAttribute(Qt::WA_LayoutUsesWidgetRect, on: false); |
1315 | g1->setAttribute(Qt::WA_LayoutUsesWidgetRect, on: false); |
1316 | pb3->setAttribute(Qt::WA_LayoutUsesWidgetRect, on: false); |
1317 | layout->addWidget(pb1); |
1318 | layout->addWidget(g1 ); |
1319 | layout->addWidget(pb3); |
1320 | |
1321 | w->setLayout(layout); |
1322 | QSize psh = pb1->sizeHint(); |
1323 | QSize gsh = g1->sizeHint(); |
1324 | |
1325 | QTest::newRow(dataTag: "subElementRect1, use layoutItemRect" ) |
1326 | << w << (PointList() |
1327 | << QPoint(0, 3) |
1328 | << QPoint(0, 3 + psh.height() + 10 - 10) |
1329 | << QPoint(0, 3 + psh.height() + 10 - 10 + gsh.height() + 10) |
1330 | ) |
1331 | << style->hspacing << style->vspacing << style->reimplementSubelementRect; |
1332 | } |
1333 | |
1334 | |
1335 | { |
1336 | /* A 3x4 gridlayout, modified arrowpad example: |
1337 | * [PB] |
1338 | * [PB] [PB] |
1339 | * |PB| |
1340 | * | | |
1341 | * | | |
1342 | * |
1343 | * Here the bottom pushbutton has a span |
1344 | */ |
1345 | style->hspacing = -1; |
1346 | style->vspacing = -1; |
1347 | style->reimplementSubelementRect = false; |
1348 | QApplication::setStyle(style); |
1349 | QWidget *w = new QWidget(); |
1350 | setFrameless(w); |
1351 | QGridLayout *layout = new QGridLayout(); |
1352 | QPushButton *left = new QPushButton(w); |
1353 | QPushButton *up = new QPushButton(w); |
1354 | QPushButton *right = new QPushButton(w); |
1355 | QPushButton *down = new QPushButton(w); |
1356 | |
1357 | layout->addWidget(up, row: 0, column: 1); |
1358 | layout->addWidget(left, row: 1, column: 0); |
1359 | layout->addWidget(right, row: 1, column: 2); |
1360 | layout->addWidget(down, row: 2, column: 1, rowSpan: 3, columnSpan: 1); |
1361 | |
1362 | w->setLayout(layout); |
1363 | int pw = up->sizeHint().width(); |
1364 | int ph = up->sizeHint().height(); |
1365 | QTest::newRow(dataTag: "arrowpad with span" ) |
1366 | << w << (PointList() |
1367 | << QPoint(0 + pw + 5, 3) |
1368 | << QPoint(0, 3 + ph + 10) |
1369 | << QPoint(0 + pw + 5 + pw + 5, 3 + ph + 10) |
1370 | << QPoint(0 + pw + 5, 3 + ph + 10 + ph + 10) |
1371 | ) |
1372 | << style->hspacing << style->vspacing << style->reimplementSubelementRect; |
1373 | } |
1374 | |
1375 | |
1376 | for (int yoff = 0; yoff < 5; ++yoff) |
1377 | { |
1378 | for (int xoff = 0; xoff < 5; ++xoff) { |
1379 | /* A 3x4 gridlayout, modified arrowpad example: |
1380 | * [empty cells] |
1381 | * [PB] |
1382 | * [PB] [PB] |
1383 | * [PB] |
1384 | * |
1385 | * It has 0-4 empty rows at the top and 0-4 empty columns to the left. |
1386 | */ |
1387 | style->hspacing = -1; |
1388 | style->vspacing = -1; |
1389 | style->reimplementSubelementRect = false; |
1390 | QApplication::setStyle(style); |
1391 | QWidget *w = new QWidget(); |
1392 | setFrameless(w); |
1393 | QGridLayout *layout = new QGridLayout(); |
1394 | QPushButton *left = new QPushButton(w); |
1395 | QPushButton *up = new QPushButton(w); |
1396 | QPushButton *right = new QPushButton(w); |
1397 | QPushButton *down = new QPushButton(w); |
1398 | |
1399 | layout->addWidget(up, row: yoff + 0, column: xoff + 1); |
1400 | layout->addWidget(left, row: yoff + 1, column: xoff + 0); |
1401 | layout->addWidget(right, row: yoff + 1, column: xoff + 2); |
1402 | layout->addWidget(down, row: yoff + 2, column: xoff + 1, rowSpan: 3, columnSpan: 1); |
1403 | |
1404 | w->setLayout(layout); |
1405 | int pw = up->sizeHint().width(); |
1406 | int ph = up->sizeHint().height(); |
1407 | QByteArray testName = "arrowpad with " + QByteArray::number(yoff) |
1408 | + " empty rows, " + QByteArray::number(xoff) + " empty columns" ; |
1409 | QTest::newRow(dataTag: testName.constData()) |
1410 | << w << (PointList() |
1411 | << QPoint(0 + pw + 5, 3) |
1412 | << QPoint(0, 3 + ph + 10) |
1413 | << QPoint(0 + pw + 5 + pw + 5, 3 + ph + 10) |
1414 | << QPoint(0 + pw + 5, 3 + ph + 10 + ph + 10) |
1415 | ) |
1416 | << style->hspacing << style->vspacing << style->reimplementSubelementRect; |
1417 | } |
1418 | } |
1419 | |
1420 | } |
1421 | |
1422 | void tst_QGridLayout::layoutSpacing() |
1423 | { |
1424 | QFETCH(QWidget *, widget); |
1425 | QFETCH(PointList, expectedpositions); |
1426 | QFETCH(int, hSpacing); |
1427 | QFETCH(int, vSpacing); |
1428 | QFETCH(bool, customSubElementRect); |
1429 | |
1430 | QWidget toplevel; |
1431 | setFrameless(&toplevel); |
1432 | |
1433 | CustomLayoutStyle *style = new CustomLayoutStyle(); |
1434 | style->hspacing = hSpacing; |
1435 | style->vspacing = vSpacing; |
1436 | style->reimplementSubelementRect = customSubElementRect; |
1437 | QApplication::setStyle(style); |
1438 | widget->setParent(&toplevel); |
1439 | widget->resize(widget->sizeHint()); |
1440 | toplevel.show(); |
1441 | QVERIFY(QTest::qWaitForWindowExposed(&toplevel)); |
1442 | |
1443 | QLayout *layout = widget->layout(); |
1444 | QVERIFY(layout); |
1445 | for (int pi = 0; pi < expectedpositions.count(); ++pi) { |
1446 | QLayoutItem *item = layout->itemAt(index: pi); |
1447 | //qDebug() << item->widget()->pos(); |
1448 | QCOMPARE(item->widget()->pos(), expectedpositions.at(pi)); |
1449 | } |
1450 | } |
1451 | |
1452 | void tst_QGridLayout::spacing() |
1453 | { |
1454 | QWidget w; |
1455 | setFrameless(&w); |
1456 | CustomLayoutStyle *style = new CustomLayoutStyle(); |
1457 | style->hspacing = 5; |
1458 | style->vspacing = 10; |
1459 | w.setStyle(style); |
1460 | QGridLayout grid(&w); |
1461 | QCOMPARE(style->hspacing, grid.horizontalSpacing()); |
1462 | QCOMPARE(style->vspacing, grid.verticalSpacing()); |
1463 | |
1464 | QCOMPARE(grid.spacing(), -1); |
1465 | grid.setVerticalSpacing(5); |
1466 | QCOMPARE(5, grid.horizontalSpacing()); |
1467 | QCOMPARE(5, grid.verticalSpacing()); |
1468 | QCOMPARE(grid.spacing(), 5); |
1469 | grid.setVerticalSpacing(-1); |
1470 | QCOMPARE(style->hspacing, grid.horizontalSpacing()); |
1471 | QCOMPARE(style->vspacing, grid.verticalSpacing()); |
1472 | |
1473 | style->hspacing = 5; |
1474 | style->vspacing = 5; |
1475 | QCOMPARE(grid.spacing(), 5); |
1476 | |
1477 | |
1478 | grid.setHorizontalSpacing(20); |
1479 | QCOMPARE(grid.spacing(), -1); |
1480 | style->vspacing = 20; |
1481 | QCOMPARE(grid.horizontalSpacing(), 20); |
1482 | QCOMPARE(grid.verticalSpacing(), 20); |
1483 | QCOMPARE(grid.spacing(), 20); |
1484 | grid.setHorizontalSpacing(-1); |
1485 | QCOMPARE(grid.spacing(), -1); |
1486 | style->hspacing = 20; |
1487 | QCOMPARE(grid.spacing(), 20); |
1488 | |
1489 | |
1490 | delete style; |
1491 | } |
1492 | |
1493 | void populate(QGridLayout *layout, int row, int kind) |
1494 | { |
1495 | if (kind == 0) { |
1496 | QWidget *widget = new QWidget; |
1497 | widget->setFixedSize(w: 100, h: 100); |
1498 | layout->addWidget(widget, row, column: 0); |
1499 | } else if (kind == 1) { |
1500 | layout->addItem(item: new QSpacerItem(10, 10), row, column: 0); |
1501 | } |
1502 | } |
1503 | |
1504 | void tst_QGridLayout::spacerWithSpacing() |
1505 | { |
1506 | // Tests all combinations of widget (w), spacer (s) and no layoutitem (-) |
1507 | // to see if they are laid out correctly. |
1508 | // Note that a combination of "s-" or "-s" should only give the height of "s" |
1509 | const int expectedHeight[] = { |
1510 | 302,// www |
1511 | 211,// wws |
1512 | 201,// ww- |
1513 | 211,// wsw |
1514 | 120,// wss |
1515 | 110,// ws- |
1516 | 201,// w-w |
1517 | 110,// w-s |
1518 | 100,// w-- |
1519 | 211,// sww |
1520 | 120,// sws |
1521 | 110,// sw- |
1522 | 120,// ssw |
1523 | 30,// sss |
1524 | 20,// ss- |
1525 | 110,// s-w |
1526 | 20,// s-s |
1527 | 10,// s-- |
1528 | 201,// -ww |
1529 | 110,// -ws |
1530 | 100,// -w- |
1531 | 110,// -sw |
1532 | 20,// -ss |
1533 | 10,// -s- |
1534 | 100,// --w |
1535 | 10,// --s |
1536 | 000 // --- |
1537 | }; |
1538 | int ii = 0; |
1539 | for (int i = 0; i < 3; ++i) { |
1540 | for (int j = 0; j < 3; ++j) { |
1541 | for (int k = 0; k < 3; ++k) { |
1542 | QWidget window; |
1543 | QGridLayout layout(&window); |
1544 | layout.setSpacing(1); |
1545 | layout.setContentsMargins(left: 0, top: 0, right: 0, bottom: 0); |
1546 | populate(layout: &layout, row: 0, kind: i); |
1547 | populate(layout: &layout, row: 1, kind: j); |
1548 | populate(layout: &layout, row: 2, kind: k); |
1549 | QCOMPARE(window.sizeHint().height(), expectedHeight[ii]); |
1550 | ++ii; |
1551 | } |
1552 | } |
1553 | } |
1554 | } |
1555 | |
1556 | void tst_QGridLayout::contentsRect() |
1557 | { |
1558 | QWidget w; |
1559 | setFrameless(&w); |
1560 | QGridLayout grid; |
1561 | w.setLayout(&grid); |
1562 | grid.addWidget(w: new QPushButton(&w)); |
1563 | w.show(); |
1564 | QVERIFY(QTest::qWaitForWindowExposed(&w)); |
1565 | int l, t, r, b; |
1566 | grid.getContentsMargins(left: &l, top: &t, right: &r, bottom: &b); |
1567 | QRect geom = grid.geometry(); |
1568 | |
1569 | QCOMPARE(geom.adjusted(+l, +t, -r, -b), grid.contentsRect()); |
1570 | |
1571 | } |
1572 | |
1573 | void tst_QGridLayout::distributeMultiCell() |
1574 | { |
1575 | QWidget w; |
1576 | Qt42Style style; |
1577 | style.spacing = 9; |
1578 | |
1579 | w.setStyle(&style); |
1580 | QGridLayout grid; |
1581 | w.setLayout(&grid); |
1582 | |
1583 | SizeHinter le1(200, 20, &w); |
1584 | le1.setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); |
1585 | SizeHinter le2(200, 20, &w); |
1586 | le2.setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed)); |
1587 | SizeHinter box(80, 57, &w); |
1588 | box.setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding)); |
1589 | box.setMinimumSize(minw: 80, minh: 57); |
1590 | |
1591 | grid.addWidget(&le1, row: 0, column: 0, rowSpan: 1, columnSpan: 1); |
1592 | grid.addWidget(&le2, row: 1, column: 0, rowSpan: 1, columnSpan: 1); |
1593 | grid.addWidget(&box, row: 0, column: 1, rowSpan: 2, columnSpan: 1); |
1594 | |
1595 | QCOMPARE(box.sizeHint().height(), 57); |
1596 | QCOMPARE(w.sizeHint().height(), 11 + 57 + 11); |
1597 | } |
1598 | |
1599 | void tst_QGridLayout::taskQTBUG_27420_takeAtShouldUnparentLayout() |
1600 | { |
1601 | QSharedPointer<QGridLayout> outer(new QGridLayout); |
1602 | QPointer<QGridLayout> inner = new QGridLayout; |
1603 | |
1604 | outer->addLayout(inner, row: 0, column: 0); |
1605 | QCOMPARE(outer->count(), 1); |
1606 | QCOMPARE(inner->parent(), outer.data()); |
1607 | |
1608 | QLayoutItem *item = outer->takeAt(index: 0); |
1609 | QCOMPARE(item->layout(), inner.data()); |
1610 | QVERIFY(!item->layout()->parent()); |
1611 | |
1612 | outer.reset(); |
1613 | |
1614 | if (inner) |
1615 | delete item; // success: a taken item/layout should not be deleted when the old parent is deleted |
1616 | else |
1617 | QVERIFY(!inner.isNull()); |
1618 | } |
1619 | |
1620 | void tst_QGridLayout::taskQTBUG_40609_addingWidgetToItsOwnLayout(){ |
1621 | QWidget widget; |
1622 | widget.setObjectName("9bb37ca762aeb7269b8" ); |
1623 | QGridLayout layout(&widget); |
1624 | layout.setObjectName("d631e91a35f2b66a6dff35" ); |
1625 | |
1626 | QTest::ignoreMessage(type: QtWarningMsg, message: "QLayout: Cannot add a null widget to QGridLayout/d631e91a35f2b66a6dff35" ); |
1627 | layout.addWidget(nullptr, row: 0, column: 0); |
1628 | QCOMPARE(layout.count(), 0); |
1629 | |
1630 | QTest::ignoreMessage(type: QtWarningMsg, message: "QLayout: Cannot add parent widget QWidget/9bb37ca762aeb7269b8 to its child layout QGridLayout/d631e91a35f2b66a6dff35" ); |
1631 | layout.addWidget(&widget, row: 0, column: 0); |
1632 | QCOMPARE(layout.count(), 0); |
1633 | } |
1634 | |
1635 | void tst_QGridLayout::taskQTBUG_40609_addingLayoutToItself(){ |
1636 | QWidget widget; |
1637 | widget.setObjectName("0373d417fffe2c59c6fe543" ); |
1638 | QGridLayout layout(&widget); |
1639 | layout.setObjectName("5d79e1b0aed83f100e3c2" ); |
1640 | |
1641 | QTest::ignoreMessage(type: QtWarningMsg, message: "QLayout: Cannot add a null layout to QGridLayout/5d79e1b0aed83f100e3c2" ); |
1642 | layout.addLayout(nullptr, row: 0, column: 0); |
1643 | QCOMPARE(layout.count(), 0); |
1644 | |
1645 | QTest::ignoreMessage(type: QtWarningMsg, message: "QLayout: Cannot add layout QGridLayout/5d79e1b0aed83f100e3c2 to itself" ); |
1646 | layout.addLayout(&layout, row: 0, column: 0); |
1647 | QCOMPARE(layout.count(), 0); |
1648 | } |
1649 | |
1650 | void tst_QGridLayout::taskQTBUG_52357_spacingWhenItemIsHidden() |
1651 | { |
1652 | QWidget widget; |
1653 | setFrameless(&widget); |
1654 | QGridLayout layout(&widget); |
1655 | layout.setContentsMargins(left: 0, top: 0, right: 0, bottom: 0); |
1656 | layout.setSpacing(5); |
1657 | QPushButton button1; |
1658 | layout.addWidget(&button1, row: 0, column: 0); |
1659 | QPushButton button2; |
1660 | layout.addWidget(&button2, row: 0, column: 1); |
1661 | QPushButton button3; |
1662 | layout.addWidget(&button3, row: 0, column: 2); |
1663 | widget.show(); |
1664 | QVERIFY(QTest::qWaitForWindowExposed(&widget)); |
1665 | int tempWidth = button1.width() + button2.width() + button3.width() + 2 * layout.spacing(); |
1666 | button2.hide(); |
1667 | QTRY_COMPARE_WITH_TIMEOUT(tempWidth, button1.width() + button3.width() + layout.spacing(), 1000); |
1668 | } |
1669 | |
1670 | void tst_QGridLayout::taskQTBUG_91261_itemIndexRange() |
1671 | { |
1672 | QWidget widget; |
1673 | QGridLayout lay(&widget); |
1674 | QPushButton *btn = new QPushButton(&widget); |
1675 | lay.addWidget(btn, row: 0, column: 0); |
1676 | |
1677 | { |
1678 | auto ptr = lay.itemAt(index: -1); |
1679 | QCOMPARE(ptr, nullptr); |
1680 | |
1681 | ptr = lay.itemAt(index: 0); |
1682 | QCOMPARE(ptr->widget(), btn); |
1683 | |
1684 | ptr = lay.itemAt(index: 1); |
1685 | QCOMPARE(ptr, nullptr); |
1686 | } |
1687 | |
1688 | { |
1689 | int row = -1; |
1690 | int column = -1; |
1691 | int rowSpan; |
1692 | int columnSpan; |
1693 | |
1694 | lay.getItemPosition(idx: -1, row: &row, column: &column, rowSpan: &rowSpan, columnSpan: &columnSpan); |
1695 | QCOMPARE(row, -1); |
1696 | QCOMPARE(column, -1); |
1697 | |
1698 | lay.getItemPosition(idx: 1, row: &row, column: &column, rowSpan: &rowSpan, columnSpan: &columnSpan); |
1699 | QCOMPARE(row, -1); |
1700 | QCOMPARE(column, -1); |
1701 | |
1702 | lay.getItemPosition(idx: 0, row: &row, column: &column, rowSpan: &rowSpan, columnSpan: &columnSpan); |
1703 | QCOMPARE(row, 0); |
1704 | QCOMPARE(column, 0); |
1705 | } |
1706 | |
1707 | { |
1708 | auto ptr = lay.takeAt(index: -1); |
1709 | QCOMPARE(ptr, nullptr); |
1710 | |
1711 | ptr = lay.takeAt(index: 1); |
1712 | QCOMPARE(ptr, nullptr); |
1713 | |
1714 | ptr = lay.takeAt(index: 0); |
1715 | QCOMPARE(ptr->widget(), btn); |
1716 | delete ptr; |
1717 | } |
1718 | } |
1719 | |
1720 | void tst_QGridLayout::replaceWidget() |
1721 | { |
1722 | QWidget wdg; |
1723 | QGridLayout *l = new QGridLayout(); |
1724 | const int itemCount = 9; |
1725 | QLabel *labels[itemCount]; |
1726 | |
1727 | // setup layout |
1728 | for (int n = 0; n < itemCount; ++n) { |
1729 | int x = n % 3; |
1730 | int y = n / 3; |
1731 | labels[n] = new QLabel(QLatin1String("label " ) + QString::number(n)); |
1732 | Qt::Alignment align = (n % 3 ? Qt::AlignLeft : Qt::AlignRight); |
1733 | l->addWidget(labels[n], row: x * 3, column: y * 3, rowSpan: (n % 2) + 1, columnSpan: (n + 1) % 2 + 1, align); |
1734 | } |
1735 | wdg.setLayout(l); |
1736 | |
1737 | // iterate and replace |
1738 | for (int n = 0; n < itemCount; n += 2) { |
1739 | int i = l->indexOf(labels[n]); |
1740 | int fromRow, fromCol, fromRowSpan, fromColSpan; |
1741 | l->getItemPosition(idx: i, row: &fromRow, column: &fromCol, rowSpan: &fromRowSpan, columnSpan: &fromColSpan); |
1742 | Qt::Alignment fromAlign = l->itemAt(index: i)->alignment(); |
1743 | // do replace |
1744 | QPushButton *pb = new QPushButton("replaced" ); |
1745 | QLayoutItem *olditem = l->replaceWidget(from: labels[n], to: pb); |
1746 | // verify |
1747 | QCOMPARE(i, l->indexOf(pb)); |
1748 | QVERIFY(olditem != 0); |
1749 | QCOMPARE(l->indexOf(labels[n]), -1); |
1750 | int toRow, toCol, toRowSpan, toColSpan; |
1751 | l->getItemPosition(idx: i, row: &toRow, column: &toCol, rowSpan: &toRowSpan, columnSpan: &toColSpan); |
1752 | QCOMPARE(fromRow, toRow); |
1753 | QCOMPARE(fromCol, toCol); |
1754 | QCOMPARE(fromRowSpan, toRowSpan); |
1755 | QCOMPARE(fromColSpan, toColSpan); |
1756 | Qt::Alignment toAlign = l->itemAt(index: i)->alignment(); |
1757 | QCOMPARE(fromAlign, toAlign); |
1758 | // clean up |
1759 | olditem->widget()->deleteLater(); |
1760 | delete olditem; |
1761 | } |
1762 | } |
1763 | |
1764 | void tst_QGridLayout::dontCrashWhenExtendsToEnd() |
1765 | { |
1766 | QWidget window; |
1767 | window.resize(w: 320,h: 200); |
1768 | QWidget parent(&window); |
1769 | QLabel *lbl0 = new QLabel(QLatin1String("lbl0:" )); |
1770 | QLabel *lbl1 = new QLabel(QLatin1String("lbl1:" )); |
1771 | QPushButton *pb = new QPushButton(QLatin1String("pb1" )); |
1772 | QGridLayout *l = new QGridLayout(&parent); |
1773 | l->addWidget(lbl0, row: 0, column: 0); |
1774 | l->addWidget(lbl1, row: 1, column: 0); |
1775 | // adding an item in the bottom right corner than spans to the end (!)... |
1776 | l->addWidget(pb, row: 1, column: 1, rowSpan: -1, columnSpan: -1); |
1777 | // ...should not cause a crash when the items are distributed.... |
1778 | l->setGeometry(QRect(0, 0, 200, 50)); // DONT CRASH HERE |
1779 | } |
1780 | |
1781 | QTEST_MAIN(tst_QGridLayout) |
1782 | #include "tst_qgridlayout.moc" |
1783 | |