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 <qtoolbutton.h>
35#include <qmenu.h>
36#include <qaction.h>
37#include <qstyleoption.h>
38#include <qscreen.h>
39#include <qlabel.h>
40
41class tst_QToolButton : public QObject
42{
43Q_OBJECT
44
45public:
46 tst_QToolButton();
47 virtual ~tst_QToolButton();
48
49private slots:
50 void getSetCheck();
51 void triggered();
52 void collapseTextOnPriority();
53 void task230994_iconSize();
54 void task176137_autoRepeatOfAction();
55 void qtbug_26956_popupTimerDone();
56 void qtbug_34759_sizeHintResetWhenSettingMenu();
57
58protected slots:
59 void sendMouseClick();
60private:
61 QPointer<QWidget> m_menu;
62};
63
64tst_QToolButton::tst_QToolButton()
65{
66}
67
68tst_QToolButton::~tst_QToolButton()
69{
70}
71
72// Testing get/set functions
73void tst_QToolButton::getSetCheck()
74{
75 QToolButton obj1;
76 // QMenu* QToolButton::menu()
77 // void QToolButton::setMenu(QMenu*)
78 QMenu *var1 = new QMenu;
79 obj1.setMenu(var1);
80 QCOMPARE(var1, obj1.menu());
81 obj1.setMenu((QMenu *)0);
82 QCOMPARE((QMenu *)0, obj1.menu());
83 delete var1;
84
85 // ToolButtonPopupMode QToolButton::popupMode()
86 // void QToolButton::setPopupMode(ToolButtonPopupMode)
87 obj1.setPopupMode(QToolButton::ToolButtonPopupMode(QToolButton::DelayedPopup));
88 QCOMPARE(QToolButton::ToolButtonPopupMode(QToolButton::DelayedPopup), obj1.popupMode());
89 obj1.setPopupMode(QToolButton::ToolButtonPopupMode(QToolButton::MenuButtonPopup));
90 QCOMPARE(QToolButton::ToolButtonPopupMode(QToolButton::MenuButtonPopup), obj1.popupMode());
91 obj1.setPopupMode(QToolButton::ToolButtonPopupMode(QToolButton::InstantPopup));
92 QCOMPARE(QToolButton::ToolButtonPopupMode(QToolButton::InstantPopup), obj1.popupMode());
93
94 // bool QToolButton::autoRaise()
95 // void QToolButton::setAutoRaise(bool)
96 obj1.setAutoRaise(false);
97 QCOMPARE(false, obj1.autoRaise());
98 obj1.setAutoRaise(true);
99 QCOMPARE(true, obj1.autoRaise());
100
101 // QAction * QToolButton::defaultAction()
102 // void QToolButton::setDefaultAction(QAction *)
103 QAction *var4 = new QAction(0);
104 obj1.setDefaultAction(var4);
105 QCOMPARE(var4, obj1.defaultAction());
106 obj1.setDefaultAction((QAction *)0);
107 QCOMPARE((QAction *)0, obj1.defaultAction());
108 delete var4;
109}
110
111void tst_QToolButton::triggered()
112{
113 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
114 QSKIP("Wayland: This fails. Figure out why.");
115
116 qRegisterMetaType<QAction *>(typeName: "QAction *");
117 QWidget mainWidget;
118 mainWidget.setWindowTitle(QStringLiteral("triggered"));
119 mainWidget.resize(w: 200, h: 200);
120 mainWidget.move(QGuiApplication::primaryScreen()->availableGeometry().center() - QPoint(100, 100));
121 QToolButton *toolButton = new QToolButton(&mainWidget);
122 QSignalSpy spy(toolButton,SIGNAL(triggered(QAction*)));
123 QScopedPointer<QMenu> menu(new QMenu(QStringLiteral("Menu")));
124 QAction *one = menu->addAction(text: "one");
125 menu->addAction(text: "two");
126 QAction *defaultAction = new QAction(QStringLiteral("def"), this);
127
128 toolButton->setMenu(menu.data());
129 toolButton->setDefaultAction(defaultAction);
130
131 mainWidget.show();
132 QApplication::setActiveWindow(&mainWidget);
133 QVERIFY(QTest::qWaitForWindowActive(&mainWidget));
134
135 defaultAction->trigger();
136 QCOMPARE(spy.count(),1);
137 QCOMPARE(qvariant_cast<QAction *>(spy.at(0).at(0)), defaultAction);
138
139 m_menu = menu.data();
140
141 QTimer *timer = new QTimer(this);
142 timer->setInterval(50);
143 connect(sender: timer, SIGNAL(timeout()), receiver: this, SLOT(sendMouseClick()));
144 timer->start();
145 QTimer::singleShot(msec: 10000, receiver: &mainWidget, SLOT(close())); // Emergency bail-out
146 toolButton->showMenu();
147 QTRY_COMPARE(spy.count(),2);
148 QCOMPARE(qvariant_cast<QAction *>(spy.at(1).at(0)), one);
149}
150
151void tst_QToolButton::collapseTextOnPriority()
152{
153 class MyToolButton : public QToolButton
154 {
155 friend class tst_QToolButton;
156 public:
157 void initStyleOption(QStyleOptionToolButton *option)
158 {
159 QToolButton::initStyleOption(option);
160 }
161 };
162
163 MyToolButton button;
164 button.setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
165 QAction action(button.style()->standardIcon(standardIcon: QStyle::SP_ArrowBack), "test", 0);
166 button.setDefaultAction(&action);
167
168 QStyleOptionToolButton option;
169 button.initStyleOption(option: &option);
170 QCOMPARE(option.toolButtonStyle, Qt::ToolButtonTextBesideIcon);
171 action.setPriority(QAction::LowPriority);
172 button.initStyleOption(option: &option);
173 QCOMPARE(option.toolButtonStyle, Qt::ToolButtonIconOnly);
174}
175
176
177void tst_QToolButton::task230994_iconSize()
178{
179 //we check that the iconsize returned bu initStyleOption is valid
180 //when the toolbutton has no parent
181 class MyToolButton : public QToolButton
182 {
183 friend class tst_QToolButton;
184 public:
185 void initStyleOption(QStyleOptionToolButton *option)
186 {
187 QToolButton::initStyleOption(option);
188 }
189 };
190
191 MyToolButton button;
192 QStyleOptionToolButton option;
193 button.initStyleOption(option: &option);
194 QVERIFY(option.iconSize.isValid());
195}
196
197void tst_QToolButton::task176137_autoRepeatOfAction()
198{
199 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
200 QSKIP("Wayland: This fails. Figure out why.");
201
202 QAction action(0);
203 QWidget mainWidget;
204 mainWidget.setWindowTitle(QStringLiteral("task176137_autoRepeatOfAction"));
205 mainWidget.resize(w: 200, h: 200);
206 mainWidget.move(QGuiApplication::primaryScreen()->availableGeometry().center() - QPoint(100, 100));
207 QToolButton *toolButton = new QToolButton(&mainWidget);
208 toolButton->setDefaultAction (&action);
209 QLabel *label = new QLabel(QStringLiteral("This test takes a while."), &mainWidget);
210 label->move(ax: 0, ay: 50);
211
212 mainWidget.show();
213 QApplication::setActiveWindow(&mainWidget);
214 QVERIFY(QTest::qWaitForWindowActive(&mainWidget));
215
216 QSignalSpy spy(&action,SIGNAL(triggered()));
217 QTest::mousePress (widget: toolButton, button: Qt::LeftButton);
218 QTest::mouseRelease (widget: toolButton, button: Qt::LeftButton, stateKey: {}, pos: QPoint (), delay: 2000);
219 QCOMPARE(spy.count(),1);
220
221 // try again with auto repeat
222 toolButton->setAutoRepeat (true);
223 QSignalSpy repeatSpy(&action,SIGNAL(triggered())); // new spy
224 QTest::mousePress (widget: toolButton, button: Qt::LeftButton);
225 QTest::mouseRelease (widget: toolButton, button: Qt::LeftButton, stateKey: {}, pos: QPoint (), delay: 3000);
226 const qreal expected = (3000 - toolButton->autoRepeatDelay()) / toolButton->autoRepeatInterval() + 1;
227 //we check that the difference is small (on some systems timers are not super accurate)
228 qreal diff = (expected - repeatSpy.count()) / expected;
229 QVERIFY2(qAbs(diff) < 0.2, qPrintable(
230 QString("expected: %1, actual: %2, diff (fraction): %3")
231 .arg(expected)
232 .arg(repeatSpy.count())
233 .arg(diff)));
234}
235
236
237void tst_QToolButton::sendMouseClick()
238{
239 if (m_menu.isNull()) {
240 qWarning(msg: "m_menu is NULL");
241 return;
242 }
243 if (!m_menu->isVisible())
244 return;
245 QTest::mouseClick(widget: m_menu.data(), button: Qt::LeftButton, stateKey: {}, pos: QPoint(7, 7));
246 if (QTimer *timer = qobject_cast<QTimer *>(object: sender())) {
247 timer->stop();
248 timer->deleteLater();
249 }
250}
251
252void tst_QToolButton::qtbug_26956_popupTimerDone()
253{
254 QToolButton *tb = new QToolButton;
255 tb->setMenu(new QMenu(tb));
256 tb->menu()->addAction(text: "Qt");
257 tb->deleteLater();
258 tb->showMenu();
259}
260
261void tst_QToolButton::qtbug_34759_sizeHintResetWhenSettingMenu()
262{
263 // There is no reliable way of checking what's ultimately a style-dependent
264 // sizing. So the idea is checking if the size is the "correct" size w.r.t.
265 // another toolbutton which has had a menu set before it was shown for the first time
266
267 QToolButton button1;
268 QToolButton button2;
269
270 button1.setToolButtonStyle(Qt::ToolButtonIconOnly);
271 button1.setPopupMode(QToolButton::MenuButtonPopup);
272
273 button2.setToolButtonStyle(Qt::ToolButtonIconOnly);
274 button2.setPopupMode(QToolButton::MenuButtonPopup);
275
276 button2.setMenu(new QMenu(&button2));
277
278 button1.show();
279 button2.show();
280
281#ifdef Q_OS_WINRT
282 QEXPECT_FAIL("", "Winrt does not support more than 1 native top level widget.", Abort);
283#endif
284 QVERIFY(QTest::qWaitForWindowExposed(&button1));
285 QVERIFY(QTest::qWaitForWindowExposed(&button2));
286
287 button1.setMenu(new QMenu(&button1));
288 QTRY_COMPARE(button1.sizeHint(), button2.sizeHint());
289}
290
291QTEST_MAIN(tst_QToolButton)
292#include "tst_qtoolbutton.moc"
293

source code of qtbase/tests/auto/widgets/widgets/qtoolbutton/tst_qtoolbutton.cpp