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 <QLineEdit>
32#include <QLabel>
33#include <QStackedLayout>
34#include <qapplication.h>
35#include <qwidget.h>
36#include <QPushButton>
37
38class tst_QStackedLayout : public QObject
39{
40 Q_OBJECT
41
42public:
43 tst_QStackedLayout();
44
45private slots:
46 void init();
47 void cleanup();
48
49 void getSetCheck();
50 void testCase();
51 void deleteCurrent();
52 void removeWidget();
53 void keepFocusAfterSetCurrent();
54 void heigthForWidth();
55 void replaceWidget();
56
57private:
58 QWidget *testWidget;
59};
60
61// Testing get/set functions
62void tst_QStackedLayout::getSetCheck()
63{
64 QStackedLayout obj1;
65 // int QStackedLayout::currentIndex()
66 // void QStackedLayout::setCurrentIndex(int)
67 obj1.setCurrentIndex(0);
68 QCOMPARE(-1, obj1.currentIndex());
69 obj1.setCurrentIndex(INT_MIN);
70 QCOMPARE(-1, obj1.currentIndex());
71 obj1.setCurrentIndex(INT_MAX);
72 QCOMPARE(-1, obj1.currentIndex());
73
74 // QWidget * QStackedLayout::currentWidget()
75 // void QStackedLayout::setCurrentWidget(QWidget *)
76 QWidget *var2 = new QWidget();
77 obj1.addWidget(w: var2);
78 obj1.setCurrentWidget(var2);
79 QCOMPARE(var2, obj1.currentWidget());
80
81 obj1.setCurrentWidget((QWidget *)0);
82 QCOMPARE(obj1.currentWidget(), var2);
83
84 delete var2;
85}
86
87
88tst_QStackedLayout::tst_QStackedLayout()
89 : testWidget(0)
90{
91}
92
93void tst_QStackedLayout::init()
94{
95 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
96 QSKIP("Wayland: This fails. Figure out why.");
97
98 if (testWidget) {
99 delete testWidget;
100 testWidget = 0;
101 }
102 testWidget = new QWidget(0);
103 testWidget->resize( w: 200, h: 200 );
104 testWidget->show();
105
106 // make sure the tests work with focus follows mouse
107 QCursor::setPos(testWidget->geometry().center());
108 testWidget->activateWindow();
109 QVERIFY(QTest::qWaitForWindowActive(testWidget));
110}
111
112void tst_QStackedLayout::cleanup()
113{
114 delete testWidget;
115 testWidget = 0;
116}
117
118void tst_QStackedLayout::testCase()
119{
120 QStackedLayout onStack(testWidget);
121 QStackedLayout *testLayout = &onStack;
122 testWidget->setLayout(testLayout);
123
124 QSignalSpy spy(testLayout,SIGNAL(currentChanged(int)));
125
126 // Nothing in layout
127 QCOMPARE(testLayout->currentIndex(), -1);
128 QCOMPARE(testLayout->currentWidget(), nullptr);
129 QCOMPARE(testLayout->count(), 0);
130
131 // One widget added to layout
132 QWidget *w1 = new QWidget(testWidget);
133 testLayout->addWidget(w: w1);
134 QCOMPARE(spy.count(), 1);
135 QCOMPARE(spy.at(0).at(0).toInt(), 0);
136 spy.clear();
137 QCOMPARE(testLayout->currentIndex(), 0);
138 QCOMPARE(testLayout->currentWidget(), w1);
139 QCOMPARE(testLayout->count(), 1);
140
141 // Another widget added to layout
142 QWidget *w2 = new QWidget(testWidget);
143 testLayout->addWidget(w: w2);
144 QCOMPARE(testLayout->currentIndex(), 0);
145 QCOMPARE(testLayout->currentWidget(), w1);
146 QCOMPARE(testLayout->indexOf(w2), 1);
147 QCOMPARE(testLayout->count(), 2);
148
149 // Change the current index
150 testLayout->setCurrentIndex(1);
151 QCOMPARE(spy.count(), 1);
152 QCOMPARE(spy.at(0).at(0).toInt(), 1);
153 spy.clear();
154 QCOMPARE(testLayout->currentIndex(), 1);
155 QCOMPARE(testLayout->currentWidget(), w2);
156
157 // First widget removed from layout
158 testLayout->removeWidget(w: w1);
159 QCOMPARE(testLayout->currentIndex(), 0);
160 QCOMPARE(testLayout->currentWidget(), w2);
161 QCOMPARE(testLayout->count(), 1);
162
163 // Second widget removed from layout; back to nothing
164 testLayout->removeWidget(w: w2);
165 QCOMPARE(spy.count(), 1);
166 QCOMPARE(spy.at(0).at(0).toInt(), -1);
167 spy.clear();
168 QCOMPARE(testLayout->currentIndex(), -1);
169 QCOMPARE(testLayout->currentWidget(), nullptr);
170 QCOMPARE(testLayout->count(), 0);
171
172 // Another widget inserted at current index.
173 // Current index should become current index + 1, but the
174 // current widget should stay the same
175 testLayout->addWidget(w: w1);
176 QCOMPARE(testLayout->currentIndex(), 0);
177 QCOMPARE(testLayout->currentWidget(), w1);
178 testLayout->insertWidget(index: 0, w: w2);
179 QCOMPARE(testLayout->currentIndex(), 1);
180 QCOMPARE(testLayout->currentWidget(), w1);
181 QVERIFY(w1->isVisible());
182 QVERIFY(!w2->isVisible());
183
184 testLayout->setCurrentWidget(w2);
185 // Another widget added, so we have: w2, w1, w3 with w2 current
186 QWidget *w3 = new QWidget(testWidget);
187 testLayout->addWidget(w: w3);
188 QCOMPARE(testLayout->indexOf(w2), 0);
189 QCOMPARE(testLayout->indexOf(w1), 1);
190 QCOMPARE(testLayout->indexOf(w3), 2);
191
192 // Set index to 1 and remove that widget (w1).
193 // Then, current index should still be 1, but w3
194 // should be the new current widget.
195 testLayout->setCurrentIndex(1);
196 testLayout->removeWidget(w: w1);
197 QCOMPARE(testLayout->currentIndex(), 1);
198 QCOMPARE(testLayout->currentWidget(), w3);
199 QVERIFY(w3->isVisible());
200
201 // Remove the current widget (w3).
202 // Since it's the last one in the list, current index should now
203 // become 0 and w2 becomes the current widget.
204 testLayout->removeWidget(w: w3);
205 QCOMPARE(testLayout->currentIndex(), 0);
206 QCOMPARE(testLayout->currentWidget(), w2);
207 QVERIFY(w2->isVisible());
208
209 // Make sure index is decremented when we remove a widget at index < current index
210 testLayout->addWidget(w: w1);
211 testLayout->addWidget(w: w3);
212 testLayout->setCurrentIndex(2);
213 testLayout->removeWidget(w: w2); // At index 0
214 QCOMPARE(testLayout->currentIndex(), 1);
215 QCOMPARE(testLayout->currentWidget(), w3);
216 QVERIFY(w3->isVisible());
217 testLayout->removeWidget(w: w1); // At index 0
218 QCOMPARE(testLayout->currentIndex(), 0);
219 QCOMPARE(testLayout->currentWidget(), w3);
220 QVERIFY(w3->isVisible());
221 testLayout->removeWidget(w: w3);
222 QCOMPARE(testLayout->currentIndex(), -1);
223 QCOMPARE(testLayout->currentWidget(), nullptr);
224}
225
226void tst_QStackedLayout::deleteCurrent()
227{
228 QStackedLayout *testLayout = new QStackedLayout(testWidget);
229
230 QWidget *w1 = new QWidget;
231 testLayout->addWidget(w: w1);
232 QWidget *w2 = new QWidget;
233 testLayout->addWidget(w: w2);
234 QCOMPARE(testLayout->currentWidget(), w1);
235 delete testLayout->currentWidget();
236 QCOMPARE(testLayout->currentWidget(), w2);
237}
238
239void tst_QStackedLayout::removeWidget()
240{
241 if (testWidget->layout()) delete testWidget->layout();
242 QVBoxLayout *vbox = new QVBoxLayout(testWidget);
243
244 QPushButton *top = new QPushButton("top", testWidget); //add another widget that can receive focus
245 top->setObjectName("top");
246 vbox->addWidget(top);
247
248 QStackedLayout *testLayout = new QStackedLayout();
249 QPushButton *w1 = new QPushButton("1st", testWidget);
250 w1->setObjectName("1st");
251 testLayout->addWidget(w: w1);
252 QPushButton *w2 = new QPushButton("2nd", testWidget);
253 w2->setObjectName("2nd");
254 testLayout->addWidget(w: w2);
255 vbox->addLayout(layout: testLayout);
256 top->setFocus();
257 top->activateWindow();
258 QTRY_COMPARE(QApplication::focusWidget(), top);
259
260 // focus should stay at the 'top' widget
261 testLayout->removeWidget(w: w1);
262
263 QCOMPARE(QApplication::focusWidget(), top);
264}
265
266class LineEdit : public QLineEdit
267{
268public:
269 LineEdit() : hasFakeEditFocus(false)
270 { }
271
272 bool hasFakeEditFocus;
273
274protected:
275 bool isSingleFocusWidget() const
276 {
277 const QWidget *w = this;
278 while ((w = w->nextInFocusChain()) != this) {
279 if (w->isVisible() && static_cast<const QWidget*>(w->focusProxy()) != this
280 && w->focusPolicy() & Qt::TabFocus) {
281 return false;
282 }
283 }
284 return true;
285 }
286
287 void focusInEvent(QFocusEvent *event)
288 {
289 QLineEdit::focusInEvent(event);
290 hasFakeEditFocus = isSingleFocusWidget();
291 }
292
293 void focusOutEvent(QFocusEvent *event)
294 {
295 hasFakeEditFocus = false;
296 QLineEdit::focusOutEvent(event);
297 }
298};
299
300void tst_QStackedLayout::keepFocusAfterSetCurrent()
301{
302 if (testWidget->layout()) delete testWidget->layout();
303 QStackedLayout *stackLayout = new QStackedLayout(testWidget);
304 testWidget->setFocusPolicy(Qt::NoFocus);
305
306 LineEdit *edit1 = new LineEdit;
307 LineEdit *edit2 = new LineEdit;
308 stackLayout->addWidget(w: edit1);
309 stackLayout->addWidget(w: edit2);
310
311 stackLayout->setCurrentIndex(0);
312
313 testWidget->show();
314 QApplication::setActiveWindow(testWidget);
315 QVERIFY(QTest::qWaitForWindowActive(testWidget));
316
317 edit1->setFocus();
318 edit1->activateWindow();
319
320 QTRY_VERIFY(edit1->hasFocus());
321
322 stackLayout->setCurrentIndex(1);
323 QVERIFY(!edit1->hasFocus());
324 QVERIFY(edit2->hasFocus());
325 QVERIFY(edit2->hasFakeEditFocus);
326}
327
328void tst_QStackedLayout::heigthForWidth()
329{
330 if (testWidget->layout()) delete testWidget->layout();
331 QStackedLayout *stackLayout = new QStackedLayout(testWidget);
332
333 QLabel *shortLabel = new QLabel("This is a short text.");
334 shortLabel->setWordWrap(true);
335 stackLayout->addWidget(w: shortLabel);
336
337 QLabel *longLabel = new QLabel("Write code once to target multiple platforms\n"
338 "Qt allows you to write advanced applications and UIs once, "
339 "and deploy them across desktop and embedded operating systems "
340 "without rewriting the source code saving time and development cost.\n\n"
341 "Create amazing user experiences\n"
342 "Whether you prefer C++ or JavaScript, Qt provides the building blocks - "
343 "a broad set of customizable widgets, graphics canvas, style engine "
344 "and more that you need to build modern user interfaces. "
345 "Incorporate 3D graphics, multimedia audio or video, visual effects, "
346 "and animations to set your application apart from the competition.");
347
348 longLabel->setWordWrap(true);
349 stackLayout->addWidget(w: longLabel);
350 stackLayout->setCurrentIndex(0);
351 int hfw_index0 = stackLayout->heightForWidth(width: 200);
352
353 stackLayout->setCurrentIndex(1);
354 QCOMPARE(stackLayout->heightForWidth(200), hfw_index0);
355
356}
357
358void tst_QStackedLayout::replaceWidget()
359{
360 QWidget w;
361 QStackedLayout *stackLayout = new QStackedLayout(&w);
362
363 QLineEdit *replaceFrom = new QLineEdit;
364 QLineEdit *replaceTo = new QLineEdit;
365 stackLayout->addWidget(w: new QLineEdit());
366 stackLayout->addWidget(w: replaceFrom);
367 stackLayout->addWidget(w: new QLineEdit());
368 stackLayout->setCurrentWidget(replaceFrom);
369
370 QCOMPARE(stackLayout->indexOf(replaceFrom), 1);
371 QCOMPARE(stackLayout->indexOf(replaceTo), -1);
372 delete stackLayout->replaceWidget(from: replaceFrom, to: replaceTo);
373
374 QCOMPARE(stackLayout->indexOf(replaceFrom), -1);
375 QCOMPARE(stackLayout->indexOf(replaceTo), 1);
376 QCOMPARE(stackLayout->currentWidget(), replaceTo);
377}
378
379QTEST_MAIN(tst_QStackedLayout)
380#include "tst_qstackedlayout.moc"
381
382

source code of qtbase/tests/auto/widgets/kernel/qstackedlayout/tst_qstackedlayout.cpp