1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44
45 #include <QMdiSubWindow>
46 #include <QMdiArea>
47
48 #include <QApplication>
49 #include <QMainWindow>
50 #include <QMenuBar>
51 #include <QPushButton>
52 #include <QStyle>
53 #include <QStyleOption>
54 #include <QVBoxLayout>
55 #include <QLineEdit>
56 #include <QDesktopWidget>
57 #include <QDockWidget>
58 #include <QScrollBar>
59 #include <QTextEdit>
60 #ifndef QT_NO_OPENGL
61 #include <QtOpenGL>
62 #endif
63 #include <QMacStyle>
64
65 #include "../../shared/util.h"
66 #include "../platformquirks.h"
67
68 static const Qt::WindowFlags DefaultWindowFlags
69 = Qt::SubWindow | Qt::WindowSystemMenuHint
70 | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint;
71
72 Q_DECLARE_METATYPE(QMdiArea::WindowOrder)
Q_DECLARE_METATYPE(QMdiSubWindow *)73 Q_DECLARE_METATYPE(QMdiSubWindow *)
74 Q_DECLARE_METATYPE(QList<int>)
75 Q_DECLARE_METATYPE(QTabWidget::TabPosition)
76
77 //TESTED_CLASS=
78 //TESTED_FILES=
79
80 static bool tabBetweenSubWindowsIn(QMdiArea *mdiArea, int tabCount = -1, bool reverse = false)
81 {
82 if (!mdiArea) {
83 qWarning("Null pointer to mdi area");
84 return false;
85 }
86
87 QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
88 const bool walkThrough = tabCount == -1;
89
90 if (walkThrough) {
91 QMdiSubWindow *active = reverse ? subWindows.front() : subWindows.back();
92 mdiArea->setActiveSubWindow(active);
93 if (mdiArea->activeSubWindow() != active) {
94 qWarning("Failed to set active sub window");
95 return false;
96 }
97 tabCount = subWindows.size();
98 }
99
100 QWidget *focusWidget = qApp->focusWidget();
101 if (!focusWidget) {
102 qWarning("No focus widget");
103 return false;
104 }
105
106 Qt::KeyboardModifiers modifiers = reverse ? Qt::ShiftModifier : Qt::NoModifier;
107 Qt::Key key;
108 #ifdef Q_WS_MAC
109 key = Qt::Key_Meta;
110 modifiers |= Qt::MetaModifier;
111 #else
112 key = Qt::Key_Control;
113 modifiers |= Qt::ControlModifier;
114 #endif
115
116 QTest::keyPress(focusWidget, key, modifiers);
117 for (int i = 0; i < tabCount; ++i) {
118 QTest::keyPress(focusWidget, reverse ? Qt::Key_Backtab : Qt::Key_Tab, modifiers);
119 if (tabCount > 1)
120 QTest::qWait(500);
121 if (walkThrough) {
122 QRubberBand *rubberBand = qFindChild<QRubberBand *>(mdiArea->viewport());
123 if (!rubberBand) {
124 qWarning("No rubber band");
125 return false;
126 }
127 QMdiSubWindow *subWindow = subWindows.at(reverse ? subWindows.size() -1 - i : i);
128 if (rubberBand->geometry() != subWindow->geometry()) {
129 qWarning("Rubber band has different geometry");
130 return false;
131 }
132 }
133 qApp->processEvents();
134 }
135 QTest::keyRelease(focusWidget, key);
136
137 return true;
138 }
139
tabBarShapeFrom(QTabWidget::TabShape shape,QTabWidget::TabPosition position)140 static inline QTabBar::Shape tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position)
141 {
142 const bool rounded = (shape == QTabWidget::Rounded);
143 if (position == QTabWidget::North)
144 return rounded ? QTabBar::RoundedNorth : QTabBar::TriangularNorth;
145 if (position == QTabWidget::South)
146 return rounded ? QTabBar::RoundedSouth : QTabBar::TriangularSouth;
147 if (position == QTabWidget::East)
148 return rounded ? QTabBar::RoundedEast : QTabBar::TriangularEast;
149 if (position == QTabWidget::West)
150 return rounded ? QTabBar::RoundedWest : QTabBar::TriangularWest;
151 return QTabBar::RoundedNorth;
152 }
153
154 enum Arrangement {
155 Tiled,
156 Cascaded
157 };
158
verifyArrangement(QMdiArea * mdiArea,Arrangement arrangement,const QList<int> & expectedIndices)159 static bool verifyArrangement(QMdiArea *mdiArea, Arrangement arrangement, const QList<int> &expectedIndices)
160 {
161 if (!mdiArea || expectedIndices.isEmpty() || mdiArea->subWindowList().isEmpty())
162 return false;
163
164 const QList<QMdiSubWindow *> subWindows = mdiArea->subWindowList();
165 const QMdiSubWindow *const firstSubWindow = subWindows.at(0);
166
167 switch (arrangement) {
168 case Tiled:
169 {
170 // Calculate the number of rows and columns.
171 const int n = subWindows.count();
172 const int numColumns = qMax(qCeil(qSqrt(qreal(n))), 1);
173 const int numRows = qMax((n % numColumns) ? (n / numColumns + 1) : (n / numColumns), 1);
174
175 // Ensure that the geometry of all the subwindows are as expected by using
176 // QWidget::childAt starting from the middle of the topleft cell and subsequently
177 // adding rowWidth and rowHeight (going from left to right).
178 const int columnWidth = mdiArea->viewport()->width() / numColumns;
179 const int rowHeight = mdiArea->viewport()->height() / numRows;
180 QPoint subWindowPos(columnWidth / 2, rowHeight / 2);
181 for (int i = 0; i < numRows; ++i) {
182 for (int j = 0; j < numColumns; ++j) {
183 const int index = expectedIndices.at(i * numColumns + j);
184 QWidget *actual = mdiArea->viewport()->childAt(subWindowPos);
185 QMdiSubWindow *expected = subWindows.at(index);
186 if (actual != expected && !expected->isAncestorOf(actual))
187 return false;
188 subWindowPos.rx() += columnWidth;
189 }
190 subWindowPos.rx() = columnWidth / 2;
191 subWindowPos.ry() += rowHeight;
192 }
193 break;
194 }
195 case Cascaded:
196 {
197 // Calculate the delta (dx, dy) between two cascaded subwindows.
198 QStyleOptionTitleBar options;
199 options.initFrom(firstSubWindow);
200 int titleBarHeight = firstSubWindow->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options);
201 #ifdef Q_WS_MAC
202 // ### Remove this after the mac style has been fixed
203 if (qobject_cast<QMacStyle *>(firstSubWindow->style()))
204 titleBarHeight -= 4;
205 #endif
206 const QFontMetrics fontMetrics = QFontMetrics(QApplication::font("QWorkspaceTitleBar"));
207 const int dy = qMax(titleBarHeight - (titleBarHeight - fontMetrics.height()) / 2, 1);
208 const int dx = 10;
209
210 // Current activation/stacking order.
211 const QList<QMdiSubWindow *> activationOrderList = mdiArea->subWindowList(QMdiArea::ActivationHistoryOrder);
212
213 // Ensure that the geometry of all the subwindows are as expected by using
214 // QWidget::childAt with the position of the first one and subsequently adding
215 // dx and dy.
216 QPoint subWindowPos(20, 5);
217 foreach (int expectedIndex, expectedIndices) {
218 QMdiSubWindow *expected = subWindows.at(expectedIndex);
219 expected->raise();
220 if (mdiArea->viewport()->childAt(subWindowPos) != expected)
221 return false;
222 expected->lower();
223 subWindowPos.rx() += dx;
224 subWindowPos.ry() += dy;
225 }
226
227 // Restore stacking order.
228 foreach (QMdiSubWindow *subWindow, activationOrderList) {
229 mdiArea->setActiveSubWindow(subWindow);
230 qApp->processEvents();
231 }
232 break;
233 }
234 default:
235 return false;
236 }
237 return true;
238 }
239
240 class tst_QMdiArea : public QObject
241 {
242 Q_OBJECT
243 public:
244 tst_QMdiArea();
245 public slots:
246 void initTestCase();
247 protected slots:
248 void activeChanged(QMdiSubWindow *child);
249
250 private slots:
251 // Tests from QWorkspace
252 void subWindowActivated_data();
253 void subWindowActivated();
254 void subWindowActivated2();
255 void subWindowActivatedWithMinimize();
256 void showWindows();
257 void changeWindowTitle();
258 void changeModified();
259 void childSize();
260 void fixedSize();
261 // New tests
262 void minimumSizeHint();
263 void sizeHint();
264 void setActiveSubWindow();
265 void activeSubWindow();
266 void currentSubWindow();
267 void addAndRemoveWindows();
268 void addAndRemoveWindowsWithReparenting();
269 void removeSubWindow_2();
270 void closeWindows();
271 void activateNextAndPreviousWindow();
272 void subWindowList_data();
273 void subWindowList();
274 void setBackground();
275 void setViewport();
276 void tileSubWindows();
277 void cascadeAndTileSubWindows();
278 void resizeMaximizedChildWindows_data();
279 void resizeMaximizedChildWindows();
280 void focusWidgetAfterAddSubWindow();
281 void dontMaximizeSubWindowOnActivation();
282 void delayedPlacement();
283 void iconGeometryInMenuBar();
284 void resizeTimer();
285 void updateScrollBars();
286 void setActivationOrder_data();
287 void setActivationOrder();
288 void tabBetweenSubWindows();
289 void setViewMode();
290 void setTabsClosable();
291 void setTabsMovable();
292 void setTabShape();
293 void setTabPosition_data();
294 void setTabPosition();
295 #if defined(Q_WS_WIN) || defined(Q_WS_X11)
296 void nativeSubWindows();
297 #endif
298 void task_209615();
299 void task_236750();
300
301 private:
302 QMdiSubWindow *activeWindow;
303 bool accelPressed;
304 };
305
tst_QMdiArea()306 tst_QMdiArea::tst_QMdiArea()
307 : activeWindow(0)
308 {
309 qRegisterMetaType<QMdiSubWindow *>();
310 }
311
initTestCase()312 void tst_QMdiArea::initTestCase()
313 {
314 #ifdef Q_OS_WINCE //disable magic for WindowsCE
315 qApp->setAutoMaximizeThreshold(-1);
316 #endif
317 }
318
319 // Old QWorkspace tests
activeChanged(QMdiSubWindow * child)320 void tst_QMdiArea::activeChanged(QMdiSubWindow *child)
321 {
322 activeWindow = child;
323 }
324
subWindowActivated_data()325 void tst_QMdiArea::subWindowActivated_data()
326 {
327 // define the test elements we're going to use
328 QTest::addColumn<int>("count");
329
330 // create a first testdata instance and fill it with data
331 QTest::newRow( "data0" ) << 0;
332 QTest::newRow( "data1" ) << 1;
333 QTest::newRow( "data2" ) << 2;
334 }
335
subWindowActivated()336 void tst_QMdiArea::subWindowActivated()
337 {
338 QMainWindow mw(0) ;
339 mw.menuBar();
340 QMdiArea *workspace = new QMdiArea(&mw);
341 workspace->setObjectName(QLatin1String("testWidget"));
342 mw.setCentralWidget(workspace);
343 QSignalSpy spy(workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)));
344 connect( workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(activeChanged(QMdiSubWindow *)));
345 mw.show();
346 qApp->setActiveWindow(&mw);
347
348 QFETCH( int, count );
349 int i;
350
351 for ( i = 0; i < count; ++i ) {
352 QWidget *widget = new QWidget(workspace, 0);
353 widget->setAttribute(Qt::WA_DeleteOnClose);
354 workspace->addSubWindow(widget)->show();
355 widget->show();
356 qApp->processEvents();
357 QVERIFY( activeWindow == workspace->activeSubWindow() );
358 QCOMPARE(spy.count(), 1);
359 spy.clear();
360 }
361
362 QList<QMdiSubWindow *> windows = workspace->subWindowList();
363 QCOMPARE( (int)windows.count(), count );
364
365 for ( i = 0; i < count; ++i ) {
366 QMdiSubWindow *window = windows.at(i);
367 window->showMinimized();
368 qApp->processEvents();
369 QVERIFY( activeWindow == workspace->activeSubWindow() );
370 if ( i == 1 )
371 QVERIFY( activeWindow == window );
372 }
373
374 for ( i = 0; i < count; ++i ) {
375 QMdiSubWindow *window = windows.at(i);
376 window->showNormal();
377 qApp->processEvents();
378 QVERIFY( window == activeWindow );
379 QVERIFY( activeWindow == workspace->activeSubWindow() );
380 }
381 spy.clear();
382
383 while (workspace->activeSubWindow() ) {
384 workspace->activeSubWindow()->close();
385 qApp->processEvents();
386 QVERIFY(activeWindow == workspace->activeSubWindow());
387 QCOMPARE(spy.count(), 1);
388 spy.clear();
389 }
390
391 QVERIFY(activeWindow == 0);
392 QVERIFY(workspace->activeSubWindow() == 0);
393 QCOMPARE(workspace->subWindowList().count(), 0);
394
395 {
396 workspace->hide();
397 QWidget *widget = new QWidget(workspace);
398 widget->setAttribute(Qt::WA_DeleteOnClose);
399 QMdiSubWindow *window = workspace->addSubWindow(widget);
400 widget->show();
401 QCOMPARE(spy.count(), 0);
402 workspace->show();
403 QCOMPARE(spy.count(), 1);
404 spy.clear();
405 QVERIFY( activeWindow == window );
406 window->close();
407 qApp->processEvents();
408 QCOMPARE(spy.count(), 1);
409 spy.clear();
410 QVERIFY( activeWindow == 0 );
411 }
412
413 {
414 workspace->hide();
415 QWidget *widget = new QWidget(workspace);
416 widget->setAttribute(Qt::WA_DeleteOnClose);
417 QMdiSubWindow *window = workspace->addSubWindow(widget);
418 widget->showMaximized();
419 qApp->sendPostedEvents();
420 QCOMPARE(spy.count(), 0);
421 spy.clear();
422 workspace->show();
423 QCOMPARE(spy.count(), 1);
424 spy.clear();
425 QVERIFY( activeWindow == window );
426 window->close();
427 qApp->processEvents();
428 QCOMPARE(spy.count(), 1);
429 spy.clear();
430 QVERIFY( activeWindow == 0 );
431 }
432
433 {
434 QWidget *widget = new QWidget(workspace);
435 widget->setAttribute(Qt::WA_DeleteOnClose);
436 QMdiSubWindow *window = workspace->addSubWindow(widget);
437 widget->showMinimized();
438 QCOMPARE(spy.count(), 1);
439 spy.clear();
440 QVERIFY( activeWindow == window );
441 QVERIFY(workspace->activeSubWindow() == window);
442 window->close();
443 qApp->processEvents();
444 QCOMPARE(spy.count(), 1);
445 spy.clear();
446 QVERIFY(workspace->activeSubWindow() == 0);
447 QVERIFY( activeWindow == 0 );
448 }
449 }
450
451 #ifdef Q_WS_MAC
452 #include <Security/AuthSession.h>
macHasAccessToWindowsServer()453 bool macHasAccessToWindowsServer()
454 {
455 SecuritySessionId mySession;
456 SessionAttributeBits sessionInfo;
457 SessionGetInfo(callerSecuritySession, &mySession, &sessionInfo);
458 return (sessionInfo & sessionHasGraphicAccess);
459 }
460 #endif
461
462
subWindowActivated2()463 void tst_QMdiArea::subWindowActivated2()
464 {
465 QMdiArea mdiArea;
466 QSignalSpy spy(&mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow *)));
467 for (int i = 0; i < 5; ++i)
468 mdiArea.addSubWindow(new QWidget);
469 QCOMPARE(spy.count(), 0);
470 mdiArea.show();
471 #ifdef Q_WS_X11
472 qt_x11_wait_for_window_manager(&mdiArea);
473 #endif
474 QTest::qWaitForWindowShown(&mdiArea);
475 mdiArea.activateWindow();
476 QTest::qWait(100);
477
478 QTRY_COMPARE(spy.count(), 5);
479 QCOMPARE(mdiArea.activeSubWindow(), mdiArea.subWindowList().back());
480 spy.clear();
481
482 // Just to make sure another widget is on top wrt. stacking order.
483 // This will typically become the active window if things are broken.
484 QMdiSubWindow *staysOnTopWindow = mdiArea.subWindowList().at(3);
485 staysOnTopWindow->setWindowFlags(Qt::WindowStaysOnTopHint);
486 mdiArea.setActiveSubWindow(staysOnTopWindow);
487 QCOMPARE(spy.count(), 1);
488 QCOMPARE(mdiArea.activeSubWindow(), staysOnTopWindow);
489 spy.clear();
490
491 QMdiSubWindow *activeSubWindow = mdiArea.subWindowList().at(2);
492 mdiArea.setActiveSubWindow(activeSubWindow);
493 QCOMPARE(spy.count(), 1);
494 QCOMPARE(mdiArea.activeSubWindow(), activeSubWindow);
495 spy.clear();
496
497 // Check that we only emit _one_ signal and the active window
498 // is unchanged after hide/show.
499 mdiArea.hide();
500 #ifdef Q_WS_X11
501 qt_x11_wait_for_window_manager(&mdiArea);
502 #endif
503 QTest::qWait(100);
504 QTRY_COMPARE(spy.count(), 1);
505 QVERIFY(!mdiArea.activeSubWindow());
506 QCOMPARE(mdiArea.currentSubWindow(), activeSubWindow);
507 spy.clear();
508
509 mdiArea.show();
510 #ifdef Q_WS_X11
511 qt_x11_wait_for_window_manager(&mdiArea);
512 #endif
513 QTest::qWait(100);
514 QTRY_COMPARE(spy.count(), 1);
515 QCOMPARE(mdiArea.activeSubWindow(), activeSubWindow);
516 spy.clear();
517
518 if (PlatformQuirks::isAutoMaximizing())
519 QSKIP("Platform is auto maximizing, so no showMinimized()", SkipAll);
520
521 // Check that we only emit _one_ signal and the active window
522 // is unchanged after showMinimized/showNormal.
523 mdiArea.showMinimized();
524 #ifdef Q_WS_X11
525 qt_x11_wait_for_window_manager(&mdiArea);
526 #elif defined (Q_WS_MAC)
527 if (!macHasAccessToWindowsServer())
528 QEXPECT_FAIL("", "showMinimized doesn't really minimize if you don't have access to the server", Abort);
529 #endif
530 QTest::qWait(10);
531 #if defined(Q_WS_QWS)
532 QEXPECT_FAIL("", "task 168682", Abort);
533 #endif
534 #ifdef Q_OS_WINCE
535 QSKIP("Not fixed yet. See Task 197453", SkipAll);
536 #endif
537 QTRY_COMPARE(spy.count(), 1);
538 QVERIFY(!mdiArea.activeSubWindow());
539 QCOMPARE(mdiArea.currentSubWindow(), activeSubWindow);
540 spy.clear();
541
542 mdiArea.showNormal();
543 #ifdef Q_WS_X11
544 qt_x11_wait_for_window_manager(&mdiArea);
545 #endif
546 QTest::qWait(100);
547 QTRY_COMPARE(spy.count(), 1);
548 QCOMPARE(mdiArea.activeSubWindow(), activeSubWindow);
549 spy.clear();
550 }
551
subWindowActivatedWithMinimize()552 void tst_QMdiArea::subWindowActivatedWithMinimize()
553 {
554 QMainWindow mw(0) ;
555 mw.menuBar();
556 QMdiArea *workspace = new QMdiArea(&mw);
557 workspace->setObjectName(QLatin1String("testWidget"));
558 mw.setCentralWidget(workspace);
559 QSignalSpy spy(workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)));
560 connect( workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(activeChanged(QMdiSubWindow *)) );
561 mw.show();
562 qApp->setActiveWindow(&mw);
563 QWidget *widget = new QWidget(workspace);
564 widget->setAttribute(Qt::WA_DeleteOnClose);
565 QMdiSubWindow *window1 = workspace->addSubWindow(widget);
566 QWidget *widget2 = new QWidget(workspace);
567 widget2->setAttribute(Qt::WA_DeleteOnClose);
568 QMdiSubWindow *window2 = workspace->addSubWindow(widget2);
569
570 widget->showMinimized();
571 QVERIFY( activeWindow == window1 );
572 widget2->showMinimized();
573 QVERIFY( activeWindow == window2 );
574
575 window2->close();
576 qApp->processEvents();
577 QVERIFY( activeWindow == window1 );
578
579 window1->close();
580 qApp->processEvents();
581 QVERIFY(workspace->activeSubWindow() == 0);
582 QVERIFY( activeWindow == 0 );
583
584 QVERIFY( workspace->subWindowList().count() == 0 );
585 }
586
showWindows()587 void tst_QMdiArea::showWindows()
588 {
589 QMdiArea *ws = new QMdiArea( 0 );
590
591 QWidget *widget = 0;
592 ws->show();
593
594 widget = new QWidget(ws);
595 widget->show();
596 QVERIFY( widget->isVisible() );
597
598 widget = new QWidget(ws);
599 widget->showMaximized();
600 QVERIFY( widget->isMaximized() );
601 widget->showNormal();
602 QVERIFY( !widget->isMaximized() );
603
604 widget = new QWidget(ws);
605 widget->showMinimized();
606 QVERIFY( widget->isMinimized() );
607 widget->showNormal();
608 QVERIFY( !widget->isMinimized() );
609
610 ws->hide();
611
612 widget = new QWidget(ws);
613 ws->show();
614 QVERIFY( widget->isVisible() );
615
616 ws->hide();
617
618 widget = new QWidget(ws);
619 widget->showMaximized();
620 QVERIFY( widget->isMaximized() );
621 ws->show();
622 QVERIFY( widget->isVisible() );
623 QVERIFY( widget->isMaximized() );
624 ws->hide();
625
626 widget = new QWidget(ws);
627 widget->showMinimized();
628 ws->show();
629 QVERIFY( widget->isMinimized() );
630 ws->hide();
631
632 delete ws;
633 }
634
635
636 //#define USE_SHOW
637
changeWindowTitle()638 void tst_QMdiArea::changeWindowTitle()
639 {
640 const QString mwc = QString::fromLatin1("MainWindow's Caption");
641 const QString mwc2 = QString::fromLatin1("MainWindow's New Caption");
642 const QString wc = QString::fromLatin1("Widget's Caption");
643 const QString wc2 = QString::fromLatin1("Widget's New Caption");
644
645 QMainWindow *mw = new QMainWindow;
646 mw->setWindowTitle( mwc );
647 QMdiArea *ws = new QMdiArea( mw );
648 mw->setCentralWidget( ws );
649 mw->menuBar();
650 mw->show();
651 QTest::qWaitForWindowShown(mw);
652
653 QWidget *widget = new QWidget( ws );
654 widget->setWindowTitle( wc );
655 ws->addSubWindow(widget);
656
657 QCOMPARE( mw->windowTitle(), mwc );
658
659 #ifdef USE_SHOW
660 widget->showMaximized();
661 #else
662 widget->setWindowState(Qt::WindowMaximized);
663 #endif
664 #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
665 QTRY_COMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc).arg(wc) );
666 #endif
667
668 mw->hide();
669 qApp->processEvents();
670 mw->show();
671 qApp->processEvents();
672 QTest::qWaitForWindowShown(mw);
673
674 #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
675 QTRY_COMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc).arg(wc) );
676 #endif
677
678 #ifdef USE_SHOW
679 widget->showNormal();
680 #else
681 widget->setWindowState(Qt::WindowNoState);
682 #endif
683 qApp->processEvents();
684 QCOMPARE( mw->windowTitle(), mwc );
685
686 #ifdef USE_SHOW
687 widget->showMaximized();
688 #else
689 widget->setWindowState(Qt::WindowMaximized);
690 #endif
691 qApp->processEvents();
692 #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
693 QTRY_COMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc).arg(wc) );
694 widget->setWindowTitle( wc2 );
695 QCOMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc).arg(wc2) );
696 mw->setWindowTitle( mwc2 );
697 QCOMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc2).arg(wc2) );
698 #endif
699
700 mw->show();
701 qApp->setActiveWindow(mw);
702
703 #ifdef USE_SHOW
704 mw->showFullScreen();
705 #else
706 mw->setWindowState(Qt::WindowFullScreen);
707 #endif
708
709 qApp->processEvents();
710 #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
711 QCOMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc2).arg(wc2) );
712 #endif
713 #ifdef USE_SHOW
714 widget->showNormal();
715 #else
716 widget->setWindowState(Qt::WindowNoState);
717 #endif
718 qApp->processEvents();
719 #if defined(Q_WS_MAC) || defined(Q_OS_WINCE) || defined(Q_OS_SYMBIAN)
720 QCOMPARE(mw->windowTitle(), mwc);
721 #else
722 QCOMPARE( mw->windowTitle(), mwc2 );
723 #endif
724
725 #ifdef USE_SHOW
726 widget->showMaximized();
727 #else
728 widget->setWindowState(Qt::WindowMaximized);
729 #endif
730 qApp->processEvents();
731 #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
732 QCOMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc2).arg(wc2) );
733 #endif
734
735 #ifdef USE_SHOW
736 mw->showNormal();
737 #else
738 mw->setWindowState(Qt::WindowNoState);
739 #endif
740 qApp->processEvents();
741 #ifdef USE_SHOW
742 widget->showNormal();
743 #else
744 widget->setWindowState(Qt::WindowNoState);
745 #endif
746
747 delete mw;
748 }
749
changeModified()750 void tst_QMdiArea::changeModified()
751 {
752 const QString mwc = QString::fromLatin1("MainWindow's Caption");
753 const QString wc = QString::fromLatin1("Widget's Caption[*]");
754
755 QMainWindow *mw = new QMainWindow(0);
756 mw->setWindowTitle( mwc );
757 QMdiArea *ws = new QMdiArea( mw );
758 mw->setCentralWidget( ws );
759 mw->menuBar();
760 mw->show();
761
762 QWidget *widget = new QWidget( ws );
763 widget->setWindowTitle( wc );
764 ws->addSubWindow(widget);
765
766 QCOMPARE( mw->isWindowModified(), false);
767 QCOMPARE( widget->isWindowModified(), false);
768 widget->setWindowState(Qt::WindowMaximized);
769 QCOMPARE( mw->isWindowModified(), false);
770 QCOMPARE( widget->isWindowModified(), false);
771
772 widget->setWindowState(Qt::WindowNoState);
773 QCOMPARE( mw->isWindowModified(), false);
774 QCOMPARE( widget->isWindowModified(), false);
775
776 widget->setWindowModified(true);
777 QCOMPARE( mw->isWindowModified(), false);
778 QCOMPARE( widget->isWindowModified(), true);
779 widget->setWindowState(Qt::WindowMaximized);
780 #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
781 QCOMPARE( mw->isWindowModified(), true);
782 #endif
783 QCOMPARE( widget->isWindowModified(), true);
784
785 widget->setWindowState(Qt::WindowNoState);
786 QCOMPARE( mw->isWindowModified(), false);
787 QCOMPARE( widget->isWindowModified(), true);
788
789 widget->setWindowState(Qt::WindowMaximized);
790 #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
791 QCOMPARE( mw->isWindowModified(), true);
792 #endif
793 QCOMPARE( widget->isWindowModified(), true);
794
795 widget->setWindowModified(false);
796 QCOMPARE( mw->isWindowModified(), false);
797 QCOMPARE( widget->isWindowModified(), false);
798
799 widget->setWindowModified(true);
800 #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
801 QCOMPARE( mw->isWindowModified(), true);
802 #endif
803 QCOMPARE( widget->isWindowModified(), true);
804
805 widget->setWindowState(Qt::WindowNoState);
806 QCOMPARE( mw->isWindowModified(), false);
807 QCOMPARE( widget->isWindowModified(), true);
808
809 delete mw;
810 }
811
812 class MyChild : public QWidget
813 {
814 public:
MyChild(QWidget * parent=0)815 MyChild(QWidget *parent = 0) : QWidget(parent) {}
sizeHint() const816 QSize sizeHint() const { return QSize(234, 123); }
817 };
818
childSize()819 void tst_QMdiArea::childSize()
820 {
821 QMdiArea ws;
822
823 MyChild *child = new MyChild(&ws);
824 child->show();
825 QCOMPARE(child->size(), child->sizeHint());
826 delete child;
827
828 child = new MyChild(&ws);
829 child->setFixedSize(200, 200);
830 child->show();
831 QCOMPARE(child->size(), child->minimumSize());
832 delete child;
833
834 child = new MyChild(&ws);
835 child->resize(150, 150);
836 child->show();
837 QCOMPARE(child->size(), QSize(150,150));
838 delete child;
839 }
840
fixedSize()841 void tst_QMdiArea::fixedSize()
842 {
843 QMdiArea *ws = new QMdiArea;
844 int i;
845
846 ws->resize(500, 500);
847 // ws->show();
848
849 QSize fixed(300, 300);
850 for (i = 0; i < 4; ++i) {
851 QWidget *child = new QWidget(ws);
852 child->setFixedSize(fixed);
853 child->show();
854 }
855
856 QList<QMdiSubWindow *> windows = ws->subWindowList();
857 for (i = 0; i < (int)windows.count(); ++i) {
858 QMdiSubWindow *child = windows.at(i);
859 QCOMPARE(child->size(), fixed);
860 }
861
862 ws->cascadeSubWindows();
863 ws->resize(800, 800);
864 for (i = 0; i < (int)windows.count(); ++i) {
865 QMdiSubWindow *child = windows.at(i);
866 QCOMPARE(child->size(), fixed);
867 }
868 ws->resize(500, 500);
869
870 ws->tileSubWindows();
871 ws->resize(800, 800);
872 for (i = 0; i < (int)windows.count(); ++i) {
873 QMdiSubWindow *child = windows.at(i);
874 QCOMPARE(child->size(), fixed);
875 }
876 ws->resize(500, 500);
877
878 for (i = 0; i < (int)windows.count(); ++i) {
879 QMdiSubWindow *child = windows.at(i);
880 delete child;
881 }
882
883 delete ws;
884 }
885
886 class LargeWidget : public QWidget
887 {
888 public:
LargeWidget(QWidget * parent=0)889 LargeWidget(QWidget *parent = 0) : QWidget(parent) {}
sizeHint() const890 QSize sizeHint() const { return QSize(1280, 1024); }
minimumSizeHint() const891 QSize minimumSizeHint() const { return QSize(300, 300); }
892 };
893
894 // New tests
minimumSizeHint()895 void tst_QMdiArea::minimumSizeHint()
896 {
897 QMdiArea workspace;
898 workspace.show();
899 QSize expectedSize(workspace.style()->pixelMetric(QStyle::PM_MDIMinimizedWidth),
900 workspace.style()->pixelMetric(QStyle::PM_TitleBarHeight));
901 qApp->processEvents();
902 QAbstractScrollArea dummyScrollArea;
903 dummyScrollArea.setFrameStyle(QFrame::NoFrame);
904 expectedSize = expectedSize.expandedTo(dummyScrollArea.minimumSizeHint());
905 QCOMPARE(workspace.minimumSizeHint(), expectedSize.expandedTo(qApp->globalStrut()));
906
907 QWidget *window = workspace.addSubWindow(new QWidget);
908 qApp->processEvents();
909 window->show();
910 QCOMPARE(workspace.minimumSizeHint(), expectedSize.expandedTo(window->minimumSizeHint()));
911
912 QMdiSubWindow *subWindow = workspace.addSubWindow(new LargeWidget);
913 subWindow->show();
914 QCOMPARE(workspace.minimumSizeHint(), expectedSize.expandedTo(subWindow->minimumSizeHint()));
915
916 workspace.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
917 workspace.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
918 QCOMPARE(workspace.minimumSizeHint(), expectedSize);
919 }
920
sizeHint()921 void tst_QMdiArea::sizeHint()
922 {
923 QMdiArea workspace;
924 workspace.show();
925 QSize desktopSize = QApplication::desktop()->size();
926 QSize expectedSize(desktopSize.width() * 2/3, desktopSize.height() * 2/3);
927 QCOMPARE(workspace.sizeHint(), expectedSize.expandedTo(qApp->globalStrut()));
928
929 QWidget *window = workspace.addSubWindow(new QWidget);
930 qApp->processEvents();
931 window->show();
932 QCOMPARE(workspace.sizeHint(), expectedSize.expandedTo(window->sizeHint()));
933
934 QMdiSubWindow *nested = workspace.addSubWindow(new QMdiArea);
935 expectedSize = QSize(desktopSize.width() * 2/6, desktopSize.height() * 2/6);
936 QCOMPARE(nested->widget()->sizeHint(), expectedSize);
937 }
938
setActiveSubWindow()939 void tst_QMdiArea::setActiveSubWindow()
940 {
941 QMdiArea workspace;
942 workspace.show();
943
944 QSignalSpy spy(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)));
945 connect(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(activeChanged(QMdiSubWindow *)));
946 qApp->setActiveWindow(&workspace);
947
948 // Activate hidden windows
949 const int windowCount = 10;
950 QMdiSubWindow *windows[windowCount];
951 for (int i = 0; i < windowCount; ++i) {
952 windows[i] = qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget));
953 qApp->processEvents();
954 QVERIFY(windows[i]->isHidden());
955 workspace.setActiveSubWindow(windows[i]);
956 }
957 QCOMPARE(spy.count(), 0);
958 QVERIFY(!activeWindow);
959 spy.clear();
960
961 // Activate visible windows
962 for (int i = 0; i < windowCount; ++i) {
963 windows[i]->show();
964 QVERIFY(!windows[i]->isHidden());
965 workspace.setActiveSubWindow(windows[i]);
966 qApp->processEvents();
967 QCOMPARE(spy.count(), 1);
968 QCOMPARE(activeWindow, windows[i]);
969 spy.clear();
970 }
971
972 // Deactivate active window
973 QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]);
974 workspace.setActiveSubWindow(0);
975 QCOMPARE(spy.count(), 1);
976 QVERIFY(!activeWindow);
977 QVERIFY(!workspace.activeSubWindow());
978
979 // Activate widget which is not child of any window inside workspace
980 QMdiSubWindow fakeWindow;
981 QTest::ignoreMessage(QtWarningMsg, "QMdiArea::setActiveSubWindow: window is not inside workspace");
982 workspace.setActiveSubWindow(&fakeWindow);
983
984 }
985
activeSubWindow()986 void tst_QMdiArea::activeSubWindow()
987 {
988 QMainWindow mainWindow;
989
990 QMdiArea *mdiArea = new QMdiArea;
991 QLineEdit *subWindowLineEdit = new QLineEdit;
992 QMdiSubWindow *subWindow = mdiArea->addSubWindow(subWindowLineEdit);
993 mainWindow.setCentralWidget(mdiArea);
994
995 QDockWidget *dockWidget = new QDockWidget(QLatin1String("Dock Widget"), &mainWindow);
996 dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea);
997 QLineEdit *dockWidgetLineEdit = new QLineEdit;
998 dockWidget->setWidget(dockWidgetLineEdit);
999 mainWindow.addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
1000
1001 mainWindow.show();
1002 #ifdef Q_WS_X11
1003 qt_x11_wait_for_window_manager(&mainWindow);
1004 #endif
1005
1006 qApp->setActiveWindow(&mainWindow);
1007 QCOMPARE(mdiArea->activeSubWindow(), subWindow);
1008 QCOMPARE(qApp->focusWidget(), (QWidget *)subWindowLineEdit);
1009
1010 dockWidgetLineEdit->setFocus();
1011 QCOMPARE(qApp->focusWidget(), (QWidget *)dockWidgetLineEdit);
1012 QCOMPARE(mdiArea->activeSubWindow(), subWindow);
1013
1014 QEvent deactivateEvent(QEvent::WindowDeactivate);
1015 qApp->sendEvent(subWindow, &deactivateEvent);
1016 QVERIFY(!mdiArea->activeSubWindow());
1017 QCOMPARE(qApp->focusWidget(), (QWidget *)dockWidgetLineEdit);
1018
1019 QEvent activateEvent(QEvent::WindowActivate);
1020 qApp->sendEvent(subWindow, &activateEvent);
1021 QCOMPARE(mdiArea->activeSubWindow(), subWindow);
1022 QCOMPARE(qApp->focusWidget(), (QWidget *)subWindowLineEdit);
1023
1024 QLineEdit dummyTopLevel;
1025 dummyTopLevel.show();
1026 #ifdef Q_WS_X11
1027 qt_x11_wait_for_window_manager(&dummyTopLevel);
1028 #endif
1029
1030 qApp->setActiveWindow(&dummyTopLevel);
1031 QCOMPARE(mdiArea->activeSubWindow(), subWindow);
1032
1033 qApp->setActiveWindow(&mainWindow);
1034 QCOMPARE(mdiArea->activeSubWindow(), subWindow);
1035
1036 #if !defined(Q_WS_MAC) && !defined(Q_WS_WIN)
1037 qApp->setActiveWindow(0);
1038 QVERIFY(!mdiArea->activeSubWindow());
1039 #endif
1040
1041 //task 202657
1042 dockWidgetLineEdit->setFocus();
1043 qApp->setActiveWindow(&mainWindow);
1044 QVERIFY(dockWidgetLineEdit->hasFocus());
1045 }
1046
currentSubWindow()1047 void tst_QMdiArea::currentSubWindow()
1048 {
1049 QMdiArea mdiArea;
1050 mdiArea.show();
1051 #ifdef Q_WS_X11
1052 qt_x11_wait_for_window_manager(&mdiArea);
1053 #endif
1054
1055 for (int i = 0; i < 5; ++i)
1056 mdiArea.addSubWindow(new QLineEdit)->show();
1057
1058 qApp->setActiveWindow(&mdiArea);
1059 QCOMPARE(qApp->activeWindow(), (QWidget *)&mdiArea);
1060
1061 // Check that the last added window is the active and the current.
1062 QMdiSubWindow *active = mdiArea.activeSubWindow();
1063 QVERIFY(active);
1064 QCOMPARE(mdiArea.subWindowList().back(), active);
1065 QCOMPARE(mdiArea.currentSubWindow(), active);
1066
1067 QLineEdit dummyTopLevel;
1068 dummyTopLevel.show();
1069 #ifdef Q_WS_X11
1070 qt_x11_wait_for_window_manager(&dummyTopLevel);
1071 #endif
1072
1073 // Move focus to another top-level and check that we still
1074 // have an active window.
1075 qApp->setActiveWindow(&dummyTopLevel);
1076 QCOMPARE(qApp->activeWindow(), (QWidget *)&dummyTopLevel);
1077 QVERIFY(mdiArea.activeSubWindow());
1078
1079 delete active;
1080 active = 0;
1081
1082 // We just deleted the current sub-window -> current should then
1083 // be the next in list (which in this case is the first sub-window).
1084 QVERIFY(mdiArea.currentSubWindow());
1085 QCOMPARE(mdiArea.currentSubWindow(), mdiArea.subWindowList().front());
1086
1087 // Activate mdi area and check that active == current.
1088 qApp->setActiveWindow(&mdiArea);
1089 active = mdiArea.activeSubWindow();
1090 QVERIFY(active);
1091 QCOMPARE(mdiArea.activeSubWindow(), mdiArea.subWindowList().front());
1092
1093 active->hide();
1094 QCOMPARE(mdiArea.activeSubWindow(), active);
1095 QCOMPARE(mdiArea.currentSubWindow(), active);
1096
1097 qApp->setActiveWindow(&dummyTopLevel);
1098 QVERIFY(mdiArea.activeSubWindow());
1099 QCOMPARE(mdiArea.currentSubWindow(), active);
1100
1101 qApp->setActiveWindow(&mdiArea);
1102 active->show();
1103 QCOMPARE(mdiArea.activeSubWindow(), active);
1104
1105 mdiArea.setActiveSubWindow(0);
1106 QVERIFY(!mdiArea.activeSubWindow());
1107 QVERIFY(!mdiArea.currentSubWindow());
1108
1109 mdiArea.setActiveSubWindow(active);
1110 QCOMPARE(mdiArea.activeSubWindow(), active);
1111 QEvent windowDeactivate(QEvent::WindowDeactivate);
1112 qApp->sendEvent(active, &windowDeactivate);
1113 QVERIFY(!mdiArea.activeSubWindow());
1114 QVERIFY(!mdiArea.currentSubWindow());
1115
1116 QEvent windowActivate(QEvent::WindowActivate);
1117 qApp->sendEvent(active, &windowActivate);
1118 QVERIFY(mdiArea.activeSubWindow());
1119 QVERIFY(mdiArea.currentSubWindow());
1120
1121 #if !defined(Q_WS_MAC) && !defined(Q_WS_WIN)
1122 qApp->setActiveWindow(0);
1123 QVERIFY(!mdiArea.activeSubWindow());
1124 QVERIFY(mdiArea.currentSubWindow());
1125 #endif
1126 }
1127
addAndRemoveWindows()1128 void tst_QMdiArea::addAndRemoveWindows()
1129 {
1130 QWidget topLevel;
1131 QMdiArea workspace(&topLevel);
1132 workspace.resize(800, 600);
1133 topLevel.show();
1134 #ifdef Q_WS_X11
1135 qt_x11_wait_for_window_manager(&workspace);
1136 #endif
1137
1138 { // addSubWindow with large widget
1139 QCOMPARE(workspace.subWindowList().count(), 0);
1140 QWidget *window = workspace.addSubWindow(new LargeWidget);
1141 QVERIFY(window);
1142 qApp->processEvents();
1143 QCOMPARE(workspace.subWindowList().count(), 1);
1144 QVERIFY(window->windowFlags() == DefaultWindowFlags);
1145 QCOMPARE(window->size(), workspace.viewport()->size());
1146 }
1147
1148 { // addSubWindow, minimumSize set.
1149 QMdiSubWindow *window = new QMdiSubWindow;
1150 window->setMinimumSize(900, 900);
1151 workspace.addSubWindow(window);
1152 QVERIFY(window);
1153 qApp->processEvents();
1154 QCOMPARE(workspace.subWindowList().count(), 2);
1155 QVERIFY(window->windowFlags() == DefaultWindowFlags);
1156 QCOMPARE(window->size(), window->minimumSize());
1157 }
1158
1159 { // addSubWindow, resized
1160 QMdiSubWindow *window = new QMdiSubWindow;
1161 window->setWidget(new QWidget);
1162 window->resize(1500, 1500);
1163 workspace.addSubWindow(window);
1164 QVERIFY(window);
1165 qApp->processEvents();
1166 QCOMPARE(workspace.subWindowList().count(), 3);
1167 QVERIFY(window->windowFlags() == DefaultWindowFlags);
1168 QCOMPARE(window->size(), QSize(1500, 1500));
1169 }
1170
1171 { // addSubWindow with 0 pointer
1172 QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: null pointer to widget");
1173 QWidget *window = workspace.addSubWindow(0);
1174 QVERIFY(!window);
1175 QCOMPARE(workspace.subWindowList().count(), 3);
1176 }
1177
1178 { // addChildWindow
1179 QMdiSubWindow *window = new QMdiSubWindow;
1180 workspace.addSubWindow(window);
1181 qApp->processEvents();
1182 QVERIFY(window->windowFlags() == DefaultWindowFlags);
1183 window->setWidget(new QWidget);
1184 QCOMPARE(workspace.subWindowList().count(), 4);
1185 QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: window is already added");
1186 workspace.addSubWindow(window);
1187 }
1188
1189 { // addChildWindow with 0 pointer
1190 QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: null pointer to widget");
1191 workspace.addSubWindow(0);
1192 QCOMPARE(workspace.subWindowList().count(), 4);
1193 }
1194
1195 // removeSubWindow
1196 foreach (QWidget *window, workspace.subWindowList()) {
1197 workspace.removeSubWindow(window);
1198 delete window;
1199 }
1200 QCOMPARE(workspace.subWindowList().count(), 0);
1201
1202 // removeSubWindow with 0 pointer
1203 QTest::ignoreMessage(QtWarningMsg, "QMdiArea::removeSubWindow: null pointer to widget");
1204 workspace.removeSubWindow(0);
1205
1206 workspace.addSubWindow(new QPushButton(QLatin1String("Dummy to make workspace non-empty")));
1207 qApp->processEvents();
1208 QCOMPARE(workspace.subWindowList().count(), 1);
1209
1210 // removeSubWindow with window not inside workspace
1211 QTest::ignoreMessage(QtWarningMsg,"QMdiArea::removeSubWindow: window is not inside workspace");
1212 QMdiSubWindow *fakeWindow = new QMdiSubWindow;
1213 workspace.removeSubWindow(fakeWindow);
1214 delete fakeWindow;
1215
1216 // Check that newly added windows don't occupy maximized windows'
1217 // restore space.
1218 workspace.closeAllSubWindows();
1219 workspace.setOption(QMdiArea::DontMaximizeSubWindowOnActivation);
1220 workspace.show();
1221 QMdiSubWindow *window1 = workspace.addSubWindow(new QWidget);
1222 window1->show();
1223 const QRect window1RestoreGeometry = window1->geometry();
1224 QCOMPARE(window1RestoreGeometry.topLeft(), QPoint(0, 0));
1225
1226 window1->showMinimized();
1227
1228 // Occupy space.
1229 QMdiSubWindow *window2 = workspace.addSubWindow(new QWidget);
1230 window2->show();
1231 const QRect window2RestoreGeometry = window2->geometry();
1232 QCOMPARE(window2RestoreGeometry.topLeft(), QPoint(0, 0));
1233
1234 window2->showMaximized();
1235
1236 // Don't occupy space.
1237 QMdiSubWindow *window3 = workspace.addSubWindow(new QWidget);
1238 window3->show();
1239 QCOMPARE(window3->geometry().topLeft(), QPoint(window2RestoreGeometry.right() + 1, 0));
1240 }
1241
addAndRemoveWindowsWithReparenting()1242 void tst_QMdiArea::addAndRemoveWindowsWithReparenting()
1243 {
1244 QMdiArea workspace;
1245 QMdiSubWindow window(&workspace);
1246 QVERIFY(window.windowFlags() == DefaultWindowFlags);
1247
1248 // 0 because the window list contains widgets and not actual
1249 // windows. Silly, but that's the behavior.
1250 QCOMPARE(workspace.subWindowList().count(), 0);
1251 window.setWidget(new QWidget);
1252 qApp->processEvents();
1253
1254 QCOMPARE(workspace.subWindowList().count(), 1);
1255 window.setParent(0); // Will also reset window flags
1256 QCOMPARE(workspace.subWindowList().count(), 0);
1257 window.setParent(&workspace);
1258 QCOMPARE(workspace.subWindowList().count(), 1);
1259 QVERIFY(window.windowFlags() == DefaultWindowFlags);
1260
1261 QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: window is already added");
1262 workspace.addSubWindow(&window);
1263 QCOMPARE(workspace.subWindowList().count(), 1);
1264 }
1265
1266 class MySubWindow : public QMdiSubWindow
1267 {
1268 public:
1269 using QObject::receivers;
1270 };
1271
numberOfConnectedSignals(MySubWindow * subWindow)1272 static int numberOfConnectedSignals(MySubWindow *subWindow)
1273 {
1274 if (!subWindow)
1275 return 0;
1276
1277 int numConnectedSignals = 0;
1278 for (int i = 0; i < subWindow->metaObject()->methodCount(); ++i) {
1279 QMetaMethod method = subWindow->metaObject()->method(i);
1280 if (method.methodType() == QMetaMethod::Signal) {
1281 QString signature(QLatin1String("2"));
1282 signature += QLatin1String(method.signature());
1283 numConnectedSignals += subWindow->receivers(signature.toLatin1());
1284 }
1285 }
1286 return numConnectedSignals;
1287 }
1288
removeSubWindow_2()1289 void tst_QMdiArea::removeSubWindow_2()
1290 {
1291 QMdiArea mdiArea;
1292 MySubWindow *subWindow = new MySubWindow;
1293 QCOMPARE(numberOfConnectedSignals(subWindow), 0);
1294
1295 // Connected to aboutToActivate() and windowStateChanged().
1296 mdiArea.addSubWindow(subWindow);
1297 QVERIFY(numberOfConnectedSignals(subWindow) >= 2);
1298
1299 // Ensure we disconnect from all signals.
1300 mdiArea.removeSubWindow(subWindow);
1301 QCOMPARE(numberOfConnectedSignals(subWindow), 0);
1302
1303 mdiArea.addSubWindow(subWindow);
1304 QVERIFY(numberOfConnectedSignals(subWindow) >= 2);
1305 subWindow->setParent(0);
1306 QCOMPARE(numberOfConnectedSignals(subWindow), 0);
1307 }
1308
closeWindows()1309 void tst_QMdiArea::closeWindows()
1310 {
1311 QMdiArea workspace;
1312 workspace.show();
1313 qApp->setActiveWindow(&workspace);
1314
1315 // Close widget
1316 QWidget *widget = new QWidget;
1317 QMdiSubWindow *subWindow = workspace.addSubWindow(widget);
1318 qApp->processEvents();
1319 QCOMPARE(workspace.subWindowList().count(), 1);
1320 subWindow->close();
1321 QCOMPARE(workspace.subWindowList().count(), 0);
1322
1323 // Close window
1324 QWidget *window = workspace.addSubWindow(new QWidget);
1325 qApp->processEvents();
1326 QCOMPARE(workspace.subWindowList().count(), 1);
1327 window->close();
1328 qApp->processEvents();
1329 QCOMPARE(workspace.subWindowList().count(), 0);
1330
1331 const int windowCount = 10;
1332
1333 // Close active window
1334 for (int i = 0; i < windowCount; ++i)
1335 workspace.addSubWindow(new QWidget)->show();
1336 qApp->processEvents();
1337 QCOMPARE(workspace.subWindowList().count(), windowCount);
1338 int activeSubWindowCount = 0;
1339 while (workspace.activeSubWindow()) {
1340 workspace.activeSubWindow()->close();
1341 qApp->processEvents();
1342 ++activeSubWindowCount;
1343 }
1344 QCOMPARE(activeSubWindowCount, windowCount);
1345 QCOMPARE(workspace.subWindowList().count(), 0);
1346
1347 // Close all windows
1348 for (int i = 0; i < windowCount; ++i)
1349 workspace.addSubWindow(new QWidget)->show();
1350 qApp->processEvents();
1351 QCOMPARE(workspace.subWindowList().count(), windowCount);
1352 QSignalSpy spy(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)));
1353 connect(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(activeChanged(QMdiSubWindow *)));
1354 workspace.closeAllSubWindows();
1355 qApp->processEvents();
1356 QCOMPARE(workspace.subWindowList().count(), 0);
1357 QCOMPARE(spy.count(), 1);
1358 QVERIFY(!activeWindow);
1359 }
1360
activateNextAndPreviousWindow()1361 void tst_QMdiArea::activateNextAndPreviousWindow()
1362 {
1363 QMdiArea workspace;
1364 workspace.show();
1365 qApp->setActiveWindow(&workspace);
1366
1367 const int windowCount = 10;
1368 QMdiSubWindow *windows[windowCount];
1369 for (int i = 0; i < windowCount; ++i) {
1370 windows[i] = qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget));
1371 windows[i]->show();
1372 qApp->processEvents();
1373 }
1374
1375 QSignalSpy spy(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)));
1376 connect(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(activeChanged(QMdiSubWindow *)));
1377
1378 // activateNextSubWindow
1379 for (int i = 0; i < windowCount; ++i) {
1380 workspace.activateNextSubWindow();
1381 qApp->processEvents();
1382 QCOMPARE(workspace.activeSubWindow(), windows[i]);
1383 QCOMPARE(spy.count(), 1);
1384 spy.clear();
1385 }
1386 QVERIFY(activeWindow);
1387 QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]);
1388 QCOMPARE(workspace.activeSubWindow(), activeWindow);
1389
1390 // activatePreviousSubWindow
1391 for (int i = windowCount - 2; i >= 0; --i) {
1392 workspace.activatePreviousSubWindow();
1393 qApp->processEvents();
1394 QCOMPARE(workspace.activeSubWindow(), windows[i]);
1395 QCOMPARE(spy.count(), 1);
1396 spy.clear();
1397 if (i % 2 == 0)
1398 windows[i]->hide(); // 10, 8, 6, 4, 2, 0
1399 }
1400 QVERIFY(activeWindow);
1401 QCOMPARE(workspace.activeSubWindow(), windows[0]);
1402 QCOMPARE(workspace.activeSubWindow(), activeWindow);
1403
1404 // activateNextSubWindow with every 2nd window hidden
1405 for (int i = 0; i < windowCount / 2; ++i) {
1406 workspace.activateNextSubWindow(); // 1, 3, 5, 7, 9
1407 QCOMPARE(spy.count(), 1);
1408 spy.clear();
1409 }
1410 QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]);
1411
1412 // activatePreviousSubWindow with every 2nd window hidden
1413 for (int i = 0; i < windowCount / 2; ++i) {
1414 workspace.activatePreviousSubWindow(); // 7, 5, 3, 1, 9
1415 QCOMPARE(spy.count(), 1);
1416 spy.clear();
1417 }
1418 QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]);
1419
1420 workspace.setActiveSubWindow(0);
1421 QVERIFY(!activeWindow);
1422 }
1423
subWindowList_data()1424 void tst_QMdiArea::subWindowList_data()
1425 {
1426 QTest::addColumn<QMdiArea::WindowOrder>("windowOrder");
1427 QTest::addColumn<int>("windowCount");
1428 QTest::addColumn<int>("activeSubWindow");
1429 QTest::addColumn<int>("staysOnTop1");
1430 QTest::addColumn<int>("staysOnTop2");
1431
1432 QTest::newRow("CreationOrder") << QMdiArea::CreationOrder << 10 << 4 << 8 << 5;
1433 QTest::newRow("StackingOrder") << QMdiArea::StackingOrder << 10 << 6 << 3 << 9;
1434 QTest::newRow("ActivationHistoryOrder") << QMdiArea::ActivationHistoryOrder << 10 << 7 << 2 << 1;
1435 }
subWindowList()1436 void tst_QMdiArea::subWindowList()
1437 {
1438 QFETCH(QMdiArea::WindowOrder, windowOrder);
1439 QFETCH(int, windowCount);
1440 QFETCH(int, activeSubWindow);
1441 QFETCH(int, staysOnTop1);
1442 QFETCH(int, staysOnTop2);
1443
1444 QMdiArea workspace;
1445 workspace.show();
1446 qApp->setActiveWindow(&workspace);
1447
1448 QList<QMdiSubWindow *> activationOrder;
1449 QVector<QMdiSubWindow *> windows;
1450 for (int i = 0; i < windowCount; ++i) {
1451 windows.append(qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget)));
1452 windows[i]->show();
1453 activationOrder.append(windows[i]);
1454 }
1455
1456 {
1457 QList<QMdiSubWindow *> widgets = workspace.subWindowList(windowOrder);
1458 QCOMPARE(widgets.count(), windowCount);
1459 for (int i = 0; i < widgets.count(); ++i)
1460 QCOMPARE(widgets.at(i), windows[i]);
1461 }
1462
1463 windows[staysOnTop1]->setWindowFlags(windows[staysOnTop1]->windowFlags() | Qt::WindowStaysOnTopHint);
1464 workspace.setActiveSubWindow(windows[activeSubWindow]);
1465 qApp->processEvents();
1466 QCOMPARE(workspace.activeSubWindow(), windows[activeSubWindow]);
1467 activationOrder.move(activationOrder.indexOf(windows[activeSubWindow]), windowCount - 1);
1468
1469 QList<QMdiSubWindow *> subWindows = workspace.subWindowList(windowOrder);
1470 if (windowOrder == QMdiArea::CreationOrder) {
1471 QCOMPARE(subWindows.at(activeSubWindow), windows[activeSubWindow]);
1472 QCOMPARE(subWindows.at(staysOnTop1), windows[staysOnTop1]);
1473 for (int i = 0; i < windowCount; ++i)
1474 QCOMPARE(subWindows.at(i), windows[i]);
1475 return;
1476 }
1477
1478 if (windowOrder == QMdiArea::StackingOrder) {
1479 QCOMPARE(subWindows.at(subWindows.count() - 1), windows[staysOnTop1]);
1480 QCOMPARE(subWindows.at(subWindows.count() - 2), windows[activeSubWindow]);
1481 QCOMPARE(subWindows.count(), windowCount);
1482 } else { // ActivationHistoryOrder
1483 QCOMPARE(subWindows, activationOrder);
1484 }
1485
1486 windows[staysOnTop2]->setWindowFlags(windows[staysOnTop2]->windowFlags() | Qt::WindowStaysOnTopHint);
1487 workspace.setActiveSubWindow(windows[staysOnTop2]);
1488 qApp->processEvents();
1489 QCOMPARE(workspace.activeSubWindow(), windows[staysOnTop2]);
1490 activationOrder.move(activationOrder.indexOf(windows[staysOnTop2]), windowCount - 1);
1491
1492 workspace.setActiveSubWindow(windows[activeSubWindow]);
1493 qApp->processEvents();
1494 QCOMPARE(workspace.activeSubWindow(), windows[activeSubWindow]);
1495 activationOrder.move(activationOrder.indexOf(windows[activeSubWindow]), windowCount - 1);
1496
1497 QList<QMdiSubWindow *> widgets = workspace.subWindowList(windowOrder);
1498 QCOMPARE(widgets.count(), windowCount);
1499 if (windowOrder == QMdiArea::StackingOrder) {
1500 QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop2]);
1501 QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]);
1502 QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]);
1503 } else { // ActivationHistory
1504 QCOMPARE(widgets, activationOrder);
1505 }
1506
1507 windows[activeSubWindow]->raise();
1508 windows[staysOnTop2]->lower();
1509
1510 widgets = workspace.subWindowList(windowOrder);
1511 if (windowOrder == QMdiArea::StackingOrder) {
1512 QCOMPARE(widgets.at(widgets.count() - 1), windows[activeSubWindow]);
1513 QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]);
1514 QCOMPARE(widgets.at(0), windows[staysOnTop2]);
1515 } else { // ActivationHistoryOrder
1516 QCOMPARE(widgets, activationOrder);
1517 }
1518
1519 windows[activeSubWindow]->stackUnder(windows[staysOnTop1]);
1520 windows[staysOnTop2]->raise();
1521
1522 widgets = workspace.subWindowList(windowOrder);
1523 if (windowOrder == QMdiArea::StackingOrder) {
1524 QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop2]);
1525 QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]);
1526 QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]);
1527 } else { // ActivationHistoryOrder
1528 QCOMPARE(widgets, activationOrder);
1529 }
1530
1531 workspace.setActiveSubWindow(windows[staysOnTop1]);
1532 activationOrder.move(activationOrder.indexOf(windows[staysOnTop1]), windowCount - 1);
1533
1534 widgets = workspace.subWindowList(windowOrder);
1535 if (windowOrder == QMdiArea::StackingOrder) {
1536 QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop1]);
1537 QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop2]);
1538 QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]);
1539 } else { // ActivationHistoryOrder
1540 QCOMPARE(widgets, activationOrder);
1541 }
1542 }
1543
setBackground()1544 void tst_QMdiArea::setBackground()
1545 {
1546 QMdiArea workspace;
1547 QCOMPARE(workspace.background(), workspace.palette().brush(QPalette::Dark));
1548 workspace.setBackground(QBrush(Qt::green));
1549 QCOMPARE(workspace.background(), QBrush(Qt::green));
1550 }
1551
setViewport()1552 void tst_QMdiArea::setViewport()
1553 {
1554 QMdiArea workspace;
1555 workspace.show();
1556
1557 QWidget *firstViewport = workspace.viewport();
1558 QVERIFY(firstViewport);
1559
1560 const int windowCount = 10;
1561 for (int i = 0; i < windowCount; ++i) {
1562 QMdiSubWindow *window = workspace.addSubWindow(new QWidget);
1563 window->show();
1564 if (i % 2 == 0) {
1565 window->showMinimized();
1566 QVERIFY(window->isMinimized());
1567 } else {
1568 window->showMaximized();
1569 QVERIFY(window->isMaximized());
1570 }
1571 }
1572
1573 qApp->processEvents();
1574 QList<QMdiSubWindow *> windowsBeforeViewportChange = workspace.subWindowList();
1575 QCOMPARE(windowsBeforeViewportChange.count(), windowCount);
1576
1577 workspace.setViewport(new QWidget);
1578 qApp->processEvents();
1579 QVERIFY(workspace.viewport() != firstViewport);
1580
1581 QList<QMdiSubWindow *> windowsAfterViewportChange = workspace.subWindowList();
1582 QCOMPARE(windowsAfterViewportChange.count(), windowCount);
1583 QCOMPARE(windowsAfterViewportChange, windowsBeforeViewportChange);
1584
1585 // for (int i = 0; i < windowCount; ++i) {
1586 // QMdiSubWindow *window = windowsAfterViewportChange.at(i);
1587 // if (i % 2 == 0)
1588 // QVERIFY(!window->isMinimized());
1589 //else
1590 // QVERIFY(!window->isMaximized());
1591 // }
1592
1593 QTest::ignoreMessage(QtWarningMsg, "QMdiArea: Deleting the view port is undefined, "
1594 "use setViewport instead.");
1595 delete workspace.viewport();
1596 qApp->processEvents();
1597
1598 QCOMPARE(workspace.subWindowList().count(), 0);
1599 QVERIFY(!workspace.activeSubWindow());
1600 }
1601
tileSubWindows()1602 void tst_QMdiArea::tileSubWindows()
1603 {
1604 QMdiArea workspace;
1605 workspace.resize(600,480);
1606 if (PlatformQuirks::isAutoMaximizing())
1607 workspace.setWindowFlags(workspace.windowFlags() | Qt::X11BypassWindowManagerHint);
1608 workspace.show();
1609 #ifdef Q_WS_X11
1610 qt_x11_wait_for_window_manager(&workspace);
1611 #endif
1612
1613 const int windowCount = 10;
1614 for (int i = 0; i < windowCount; ++i) {
1615 QMdiSubWindow *subWindow = workspace.addSubWindow(new QWidget);
1616 subWindow->setMinimumSize(50, 30);
1617 subWindow->show();
1618 }
1619 workspace.tileSubWindows();
1620 workspace.setActiveSubWindow(0);
1621 QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1622
1623 QList<QMdiSubWindow *> windows = workspace.subWindowList();
1624 for (int i = 0; i < windowCount; ++i) {
1625 QMdiSubWindow *window = windows.at(i);
1626 for (int j = 0; j < windowCount; ++j) {
1627 if (i == j)
1628 continue;
1629 QVERIFY(!window->geometry().intersects(windows.at(j)->geometry()));
1630 }
1631 }
1632
1633 // Keep the views tiled through any subsequent resize events.
1634 for (int i = 0; i < 5; ++i) {
1635 workspace.resize(workspace.size() - QSize(10, 10));
1636 qApp->processEvents();
1637 }
1638 workspace.setActiveSubWindow(0);
1639 #ifndef Q_OS_WINCE //See Task 197453 ToDo
1640 QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1641 #endif
1642
1643 QMdiSubWindow *window = windows.at(0);
1644
1645 // Change the geometry of one of the children and verify
1646 // that the views are not tiled anymore.
1647 window->move(window->x() + 1, window->y());
1648 workspace.resize(workspace.size() - QSize(10, 10));
1649 workspace.setActiveSubWindow(0);
1650 QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1651 qApp->processEvents();
1652
1653 // Re-tile.
1654 workspace.tileSubWindows();
1655 workspace.setActiveSubWindow(0);
1656 QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1657
1658 // Close one of the children and verify that the views
1659 // are not tiled anymore.
1660 window->close();
1661 workspace.resize(workspace.size() - QSize(10, 10));
1662 workspace.setActiveSubWindow(0);
1663 QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1664 qApp->processEvents();
1665
1666 // Re-tile.
1667 workspace.tileSubWindows();
1668 workspace.setActiveSubWindow(0);
1669 QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1670
1671 window = windows.at(1);
1672
1673 // Maximize one of the children and verify that the views
1674 // are not tiled anymore.
1675 workspace.tileSubWindows();
1676 window->showMaximized();
1677 workspace.resize(workspace.size() - QSize(10, 10));
1678 workspace.setActiveSubWindow(0);
1679 QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1680 qApp->processEvents();
1681
1682 // Re-tile.
1683 workspace.tileSubWindows();
1684 workspace.setActiveSubWindow(0);
1685 QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1686
1687 // Minimize one of the children and verify that the views
1688 // are not tiled anymore.
1689 workspace.tileSubWindows();
1690 window->showMinimized();
1691 workspace.resize(workspace.size() - QSize(10, 10));
1692 workspace.setActiveSubWindow(0);
1693 QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1694 qApp->processEvents();
1695
1696 // Re-tile.
1697 workspace.tileSubWindows();
1698 workspace.setActiveSubWindow(0);
1699 QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1700
1701 // Active/deactivate windows and verify that the views are tiled.
1702 workspace.setActiveSubWindow(windows.at(5));
1703 workspace.resize(workspace.size() - QSize(10, 10));
1704 workspace.setActiveSubWindow(0);
1705 QTest::qWait(250); // delayed re-arrange of minimized windows
1706 QTRY_COMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1707
1708 // Add another window and verify that the views are not tiled anymore.
1709 workspace.addSubWindow(new QPushButton(QLatin1String("I'd like to mess up tiled views")))->show();
1710 workspace.resize(workspace.size() - QSize(10, 10));
1711 workspace.setActiveSubWindow(0);
1712 QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1713
1714 // Re-tile.
1715 workspace.tileSubWindows();
1716 workspace.setActiveSubWindow(0);
1717 QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect());
1718
1719 // Cascade and verify that the views are not tiled anymore.
1720 workspace.cascadeSubWindows();
1721 workspace.resize(workspace.size() - QSize(10, 10));
1722 workspace.setActiveSubWindow(0);
1723 QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect());
1724
1725 // Make sure the active window is placed in top left corner regardless
1726 // of whether we have any windows with staysOnTopHint or not.
1727 windows.at(3)->setWindowFlags(windows.at(3)->windowFlags() | Qt::WindowStaysOnTopHint);
1728 QMdiSubWindow *activeSubWindow = windows.at(6);
1729 workspace.setActiveSubWindow(activeSubWindow);
1730 QCOMPARE(workspace.activeSubWindow(), activeSubWindow);
1731 workspace.tileSubWindows();
1732 QCOMPARE(activeSubWindow->geometry().topLeft(), QPoint(0, 0));
1733
1734 // Verify that we try to resize the area such that all sub-windows are visible.
1735 // It's important that tiled windows are NOT overlapping.
1736 workspace.resize(350, 150);
1737 qApp->processEvents();
1738 QTRY_COMPARE(workspace.size(), QSize(350, 150));
1739
1740 const QSize minSize(300, 100);
1741 foreach (QMdiSubWindow *subWindow, workspace.subWindowList())
1742 subWindow->setMinimumSize(minSize);
1743
1744 QCOMPARE(workspace.size(), QSize(350, 150));
1745 workspace.tileSubWindows();
1746 // The sub-windows are now tiled like this:
1747 // | win 1 || win 2 || win 3 |
1748 // +-------++-------++-------+
1749 // +-------++-------++-------+
1750 // | win 4 || win 5 || win 6 |
1751 // +-------++-------++-------+
1752 // +-------++-------++-------+
1753 // | win 7 || win 8 || win 9 |
1754 workspace.setActiveSubWindow(0);
1755 int frameWidth = 0;
1756 if (workspace.style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, &workspace))
1757 frameWidth = workspace.style()->pixelMetric(QStyle::PM_DefaultFrameWidth);
1758 const int spacing = 2 * frameWidth + 2;
1759 const QSize expectedViewportSize(3 * minSize.width() + spacing, 3 * minSize.height() + spacing);
1760 #ifdef Q_OS_WINCE
1761 QSKIP("Not fixed yet! See task 197453", SkipAll);
1762 #endif
1763 QTRY_COMPARE(workspace.viewport()->rect().size(), expectedViewportSize);
1764
1765 // Not enough space for all sub-windows to be visible -> provide scroll bars.
1766 workspace.resize(160, 150);
1767 qApp->processEvents();
1768 QTRY_COMPARE(workspace.size(), QSize(160, 150));
1769
1770 // Horizontal scroll bar.
1771 QScrollBar *hBar = workspace.horizontalScrollBar();
1772 QCOMPARE(workspace.horizontalScrollBarPolicy(), Qt::ScrollBarAsNeeded);
1773 QTRY_VERIFY(hBar->isVisible());
1774 QCOMPARE(hBar->value(), 0);
1775 QCOMPARE(hBar->minimum(), 0);
1776
1777 // Vertical scroll bar.
1778 QScrollBar *vBar = workspace.verticalScrollBar();
1779 QCOMPARE(workspace.verticalScrollBarPolicy(), Qt::ScrollBarAsNeeded);
1780 QVERIFY(vBar->isVisible());
1781 QCOMPARE(vBar->value(), 0);
1782 QCOMPARE(vBar->minimum(), 0);
1783
1784 workspace.tileSubWindows();
1785 #ifdef Q_WS_X11
1786 qt_x11_wait_for_window_manager(&workspace);
1787 #endif
1788 qApp->processEvents();
1789
1790 QTRY_VERIFY(workspace.size() != QSize(150, 150));
1791 QTRY_VERIFY(!vBar->isVisible());
1792 #if defined(UBUNTU_LUCID) && !defined(Q_WS_QWS)
1793 QEXPECT_FAIL("", "QTBUG-26726", Abort);
1794 #endif
1795 QTRY_VERIFY(!hBar->isVisible());
1796 }
1797
cascadeAndTileSubWindows()1798 void tst_QMdiArea::cascadeAndTileSubWindows()
1799 {
1800 QMdiArea workspace;
1801 workspace.resize(400, 400);
1802 workspace.show();
1803 #ifdef Q_WS_X11
1804 qt_x11_wait_for_window_manager(&workspace);
1805 #endif
1806
1807 const int windowCount = 10;
1808 QList<QMdiSubWindow *> windows;
1809 for (int i = 0; i < windowCount; ++i) {
1810 QMdiSubWindow *window = workspace.addSubWindow(new MyChild);
1811 if (i % 3 == 0) {
1812 window->showMinimized();
1813 QVERIFY(window->isMinimized());
1814 } else {
1815 window->showMaximized();
1816 QVERIFY(window->isMaximized());
1817 }
1818 windows.append(window);
1819 }
1820
1821 // cascadeSubWindows
1822 qApp->processEvents();
1823 workspace.cascadeSubWindows();
1824 qApp->processEvents();
1825
1826 // Check dy between two cascaded windows
1827 QStyleOptionTitleBar options;
1828 options.initFrom(windows.at(1));
1829 int titleBarHeight = windows.at(1)->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options);
1830 // ### Remove this after the mac style has been fixed
1831 if (windows.at(1)->style()->inherits("QMacStyle"))
1832 titleBarHeight -= 4;
1833 const QFontMetrics fontMetrics = QFontMetrics(QApplication::font("QWorkspaceTitleBar"));
1834 const int dy = qMax(titleBarHeight - (titleBarHeight - fontMetrics.height()) / 2, 1);
1835 QCOMPARE(windows.at(2)->geometry().top() - windows.at(1)->geometry().top(), dy);
1836
1837 for (int i = 0; i < windows.count(); ++i) {
1838 QMdiSubWindow *window = windows.at(i);
1839 if (i % 3 == 0) {
1840 QVERIFY(window->isMinimized());
1841 } else {
1842 QVERIFY(!window->isMaximized());
1843 QCOMPARE(window->size(), window->sizeHint());
1844 window->showMaximized();
1845 QVERIFY(window->isMaximized());
1846 }
1847 }
1848 }
1849
resizeMaximizedChildWindows_data()1850 void tst_QMdiArea::resizeMaximizedChildWindows_data()
1851 {
1852 QTest::addColumn<int>("startSize");
1853 QTest::addColumn<int>("increment");
1854 QTest::addColumn<int>("windowCount");
1855
1856 QTest::newRow("multiple children") << 400 << 20 << 10;
1857 }
1858
resizeMaximizedChildWindows()1859 void tst_QMdiArea::resizeMaximizedChildWindows()
1860 {
1861 QFETCH(int, startSize);
1862 QFETCH(int, increment);
1863 QFETCH(int, windowCount);
1864
1865 QWidget topLevel;
1866 QMdiArea workspace(&topLevel);
1867 topLevel.show();
1868 #if defined(Q_WS_X11)
1869 qt_x11_wait_for_window_manager(&workspace);
1870 #endif
1871 QTest::qWait(100);
1872 workspace.resize(startSize, startSize);
1873 workspace.setOption(QMdiArea::DontMaximizeSubWindowOnActivation);
1874 QSize workspaceSize = workspace.size();
1875 QVERIFY(workspaceSize.isValid());
1876 QCOMPARE(workspaceSize, QSize(startSize, startSize));
1877
1878 QList<QMdiSubWindow *> windows;
1879 for (int i = 0; i < windowCount; ++i) {
1880 QMdiSubWindow *window = workspace.addSubWindow(new QWidget);
1881 windows.append(window);
1882 qApp->processEvents();
1883 window->showMaximized();
1884 QTest::qWait(100);
1885 QVERIFY(window->isMaximized());
1886 QSize windowSize = window->size();
1887 QVERIFY(windowSize.isValid());
1888 QCOMPARE(window->rect(), workspace.contentsRect());
1889
1890 workspace.resize(workspaceSize + QSize(increment, increment));
1891 QTest::qWait(100);
1892 qApp->processEvents();
1893 QTRY_COMPARE(workspace.size(), workspaceSize + QSize(increment, increment));
1894 QTRY_COMPARE(window->size(), windowSize + QSize(increment, increment));
1895 workspaceSize = workspace.size();
1896 }
1897
1898 int newSize = startSize + increment * windowCount;
1899 QCOMPARE(workspaceSize, QSize(newSize, newSize));
1900 foreach (QWidget *window, windows)
1901 QCOMPARE(window->rect(), workspace.contentsRect());
1902 }
1903
1904 // QWidget::setParent clears focusWidget so make sure
1905 // we restore it after QMdiArea::addSubWindow.
focusWidgetAfterAddSubWindow()1906 void tst_QMdiArea::focusWidgetAfterAddSubWindow()
1907 {
1908 QWidget *view = new QWidget;
1909 view->setLayout(new QVBoxLayout);
1910
1911 QLineEdit *lineEdit1 = new QLineEdit;
1912 QLineEdit *lineEdit2 = new QLineEdit;
1913 view->layout()->addWidget(lineEdit1);
1914 view->layout()->addWidget(lineEdit2);
1915
1916 lineEdit2->setFocus();
1917 QCOMPARE(view->focusWidget(), static_cast<QWidget *>(lineEdit2));
1918
1919 QMdiArea mdiArea;
1920 mdiArea.addSubWindow(view);
1921 QCOMPARE(view->focusWidget(), static_cast<QWidget *>(lineEdit2));
1922
1923 mdiArea.show();
1924 view->show();
1925 qApp->setActiveWindow(&mdiArea);
1926 QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(lineEdit2));
1927 }
1928
dontMaximizeSubWindowOnActivation()1929 void tst_QMdiArea::dontMaximizeSubWindowOnActivation()
1930 {
1931 QMdiArea mdiArea;
1932 mdiArea.show();
1933 #ifdef Q_WS_X11
1934 qt_x11_wait_for_window_manager(&mdiArea);
1935 #endif
1936 qApp->setActiveWindow(&mdiArea);
1937
1938 // Add one maximized window.
1939 mdiArea.addSubWindow(new QWidget)->showMaximized();
1940 QVERIFY(mdiArea.activeSubWindow());
1941 QVERIFY(mdiArea.activeSubWindow()->isMaximized());
1942
1943 // Add few more windows and verify that they are maximized.
1944 for (int i = 0; i < 5; ++i) {
1945 QMdiSubWindow *window = mdiArea.addSubWindow(new QWidget);
1946 window->show();
1947 QVERIFY(window->isMaximized());
1948 qApp->processEvents();
1949 }
1950
1951 // Verify that activated windows still are maximized on activation.
1952 QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
1953 for (int i = 0; i < subWindows.count(); ++i) {
1954 mdiArea.activateNextSubWindow();
1955 QMdiSubWindow *window = subWindows.at(i);
1956 QCOMPARE(mdiArea.activeSubWindow(), window);
1957 QVERIFY(window->isMaximized());
1958 qApp->processEvents();
1959 }
1960
1961 // Restore active window and verify that other windows aren't
1962 // maximized on activation.
1963 mdiArea.activeSubWindow()->showNormal();
1964 for (int i = 0; i < subWindows.count(); ++i) {
1965 mdiArea.activateNextSubWindow();
1966 QMdiSubWindow *window = subWindows.at(i);
1967 QCOMPARE(mdiArea.activeSubWindow(), window);
1968 QVERIFY(!window->isMaximized());
1969 qApp->processEvents();
1970 }
1971
1972 // Enable 'DontMaximizedSubWindowOnActivation' and maximize the active window.
1973 mdiArea.setOption(QMdiArea::DontMaximizeSubWindowOnActivation);
1974 mdiArea.activeSubWindow()->showMaximized();
1975 int indexOfMaximized = subWindows.indexOf(mdiArea.activeSubWindow());
1976
1977 // Verify that windows are not maximized on activation.
1978 for (int i = 0; i < subWindows.count(); ++i) {
1979 mdiArea.activateNextSubWindow();
1980 QMdiSubWindow *window = subWindows.at(i);
1981 QCOMPARE(mdiArea.activeSubWindow(), window);
1982 if (indexOfMaximized != i)
1983 QVERIFY(!window->isMaximized());
1984 qApp->processEvents();
1985 }
1986 QVERIFY(mdiArea.activeSubWindow()->isMaximized());
1987
1988 // Minimize all windows.
1989 foreach (QMdiSubWindow *window, subWindows) {
1990 window->showMinimized();
1991 QVERIFY(window->isMinimized());
1992 qApp->processEvents();
1993 }
1994
1995 // Disable 'DontMaximizedSubWindowOnActivation' and maximize the active window.
1996 mdiArea.setOption(QMdiArea::DontMaximizeSubWindowOnActivation, false);
1997 mdiArea.activeSubWindow()->showMaximized();
1998
1999 // Verify that minimized windows are maximized on activation.
2000 for (int i = 0; i < subWindows.count(); ++i) {
2001 mdiArea.activateNextSubWindow();
2002 QMdiSubWindow *window = subWindows.at(i);
2003 QCOMPARE(mdiArea.activeSubWindow(), window);
2004 QVERIFY(window->isMaximized());
2005 qApp->processEvents();
2006 }
2007
2008 // Verify that activated windows are maximized after closing
2009 // the active window
2010 for (int i = 0; i < subWindows.count(); ++i) {
2011 QVERIFY(mdiArea.activeSubWindow());
2012 QVERIFY(mdiArea.activeSubWindow()->isMaximized());
2013 mdiArea.activeSubWindow()->close();
2014 qApp->processEvents();
2015 }
2016
2017 QVERIFY(!mdiArea.activeSubWindow());
2018 QCOMPARE(mdiArea.subWindowList().size(), 0);
2019
2020 // Verify that new windows are not maximized.
2021 mdiArea.addSubWindow(new QWidget)->show();
2022 QVERIFY(mdiArea.activeSubWindow());
2023 QVERIFY(!mdiArea.activeSubWindow()->isMaximized());
2024 }
2025
delayedPlacement()2026 void tst_QMdiArea::delayedPlacement()
2027 {
2028 QMdiArea mdiArea;
2029
2030 QMdiSubWindow *window1 = mdiArea.addSubWindow(new QWidget);
2031 QCOMPARE(window1->geometry().topLeft(), QPoint(0, 0));
2032
2033 QMdiSubWindow *window2 = mdiArea.addSubWindow(new QWidget);
2034 QCOMPARE(window2->geometry().topLeft(), QPoint(0, 0));
2035
2036 QMdiSubWindow *window3 = mdiArea.addSubWindow(new QWidget);
2037 QCOMPARE(window3->geometry().topLeft(), QPoint(0, 0));
2038
2039 mdiArea.resize(window3->minimumSizeHint().width() * 3, 400);
2040 mdiArea.show();
2041 #ifdef Q_WS_X11
2042 qt_x11_wait_for_window_manager(&mdiArea);
2043 #endif
2044
2045 QCOMPARE(window1->geometry().topLeft(), QPoint(0, 0));
2046 QCOMPARE(window2->geometry().topLeft(), window1->geometry().topRight() + QPoint(1, 0));
2047 QCOMPARE(window3->geometry().topLeft(), window2->geometry().topRight() + QPoint(1, 0));
2048 }
2049
iconGeometryInMenuBar()2050 void tst_QMdiArea::iconGeometryInMenuBar()
2051 {
2052 #if !defined (Q_WS_MAC) && !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
2053 QMainWindow mainWindow;
2054 QMenuBar *menuBar = mainWindow.menuBar();
2055 QMdiArea *mdiArea = new QMdiArea;
2056 QMdiSubWindow *subWindow = mdiArea->addSubWindow(new QWidget);
2057 mainWindow.setCentralWidget(mdiArea);
2058 mainWindow.show();
2059 #ifdef Q_WS_X11
2060 qt_x11_wait_for_window_manager(&mainWindow);
2061 #endif
2062
2063 subWindow->showMaximized();
2064 QVERIFY(subWindow->isMaximized());
2065
2066 QWidget *leftCornerWidget = menuBar->cornerWidget(Qt::TopLeftCorner);
2067 QVERIFY(leftCornerWidget);
2068 int topMargin = (menuBar->height() - leftCornerWidget->height()) / 2;
2069 int leftMargin = qApp->style()->pixelMetric(QStyle::PM_MenuBarHMargin)
2070 + qApp->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth);
2071 QPoint pos(leftMargin, topMargin);
2072 QRect geometry = QStyle::visualRect(qApp->layoutDirection(), menuBar->rect(),
2073 QRect(pos, leftCornerWidget->size()));
2074 QCOMPARE(leftCornerWidget->geometry(), geometry);
2075 #endif
2076 }
2077
2078 class EventSpy : public QObject
2079 {
2080 public:
EventSpy(QObject * object,QEvent::Type event)2081 EventSpy(QObject *object, QEvent::Type event)
2082 : eventToSpy(event), _count(0)
2083 {
2084 if (object)
2085 object->installEventFilter(this);
2086 }
2087
count() const2088 int count() const { return _count; }
clear()2089 void clear() { _count = 0; }
2090
2091 protected:
eventFilter(QObject * object,QEvent * event)2092 bool eventFilter(QObject *object, QEvent *event)
2093 {
2094 if (event->type() == eventToSpy)
2095 ++_count;
2096 return QObject::eventFilter(object, event);
2097 }
2098
2099 private:
2100 QEvent::Type eventToSpy;
2101 int _count;
2102 };
2103
resizeTimer()2104 void tst_QMdiArea::resizeTimer()
2105 {
2106 QMdiArea mdiArea;
2107 QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QWidget);
2108 mdiArea.show();
2109 #ifdef Q_WS_X11
2110 qt_x11_wait_for_window_manager(&mdiArea);
2111 #endif
2112 QTest::qWaitForWindowShown(&mdiArea);
2113
2114 #ifndef Q_OS_WINCE
2115 int time = 250;
2116 #else
2117 int time = 1000;
2118 #endif
2119
2120 QTest::qWait(time);
2121
2122 EventSpy timerEventSpy(subWindow, QEvent::Timer);
2123 QCOMPARE(timerEventSpy.count(), 0);
2124
2125 mdiArea.tileSubWindows();
2126 QTest::qWait(time); // Wait for timer events to occur.
2127 QCOMPARE(timerEventSpy.count(), 1);
2128 timerEventSpy.clear();
2129
2130 mdiArea.resize(mdiArea.size() + QSize(2, 2));
2131 QTest::qWait(time); // Wait for timer events to occur.
2132 QCOMPARE(timerEventSpy.count(), 1);
2133 timerEventSpy.clear();
2134
2135 // Check that timers are killed.
2136 QTest::qWait(time); // Wait for timer events to occur.
2137 QCOMPARE(timerEventSpy.count(), 0);
2138 }
2139
updateScrollBars()2140 void tst_QMdiArea::updateScrollBars()
2141 {
2142 QMdiArea mdiArea;
2143 mdiArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
2144 mdiArea.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
2145
2146 QMdiSubWindow *subWindow1 = mdiArea.addSubWindow(new QWidget);
2147 QMdiSubWindow *subWindow2 = mdiArea.addSubWindow(new QWidget);
2148
2149 mdiArea.show();
2150 #ifdef Q_WS_X11
2151 qt_x11_wait_for_window_manager(&mdiArea);
2152 #endif
2153 qApp->processEvents();
2154
2155 QScrollBar *hbar = mdiArea.horizontalScrollBar();
2156 QVERIFY(hbar);
2157 QVERIFY(!hbar->isVisible());
2158
2159 QScrollBar *vbar = mdiArea.verticalScrollBar();
2160 QVERIFY(vbar);
2161 QVERIFY(!vbar->isVisible());
2162
2163 // Move sub-window 2 away.
2164 subWindow2->move(10000, 10000);
2165 qApp->processEvents();
2166 QVERIFY(hbar->isVisible());
2167 QVERIFY(vbar->isVisible());
2168
2169 for (int i = 0; i < 2; ++i) {
2170 // Maximize sub-window 1 and make sure we don't have any scroll bars.
2171 subWindow1->showMaximized();
2172 qApp->processEvents();
2173 QVERIFY(subWindow1->isMaximized());
2174 QVERIFY(!hbar->isVisible());
2175 QVERIFY(!vbar->isVisible());
2176
2177 // We still shouldn't get any scroll bars.
2178 mdiArea.resize(mdiArea.size() - QSize(20, 20));
2179 #ifdef Q_WS_X11
2180 qt_x11_wait_for_window_manager(&mdiArea);
2181 #endif
2182 qApp->processEvents();
2183 QVERIFY(subWindow1->isMaximized());
2184 QVERIFY(!hbar->isVisible());
2185 QVERIFY(!vbar->isVisible());
2186
2187 // Restore sub-window 1 and make sure we have scroll bars again.
2188 subWindow1->showNormal();
2189 qApp->processEvents();
2190 QVERIFY(!subWindow1->isMaximized());
2191 QVERIFY(hbar->isVisible());
2192 QVERIFY(vbar->isVisible());
2193 if (i == 0) {
2194 // Now, do the same when the viewport is scrolled.
2195 hbar->setValue(1000);
2196 vbar->setValue(1000);
2197 }
2198 }
2199 }
2200
setActivationOrder_data()2201 void tst_QMdiArea::setActivationOrder_data()
2202 {
2203 QTest::addColumn<QMdiArea::WindowOrder>("activationOrder");
2204 QTest::addColumn<int>("subWindowCount");
2205 QTest::addColumn<int>("staysOnTopIndex");
2206 QTest::addColumn<int>("firstActiveIndex");
2207 QTest::addColumn<QList<int> >("expectedActivationIndices");
2208 // The order of expectedCascadeIndices:
2209 // window 1 -> (index 0)
2210 // window 2 -> (index 1)
2211 // window 3 -> (index 2)
2212 // ....
2213 QTest::addColumn<QList<int> >("expectedCascadeIndices");
2214
2215 // The order of expectedTileIndices (the same as reading a book LTR).
2216 // +--------------------+--------------------+--------------------+
2217 // | window 1 (index 0) | window 2 (index 1) | window 3 (index 2) |
2218 // | +--------------------+--------------------+
2219 // | (index 3) | window 4 (index 4) | window 5 (index 5) |
2220 // +--------------------------------------------------------------+
2221 QTest::addColumn<QList<int> >("expectedTileIndices");
2222
2223 QList<int> list;
2224 QList<int> list2;
2225 QList<int> list3;
2226
2227 list << 2 << 1 << 0 << 1 << 2 << 3 << 4;
2228 list2 << 0 << 1 << 2 << 3 << 4;
2229 list3 << 1 << 4 << 3 << 1 << 2 << 0;
2230 QTest::newRow("CreationOrder") << QMdiArea::CreationOrder << 5 << 3 << 1 << list << list2 << list3;
2231
2232 list = QList<int>();
2233 list << 3 << 1 << 4 << 3 << 1 << 2 << 0;
2234 list2 = QList<int>();
2235 list2 << 0 << 2 << 4 << 1 << 3;
2236 list3 = QList<int>();
2237 list3 << 1 << 3 << 4 << 1 << 2 << 0;
2238 QTest::newRow("StackingOrder") << QMdiArea::StackingOrder << 5 << 3 << 1 << list << list2 << list3;
2239
2240 list = QList<int>();
2241 list << 0 << 1 << 0 << 1 << 4 << 3 << 2;
2242 list2 = QList<int>();
2243 list2 << 0 << 2 << 3 << 4 << 1;
2244 list3 = QList<int>();
2245 list3 << 1 << 4 << 3 << 1 << 2 << 0;
2246 QTest::newRow("ActivationHistoryOrder") << QMdiArea::ActivationHistoryOrder << 5 << 3 << 1 << list << list2 << list3;
2247 }
2248
setActivationOrder()2249 void tst_QMdiArea::setActivationOrder()
2250 {
2251 QFETCH(QMdiArea::WindowOrder, activationOrder);
2252 QFETCH(int, subWindowCount);
2253 QFETCH(int, staysOnTopIndex);
2254 QFETCH(int, firstActiveIndex);
2255 QFETCH(QList<int>, expectedActivationIndices);
2256 QFETCH(QList<int>, expectedCascadeIndices);
2257 QFETCH(QList<int>, expectedTileIndices);
2258
2259 // Default order.
2260 QMdiArea mdiArea;
2261 QCOMPARE(mdiArea.activationOrder(), QMdiArea::CreationOrder);
2262
2263 // New order.
2264 mdiArea.setActivationOrder(activationOrder);
2265 QCOMPARE(mdiArea.activationOrder(), activationOrder);
2266
2267 QList<QMdiSubWindow *> subWindows;
2268 for (int i = 0; i < subWindowCount; ++i)
2269 subWindows << mdiArea.addSubWindow(new QPushButton(tr("%1").arg(i)));
2270 QCOMPARE(mdiArea.subWindowList(activationOrder), subWindows);
2271
2272 mdiArea.show();
2273 #ifdef Q_WS_X11
2274 qt_x11_wait_for_window_manager(&mdiArea);
2275 #endif
2276
2277 for (int i = 0; i < subWindows.count(); ++i) {
2278 mdiArea.activateNextSubWindow();
2279 QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(i));
2280 qApp->processEvents();
2281 }
2282
2283 QMdiSubWindow *staysOnTop = subWindows.at(staysOnTopIndex);
2284 staysOnTop->setWindowFlags(staysOnTop->windowFlags() | Qt::WindowStaysOnTopHint);
2285 staysOnTop->raise();
2286
2287 mdiArea.setActiveSubWindow(subWindows.at(firstActiveIndex));
2288 QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(firstActiveIndex));
2289
2290 // Verify the actual arrangement/geometry.
2291 mdiArea.tileSubWindows();
2292 QTest::qWait(100);
2293 QVERIFY(verifyArrangement(&mdiArea, Tiled, expectedTileIndices));
2294
2295 mdiArea.cascadeSubWindows();
2296 QVERIFY(verifyArrangement(&mdiArea, Cascaded, expectedCascadeIndices));
2297 QTest::qWait(100);
2298
2299 mdiArea.activateNextSubWindow();
2300 QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst()));
2301
2302 mdiArea.activatePreviousSubWindow();
2303 QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst()));
2304
2305 mdiArea.activatePreviousSubWindow();
2306 QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst()));
2307
2308 for (int i = 0; i < subWindowCount; ++i) {
2309 mdiArea.closeActiveSubWindow();
2310 qApp->processEvents();
2311 if (i == subWindowCount - 1) { // Last window closed.
2312 QVERIFY(!mdiArea.activeSubWindow());
2313 break;
2314 }
2315 QVERIFY(mdiArea.activeSubWindow());
2316 QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst()));
2317 }
2318
2319 QVERIFY(mdiArea.subWindowList(activationOrder).isEmpty());
2320 QVERIFY(expectedActivationIndices.isEmpty());
2321 }
2322
tabBetweenSubWindows()2323 void tst_QMdiArea::tabBetweenSubWindows()
2324 {
2325 QMdiArea mdiArea;
2326 QList<QMdiSubWindow *> subWindows;
2327 for (int i = 0; i < 5; ++i)
2328 subWindows << mdiArea.addSubWindow(new QLineEdit);
2329
2330 mdiArea.show();
2331 #ifdef Q_WS_X11
2332 qt_x11_wait_for_window_manager(&mdiArea);
2333 #endif
2334
2335 qApp->setActiveWindow(&mdiArea);
2336 QWidget *focusWidget = subWindows.back()->widget();
2337 QCOMPARE(qApp->focusWidget(), focusWidget);
2338
2339 QSignalSpy spy(&mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow *)));
2340 QCOMPARE(spy.count(), 0);
2341
2342 // Walk through the entire list of sub windows.
2343 QVERIFY(tabBetweenSubWindowsIn(&mdiArea));
2344 QCOMPARE(mdiArea.activeSubWindow(), subWindows.back());
2345 QCOMPARE(spy.count(), 0);
2346
2347 mdiArea.setActiveSubWindow(subWindows.front());
2348 QCOMPARE(mdiArea.activeSubWindow(), subWindows.front());
2349 spy.clear();
2350
2351 // Walk through the entire list of sub windows in the opposite direction (Ctrl-Shift-Tab).
2352 QVERIFY(tabBetweenSubWindowsIn(&mdiArea, -1, true));
2353 QCOMPARE(mdiArea.activeSubWindow(), subWindows.front());
2354 QCOMPARE(spy.count(), 0);
2355
2356 // Ctrl-Tab-Tab-Tab
2357 QVERIFY(tabBetweenSubWindowsIn(&mdiArea, 3));
2358 QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(3));
2359 QCOMPARE(spy.count(), 1);
2360
2361 mdiArea.setActiveSubWindow(subWindows.at(1));
2362 QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(1));
2363 spy.clear();
2364
2365 // Quick switch (Ctrl-Tab once) -> switch back to the previously active sub-window.
2366 QVERIFY(tabBetweenSubWindowsIn(&mdiArea, 1));
2367 QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(3));
2368 QCOMPARE(spy.count(), 1);
2369 }
2370
setViewMode()2371 void tst_QMdiArea::setViewMode()
2372 {
2373 QMdiArea mdiArea;
2374
2375 QPixmap iconPixmap(16, 16);
2376 iconPixmap.fill(Qt::red);
2377 for (int i = 0; i < 5; ++i) {
2378 QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QWidget);
2379 subWindow->setWindowTitle(QString(QLatin1String("Title %1")).arg(i));
2380 subWindow->setWindowIcon(iconPixmap);
2381 }
2382
2383 mdiArea.show();
2384 #ifdef Q_WS_X11
2385 qt_x11_wait_for_window_manager(&mdiArea);
2386 #endif
2387
2388 QMdiSubWindow *activeSubWindow = mdiArea.activeSubWindow();
2389 const QList<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
2390
2391 // Default.
2392 QVERIFY(!activeSubWindow->isMaximized());
2393 QTabBar *tabBar = qFindChild<QTabBar *>(&mdiArea);
2394 QVERIFY(!tabBar);
2395 QCOMPARE(mdiArea.viewMode(), QMdiArea::SubWindowView);
2396
2397 // Tabbed view.
2398 mdiArea.setViewMode(QMdiArea::TabbedView);
2399 QCOMPARE(mdiArea.viewMode(), QMdiArea::TabbedView);
2400 tabBar = qFindChild<QTabBar *>(&mdiArea);
2401 QVERIFY(tabBar);
2402 QVERIFY(tabBar->isVisible());
2403
2404 QCOMPARE(tabBar->count(), subWindows.count());
2405 QVERIFY(activeSubWindow->isMaximized());
2406 QCOMPARE(tabBar->currentIndex(), subWindows.indexOf(activeSubWindow));
2407
2408 // Check that tabIcon and tabText are set properly.
2409 for (int i = 0; i < subWindows.size(); ++i) {
2410 QMdiSubWindow *subWindow = subWindows.at(i);
2411 QCOMPARE(tabBar->tabText(i), subWindow->windowTitle());
2412 QCOMPARE(tabBar->tabIcon(i), subWindow->windowIcon());
2413 }
2414
2415 // Check that tabText and tabIcon are updated.
2416 activeSubWindow->setWindowTitle(QLatin1String("Dude, I want another window title"));
2417 QCOMPARE(tabBar->tabText(tabBar->currentIndex()), activeSubWindow->windowTitle());
2418 iconPixmap.fill(Qt::green);
2419 activeSubWindow->setWindowIcon(iconPixmap);
2420 QCOMPARE(tabBar->tabIcon(tabBar->currentIndex()), activeSubWindow->windowIcon());
2421
2422 // If there's an empty window title, tabText should return "(Untitled)" (as in firefox).
2423 activeSubWindow->setWindowTitle(QString());
2424 QCOMPARE(tabBar->tabText(tabBar->currentIndex()), QLatin1String("(Untitled)"));
2425
2426 // If there's no window icon, tabIcon should return ... an empty icon :)
2427 activeSubWindow->setWindowIcon(QIcon());
2428 QCOMPARE(tabBar->tabIcon(tabBar->currentIndex()), QIcon());
2429
2430 // Check that the current tab changes when activating another sub-window.
2431 for (int i = 0; i < subWindows.size(); ++i) {
2432 mdiArea.activateNextSubWindow();
2433 activeSubWindow = mdiArea.activeSubWindow();
2434 QCOMPARE(tabBar->currentIndex(), subWindows.indexOf(activeSubWindow));
2435 }
2436
2437 activeSubWindow = mdiArea.activeSubWindow();
2438 const int tabIndex = tabBar->currentIndex();
2439
2440 // The current tab should not change when the sub-window is hidden.
2441 activeSubWindow->hide();
2442 QCOMPARE(tabBar->currentIndex(), tabIndex);
2443 activeSubWindow->show();
2444 QCOMPARE(tabBar->currentIndex(), tabIndex);
2445
2446 // Disable the tab when the sub-window is hidden and another sub-window is activated.
2447 activeSubWindow->hide();
2448 mdiArea.activateNextSubWindow();
2449 QVERIFY(tabBar->currentIndex() != tabIndex);
2450 QVERIFY(!tabBar->isTabEnabled(tabIndex));
2451
2452 // Enable it again.
2453 activeSubWindow->show();
2454 QCOMPARE(tabBar->currentIndex(), tabIndex);
2455 QVERIFY(tabBar->isTabEnabled(tabIndex));
2456
2457 // Remove sub-windows and make sure the tab is removed.
2458 foreach (QMdiSubWindow *subWindow, subWindows) {
2459 if (subWindow != activeSubWindow)
2460 mdiArea.removeSubWindow(subWindow);
2461 }
2462 QCOMPARE(tabBar->count(), 1);
2463
2464 // Go back to default (QMdiArea::SubWindowView).
2465 mdiArea.setViewMode(QMdiArea::SubWindowView);
2466 QVERIFY(!activeSubWindow->isMaximized());
2467 tabBar = qFindChild<QTabBar *>(&mdiArea);
2468 QVERIFY(!tabBar);
2469 QCOMPARE(mdiArea.viewMode(), QMdiArea::SubWindowView);
2470 }
2471
setTabsClosable()2472 void tst_QMdiArea::setTabsClosable()
2473 {
2474 QMdiArea mdiArea;
2475 mdiArea.addSubWindow(new QWidget);
2476
2477 // test default
2478 QCOMPARE(mdiArea.tabsClosable(), false);
2479
2480 // change value before tab bar exists
2481 QTabBar *tabBar = qFindChild<QTabBar *>(&mdiArea);
2482 QVERIFY(!tabBar);
2483 mdiArea.setTabsClosable(true);
2484 QCOMPARE(mdiArea.tabsClosable(), true);
2485
2486 // force tab bar creation
2487 mdiArea.setViewMode(QMdiArea::TabbedView);
2488 tabBar = qFindChild<QTabBar *>(&mdiArea);
2489 QVERIFY(tabBar);
2490
2491 // value must've been propagated
2492 QCOMPARE(tabBar->tabsClosable(), true);
2493
2494 // change value when tab bar exists
2495 mdiArea.setTabsClosable(false);
2496 QCOMPARE(mdiArea.tabsClosable(), false);
2497 QCOMPARE(tabBar->tabsClosable(), false);
2498 }
2499
setTabsMovable()2500 void tst_QMdiArea::setTabsMovable()
2501 {
2502 QMdiArea mdiArea;
2503 QMdiSubWindow *subWindow1 = mdiArea.addSubWindow(new QWidget);
2504 QMdiSubWindow *subWindow2 = mdiArea.addSubWindow(new QWidget);
2505 QMdiSubWindow *subWindow3 = mdiArea.addSubWindow(new QWidget);
2506
2507 // test default
2508 QCOMPARE(mdiArea.tabsMovable(), false);
2509
2510 // change value before tab bar exists
2511 QTabBar *tabBar = qFindChild<QTabBar *>(&mdiArea);
2512 QVERIFY(!tabBar);
2513 mdiArea.setTabsMovable(true);
2514 QCOMPARE(mdiArea.tabsMovable(), true);
2515
2516 // force tab bar creation
2517 mdiArea.setViewMode(QMdiArea::TabbedView);
2518 tabBar = qFindChild<QTabBar *>(&mdiArea);
2519 QVERIFY(tabBar);
2520
2521 // value must've been propagated
2522 QCOMPARE(tabBar->isMovable(), true);
2523
2524 // test tab moving
2525 QList<QMdiSubWindow *> subWindows;
2526 subWindows << subWindow1 << subWindow2 << subWindow3;
2527 QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows);
2528 tabBar->moveTab(1, 2); // 1,3,2
2529 subWindows.clear();
2530 subWindows << subWindow1 << subWindow3 << subWindow2;
2531 QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows);
2532 tabBar->moveTab(0, 2); // 3,2,1
2533 subWindows.clear();
2534 subWindows << subWindow3 << subWindow2 << subWindow1;
2535 QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows);
2536
2537 // change value when tab bar exists
2538 mdiArea.setTabsMovable(false);
2539 QCOMPARE(mdiArea.tabsMovable(), false);
2540 QCOMPARE(tabBar->isMovable(), false);
2541 }
2542
setTabShape()2543 void tst_QMdiArea::setTabShape()
2544 {
2545 QMdiArea mdiArea;
2546 mdiArea.addSubWindow(new QWidget);
2547 mdiArea.show();
2548 #ifdef Q_WS_X11
2549 qt_x11_wait_for_window_manager(&mdiArea);
2550 #endif
2551
2552 // Default.
2553 QCOMPARE(mdiArea.tabShape(), QTabWidget::Rounded);
2554
2555 // Triangular.
2556 mdiArea.setTabShape(QTabWidget::Triangular);
2557 QCOMPARE(mdiArea.tabShape(), QTabWidget::Triangular);
2558
2559 mdiArea.setViewMode(QMdiArea::TabbedView);
2560
2561 QTabBar *tabBar = qFindChild<QTabBar *>(&mdiArea);
2562 QVERIFY(tabBar);
2563 QCOMPARE(tabBar->shape(), QTabBar::TriangularNorth);
2564
2565 // Back to default (Rounded).
2566 mdiArea.setTabShape(QTabWidget::Rounded);
2567 QCOMPARE(mdiArea.tabShape(), QTabWidget::Rounded);
2568 QCOMPARE(tabBar->shape(), QTabBar::RoundedNorth);
2569 }
2570
setTabPosition_data()2571 void tst_QMdiArea::setTabPosition_data()
2572 {
2573 QTest::addColumn<QTabWidget::TabPosition>("tabPosition");
2574 QTest::addColumn<bool>("hasLeftMargin");
2575 QTest::addColumn<bool>("hasTopMargin");
2576 QTest::addColumn<bool>("hasRightMargin");
2577 QTest::addColumn<bool>("hasBottomMargin");
2578
2579 QTest::newRow("North") << QTabWidget::North << false << true << false << false;
2580 QTest::newRow("South") << QTabWidget::South << false << false << false << true;
2581 QTest::newRow("East") << QTabWidget::East << false << false << true << false;
2582 QTest::newRow("West") << QTabWidget::West << true << false << false << false;
2583 }
2584
setTabPosition()2585 void tst_QMdiArea::setTabPosition()
2586 {
2587 QFETCH(QTabWidget::TabPosition, tabPosition);
2588 QFETCH(bool, hasLeftMargin);
2589 QFETCH(bool, hasTopMargin);
2590 QFETCH(bool, hasRightMargin);
2591 QFETCH(bool, hasBottomMargin);
2592
2593 QMdiArea mdiArea;
2594 mdiArea.addSubWindow(new QWidget);
2595 mdiArea.show();
2596 #ifdef Q_WS_X11
2597 qt_x11_wait_for_window_manager(&mdiArea);
2598 #endif
2599
2600 // Make sure there are no margins.
2601 mdiArea.setContentsMargins(0, 0, 0, 0);
2602
2603 // Default.
2604 QCOMPARE(mdiArea.tabPosition(), QTabWidget::North);
2605 mdiArea.setViewMode(QMdiArea::TabbedView);
2606 QTabBar *tabBar = qFindChild<QTabBar *>(&mdiArea);
2607 QVERIFY(tabBar);
2608 QCOMPARE(tabBar->shape(), QTabBar::RoundedNorth);
2609
2610 // New position.
2611 mdiArea.setTabPosition(tabPosition);
2612 QCOMPARE(mdiArea.tabPosition(), tabPosition);
2613 QCOMPARE(tabBar->shape(), tabBarShapeFrom(QTabWidget::Rounded, tabPosition));
2614
2615 const Qt::LayoutDirection originalLayoutDirection = qApp->layoutDirection();
2616
2617 // Check that we have correct geometry in both RightToLeft and LeftToRight.
2618 for (int i = 0; i < 2; ++i) {
2619 // Check viewportMargins.
2620 const QRect viewportGeometry = mdiArea.viewport()->geometry();
2621 const int left = viewportGeometry.left();
2622 const int top = viewportGeometry.y();
2623 const int right = mdiArea.width() - viewportGeometry.width();
2624 const int bottom = mdiArea.height() - viewportGeometry.height();
2625
2626 const QSize sizeHint = tabBar->sizeHint();
2627
2628 if (hasLeftMargin)
2629 QCOMPARE(qApp->isLeftToRight() ? left : right, sizeHint.width());
2630 if (hasRightMargin)
2631 QCOMPARE(qApp->isLeftToRight() ? right : left, sizeHint.width());
2632 if (hasTopMargin || hasBottomMargin)
2633 QCOMPARE(hasTopMargin ? top : bottom, sizeHint.height());
2634
2635 // Check actual tab bar geometry.
2636 const QRegion expectedTabBarGeometry = QRegion(mdiArea.rect()).subtracted(viewportGeometry);
2637 QVERIFY(!expectedTabBarGeometry.isEmpty());
2638 QCOMPARE(QRegion(tabBar->geometry()), expectedTabBarGeometry);
2639
2640 if (i == 0)
2641 qApp->setLayoutDirection(originalLayoutDirection == Qt::LeftToRight ? Qt::RightToLeft : Qt::LeftToRight);
2642 qApp->processEvents();
2643 }
2644
2645 qApp->setLayoutDirection(originalLayoutDirection);
2646 }
2647
2648 #if defined(Q_WS_WIN) || defined(Q_WS_X11)
nativeSubWindows()2649 void tst_QMdiArea::nativeSubWindows()
2650 {
2651 { // Add native widgets after show.
2652 QMdiArea mdiArea;
2653 mdiArea.addSubWindow(new QWidget);
2654 mdiArea.addSubWindow(new QWidget);
2655 mdiArea.show();
2656 #ifdef Q_WS_X11
2657 qt_x11_wait_for_window_manager(&mdiArea);
2658 #endif
2659
2660 // No native widgets.
2661 QVERIFY(!mdiArea.viewport()->internalWinId());
2662 foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
2663 QVERIFY(!subWindow->internalWinId());
2664
2665 QWidget *nativeWidget = new QWidget;
2666 QVERIFY(nativeWidget->winId()); // enforce native window.
2667 mdiArea.addSubWindow(nativeWidget);
2668
2669 // The viewport and all the sub-windows must be native.
2670 QVERIFY(mdiArea.viewport()->internalWinId());
2671 foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
2672 QVERIFY(subWindow->internalWinId());
2673
2674 // Add a non-native widget. This should become native.
2675 QMdiSubWindow *subWindow = new QMdiSubWindow;
2676 subWindow->setWidget(new QWidget);
2677 QVERIFY(!subWindow->internalWinId());
2678 mdiArea.addSubWindow(subWindow);
2679 QVERIFY(subWindow->internalWinId());
2680 }
2681
2682 { // Add native widgets before show.
2683 QMdiArea mdiArea;
2684 mdiArea.addSubWindow(new QWidget);
2685 QWidget *nativeWidget = new QWidget;
2686 (void)nativeWidget->winId();
2687 mdiArea.addSubWindow(nativeWidget);
2688 mdiArea.show();
2689 #ifdef Q_WS_X11
2690 qt_x11_wait_for_window_manager(&mdiArea);
2691 #endif
2692
2693 // The viewport and all the sub-windows must be native.
2694 QVERIFY(mdiArea.viewport()->internalWinId());
2695 foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
2696 QVERIFY(subWindow->internalWinId());
2697 }
2698
2699 { // Make a sub-window native *after* it's added to the area.
2700 QMdiArea mdiArea;
2701 mdiArea.addSubWindow(new QWidget);
2702 mdiArea.addSubWindow(new QWidget);
2703 mdiArea.show();
2704 #ifdef Q_WS_X11
2705 qt_x11_wait_for_window_manager(&mdiArea);
2706 #endif
2707
2708 QMdiSubWindow *nativeSubWindow = mdiArea.subWindowList().last();
2709 QVERIFY(!nativeSubWindow->internalWinId());
2710 (void)nativeSubWindow->winId();
2711
2712 // All the sub-windows should be native at this point
2713 QVERIFY(mdiArea.viewport()->internalWinId());
2714 foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
2715 QVERIFY(subWindow->internalWinId());
2716 }
2717
2718 #ifndef QT_NO_OPENGL
2719 {
2720 if (!QGLFormat::hasOpenGL())
2721 QSKIP("QGL not supported on this platform", SkipAll);
2722
2723 QMdiArea mdiArea;
2724 QGLWidget *glViewport = new QGLWidget;
2725 mdiArea.setViewport(glViewport);
2726 mdiArea.addSubWindow(new QWidget);
2727 mdiArea.addSubWindow(new QWidget);
2728 mdiArea.show();
2729 #ifdef Q_WS_X11
2730 qt_x11_wait_for_window_manager(&mdiArea);
2731 #endif
2732
2733 const QGLContext *context = glViewport->context();
2734 if (!context || !context->isValid())
2735 QSKIP("QGL is broken, cannot continue test", SkipAll);
2736
2737 // The viewport and all the sub-windows must be native.
2738 QVERIFY(mdiArea.viewport()->internalWinId());
2739 foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList())
2740 QVERIFY(subWindow->internalWinId());
2741 }
2742 #endif
2743 }
2744 #endif
2745
task_209615()2746 void tst_QMdiArea::task_209615()
2747 {
2748 QTabWidget tabWidget;
2749 QMdiArea *mdiArea1 = new QMdiArea;
2750 QMdiArea *mdiArea2 = new QMdiArea;
2751 QMdiSubWindow *subWindow = mdiArea1->addSubWindow(new QLineEdit);
2752
2753 tabWidget.addTab(mdiArea1, QLatin1String("1"));
2754 tabWidget.addTab(mdiArea2, QLatin1String("2"));
2755 tabWidget.show();
2756
2757 mdiArea1->removeSubWindow(subWindow);
2758 mdiArea2->addSubWindow(subWindow);
2759
2760 // Please do not assert/crash.
2761 tabWidget.setCurrentIndex(1);
2762 }
2763
task_236750()2764 void tst_QMdiArea::task_236750()
2765 {
2766 QMdiArea mdiArea;
2767 QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QTextEdit);
2768 mdiArea.show();
2769
2770 subWindow->setWindowFlags(subWindow->windowFlags() | Qt::FramelessWindowHint);
2771 // Please do not crash (floating point exception).
2772 subWindow->showMinimized();
2773 }
2774
2775 QTEST_MAIN(tst_QMdiArea)
2776 #include "tst_qmdiarea.moc"
2777
2778