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 test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44 #include <qgraphicslinearlayout.h>
45 #include <qgraphicsproxywidget.h>
46 #include <qgraphicswidget.h>
47 #include <qgraphicsscene.h>
48 #include <qgraphicsview.h>
49 #include <qapplication.h>
50 #include <qplastiquestyle.h>
51
52 class tst_QGraphicsLinearLayout : public QObject {
53 Q_OBJECT
54
55 public slots:
56 void initTestCase();
57 void cleanupTestCase();
58 void init();
59 void cleanup();
60
61 private slots:
62 void qgraphicslinearlayout_data();
63 void qgraphicslinearlayout();
64
65 void alignment_data();
66 void alignment();
67 void count_data();
68 void count();
69 void dump_data();
70 void dump();
71 void geometry_data();
72 void geometry();
73 void insertItem_data();
74 void insertItem();
75 void insertStretch_data();
76 void insertStretch();
77 void invalidate_data();
78 void invalidate();
79 void itemAt_data();
80 void itemAt();
81 void itemAt_visualOrder();
82 void orientation_data();
83 void orientation();
84 void removeAt_data();
85 void removeAt();
86 void removeItem_data();
87 void removeItem();
88 void setGeometry_data();
89 void setGeometry();
90 void setSpacing_data();
91 void setSpacing();
92 void setItemSpacing_data();
93 void setItemSpacing();
94 void itemSpacing();
95 void setStretchFactor_data();
96 void setStretchFactor();
97 void testStretch();
98 void defaultStretchFactors_data();
99 void defaultStretchFactors();
100 void sizeHint_data();
101 void sizeHint();
102 void updateGeometry();
103 void layoutDirection();
104 void removeLayout();
105 void avoidRecursionInInsertItem();
106 void styleInfoLeak();
107 void testAlignmentInLargerLayout();
108 void testOffByOneInLargerLayout();
109 void testDefaultAlignment();
110 void combineSizePolicies();
111 void hiddenItems();
112
113 // Task specific tests
114 void task218400_insertStretchCrash();
115 };
116
117 // Subclass that exposes the protected functions.
118 class SubQGraphicsLinearLayout : public QGraphicsLinearLayout {
119 public:
SubQGraphicsLinearLayout(Qt::Orientation orientation=Qt::Horizontal)120 SubQGraphicsLinearLayout(Qt::Orientation orientation = Qt::Horizontal) : QGraphicsLinearLayout(orientation),
121 graphicsSceneResize(0),
122 layoutRequest(0),
123 layoutDirectionChange(0)
124 { }
125
widgetEvent(QEvent * e)126 void widgetEvent(QEvent *e)
127 {
128 switch (e->type()) {
129 case QEvent::GraphicsSceneResize:
130 graphicsSceneResize++;
131 break;
132 case QEvent::LayoutRequest:
133 layoutRequest++;
134 break;
135 case QEvent::LayoutDirectionChange:
136 layoutDirectionChange++;
137 break;
138 default:
139 break;
140 }
141
142 QGraphicsLinearLayout::widgetEvent(e);
143 }
144
145 int graphicsSceneResize;
146 int layoutRequest;
147 int layoutDirectionChange;
148 };
149
150 // This will be called before the first test function is executed.
151 // It is only called once.
initTestCase()152 void tst_QGraphicsLinearLayout::initTestCase()
153 {
154 // since the style will influence the results, we have to ensure
155 // that the tests are run using the same style on all platforms
156 #if defined( Q_WS_S60 )|| defined (Q_WS_WINCE)
157 QApplication::setStyle(new QWindowsStyle);
158 #else
159 QApplication::setStyle(new QPlastiqueStyle);
160 #endif
161 }
162
163 // This will be called after the last test function is executed.
164 // It is only called once.
cleanupTestCase()165 void tst_QGraphicsLinearLayout::cleanupTestCase()
166 {
167 }
168
169 // This will be called before each test function is executed.
init()170 void tst_QGraphicsLinearLayout::init()
171 {
172 }
173
174 // This will be called after every test function.
cleanup()175 void tst_QGraphicsLinearLayout::cleanup()
176 {
177 }
178
179 class RectWidget : public QGraphicsWidget
180 {
181 public:
RectWidget(QGraphicsItem * parent=0,const QBrush & brush=QBrush ())182 RectWidget(QGraphicsItem *parent = 0, const QBrush &brush = QBrush()) : QGraphicsWidget(parent){ m_brush = brush;}
183
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)184 void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
185 {
186 Q_UNUSED(option);
187 Q_UNUSED(widget);
188 painter->setBrush(m_brush);
189 painter->drawRoundRect(rect());
190 }
191
setSizeHint(Qt::SizeHint which,const QSizeF & size)192 void setSizeHint(Qt::SizeHint which, const QSizeF &size) {
193 m_sizeHints[which] = size;
194 updateGeometry();
195 }
196
sizeHint(Qt::SizeHint which,const QSizeF & constraint=QSizeF ()) const197 virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const {
198 if (m_sizeHints[which].isValid()) {
199 return m_sizeHints[which];
200 }
201 return QGraphicsWidget::sizeHint(which, constraint);
202 }
203
204 QSizeF m_sizeHints[Qt::NSizeHints];
205 QBrush m_brush;
206 };
207
208
Q_DECLARE_METATYPE(Qt::Orientation)209 Q_DECLARE_METATYPE(Qt::Orientation)
210 void tst_QGraphicsLinearLayout::qgraphicslinearlayout_data()
211 {
212 QTest::addColumn<Qt::Orientation>("orientation");
213 QTest::newRow("vertical") << Qt::Vertical;
214 QTest::newRow("horizontal") << Qt::Horizontal;
215 }
216
qgraphicslinearlayout()217 void tst_QGraphicsLinearLayout::qgraphicslinearlayout()
218 {
219 QFETCH(Qt::Orientation, orientation);
220 SubQGraphicsLinearLayout layout(orientation);
221 QVERIFY(layout.isLayout());
222
223 qApp->processEvents();
224 QCOMPARE(layout.graphicsSceneResize, 0);
225 QCOMPARE(layout.layoutRequest, 0);
226 QCOMPARE(layout.layoutDirectionChange, 0);
227
228 layout.setOrientation(Qt::Vertical);
229 layout.orientation();
230 QTest::ignoreMessage(QtWarningMsg, "QGraphicsLinearLayout::insertItem: cannot insert null item");
231 QCOMPARE(layout.count(), 0);
232 layout.addItem(0);
233 QCOMPARE(layout.count(), 0);
234 layout.addStretch(0);
235 QCOMPARE(layout.count(), 0);
236 QTest::ignoreMessage(QtWarningMsg, "QGraphicsLinearLayout::insertItem: cannot insert null item");
237 layout.insertItem(0, 0);
238 layout.insertStretch(0, 0);
239 layout.removeItem(0);
240 QCOMPARE(layout.count(), 0);
241 layout.setSpacing(0);
242 layout.spacing();
243 QTest::ignoreMessage(QtWarningMsg, "QGraphicsLinearLayout::setStretchFactor: cannot assign a stretch factor to a null item");
244 layout.setStretchFactor(0, 0);
245 QTest::ignoreMessage(QtWarningMsg, "QGraphicsLinearLayout::setStretchFactor: cannot return a stretch factor for a null item");
246 layout.stretchFactor(0);
247 layout.setAlignment(0, Qt::AlignHCenter);
248 QCOMPARE(layout.alignment(0), 0);
249 layout.setGeometry(QRectF());
250 layout.geometry();
251 QCOMPARE(layout.count(), 0);
252 layout.invalidate();
253 layout.sizeHint(Qt::MinimumSize, QSizeF());
254 }
255
Q_DECLARE_METATYPE(Qt::AlignmentFlag)256 Q_DECLARE_METATYPE(Qt::AlignmentFlag)
257 void tst_QGraphicsLinearLayout::alignment_data()
258 {
259 QTest::addColumn<Qt::Orientation>("orientation");
260 QTest::addColumn<QSize>("newSize");
261 QTest::newRow("h-defaultsize") << Qt::Horizontal << QSize();
262 QTest::newRow("v-defaultsize") << Qt::Vertical << QSize();
263 QTest::newRow("h-300") << Qt::Horizontal << QSize(300,100);
264 QTest::newRow("v-300") << Qt::Vertical << QSize(100, 300);
265 }
266
alignment()267 void tst_QGraphicsLinearLayout::alignment()
268 {
269 QFETCH(Qt::Orientation, orientation);
270 QFETCH(QSize, newSize);
271
272 //if (alignment == Qt::AlignAbsolute)
273 // QApplication::setLayoutDirection(Qt::RightToLeft);
274 QGraphicsScene scene;
275 QGraphicsView view(&scene);
276 view.setSceneRect(0, 0, 320, 240);
277 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
278 SubQGraphicsLinearLayout &layout = *(new SubQGraphicsLinearLayout(orientation));
279 scene.addItem(widget);
280 widget->setLayout(&layout);
281
282 static const Qt::Alignment alignmentsToTest[] = {
283 (Qt::Alignment)0,
284 Qt::AlignLeft,
285 Qt::AlignRight,
286 Qt::AlignHCenter,
287 Qt::AlignTop,
288 Qt::AlignBottom,
289 Qt::AlignVCenter,
290 Qt::AlignCenter,
291 (Qt::Alignment)0,
292 Qt::AlignLeft,
293 Qt::AlignRight,
294 Qt::AlignHCenter,
295 Qt::AlignTop,
296 Qt::AlignBottom,
297 Qt::AlignVCenter,
298 Qt::AlignCenter
299 };
300
301 int i;
302 bool addWidget = true;
303 for (i = 0; i < sizeof(alignmentsToTest)/sizeof(Qt::Alignment); ++i) {
304 QGraphicsLayoutItem *loutItem;
305 Qt::Alignment align = alignmentsToTest[i];
306 if (!align && i > 0)
307 addWidget = false;
308 if (addWidget)
309 loutItem = new RectWidget(widget, QBrush(Qt::blue));
310 else {
311 SubQGraphicsLinearLayout *lay = new SubQGraphicsLinearLayout(Qt::Vertical);
312 lay->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred, QSizePolicy::DefaultType);
313 lay->setContentsMargins(0,0,0,0);
314 QGraphicsWidget *w = new RectWidget(widget, QBrush(Qt::red));
315 if (align) {
316 w->setMinimumSize(QSizeF(10,10));
317 w->setMaximumSize(QSizeF(10,10));
318 } else {
319 w->setMinimumSize(QSizeF(50,50));
320 w->setMaximumSize(QSizeF(50,50));
321 }
322 lay->addItem(w);
323 loutItem = lay;
324 }
325 if (align) {
326 loutItem->setMinimumSize(QSizeF(10,10));
327 loutItem->setMaximumSize(QSizeF(10,10));
328 } else {
329 loutItem->setMinimumSize(QSizeF(50,50));
330 loutItem->setMaximumSize(QSizeF(50,50));
331 }
332 layout.addItem(loutItem);
333 layout.setAlignment(loutItem, align);
334
335 }
336 layout.setContentsMargins(0,0,0,0);
337 int spacing = 1;
338 layout.setSpacing(spacing);
339 if (newSize.isValid())
340 widget->resize(newSize);
341 view.show();
342 widget->show();
343 QTest::qWaitForWindowShown(&view);
344 QApplication::processEvents();
345
346 int x = 0;
347 int y = 0;
348 for (i = 0; i < layout.count(); ++i) {
349 QGraphicsLayoutItem *item = layout.itemAt(i);
350 Qt::Alignment align = layout.alignment(item);
351
352 int w = 10;
353 int h = 10;
354 switch(align) {
355 case Qt::AlignLeft:
356 break;
357 case Qt::AlignRight:
358 if (orientation == Qt::Vertical)
359 x += 40;
360 break;
361 case Qt::AlignHCenter:
362 if (orientation == Qt::Vertical)
363 x += 20;
364 break;
365 case Qt::AlignTop:
366 break;
367 case Qt::AlignBottom:
368 if (orientation == Qt::Horizontal)
369 y += 40;
370 break;
371 case Qt::AlignVCenter:
372 if (orientation == Qt::Horizontal)
373 y += 20;
374 break;
375 case Qt::AlignCenter:
376 if (orientation == Qt::Horizontal)
377 y += 20;
378 else
379 x += 20;
380 break;
381 case 0:
382 w = 50;
383 h = 50;
384 break;
385 default:
386 break;
387 }
388 QRectF expectedGeometry(x, y, w, h);
389 QCOMPARE(item->geometry(), expectedGeometry);
390 if (orientation == Qt::Horizontal) {
391 x += w;
392 y = 0;
393 x += spacing;
394 } else {
395 x = 0;
396 y += h;
397 y += spacing;
398 }
399 }
400 }
401
count_data()402 void tst_QGraphicsLinearLayout::count_data()
403 {
404 QTest::addColumn<int>("itemCount");
405 QTest::addColumn<int>("layoutCount");
406 QTest::newRow("0, 0") << 0 << 0;
407 QTest::newRow("0, 5") << 0 << 5;
408 QTest::newRow("5, 0") << 5 << 0;
409 QTest::newRow("5, 5") << 5 << 5;
410 }
411
412 // int count() const public
count()413 void tst_QGraphicsLinearLayout::count()
414 {
415 QFETCH(int, itemCount);
416 QFETCH(int, layoutCount);
417
418 SubQGraphicsLinearLayout layout;
419 QCOMPARE(layout.count(), 0);
420
421 for (int i = 0; i < itemCount; ++i)
422 layout.addItem(new QGraphicsWidget);
423 QCOMPARE(layout.count(), itemCount);
424
425 for (int i = 0; i < layoutCount; ++i)
426 layout.addItem(new SubQGraphicsLinearLayout);
427 QCOMPARE(layout.count(), itemCount + layoutCount);
428
429 // see also removeAt()
430 }
431
dump_data()432 void tst_QGraphicsLinearLayout::dump_data()
433 {
434 QTest::addColumn<int>("itemCount");
435 QTest::addColumn<int>("layoutCount");
436 for (int i = -1; i < 3; ++i) {
437 QTest::newRow(QString("%1, 0, 0").arg(i).toLatin1()) << 0 << 0;
438 QTest::newRow(QString("%1, 0, 5").arg(i).toLatin1()) << 5 << 5;
439 QTest::newRow(QString("%1, 5, 0").arg(i).toLatin1()) << 5 << 5;
440 QTest::newRow(QString("%1, 5, 5").arg(i).toLatin1()) << 5 << 5;
441 }
442 }
443
444 // void dump(int indent = 0) const public
dump()445 void tst_QGraphicsLinearLayout::dump()
446 {
447 QFETCH(int, itemCount);
448 QFETCH(int, layoutCount);
449 SubQGraphicsLinearLayout layout;
450 for (int i = 0; i < itemCount; ++i)
451 layout.addItem(new QGraphicsWidget);
452 for (int i = 0; i < layoutCount; ++i)
453 layout.addItem(new SubQGraphicsLinearLayout);
454 }
455
geometry_data()456 void tst_QGraphicsLinearLayout::geometry_data()
457 {
458 QTest::addColumn<int>("itemCount");
459 QTest::addColumn<int>("layoutCount");
460 QTest::addColumn<int>("itemSpacing");
461 QTest::addColumn<int>("spacing");
462 QTest::addColumn<Qt::Orientation>("orientation");
463 QTest::addColumn<QRectF>("rect");
464
465 QTest::newRow("null") << 0 << 0 << 0 << 0 << Qt::Horizontal << QRectF();
466
467 QTest::newRow("one item") << 1 << 0 << 0 << 0 << Qt::Horizontal << QRectF(0, 0, 10, 10);
468 QTest::newRow("one layout") << 0 << 1 << 0 << 0 << Qt::Horizontal << QRectF(0, 0, 10, 10);
469 QTest::newRow("two h") << 1 << 1 << 0 << 0 << Qt::Horizontal << QRectF(0, 0, 20, 10);
470 QTest::newRow("two v") << 1 << 1 << 0 << 0 << Qt::Vertical << QRectF(0, 0, 10, 20);
471
472 QTest::newRow("two w/itemspacing") << 1 << 1 << 5 << 0 << Qt::Horizontal << QRectF(0, 0, 25, 10);
473 QTest::newRow("two w/spacing") << 1 << 1 << 8 << 0 << Qt::Horizontal << QRectF(0, 0, 28, 10);
474
475 QTest::newRow("two w/itemspacing v") << 1 << 1 << 5 << 0 << Qt::Vertical << QRectF(0, 0, 10, 25);
476 QTest::newRow("two w/spacing v") << 1 << 1 << 8 << 0 << Qt::Vertical << QRectF(0, 0, 10, 28);
477 }
478
479 // QRectF geometry() const public
geometry()480 void tst_QGraphicsLinearLayout::geometry()
481 {
482 QFETCH(int, itemCount);
483 QFETCH(int, layoutCount);
484 QFETCH(int, itemSpacing);
485 QFETCH(int, spacing);
486 QFETCH(Qt::Orientation, orientation);
487 QFETCH(QRectF, rect);
488 QGraphicsScene scene;
489 QGraphicsView view(&scene);
490 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
491 SubQGraphicsLinearLayout &layout = *(new SubQGraphicsLinearLayout(orientation));
492 scene.addItem(widget);
493 widget->setLayout(&layout);
494 widget->setContentsMargins(0, 0, 0, 0);
495 for (int i = 0; i < itemCount; ++i)
496 layout.addItem(new QGraphicsWidget);
497 for (int i = 0; i < layoutCount; ++i)
498 layout.addItem(new SubQGraphicsLinearLayout);
499
500 for (int i = 0; i < layout.count(); ++i) {
501 QGraphicsLayoutItem *item = layout.itemAt(i);
502 item->setMaximumSize(10, 10);
503 item->setMinimumSize(10, 10);
504 }
505 layout.setItemSpacing(0, itemSpacing);
506 layout.setSpacing(spacing);
507 layout.setContentsMargins(0, 0, 0, 0);
508
509 widget->show();
510 view.show();
511 QApplication::processEvents();
512 QCOMPARE(layout.geometry(), rect);
513 delete widget;
514 }
515
insertItem_data()516 void tst_QGraphicsLinearLayout::insertItem_data()
517 {
518 QTest::addColumn<int>("itemCount");
519 QTest::addColumn<int>("layoutCount");
520 QTest::addColumn<int>("insertItemAt");
521 QTest::addColumn<bool>("isWidget");
522 for (int i = -1; i < 4; ++i) {
523 for (int j = 0; j < 2; ++j) {
524 QTest::newRow(QString("0, 0, %1 %2").arg(i).arg(j).toLatin1()) << 0 << 0 << i << (bool)j;
525 QTest::newRow(QString("1, 0, %1 %2").arg(i).arg(j).toLatin1()) << 1 << 0 << i << (bool)j;
526 QTest::newRow(QString("0, 1, %1 %2").arg(i).arg(j).toLatin1()) << 0 << 1 << i << (bool)j;
527 QTest::newRow(QString("2, 2, %1 %2").arg(i).arg(j).toLatin1()) << 2 << 2 << i << (bool)j;
528 }
529 }
530 }
531
532 // void insertItem(int index, QGraphicsLayoutItem* item) public
insertItem()533 void tst_QGraphicsLinearLayout::insertItem()
534 {
535 QFETCH(int, itemCount);
536 QFETCH(int, layoutCount);
537 QFETCH(int, insertItemAt);
538 QFETCH(bool, isWidget);
539 if (insertItemAt > layoutCount + itemCount)
540 return;
541
542 SubQGraphicsLinearLayout layout;
543 for (int i = 0; i < itemCount; ++i)
544 layout.addItem(new QGraphicsWidget);
545 for (int i = 0; i < layoutCount; ++i)
546 layout.addItem(new SubQGraphicsLinearLayout);
547
548 QGraphicsLayoutItem *item = 0;
549 if (isWidget)
550 item = new QGraphicsWidget;
551 else
552 item = new SubQGraphicsLinearLayout;
553
554 QSizeF oldSizeHint = layout.sizeHint(Qt::PreferredSize, QSizeF());
555 layout.insertItem(insertItemAt, item);
556 QCOMPARE(layout.count(), itemCount + layoutCount + 1);
557
558 if (insertItemAt >= 0 && (itemCount + layoutCount >= 0)) {
559 QCOMPARE(layout.itemAt(insertItemAt), item);
560 }
561
562 layout.activate();
563 QSizeF newSizeHint = layout.sizeHint(Qt::PreferredSize, QSizeF());
564 if (!isWidget && layout.count() == 1)
565 QCOMPARE(oldSizeHint.width(), newSizeHint.width());
566 else if (itemCount + layoutCount > 0)
567 QVERIFY(oldSizeHint.width() < newSizeHint.width());
568 }
569
insertStretch_data()570 void tst_QGraphicsLinearLayout::insertStretch_data()
571 {
572 QTest::addColumn<int>("itemCount");
573 QTest::addColumn<int>("layoutCount");
574 QTest::addColumn<int>("insertItemAt");
575 QTest::addColumn<int>("stretch");
576 for (int i = -1; i < 4; ++i) {
577 for (int j = 0; j < 2; ++j) {
578 QTest::newRow(QString("0, 0, %1 %2").arg(i).arg(j).toLatin1()) << 0 << 0 << i << j;
579 QTest::newRow(QString("1, 0, %1 %2").arg(i).arg(j).toLatin1()) << 1 << 0 << i << j;
580 QTest::newRow(QString("0, 1, %1 %2").arg(i).arg(j).toLatin1()) << 0 << 1 << i << j;
581 QTest::newRow(QString("2, 2, %1 %2").arg(i).arg(j).toLatin1()) << 2 << 2 << i << j;
582 }
583 }
584 }
585
586 // void insertStretch(int index, int stretch = 1) public
insertStretch()587 void tst_QGraphicsLinearLayout::insertStretch()
588 {
589 QFETCH(int, itemCount);
590 QFETCH(int, layoutCount);
591 QFETCH(int, insertItemAt);
592 QFETCH(int, stretch);
593 if (insertItemAt > layoutCount + itemCount)
594 return;
595
596 QGraphicsScene scene;
597 QGraphicsView view(&scene);
598 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
599 SubQGraphicsLinearLayout *layout = new SubQGraphicsLinearLayout;
600 scene.addItem(widget);
601
602 QList<QGraphicsWidget *>items;
603 QGraphicsWidget *item = 0;
604 for (int i = 0; i < itemCount; ++i) {
605 item = new RectWidget;
606 item->setMinimumSize(10, 10);
607 item->setPreferredSize(25, 25);
608 item->setMaximumSize(50, 50);
609 layout->addItem(item);
610 }
611 for (int i = 0; i < layoutCount; ++i) {
612 item = new RectWidget;
613 item->setMinimumSize(10, 10);
614 item->setPreferredSize(25, 25);
615 item->setMaximumSize(50, 50);
616 SubQGraphicsLinearLayout *sublayout = new SubQGraphicsLinearLayout;
617 sublayout->addItem(item);
618 layout->addItem(sublayout);
619 }
620 widget->setLayout(layout);
621 layout->insertStretch(insertItemAt, stretch);
622 QCOMPARE(layout->count(), itemCount + layoutCount);
623
624 layout->activate();
625 view.show();
626 widget->show();
627
628 int prevStretch = -2;
629 int prevWidth = -2;
630 widget->resize((layoutCount + itemCount) * 25 + 25, 25);
631 for (int i = 0; i < layout->count(); ++i) {
632 if (QGraphicsLayoutItem *item = layout->itemAt(i)) {
633 if (prevStretch != -2) {
634 if (layout->stretchFactor(item) >= prevStretch) {
635 QVERIFY(item->geometry().width() >= prevWidth);
636 } else {
637 QVERIFY(item->geometry().width() < prevWidth);
638 }
639 }
640 prevStretch = layout->stretchFactor(item);
641 prevWidth = (int)(item->geometry().width());
642 }
643 }
644
645 //QTest::qWait(1000);
646 delete widget;
647 }
648
invalidate_data()649 void tst_QGraphicsLinearLayout::invalidate_data()
650 {
651 QTest::addColumn<int>("count");
652 QTest::newRow("0") << 0;
653 QTest::newRow("1") << 1;
654 QTest::newRow("2") << 2;
655 QTest::newRow("3") << 3;
656 }
657
658 // void invalidate() public
invalidate()659 void tst_QGraphicsLinearLayout::invalidate()
660 {
661 QFETCH(int, count);
662 QGraphicsScene scene;
663 QGraphicsView view(&scene);
664 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
665 SubQGraphicsLinearLayout &layout = *(new SubQGraphicsLinearLayout);
666 scene.addItem(widget);
667 widget->setLayout(&layout);
668 widget->setContentsMargins(0, 0, 0, 0);
669 layout.setContentsMargins(0, 0, 0, 0);
670 view.show();
671 widget->show();
672 //QTest::qWait(1000);
673 QTest::qWaitForWindowShown(&view);
674 qApp->processEvents();
675 layout.layoutRequest = 0;
676
677 layout.setContentsMargins(1, 2, 3, 4);
678 QApplication::sendPostedEvents(0, 0);
679 QCOMPARE(layout.layoutRequest, 1);
680
681 layout.setOrientation(Qt::Vertical);
682 QApplication::sendPostedEvents(0, 0);
683 QCOMPARE(layout.layoutRequest, 2);
684
685 for (int i = 0; i < count; ++i)
686 layout.invalidate(); // Event is compressed, should only get one layoutrequest
687 QApplication::sendPostedEvents(0, 0);
688 QCOMPARE(layout.layoutRequest, count ? 3 : 2);
689 delete widget;
690 }
691
itemAt_data()692 void tst_QGraphicsLinearLayout::itemAt_data()
693 {
694 QTest::addColumn<int>("index");
695 QTest::newRow("0") << 0;
696 QTest::newRow("1") << 1;
697 QTest::newRow("2") << 2;
698 }
699
700 // QGraphicsLayoutItem* itemAt(int index) const public
itemAt()701 void tst_QGraphicsLinearLayout::itemAt()
702 {
703 // see also the insertItem() etc tests
704 QFETCH(int, index);
705 SubQGraphicsLinearLayout layout;
706 for (int i = 0; i < 3; ++i)
707 layout.addItem(new QGraphicsWidget);
708
709 QVERIFY(layout.itemAt(index) != 0);
710 }
711
itemAt_visualOrder()712 void tst_QGraphicsLinearLayout::itemAt_visualOrder()
713 {
714 QGraphicsLinearLayout *l = new QGraphicsLinearLayout;
715
716 QGraphicsWidget *w1 = new QGraphicsWidget;
717 l->addItem(w1);
718
719 QGraphicsWidget *w3 = new QGraphicsWidget;
720 l->addItem(w3);
721
722 QGraphicsWidget *w0 = new QGraphicsWidget;
723 l->insertItem(0, w0);
724
725 QGraphicsWidget *w2 = new QGraphicsWidget;
726 l->insertItem(2, w2);
727
728 QCOMPARE(l->itemAt(0), static_cast<QGraphicsLayoutItem*>(w0));
729 QCOMPARE(l->itemAt(1), static_cast<QGraphicsLayoutItem*>(w1));
730 QCOMPARE(l->itemAt(2), static_cast<QGraphicsLayoutItem*>(w2));
731 QCOMPARE(l->itemAt(3), static_cast<QGraphicsLayoutItem*>(w3));
732 }
733
orientation_data()734 void tst_QGraphicsLinearLayout::orientation_data()
735 {
736 QTest::addColumn<Qt::Orientation>("orientation");
737 QTest::newRow("vertical") << Qt::Vertical;
738 QTest::newRow("horizontal") << Qt::Horizontal;
739 }
740
741 // Qt::Orientation orientation() const public
orientation()742 void tst_QGraphicsLinearLayout::orientation()
743 {
744 QFETCH(Qt::Orientation, orientation);
745
746 QGraphicsScene scene;
747 QGraphicsView view(&scene);
748 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
749 Qt::Orientation initialOrientation = (orientation == Qt::Vertical ? Qt::Horizontal : Qt::Vertical);
750 SubQGraphicsLinearLayout &layout = *(new SubQGraphicsLinearLayout(initialOrientation));
751 scene.addItem(widget);
752 widget->setLayout(&layout);
753 widget->setContentsMargins(0, 0, 0, 0);
754 layout.setContentsMargins(0, 0, 0, 0);
755 int i;
756 int itemCount = 3;
757 for (i = 0; i < itemCount; ++i)
758 layout.addItem(new RectWidget);
759 QCOMPARE(layout.orientation(), initialOrientation);
760 QList<qreal> positions;
761
762 view.show();
763 widget->show();
764 qApp->processEvents();
765
766 for (i = 0; i < itemCount; ++i) {
767 QGraphicsWidget *item = static_cast<QGraphicsWidget*>(layout.itemAt(i));
768 qreal pos;
769 if (initialOrientation == Qt::Horizontal)
770 pos = item->pos().x();
771 else
772 pos = item->pos().y();
773 positions.append(pos);
774
775 }
776
777 layout.setOrientation(orientation);
778 QCOMPARE(layout.orientation(), orientation);
779 // important to resize to preferredsize when orientation is switched
780 widget->resize(widget->effectiveSizeHint(Qt::PreferredSize));
781 qApp->processEvents();
782 for (i = 0; i < positions.count(); ++i) {
783 QGraphicsWidget *item = static_cast<QGraphicsWidget*>(layout.itemAt(i));
784 if (initialOrientation == Qt::Horizontal)
785 QCOMPARE(item->pos().y(), positions.at(i));
786 else
787 QCOMPARE(item->pos().x(), positions.at(i));
788 }
789
790 //QSKIP("LayoutdirectionChange should only posted when QGraphicsWidget::setLayoutDirection() is called, right?", SkipAll);
791
792 //QCOMPARE(layout.layoutDirectionChange, 1);
793 }
794
removeAt_data()795 void tst_QGraphicsLinearLayout::removeAt_data()
796 {
797 QTest::addColumn<int>("itemCount");
798 QTest::addColumn<int>("layoutCount");
799 QTest::addColumn<int>("removeItemAt");
800 QTest::addColumn<Qt::Orientation>("orientation");
801 for (int i = -1; i < 4; ++i) {
802 for (int k = 0; k < 2; ++k) {
803 Qt::Orientation orientation = (k == 0) ? Qt::Vertical : Qt::Horizontal;
804 QTest::newRow(QString("0, 0, %1").arg(i).toLatin1()) << 0 << 0 << i << orientation;
805 QTest::newRow(QString("1, 0, %1").arg(i).toLatin1()) << 1 << 0 << i << orientation;
806 QTest::newRow(QString("0, 1, %1").arg(i).toLatin1()) << 0 << 1 << i << orientation;
807 QTest::newRow(QString("2, 2, %1").arg(i).toLatin1()) << 2 << 2 << i << orientation;
808 }
809 }
810 }
811
812 // void removeAt(int index) public
removeAt()813 void tst_QGraphicsLinearLayout::removeAt()
814 {
815 QFETCH(int, itemCount);
816 QFETCH(int, layoutCount);
817 QFETCH(int, removeItemAt);
818 QFETCH(Qt::Orientation, orientation);
819 if (removeItemAt >= layoutCount + itemCount)
820 return;
821
822 SubQGraphicsLinearLayout layout(orientation);
823 for (int i = 0; i < itemCount; ++i)
824 layout.addItem(new QGraphicsWidget);
825 for (int i = 0; i < layoutCount; ++i)
826 layout.addItem(new SubQGraphicsLinearLayout);
827 QSizeF oldSizeHint = layout.sizeHint(Qt::PreferredSize, QSizeF());
828
829 QGraphicsLayoutItem *w = 0;
830 if (removeItemAt >= 0 && removeItemAt < layout.count())
831 w = layout.itemAt(removeItemAt);
832 if (w) {
833 QGraphicsLayoutItem *wParent = w->parentLayoutItem();
834 QCOMPARE(wParent, static_cast<QGraphicsLayoutItem *>(&layout));
835 layout.removeAt(removeItemAt);
836 wParent = w->parentLayoutItem();
837 QCOMPARE(wParent, static_cast<QGraphicsLayoutItem *>(0));
838 delete w;
839 }
840 QCOMPARE(layout.count(), itemCount + layoutCount - (w ? 1 : 0));
841
842 layout.activate();
843 QSizeF newSizeHint = layout.sizeHint(Qt::PreferredSize, QSizeF());
844 if (orientation == Qt::Horizontal)
845 QVERIFY(oldSizeHint.width() >= newSizeHint.width());
846 else
847 QVERIFY(oldSizeHint.height() >= newSizeHint.height());
848 }
849
removeItem_data()850 void tst_QGraphicsLinearLayout::removeItem_data()
851 {
852 QTest::addColumn<int>("itemCount");
853 QTest::addColumn<int>("layoutCount");
854 QTest::addColumn<int>("removeItemAt");
855 for (int i = -1; i < 4; ++i) {
856 QTest::newRow(QString("0, 0, %1").arg(i).toLatin1()) << 0 << 0 << i;
857 QTest::newRow(QString("1, 0, %1").arg(i).toLatin1()) << 1 << 0 << i;
858 QTest::newRow(QString("0, 1, %1").arg(i).toLatin1()) << 0 << 1 << i;
859 QTest::newRow(QString("2, 2, %1").arg(i).toLatin1()) << 2 << 2 << i;
860 }
861 }
862
863 // void removeItem(QGraphicsLayoutItem* item) public
removeItem()864 void tst_QGraphicsLinearLayout::removeItem()
865 {
866 QFETCH(int, itemCount);
867 QFETCH(int, layoutCount);
868 QFETCH(int, removeItemAt);
869 if (removeItemAt >= layoutCount + itemCount)
870 return;
871
872 SubQGraphicsLinearLayout layout;
873 for (int i = 0; i < itemCount; ++i)
874 layout.addItem(new QGraphicsWidget);
875 for (int i = 0; i < layoutCount; ++i)
876 layout.addItem(new SubQGraphicsLinearLayout);
877
878 QGraphicsLayoutItem *w = 0;
879 if (removeItemAt >= 0 && removeItemAt < layout.count())
880 w = layout.itemAt(removeItemAt);
881 QSizeF oldSizeHint = layout.sizeHint(Qt::PreferredSize, QSizeF());
882 if (w) {
883 layout.removeItem(w);
884 delete w;
885 }
886 QCOMPARE(layout.count(), itemCount + layoutCount - (w ? 1 : 0));
887
888 layout.activate();
889 QSizeF newSizeHint = layout.sizeHint(Qt::PreferredSize, QSizeF());
890 QVERIFY(oldSizeHint.width() >= newSizeHint.width());
891 }
892
setGeometry_data()893 void tst_QGraphicsLinearLayout::setGeometry_data()
894 {
895 QTest::addColumn<QRectF>("rect");
896 QTest::newRow("null") << QRectF();
897 QTest::newRow("small") << QRectF(0, 0, 10, 10);
898 }
899
900 // void setGeometry(QRectF const& rect) public
setGeometry()901 void tst_QGraphicsLinearLayout::setGeometry()
902 {
903 QFETCH(QRectF, rect);
904 QGraphicsScene scene;
905 QGraphicsView view(&scene);
906 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
907 SubQGraphicsLinearLayout &layout = *(new SubQGraphicsLinearLayout);
908 scene.addItem(widget);
909 widget->setLayout(&layout);
910 widget->setContentsMargins(0, 0, 0, 0);
911 layout.setContentsMargins(0, 0, 0, 0);
912 layout.setMaximumSize(100, 100);
913 view.show();
914 widget->show();
915 QApplication::processEvents();
916 widget->setGeometry(rect);
917 QCOMPARE(layout.geometry(), rect);
918 // see also geometry()
919 delete widget;
920 }
921
setSpacing_data()922 void tst_QGraphicsLinearLayout::setSpacing_data()
923 {
924 QTest::addColumn<qreal>("spacing");
925 QTest::newRow("0") << (qreal)0;
926 QTest::newRow("5") << (qreal)5;
927 QTest::newRow("3.3") << (qreal)3.3;
928 QTest::newRow("-4.3") << (qreal)4.3;
929 }
930
931 // void setSpacing(qreal spacing) public
setSpacing()932 void tst_QGraphicsLinearLayout::setSpacing()
933 {
934 QFETCH(qreal, spacing);
935
936 QGraphicsScene scene;
937 QGraphicsView view(&scene);
938 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
939 SubQGraphicsLinearLayout &layout = *(new SubQGraphicsLinearLayout);
940 scene.addItem(widget);
941 widget->setLayout(&layout);
942 layout.setContentsMargins(0, 0, 0, 0);
943
944 qreal oldSpacing = layout.spacing();
945 if (oldSpacing != -1) {
946 for (int i = 0; i < 3; ++i)
947 layout.addItem(new QGraphicsWidget);
948 QSizeF oldSizeHint = layout.sizeHint(Qt::PreferredSize);
949
950 layout.setSpacing(spacing);
951 QCOMPARE(layout.spacing(), spacing);
952
953 view.show();
954 widget->show();
955 QApplication::processEvents();
956 QSizeF newSizeHint = layout.sizeHint(Qt::PreferredSize);
957
958 QCOMPARE(oldSizeHint.width() - oldSpacing * 2, newSizeHint.width() - spacing * 2);
959 } else {
960 QSKIP("This style uses non-uniform spacings (layoutSpacingImplementation() is reimplemented)", SkipAll);
961 }
962 delete widget;
963 }
964
setItemSpacing_data()965 void tst_QGraphicsLinearLayout::setItemSpacing_data()
966 {
967 QTest::addColumn<int>("index");
968 QTest::addColumn<int>("spacing");
969
970 QTest::newRow("0 at 0") << 0 << 0;
971 QTest::newRow("10 at 0") << 0 << 10;
972 QTest::newRow("10 at 1") << 1 << 10;
973 QTest::newRow("10 at the end") << 4 << 10;
974 }
975
setItemSpacing()976 void tst_QGraphicsLinearLayout::setItemSpacing()
977 {
978 QFETCH(int, index);
979 QFETCH(int, spacing);
980
981 QGraphicsScene scene;
982 QGraphicsView view(&scene);
983 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
984 SubQGraphicsLinearLayout *layout = new SubQGraphicsLinearLayout;
985 scene.addItem(widget);
986 widget->setLayout(layout);
987 layout->setContentsMargins(0, 0, 0, 0);
988 for (int i = 0; i < 5; ++i) {
989 QGraphicsWidget *w = new QGraphicsWidget;
990 layout->addItem(w);
991 }
992 QSizeF oldSizeHint = layout->sizeHint(Qt::PreferredSize);
993 qreal oldSpacing = 0;
994 if (index < layout->count() - 1)
995 oldSpacing = layout->spacing();
996 else
997 spacing = 0;
998
999 layout->setItemSpacing(index, spacing);
1000 view.show();
1001 QApplication::processEvents();
1002 QSizeF newSizeHint = layout->sizeHint(Qt::PreferredSize);
1003 if (oldSpacing >= 0) {
1004 QCOMPARE(newSizeHint.width() - spacing, oldSizeHint.width() - oldSpacing);
1005 } else {
1006 QSKIP("This style uses non-uniform spacings (layoutSpacingImplementation() is reimplemented)", SkipAll);
1007 }
1008 delete widget;
1009 }
1010
itemSpacing()1011 void tst_QGraphicsLinearLayout::itemSpacing()
1012 {
1013 QGraphicsScene scene;
1014 QGraphicsView view(&scene);
1015 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
1016 SubQGraphicsLinearLayout *layout = new SubQGraphicsLinearLayout;
1017 scene.addItem(widget);
1018 widget->setLayout(layout);
1019 layout->setContentsMargins(0, 0, 0, 0);
1020 for (int i = 0; i < 5; ++i) {
1021 QGraphicsWidget *w = new QGraphicsWidget;
1022 layout->addItem(w);
1023 }
1024
1025 // Check defaults
1026 qreal defaultSpacing = layout->spacing();
1027 if (defaultSpacing >= 0) {
1028 QCOMPARE(layout->itemSpacing(0), defaultSpacing);
1029 } else {
1030 // all widgets are the same, so the spacing should be uniform
1031 QCOMPARE(layout->itemSpacing(0), layout->itemSpacing(1));
1032 }
1033
1034 layout->setItemSpacing(1, 42);
1035 QCOMPARE(layout->itemSpacing(1), qreal(42));
1036
1037 // try to unset
1038 layout->setItemSpacing(1, -1);
1039 QCOMPARE(layout->itemSpacing(1), defaultSpacing);
1040
1041 delete widget;
1042 }
1043
1044 /**
1045 * The stretch factors are not applied linearly, but they are used together with both the preferred size, maximum size to form the
1046 * internal effective stretch factor.
1047 * There is only need to apply stretch factors if the size of the layout is different than the layouts preferred size.
1048 * (If the size of the layout is the preferred size, then all items should get their preferred sizes.
1049 * However, imagine this use case:
1050 * Layout
1051 * +----------+----------+----------+
1052 * name | A | B | C |
1053 * stretch | 1 | 2 | 3 |
1054 * sizehints|[5,10,50] |[5,10,50] |[5,10,50] |
1055 * +----------+----------+----------+
1056 *
1057 * layout->resize(120, h)
1058 *
1059 * In QLayout, C would become 50, B would become 50 and A would get 20. When scaling a layout this would give a jerky feeling, since
1060 * the item with the highest stretch factor will first resize. When that has reached its maximum the next candidate for stretch will
1061 * resize, and finally, item with the lowest stretch factor will resize.
1062 * In QGraphicsLinearLayout we try to scale all items so that they all reach their maximum at the same time. This means that
1063 * their relative sizes are not proportional to their stretch factors.
1064 */
1065
1066 typedef QList<int> IntList;
1067 Q_DECLARE_METATYPE(IntList)
Q_DECLARE_METATYPE(qreal)1068 Q_DECLARE_METATYPE(qreal)
1069
1070 void tst_QGraphicsLinearLayout::setStretchFactor_data()
1071 {
1072 QTest::addColumn<qreal>("totalSize");
1073 QTest::addColumn<IntList>("stretches");
1074
1075 QTest::newRow(QString("60 [1,2]").toLatin1()) << qreal(60.0) << (IntList() << 1 << 2);
1076 QTest::newRow(QString("60 [1,2,3]").toLatin1()) << qreal(60.0) << (IntList() << 1 << 2 << 3);
1077 QTest::newRow(QString("120 [1,2,3,6]").toLatin1()) << qreal(120.0) << (IntList() << 1 << 2 << 3 << 6);
1078 }
1079
1080 // void setStretchFactor(QGraphicsLayoutItem* item, int stretch) public
setStretchFactor()1081 void tst_QGraphicsLinearLayout::setStretchFactor()
1082 {
1083 QFETCH(qreal, totalSize);
1084 QFETCH(IntList, stretches);
1085 //QSKIP("Seems to be some problems with stretch factors. Talk with Jasmin", SkipAll);
1086 QGraphicsScene scene;
1087 QGraphicsView view(&scene);
1088 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
1089 SubQGraphicsLinearLayout &layout = *(new SubQGraphicsLinearLayout);
1090 scene.addItem(widget);
1091 widget->setLayout(&layout);
1092 layout.setContentsMargins(0, 0, 0, 0);
1093 layout.setSpacing(0.0);
1094 widget->setContentsMargins(0, 0, 0, 0);
1095
1096
1097 int i;
1098 for (i = 0; i < stretches.count(); ++i) {
1099 QGraphicsWidget *item = new RectWidget(widget);
1100 item->setMinimumSize(5,5);
1101 item->setPreferredSize(10,5);
1102 item->setMaximumSize(50,5);
1103 layout.addItem(item);
1104 layout.setStretchFactor(item, stretches.at(i));
1105 }
1106
1107 widget->resize(totalSize, 10);
1108 QApplication::processEvents();
1109
1110 view.show();
1111 widget->show();
1112
1113 qreal firstStretch = -1;
1114 qreal firstExtent = -1.;
1115 qreal sumExtent = 0;
1116 for (i = 0; i < stretches.count(); ++i) {
1117 QGraphicsWidget *item = static_cast<QGraphicsWidget*>(layout.itemAt(i));
1118 qreal extent = item->size().width();
1119 qreal stretch = (qreal)stretches.at(i);
1120 if (firstStretch != -1 && firstExtent != -1) {
1121 // The resulting widths does not correspond linearly to the stretch factors.
1122 if (stretch == firstStretch)
1123 QCOMPARE(extent, firstExtent);
1124 else if (stretch > firstStretch)
1125 QVERIFY(extent > firstExtent);
1126 else
1127 QVERIFY(extent < firstExtent);
1128 } else {
1129 firstStretch = (qreal)stretch;
1130 firstExtent = extent;
1131 }
1132 sumExtent+= extent;
1133 }
1134 QCOMPARE(sumExtent, totalSize);
1135
1136 delete widget;
1137 }
1138
testStretch()1139 void tst_QGraphicsLinearLayout::testStretch()
1140 {
1141 QGraphicsScene scene;
1142 QGraphicsView *view = new QGraphicsView(&scene);
1143 QGraphicsWidget *form = new QGraphicsWidget(0, Qt::Window);
1144
1145 scene.addItem(form);
1146 form->setMinimumSize(600, 600);
1147 form->setMaximumSize(600, 600);
1148 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Horizontal, form);
1149 QGraphicsWidget *w1 = new RectWidget;
1150 w1->setPreferredSize(100,100);
1151 w1->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
1152 QGraphicsWidget *w2 = new RectWidget;
1153 w2->setPreferredSize(200,200);
1154 w2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
1155 layout->setSpacing(0);
1156 layout->setContentsMargins(0, 0, 0, 0);
1157 layout->addItem(w1);
1158 layout->addStretch(2);
1159 layout->addItem(w2);
1160 QCOMPARE(layout->count(), 2);
1161 QVERIFY(layout->itemAt(0) == w1);
1162 QVERIFY(layout->itemAt(1) == w2);
1163 layout->activate();
1164
1165 //view->setSceneRect(-50, -50, 800, 800);
1166 //view->show();
1167 //QTest::qWaitForWindowShown(view);
1168 //QTest::qWait(5000);
1169 QCOMPARE(form->geometry().size(), QSizeF(600,600));
1170 QCOMPARE(w1->geometry(), QRectF(0, 0, 100, 100));
1171 QCOMPARE(w2->geometry(), QRectF(400, 0, 200, 200));
1172 }
1173
defaultStretchFactors_data()1174 void tst_QGraphicsLinearLayout::defaultStretchFactors_data()
1175 {
1176 QTest::addColumn<Qt::Orientation>("orientation");
1177 QTest::addColumn<int>("count");
1178 QTest::addColumn<IntList>("preferredSizeHints");
1179 QTest::addColumn<IntList>("stretches");
1180 QTest::addColumn<IntList>("ignoreFlag");
1181 QTest::addColumn<QSizeF>("newSize");
1182 QTest::addColumn<IntList>("expectedSizes");
1183
1184 QTest::newRow("hor") << Qt::Horizontal << 3
1185 << (IntList() << 20 << 40 << 60)
1186 << (IntList())
1187 << (IntList())
1188 << QSizeF()
1189 << (IntList() << 20 << 40 << 60);
1190
1191 QTest::newRow("ver") << Qt::Vertical << 3
1192 << (IntList() << 20 << 40 << 60)
1193 << (IntList())
1194 << (IntList())
1195 << QSizeF()
1196 << (IntList() << 20 << 40 << 60);
1197
1198 QTest::newRow("hor,ignore123") << Qt::Horizontal << 3
1199 << (IntList() << 20 << 40 << 60)
1200 << (IntList())
1201 << (IntList() << 1 << 1 << 1)
1202 << QSizeF()
1203 << (IntList() << 0 << 0 << 0);
1204
1205 QTest::newRow("hor,ignore23") << Qt::Horizontal << 3
1206 << (IntList() << 10 << 10 << 10)
1207 << (IntList())
1208 << (IntList() << 0 << 1 << 1)
1209 << QSizeF(200, 50)
1210 << (IntList()); //### stretches are not linear.
1211
1212 QTest::newRow("hor,ignore2") << Qt::Horizontal << 3
1213 << (IntList() << 10 << 10 << 10)
1214 << (IntList())
1215 << (IntList() << 0 << 1 << 0)
1216 << QSizeF()
1217 << (IntList() << 10 << 0 << 10);
1218
1219 }
1220
defaultStretchFactors()1221 void tst_QGraphicsLinearLayout::defaultStretchFactors()
1222 {
1223 QFETCH(Qt::Orientation, orientation);
1224 QFETCH(int, count);
1225 QFETCH(IntList, preferredSizeHints);
1226 QFETCH(IntList, stretches);
1227 QFETCH(IntList, ignoreFlag);
1228 QFETCH(QSizeF, newSize);
1229 QFETCH(IntList, expectedSizes);
1230
1231 QGraphicsScene scene;
1232 QGraphicsView view(&scene);
1233 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
1234 SubQGraphicsLinearLayout *layout = new SubQGraphicsLinearLayout(orientation);
1235 scene.addItem(widget);
1236 widget->setLayout(layout);
1237 layout->setContentsMargins(0, 0, 0, 0);
1238 layout->setSpacing(0.0);
1239 widget->setContentsMargins(0, 0, 0, 0);
1240
1241 int i;
1242 for (i = 0; i < count; ++i) {
1243 RectWidget *item = new RectWidget(widget);
1244 layout->addItem(item);
1245 if (preferredSizeHints.value(i, -1) >= 0) {
1246 item->setSizeHint(Qt::PreferredSize, QSizeF(preferredSizeHints.at(i), preferredSizeHints.at(i)));
1247 }
1248 if (stretches.value(i, -1) >= 0) {
1249 layout->setStretchFactor(item, stretches.at(i));
1250 }
1251 if (ignoreFlag.value(i, 0) != 0) {
1252 QSizePolicy sp = item->sizePolicy();
1253 if (orientation == Qt::Horizontal)
1254 sp.setHorizontalPolicy(QSizePolicy::Policy(sp.horizontalPolicy() | QSizePolicy::IgnoreFlag));
1255 else
1256 sp.setVerticalPolicy(QSizePolicy::Policy(sp.verticalPolicy() | QSizePolicy::IgnoreFlag));
1257 item->setSizePolicy(sp);
1258 }
1259 }
1260
1261 QApplication::processEvents();
1262
1263 widget->show();
1264 view.show();
1265 view.resize(400,300);
1266 if (newSize.isValid())
1267 widget->resize(newSize);
1268
1269 QApplication::processEvents();
1270 for (i = 0; i < count; ++i) {
1271 QSizeF itemSize = layout->itemAt(i)->geometry().size();
1272 if (orientation == Qt::Vertical)
1273 itemSize.transpose();
1274 if (i < expectedSizes.count())
1275 QCOMPARE(itemSize.width(), qreal(expectedSizes.at(i)));
1276 }
1277
1278 delete widget;
1279 }
1280
Q_DECLARE_METATYPE(Qt::SizeHint)1281 Q_DECLARE_METATYPE(Qt::SizeHint)
1282 void tst_QGraphicsLinearLayout::sizeHint_data()
1283 {
1284 QTest::addColumn<Qt::SizeHint>("which");
1285 QTest::addColumn<QSizeF>("constraint");
1286 QTest::addColumn<qreal>("spacing");
1287 QTest::addColumn<qreal>("layoutMargin");
1288 QTest::addColumn<QSizeF>("sizeHint");
1289
1290 QTest::newRow("minimumSize") << Qt::MinimumSize << QSizeF() << qreal(0.0) << qreal(0.0) << QSizeF(30, 10);
1291 QTest::newRow("preferredSize") << Qt::PreferredSize << QSizeF() << qreal(0.0) << qreal(0.0) << QSizeF(75, 25);
1292 QTest::newRow("maximumSize") << Qt::MaximumSize << QSizeF() << qreal(0.0) << qreal(0.0) << QSizeF(150, 50);
1293 QTest::newRow("minimumSize, spacing=3") << Qt::MinimumSize << QSizeF() << qreal(3.0) << qreal(0.0) << QSizeF(30 + 2*3, 10);
1294 QTest::newRow("minimumSize, spacing=3, layoutMargin=10") << Qt::MinimumSize << QSizeF() << qreal(3.0) << qreal(10.0) << QSizeF(30 + 2*3 + 2*10, 10 + 2*10);
1295 QTest::newRow("minimumSize, spacing=0, layoutMargin=7") << Qt::MinimumSize << QSizeF() << qreal(0.0) << qreal(7.0) << QSizeF(30 + 0 + 2*7, 10 + 2*7);
1296 }
1297
1298 // QSizeF sizeHint(Qt::SizeHint which, QSizeF const& constraint) const public
sizeHint()1299 void tst_QGraphicsLinearLayout::sizeHint()
1300 {
1301 QFETCH(Qt::SizeHint, which);
1302 QFETCH(QSizeF, constraint);
1303 QFETCH(qreal, spacing);
1304 QFETCH(qreal, layoutMargin);
1305 QFETCH(QSizeF, sizeHint);
1306
1307 QGraphicsScene scene;
1308 QGraphicsView view(&scene);
1309 QGraphicsWidget *widget = new QGraphicsWidget(0, Qt::Window);
1310 SubQGraphicsLinearLayout &layout = *(new SubQGraphicsLinearLayout);
1311 scene.addItem(widget);
1312 widget->setLayout(&layout);
1313 layout.setContentsMargins(layoutMargin, layoutMargin, layoutMargin, layoutMargin);
1314 layout.setSpacing(spacing);
1315 for (int i = 0; i < 3; ++i) {
1316 QGraphicsWidget *item = new QGraphicsWidget(widget);
1317 item->setMinimumSize(10, 10);
1318 item->setPreferredSize(25, 25);
1319 item->setMaximumSize(50, 50);
1320 layout.addItem(item);
1321 }
1322 QApplication::processEvents();
1323 QCOMPARE(layout.sizeHint(which, constraint), sizeHint);
1324 delete widget;
1325 }
1326
updateGeometry()1327 void tst_QGraphicsLinearLayout::updateGeometry()
1328 {
1329 QGraphicsScene scene;
1330 QGraphicsView view(&scene);
1331
1332 QGraphicsWidget *window = new QGraphicsWidget(0, Qt::Window);
1333 QGraphicsWidget *w1 = new QGraphicsWidget(window);
1334 w1->setMinimumSize(100, 40);
1335 SubQGraphicsLinearLayout *layout = new SubQGraphicsLinearLayout;
1336 layout->addItem(w1);
1337 scene.addItem(window);
1338 window->setLayout(layout);
1339 layout->setContentsMargins(0, 0, 0, 0);
1340 QCOMPARE(w1->parentLayoutItem(), static_cast<QGraphicsLayoutItem*>(layout));
1341 QCOMPARE(layout->parentLayoutItem(), static_cast<QGraphicsLayoutItem*>(window));
1342
1343 view.show();
1344 QApplication::processEvents();
1345 QCOMPARE(window->size().toSize(), QSize(100, 50));
1346 w1->setMinimumSize(110, 60);
1347 QApplication::processEvents();
1348 QCOMPARE(window->size().toSize(), QSize(110, 60));
1349 QApplication::processEvents();
1350
1351 {
1352 delete window;
1353 window = new QGraphicsWidget(0, Qt::Window);
1354 SubQGraphicsLinearLayout *layout2a = new SubQGraphicsLinearLayout;
1355 QGraphicsWidget *w1 = new QGraphicsWidget(window);
1356 w1->setMinimumSize(110, 50);
1357 layout2a->addItem(w1);
1358 SubQGraphicsLinearLayout *layout2 = new SubQGraphicsLinearLayout;
1359 layout2->addItem(layout2a);
1360 layout2->setContentsMargins(1, 1, 1, 1);
1361 layout2a->setContentsMargins(1, 1, 1, 1);
1362 window->setLayout(layout2);
1363 QApplication::processEvents();
1364 QCOMPARE(w1->parentLayoutItem(), static_cast<QGraphicsLayoutItem*>(layout2a));
1365 QCOMPARE(layout2a->parentLayoutItem(), static_cast<QGraphicsLayoutItem*>(layout2));
1366 QCOMPARE(layout2->parentLayoutItem(), static_cast<QGraphicsLayoutItem*>(window));
1367 QCOMPARE(window->size().toSize(), QSize(114, 54));
1368 QApplication::processEvents();
1369 w1->setMinimumSize(120, 60);
1370 QApplication::processEvents();
1371 QCOMPARE(window->size().toSize(), QSize(124, 64));
1372 }
1373
1374 {
1375 delete window;
1376 window = new QGraphicsWidget(0, Qt::Window);
1377 scene.addItem(window);
1378 window->show();
1379 QGraphicsWidget *w1 = new QGraphicsWidget(window);
1380 w1->setMinimumSize(100, 50);
1381 SubQGraphicsLinearLayout *layout2a = new SubQGraphicsLinearLayout;
1382 layout2a->addItem(w1);
1383 SubQGraphicsLinearLayout *layout2 = new SubQGraphicsLinearLayout;
1384 layout2->addItem(layout2a);
1385 layout2a->setContentsMargins(1, 1, 1, 1);
1386 window->setLayout(layout2);
1387 QApplication::processEvents();
1388 qreal left, top, right, bottom;
1389 layout2->getContentsMargins(&left, &top, &right, &bottom);
1390 QCOMPARE(window->size().toSize(), QSize(102 +left + right, 52 + top + bottom));
1391 }
1392
1393 {
1394 delete window;
1395 window = new QGraphicsWidget(0, Qt::Window);
1396 scene.addItem(window);
1397 QGraphicsWidget *w1 = new QGraphicsWidget(window);
1398 w1->setMinimumSize(100, 50);
1399 window->setLayout(0);
1400 SubQGraphicsLinearLayout *layout2a = new SubQGraphicsLinearLayout;
1401 layout2a->addItem(w1);
1402 SubQGraphicsLinearLayout *layout2 = new SubQGraphicsLinearLayout;
1403 layout2->addItem(layout2a);
1404 window->resize(200, 80);
1405 window->setLayout(layout2);
1406 window->show();
1407 QApplication::processEvents();
1408 QCOMPARE(window->size().toSize(), QSize(200, 80));
1409 }
1410
1411 }
1412
layoutDirection()1413 void tst_QGraphicsLinearLayout::layoutDirection()
1414 {
1415 QGraphicsScene scene;
1416 QGraphicsView view(&scene);
1417
1418 QGraphicsWidget *window = new QGraphicsWidget(0, Qt::Window);
1419 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout;
1420 layout->setContentsMargins(1, 2, 3, 4);
1421 layout->setSpacing(6);
1422
1423 RectWidget *w1 = new RectWidget;
1424 w1->setPreferredSize(20, 20);
1425 w1->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
1426 layout->addItem(w1);
1427 RectWidget *w2 = new RectWidget;
1428 w2->setPreferredSize(20, 20);
1429 w2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
1430 layout->addItem(w2);
1431
1432 scene.addItem(window);
1433 window->setLayout(layout);
1434 view.show();
1435 window->resize(50, 20);
1436 window->setLayoutDirection(Qt::LeftToRight);
1437 QApplication::processEvents();
1438 QCOMPARE(w1->geometry().left(), 1.0);
1439 QCOMPARE(w1->geometry().right(), 21.0);
1440 QCOMPARE(w2->geometry().left(), 27.0);
1441 QCOMPARE(w2->geometry().right(), 47.0);
1442
1443 window->setLayoutDirection(Qt::RightToLeft);
1444 QApplication::processEvents();
1445 QCOMPARE(w1->geometry().right(), 49.0);
1446 QCOMPARE(w1->geometry().left(), 29.0);
1447 QCOMPARE(w2->geometry().right(), 23.0);
1448 QCOMPARE(w2->geometry().left(), 3.0);
1449
1450 delete window;
1451 }
1452
removeLayout()1453 void tst_QGraphicsLinearLayout::removeLayout()
1454 {
1455 QGraphicsScene scene;
1456 RectWidget *textEdit = new RectWidget;
1457 RectWidget *pushButton = new RectWidget;
1458 scene.addItem(textEdit);
1459 scene.addItem(pushButton);
1460
1461 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout;
1462 layout->addItem(textEdit);
1463 layout->addItem(pushButton);
1464
1465 QGraphicsWidget *form = new QGraphicsWidget;
1466 form->setLayout(layout);
1467 scene.addItem(form);
1468
1469 QGraphicsView view(&scene);
1470 view.show();
1471 QTest::qWait(20);
1472
1473 QRectF r1 = textEdit->geometry();
1474 QRectF r2 = pushButton->geometry();
1475 form->setLayout(0);
1476 //documentation of QGraphicsWidget::setLayout:
1477 //If layout is 0, the widget is left without a layout. Existing subwidgets' geometries will remain unaffected.
1478 QCOMPARE(textEdit->geometry(), r1);
1479 QCOMPARE(pushButton->geometry(), r2);
1480 }
1481
avoidRecursionInInsertItem()1482 void tst_QGraphicsLinearLayout::avoidRecursionInInsertItem()
1483 {
1484 QGraphicsWidget window(0, Qt::Window);
1485 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(&window);
1486 QCOMPARE(layout->count(), 0);
1487 QTest::ignoreMessage(QtWarningMsg, "QGraphicsLinearLayout::insertItem: cannot insert itself");
1488 layout->insertItem(0, layout);
1489 QCOMPARE(layout->count(), 0);
1490 }
1491
styleInfoLeak()1492 void tst_QGraphicsLinearLayout::styleInfoLeak()
1493 {
1494 QGraphicsLinearLayout layout;
1495 layout.spacing();
1496 }
1497
task218400_insertStretchCrash()1498 void tst_QGraphicsLinearLayout::task218400_insertStretchCrash()
1499 {
1500 QGraphicsScene *scene = new QGraphicsScene;
1501 QGraphicsWidget *a = scene->addWidget(new QWidget);
1502 QGraphicsWidget *b = scene->addWidget(new QWidget);
1503
1504 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout;
1505 layout->addItem(a);
1506 layout->addItem(b);
1507 layout->insertStretch(0); // inserts gap in item grid in the layout engine
1508
1509 QGraphicsWidget *form = new QGraphicsWidget;
1510 form->setLayout(layout); // crash
1511 }
1512
testAlignmentInLargerLayout()1513 void tst_QGraphicsLinearLayout::testAlignmentInLargerLayout()
1514 {
1515 QGraphicsScene *scene = new QGraphicsScene;
1516 QGraphicsWidget *form = new QGraphicsWidget;
1517 scene->addItem(form);
1518 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Vertical, form);
1519 layout->setSpacing(0);
1520 layout->setContentsMargins(0,0,0,0);
1521
1522 QGraphicsWidget *a = new QGraphicsWidget;
1523 a->setMaximumSize(100,100);
1524 layout->addItem(a);
1525
1526 QCOMPARE(form->maximumSize(), QSizeF(100,100));
1527 QCOMPARE(layout->maximumSize(), QSizeF(100,100));
1528 layout->setMinimumSize(QSizeF(200,200));
1529 layout->setMaximumSize(QSizeF(200,200));
1530
1531 layout->setAlignment(a, Qt::AlignCenter);
1532 layout->activate();
1533 QCOMPARE(a->geometry(), QRectF(50,50,100,100));
1534
1535 layout->setAlignment(a, Qt::AlignRight | Qt::AlignBottom);
1536 layout->activate();
1537 QCOMPARE(a->geometry(), QRectF(100,100,100,100));
1538
1539 layout->setAlignment(a, Qt::AlignHCenter | Qt::AlignTop);
1540 layout->activate();
1541 QCOMPARE(a->geometry(), QRectF(50,0,100,100));
1542
1543 QGraphicsWidget *b = new QGraphicsWidget;
1544 b->setMaximumSize(100,100);
1545 layout->addItem(b);
1546
1547 layout->setAlignment(a, Qt::AlignCenter);
1548 layout->setAlignment(b, Qt::AlignCenter);
1549 layout->activate();
1550 QCOMPARE(a->geometry(), QRectF(50,0,100,100));
1551 QCOMPARE(b->geometry(), QRectF(50,100,100,100));
1552
1553 layout->setAlignment(a, Qt::AlignRight | Qt::AlignBottom);
1554 layout->setAlignment(b, Qt::AlignLeft | Qt::AlignTop);
1555 layout->activate();
1556 QCOMPARE(a->geometry(), QRectF(100,0,100,100));
1557 QCOMPARE(b->geometry(), QRectF(0,100,100,100));
1558 }
1559
testOffByOneInLargerLayout()1560 void tst_QGraphicsLinearLayout::testOffByOneInLargerLayout() {
1561 QGraphicsScene *scene = new QGraphicsScene;
1562 QGraphicsWidget *form = new QGraphicsWidget;
1563 scene->addItem(form);
1564 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Vertical, form);
1565 layout->setSpacing(0);
1566 layout->setContentsMargins(0,0,0,0);
1567
1568 QGraphicsWidget *a = new QGraphicsWidget;
1569 QGraphicsWidget *b = new QGraphicsWidget;
1570 a->setMaximumSize(100,100);
1571 b->setMaximumSize(100,100);
1572 layout->addItem(a);
1573 layout->addItem(b);
1574
1575 layout->setAlignment(a, Qt::AlignRight | Qt::AlignBottom);
1576 layout->setAlignment(b, Qt::AlignLeft | Qt::AlignTop);
1577 layout->setMinimumSize(QSizeF(101,201));
1578 layout->setMaximumSize(QSizeF(101,201));
1579 layout->activate();
1580 QCOMPARE(a->geometry(), QRectF(1,0.5,100,100));
1581 QCOMPARE(b->geometry(), QRectF(0,100.5,100,100));
1582
1583 layout->setMinimumSize(QSizeF(100,200));
1584 layout->setMaximumSize(QSizeF(100,200));
1585 layout->activate();
1586 QCOMPARE(a->geometry(), QRectF(0,0,100,100));
1587 QCOMPARE(b->geometry(), QRectF(0,100,100,100));
1588
1589 layout->setMinimumSize(QSizeF(99,199));
1590 layout->setMaximumSize(QSizeF(99,199));
1591 layout->activate();
1592 QCOMPARE(a->geometry(), QRectF(0,0,99,99.5));
1593 QCOMPARE(b->geometry(), QRectF(0,99.5,99,99.5));
1594 }
testDefaultAlignment()1595 void tst_QGraphicsLinearLayout::testDefaultAlignment()
1596 {
1597 QGraphicsWidget *widget = new QGraphicsWidget;
1598 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Vertical, widget);
1599 layout->setContentsMargins(0, 0, 0, 0);
1600 layout->setSpacing(0);
1601
1602 QGraphicsWidget *w = new QGraphicsWidget;
1603 w->setMinimumSize(50,50);
1604 w->setMaximumSize(50,50);
1605 layout->addItem(w);
1606
1607 //Default alignment should be to the top-left
1608 QCOMPARE(layout->alignment(w), 0);
1609
1610 //First, check by forcing the layout to be bigger
1611 layout->setMinimumSize(100,100);
1612 layout->activate();
1613 QCOMPARE(layout->geometry(), QRectF(0,0,100,100));
1614 QCOMPARE(w->geometry(), QRectF(0,0,50,50));
1615 layout->setMinimumSize(-1,-1);
1616
1617 //Second, check by adding a larger item in the column
1618 QGraphicsWidget *w2 = new QGraphicsWidget;
1619 w2->setMinimumSize(100,100);
1620 w2->setMaximumSize(100,100);
1621 layout->addItem(w2);
1622 layout->activate();
1623 QCOMPARE(layout->geometry(), QRectF(0,0,100,150));
1624 QCOMPARE(w->geometry(), QRectF(0,0,50,50));
1625 QCOMPARE(w2->geometry(), QRectF(0,50,100,100));
1626 }
1627
combineSizePolicies()1628 void tst_QGraphicsLinearLayout::combineSizePolicies()
1629 {
1630 QGraphicsWidget *widget = new QGraphicsWidget;
1631 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Horizontal, widget);
1632 layout->setContentsMargins(0, 0, 0, 0);
1633 layout->setSpacing(0);
1634
1635 QGraphicsWidget *w1 = new QGraphicsWidget;
1636 w1->setMaximumSize(200,200);
1637 w1->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
1638 layout->addItem(w1);
1639
1640 QGraphicsWidget *w2 = new QGraphicsWidget;
1641 w2->setPreferredSize(50,50);
1642 w2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
1643 layout->addItem(w2);
1644 QCOMPARE(layout->maximumHeight(), qreal(200));
1645
1646 // now remove the fixed vertical size policy, and set instead the maximum height to 50
1647 // this should in effect give the same maximumHeight
1648 w2->setMaximumHeight(50);
1649 w2->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
1650 QCOMPARE(layout->maximumHeight(), qreal(200));
1651 }
1652
hiddenItems()1653 void tst_QGraphicsLinearLayout::hiddenItems()
1654 {
1655 QGraphicsWidget *widget = new QGraphicsWidget;
1656 QGraphicsLinearLayout *layout = new QGraphicsLinearLayout(Qt::Horizontal, widget);
1657 layout->setContentsMargins(0, 0, 0, 0);
1658 layout->setSpacing(2);
1659
1660 RectWidget *w1 = new RectWidget;
1661 w1->setPreferredSize(QSizeF(20, 20));
1662 layout->addItem(w1);
1663
1664 RectWidget *w2 = new RectWidget;
1665 w2->setPreferredSize(QSizeF(20, 20));
1666 layout->addItem(w2);
1667
1668 RectWidget *w3 = new RectWidget;
1669 w3->setPreferredSize(QSizeF(20, 20));
1670 layout->addItem(w3);
1671
1672 QCOMPARE(layout->preferredWidth(), qreal(64));
1673 w2->hide();
1674 QCOMPARE(layout->preferredWidth(), qreal(42));
1675 w2->show();
1676 QCOMPARE(layout->preferredWidth(), qreal(64));
1677 }
1678
1679
1680 QTEST_MAIN(tst_QGraphicsLinearLayout)
1681 #include "tst_qgraphicslinearlayout.moc"
1682
1683