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 <qfont.h>
32#include <qfontmetrics.h>
33#include <qtooltip.h>
34#include <qwhatsthis.h>
35#include <qscreen.h>
36
37class tst_QToolTip : public QObject
38{
39 Q_OBJECT
40
41private slots:
42 void init();
43 void cleanup();
44 void task183679_data();
45 void task183679();
46 void whatsThis();
47 void setPalette();
48 void qtbug64550_stylesheet();
49 void dontCrashOutsideScreenGeometry();
50};
51
52void tst_QToolTip::init()
53{
54 QVERIFY(!QToolTip::isVisible());
55}
56
57void tst_QToolTip::cleanup()
58{
59 QTRY_VERIFY(QApplication::topLevelWidgets().isEmpty());
60 qApp->setStyleSheet(QString());
61}
62
63class Widget_task183679 : public QWidget
64{
65 Q_OBJECT
66public:
67 Widget_task183679(QWidget *parent = 0) : QWidget(parent) {}
68
69 void showDelayedToolTip(int msecs)
70 {
71 QTimer::singleShot(msec: msecs, receiver: this, SLOT(showToolTip()));
72 }
73
74 static inline QString toolTipText() { return QStringLiteral("tool tip text"); }
75
76private slots:
77 void showToolTip()
78 {
79 QToolTip::showText(pos: mapToGlobal(QPoint(0, 0)), text: Widget_task183679::toolTipText(), w: this);
80 }
81};
82
83Q_DECLARE_METATYPE(Qt::Key)
84
85void tst_QToolTip::task183679_data()
86{
87 QTest::addColumn<Qt::Key>(name: "key");
88 QTest::addColumn<bool>(name: "visible");
89
90 QTest::newRow(dataTag: "non-modifier") << Qt::Key_A << true;
91 QTest::newRow(dataTag: "Shift") << Qt::Key_Shift << true;
92 QTest::newRow(dataTag: "Control") << Qt::Key_Control << true;
93 QTest::newRow(dataTag: "Alt") << Qt::Key_Alt << true;
94 QTest::newRow(dataTag: "Meta") << Qt::Key_Meta << true;
95}
96
97void tst_QToolTip::task183679()
98{
99 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
100 QSKIP("Wayland: This fails. Figure out why.");
101
102 QFETCH(Qt::Key, key);
103 QFETCH(bool, visible);
104
105#ifdef Q_OS_MAC
106 QSKIP("This test fails in the CI system, QTBUG-30040");
107#endif
108
109 Widget_task183679 widget;
110 widget.move(QGuiApplication::primaryScreen()->availableGeometry().topLeft() + QPoint(50, 50));
111 // Ensure cursor is not over tooltip, which causes it to hide
112#ifndef QT_NO_CURSOR
113 QCursor::setPos(widget.geometry().topRight() + QPoint(-50, 50));
114#endif
115 widget.setWindowTitle(QLatin1String(QTest::currentTestFunction())
116 + QLatin1Char(' ') + QLatin1String(QTest::currentDataTag()));
117 widget.show();
118 QApplication::setActiveWindow(&widget);
119 QVERIFY(QTest::qWaitForWindowActive(&widget));
120
121 widget.showDelayedToolTip(msecs: 100);
122 QTRY_VERIFY(QToolTip::isVisible());
123
124 QTest::keyPress(widget: &widget, key);
125
126 // Important: the following delay must be larger than the duration of the timer potentially
127 // initiated by the key press (currently 300 msecs), but smaller than the minimum
128 // auto-close timeout (currently 10000 msecs)
129 QTest::qWait(ms: 1500);
130
131 QCOMPARE(QToolTip::isVisible(), visible);
132 if (visible)
133 QToolTip::hideText();
134}
135
136static QWidget *findWhatsThat()
137{
138 foreach (QWidget *widget, QApplication::topLevelWidgets()) {
139 if (widget->inherits(classname: "QWhatsThat"))
140 return widget;
141 }
142 return nullptr;
143}
144
145void tst_QToolTip::whatsThis()
146{
147 qApp->setStyleSheet( "QWidget { font-size: 72px; }" );
148 QWhatsThis::showText(pos: QPoint(0, 0), text: "This is text");
149
150 QWidget *whatsthis = nullptr;
151 QTRY_VERIFY( (whatsthis = findWhatsThat()) );
152 QVERIFY(whatsthis->isVisible());
153 const int whatsThisHeight = whatsthis->height();
154 qApp->setStyleSheet(QString());
155 QWhatsThis::hideText();
156 QVERIFY2(whatsThisHeight > 100, QByteArray::number(whatsThisHeight)); // Test QTBUG-2416
157}
158
159static QWidget *findToolTip()
160{
161 const QWidgetList &topLevelWidgets = QApplication::topLevelWidgets();
162 for (QWidget *widget : topLevelWidgets) {
163 if (widget->windowType() == Qt::ToolTip && widget->objectName() == QLatin1String("qtooltip_label"))
164 return widget;
165 }
166 return nullptr;
167}
168
169void tst_QToolTip::setPalette()
170{
171 //the previous test may still have a tooltip pending for deletion
172 QVERIFY(!QToolTip::isVisible());
173
174 QToolTip::showText(pos: QPoint(), text: "tool tip text", w: 0);
175
176 QTRY_VERIFY(QToolTip::isVisible());
177
178 QWidget *toolTip = findToolTip();
179 QVERIFY(toolTip);
180 QTRY_VERIFY(toolTip->isVisible());
181
182 const QPalette oldPalette = toolTip->palette();
183 QPalette newPalette = oldPalette;
184 newPalette.setColor(acr: QPalette::ToolTipBase, acolor: Qt::red);
185 newPalette.setColor(acr: QPalette::ToolTipText, acolor: Qt::blue);
186 QToolTip::setPalette(newPalette);
187 QCOMPARE(toolTip->palette(), newPalette);
188 QToolTip::hideText();
189}
190
191static QByteArray msgSizeTooSmall(const QSize &actual, const QSize &expected)
192{
193 return QByteArray::number(actual.width()) + 'x'
194 + QByteArray::number(actual.height()) + " < "
195 + QByteArray::number(expected.width()) + 'x'
196 + QByteArray::number(expected.height());
197}
198
199// QTBUG-4550: When setting a style sheet specifying a font size on the tooltip's
200// parent widget (as opposed to setting on QApplication), the tooltip should
201// resize accordingly. This is an issue on Windows since the ToolTip widget is
202// not directly parented on the widget itself.
203// Set a large font size and verify that the tool tip is big enough.
204void tst_QToolTip::qtbug64550_stylesheet()
205{
206 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
207 QSKIP("Wayland: This fails. Figure out why.");
208
209 Widget_task183679 widget;
210 widget.setStyleSheet(QStringLiteral("* { font-size: 48pt; }\n"));
211 widget.show();
212 QApplication::setActiveWindow(&widget);
213 QVERIFY(QTest::qWaitForWindowActive(&widget));
214
215 widget.showDelayedToolTip(msecs: 100);
216 QTRY_VERIFY(QToolTip::isVisible());
217 QWidget *toolTip = findToolTip();
218 QVERIFY(toolTip);
219 QTRY_VERIFY(toolTip->isVisible());
220
221 const QRect boundingRect = QFontMetrics(widget.font()).boundingRect(text: Widget_task183679::toolTipText());
222 const QSize toolTipSize = toolTip->size();
223 QVERIFY2(toolTipSize.width() >= boundingRect.width()
224 && toolTipSize.height() >= boundingRect.height(),
225 msgSizeTooSmall(toolTipSize, boundingRect.size()).constData());
226}
227
228void tst_QToolTip::dontCrashOutsideScreenGeometry() {
229 QToolTip::showText(pos: QPoint(-10000, -10000), text: "tip outside monitor", w: nullptr);
230 QTRY_VERIFY(QToolTip::isVisible());
231 QToolTip::hideText();
232}
233
234QTEST_MAIN(tst_QToolTip)
235#include "tst_qtooltip.moc"
236

source code of qtbase/tests/auto/widgets/kernel/qtooltip/tst_qtooltip.cpp