Remove QWorkspace.
[qt:rb-qtbase.git] / tests / auto / widgets / widgets / qmdisubwindow / tst_qmdisubwindow.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the test suite of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42
43 #include <QtTest/QtTest>
44
45 #include "qmdisubwindow.h"
46 #include "qmdiarea.h"
47
48 #include <QLayout>
49 #include <QLineEdit>
50 #include <QMainWindow>
51 #include <QMenuBar>
52 #include <QMenu>
53 #include <QGroupBox>
54 #include <QTextEdit>
55 #include <QLayout>
56 #include <QHBoxLayout>
57 #include <QByteArray>
58 #include <QStyle>
59 #include <QStyleOptionTitleBar>
60 #include <QPushButton>
61 #include <QSizeGrip>
62 #if defined(Q_OS_MAC) && !defined(QT_NO_STYLE_MAC)
63 #include <QMacStyle>
64 #endif
65
66 QT_BEGIN_NAMESPACE
67 #if defined(Q_WS_X11)
68 extern void qt_x11_wait_for_window_manager(QWidget *w);
69 #endif
70 #if !defined(Q_WS_WIN)
71 extern bool qt_tab_all_widgets;
72 #endif
73 QT_END_NAMESPACE
74
75 static inline bool tabAllWidgets()
76 {
77 #if !defined(Q_OS_WIN)
78     if (qApp->style()->inherits("QMacStyle"))
79         return qt_tab_all_widgets;
80 #endif
81     return true;
82 }
83
84 static inline void triggerSignal(QMdiSubWindow *window, QMdiArea *workspace,
85                                  const QByteArray &signal)
86 {
87     if (signal == SIGNAL(windowMaximized())) {
88         window->showMaximized();
89         qApp->processEvents();
90         if (window->parent())
91             QVERIFY(window->isMaximized());
92     } else if (signal == SIGNAL(windowMinimized())) {
93         window->showMinimized();
94         qApp->processEvents();
95         if (window->parent())
96             QVERIFY(window->isMinimized());
97     } else if (signal == SIGNAL(windowRestored())) {
98         window->showMaximized();
99         qApp->processEvents();
100         window->showNormal();
101         qApp->processEvents();
102         QVERIFY(!window->isMinimized());
103         QVERIFY(!window->isMaximized());
104         QVERIFY(!window->isShaded());
105     } else if (signal == SIGNAL(aboutToActivate())) {
106         if (window->parent()) {
107             workspace->setActiveSubWindow(window);
108             qApp->processEvents();
109         }
110     } else if (signal == SIGNAL(windowActivated())) {
111         if (window->parent()) {
112             workspace->setActiveSubWindow(window);
113             qApp->processEvents();
114         }
115     } else if (signal == SIGNAL(windowDeactivated())) {
116         if (!window->parent())
117             return;
118         workspace->setActiveSubWindow(window);
119         qApp->processEvents();
120         workspace->setActiveSubWindow(0);
121         qApp->processEvents();
122     }
123 }
124
125 // --- from tst_qgraphicsview.cpp ---
126 static void sendMousePress(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton)
127 {
128     QMouseEvent event(QEvent::MouseButtonPress, point, widget->mapToGlobal(point), button, 0, 0);
129     QApplication::sendEvent(widget, &event);
130 }
131
132 static void sendMouseMove(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton)
133 {
134     QMouseEvent event(QEvent::MouseMove, point, widget->mapToGlobal(point), button, button, 0);
135     QApplication::sendEvent(widget, &event);
136 }
137
138 static void sendMouseRelease(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton)
139 {
140     QMouseEvent event(QEvent::MouseButtonRelease, point, widget->mapToGlobal(point), button, 0, 0);
141     QApplication::sendEvent(widget, &event);
142 }
143 // ---
144
145 static void sendMouseDoubleClick(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton)
146 {
147     sendMousePress(widget, point, button);
148     sendMouseRelease(widget, point, button);
149     QMouseEvent event(QEvent::MouseButtonDblClick, point, widget->mapToGlobal(point), button, 0, 0);
150     QApplication::sendEvent(widget, &event);
151 }
152
153 static const Qt::WindowFlags StandardWindowFlags
154     = Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint;
155 static const Qt::WindowFlags DialogWindowFlags
156     = Qt::WindowTitleHint | Qt::WindowSystemMenuHint;
157
158 Q_DECLARE_METATYPE(Qt::WindowState);
159 Q_DECLARE_METATYPE(Qt::WindowStates);
160 Q_DECLARE_METATYPE(Qt::WindowType);
161 Q_DECLARE_METATYPE(Qt::WindowFlags);
162
163 class tst_QMdiSubWindow : public QObject
164 {
165     Q_OBJECT
166 private slots:
167     void initTestCase();
168     void sizeHint();
169     void minimumSizeHint();
170     void minimumSize();
171     void setWidget();
172     void setWindowState_data();
173     void setWindowState();
174     void mainWindowSupport();
175     void emittingOfSignals_data();
176     void emittingOfSignals();
177     void showShaded();
178     void showNormal_data();
179     void showNormal();
180     void setOpaqueResizeAndMove_data();
181     void setOpaqueResizeAndMove();
182     void setWindowFlags_data();
183     void setWindowFlags();
184     void mouseDoubleClick();
185     void setSystemMenu();
186     void restoreFocus();
187     void changeFocusWithTab();
188     void closeEvent();
189     void setWindowTitle();
190     void resizeEvents_data();
191     void resizeEvents();
192 #if defined(Q_OS_MAC)
193     void defaultSizeGrip();
194 #endif
195     void hideAndShow();
196     void keepWindowMaximizedState();
197     void explicitlyHiddenWidget();
198     void resizeTimer();
199     void fixedMinMaxSize();
200 #if !defined (Q_OS_MAC) && !defined (Q_OS_WINCE)
201     void replaceMenuBarWhileMaximized();
202     void closeOnDoubleClick();
203 #endif
204     void setFont();
205     void task_188849();
206     void mdiArea();
207     void task_182852();
208     void task_233197();
209     void task_226929();
210 };
211
212 void tst_QMdiSubWindow::initTestCase()
213 {
214     qRegisterMetaType<Qt::WindowStates>("Qt::WindowStates");
215 }
216
217 void tst_QMdiSubWindow::sizeHint()
218 {
219     QMdiSubWindow *window = new QMdiSubWindow;
220     QCOMPARE(window->sizeHint(), window->minimumSizeHint());
221     window->show();
222     QCOMPARE(window->sizeHint(), window->minimumSizeHint());
223     QMdiArea workspace;
224     workspace.addSubWindow(window);
225     QCOMPARE(window->sizeHint(), window->minimumSizeHint());
226 }
227
228 void tst_QMdiSubWindow::minimumSizeHint()
229 {
230     QMdiSubWindow window;
231     window.show();
232
233     QCOMPARE(window.minimumSizeHint(), qApp->globalStrut());
234
235     window.setWidget(new QWidget);
236     QCOMPARE(window.minimumSizeHint(), window.layout()->minimumSize()
237                                        .expandedTo(qApp->globalStrut()));
238
239     delete window.widget();
240     delete window.layout();
241     window.setWidget(new QWidget);
242     QCOMPARE(window.minimumSizeHint(), qApp->globalStrut());
243
244     window.widget()->show();
245     QCOMPARE(window.minimumSizeHint(), window.widget()->minimumSizeHint()
246                                        .expandedTo(qApp->globalStrut()));
247 }
248
249 void tst_QMdiSubWindow::minimumSize()
250 {
251     QMdiArea mdiArea;
252     mdiArea.resize(200, 200);
253
254     // Check that we respect the minimum size set on the sub-window itself.
255     QMdiSubWindow *subWindow1 = mdiArea.addSubWindow(new QWidget);
256     subWindow1->setMinimumSize(1000, 1000);
257     mdiArea.show();
258 #if defined(Q_WS_X11)
259     qt_x11_wait_for_window_manager(&mdiArea);
260 #endif
261     QCOMPARE(subWindow1->size(), QSize(1000, 1000));
262
263     // Check that we respect the minimum size set on the internal widget.
264     QWidget *widget = new QWidget;
265     widget->setMinimumSize(1000, 1000);
266     QMdiSubWindow *subWindow2 = mdiArea.addSubWindow(widget);
267     QVERIFY(subWindow2->size() != mdiArea.viewport()->size());
268     QCOMPARE(subWindow2->size(), subWindow2->minimumSizeHint());
269 }
270
271 void tst_QMdiSubWindow::setWidget()
272 {
273     QMdiSubWindow window;
274     window.show();
275     QVERIFY(window.layout());
276     QVERIFY(!window.widget());
277
278     // QPointer so we can check if the widget is deleted
279     QPointer<QWidget> widget = new QWidget;
280     widget->setWindowTitle(QString::fromLatin1("DummyTitle"));
281     QCOMPARE(widget->windowTitle(), QString::fromLatin1("DummyTitle"));
282     window.setWidget(widget);
283     QCOMPARE(window.windowTitle(), window.widget()->windowTitle());
284     QCOMPARE(widget->parentWidget(), static_cast<QWidget *>(&window));
285     QVERIFY(!widget->isVisible());
286     QCOMPARE(window.layout()->count(), 1);
287
288     QTest::ignoreMessage(QtWarningMsg,"QMdiSubWindow::setWidget: widget is already set");
289     window.setWidget(widget);
290     QCOMPARE(window.widget(), static_cast<QWidget *>(widget));
291     QCOMPARE(widget->parentWidget(), static_cast<QWidget *>(&window));
292
293     window.setWidget(0);
294     QVERIFY(widget);
295     QVERIFY(!widget->parent());
296     QVERIFY(!window.widget());
297     QCOMPARE(window.layout()->count(), 0);
298
299     window.setWidget(widget);
300     delete window.layout();
301     QVERIFY(!window.layout());
302     QVERIFY(window.widget());
303     QCOMPARE(window.widget()->parentWidget(), static_cast<QWidget *>(&window));
304
305     delete window.widget();
306     QVERIFY(!widget);
307     QVERIFY(!window.widget());
308 }
309
310 void tst_QMdiSubWindow::setWindowState_data()
311 {
312     QTest::addColumn<Qt::WindowState>("windowState");
313
314     QTest::newRow("maximized") << Qt::WindowMaximized;
315     QTest::newRow("minimized") << Qt::WindowMinimized;
316     QTest::newRow("normalized") << Qt::WindowNoState;
317 }
318
319 void tst_QMdiSubWindow::setWindowState()
320 {
321     QFETCH(Qt::WindowState, windowState);
322     QMdiArea workspace;
323     QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QLineEdit));
324     window->show();
325     workspace.show();
326 #if defined(Q_WS_X11)
327     qt_x11_wait_for_window_manager(&workspace);
328 #endif
329
330     QWidget *testWidget = 0;
331     for (int iteration = 0; iteration < 2; ++iteration) {
332         if (iteration == 0)
333             testWidget = window;
334         else
335             testWidget = window->widget();
336
337         testWidget->setWindowState(windowState);
338
339         Qt::WindowStates windowStateWindow = window->windowState();
340         windowStateWindow &= ~Qt::WindowActive;
341         Qt::WindowStates windowStateWidget = window->widget()->windowState();
342         windowStateWidget &= ~Qt::WindowActive;
343         QCOMPARE(windowStateWindow, windowStateWidget);
344
345         switch (windowState) {
346         case Qt::WindowNoState:
347             QVERIFY(!window->widget()->isMinimized());
348             QVERIFY(!window->widget()->isMaximized());
349             QVERIFY(!window->isMinimized());
350             QVERIFY(!window->isMaximized());
351             break;
352         case Qt::WindowMinimized:
353             QVERIFY(window->widget()->isMinimized());
354             QVERIFY(window->isMinimized());
355             break;
356         case Qt::WindowMaximized:
357             QVERIFY(window->widget()->isMaximized());
358             QVERIFY(window->isMaximized());
359             break;
360         default:
361             break;
362         }
363     }
364 }
365
366 void tst_QMdiSubWindow::mainWindowSupport()
367 {
368     QList<QMdiSubWindow *> windows;
369     QMdiArea *workspace = new QMdiArea;
370     QMainWindow mainWindow;
371     mainWindow.setCentralWidget(workspace);
372     mainWindow.show();
373     mainWindow.menuBar()->setVisible(true);
374     qApp->setActiveWindow(&mainWindow);
375
376     // QMainWindow's window title is empty
377 #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE)
378     {
379     QCOMPARE(mainWindow.windowTitle(), QString());
380     QMdiSubWindow *window = workspace->addSubWindow(new QPushButton(QLatin1String("Test")));
381     QString expectedTitle = QLatin1String("MainWindow's title is empty");
382     window->setWindowTitle(expectedTitle);
383     QCOMPARE(window->windowTitle(), expectedTitle);
384     window->showMaximized();
385     QVERIFY(window->isMaximized());
386     QCOMPARE(window->windowTitle(), expectedTitle);
387     QCOMPARE(mainWindow.windowTitle(), expectedTitle);
388     window->showNormal();
389     QCOMPARE(window->windowTitle(), expectedTitle);
390     QCOMPARE(mainWindow.windowTitle(), QString());
391     window->close();
392     }
393 #endif
394
395     QString originalWindowTitle = QString::fromLatin1("MainWindow");
396     mainWindow.setWindowTitle(originalWindowTitle);
397
398     for (int i = 0; i < 5; ++i) {
399         mainWindow.menuBar()->setVisible(false);
400
401         QMdiSubWindow *window = new QMdiSubWindow;
402         windows.append(window);
403         QVERIFY(!window->maximizedButtonsWidget());
404         QVERIFY(!window->maximizedSystemMenuIconWidget());
405
406         QMdiArea *nestedWorkspace = new QMdiArea; // :-)
407         window->setWidget(nestedWorkspace);
408         window->widget()->setWindowTitle(QString::fromLatin1("Window %1").arg(i));
409
410         workspace->addSubWindow(window);
411         QVERIFY(!window->maximizedButtonsWidget());
412         QVERIFY(!window->maximizedSystemMenuIconWidget());
413         window->show();
414
415         // mainWindow.menuBar() is not visible
416         window->showMaximized();
417         qApp->processEvents();
418         QVERIFY(window->isMaximized());
419         QVERIFY(!window->maximizedButtonsWidget());
420         QVERIFY(!window->maximizedSystemMenuIconWidget());
421         window->showNormal();
422
423         // Now it is
424         mainWindow.menuBar()->setVisible(true);
425
426         window->showMaximized();
427         qApp->processEvents();
428         QVERIFY(window->isMaximized());
429 #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE)
430         QVERIFY(window->maximizedButtonsWidget());
431         QCOMPARE(window->maximizedButtonsWidget(), mainWindow.menuBar()->cornerWidget(Qt::TopRightCorner));
432         QVERIFY(window->maximizedSystemMenuIconWidget());
433         QCOMPARE(window->maximizedSystemMenuIconWidget(), qobject_cast<QWidget *>(mainWindow.menuBar()
434                                                                     ->cornerWidget(Qt::TopLeftCorner)));
435         QCOMPARE(mainWindow.windowTitle(), QString::fromLatin1("%1 - [%2]")
436                                            .arg(originalWindowTitle, window->widget()->windowTitle()));
437 #endif
438
439         // Check that nested child windows don't set window title
440         nestedWorkspace->show();
441         QMdiSubWindow *nestedWindow = new QMdiSubWindow;
442         nestedWindow->setWidget(new QWidget);
443         nestedWorkspace->addSubWindow(nestedWindow);
444         nestedWindow->widget()->setWindowTitle(QString::fromLatin1("NestedWindow %1").arg(i));
445         nestedWindow->showMaximized();
446         qApp->processEvents();
447         QVERIFY(nestedWindow->isMaximized());
448         QVERIFY(!nestedWindow->maximizedButtonsWidget());
449         QVERIFY(!nestedWindow->maximizedSystemMenuIconWidget());
450
451 #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE)
452         QCOMPARE(mainWindow.windowTitle(), QString::fromLatin1("%1 - [%2]")
453                                            .arg(originalWindowTitle, window->widget()->windowTitle()));
454 #endif
455     }
456
457 #if defined(Q_OS_MAC) || defined(Q_OS_WINCE)
458     return;
459 #endif
460
461     workspace->activateNextSubWindow();
462     qApp->processEvents();
463     foreach (QMdiSubWindow *window, windows) {
464         QCOMPARE(workspace->activeSubWindow(), window);
465         QVERIFY(window->isMaximized());
466         QVERIFY(window->maximizedButtonsWidget());
467         QCOMPARE(window->maximizedButtonsWidget(), mainWindow.menuBar()->cornerWidget(Qt::TopRightCorner));
468         QVERIFY(window->maximizedSystemMenuIconWidget());
469         QCOMPARE(window->maximizedSystemMenuIconWidget(), qobject_cast<QWidget *>(mainWindow.menuBar()
470                                                                    ->cornerWidget(Qt::TopLeftCorner)));
471         QCOMPARE(mainWindow.windowTitle(), QString::fromLatin1("%1 - [%2]")
472                                            .arg(originalWindowTitle, window->widget()->windowTitle()));
473         workspace->activateNextSubWindow();
474         qApp->processEvents();
475     }
476 }
477
478 // This test was written when QMdiSubWindow emitted separate signals
479 void tst_QMdiSubWindow::emittingOfSignals_data()
480 {
481     QTest::addColumn<QByteArray>("signal");
482     QTest::addColumn<Qt::WindowState>("watchedState");
483
484     QTest::newRow("windowMaximized") << QByteArray(SIGNAL(windowMaximized())) << Qt::WindowMaximized;
485     QTest::newRow("windowMinimized") << QByteArray(SIGNAL(windowMinimized())) << Qt::WindowMinimized;
486     QTest::newRow("windowRestored") << QByteArray(SIGNAL(windowRestored())) << Qt::WindowNoState;
487     QTest::newRow("aboutToActivate") << QByteArray(SIGNAL(aboutToActivate())) << Qt::WindowNoState;
488     QTest::newRow("windowActivated") << QByteArray(SIGNAL(windowActivated())) << Qt::WindowActive;
489     QTest::newRow("windowDeactivated") << QByteArray(SIGNAL(windowDeactivated())) << Qt::WindowActive;
490 }
491
492 void tst_QMdiSubWindow::emittingOfSignals()
493 {
494     QFETCH(QByteArray, signal);
495     QFETCH(Qt::WindowState, watchedState);
496     QMdiArea workspace;
497     workspace.show();
498     qApp->processEvents();
499     qApp->setActiveWindow(&workspace);
500     QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget));
501     qApp->processEvents();
502     window->show();
503     if (signal != SIGNAL(windowRestored()))
504         workspace.setActiveSubWindow(0);
505     qApp->processEvents();
506
507     QSignalSpy spy(window, signal == SIGNAL(aboutToActivate())
508                            ? signal.data()
509                            : SIGNAL(windowStateChanged(Qt::WindowStates, Qt::WindowStates)));
510     QVERIFY(spy.isEmpty());
511     triggerSignal(window, &workspace, signal);
512     // Unless the signal is windowRestored or windowDeactivated,
513     // we're already in correct state and nothing should happen.
514     if (signal != SIGNAL(windowRestored()) && signal != SIGNAL(windowDeactivated()))
515         triggerSignal(window, &workspace, signal);
516
517     int count = 0;
518     if (signal == SIGNAL(aboutToActivate())) {
519         count += spy.count();
520     } else {
521         for (int i = 0; i < spy.count(); ++i) {
522             Qt::WindowStates oldState = qvariant_cast<Qt::WindowStates>(spy.at(i).at(0));
523             Qt::WindowStates newState = qvariant_cast<Qt::WindowStates>(spy.at(i).at(1));
524             if (watchedState != Qt::WindowNoState) {
525                 if (!(oldState & watchedState) && (newState & watchedState))
526                     ++count;
527             } else {
528                 if ((oldState & (Qt::WindowMinimized | Qt::WindowMaximized))
529                         && (newState & (watchedState | Qt::WindowActive))) {
530                     ++count;
531                 }
532             }
533         }
534     }
535     QCOMPARE(count, 1);
536
537     window->setParent(0);
538     window->showNormal();
539 #if defined(Q_WS_X11)
540     qt_x11_wait_for_window_manager(window);
541 #endif
542     qApp->processEvents();
543
544     spy.clear();
545     triggerSignal(window, &workspace, signal);
546     QCOMPARE(spy.count(), 0);
547
548     delete window;
549     window = 0;
550 }
551
552 void tst_QMdiSubWindow::showShaded()
553 {
554     QMdiArea workspace;
555     QMdiSubWindow *window = workspace.addSubWindow(new QLineEdit);
556     window->resize(300, 300);
557     qApp->processEvents();
558     workspace.show();
559 #ifdef Q_WS_X11
560     qt_x11_wait_for_window_manager(&workspace);
561 #endif
562
563     QVERIFY(!window->isShaded());
564     QVERIFY(!window->isMaximized());
565
566     QCOMPARE(window->size(), QSize(300, 300));
567     QRect restoreGeometry = window->geometry();
568     window->showShaded();
569     QVERIFY(window->isShaded());
570     QVERIFY(window->isMinimized());
571
572     window->showNormal();
573     QVERIFY(!window->isShaded());
574     QVERIFY(!window->isMinimized());
575     QCOMPARE(window->geometry(), restoreGeometry);
576     window->showShaded();
577
578     window->showNormal();
579     QVERIFY(!window->isShaded());
580     QVERIFY(!window->isMinimized());
581     QCOMPARE(window->geometry(), restoreGeometry);
582     window->showMinimized();
583     window->showMaximized();
584     window->showShaded();
585     QCOMPARE(window->width(), workspace.contentsRect().width());
586     window->showNormal();
587     QCOMPARE(window->geometry(), workspace.contentsRect());
588
589     window->resize(300, 300);
590     QCOMPARE(window->size(), QSize(300, 300));
591     window->showShaded();
592     window->showNormal();
593     QTest::qWait(250);
594
595 #ifdef Q_OS_WINCE
596     QSKIP("Until we have a QEvent::WindowFlagsChange event, this will skip");
597 #endif
598
599     const QSize minimumSizeHint = window->minimumSizeHint();
600     QVERIFY(minimumSizeHint.height() < 300);
601     const int maxHeightDiff = 300 - minimumSizeHint.height();
602
603     // Calculate mouse position for bottom right corner and simulate a
604     // vertical resize with the mouse.
605     int offset = window->style()->pixelMetric(QStyle::PM_MDIFrameWidth) / 2;
606     QPoint mousePosition(window->width() - qMax(offset, 2), window->height() - qMax(offset, 2));
607     QWidget *mouseReceiver = 0;
608 #ifdef Q_OS_MAC
609     if (qobject_cast<QMacStyle*>(window->style()))
610         mouseReceiver = qFindChild<QSizeGrip *>(window);
611     else
612 #endif
613         mouseReceiver = window;
614     QVERIFY(mouseReceiver);
615     sendMouseMove(mouseReceiver, mousePosition, Qt::NoButton);
616     sendMousePress(mouseReceiver, mousePosition);
617
618     for (int i = 0; i < maxHeightDiff + 20; ++i) {
619         --mousePosition.ry();
620         sendMouseMove(mouseReceiver, mousePosition);
621     }
622
623     sendMouseRelease(mouseReceiver, mousePosition);
624     // Make sure we respect the minimumSizeHint!
625     QCOMPARE(window->height(), minimumSizeHint.height());
626
627     window->showShaded();
628     window->setParent(0);
629     window->show();
630     QVERIFY(!window->isShaded());
631
632     delete window;
633 }
634
635 void tst_QMdiSubWindow::showNormal_data()
636 {
637     QTest::addColumn<QByteArray>("slot");
638
639     QTest::newRow("showMinimized") << QByteArray("showMinimized");
640     QTest::newRow("showMaximized") << QByteArray("showMaximized");
641     QTest::newRow("showShaded") << QByteArray("showShaded");
642 }
643
644 void tst_QMdiSubWindow::showNormal()
645 {
646     QFETCH(QByteArray, slot);
647
648     QMdiArea workspace;
649     QWidget *window = workspace.addSubWindow(new QWidget);
650     qApp->processEvents();
651     workspace.show();
652     window->show();
653 #if defined(Q_WS_X11)
654     qt_x11_wait_for_window_manager(&workspace);
655 #endif
656
657     QRect originalGeometry = window->geometry();
658     QVERIFY(QMetaObject::invokeMethod(window, slot.data()));
659     qApp->processEvents();
660     window->showNormal();
661     qApp->processEvents();
662     QCOMPARE(window->geometry(), originalGeometry);
663 }
664
665 class EventSpy : public QObject
666 {
667 public:
668     EventSpy(QObject *object, QEvent::Type event)
669         : eventToSpy(event), _count(0)
670     {
671         if (object)
672             object->installEventFilter(this);
673     }
674
675     int count() const { return _count; }
676     void clear() { _count = 0; }
677
678 protected:
679     bool eventFilter(QObject *object, QEvent *event)
680     {
681         if (event->type() == eventToSpy)
682             ++_count;
683         return  QObject::eventFilter(object, event);
684     }
685
686 private:
687     QEvent::Type eventToSpy;
688     int _count;
689 };
690
691 void tst_QMdiSubWindow::setOpaqueResizeAndMove_data()
692 {
693     QTest::addColumn<bool>("opaqueMode");
694     QTest::addColumn<int>("geometryCount");
695     QTest::addColumn<int>("expectedGeometryCount");
696     QTest::addColumn<QSize>("workspaceSize");
697     QTest::addColumn<QSize>("windowSize");
698
699     QTest::newRow("normal mode") << true<< 20 << 20 << QSize(400, 400) << QSize(200, 200);
700     QTest::newRow("rubberband mode") << false << 20 << 1 << QSize(400, 400) << QSize(200, 200);
701 }
702
703 void tst_QMdiSubWindow::setOpaqueResizeAndMove()
704 {
705 #if defined (QT_NO_CURSOR) || defined (Q_OS_WINCE_WM) //For Windows CE we will set QT_NO_CURSOR if there is no cursor support
706      QSKIP("No cursor available");
707 #endif
708     QFETCH(bool, opaqueMode);
709     QFETCH(int, geometryCount);
710     QFETCH(int, expectedGeometryCount);
711     QFETCH(QSize, workspaceSize);
712     QFETCH(QSize, windowSize);
713
714     QMdiArea workspace;
715     QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget));
716     qApp->processEvents();
717     workspace.resize(workspaceSize);
718     workspace.show();
719 #ifdef Q_WS_X11
720     qt_x11_wait_for_window_manager(&workspace);
721 #endif
722
723     QWidget *mouseReceiver = 0;
724     if (window->style()->inherits("QMacStyle"))
725         mouseReceiver = qFindChild<QSizeGrip *>(window);
726     else
727         mouseReceiver = window;
728     QVERIFY(mouseReceiver);
729
730     // ----------------------------- resize -----------------------------
731     {
732     // setOpaqueResize
733     window->setOption(QMdiSubWindow::RubberBandResize, !opaqueMode);
734     QCOMPARE(window->testOption(QMdiSubWindow::RubberBandResize), !opaqueMode);
735
736     // Check that the event spy actually works
737     EventSpy resizeSpy(window, QEvent::Resize);
738     QCOMPARE(resizeSpy.count(), 0);
739     window->resize(windowSize);
740     QCOMPARE(window->size(), windowSize);
741     QCOMPARE(resizeSpy.count(), 1);
742     resizeSpy.clear();
743     QCOMPARE(resizeSpy.count(), 0);
744
745     QTest::qWait(250); // delayed update of dirty regions
746
747     // Enter resize mode.
748     int offset = window->style()->pixelMetric(QStyle::PM_MDIFrameWidth) / 2;
749     QPoint mousePosition(mouseReceiver->width() - qMax(offset, 2), mouseReceiver->height() - qMax(offset, 2));
750     sendMouseMove(mouseReceiver, mousePosition, Qt::NoButton);
751     sendMousePress(mouseReceiver, mousePosition);
752
753     // The window itself is the grabber in rubberband mode
754     if (!opaqueMode) {
755         mouseReceiver = window;
756         mousePosition = QPoint(window->width() - qMax(offset, 2), window->height() - qMax(offset, 2));
757     }
758
759     // Trigger resize events
760     for (int i = 0; i < geometryCount; ++i) {
761         if (mouseReceiver == window) {
762             ++mousePosition.rx();
763             ++mousePosition.ry();
764             sendMouseMove(mouseReceiver, mousePosition);
765         } else {
766             sendMouseMove(mouseReceiver, mousePosition + QPoint(1, 1));
767         }
768     }
769
770     // Leave resize mode
771     sendMouseRelease(mouseReceiver, mousePosition);
772     QCOMPARE(resizeSpy.count(), expectedGeometryCount);
773     QCOMPARE(window->size(), windowSize + QSize(geometryCount, geometryCount));
774     }
775
776     // ------------------------------ move ------------------------------
777     {
778     // setOpaqueMove
779     window->setOption(QMdiSubWindow::RubberBandMove, !opaqueMode);
780     QCOMPARE(window->testOption(QMdiSubWindow::RubberBandMove), !opaqueMode);
781
782     EventSpy moveSpy(window, QEvent::Move);
783     QCOMPARE(moveSpy.count(), 0);
784     window->move(30, 30);
785     QCOMPARE(moveSpy.count(), 1);
786     moveSpy.clear();
787
788     // Enter move mode
789     QStyleOptionTitleBar options;
790     options.initFrom(window);
791     int height = window->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options);
792 #if defined(Q_OS_MAC)
793     // ### Remove this after mac style has been fixed
794     height -= 4;
795 #endif
796     QPoint mousePosition(window->width() / 2, height - 1);
797     sendMouseMove(window, mousePosition, Qt::NoButton);
798     sendMousePress(window, mousePosition);
799
800     // Trigger move events
801     for (int i = 0; i < geometryCount; ++i) {
802         ++mousePosition.rx();
803         ++mousePosition.ry();
804         sendMouseMove(window, mousePosition);
805     }
806
807     // Leave move mode
808     sendMouseRelease(window, mousePosition);
809     QCOMPARE(moveSpy.count(), expectedGeometryCount);
810     QCOMPARE(window->size(), windowSize + QSize(geometryCount, geometryCount));
811     }
812 }
813
814 void tst_QMdiSubWindow::setWindowFlags_data()
815 {
816     QTest::addColumn<Qt::WindowType>("windowType");
817     QTest::addColumn<Qt::WindowType>("expectedWindowType");
818     QTest::addColumn<Qt::WindowFlags>("customFlags");
819     QTest::addColumn<Qt::WindowFlags>("expectedCustomFlags");
820
821     // NB! If 'expectedCustomFlags' is set to 'Qt::WindowFlags(0)'
822     // and nothing else, it means we're expecting the same as customFlags.
823
824     // Standard window types with no custom flags set.
825     QTest::newRow("Qt::Widget") << Qt::Widget << Qt::SubWindow
826                                 << Qt::WindowFlags(0) << StandardWindowFlags;
827     QTest::newRow("Qt::Window") << Qt::Window << Qt::SubWindow
828                                 << Qt::WindowFlags(0) << StandardWindowFlags;
829     QTest::newRow("Qt::Dialog") << Qt::Dialog << Qt::SubWindow
830                                 << Qt::WindowFlags(0) << DialogWindowFlags;
831     QTest::newRow("Qt::Sheet") << Qt::Sheet << Qt::SubWindow
832                                << Qt::WindowFlags(0) << StandardWindowFlags;
833     QTest::newRow("Qt::Drawer") << Qt::Drawer << Qt::SubWindow
834                                 << Qt::WindowFlags(0) << StandardWindowFlags;
835     QTest::newRow("Qt::Popup") << Qt::Popup << Qt::SubWindow
836                                << Qt::WindowFlags(0) << StandardWindowFlags;
837     QTest::newRow("Qt::Tool") << Qt::Tool << Qt::SubWindow
838                               << Qt::WindowFlags(0) << StandardWindowFlags;
839     QTest::newRow("Qt::ToolTip") << Qt::ToolTip << Qt::SubWindow
840                                  << Qt::WindowFlags(0) << StandardWindowFlags;
841     QTest::newRow("Qt::SplashScreen") << Qt::SplashScreen << Qt::SubWindow
842                                       << Qt::WindowFlags(0) << StandardWindowFlags;
843     QTest::newRow("Qt::Desktop") << Qt::Desktop << Qt::SubWindow
844                                  << Qt::WindowFlags(0) << StandardWindowFlags;
845     QTest::newRow("Qt::SubWindow") << Qt::SubWindow << Qt::SubWindow
846                                    << Qt::WindowFlags(0) << StandardWindowFlags;
847
848     // Custom flags
849     QTest::newRow("Title") << Qt::SubWindow << Qt::SubWindow
850                            << (Qt::WindowTitleHint | Qt::WindowFlags(0))
851                            << Qt::WindowFlags(0);
852     QTest::newRow("TitleAndMin") << Qt::SubWindow << Qt::SubWindow
853                                  << (Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint)
854                                  << Qt::WindowFlags(0);
855     QTest::newRow("TitleAndMax") << Qt::SubWindow << Qt::SubWindow
856                                  << (Qt::WindowTitleHint | Qt::WindowMaximizeButtonHint)
857                                  << Qt::WindowFlags(0);
858     QTest::newRow("TitleAndMinMax") << Qt::SubWindow << Qt::SubWindow
859                                     << (Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint)
860                                     << Qt::WindowFlags(0);
861     QTest::newRow("Standard") << Qt::SubWindow << Qt::SubWindow
862                               << StandardWindowFlags
863                               << Qt::WindowFlags(0);
864     QTest::newRow("StandardAndShade") << Qt::SubWindow << Qt::SubWindow
865                                       << (StandardWindowFlags | Qt::WindowShadeButtonHint)
866                                       << Qt::WindowFlags(0);
867     QTest::newRow("StandardAndContext") << Qt::SubWindow << Qt::SubWindow
868                                         << (StandardWindowFlags | Qt::WindowContextHelpButtonHint)
869                                         << Qt::WindowFlags(0);
870     QTest::newRow("StandardAndStaysOnTop") << Qt::SubWindow << Qt::SubWindow
871                                            << (StandardWindowFlags | Qt::WindowStaysOnTopHint)
872                                            << Qt::WindowFlags(0);
873     QTest::newRow("StandardAndFrameless") << Qt::SubWindow << Qt::SubWindow
874                                           << (StandardWindowFlags | Qt::FramelessWindowHint)
875                                           << (Qt::FramelessWindowHint | Qt::WindowFlags(0));
876     QTest::newRow("StandardAndFramelessAndStaysOnTop") << Qt::SubWindow << Qt::SubWindow
877                                                        << (StandardWindowFlags | Qt::FramelessWindowHint
878                                                            | Qt::WindowStaysOnTopHint)
879                                                        << (Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint);
880     QTest::newRow("Shade") << Qt::SubWindow << Qt::SubWindow
881                            << (Qt::WindowShadeButtonHint | Qt::WindowFlags(0))
882                            << (StandardWindowFlags | Qt::WindowShadeButtonHint);
883     QTest::newRow("ShadeAndCustomize") << Qt::SubWindow << Qt::SubWindow
884                            << (Qt::WindowShadeButtonHint | Qt::CustomizeWindowHint)
885                            << Qt::WindowFlags(0);
886     QTest::newRow("Context") << Qt::SubWindow << Qt::SubWindow
887                              << (Qt::WindowContextHelpButtonHint | Qt::WindowFlags(0))
888                              << (StandardWindowFlags | Qt::WindowContextHelpButtonHint);
889     QTest::newRow("ContextAndCustomize") << Qt::SubWindow << Qt::SubWindow
890                              << (Qt::WindowContextHelpButtonHint | Qt::CustomizeWindowHint)
891                              << Qt::WindowFlags(0);
892     QTest::newRow("ShadeAndContext") << Qt::SubWindow << Qt::SubWindow
893                              << (Qt::WindowShadeButtonHint | Qt::WindowContextHelpButtonHint)
894                              << (StandardWindowFlags | Qt::WindowShadeButtonHint | Qt::WindowContextHelpButtonHint);
895     QTest::newRow("ShadeAndContextAndCustomize") << Qt::SubWindow << Qt::SubWindow
896                              << (Qt::WindowShadeButtonHint | Qt::WindowContextHelpButtonHint | Qt::CustomizeWindowHint)
897                              << Qt::WindowFlags(0);
898     QTest::newRow("OnlyCustomize") << Qt::SubWindow << Qt::SubWindow
899                                    << (Qt::CustomizeWindowHint | Qt::WindowFlags(0))
900                                    << Qt::WindowFlags(0);
901 }
902
903 void tst_QMdiSubWindow::setWindowFlags()
904 {
905     QSKIP("Until we have a QEvent::WindowFlagsChange event, this will skip");
906     QFETCH(Qt::WindowType, windowType);
907     QFETCH(Qt::WindowType, expectedWindowType);
908     QFETCH(Qt::WindowFlags, customFlags);
909     QFETCH(Qt::WindowFlags, expectedCustomFlags);
910
911     QMdiArea workspace;
912     QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget));
913     qApp->processEvents();
914     workspace.show();
915     window->show();
916 #if defined(Q_WS_X11)
917     qt_x11_wait_for_window_manager(&workspace);
918 #endif
919
920     window->setWindowFlags(windowType | customFlags);
921     QCOMPARE(window->windowType(), expectedWindowType);
922     if (!expectedCustomFlags) // We expect the same as 'customFlags'
923         QCOMPARE(window->windowFlags() & ~expectedWindowType, customFlags);
924     else
925         QCOMPARE(window->windowFlags() & ~expectedWindowType, expectedCustomFlags);
926
927 }
928
929 void tst_QMdiSubWindow::mouseDoubleClick()
930 {
931     QMdiArea workspace;
932     QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget));
933     qApp->processEvents();
934     workspace.show();
935     window->show();
936
937     QVERIFY(!window->isMaximized());
938     QVERIFY(!window->isShaded());
939
940     QRect originalGeometry = window->geometry();
941
942     // Calculate mouse position
943     QStyleOptionTitleBar options;
944     options.initFrom(window);
945     int height = window->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options);
946     // ### Remove this after mac style has been fixed
947     if (window->style()->inherits("QMacStyle"))
948         height -= 4;
949     // has border
950     if (!window->style()->styleHint(QStyle::SH_TitleBar_NoBorder, &options, window))
951         height += window->isMinimized() ? 8 : 4;
952     QPoint mousePosition(window->width() / 2, height - 1);
953     sendMouseMove(window, mousePosition, Qt::NoButton);
954
955     // Without Qt::WindowShadeButtonHint flag set
956     sendMouseDoubleClick(window, mousePosition);
957     qApp->processEvents();
958     QVERIFY(window->isMaximized());
959
960     sendMouseDoubleClick(window, mousePosition);
961     qApp->processEvents();
962     QVERIFY(!window->isMaximized());
963     QCOMPARE(window->geometry(), originalGeometry);
964
965     // With Qt::WindowShadeButtonHint flag set
966     QSKIP("Until we have a QEvent::WindowFlagsChange event, this will skip");
967     window->setWindowFlags(window->windowFlags() | Qt::WindowShadeButtonHint);
968     QVERIFY(window->windowFlags() & Qt::WindowShadeButtonHint);
969     originalGeometry = window->geometry();
970     sendMouseDoubleClick(window, mousePosition);
971     qApp->processEvents();
972     QVERIFY(window->isShaded());
973
974     sendMouseDoubleClick(window, mousePosition);
975     qApp->processEvents();
976     QVERIFY(!window->isShaded());
977     QCOMPARE(window->geometry(), originalGeometry);
978
979     window->showMinimized();
980     QVERIFY(window->isMinimized());
981     sendMouseDoubleClick(window, mousePosition);
982     QVERIFY(!window->isMinimized());
983     QCOMPARE(window->geometry(), originalGeometry);
984 }
985
986 void tst_QMdiSubWindow::setSystemMenu()
987 {
988     QMdiSubWindow *subWindow = new QMdiSubWindow;
989     subWindow->resize(200, 50);
990     QPointer<QMenu>systemMenu = subWindow->systemMenu();
991     QVERIFY(systemMenu);
992     QCOMPARE(subWindow->actions(), systemMenu->actions());
993
994     QMainWindow mainWindow;
995     QMdiArea *mdiArea = new QMdiArea;
996     mdiArea->addSubWindow(subWindow);
997     mainWindow.setCentralWidget(mdiArea);
998     mainWindow.menuBar();
999     mainWindow.show();
1000     QTest::qWaitForWindowShown(&mainWindow);
1001     QTest::qWait(60);
1002
1003
1004     QTRY_VERIFY(subWindow->isVisible());
1005     QPoint globalPopupPos;
1006
1007     // Show system menu
1008     QVERIFY(!qApp->activePopupWidget());
1009     subWindow->showSystemMenu();
1010     QTest::qWait(25);
1011     QTRY_COMPARE(qApp->activePopupWidget(), qobject_cast<QWidget *>(systemMenu));
1012     QTRY_COMPARE(systemMenu->mapToGlobal(QPoint(0, 0)),
1013                  (globalPopupPos = subWindow->mapToGlobal(subWindow->contentsRect().topLeft())) );
1014
1015     systemMenu->hide();
1016     QVERIFY(!qApp->activePopupWidget());
1017
1018     QTest::ignoreMessage(QtWarningMsg, "QMdiSubWindow::setSystemMenu: system menu is already set");
1019     subWindow->setSystemMenu(systemMenu);
1020
1021     subWindow->setSystemMenu(0);
1022     QVERIFY(!systemMenu); // systemMenu is QPointer
1023
1024     systemMenu = new QMenu(subWindow);
1025     systemMenu->addAction(QIcon(subWindow->style()->standardIcon(QStyle::SP_TitleBarCloseButton)),
1026                           QObject::tr("&Close"), subWindow, SLOT(close()));
1027     subWindow->setSystemMenu(systemMenu);
1028     QCOMPARE(subWindow->systemMenu(), qobject_cast<QMenu *>(systemMenu));
1029     QCOMPARE(subWindow->systemMenu()->parentWidget(), static_cast<QWidget *>(subWindow));
1030     QCOMPARE(subWindow->systemMenu()->actions().count(), 1);
1031
1032     // Show the new system menu
1033     QVERIFY(!qApp->activePopupWidget());
1034     subWindow->showSystemMenu();
1035     QTest::qWait(25);
1036     QTRY_COMPARE(qApp->activePopupWidget(), qobject_cast<QWidget *>(systemMenu));
1037     QTRY_COMPARE(systemMenu->mapToGlobal(QPoint(0, 0)), globalPopupPos);
1038
1039     systemMenu->hide();
1040     QVERIFY(!qApp->activePopupWidget());
1041
1042 #if !defined (Q_OS_MAC) && !defined (Q_OS_WINCE)
1043     // System menu in menu bar.
1044     subWindow->showMaximized();
1045     QVERIFY(subWindow->isMaximized());
1046     QWidget *menuLabel = subWindow->maximizedSystemMenuIconWidget();
1047     QVERIFY(menuLabel);
1048     subWindow->showSystemMenu();
1049     QTest::qWait(25);
1050     QTRY_COMPARE(qApp->activePopupWidget(), qobject_cast<QWidget *>(systemMenu));
1051      QCOMPARE(systemMenu->mapToGlobal(QPoint(0, 0)),
1052               (globalPopupPos = menuLabel->mapToGlobal(QPoint(0, menuLabel->y() + menuLabel->height()))));
1053     systemMenu->hide();
1054     QTRY_VERIFY(!qApp->activePopupWidget());
1055     subWindow->showNormal();
1056 #endif
1057
1058     // Reverse
1059     qApp->setLayoutDirection(Qt::RightToLeft);
1060     qApp->processEvents();
1061     mainWindow.updateGeometry();
1062     QTest::qWait(150);
1063
1064     subWindow->showSystemMenu();
1065     QTest::qWait(250);
1066     QTRY_COMPARE(qApp->activePopupWidget(), qobject_cast<QWidget *>(systemMenu));
1067     // + QPoint(1, 0) because topRight() == QPoint(left() + width() -1, top())
1068     globalPopupPos = subWindow->mapToGlobal(subWindow->contentsRect().topRight()) + QPoint(1, 0);
1069     globalPopupPos -= QPoint(systemMenu->sizeHint().width(), 0);
1070     QTRY_COMPARE(systemMenu->mapToGlobal(QPoint(0, 0)), globalPopupPos);
1071
1072     systemMenu->hide();
1073     QVERIFY(!qApp->activePopupWidget());
1074
1075 #if !defined (Q_OS_MAC) && !defined (Q_OS_WINCE)
1076     // System menu in menu bar in reverse mode.
1077     subWindow->showMaximized();
1078     QVERIFY(subWindow->isMaximized());
1079     menuLabel = subWindow->maximizedSystemMenuIconWidget();
1080     QVERIFY(menuLabel);
1081     subWindow->showSystemMenu();
1082     QTest::qWait(250);
1083     QTRY_COMPARE(qApp->activePopupWidget(), qobject_cast<QWidget *>(systemMenu));
1084     globalPopupPos = menuLabel->mapToGlobal(QPoint(menuLabel->width(), menuLabel->y() + menuLabel->height()));
1085     globalPopupPos -= QPoint(systemMenu->sizeHint().width(), 0);
1086     QTRY_COMPARE(systemMenu->mapToGlobal(QPoint(0, 0)), globalPopupPos);
1087 #endif
1088
1089     delete systemMenu;
1090     QVERIFY(!qApp->activePopupWidget());
1091     QVERIFY(!subWindow->systemMenu());
1092
1093     // Restore layout direction.
1094     qApp->setLayoutDirection(Qt::LeftToRight);
1095 }
1096
1097 void tst_QMdiSubWindow::restoreFocus()
1098 {
1099     // Create complex layout.
1100     QGroupBox *box = new QGroupBox(tr("GroupBox"));
1101     box->setCheckable(true);
1102
1103     QGroupBox *box1 = new QGroupBox(tr("&TopLeft"));
1104     box1->setLayout(new QHBoxLayout);
1105     box1->layout()->addWidget(new QTextEdit);
1106
1107     QGroupBox *box2 = new QGroupBox(tr("&TopRight"));
1108     box2->setLayout(new QHBoxLayout);
1109     box2->layout()->addWidget(new QTextEdit);
1110
1111     QGroupBox *box3 = new QGroupBox(tr("&BottomLeft"));
1112     box3->setLayout(new QHBoxLayout);
1113     box3->layout()->addWidget(new QTextEdit);
1114
1115     QGroupBox *box4 = new QGroupBox(tr("&BottomRight"));
1116     box4->setLayout(new QHBoxLayout);
1117     QMdiArea *nestedWorkspace = new QMdiArea;
1118     for (int i = 0; i < 4; ++i)
1119         nestedWorkspace->addSubWindow(new QTextEdit)->show();
1120     qApp->processEvents();
1121     nestedWorkspace->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1122     nestedWorkspace->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
1123     box4->layout()->addWidget(nestedWorkspace);
1124
1125     QGridLayout *layout = new QGridLayout;
1126     layout->addWidget(box1, 0, 0);
1127     layout->addWidget(box2, 0, 1);
1128     layout->addWidget(box3, 1, 0);
1129     layout->addWidget(box4, 1, 1);
1130
1131     box->setLayout(layout);
1132
1133     // Add complex widget to workspace.
1134     QMdiArea topArea;
1135     QMdiSubWindow *complexWindow = topArea.addSubWindow(box);
1136     topArea.show();
1137     box->show();
1138
1139     qApp->setActiveWindow(&topArea);
1140     QMdiSubWindow *expectedFocusWindow = nestedWorkspace->subWindowList().last();
1141     QVERIFY(expectedFocusWindow);
1142     QVERIFY(expectedFocusWindow->widget());
1143     QCOMPARE(qApp->focusWidget(), expectedFocusWindow->widget());
1144
1145     // Normal -> minimized
1146     expectedFocusWindow->showMinimized();
1147     qApp->processEvents();
1148     QVERIFY(expectedFocusWindow->isMinimized());
1149     QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(expectedFocusWindow));
1150
1151     // Minimized -> normal
1152     expectedFocusWindow->showNormal();
1153     qApp->processEvents();
1154     QVERIFY(!expectedFocusWindow->isMinimized());
1155     QCOMPARE(qApp->focusWidget(), expectedFocusWindow->widget());
1156
1157     // Normal -> maximized
1158     expectedFocusWindow->showMaximized();
1159     qApp->processEvents();
1160     QVERIFY(expectedFocusWindow->isMaximized());
1161     QCOMPARE(qApp->focusWidget(), expectedFocusWindow->widget());
1162
1163     // Maximized -> normal
1164     expectedFocusWindow->showNormal();
1165     qApp->processEvents();
1166     QVERIFY(!expectedFocusWindow->isMaximized());
1167     QCOMPARE(qApp->focusWidget(), expectedFocusWindow->widget());
1168
1169     // Minimized -> maximized
1170     expectedFocusWindow->showMinimized();
1171     qApp->processEvents();
1172     QVERIFY(expectedFocusWindow->isMinimized());
1173     expectedFocusWindow->showMaximized();
1174     qApp->processEvents();
1175     QVERIFY(expectedFocusWindow->isMaximized());
1176     QCOMPARE(qApp->focusWidget(), expectedFocusWindow->widget());
1177
1178     // Maximized -> minimized
1179     expectedFocusWindow->showNormal();
1180     qApp->processEvents();
1181     QVERIFY(!expectedFocusWindow->isMaximized());
1182     expectedFocusWindow->showMaximized();
1183     qApp->processEvents();
1184     QVERIFY(expectedFocusWindow->isMaximized());
1185     expectedFocusWindow->showMinimized();
1186     qApp->processEvents();
1187     QVERIFY(expectedFocusWindow->isMinimized());
1188     QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(expectedFocusWindow));
1189
1190     complexWindow->showMinimized();
1191     qApp->processEvents();
1192     QVERIFY(complexWindow->isMinimized());
1193     QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(complexWindow));
1194
1195     complexWindow->showNormal();
1196     qApp->processEvents();
1197     QVERIFY(!complexWindow->isMinimized());
1198     QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(expectedFocusWindow));
1199 }
1200
1201 void tst_QMdiSubWindow::changeFocusWithTab()
1202 {
1203     QWidget *widget = new QWidget;
1204     widget->setLayout(new QVBoxLayout);
1205
1206     QLineEdit *firstLineEdit = new QLineEdit;
1207     widget->layout()->addWidget(firstLineEdit);
1208     QLineEdit *secondLineEdit = new QLineEdit;
1209     widget->layout()->addWidget(secondLineEdit);
1210     QLineEdit *thirdLineEdit = new QLineEdit;
1211     widget->layout()->addWidget(thirdLineEdit);
1212
1213     QMdiArea mdiArea;
1214     mdiArea.addSubWindow(widget);
1215     mdiArea.show();
1216     QCOMPARE(mdiArea.subWindowList().count(), 1);
1217
1218     qApp->setActiveWindow(&mdiArea);
1219     QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(firstLineEdit));
1220
1221     // Next
1222     QTest::keyPress(widget, Qt::Key_Tab);
1223     QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(secondLineEdit));
1224
1225     // Next
1226     QTest::keyPress(widget, Qt::Key_Tab);
1227     QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(thirdLineEdit));
1228
1229     // Previous
1230     QTest::keyPress(widget, Qt::Key_Backtab);
1231     QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(secondLineEdit));
1232
1233     // Previous
1234     QTest::keyPress(widget, Qt::Key_Backtab);
1235     QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(firstLineEdit));
1236
1237     QMdiSubWindow *window = mdiArea.addSubWindow(new QPushButton);
1238     window->show();
1239     QCOMPARE(mdiArea.activeSubWindow(), window);
1240
1241     // Check that we don't give away focus to another window by
1242     // just hitting tab if the child widget does not accept
1243     // focus (which is the case for a QPushButton).
1244     QTest::keyPress(window, Qt::Key_Tab);
1245     QCOMPARE(mdiArea.activeSubWindow(), window);
1246     QCOMPARE(qApp->focusWidget(), tabAllWidgets() ? window->widget() : window);
1247     QTest::keyPress(window, Qt::Key_Tab);
1248     QCOMPARE(mdiArea.activeSubWindow(), window);
1249     QCOMPARE(qApp->focusWidget(), tabAllWidgets() ? window->widget() : window);
1250 }
1251
1252 class MyTextEdit : public QTextEdit
1253 {
1254 public:
1255     MyTextEdit(QWidget *parent = 0) : QTextEdit(parent), acceptClose(false) {}
1256     void setAcceptClose(bool enable = true) { acceptClose = enable; }
1257 protected:
1258     void closeEvent(QCloseEvent *closeEvent)
1259     {
1260         if (!acceptClose)
1261             closeEvent->ignore();
1262     }
1263
1264 private:
1265     bool acceptClose;
1266 };
1267
1268 void tst_QMdiSubWindow::closeEvent()
1269 {
1270     QMdiArea mdiArea;
1271     mdiArea.show();
1272
1273     MyTextEdit *textEdit = new MyTextEdit;
1274     textEdit->setAcceptClose(false);
1275     QMdiSubWindow *window = mdiArea.addSubWindow(textEdit);
1276     EventSpy closeSpy(window->widget(), QEvent::Close);
1277     window->show();
1278
1279     QCOMPARE(closeSpy.count(), 0);
1280     QVERIFY(window->isVisible());
1281     QVERIFY(textEdit->isVisible());
1282
1283     QVERIFY(!window->close());
1284     QCOMPARE(closeSpy.count(), 1);
1285     QVERIFY(window->isVisible());
1286     QVERIFY(textEdit->isVisible());
1287
1288     QVERIFY(!textEdit->close());
1289     QCOMPARE(closeSpy.count(), 2);
1290     QVERIFY(window->isVisible());
1291     QVERIFY(textEdit->isVisible());
1292
1293     textEdit->setAcceptClose(true);
1294
1295     QVERIFY(window->close());
1296     QCOMPARE(closeSpy.count(), 3);
1297     QCOMPARE(mdiArea.subWindowList().count(), 0);
1298 }
1299
1300 // There exists more tests in QMdiArea which covers window title support
1301 // related to QMainWindow. This test is specific for QMdiSubWindow and its
1302 // widget.
1303 void tst_QMdiSubWindow::setWindowTitle()
1304 {
1305     QString expectedWindowTitle = QLatin1String("This is teh shit[*]");
1306     QTextEdit *textEdit = new QTextEdit;
1307     textEdit->setWindowTitle(expectedWindowTitle);
1308     QCOMPARE(textEdit->windowTitle(), expectedWindowTitle);
1309     textEdit->setWindowModified(true);
1310     QCOMPARE(textEdit->isWindowModified(), true);
1311
1312     QMdiArea mdiArea;
1313     QMdiSubWindow *window = new QMdiSubWindow;
1314     mdiArea.addSubWindow(window);
1315     QCOMPARE(window->windowTitle(), QString());
1316     QVERIFY(!window->isWindowModified());
1317
1318     window->setWidget(textEdit);
1319     QVERIFY(window->isWindowModified());
1320     QCOMPARE(textEdit->windowTitle(), expectedWindowTitle);
1321     QCOMPARE(window->windowTitle(), window->widget()->windowTitle());
1322
1323     textEdit->setWindowModified(false);
1324     QVERIFY(!textEdit->isWindowModified());
1325     QVERIFY(!window->isWindowModified());
1326     // This will return the title including the astrix, but the
1327     // actual window title does not contain the astrix. This behavior
1328     // seems a bit odd, but is equal to e.g. QTextEdit (and probably all
1329     // other widgets which are not real top-level widgets).
1330     QCOMPARE(window->windowTitle(), expectedWindowTitle);
1331
1332     textEdit->setWindowModified(true);;
1333     expectedWindowTitle = QLatin1String("Override child title");
1334     window->setWindowTitle(expectedWindowTitle);
1335     QVERIFY(window->isWindowModified());
1336     QCOMPARE(window->windowTitle(), expectedWindowTitle);
1337
1338     textEdit->setWindowTitle(QLatin1String("My parent overrides me"));
1339     QCOMPARE(window->windowTitle(), expectedWindowTitle);
1340
1341     textEdit->setWindowModified(false);
1342     QVERIFY(window->isWindowModified());
1343     QCOMPARE(window->windowTitle(), expectedWindowTitle);
1344
1345     window->setWindowModified(false);
1346     QVERIFY(!window->isWindowModified());
1347     window->setWindowTitle(QString());
1348     QCOMPARE(window->windowTitle(), QString());
1349
1350     expectedWindowTitle = QLatin1String("My parent doesn't have any title so now I can set one[*]");
1351     textEdit->setWindowTitle(expectedWindowTitle);
1352     QCOMPARE(window->windowTitle(), expectedWindowTitle);
1353     textEdit->setWindowModified(true);
1354     QVERIFY(window->isWindowModified());
1355
1356     window->setWidget(0);
1357     QCOMPARE(window->windowTitle(), QString());
1358     QVERIFY(!window->isWindowModified());
1359     delete textEdit;
1360 }
1361
1362 void tst_QMdiSubWindow::resizeEvents_data()
1363 {
1364     QTest::addColumn<Qt::WindowState>("windowState");
1365     QTest::addColumn<int>("expectedWindowResizeEvents");
1366     QTest::addColumn<int>("expectedWidgetResizeEvents");
1367     QTest::addColumn<bool>("isShadeMode");
1368
1369     QTest::newRow("minimized") << Qt::WindowMinimized << 1 << 0 << false;
1370     QTest::newRow("maximized") << Qt::WindowMaximized << 1 << 1 << false;
1371     QTest::newRow("shaded") << Qt::WindowMinimized << 1 << 0 << true;
1372 }
1373
1374 void tst_QMdiSubWindow::resizeEvents()
1375 {
1376     QFETCH(Qt::WindowState, windowState);
1377     QFETCH(int, expectedWindowResizeEvents);
1378     QFETCH(int, expectedWidgetResizeEvents);
1379     QFETCH(bool, isShadeMode);
1380
1381     QMainWindow mainWindow;
1382     QMdiArea *mdiArea = new QMdiArea;
1383     mainWindow.setCentralWidget(mdiArea);
1384     mainWindow.show();
1385 #if defined(Q_WS_X11)
1386     qt_x11_wait_for_window_manager(&mainWindow);
1387 #endif
1388
1389     QMdiSubWindow *window = mdiArea->addSubWindow(new QTextEdit);
1390     window->show();
1391
1392     EventSpy windowResizeEventSpy(window, QEvent::Resize);
1393     QCOMPARE(windowResizeEventSpy.count(), 0);
1394     EventSpy widgetResizeEventSpy(window->widget(), QEvent::Resize);
1395     QCOMPARE(widgetResizeEventSpy.count(), 0);
1396
1397     // Set the window state.
1398     if (!isShadeMode)
1399         window->setWindowState(windowState);
1400     else
1401         window->showShaded();
1402
1403     // Check that the window state is correct.
1404     QCOMPARE(window->windowState(), windowState | Qt::WindowActive);
1405     QCOMPARE(window->widget()->windowState(), windowState);
1406
1407     // Make sure we got as many resize events as expected.
1408     QCOMPARE(windowResizeEventSpy.count(), expectedWindowResizeEvents);
1409     QCOMPARE(widgetResizeEventSpy.count(), expectedWidgetResizeEvents);
1410     windowResizeEventSpy.clear();
1411     widgetResizeEventSpy.clear();
1412
1413     // Normalize.
1414     window->showNormal();
1415
1416     // Check that the window state is correct.
1417     QCOMPARE(window->windowState(), Qt::WindowNoState | Qt::WindowActive);
1418     QCOMPARE(window->widget()->windowState(), Qt::WindowNoState);
1419
1420     // Make sure we got as many resize events as expected.
1421     QCOMPARE(windowResizeEventSpy.count(), expectedWindowResizeEvents);
1422     QCOMPARE(widgetResizeEventSpy.count(), expectedWidgetResizeEvents);
1423 }
1424
1425 #if defined(Q_OS_MAC)
1426 void tst_QMdiSubWindow::defaultSizeGrip()
1427 {
1428     if (!qApp->style()->inherits("QMacStyle"))
1429         return;
1430     QMdiArea mdiArea;
1431     mdiArea.show();
1432
1433     // QSizeGrip on windows with decoration.
1434     QMdiSubWindow *windowWithDecoration = mdiArea.addSubWindow(new QWidget);
1435     windowWithDecoration->show();
1436     QVERIFY(qFindChild<QSizeGrip *>(windowWithDecoration));
1437
1438     // ...but not on windows without decoration (Qt::FramelessWindowHint).
1439     QMdiSubWindow *windowWithoutDecoration = mdiArea.addSubWindow(new QWidget, Qt::FramelessWindowHint);
1440     windowWithoutDecoration->show();
1441     QVERIFY(!qFindChild<QSizeGrip *>(windowWithoutDecoration));
1442 }
1443 #endif
1444
1445 void tst_QMdiSubWindow::hideAndShow()
1446 {
1447     // Create a QTabWidget with two tabs; QMdiArea and QTextEdit.
1448     QTabWidget *tabWidget = new QTabWidget;
1449     QMdiArea *mdiArea = new QMdiArea;
1450     tabWidget->addTab(mdiArea, QLatin1String("QMdiArea"));
1451     tabWidget->addTab(new QTextEdit, QLatin1String("Dummy"));
1452
1453     // Set the tab widget as the central widget in QMainWindow.
1454     QMainWindow mainWindow;
1455     mainWindow.setGeometry(0, 0, 640, 480);
1456     QMenuBar *menuBar = mainWindow.menuBar();
1457     mainWindow.setCentralWidget(tabWidget);
1458     mainWindow.show();
1459 #ifdef Q_WS_X11
1460     qt_x11_wait_for_window_manager(&mainWindow);
1461 #endif
1462
1463     QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner));
1464     QMdiSubWindow *subWindow = mdiArea->addSubWindow(new QTextEdit);
1465     subWindow->showMaximized();
1466 #if !defined (Q_OS_MAC) && !defined (Q_OS_WINCE)
1467     QVERIFY(menuBar->cornerWidget(Qt::TopRightCorner));
1468     QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget());
1469 #endif
1470
1471     // Hide QMdiArea.
1472     tabWidget->setCurrentIndex(1);
1473
1474     QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner));
1475     QVERIFY(!subWindow->maximizedButtonsWidget());
1476     QVERIFY(!subWindow->maximizedSystemMenuIconWidget());
1477
1478     // Show QMdiArea.
1479     tabWidget->setCurrentIndex(0);
1480
1481 #if !defined (Q_OS_MAC) && !defined (Q_OS_WINCE)
1482     QVERIFY(menuBar->cornerWidget(Qt::TopRightCorner));
1483     QVERIFY(subWindow->maximizedButtonsWidget());
1484     QVERIFY(subWindow->maximizedSystemMenuIconWidget());
1485     QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget());
1486 #endif
1487
1488     // Hide QMdiArea.
1489     tabWidget->setCurrentIndex(1);
1490
1491     // Add few more windows.
1492     for (int i = 0; i < 5; ++i)
1493         mdiArea->addSubWindow(new QTextEdit);
1494
1495     // Show QMdiArea.
1496     tabWidget->setCurrentIndex(0);
1497     qApp->processEvents();
1498
1499     subWindow = mdiArea->subWindowList().back();
1500     QVERIFY(subWindow);
1501     QCOMPARE(mdiArea->activeSubWindow(), subWindow);
1502
1503 #if !defined (Q_OS_MAC) && !defined (Q_OS_WINCE)
1504     QVERIFY(menuBar->cornerWidget(Qt::TopRightCorner));
1505     QVERIFY(subWindow->maximizedButtonsWidget());
1506     QVERIFY(subWindow->maximizedSystemMenuIconWidget());
1507     QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget());
1508 #endif
1509
1510     subWindow->showNormal();
1511     QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner));
1512
1513     // Check that newly added windows got right sizes.
1514     foreach (QMdiSubWindow *window, mdiArea->subWindowList())
1515         QCOMPARE(window->size(), window->sizeHint());
1516
1517     subWindow->showMaximized();
1518 #ifndef Q_OS_MAC
1519     QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget());
1520 #endif
1521
1522     subWindow->hide();
1523     QVERIFY(!subWindow->maximizedButtonsWidget());
1524     QVERIFY(!subWindow->maximizedSystemMenuIconWidget());
1525     QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner));
1526
1527     subWindow->show();
1528 #if !defined (Q_OS_MAC) && !defined (Q_OS_WINCE)
1529     QVERIFY(subWindow->maximizedButtonsWidget());
1530     QVERIFY(subWindow->maximizedSystemMenuIconWidget());
1531     QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget());
1532 #endif
1533
1534     // Hide QMainWindow.
1535     mainWindow.hide();
1536     QVERIFY(!subWindow->maximizedButtonsWidget());
1537     QVERIFY(!subWindow->maximizedSystemMenuIconWidget());
1538     QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner));
1539
1540     // Show QMainWindow.
1541     mainWindow.show();
1542 #if !defined (Q_OS_MAC) && !defined (Q_OS_WINCE)
1543     QVERIFY(subWindow->maximizedButtonsWidget());
1544     QVERIFY(subWindow->maximizedSystemMenuIconWidget());
1545     QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget());
1546 #endif
1547 }
1548
1549 void tst_QMdiSubWindow::keepWindowMaximizedState()
1550 {
1551     QMdiArea mdiArea;
1552     QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QTextEdit);
1553     mdiArea.show();
1554 #ifdef Q_WS_X11
1555     qt_x11_wait_for_window_manager(&mdiArea);
1556 #endif
1557
1558     subWindow->showMaximized();
1559     QVERIFY(subWindow->isMaximized());
1560
1561     // move
1562     const QPoint newPosition = subWindow->pos() + QPoint(10, 10);
1563     subWindow->move(newPosition);
1564     QCOMPARE(subWindow->pos(), newPosition);
1565     QVERIFY(subWindow->isMaximized());
1566
1567     // resize
1568     const QSize newSize = subWindow->size() - QSize(10, 10);
1569     subWindow->resize(newSize);
1570     QCOMPARE(subWindow->size(), newSize);
1571     QVERIFY(subWindow->isMaximized());
1572
1573     // setGeometry
1574     const QRect newGeometry = QRect(newPosition - QPoint(10, 10), newSize + QSize(10, 10));
1575     subWindow->setGeometry(newGeometry);
1576     QCOMPARE(subWindow->geometry(), newGeometry);
1577     QVERIFY(subWindow->isMaximized());
1578
1579     subWindow->showNormal();
1580
1581     // Verify that we don't force Qt::WindowMaximized.
1582     QVERIFY(!subWindow->isMaximized());
1583     subWindow->setGeometry(QRect(newPosition, newSize));
1584     QCOMPARE(subWindow->geometry(), QRect(newPosition, newSize));
1585     QVERIFY(!subWindow->isMaximized());
1586 }
1587
1588 void tst_QMdiSubWindow::explicitlyHiddenWidget()
1589 {
1590     QMdiArea mdiArea;
1591     QTextEdit *textEdit = new QTextEdit;
1592     textEdit->hide();
1593     QMdiSubWindow *subWindow = mdiArea.addSubWindow(textEdit);
1594     mdiArea.show();
1595 #ifdef Q_WS_X11
1596     qt_x11_wait_for_window_manager(&mdiArea);
1597 #endif
1598
1599     QVERIFY(subWindow->isVisible());
1600     QVERIFY(!textEdit->isVisible());
1601
1602     textEdit->show();
1603     QVERIFY(textEdit->isVisible());
1604
1605     // normal -> minimized
1606     subWindow->showMinimized();
1607     QVERIFY(subWindow->isVisible());
1608     QVERIFY(!textEdit->isVisible());
1609
1610     // minimized -> normal
1611     subWindow->showNormal();
1612     QVERIFY(subWindow->isVisible());
1613     QVERIFY(textEdit->isVisible());
1614
1615     // minimized -> maximized
1616     subWindow->showMinimized();
1617     subWindow->showMaximized();
1618     QVERIFY(subWindow->isVisible());
1619     QVERIFY(textEdit->isVisible());
1620
1621     textEdit->hide();
1622
1623     // maximized -> normal
1624     subWindow->showNormal();
1625     QVERIFY(subWindow->isVisible());
1626     QVERIFY(!textEdit->isVisible());
1627
1628     textEdit->show();
1629
1630     subWindow->showMinimized();
1631     subWindow->setWidget(0);
1632     delete textEdit;
1633     textEdit = new QTextEdit;
1634     textEdit->hide();
1635     subWindow->setWidget(textEdit);
1636     subWindow->showNormal();
1637     QVERIFY(subWindow->isVisible());
1638     QVERIFY(!textEdit->isVisible());
1639 }
1640
1641 void tst_QMdiSubWindow::resizeTimer()
1642 {
1643     QMdiArea mdiArea;
1644     QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QWidget);
1645     mdiArea.show();
1646     QTest::qWaitForWindowShown(&mdiArea);
1647     QTest::qWait(300);
1648
1649
1650     EventSpy timerEventSpy(subWindow, QEvent::Timer);
1651     QCOMPARE(timerEventSpy.count(), 0);
1652
1653     for (int i = 0; i < 20; ++i) {
1654         subWindow->resize(subWindow->size() + QSize(2, 2));
1655         qApp->processEvents();
1656     }
1657
1658     QTest::qWait(500); // Wait for timer events to occur.
1659
1660     QTRY_VERIFY(timerEventSpy.count() > 0);
1661 }
1662
1663 void tst_QMdiSubWindow::fixedMinMaxSize()
1664 {
1665     QMdiArea mdiArea;
1666     mdiArea.setGeometry(0, 0, 640, 480);
1667     mdiArea.show();
1668 #ifdef Q_WS_X11
1669     qt_x11_wait_for_window_manager(&mdiArea);
1670 #endif
1671
1672     const QSize minimumSize = QSize(250, 150);
1673     const QSize maximumSize = QSize(300, 200);
1674
1675     // Add the sub window to QMdiArea and set min/max size.
1676     QMdiSubWindow *subWindow = new QMdiSubWindow;
1677     subWindow->setMinimumSize(minimumSize);
1678     QCOMPARE(subWindow->minimumSize(), minimumSize);
1679     subWindow->setMaximumSize(maximumSize);
1680     QCOMPARE(subWindow->maximumSize(), maximumSize);
1681     mdiArea.addSubWindow(subWindow);
1682     subWindow->show();
1683     QCOMPARE(subWindow->size(), minimumSize);
1684
1685     // Calculate the size of a minimized sub window.
1686     QStyleOptionTitleBar options;
1687     options.initFrom(subWindow);
1688     int minimizedHeight = subWindow->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options);
1689 #if defined(Q_OS_MAC) && !defined(QT_NO_STYLE_MAC)
1690     // ### Remove this after mac style has been fixed
1691     if (qobject_cast<QMacStyle *>(subWindow->style()))
1692         minimizedHeight -= 4;
1693 #endif
1694     if (!subWindow->style()->styleHint(QStyle::SH_TitleBar_NoBorder, &options, subWindow))
1695         minimizedHeight += 8;
1696     int minimizedWidth = subWindow->style()->pixelMetric(QStyle::PM_MDIMinimizedWidth, &options);
1697     const QSize minimizedSize = QSize(minimizedWidth, minimizedHeight);
1698
1699     // Even though the sub window has a minimum size set, it should be possible
1700     // to minimize the window.
1701     subWindow->showMinimized();
1702     QVERIFY(subWindow->isMinimized());
1703     QCOMPARE(subWindow->size(), minimizedSize);
1704     QCOMPARE(subWindow->minimumSize(), minimizedSize);
1705
1706     // Restore minimum size.
1707     subWindow->showNormal();
1708     QVERIFY(!subWindow->isMinimized());
1709     QCOMPARE(subWindow->size(), minimumSize);
1710     QCOMPARE(subWindow->minimumSize(), minimumSize);
1711
1712     // Well, the logic here is of course broken (calling showMaximized on a window with
1713     // maximum size set), but we should handle it :)
1714     subWindow->showMaximized();
1715     QVERIFY(subWindow->isMaximized());
1716     QCOMPARE(subWindow->size(), maximumSize);
1717
1718     subWindow->showNormal();
1719     QVERIFY(!subWindow->isMaximized());
1720     QCOMPARE(subWindow->size(), minimumSize);
1721 }
1722
1723 #if !defined( Q_OS_MAC) && !defined( Q_OS_WINCE)
1724 void tst_QMdiSubWindow::replaceMenuBarWhileMaximized()
1725 {
1726
1727     QMainWindow mainWindow;
1728
1729     QMdiArea *mdiArea = new QMdiArea;
1730     QMdiSubWindow *subWindow = mdiArea->addSubWindow(new QTextEdit);
1731     subWindow->showMaximized();
1732
1733     mainWindow.setCentralWidget(mdiArea);
1734     QMenuBar *menuBar = mainWindow.menuBar();
1735     mainWindow.show();
1736 #ifdef Q_WS_X11
1737     qt_x11_wait_for_window_manager(&mainWindow);
1738 #endif
1739
1740     qApp->processEvents();
1741
1742     QVERIFY(subWindow->maximizedButtonsWidget());
1743     QVERIFY(subWindow->maximizedSystemMenuIconWidget());
1744     QCOMPARE(menuBar->cornerWidget(Qt::TopLeftCorner), subWindow->maximizedSystemMenuIconWidget());
1745     QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget());
1746
1747     // Replace.
1748     mainWindow.setMenuBar(new QMenuBar);
1749     menuBar = mainWindow.menuBar();
1750     qApp->processEvents();
1751
1752     QVERIFY(subWindow->maximizedButtonsWidget());
1753     QVERIFY(subWindow->maximizedSystemMenuIconWidget());
1754     QCOMPARE(menuBar->cornerWidget(Qt::TopLeftCorner), subWindow->maximizedSystemMenuIconWidget());
1755     QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget());
1756
1757     subWindow->showNormal();
1758     QVERIFY(!subWindow->maximizedButtonsWidget());
1759     QVERIFY(!subWindow->maximizedSystemMenuIconWidget());
1760     QVERIFY(!menuBar->cornerWidget(Qt::TopLeftCorner));
1761     QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner));
1762
1763     // Delete and replace.
1764     subWindow->showMaximized();
1765     delete menuBar;
1766     mainWindow.setMenuBar(new QMenuBar);
1767     qApp->processEvents();
1768
1769     QVERIFY(!subWindow->maximizedButtonsWidget());
1770     QVERIFY(!subWindow->maximizedSystemMenuIconWidget());
1771
1772     subWindow->showNormal();
1773     QVERIFY(!subWindow->maximizedButtonsWidget());
1774     QVERIFY(!subWindow->maximizedSystemMenuIconWidget());
1775
1776     // Delete.
1777     subWindow->showMaximized();
1778     mainWindow.setMenuBar(0);
1779     qApp->processEvents();
1780     QVERIFY(!mainWindow.menuWidget());
1781
1782     QVERIFY(!subWindow->maximizedButtonsWidget());
1783     QVERIFY(!subWindow->maximizedSystemMenuIconWidget());
1784
1785     subWindow->showNormal();
1786     QVERIFY(!subWindow->maximizedButtonsWidget());
1787     QVERIFY(!subWindow->maximizedSystemMenuIconWidget());
1788 }
1789
1790 void tst_QMdiSubWindow::closeOnDoubleClick()
1791 {
1792     QMdiArea mdiArea;
1793     QPointer<QMdiSubWindow> subWindow = mdiArea.addSubWindow(new QWidget);
1794     mdiArea.show();
1795 #ifdef Q_WS_X11
1796     qt_x11_wait_for_window_manager(&mdiArea);
1797 #endif
1798
1799     subWindow->showSystemMenu();
1800     QTest::qWait(200);
1801
1802     QPointer<QMenu> systemMenu = subWindow->systemMenu();
1803     QVERIFY(systemMenu);
1804     QVERIFY(systemMenu->isVisible());
1805
1806     sendMouseDoubleClick(systemMenu, QPoint(10, 10));
1807     if (qApp->activePopupWidget() == static_cast<QWidget *>(systemMenu))
1808         systemMenu->hide();
1809     qApp->processEvents();
1810     QVERIFY(!subWindow || !subWindow->isVisible());
1811     QVERIFY(!systemMenu || !systemMenu->isVisible());
1812 }
1813 #endif
1814
1815 void tst_QMdiSubWindow::setFont()
1816 {
1817     QSKIP("This test function is unstable in CI, please see QTBUG-22544");
1818     QMdiArea mdiArea;
1819     QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QPushButton(QLatin1String("test")));
1820     subWindow->resize(300, 100);
1821     subWindow->setWindowTitle(QLatin1String("Window title"));
1822     mdiArea.show();
1823 #ifdef Q_WS_X11
1824     qt_x11_wait_for_window_manager(&mdiArea);
1825 #endif
1826
1827     const QFont originalFont = QApplication::font("QMdiSubWindowTitleBar");
1828     QStyleOptionTitleBar opt;
1829     opt.initFrom(subWindow);
1830     const int titleBarHeight = subWindow->style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt);
1831     const QRect titleBarRect = QRect(0, 0, subWindow->width(), titleBarHeight);
1832     const QImage originalTitleBar = subWindow->grab(titleBarRect).toImage();
1833
1834     QFont newFont(QLatin1String("Helvetica"), 16);
1835     newFont.setBold(true);
1836     subWindow->setFont(newFont);
1837     qApp->processEvents();
1838     const QFont &swFont = subWindow->font();
1839     QCOMPARE(swFont.family(), newFont.family());
1840     QCOMPARE(swFont.pointSize(), newFont.pointSize());
1841     QCOMPARE(swFont.weight(), newFont.weight());
1842     QImage newTitleBar = subWindow->grab(titleBarRect).toImage();
1843     QVERIFY(newTitleBar != originalTitleBar);
1844
1845     subWindow->setFont(originalFont);
1846     qApp->processEvents();
1847     QCOMPARE(subWindow->font(), originalFont);
1848     newTitleBar = subWindow->grab(titleBarRect).toImage();
1849     QCOMPARE(newTitleBar, originalTitleBar);
1850 }
1851
1852 void tst_QMdiSubWindow::task_188849()
1853 {
1854     QMainWindow mainWindow;
1855     // Sets a regular QWidget (and NOT a QMenuBar) as the menu bar.
1856     mainWindow.setMenuWidget(new QWidget);
1857
1858     QMdiArea *mdiArea = new QMdiArea;
1859     QMdiSubWindow *subWindow = mdiArea->addSubWindow(new QWidget);
1860     mainWindow.setCentralWidget(mdiArea);
1861     mainWindow.show();
1862 #if defined(Q_WS_X11)
1863     qt_x11_wait_for_window_manager(&mainWindow);
1864 #endif
1865
1866     // QMdiSubWindow will now try to show its buttons in the menu bar.
1867     // Without checking that the menu bar is actually a QMenuBar
1868     // and not a regular QWidget, this will crash.
1869     subWindow->showMaximized();
1870 }
1871
1872 void tst_QMdiSubWindow::mdiArea()
1873 {
1874     QMdiArea mdiArea;
1875     QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QWidget);
1876     QCOMPARE(subWindow->mdiArea(), &mdiArea);
1877
1878     subWindow->setParent(0);
1879     QVERIFY(!subWindow->mdiArea());
1880
1881     // Child of the area's corner widget.
1882     mdiArea.setCornerWidget(new QWidget);
1883     subWindow->setParent(mdiArea.cornerWidget());
1884     QVERIFY(!subWindow->mdiArea());
1885
1886     // Nested mdi area.
1887     QMdiArea *nestedArea = new QMdiArea;
1888     mdiArea.addSubWindow(nestedArea);
1889     nestedArea->addSubWindow(subWindow);
1890     QCOMPARE(subWindow->mdiArea(), nestedArea);
1891     nestedArea->setViewport(new QWidget);
1892     QCOMPARE(subWindow->mdiArea(), nestedArea);
1893 }
1894
1895 void tst_QMdiSubWindow::task_182852()
1896 {
1897 #if !defined(Q_OS_MAC) && !defined(Q_OS_WINCE)
1898
1899     QMdiArea *workspace = new QMdiArea;
1900     QMainWindow mainWindow;
1901     mainWindow.setCentralWidget(workspace);
1902     mainWindow.show();
1903     mainWindow.menuBar()->setVisible(true);
1904     qApp->setActiveWindow(&mainWindow);
1905
1906     QString originalWindowTitle = QString::fromLatin1("MainWindow - [foo]");
1907     mainWindow.setWindowTitle(originalWindowTitle);
1908
1909     QMdiSubWindow *window = new QMdiSubWindow;
1910
1911     QMdiArea *nestedWorkspace = new QMdiArea; // :-)
1912     window->setWidget(nestedWorkspace);
1913     window->widget()->setWindowTitle(QString::fromLatin1("Window"));
1914
1915     workspace->addSubWindow(window);
1916
1917     window->showMaximized();
1918     qApp->processEvents();
1919     QVERIFY(window->isMaximized());
1920
1921     QCOMPARE(mainWindow.windowTitle(), QString::fromLatin1("%1 - [%2]")
1922             .arg(originalWindowTitle, window->widget()->windowTitle()));
1923
1924     window->showNormal();
1925     QCOMPARE(mainWindow.windowTitle(), originalWindowTitle);
1926
1927     window->widget()->setWindowTitle(QString::fromLatin1("foo"));
1928     window->showMaximized();
1929
1930     QCOMPARE(mainWindow.windowTitle(), originalWindowTitle);
1931
1932     window->showNormal();
1933     QCOMPARE(mainWindow.windowTitle(), originalWindowTitle);
1934
1935     window->widget()->setWindowTitle(QString::fromLatin1("bar"));
1936     window->showMaximized();
1937
1938     QCOMPARE(mainWindow.windowTitle(), QString::fromLatin1("%1 - [%2]")
1939             .arg(originalWindowTitle, window->widget()->windowTitle()));
1940
1941
1942 #endif
1943 }
1944
1945 void tst_QMdiSubWindow::task_233197()
1946 {
1947     QMainWindow *mainWindow = new QMainWindow;
1948     mainWindow->setAttribute(Qt::WA_DeleteOnClose);
1949     mainWindow->resize(500, 200);
1950     mainWindow->show();
1951
1952     QMdiArea *mdiArea = new QMdiArea(mainWindow);
1953     mdiArea->setOption(QMdiArea::DontMaximizeSubWindowOnActivation, true);
1954     mainWindow->setCentralWidget(mdiArea);
1955
1956     QMdiSubWindow *subWindow1 = new QMdiSubWindow();
1957     mdiArea->addSubWindow(subWindow1);
1958     subWindow1->showMaximized();
1959
1960     QMdiSubWindow *subWindow2 = new QMdiSubWindow();
1961     mdiArea->addSubWindow(subWindow2);
1962     subWindow2->showMaximized();
1963
1964     QMdiSubWindow *subWindow3 = new QMdiSubWindow();
1965     mdiArea->addSubWindow(subWindow3);
1966     subWindow3->showMaximized();
1967
1968     QMenuBar *menuBar = mainWindow->menuBar(); // force creation of a menubar
1969     Q_UNUSED(menuBar);
1970
1971     QPushButton *focus1 = new QPushButton(QLatin1String("Focus 1"), mainWindow);
1972     QObject::connect(focus1, SIGNAL(clicked()), subWindow1, SLOT(setFocus()));
1973     focus1->move(5, 30);
1974     focus1->show();
1975
1976     QPushButton *focus2 = new QPushButton(QLatin1String("Focus 2"), mainWindow);
1977     QObject::connect(focus2, SIGNAL(clicked()), subWindow2, SLOT(setFocus()));
1978     focus2->move(5, 60);
1979     focus2->show();
1980
1981     QPushButton *close = new QPushButton(QLatin1String("Close"), mainWindow);
1982     QObject::connect(close, SIGNAL(clicked()), mainWindow, SLOT(close()));
1983     close->move(5, 90);
1984     close->show();
1985
1986     QTest::qWait(200);
1987
1988     sendMousePress(focus2, QPoint());
1989     sendMouseRelease(focus2, QPoint());
1990
1991     sendMousePress(focus1, QPoint());
1992     sendMouseRelease(focus1, QPoint());
1993
1994     sendMousePress(focus2, QPoint());
1995     sendMouseRelease(focus2, QPoint());
1996
1997     sendMousePress(close, QPoint());
1998     sendMouseRelease(close, QPoint());
1999
2000     QTest::qWait(200);
2001 }
2002
2003 void tst_QMdiSubWindow::task_226929()
2004 {
2005     QMdiArea mdiArea;
2006     mdiArea.show();
2007 #ifdef Q_WS_X11
2008     qt_x11_wait_for_window_manager(&mdiArea);
2009 #endif
2010
2011     QMdiSubWindow *sub1 = mdiArea.addSubWindow(new QTextEdit);
2012     sub1->showMinimized();
2013
2014     QMdiSubWindow *sub2 = mdiArea.addSubWindow(new QTextEdit);
2015     sub2->showMaximized();
2016
2017     QTest::qWait(100);
2018
2019     // Do not assert.
2020     // This window will now be activated and automatically maximized
2021     // (if not QMdiArea::DontMaximizeSubWindowOnActionvation is set).
2022     sub1->showNormal();
2023     QVERIFY(sub1->isMaximized());
2024 }
2025
2026 QTEST_MAIN(tst_QMdiSubWindow)
2027 #include "tst_qmdisubwindow.moc"
2028