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
32#include <qcoreapplication.h>
33#include <qdebug.h>
34#include <qscrollarea.h>
35#include <qlayout.h>
36#include <qscrollbar.h>
37
38class tst_QScrollArea : public QObject
39{
40Q_OBJECT
41
42public:
43 tst_QScrollArea();
44 virtual ~tst_QScrollArea();
45
46private slots:
47 void getSetCheck();
48 void ensureMicroFocusVisible_Task_167838();
49 void checkHFW_Task_197736();
50 void stableHeightForWidth();
51};
52
53tst_QScrollArea::tst_QScrollArea()
54{
55}
56
57tst_QScrollArea::~tst_QScrollArea()
58{
59}
60
61// Testing get/set functions
62void tst_QScrollArea::getSetCheck()
63{
64 QScrollArea obj1;
65 // QWidget * QScrollArea::widget()
66 // void QScrollArea::setWidget(QWidget *)
67 QWidget *var1 = new QWidget();
68 obj1.setWidget(var1);
69 QCOMPARE(var1, obj1.widget());
70 obj1.setWidget((QWidget *)0);
71 QCOMPARE(var1, obj1.widget()); // Cannot set a 0-widget. Old widget returned
72 // delete var1; // No delete, since QScrollArea takes ownership
73
74 // bool QScrollArea::widgetResizable()
75 // void QScrollArea::setWidgetResizable(bool)
76 obj1.setWidgetResizable(false);
77 QCOMPARE(false, obj1.widgetResizable());
78 obj1.setWidgetResizable(true);
79 QCOMPARE(true, obj1.widgetResizable());
80}
81
82class WidgetWithMicroFocus : public QWidget
83{
84public:
85 WidgetWithMicroFocus(QWidget *parent = 0) : QWidget(parent)
86 {
87 setBackgroundRole(QPalette::Dark);
88 }
89protected:
90 QVariant inputMethodQuery(Qt::InputMethodQuery query) const
91 {
92 if (query == Qt::ImCursorRectangle)
93 return QRect(width() / 2, height() / 2, 5, 5);
94 return QWidget::inputMethodQuery(query);
95 }
96// void paintEvent(QPaintEvent *event)
97// {
98// QPainter painter(this);
99// painter.fillRect(rect(), QBrush(Qt::red));
100// }
101};
102
103void tst_QScrollArea::ensureMicroFocusVisible_Task_167838()
104{
105 QScrollArea scrollArea;
106 scrollArea.resize(w: 100, h: 100);
107 scrollArea.show();
108 QWidget *parent = new QWidget;
109 parent->setLayout(new QVBoxLayout);
110 QWidget *child = new WidgetWithMicroFocus;
111 parent->layout()->addWidget(w: child);
112 parent->resize(w: 300, h: 300);
113 scrollArea.setWidget(parent);
114 scrollArea.ensureWidgetVisible(childWidget: child, xmargin: 10, ymargin: 10);
115 QRect microFocus = child->inputMethodQuery(Qt::ImCursorRectangle).toRect();
116 QPoint p = child->mapTo(scrollArea.viewport(), microFocus.topLeft());
117 microFocus.translate(p: p - microFocus.topLeft());
118 QVERIFY(scrollArea.viewport()->rect().contains(microFocus));
119}
120
121class HFWWidget : public QWidget
122{
123 public:
124 HFWWidget();
125 int heightForWidth(int w) const;
126};
127
128HFWWidget::HFWWidget()
129 : QWidget()
130{
131 setMinimumSize(QSize(100,50));
132 QSizePolicy s = sizePolicy();
133 s.setHeightForWidth(true);
134 setSizePolicy(s);
135}
136
137int HFWWidget::heightForWidth(int w) const
138{
139 // Mimic a label - the narrower we are, the taller we have to be
140 if (w > 0)
141 return 40000 / w;
142 else
143 return 40000;
144}
145
146void tst_QScrollArea::checkHFW_Task_197736()
147{
148 QScrollArea scrollArea;
149 HFWWidget *w = new HFWWidget;
150 scrollArea.resize(w: 200,h: 100);
151 scrollArea.show();
152 scrollArea.setWidgetResizable(true);
153 scrollArea.setWidget(w);
154
155 // at 200x100px, we expect HFW to be 200px tall, not 100px
156 QVERIFY(w->height() >= 200);
157
158 // at 200x300px, we expect HFW to be 300px tall (the heightForWidth is a min, not prescribed)
159 scrollArea.resize(QSize(200, 300));
160 QVERIFY(w->height() >= 250); // 50px for a fudge factor (size of frame margins/scrollbars etc)
161
162 // make sure this only happens with widget resizable
163 scrollArea.setWidgetResizable(false);
164 scrollArea.resize(QSize(100,100));
165 w->resize(QSize(200,200));
166 QCOMPARE(w->width(), 200);
167 QCOMPARE(w->height(), 200);
168}
169
170
171/*
172 If the scroll area rides the size where, due to the height-for-width
173 implementation of the widget, the vertical scrollbar is needed only
174 if the vertical scrollbar is visible, then we don't want it to flip
175 back and forth, but rather constrain the width of the widget.
176 See QTBUG-92958.
177*/
178void tst_QScrollArea::stableHeightForWidth()
179{
180 struct HeightForWidthWidget : public QWidget
181 {
182 HeightForWidthWidget()
183 {
184 QSizePolicy policy = sizePolicy();
185 policy.setHeightForWidth(true);
186 setSizePolicy(policy);
187 }
188 // Aspect ratio 1:1
189 int heightForWidth(int width) const override { return width; }
190 };
191
192 class HeightForWidthArea : public QScrollArea
193 {
194 public:
195 HeightForWidthArea()
196 {
197 this->verticalScrollBar()->installEventFilter(filterObj: this);
198 }
199 protected:
200 bool eventFilter(QObject *obj, QEvent *e) override
201 {
202 if (obj == verticalScrollBar() && e->type() == QEvent::Hide)
203 ++m_hideCount;
204 return QScrollArea::eventFilter(obj,e);
205 }
206 public:
207 int m_hideCount = 0;
208 };
209
210 HeightForWidthArea area;
211 HeightForWidthWidget equalWHWidget;
212 area.setWidget(&equalWHWidget);
213 area.setWidgetResizable(true);
214 // at this size, the widget wants to be 501 pixels high,
215 // requiring a vertical scrollbar in a 499 pixel high area.
216 // but the width resulting from showing the scrollbar would
217 // be less than 499, so no scrollbars would be needed anymore.
218 area.resize(w: 501, h: 499);
219 area.show();
220 QTest::qWait(ms: 500);
221 // if the scrollbar got hidden more than once, then the layout
222 // isn't stable.
223 QVERIFY(area.m_hideCount <= 1);
224}
225
226QTEST_MAIN(tst_QScrollArea)
227#include "tst_qscrollarea.moc"
228

source code of qtbase/tests/auto/widgets/widgets/qscrollarea/tst_qscrollarea.cpp