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
31#include <QtTest/QtTest>
32
33
34#include <qaction.h>
35#include <qdockwidget.h>
36#include <qmainwindow.h>
37#include <qlineedit.h>
38#include <qtabbar.h>
39#include <QScreen>
40#include <QtGui/QPainter>
41#include "private/qdockwidget_p.h"
42
43bool hasFeature(QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature)
44{ return (dockwidget->features() & feature) == feature; }
45
46void setFeature(QDockWidget *dockwidget, QDockWidget::DockWidgetFeature feature, bool on = true)
47{
48 const QDockWidget::DockWidgetFeatures features = dockwidget->features();
49 dockwidget->setFeatures(on ? features | feature : features & ~feature);
50}
51
52class tst_QDockWidget : public QObject
53{
54 Q_OBJECT
55
56public:
57 tst_QDockWidget();
58
59private slots:
60 void getSetCheck();
61 void widget();
62 void features();
63 void setFloating();
64 void allowedAreas();
65 void toggleViewAction();
66 void visibilityChanged();
67 void updateTabBarOnVisibilityChanged();
68 void dockLocationChanged();
69 void setTitleBarWidget();
70 void titleBarDoubleClick();
71 void restoreStateOfFloating();
72 void restoreDockWidget();
73 void restoreStateWhileStillFloating();
74 void setWindowTitle();
75 // task specific tests:
76 void task165177_deleteFocusWidget();
77 void task169808_setFloating();
78 void task237438_setFloatingCrash();
79 void task248604_infiniteResize();
80 void task258459_visibilityChanged();
81 void taskQTBUG_1665_closableChanged();
82 void taskQTBUG_9758_undockedGeometry();
83};
84
85// Testing get/set functions
86void tst_QDockWidget::getSetCheck()
87{
88 QDockWidget obj1;
89 // QWidget * QDockWidget::widget()
90 // void QDockWidget::setWidget(QWidget *)
91 QWidget *var1 = new QWidget();
92 obj1.setWidget(var1);
93 QCOMPARE(var1, obj1.widget());
94 obj1.setWidget((QWidget *)0);
95 QCOMPARE((QWidget *)0, obj1.widget());
96 delete var1;
97
98 // DockWidgetFeatures QDockWidget::features()
99 // void QDockWidget::setFeatures(DockWidgetFeatures)
100 obj1.setFeatures(QDockWidget::DockWidgetFeatures(QDockWidget::DockWidgetClosable));
101 QCOMPARE(QDockWidget::DockWidgetFeatures(QDockWidget::DockWidgetClosable), obj1.features());
102 obj1.setFeatures(QDockWidget::DockWidgetFeatures(QDockWidget::DockWidgetMovable));
103 QCOMPARE(QDockWidget::DockWidgetFeatures(QDockWidget::DockWidgetMovable), obj1.features());
104 obj1.setFeatures(QDockWidget::DockWidgetFeatures(QDockWidget::DockWidgetFloatable));
105 QCOMPARE(QDockWidget::DockWidgetFeatures(QDockWidget::DockWidgetFloatable), obj1.features());
106 obj1.setFeatures(QDockWidget::DockWidgetFeatures(QDockWidget::AllDockWidgetFeatures));
107 QCOMPARE(QDockWidget::DockWidgetFeatures(QDockWidget::AllDockWidgetFeatures), obj1.features());
108 obj1.setFeatures(QDockWidget::DockWidgetFeatures(QDockWidget::NoDockWidgetFeatures));
109 QCOMPARE(QDockWidget::DockWidgetFeatures(QDockWidget::NoDockWidgetFeatures), obj1.features());
110}
111
112tst_QDockWidget::tst_QDockWidget()
113{
114 qRegisterMetaType<QDockWidget::DockWidgetFeatures>(typeName: "QDockWidget::DockWidgetFeatures");
115 qRegisterMetaType<Qt::DockWidgetAreas>(typeName: "Qt::DockWidgetAreas");
116}
117
118void tst_QDockWidget::widget()
119{
120 {
121 QDockWidget dw;
122 QVERIFY(!dw.widget());
123 }
124
125 {
126 QDockWidget dw;
127 QWidget *w1 = new QWidget;
128 QWidget *w2 = new QWidget;
129
130 dw.setWidget(w1);
131 QVERIFY(dw.widget() != 0);
132 QCOMPARE(dw.widget(), w1);
133 QCOMPARE(w1->parentWidget(), (QWidget*)&dw);
134
135 dw.setWidget(0);
136 QVERIFY(!dw.widget());
137
138 dw.setWidget(w2);
139 QVERIFY(dw.widget() != 0);
140 QCOMPARE(dw.widget(), w2);
141 QCOMPARE(w2->parentWidget(), (QWidget*)&dw);
142
143 dw.setWidget(0);
144 QVERIFY(!dw.widget());
145
146 dw.setWidget(w1);
147 QVERIFY(dw.widget() != 0);
148 QCOMPARE(dw.widget(), w1);
149 QCOMPARE(w1->parentWidget(), (QWidget*)&dw);
150
151 dw.setWidget(w2);
152 QVERIFY(dw.widget() != 0);
153 QCOMPARE(dw.widget(), w2);
154 QCOMPARE(w2->parentWidget(), (QWidget*)&dw);
155
156 dw.setWidget(0);
157 QVERIFY(!dw.widget());
158 }
159
160 {
161 QDockWidget dw;
162 QWidget *w1 = new QWidget;
163 QWidget *w2 = new QWidget;
164
165 dw.setWidget(w1);
166 QVERIFY(dw.widget() != 0);
167 QCOMPARE(dw.widget(), w1);
168 QCOMPARE(w1->parentWidget(), (QWidget*)&dw);
169
170 w1->setParent(0);
171 QVERIFY(!dw.widget());
172
173 dw.setWidget(w2);
174 QVERIFY(dw.widget() != 0);
175 QCOMPARE(dw.widget(), w2);
176 QCOMPARE(w2->parentWidget(), (QWidget*)&dw);
177
178 w2->setParent(0);
179 QVERIFY(!dw.widget());
180
181 dw.setWidget(w1);
182 QVERIFY(dw.widget() != 0);
183 QCOMPARE(dw.widget(), w1);
184 QCOMPARE(w1->parentWidget(), (QWidget*)&dw);
185
186 dw.setWidget(w2);
187 QVERIFY(dw.widget() != 0);
188 QCOMPARE(dw.widget(), w2);
189 QCOMPARE(w2->parentWidget(), (QWidget*)&dw);
190
191 w1->setParent(0);
192 QVERIFY(dw.widget() != 0);
193 QCOMPARE(dw.widget(), w2);
194 QCOMPARE(w2->parentWidget(), (QWidget*)&dw);
195
196 w2->setParent(0);
197 QVERIFY(!dw.widget());
198 delete w1;
199 delete w2;
200 }
201}
202
203void tst_QDockWidget::features()
204{
205 QDockWidget dw;
206
207 QSignalSpy spy(&dw, SIGNAL(featuresChanged(QDockWidget::DockWidgetFeatures)));
208
209 // default features for dock widgets
210 int allDockWidgetFeatures = QDockWidget::DockWidgetClosable |
211 QDockWidget::DockWidgetMovable |
212 QDockWidget::DockWidgetFloatable;
213
214 // defaults
215 QCOMPARE(dw.features(), allDockWidgetFeatures);
216 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable));
217 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable));
218 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable));
219
220 // test individual setting
221 setFeature(dockwidget: &dw, feature: QDockWidget::DockWidgetClosable, on: false);
222 QCOMPARE(dw.features(), QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable);
223 QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetClosable));
224 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable));
225 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable));
226 QCOMPARE(spy.count(), 1);
227 QCOMPARE((int)*(static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData())),
228 (int)dw.features());
229 spy.clear();
230 dw.setFeatures(dw.features());
231 QCOMPARE(spy.count(), 0);
232 spy.clear();
233
234 setFeature(dockwidget: &dw, feature: QDockWidget::DockWidgetClosable);
235 QCOMPARE(dw.features(), allDockWidgetFeatures);
236 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable));
237 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable));
238 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable));
239 QCOMPARE(spy.count(), 1);
240 QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()),
241 (int)dw.features());
242 spy.clear();
243 dw.setFeatures(dw.features());
244 QCOMPARE(spy.count(), 0);
245 spy.clear();
246
247 setFeature(dockwidget: &dw, feature: QDockWidget::DockWidgetMovable, on: false);
248 QCOMPARE(dw.features(), QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable);
249 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable));
250 QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetMovable));
251 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable));
252 QCOMPARE(spy.count(), 1);
253 QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()),
254 (int)dw.features());
255 spy.clear();
256 dw.setFeatures(dw.features());
257 QCOMPARE(spy.count(), 0);
258 spy.clear();
259
260 setFeature(dockwidget: &dw, feature: QDockWidget::DockWidgetMovable);
261 QCOMPARE(dw.features(), allDockWidgetFeatures);
262 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable));
263 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable));
264 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable));
265 QCOMPARE(spy.count(), 1);
266 QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()),
267 (int)dw.features());
268 spy.clear();
269 dw.setFeatures(dw.features());
270 QCOMPARE(spy.count(), 0);
271 spy.clear();
272
273 setFeature(dockwidget: &dw, feature: QDockWidget::DockWidgetFloatable, on: false);
274 QCOMPARE(dw.features(), QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
275 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable));
276 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable));
277 QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetFloatable));
278 QCOMPARE(spy.count(), 1);
279 QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()),
280 (int)dw.features());
281 spy.clear();
282 dw.setFeatures(dw.features());
283 QCOMPARE(spy.count(), 0);
284 spy.clear();
285
286 setFeature(dockwidget: &dw, feature: QDockWidget::DockWidgetFloatable);
287 QCOMPARE(dw.features(), allDockWidgetFeatures);
288 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable));
289 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable));
290 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable));
291 QCOMPARE(spy.count(), 1);
292 QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()),
293 (int)dw.features());
294 spy.clear();
295 dw.setFeatures(dw.features());
296 QCOMPARE(spy.count(), 0);
297 spy.clear();
298
299 // set all at once
300 dw.setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
301 QCOMPARE(dw.features(), QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetMovable);
302 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable));
303 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable));
304 QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetFloatable));
305 QCOMPARE(spy.count(), 1);
306 QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()),
307 (int)dw.features());
308 spy.clear();
309 dw.setFeatures(dw.features());
310 QCOMPARE(spy.count(), 0);
311 spy.clear();
312
313 dw.setFeatures(QDockWidget::DockWidgetClosable);
314 QCOMPARE(dw.features(), QDockWidget::DockWidgetClosable);
315 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable));
316 QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetMovable));
317 QVERIFY(!hasFeature(&dw, QDockWidget::DockWidgetFloatable));
318 QCOMPARE(spy.count(), 1);
319 QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()),
320 (int)dw.features());
321 spy.clear();
322 dw.setFeatures(dw.features());
323 QCOMPARE(spy.count(), 0);
324 spy.clear();
325
326 dw.setFeatures(QDockWidget::AllDockWidgetFeatures);
327 QCOMPARE(dw.features(), QDockWidget::AllDockWidgetFeatures);
328 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetClosable));
329 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetMovable));
330 QVERIFY(hasFeature(&dw, QDockWidget::DockWidgetFloatable));
331 QCOMPARE(spy.count(), 1);
332 QCOMPARE((int)*static_cast<const QDockWidget::DockWidgetFeature *>(spy.at(0).value(0).constData()),
333 (int)dw.features());
334 spy.clear();
335 dw.setFeatures(dw.features());
336 QCOMPARE(spy.count(), 0);
337 spy.clear();
338}
339
340void tst_QDockWidget::setFloating()
341{
342 const QRect deskRect = QGuiApplication::primaryScreen()->availableGeometry();
343 QMainWindow mw;
344 mw.move(ax: deskRect.left() + deskRect.width() * 2 / 3, ay: deskRect.top() + deskRect.height() / 3);
345 QDockWidget dw;
346 mw.addDockWidget(area: Qt::LeftDockWidgetArea, dockwidget: &dw);
347
348 mw.show();
349 QVERIFY(QTest::qWaitForWindowExposed(&mw));
350
351 QVERIFY(!dw.isFloating());
352 const QPoint dockedPosition = dw.mapToGlobal(dw.pos());
353
354 QSignalSpy spy(&dw, SIGNAL(topLevelChanged(bool)));
355
356 dw.setFloating(true);
357 const QPoint floatingPosition = dw.pos();
358
359 // QTBUG-31044, show approximately at old position, give or take window frame.
360 QVERIFY((dockedPosition - floatingPosition).manhattanLength() < 50);
361
362 QVERIFY(dw.isFloating());
363 QCOMPARE(spy.count(), 1);
364 QCOMPARE(spy.at(0).value(0).toBool(), dw.isFloating());
365 spy.clear();
366 dw.setFloating(dw.isFloating());
367 QCOMPARE(spy.count(), 0);
368 spy.clear();
369
370 dw.setFloating(false);
371 QVERIFY(!dw.isFloating());
372 QCOMPARE(spy.count(), 1);
373 QCOMPARE(spy.at(0).value(0).toBool(), dw.isFloating());
374 spy.clear();
375 dw.setFloating(dw.isFloating());
376 QCOMPARE(spy.count(), 0);
377 spy.clear();
378}
379
380void tst_QDockWidget::allowedAreas()
381{
382 QDockWidget dw;
383
384 QSignalSpy spy(&dw, SIGNAL(allowedAreasChanged(Qt::DockWidgetAreas)));
385
386 // default
387 QCOMPARE(dw.allowedAreas(), Qt::AllDockWidgetAreas);
388 QVERIFY(dw.isAreaAllowed(Qt::LeftDockWidgetArea));
389 QVERIFY(dw.isAreaAllowed(Qt::RightDockWidgetArea));
390 QVERIFY(dw.isAreaAllowed(Qt::TopDockWidgetArea));
391 QVERIFY(dw.isAreaAllowed(Qt::BottomDockWidgetArea));
392
393 // a single dock window area
394 dw.setAllowedAreas(Qt::LeftDockWidgetArea);
395 QCOMPARE(dw.allowedAreas(), Qt::LeftDockWidgetArea);
396 QVERIFY(dw.isAreaAllowed(Qt::LeftDockWidgetArea));
397 QVERIFY(!dw.isAreaAllowed(Qt::RightDockWidgetArea));
398 QVERIFY(!dw.isAreaAllowed(Qt::TopDockWidgetArea));
399 QVERIFY(!dw.isAreaAllowed(Qt::BottomDockWidgetArea));
400 QCOMPARE(spy.count(), 1);
401 QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()),
402 dw.allowedAreas());
403 spy.clear();
404 dw.setAllowedAreas(dw.allowedAreas());
405 QCOMPARE(spy.count(), 0);
406
407 dw.setAllowedAreas(Qt::RightDockWidgetArea);
408 QCOMPARE(dw.allowedAreas(), Qt::RightDockWidgetArea);
409 QVERIFY(!dw.isAreaAllowed(Qt::LeftDockWidgetArea));
410 QVERIFY(dw.isAreaAllowed(Qt::RightDockWidgetArea));
411 QVERIFY(!dw.isAreaAllowed(Qt::TopDockWidgetArea));
412 QVERIFY(!dw.isAreaAllowed(Qt::BottomDockWidgetArea));
413 QCOMPARE(spy.count(), 1);
414 QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()),
415 dw.allowedAreas());
416 spy.clear();
417 dw.setAllowedAreas(dw.allowedAreas());
418 QCOMPARE(spy.count(), 0);
419
420 dw.setAllowedAreas(Qt::TopDockWidgetArea);
421 QCOMPARE(dw.allowedAreas(), Qt::TopDockWidgetArea);
422 QVERIFY(!dw.isAreaAllowed(Qt::LeftDockWidgetArea));
423 QVERIFY(!dw.isAreaAllowed(Qt::RightDockWidgetArea));
424 QVERIFY(dw.isAreaAllowed(Qt::TopDockWidgetArea));
425 QVERIFY(!dw.isAreaAllowed(Qt::BottomDockWidgetArea));
426 QCOMPARE(spy.count(), 1);
427 QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()),
428 dw.allowedAreas());
429 spy.clear();
430 dw.setAllowedAreas(dw.allowedAreas());
431 QCOMPARE(spy.count(), 0);
432
433 dw.setAllowedAreas(Qt::BottomDockWidgetArea);
434 QCOMPARE(dw.allowedAreas(), Qt::BottomDockWidgetArea);
435 QVERIFY(!dw.isAreaAllowed(Qt::LeftDockWidgetArea));
436 QVERIFY(!dw.isAreaAllowed(Qt::RightDockWidgetArea));
437 QVERIFY(!dw.isAreaAllowed(Qt::TopDockWidgetArea));
438 QVERIFY(dw.isAreaAllowed(Qt::BottomDockWidgetArea));
439 QCOMPARE(spy.count(), 1);
440 QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()),
441 dw.allowedAreas());
442 spy.clear();
443 dw.setAllowedAreas(dw.allowedAreas());
444 QCOMPARE(spy.count(), 0);
445
446 // multiple dock window areas
447 dw.setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
448 QCOMPARE(dw.allowedAreas(), Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
449 QVERIFY(!dw.isAreaAllowed(Qt::LeftDockWidgetArea));
450 QVERIFY(!dw.isAreaAllowed(Qt::RightDockWidgetArea));
451 QVERIFY(dw.isAreaAllowed(Qt::TopDockWidgetArea));
452 QVERIFY(dw.isAreaAllowed(Qt::BottomDockWidgetArea));
453 QCOMPARE(spy.count(), 1);
454 QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()),
455 dw.allowedAreas());
456 spy.clear();
457 dw.setAllowedAreas(dw.allowedAreas());
458 QCOMPARE(spy.count(), 0);
459
460 dw.setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
461 QCOMPARE(dw.allowedAreas(), Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
462 QVERIFY(dw.isAreaAllowed(Qt::LeftDockWidgetArea));
463 QVERIFY(dw.isAreaAllowed(Qt::RightDockWidgetArea));
464 QVERIFY(!dw.isAreaAllowed(Qt::TopDockWidgetArea));
465 QVERIFY(!dw.isAreaAllowed(Qt::BottomDockWidgetArea));
466 QCOMPARE(spy.count(), 1);
467 QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()),
468 dw.allowedAreas());
469 spy.clear();
470 dw.setAllowedAreas(dw.allowedAreas());
471 QCOMPARE(spy.count(), 0);
472
473 dw.setAllowedAreas(Qt::TopDockWidgetArea | Qt::LeftDockWidgetArea);
474 QCOMPARE(dw.allowedAreas(), Qt::TopDockWidgetArea | Qt::LeftDockWidgetArea);
475 QVERIFY(dw.isAreaAllowed(Qt::LeftDockWidgetArea));
476 QVERIFY(!dw.isAreaAllowed(Qt::RightDockWidgetArea));
477 QVERIFY(dw.isAreaAllowed(Qt::TopDockWidgetArea));
478 QVERIFY(!dw.isAreaAllowed(Qt::BottomDockWidgetArea));
479 QCOMPARE(spy.count(), 1);
480 QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()),
481 dw.allowedAreas());
482 spy.clear();
483 dw.setAllowedAreas(dw.allowedAreas());
484 QCOMPARE(spy.count(), 0);
485
486 dw.setAllowedAreas(Qt::BottomDockWidgetArea | Qt::RightDockWidgetArea);
487 QCOMPARE(dw.allowedAreas(), Qt::BottomDockWidgetArea | Qt::RightDockWidgetArea);
488 QVERIFY(!dw.isAreaAllowed(Qt::LeftDockWidgetArea));
489 QVERIFY(dw.isAreaAllowed(Qt::RightDockWidgetArea));
490 QVERIFY(!dw.isAreaAllowed(Qt::TopDockWidgetArea));
491 QVERIFY(dw.isAreaAllowed(Qt::BottomDockWidgetArea));
492 QCOMPARE(spy.count(), 1);
493 QCOMPARE(*static_cast<const Qt::DockWidgetAreas *>(spy.at(0).value(0).constData()),
494 dw.allowedAreas());
495 spy.clear();
496 dw.setAllowedAreas(dw.allowedAreas());
497 QCOMPARE(spy.count(), 0);
498}
499
500void tst_QDockWidget::toggleViewAction()
501{
502 QMainWindow mw;
503 QDockWidget dw(&mw);
504 mw.addDockWidget(area: Qt::LeftDockWidgetArea, dockwidget: &dw);
505 mw.show();
506 QAction *toggleViewAction = dw.toggleViewAction();
507 QVERIFY(!dw.isHidden());
508 toggleViewAction->trigger();
509 QVERIFY(dw.isHidden());
510 toggleViewAction->trigger();
511 QVERIFY(!dw.isHidden());
512 toggleViewAction->trigger();
513 QVERIFY(dw.isHidden());
514}
515
516void tst_QDockWidget::visibilityChanged()
517{
518 QMainWindow mw;
519 QDockWidget dw;
520 QSignalSpy spy(&dw, SIGNAL(visibilityChanged(bool)));
521
522 mw.addDockWidget(area: Qt::LeftDockWidgetArea, dockwidget: &dw);
523 mw.show();
524
525 QCOMPARE(spy.count(), 1);
526 QCOMPARE(spy.at(0).at(0).toBool(), true);
527 spy.clear();
528
529 dw.hide();
530 QCOMPARE(spy.count(), 1);
531 QCOMPARE(spy.at(0).at(0).toBool(), false);
532 spy.clear();
533
534 dw.hide();
535 QCOMPARE(spy.count(), 0);
536
537 dw.show();
538 QCOMPARE(spy.count(), 1);
539 QCOMPARE(spy.at(0).at(0).toBool(), true);
540 spy.clear();
541
542 dw.show();
543 QCOMPARE(spy.count(), 0);
544
545 QDockWidget dw2;
546 mw.tabifyDockWidget(first: &dw, second: &dw2);
547 dw2.show();
548 dw2.raise();
549 QCOMPARE(spy.count(), 1);
550 QCOMPARE(spy.at(0).at(0).toBool(), false);
551 spy.clear();
552
553 dw2.hide();
554 qApp->processEvents();
555 QCOMPARE(spy.count(), 1);
556 QCOMPARE(spy.at(0).at(0).toBool(), true);
557 spy.clear();
558
559 dw2.show();
560 dw2.raise();
561 qApp->processEvents();
562 QCOMPARE(spy.count(), 1);
563 QCOMPARE(spy.at(0).at(0).toBool(), false);
564 spy.clear();
565
566 dw.raise();
567 QCOMPARE(spy.count(), 1);
568 QCOMPARE(spy.at(0).at(0).toBool(), true);
569 spy.clear();
570
571 dw.raise();
572 QCOMPARE(spy.count(), 0);
573
574 dw2.raise();
575 QCOMPARE(spy.count(), 1);
576 QCOMPARE(spy.at(0).at(0).toBool(), false);
577 spy.clear();
578
579 dw2.raise();
580 QCOMPARE(spy.count(), 0);
581
582 mw.addDockWidget(area: Qt::RightDockWidgetArea, dockwidget: &dw2);
583 QTRY_COMPARE(spy.count(), 1);
584 QCOMPARE(spy.at(0).at(0).toBool(), true);
585}
586
587void tst_QDockWidget::updateTabBarOnVisibilityChanged()
588{
589 // QTBUG49045: Populate tabified dock area with 4 widgets, set the tab
590 // index to 2 (dw2), hide dw0, dw1 and check that the tab index is 0 (dw3).
591 QMainWindow mw;
592 mw.setMinimumSize(minw: 400, minh: 400);
593 mw.setWindowTitle(QTest::currentTestFunction());
594 QDockWidget *dw0 = new QDockWidget("d1", &mw);
595 dw0->setAllowedAreas(Qt::LeftDockWidgetArea);
596 mw.addDockWidget(area: Qt::LeftDockWidgetArea, dockwidget: dw0);
597 QDockWidget *dw1 = new QDockWidget("d2", &mw);
598 dw1->setAllowedAreas(Qt::LeftDockWidgetArea);
599 mw.addDockWidget(area: Qt::LeftDockWidgetArea, dockwidget: dw1);
600 QDockWidget *dw2 = new QDockWidget("d3", &mw);
601 dw2->setAllowedAreas(Qt::LeftDockWidgetArea);
602 mw.addDockWidget(area: Qt::LeftDockWidgetArea, dockwidget: dw2);
603 QDockWidget *dw3 = new QDockWidget("d4", &mw);
604 dw3->setAllowedAreas(Qt::LeftDockWidgetArea);
605 mw.addDockWidget(area: Qt::LeftDockWidgetArea, dockwidget: dw3);
606 mw.tabifyDockWidget(first: dw0, second: dw1);
607 mw.tabifyDockWidget(first: dw1, second: dw2);
608 mw.tabifyDockWidget(first: dw2, second: dw3);
609
610 QTabBar *tabBar = mw.findChild<QTabBar *>();
611 QVERIFY(tabBar);
612 tabBar->setCurrentIndex(2);
613
614 mw.show();
615 QVERIFY(QTest::qWaitForWindowExposed(&mw));
616
617 QCOMPARE(tabBar->currentIndex(), 2);
618
619 dw0->hide();
620 dw1->hide();
621 QTRY_COMPARE(tabBar->count(), 2);
622 QCOMPARE(tabBar->currentIndex(), 0);
623}
624
625Q_DECLARE_METATYPE(Qt::DockWidgetArea)
626
627void tst_QDockWidget::dockLocationChanged()
628{
629 qRegisterMetaType<Qt::DockWidgetArea>(typeName: "Qt::DockWidgetArea");
630
631 QMainWindow mw;
632 QDockWidget dw;
633 dw.setObjectName("dock1");
634 QSignalSpy spy(&dw, SIGNAL(dockLocationChanged(Qt::DockWidgetArea)));
635
636 mw.addDockWidget(area: Qt::LeftDockWidgetArea, dockwidget: &dw);
637 QCOMPARE(spy.count(), 1);
638 QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)),
639 Qt::LeftDockWidgetArea);
640 spy.clear();
641
642 mw.addDockWidget(area: Qt::LeftDockWidgetArea, dockwidget: &dw);
643 QCOMPARE(spy.count(), 1);
644 QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)),
645 Qt::LeftDockWidgetArea);
646 spy.clear();
647
648 mw.addDockWidget(area: Qt::RightDockWidgetArea, dockwidget: &dw);
649 QCOMPARE(spy.count(), 1);
650 QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)),
651 Qt::RightDockWidgetArea);
652 spy.clear();
653
654 mw.removeDockWidget(dockwidget: &dw);
655 QCOMPARE(spy.count(), 0);
656
657 QDockWidget dw2;
658 dw2.setObjectName("dock2");
659 mw.addDockWidget(area: Qt::TopDockWidgetArea, dockwidget: &dw2);
660 mw.tabifyDockWidget(first: &dw2, second: &dw);
661 QCOMPARE(spy.count(), 1);
662 QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)),
663 Qt::TopDockWidgetArea);
664 spy.clear();
665
666 mw.splitDockWidget(after: &dw2, dockwidget: &dw, orientation: Qt::Horizontal);
667 QCOMPARE(spy.count(), 1);
668 QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)),
669 Qt::TopDockWidgetArea);
670 spy.clear();
671
672 dw.setFloating(true);
673 QTRY_COMPARE(spy.count(), 1);
674 QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)),
675 Qt::NoDockWidgetArea);
676 spy.clear();
677
678 dw.setFloating(false);
679 QTRY_COMPARE(spy.count(), 1);
680 QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)),
681 Qt::TopDockWidgetArea);
682 spy.clear();
683
684 QByteArray ba = mw.saveState();
685 mw.restoreState(state: ba);
686 QCOMPARE(spy.count(), 1);
687 QCOMPARE(qvariant_cast<Qt::DockWidgetArea>(spy.at(0).at(0)),
688 Qt::TopDockWidgetArea);
689}
690
691void tst_QDockWidget::setTitleBarWidget()
692{
693 //test the successive usage of setTitleBarWidget
694
695 QDockWidget dock;
696 QWidget w, w2;
697
698 dock.show();
699 qApp->processEvents();
700
701 dock.setTitleBarWidget(&w);
702 qApp->processEvents();
703 QCOMPARE(w.isVisible(), true);
704
705 //set another widget as the titlebar widget
706 dock.setTitleBarWidget(&w2); // this used to crash (task 184668)
707 qApp->processEvents();
708 QCOMPARE(w.isVisible(), false);
709 QCOMPARE(w2.isVisible(), true);
710
711 //tries to reset the titlebarwidget to none
712 dock.setTitleBarWidget(0);
713 qApp->processEvents();
714 QCOMPARE(w.isVisible(), false);
715 QCOMPARE(w2.isVisible(), false);
716}
717
718void tst_QDockWidget::titleBarDoubleClick()
719{
720 QMainWindow win;
721 QDockWidget dock(&win);
722 win.show();
723 dock.setFloating(true);
724
725 QEvent e(QEvent::NonClientAreaMouseButtonDblClick);
726 QApplication::sendEvent(receiver: &dock, event: &e);
727 QVERIFY(dock.isFloating());
728 QCOMPARE(win.dockWidgetArea(&dock), Qt::NoDockWidgetArea);
729
730 win.addDockWidget(area: Qt::TopDockWidgetArea, dockwidget: &dock);
731 dock.setFloating(true);
732 QApplication::sendEvent(receiver: &dock, event: &e);
733 QVERIFY(!dock.isFloating());
734 QCOMPARE(win.dockWidgetArea(&dock), Qt::TopDockWidgetArea);
735}
736
737static QDockWidget *createTestDock(QMainWindow &parent)
738{
739 const QString title = QStringLiteral("dock1");
740 QDockWidget *dock = new QDockWidget(title, &parent);
741 dock->setObjectName(title);
742 dock->setAllowedAreas(Qt::AllDockWidgetAreas);
743 return dock;
744}
745
746void tst_QDockWidget::restoreStateOfFloating()
747{
748 QMainWindow mw;
749 QDockWidget *dock = createTestDock(parent&: mw);
750 mw.addDockWidget(area: Qt::TopDockWidgetArea, dockwidget: dock);
751 QVERIFY(!dock->isFloating());
752 QByteArray ba = mw.saveState();
753 dock->setFloating(true);
754 QVERIFY(dock->isFloating());
755 QVERIFY(mw.restoreState(ba));
756 QVERIFY(!dock->isFloating());
757}
758
759void tst_QDockWidget::restoreStateWhileStillFloating()
760{
761 // When the dock widget is already floating then it takes a different code path
762 // so this test covers the case where the restoreState() is effectively just
763 // moving it back and resizing it
764 const QRect availGeom = QGuiApplication::primaryScreen()->availableGeometry();
765 const QPoint startingDockPos = availGeom.center();
766 QMainWindow mw;
767 QDockWidget *dock = createTestDock(parent&: mw);
768 mw.addDockWidget(area: Qt::TopDockWidgetArea, dockwidget: dock);
769 dock->setFloating(true);
770 dock->move(startingDockPos);
771 mw.show();
772 QVERIFY(QTest::qWaitForWindowExposed(&mw));
773 QVERIFY(dock->isFloating());
774 QByteArray ba = mw.saveState();
775 const QPoint dockPos = dock->pos();
776 dock->move(availGeom.topLeft() + QPoint(10, 10));
777 dock->resize(dock->size() + QSize(10, 10));
778 QVERIFY(mw.restoreState(ba));
779 QVERIFY(dock->isFloating());
780 if (!QGuiApplication::platformName().compare(s: "xcb", cs: Qt::CaseInsensitive))
781 QTRY_COMPARE(dock->pos(), dockPos);
782}
783
784void tst_QDockWidget::restoreDockWidget()
785{
786 QByteArray geometry;
787 QByteArray state;
788
789 const QString name = QStringLiteral("main");
790 const QRect availableGeometry = QGuiApplication::primaryScreen()->availableGeometry();
791 const QSize size = availableGeometry.size() / 5;
792 const QPoint mainWindowPos = availableGeometry.bottomRight() - QPoint(size.width(), size.height()) - QPoint(100, 100);
793 const QPoint dockPos = availableGeometry.center();
794
795 {
796 QMainWindow saveWindow;
797 saveWindow.setObjectName(name);
798 saveWindow.setWindowTitle(QTest::currentTestFunction() + QStringLiteral(" save"));
799 saveWindow.resize(size);
800 saveWindow.move(mainWindowPos);
801 saveWindow.restoreState(state: QByteArray());
802 QDockWidget *dock = createTestDock(parent&: saveWindow);
803 QVERIFY(!saveWindow.restoreDockWidget(dock)); // Not added, no placeholder
804 saveWindow.addDockWidget(area: Qt::TopDockWidgetArea, dockwidget: dock);
805 dock->setFloating(true);
806 dock->resize(size);
807 dock->move(dockPos);
808 saveWindow.show();
809 QVERIFY(QTest::qWaitForWindowExposed(&saveWindow));
810 QVERIFY(dock->isFloating());
811 state = saveWindow.saveState();
812 geometry = saveWindow.saveGeometry();
813
814 // QTBUG-49832: Delete and recreate the dock; it should be restored to the same position.
815 delete dock;
816 dock = createTestDock(parent&: saveWindow);
817 QVERIFY(saveWindow.restoreDockWidget(dock));
818 dock->show();
819 QVERIFY(QTest::qWaitForWindowExposed(dock));
820 QTRY_VERIFY(dock->isFloating());
821 QTRY_COMPARE(dock->pos(), dockPos);
822 }
823
824 QVERIFY(!geometry.isEmpty());
825 QVERIFY(!state.isEmpty());
826
827 // QTBUG-45780: Completely recreate the dock widget from the saved state.
828 {
829 QMainWindow restoreWindow;
830 restoreWindow.setObjectName(name);
831 restoreWindow.setWindowTitle(QTest::currentTestFunction() + QStringLiteral(" restore"));
832 QVERIFY(restoreWindow.restoreState(state));
833 QVERIFY(restoreWindow.restoreGeometry(geometry));
834
835 // QMainWindow::restoreDockWidget() restores the state when adding the dock
836 // after restoreState().
837 QDockWidget *dock = createTestDock(parent&: restoreWindow);
838 QVERIFY(restoreWindow.restoreDockWidget(dock));
839 restoreWindow.show();
840 QVERIFY(QTest::qWaitForWindowExposed(&restoreWindow));
841 QTRY_VERIFY(dock->isFloating());
842 QTRY_COMPARE(dock->pos(), dockPos);
843 }
844}
845
846void tst_QDockWidget::task165177_deleteFocusWidget()
847{
848 QMainWindow mw;
849 QDockWidget *dw = new QDockWidget(&mw);
850 mw.addDockWidget(area: Qt::LeftDockWidgetArea, dockwidget: dw);
851 QLineEdit *ledit = new QLineEdit;
852 dw->setWidget(ledit);
853 mw.show();
854 QVERIFY(QTest::qWaitForWindowExposed(&mw));
855 qApp->processEvents();
856 dw->setFloating(true);
857 delete ledit;
858 QCOMPARE(mw.focusWidget(), nullptr);
859 QCOMPARE(dw->focusWidget(), nullptr);
860}
861
862void tst_QDockWidget::task169808_setFloating()
863{
864 //we try to test if the sizeHint of the dock widget widget is taken into account
865
866 class MyWidget : public QWidget
867 {
868 public:
869 QSize sizeHint() const
870 {
871 const QRect& deskRect = QGuiApplication::primaryScreen()->availableGeometry();
872 return QSize(qMin(a: 300, b: deskRect.width() / 2), qMin(a: 300, b: deskRect.height() / 2));
873 }
874
875 QSize minimumSizeHint() const
876 {
877 return QSize(20,20);
878 }
879
880 void paintEvent(QPaintEvent *)
881 {
882 QPainter p(this);
883 p.fillRect(r: rect(), c: Qt::red);
884 }
885 };
886 QMainWindow mw;
887 mw.setCentralWidget(new MyWidget);
888 QDockWidget *dw = new QDockWidget("my dock");
889 dw->setWidget(new MyWidget);
890 mw.addDockWidget(area: Qt::LeftDockWidgetArea, dockwidget: dw);
891 dw->setFloating(true);
892 mw.show();
893 QVERIFY(QTest::qWaitForWindowExposed(&mw));
894
895#ifdef Q_OS_WINRT
896 QEXPECT_FAIL("", "Widgets are maximized on WinRT by default", Abort);
897#endif
898 QCOMPARE(dw->widget()->size(), dw->widget()->sizeHint());
899
900 //and now we try to test if the contents margin is taken into account
901 dw->widget()->setSizePolicy(hor: QSizePolicy::Fixed, ver: QSizePolicy::Fixed);
902 dw->setFloating(false);
903 QVERIFY(QTest::qWaitForWindowExposed(&mw));
904 qApp->processEvents(); //leave time processing events
905
906
907 const QSize oldSize = dw->size();
908 const int margin = 20;
909
910 dw->setContentsMargins(left: margin, top: margin, right: margin, bottom: margin);
911
912 QVERIFY(QTest::qWaitForWindowExposed(&mw));
913 qApp->processEvents(); //leave time processing events
914
915 //widget size shouldn't have changed
916 QCOMPARE(dw->widget()->size(), dw->widget()->sizeHint());
917 //dockwidget should be bigger
918 QCOMPARE(dw->size(), oldSize + QSize(margin * 2, margin * 2));
919
920
921}
922
923void tst_QDockWidget::task237438_setFloatingCrash()
924{
925 //should not crash
926 QDockWidget pqdwDock;
927 pqdwDock.setFloating(false);
928 pqdwDock.show();
929}
930
931void tst_QDockWidget::task248604_infiniteResize()
932{
933 QDockWidget d;
934 QTabWidget *t = new QTabWidget;
935 t->addTab(widget: new QWidget, "Foo");
936 d.setWidget(t);
937 d.setContentsMargins(left: 2, top: 2, right: 2, bottom: 2);
938 d.setMinimumSize(minw: 320, minh: 240);
939 d.showNormal();
940#ifdef Q_OS_WINRT
941 QEXPECT_FAIL("", "Widgets are maximized on WinRT by default", Abort);
942#endif
943 QTRY_COMPARE(d.size(), QSize(320, 240));
944}
945
946
947void tst_QDockWidget::task258459_visibilityChanged()
948{
949 if (QGuiApplication::platformName().startsWith(s: QLatin1String("wayland"), cs: Qt::CaseInsensitive))
950 QSKIP("Wayland: This fails. Figure out why.");
951
952 QMainWindow win;
953 QDockWidget dock1, dock2;
954 win.addDockWidget(area: Qt::RightDockWidgetArea, dockwidget: &dock1);
955 win.tabifyDockWidget(first: &dock1, second: &dock2);
956 QSignalSpy spy1(&dock1, SIGNAL(visibilityChanged(bool)));
957 QSignalSpy spy2(&dock2, SIGNAL(visibilityChanged(bool)));
958 win.show();
959 QVERIFY(QTest::qWaitForWindowActive(&win));
960 QCOMPARE(spy1.count(), 1);
961 QCOMPARE(spy1.first().first().toBool(), false); //dock1 is invisible
962 QCOMPARE(spy2.count(), 1);
963 QCOMPARE(spy2.first().first().toBool(), true); //dock1 is visible
964}
965
966void tst_QDockWidget::taskQTBUG_1665_closableChanged()
967{
968 QDockWidget dock;
969 dock.show();
970 QVERIFY(QTest::qWaitForWindowExposed(&dock));
971
972 QDockWidgetLayout *l = qobject_cast<QDockWidgetLayout*>(object: dock.layout());
973
974 if (l && !l->nativeWindowDeco())
975 QSKIP("this machine doesn't support native dock widget");
976
977 QVERIFY(dock.windowFlags() & Qt::WindowCloseButtonHint);
978
979 //now let's remove the closable attribute
980 dock.setFeatures(dock.features() ^ QDockWidget::DockWidgetClosable);
981 QVERIFY(!(dock.windowFlags() & Qt::WindowCloseButtonHint));
982}
983
984void tst_QDockWidget::taskQTBUG_9758_undockedGeometry()
985{
986 QMainWindow window;
987 QDockWidget dock1(&window);
988 QDockWidget dock2(&window);
989 window.addDockWidget(area: Qt::RightDockWidgetArea, dockwidget: &dock1);
990 window.addDockWidget(area: Qt::RightDockWidgetArea, dockwidget: &dock2);
991 window.tabifyDockWidget(first: &dock1, second: &dock2);
992 dock1.hide();
993 dock2.hide();
994 window.show();
995 QVERIFY(QTest::qWaitForWindowExposed(&window));
996 dock1.setFloating(true);
997 dock1.show();
998 QVERIFY(QTest::qWaitForWindowExposed(&dock1));
999
1000 QVERIFY(dock1.x() >= 0);
1001 QVERIFY(dock1.y() >= 0);
1002}
1003
1004void tst_QDockWidget::setWindowTitle()
1005{
1006 QMainWindow window;
1007 QDockWidget dock1(&window);
1008 QDockWidget dock2(&window);
1009 const QString dock1Title = QStringLiteral("&Window");
1010 const QString dock2Title = QStringLiteral("&Modifiable Window [*]");
1011
1012 dock1.setWindowTitle(dock1Title);
1013 dock2.setWindowTitle(dock2Title);
1014 window.addDockWidget(area: Qt::RightDockWidgetArea, dockwidget: &dock1);
1015 window.addDockWidget(area: Qt::RightDockWidgetArea, dockwidget: &dock2);
1016 window.show();
1017 QVERIFY(QTest::qWaitForWindowExposed(&window));
1018
1019 QCOMPARE(dock1.windowTitle(), dock1Title);
1020 QCOMPARE(dock2.windowTitle(), dock2Title);
1021
1022 dock1.setFloating(true);
1023 dock1.show();
1024 QVERIFY(QTest::qWaitForWindowExposed(&dock1));
1025 QCOMPARE(dock1.windowTitle(), dock1Title);
1026 dock1.setFloating(false);
1027 QCOMPARE(dock1.windowTitle(), dock1Title);
1028 dock1.setFloating(true);
1029 dock1.show();
1030 QVERIFY(QTest::qWaitForWindowExposed(&dock1));
1031 const QString changed = QStringLiteral("Changed ");
1032 dock1.setWindowTitle(QString(changed + dock1Title));
1033 QCOMPARE(dock1.windowTitle(), QString(changed + dock1Title));
1034 dock1.setFloating(false);
1035 QCOMPARE(dock1.windowTitle(), QString(changed + dock1Title));
1036
1037 dock2.setWindowModified(true);
1038 QCOMPARE(dock2.windowTitle(), dock2Title);
1039 dock2.setFloating(true);
1040 dock2.show();
1041 QVERIFY(QTest::qWaitForWindowExposed(&dock2));
1042 QCOMPARE(dock2.windowTitle(), dock2Title);
1043 dock2.setWindowModified(false);
1044 QCOMPARE(dock2.windowTitle(), dock2Title);
1045 dock2.setFloating(false);
1046 QCOMPARE(dock2.windowTitle(), dock2Title);
1047 dock2.setFloating(true);
1048 dock2.show();
1049 QVERIFY(QTest::qWaitForWindowExposed(&dock2));
1050 QCOMPARE(dock2.windowTitle(), dock2Title);
1051}
1052
1053QTEST_MAIN(tst_QDockWidget)
1054#include "tst_qdockwidget.moc"
1055

source code of qtbase/tests/auto/widgets/widgets/qdockwidget/tst_qdockwidget.cpp