From 9f1aa866bda7678261f2f441d4cfd5bb524c2411 Mon Sep 17 00:00:00 2001 From: Jo Asplin Date: Thu, 20 Oct 2011 13:17:26 +0200 Subject: Moved tests into integrationtests/ and widgets/ Task-number: QTBUG-19013 Change-Id: Ibb776f5967c0645ce6d22ef7afdc40657c575461 Reviewed-by: Holger Ihrig --- .../auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp | 2773 ++++++++++++++++++++ 1 file changed, 2773 insertions(+) create mode 100644 tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp (limited to 'tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp') diff --git a/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp new file mode 100644 index 0000000000..a4ce94cc3d --- /dev/null +++ b/tests/auto/widgets/widgets/qmdiarea/tst_qmdiarea.cpp @@ -0,0 +1,2773 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef QT_NO_OPENGL +#include +#endif +#include + +#include "../../../platformquirks.h" + +static const Qt::WindowFlags DefaultWindowFlags + = Qt::SubWindow | Qt::WindowSystemMenuHint + | Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint | Qt::WindowCloseButtonHint; + +Q_DECLARE_METATYPE(QMdiArea::WindowOrder) +Q_DECLARE_METATYPE(QMdiSubWindow *) +Q_DECLARE_METATYPE(QList) +Q_DECLARE_METATYPE(QTabWidget::TabPosition) + +//TESTED_CLASS= +//TESTED_FILES= + +static bool tabBetweenSubWindowsIn(QMdiArea *mdiArea, int tabCount = -1, bool reverse = false) +{ + if (!mdiArea) { + qWarning("Null pointer to mdi area"); + return false; + } + + QList subWindows = mdiArea->subWindowList(); + const bool walkThrough = tabCount == -1; + + if (walkThrough) { + QMdiSubWindow *active = reverse ? subWindows.front() : subWindows.back(); + mdiArea->setActiveSubWindow(active); + if (mdiArea->activeSubWindow() != active) { + qWarning("Failed to set active sub window"); + return false; + } + tabCount = subWindows.size(); + } + + QWidget *focusWidget = qApp->focusWidget(); + if (!focusWidget) { + qWarning("No focus widget"); + return false; + } + + Qt::KeyboardModifiers modifiers = reverse ? Qt::ShiftModifier : Qt::NoModifier; + Qt::Key key; +#ifdef Q_WS_MAC + key = Qt::Key_Meta; + modifiers |= Qt::MetaModifier; +#else + key = Qt::Key_Control; + modifiers |= Qt::ControlModifier; +#endif + + QTest::keyPress(focusWidget, key, modifiers); + for (int i = 0; i < tabCount; ++i) { + QTest::keyPress(focusWidget, reverse ? Qt::Key_Backtab : Qt::Key_Tab, modifiers); + if (tabCount > 1) + QTest::qWait(500); + if (walkThrough) { + QRubberBand *rubberBand = qFindChild(mdiArea->viewport()); + if (!rubberBand) { + qWarning("No rubber band"); + return false; + } + QMdiSubWindow *subWindow = subWindows.at(reverse ? subWindows.size() -1 - i : i); + if (rubberBand->geometry() != subWindow->geometry()) { + qWarning("Rubber band has different geometry"); + return false; + } + } + qApp->processEvents(); + } + QTest::keyRelease(focusWidget, key); + + return true; +} + +static inline QTabBar::Shape tabBarShapeFrom(QTabWidget::TabShape shape, QTabWidget::TabPosition position) +{ + const bool rounded = (shape == QTabWidget::Rounded); + if (position == QTabWidget::North) + return rounded ? QTabBar::RoundedNorth : QTabBar::TriangularNorth; + if (position == QTabWidget::South) + return rounded ? QTabBar::RoundedSouth : QTabBar::TriangularSouth; + if (position == QTabWidget::East) + return rounded ? QTabBar::RoundedEast : QTabBar::TriangularEast; + if (position == QTabWidget::West) + return rounded ? QTabBar::RoundedWest : QTabBar::TriangularWest; + return QTabBar::RoundedNorth; +} + +enum Arrangement { + Tiled, + Cascaded +}; + +static bool verifyArrangement(QMdiArea *mdiArea, Arrangement arrangement, const QList &expectedIndices) +{ + if (!mdiArea || expectedIndices.isEmpty() || mdiArea->subWindowList().isEmpty()) + return false; + + const QList subWindows = mdiArea->subWindowList(); + const QMdiSubWindow *const firstSubWindow = subWindows.at(0); + + switch (arrangement) { + case Tiled: + { + // Calculate the number of rows and columns. + const int n = subWindows.count(); + const int numColumns = qMax(qCeil(qSqrt(qreal(n))), 1); + const int numRows = qMax((n % numColumns) ? (n / numColumns + 1) : (n / numColumns), 1); + + // Ensure that the geometry of all the subwindows are as expected by using + // QWidget::childAt starting from the middle of the topleft cell and subsequently + // adding rowWidth and rowHeight (going from left to right). + const int columnWidth = mdiArea->viewport()->width() / numColumns; + const int rowHeight = mdiArea->viewport()->height() / numRows; + QPoint subWindowPos(columnWidth / 2, rowHeight / 2); + for (int i = 0; i < numRows; ++i) { + for (int j = 0; j < numColumns; ++j) { + const int index = expectedIndices.at(i * numColumns + j); + QWidget *actual = mdiArea->viewport()->childAt(subWindowPos); + QMdiSubWindow *expected = subWindows.at(index); + if (actual != expected && !expected->isAncestorOf(actual)) + return false; + subWindowPos.rx() += columnWidth; + } + subWindowPos.rx() = columnWidth / 2; + subWindowPos.ry() += rowHeight; + } + break; + } + case Cascaded: + { + // Calculate the delta (dx, dy) between two cascaded subwindows. + QStyleOptionTitleBar options; + options.initFrom(firstSubWindow); + int titleBarHeight = firstSubWindow->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options); +#ifdef Q_WS_MAC + // ### Remove this after the mac style has been fixed + if (qobject_cast(firstSubWindow->style())) + titleBarHeight -= 4; +#endif + const QFontMetrics fontMetrics = QFontMetrics(QApplication::font("QWorkspaceTitleBar")); + const int dy = qMax(titleBarHeight - (titleBarHeight - fontMetrics.height()) / 2, 1); + const int dx = 10; + + // Current activation/stacking order. + const QList activationOrderList = mdiArea->subWindowList(QMdiArea::ActivationHistoryOrder); + + // Ensure that the geometry of all the subwindows are as expected by using + // QWidget::childAt with the position of the first one and subsequently adding + // dx and dy. + QPoint subWindowPos(20, 5); + foreach (int expectedIndex, expectedIndices) { + QMdiSubWindow *expected = subWindows.at(expectedIndex); + expected->raise(); + if (mdiArea->viewport()->childAt(subWindowPos) != expected) + return false; + expected->lower(); + subWindowPos.rx() += dx; + subWindowPos.ry() += dy; + } + + // Restore stacking order. + foreach (QMdiSubWindow *subWindow, activationOrderList) { + mdiArea->setActiveSubWindow(subWindow); + qApp->processEvents(); + } + break; + } + default: + return false; + } + return true; +} + +class tst_QMdiArea : public QObject +{ + Q_OBJECT +public: + tst_QMdiArea(); +public slots: + void initTestCase(); +protected slots: + void activeChanged(QMdiSubWindow *child); + +private slots: + // Tests from QWorkspace + void subWindowActivated_data(); + void subWindowActivated(); + void subWindowActivated2(); + void subWindowActivatedWithMinimize(); + void showWindows(); + void changeWindowTitle(); + void changeModified(); + void childSize(); + void fixedSize(); + // New tests + void minimumSizeHint(); + void sizeHint(); + void setActiveSubWindow(); + void activeSubWindow(); + void currentSubWindow(); + void addAndRemoveWindows(); + void addAndRemoveWindowsWithReparenting(); + void removeSubWindow_2(); + void closeWindows(); + void activateNextAndPreviousWindow(); + void subWindowList_data(); + void subWindowList(); + void setBackground(); + void setViewport(); + void tileSubWindows(); + void cascadeAndTileSubWindows(); + void resizeMaximizedChildWindows_data(); + void resizeMaximizedChildWindows(); + void focusWidgetAfterAddSubWindow(); + void dontMaximizeSubWindowOnActivation(); + void delayedPlacement(); + void iconGeometryInMenuBar(); + void resizeTimer(); + void updateScrollBars(); + void setActivationOrder_data(); + void setActivationOrder(); + void tabBetweenSubWindows(); + void setViewMode(); + void setTabsClosable(); + void setTabsMovable(); + void setTabShape(); + void setTabPosition_data(); + void setTabPosition(); +#if defined(Q_WS_WIN) || defined(Q_WS_X11) + void nativeSubWindows(); +#endif + void task_209615(); + void task_236750(); + +private: + QMdiSubWindow *activeWindow; + bool accelPressed; +}; + +tst_QMdiArea::tst_QMdiArea() + : activeWindow(0) +{ + qRegisterMetaType(); +} + +void tst_QMdiArea::initTestCase() +{ +#ifdef Q_OS_WINCE //disable magic for WindowsCE + qApp->setAutoMaximizeThreshold(-1); +#endif +} + +// Old QWorkspace tests +void tst_QMdiArea::activeChanged(QMdiSubWindow *child) +{ + activeWindow = child; +} + +void tst_QMdiArea::subWindowActivated_data() +{ + // define the test elements we're going to use + QTest::addColumn("count"); + + // create a first testdata instance and fill it with data + QTest::newRow( "data0" ) << 0; + QTest::newRow( "data1" ) << 1; + QTest::newRow( "data2" ) << 2; +} + +void tst_QMdiArea::subWindowActivated() +{ + QMainWindow mw(0) ; + mw.menuBar(); + QMdiArea *workspace = new QMdiArea(&mw); + workspace->setObjectName(QLatin1String("testWidget")); + mw.setCentralWidget(workspace); + QSignalSpy spy(workspace, SIGNAL(subWindowActivated(QMdiSubWindow *))); + connect( workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(activeChanged(QMdiSubWindow *))); + mw.show(); + qApp->setActiveWindow(&mw); + + QFETCH( int, count ); + int i; + + for ( i = 0; i < count; ++i ) { + QWidget *widget = new QWidget(workspace, 0); + widget->setAttribute(Qt::WA_DeleteOnClose); + workspace->addSubWindow(widget)->show(); + widget->show(); + qApp->processEvents(); + QVERIFY( activeWindow == workspace->activeSubWindow() ); + QCOMPARE(spy.count(), 1); + spy.clear(); + } + + QList windows = workspace->subWindowList(); + QCOMPARE( (int)windows.count(), count ); + + for ( i = 0; i < count; ++i ) { + QMdiSubWindow *window = windows.at(i); + window->showMinimized(); + qApp->processEvents(); + QVERIFY( activeWindow == workspace->activeSubWindow() ); + if ( i == 1 ) + QVERIFY( activeWindow == window ); + } + + for ( i = 0; i < count; ++i ) { + QMdiSubWindow *window = windows.at(i); + window->showNormal(); + qApp->processEvents(); + QVERIFY( window == activeWindow ); + QVERIFY( activeWindow == workspace->activeSubWindow() ); + } + spy.clear(); + + while (workspace->activeSubWindow() ) { + workspace->activeSubWindow()->close(); + qApp->processEvents(); + QVERIFY(activeWindow == workspace->activeSubWindow()); + QCOMPARE(spy.count(), 1); + spy.clear(); + } + + QVERIFY(activeWindow == 0); + QVERIFY(workspace->activeSubWindow() == 0); + QCOMPARE(workspace->subWindowList().count(), 0); + + { + workspace->hide(); + QWidget *widget = new QWidget(workspace); + widget->setAttribute(Qt::WA_DeleteOnClose); + QMdiSubWindow *window = workspace->addSubWindow(widget); + widget->show(); + QCOMPARE(spy.count(), 0); + workspace->show(); + QCOMPARE(spy.count(), 1); + spy.clear(); + QVERIFY( activeWindow == window ); + window->close(); + qApp->processEvents(); + QCOMPARE(spy.count(), 1); + spy.clear(); + QVERIFY( activeWindow == 0 ); + } + + { + workspace->hide(); + QWidget *widget = new QWidget(workspace); + widget->setAttribute(Qt::WA_DeleteOnClose); + QMdiSubWindow *window = workspace->addSubWindow(widget); + widget->showMaximized(); + qApp->sendPostedEvents(); + QCOMPARE(spy.count(), 0); + spy.clear(); + workspace->show(); + QCOMPARE(spy.count(), 1); + spy.clear(); + QVERIFY( activeWindow == window ); + window->close(); + qApp->processEvents(); + QCOMPARE(spy.count(), 1); + spy.clear(); + QVERIFY( activeWindow == 0 ); + } + + { + QWidget *widget = new QWidget(workspace); + widget->setAttribute(Qt::WA_DeleteOnClose); + QMdiSubWindow *window = workspace->addSubWindow(widget); + widget->showMinimized(); + QCOMPARE(spy.count(), 1); + spy.clear(); + QVERIFY( activeWindow == window ); + QVERIFY(workspace->activeSubWindow() == window); + window->close(); + qApp->processEvents(); + QCOMPARE(spy.count(), 1); + spy.clear(); + QVERIFY(workspace->activeSubWindow() == 0); + QVERIFY( activeWindow == 0 ); + } +} + +#ifdef Q_WS_MAC +#include +bool macHasAccessToWindowsServer() +{ + SecuritySessionId mySession; + SessionAttributeBits sessionInfo; + SessionGetInfo(callerSecuritySession, &mySession, &sessionInfo); + return (sessionInfo & sessionHasGraphicAccess); +} +#endif + + +void tst_QMdiArea::subWindowActivated2() +{ + QMdiArea mdiArea; + QSignalSpy spy(&mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow *))); + for (int i = 0; i < 5; ++i) + mdiArea.addSubWindow(new QWidget); + QCOMPARE(spy.count(), 0); + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + QTest::qWaitForWindowShown(&mdiArea); + mdiArea.activateWindow(); + QTest::qWait(100); + + QTRY_COMPARE(spy.count(), 5); + QCOMPARE(mdiArea.activeSubWindow(), mdiArea.subWindowList().back()); + spy.clear(); + + // Just to make sure another widget is on top wrt. stacking order. + // This will typically become the active window if things are broken. + QMdiSubWindow *staysOnTopWindow = mdiArea.subWindowList().at(3); + staysOnTopWindow->setWindowFlags(Qt::WindowStaysOnTopHint); + mdiArea.setActiveSubWindow(staysOnTopWindow); + QCOMPARE(spy.count(), 1); + QCOMPARE(mdiArea.activeSubWindow(), staysOnTopWindow); + spy.clear(); + + QMdiSubWindow *activeSubWindow = mdiArea.subWindowList().at(2); + mdiArea.setActiveSubWindow(activeSubWindow); + QCOMPARE(spy.count(), 1); + QCOMPARE(mdiArea.activeSubWindow(), activeSubWindow); + spy.clear(); + + // Check that we only emit _one_ signal and the active window + // is unchanged after hide/show. + mdiArea.hide(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + QTest::qWait(100); + QTRY_COMPARE(spy.count(), 1); + QVERIFY(!mdiArea.activeSubWindow()); + QCOMPARE(mdiArea.currentSubWindow(), activeSubWindow); + spy.clear(); + + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + QTest::qWait(100); + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(mdiArea.activeSubWindow(), activeSubWindow); + spy.clear(); + + if (PlatformQuirks::isAutoMaximizing()) + QSKIP("Platform is auto maximizing, so no showMinimized()", SkipAll); + + // Check that we only emit _one_ signal and the active window + // is unchanged after showMinimized/showNormal. + mdiArea.showMinimized(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#elif defined (Q_WS_MAC) + if (!macHasAccessToWindowsServer()) + QEXPECT_FAIL("", "showMinimized doesn't really minimize if you don't have access to the server", Abort); +#endif + QTest::qWait(10); +#if defined(Q_WS_QWS) + QEXPECT_FAIL("", "task 168682", Abort); +#endif +#ifdef Q_OS_WINCE + QSKIP("Not fixed yet. See Task 197453", SkipAll); +#endif + QTRY_COMPARE(spy.count(), 1); + QVERIFY(!mdiArea.activeSubWindow()); + QCOMPARE(mdiArea.currentSubWindow(), activeSubWindow); + spy.clear(); + + mdiArea.showNormal(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + QTest::qWait(100); + QTRY_COMPARE(spy.count(), 1); + QCOMPARE(mdiArea.activeSubWindow(), activeSubWindow); + spy.clear(); +} + +void tst_QMdiArea::subWindowActivatedWithMinimize() +{ + QMainWindow mw(0) ; + mw.menuBar(); + QMdiArea *workspace = new QMdiArea(&mw); + workspace->setObjectName(QLatin1String("testWidget")); + mw.setCentralWidget(workspace); + QSignalSpy spy(workspace, SIGNAL(subWindowActivated(QMdiSubWindow *))); + connect( workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(activeChanged(QMdiSubWindow *)) ); + mw.show(); + qApp->setActiveWindow(&mw); + QWidget *widget = new QWidget(workspace); + widget->setAttribute(Qt::WA_DeleteOnClose); + QMdiSubWindow *window1 = workspace->addSubWindow(widget); + QWidget *widget2 = new QWidget(workspace); + widget2->setAttribute(Qt::WA_DeleteOnClose); + QMdiSubWindow *window2 = workspace->addSubWindow(widget2); + + widget->showMinimized(); + QVERIFY( activeWindow == window1 ); + widget2->showMinimized(); + QVERIFY( activeWindow == window2 ); + + window2->close(); + qApp->processEvents(); + QVERIFY( activeWindow == window1 ); + + window1->close(); + qApp->processEvents(); + QVERIFY(workspace->activeSubWindow() == 0); + QVERIFY( activeWindow == 0 ); + + QVERIFY( workspace->subWindowList().count() == 0 ); +} + +void tst_QMdiArea::showWindows() +{ + QMdiArea *ws = new QMdiArea( 0 ); + + QWidget *widget = 0; + ws->show(); + + widget = new QWidget(ws); + widget->show(); + QVERIFY( widget->isVisible() ); + + widget = new QWidget(ws); + widget->showMaximized(); + QVERIFY( widget->isMaximized() ); + widget->showNormal(); + QVERIFY( !widget->isMaximized() ); + + widget = new QWidget(ws); + widget->showMinimized(); + QVERIFY( widget->isMinimized() ); + widget->showNormal(); + QVERIFY( !widget->isMinimized() ); + + ws->hide(); + + widget = new QWidget(ws); + ws->show(); + QVERIFY( widget->isVisible() ); + + ws->hide(); + + widget = new QWidget(ws); + widget->showMaximized(); + QVERIFY( widget->isMaximized() ); + ws->show(); + QVERIFY( widget->isVisible() ); + QVERIFY( widget->isMaximized() ); + ws->hide(); + + widget = new QWidget(ws); + widget->showMinimized(); + ws->show(); + QVERIFY( widget->isMinimized() ); + ws->hide(); + + delete ws; +} + + +//#define USE_SHOW + +void tst_QMdiArea::changeWindowTitle() +{ + const QString mwc = QString::fromLatin1("MainWindow's Caption"); + const QString mwc2 = QString::fromLatin1("MainWindow's New Caption"); + const QString wc = QString::fromLatin1("Widget's Caption"); + const QString wc2 = QString::fromLatin1("Widget's New Caption"); + + QMainWindow *mw = new QMainWindow; + mw->setWindowTitle( mwc ); + QMdiArea *ws = new QMdiArea( mw ); + mw->setCentralWidget( ws ); + mw->menuBar(); + mw->show(); + QTest::qWaitForWindowShown(mw); + + QWidget *widget = new QWidget( ws ); + widget->setWindowTitle( wc ); + ws->addSubWindow(widget); + + QCOMPARE( mw->windowTitle(), mwc ); + +#ifdef USE_SHOW + widget->showMaximized(); +#else + widget->setWindowState(Qt::WindowMaximized); +#endif +#if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) + QTRY_COMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc).arg(wc) ); +#endif + + mw->hide(); + qApp->processEvents(); + mw->show(); + qApp->processEvents(); + QTest::qWaitForWindowShown(mw); + +#if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) + QTRY_COMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc).arg(wc) ); +#endif + +#ifdef USE_SHOW + widget->showNormal(); +#else + widget->setWindowState(Qt::WindowNoState); +#endif + qApp->processEvents(); + QCOMPARE( mw->windowTitle(), mwc ); + +#ifdef USE_SHOW + widget->showMaximized(); +#else + widget->setWindowState(Qt::WindowMaximized); +#endif + qApp->processEvents(); +#if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) + QTRY_COMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc).arg(wc) ); + widget->setWindowTitle( wc2 ); + QCOMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc).arg(wc2) ); + mw->setWindowTitle( mwc2 ); + QCOMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc2).arg(wc2) ); +#endif + + mw->show(); + qApp->setActiveWindow(mw); + +#ifdef USE_SHOW + mw->showFullScreen(); +#else + mw->setWindowState(Qt::WindowFullScreen); +#endif + + qApp->processEvents(); +#if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) + QCOMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc2).arg(wc2) ); +#endif +#ifdef USE_SHOW + widget->showNormal(); +#else + widget->setWindowState(Qt::WindowNoState); +#endif + qApp->processEvents(); +#if defined(Q_WS_MAC) || defined(Q_OS_WINCE) + QCOMPARE(mw->windowTitle(), mwc); +#else + QCOMPARE( mw->windowTitle(), mwc2 ); +#endif + +#ifdef USE_SHOW + widget->showMaximized(); +#else + widget->setWindowState(Qt::WindowMaximized); +#endif + qApp->processEvents(); +#if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) + QCOMPARE( mw->windowTitle(), QString::fromLatin1("%1 - [%2]").arg(mwc2).arg(wc2) ); +#endif + +#ifdef USE_SHOW + mw->showNormal(); +#else + mw->setWindowState(Qt::WindowNoState); +#endif + qApp->processEvents(); +#ifdef USE_SHOW + widget->showNormal(); +#else + widget->setWindowState(Qt::WindowNoState); +#endif + + delete mw; +} + +void tst_QMdiArea::changeModified() +{ + const QString mwc = QString::fromLatin1("MainWindow's Caption"); + const QString wc = QString::fromLatin1("Widget's Caption[*]"); + + QMainWindow *mw = new QMainWindow(0); + mw->setWindowTitle( mwc ); + QMdiArea *ws = new QMdiArea( mw ); + mw->setCentralWidget( ws ); + mw->menuBar(); + mw->show(); + + QWidget *widget = new QWidget( ws ); + widget->setWindowTitle( wc ); + ws->addSubWindow(widget); + + QCOMPARE( mw->isWindowModified(), false); + QCOMPARE( widget->isWindowModified(), false); + widget->setWindowState(Qt::WindowMaximized); + QCOMPARE( mw->isWindowModified(), false); + QCOMPARE( widget->isWindowModified(), false); + + widget->setWindowState(Qt::WindowNoState); + QCOMPARE( mw->isWindowModified(), false); + QCOMPARE( widget->isWindowModified(), false); + + widget->setWindowModified(true); + QCOMPARE( mw->isWindowModified(), false); + QCOMPARE( widget->isWindowModified(), true); + widget->setWindowState(Qt::WindowMaximized); +#if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) + QCOMPARE( mw->isWindowModified(), true); +#endif + QCOMPARE( widget->isWindowModified(), true); + + widget->setWindowState(Qt::WindowNoState); + QCOMPARE( mw->isWindowModified(), false); + QCOMPARE( widget->isWindowModified(), true); + + widget->setWindowState(Qt::WindowMaximized); +#if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) + QCOMPARE( mw->isWindowModified(), true); +#endif + QCOMPARE( widget->isWindowModified(), true); + + widget->setWindowModified(false); + QCOMPARE( mw->isWindowModified(), false); + QCOMPARE( widget->isWindowModified(), false); + + widget->setWindowModified(true); +#if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) + QCOMPARE( mw->isWindowModified(), true); +#endif + QCOMPARE( widget->isWindowModified(), true); + + widget->setWindowState(Qt::WindowNoState); + QCOMPARE( mw->isWindowModified(), false); + QCOMPARE( widget->isWindowModified(), true); + + delete mw; +} + +class MyChild : public QWidget +{ +public: + MyChild(QWidget *parent = 0) : QWidget(parent) {} + QSize sizeHint() const { return QSize(234, 123); } +}; + +void tst_QMdiArea::childSize() +{ + QMdiArea ws; + + MyChild *child = new MyChild(&ws); + child->show(); + QCOMPARE(child->size(), child->sizeHint()); + delete child; + + child = new MyChild(&ws); + child->setFixedSize(200, 200); + child->show(); + QCOMPARE(child->size(), child->minimumSize()); + delete child; + + child = new MyChild(&ws); + child->resize(150, 150); + child->show(); + QCOMPARE(child->size(), QSize(150,150)); + delete child; +} + +void tst_QMdiArea::fixedSize() +{ + QMdiArea *ws = new QMdiArea; + int i; + + ws->resize(500, 500); +// ws->show(); + + QSize fixed(300, 300); + for (i = 0; i < 4; ++i) { + QWidget *child = new QWidget(ws); + child->setFixedSize(fixed); + child->show(); + } + + QList windows = ws->subWindowList(); + for (i = 0; i < (int)windows.count(); ++i) { + QMdiSubWindow *child = windows.at(i); + QCOMPARE(child->size(), fixed); + } + + ws->cascadeSubWindows(); + ws->resize(800, 800); + for (i = 0; i < (int)windows.count(); ++i) { + QMdiSubWindow *child = windows.at(i); + QCOMPARE(child->size(), fixed); + } + ws->resize(500, 500); + + ws->tileSubWindows(); + ws->resize(800, 800); + for (i = 0; i < (int)windows.count(); ++i) { + QMdiSubWindow *child = windows.at(i); + QCOMPARE(child->size(), fixed); + } + ws->resize(500, 500); + + for (i = 0; i < (int)windows.count(); ++i) { + QMdiSubWindow *child = windows.at(i); + delete child; + } + + delete ws; +} + +class LargeWidget : public QWidget +{ +public: + LargeWidget(QWidget *parent = 0) : QWidget(parent) {} + QSize sizeHint() const { return QSize(1280, 1024); } + QSize minimumSizeHint() const { return QSize(300, 300); } +}; + +// New tests +void tst_QMdiArea::minimumSizeHint() +{ + QMdiArea workspace; + workspace.show(); + QSize expectedSize(workspace.style()->pixelMetric(QStyle::PM_MDIMinimizedWidth), + workspace.style()->pixelMetric(QStyle::PM_TitleBarHeight)); + qApp->processEvents(); + QAbstractScrollArea dummyScrollArea; + dummyScrollArea.setFrameStyle(QFrame::NoFrame); + expectedSize = expectedSize.expandedTo(dummyScrollArea.minimumSizeHint()); + QCOMPARE(workspace.minimumSizeHint(), expectedSize.expandedTo(qApp->globalStrut())); + + QWidget *window = workspace.addSubWindow(new QWidget); + qApp->processEvents(); + window->show(); + QCOMPARE(workspace.minimumSizeHint(), expectedSize.expandedTo(window->minimumSizeHint())); + + QMdiSubWindow *subWindow = workspace.addSubWindow(new LargeWidget); + subWindow->show(); + QCOMPARE(workspace.minimumSizeHint(), expectedSize.expandedTo(subWindow->minimumSizeHint())); + + workspace.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + workspace.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + QCOMPARE(workspace.minimumSizeHint(), expectedSize); +} + +void tst_QMdiArea::sizeHint() +{ + QMdiArea workspace; + workspace.show(); + QSize desktopSize = QApplication::desktop()->size(); + QSize expectedSize(desktopSize.width() * 2/3, desktopSize.height() * 2/3); + QCOMPARE(workspace.sizeHint(), expectedSize.expandedTo(qApp->globalStrut())); + + QWidget *window = workspace.addSubWindow(new QWidget); + qApp->processEvents(); + window->show(); + QCOMPARE(workspace.sizeHint(), expectedSize.expandedTo(window->sizeHint())); + + QMdiSubWindow *nested = workspace.addSubWindow(new QMdiArea); + expectedSize = QSize(desktopSize.width() * 2/6, desktopSize.height() * 2/6); + QCOMPARE(nested->widget()->sizeHint(), expectedSize); +} + +void tst_QMdiArea::setActiveSubWindow() +{ + QMdiArea workspace; + workspace.show(); + + QSignalSpy spy(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *))); + connect(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(activeChanged(QMdiSubWindow *))); + qApp->setActiveWindow(&workspace); + + // Activate hidden windows + const int windowCount = 10; + QMdiSubWindow *windows[windowCount]; + for (int i = 0; i < windowCount; ++i) { + windows[i] = qobject_cast(workspace.addSubWindow(new QWidget)); + qApp->processEvents(); + QVERIFY(windows[i]->isHidden()); + workspace.setActiveSubWindow(windows[i]); + } + QCOMPARE(spy.count(), 0); + QVERIFY(!activeWindow); + spy.clear(); + + // Activate visible windows + for (int i = 0; i < windowCount; ++i) { + windows[i]->show(); + QVERIFY(!windows[i]->isHidden()); + workspace.setActiveSubWindow(windows[i]); + qApp->processEvents(); + QCOMPARE(spy.count(), 1); + QCOMPARE(activeWindow, windows[i]); + spy.clear(); + } + + // Deactivate active window + QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]); + workspace.setActiveSubWindow(0); + QCOMPARE(spy.count(), 1); + QVERIFY(!activeWindow); + QVERIFY(!workspace.activeSubWindow()); + + // Activate widget which is not child of any window inside workspace + QMdiSubWindow fakeWindow; + QTest::ignoreMessage(QtWarningMsg, "QMdiArea::setActiveSubWindow: window is not inside workspace"); + workspace.setActiveSubWindow(&fakeWindow); + +} + +void tst_QMdiArea::activeSubWindow() +{ + QMainWindow mainWindow; + + QMdiArea *mdiArea = new QMdiArea; + QLineEdit *subWindowLineEdit = new QLineEdit; + QMdiSubWindow *subWindow = mdiArea->addSubWindow(subWindowLineEdit); + mainWindow.setCentralWidget(mdiArea); + + QDockWidget *dockWidget = new QDockWidget(QLatin1String("Dock Widget"), &mainWindow); + dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea); + QLineEdit *dockWidgetLineEdit = new QLineEdit; + dockWidget->setWidget(dockWidgetLineEdit); + mainWindow.addDockWidget(Qt::LeftDockWidgetArea, dockWidget); + + mainWindow.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mainWindow); +#endif + + qApp->setActiveWindow(&mainWindow); + QCOMPARE(mdiArea->activeSubWindow(), subWindow); + QCOMPARE(qApp->focusWidget(), (QWidget *)subWindowLineEdit); + + dockWidgetLineEdit->setFocus(); + QCOMPARE(qApp->focusWidget(), (QWidget *)dockWidgetLineEdit); + QCOMPARE(mdiArea->activeSubWindow(), subWindow); + + QEvent deactivateEvent(QEvent::WindowDeactivate); + qApp->sendEvent(subWindow, &deactivateEvent); + QVERIFY(!mdiArea->activeSubWindow()); + QCOMPARE(qApp->focusWidget(), (QWidget *)dockWidgetLineEdit); + + QEvent activateEvent(QEvent::WindowActivate); + qApp->sendEvent(subWindow, &activateEvent); + QCOMPARE(mdiArea->activeSubWindow(), subWindow); + QCOMPARE(qApp->focusWidget(), (QWidget *)subWindowLineEdit); + + QLineEdit dummyTopLevel; + dummyTopLevel.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&dummyTopLevel); +#endif + + qApp->setActiveWindow(&dummyTopLevel); + QCOMPARE(mdiArea->activeSubWindow(), subWindow); + + qApp->setActiveWindow(&mainWindow); + QCOMPARE(mdiArea->activeSubWindow(), subWindow); + +#if !defined(Q_WS_MAC) && !defined(Q_WS_WIN) + qApp->setActiveWindow(0); + QVERIFY(!mdiArea->activeSubWindow()); +#endif + + //task 202657 + dockWidgetLineEdit->setFocus(); + qApp->setActiveWindow(&mainWindow); + QVERIFY(dockWidgetLineEdit->hasFocus()); +} + +void tst_QMdiArea::currentSubWindow() +{ + QMdiArea mdiArea; + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + + for (int i = 0; i < 5; ++i) + mdiArea.addSubWindow(new QLineEdit)->show(); + + qApp->setActiveWindow(&mdiArea); + QCOMPARE(qApp->activeWindow(), (QWidget *)&mdiArea); + + // Check that the last added window is the active and the current. + QMdiSubWindow *active = mdiArea.activeSubWindow(); + QVERIFY(active); + QCOMPARE(mdiArea.subWindowList().back(), active); + QCOMPARE(mdiArea.currentSubWindow(), active); + + QLineEdit dummyTopLevel; + dummyTopLevel.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&dummyTopLevel); +#endif + + // Move focus to another top-level and check that we still + // have an active window. + qApp->setActiveWindow(&dummyTopLevel); + QCOMPARE(qApp->activeWindow(), (QWidget *)&dummyTopLevel); + QVERIFY(mdiArea.activeSubWindow()); + + delete active; + active = 0; + + // We just deleted the current sub-window -> current should then + // be the next in list (which in this case is the first sub-window). + QVERIFY(mdiArea.currentSubWindow()); + QCOMPARE(mdiArea.currentSubWindow(), mdiArea.subWindowList().front()); + + // Activate mdi area and check that active == current. + qApp->setActiveWindow(&mdiArea); + active = mdiArea.activeSubWindow(); + QVERIFY(active); + QCOMPARE(mdiArea.activeSubWindow(), mdiArea.subWindowList().front()); + + active->hide(); + QCOMPARE(mdiArea.activeSubWindow(), active); + QCOMPARE(mdiArea.currentSubWindow(), active); + + qApp->setActiveWindow(&dummyTopLevel); + QVERIFY(mdiArea.activeSubWindow()); + QCOMPARE(mdiArea.currentSubWindow(), active); + + qApp->setActiveWindow(&mdiArea); + active->show(); + QCOMPARE(mdiArea.activeSubWindow(), active); + + mdiArea.setActiveSubWindow(0); + QVERIFY(!mdiArea.activeSubWindow()); + QVERIFY(!mdiArea.currentSubWindow()); + + mdiArea.setActiveSubWindow(active); + QCOMPARE(mdiArea.activeSubWindow(), active); + QEvent windowDeactivate(QEvent::WindowDeactivate); + qApp->sendEvent(active, &windowDeactivate); + QVERIFY(!mdiArea.activeSubWindow()); + QVERIFY(!mdiArea.currentSubWindow()); + + QEvent windowActivate(QEvent::WindowActivate); + qApp->sendEvent(active, &windowActivate); + QVERIFY(mdiArea.activeSubWindow()); + QVERIFY(mdiArea.currentSubWindow()); + +#if !defined(Q_WS_MAC) && !defined(Q_WS_WIN) + qApp->setActiveWindow(0); + QVERIFY(!mdiArea.activeSubWindow()); + QVERIFY(mdiArea.currentSubWindow()); +#endif +} + +void tst_QMdiArea::addAndRemoveWindows() +{ + QWidget topLevel; + QMdiArea workspace(&topLevel); + workspace.resize(800, 600); + topLevel.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&workspace); +#endif + + { // addSubWindow with large widget + QCOMPARE(workspace.subWindowList().count(), 0); + QWidget *window = workspace.addSubWindow(new LargeWidget); + QVERIFY(window); + qApp->processEvents(); + QCOMPARE(workspace.subWindowList().count(), 1); + QVERIFY(window->windowFlags() == DefaultWindowFlags); + QCOMPARE(window->size(), workspace.viewport()->size()); + } + + { // addSubWindow, minimumSize set. + QMdiSubWindow *window = new QMdiSubWindow; + window->setMinimumSize(900, 900); + workspace.addSubWindow(window); + QVERIFY(window); + qApp->processEvents(); + QCOMPARE(workspace.subWindowList().count(), 2); + QVERIFY(window->windowFlags() == DefaultWindowFlags); + QCOMPARE(window->size(), window->minimumSize()); + } + + { // addSubWindow, resized + QMdiSubWindow *window = new QMdiSubWindow; + window->setWidget(new QWidget); + window->resize(1500, 1500); + workspace.addSubWindow(window); + QVERIFY(window); + qApp->processEvents(); + QCOMPARE(workspace.subWindowList().count(), 3); + QVERIFY(window->windowFlags() == DefaultWindowFlags); + QCOMPARE(window->size(), QSize(1500, 1500)); + } + + { // addSubWindow with 0 pointer + QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: null pointer to widget"); + QWidget *window = workspace.addSubWindow(0); + QVERIFY(!window); + QCOMPARE(workspace.subWindowList().count(), 3); + } + + { // addChildWindow + QMdiSubWindow *window = new QMdiSubWindow; + workspace.addSubWindow(window); + qApp->processEvents(); + QVERIFY(window->windowFlags() == DefaultWindowFlags); + window->setWidget(new QWidget); + QCOMPARE(workspace.subWindowList().count(), 4); + QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: window is already added"); + workspace.addSubWindow(window); + } + + { // addChildWindow with 0 pointer + QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: null pointer to widget"); + workspace.addSubWindow(0); + QCOMPARE(workspace.subWindowList().count(), 4); + } + + // removeSubWindow + foreach (QWidget *window, workspace.subWindowList()) { + workspace.removeSubWindow(window); + delete window; + } + QCOMPARE(workspace.subWindowList().count(), 0); + + // removeSubWindow with 0 pointer + QTest::ignoreMessage(QtWarningMsg, "QMdiArea::removeSubWindow: null pointer to widget"); + workspace.removeSubWindow(0); + + workspace.addSubWindow(new QPushButton(QLatin1String("Dummy to make workspace non-empty"))); + qApp->processEvents(); + QCOMPARE(workspace.subWindowList().count(), 1); + + // removeSubWindow with window not inside workspace + QTest::ignoreMessage(QtWarningMsg,"QMdiArea::removeSubWindow: window is not inside workspace"); + QMdiSubWindow *fakeWindow = new QMdiSubWindow; + workspace.removeSubWindow(fakeWindow); + delete fakeWindow; + + // Check that newly added windows don't occupy maximized windows' + // restore space. + workspace.closeAllSubWindows(); + workspace.setOption(QMdiArea::DontMaximizeSubWindowOnActivation); + workspace.show(); + QMdiSubWindow *window1 = workspace.addSubWindow(new QWidget); + window1->show(); + const QRect window1RestoreGeometry = window1->geometry(); + QCOMPARE(window1RestoreGeometry.topLeft(), QPoint(0, 0)); + + window1->showMinimized(); + + // Occupy space. + QMdiSubWindow *window2 = workspace.addSubWindow(new QWidget); + window2->show(); + const QRect window2RestoreGeometry = window2->geometry(); + QCOMPARE(window2RestoreGeometry.topLeft(), QPoint(0, 0)); + + window2->showMaximized(); + + // Don't occupy space. + QMdiSubWindow *window3 = workspace.addSubWindow(new QWidget); + window3->show(); + QCOMPARE(window3->geometry().topLeft(), QPoint(window2RestoreGeometry.right() + 1, 0)); +} + +void tst_QMdiArea::addAndRemoveWindowsWithReparenting() +{ + QMdiArea workspace; + QMdiSubWindow window(&workspace); + QVERIFY(window.windowFlags() == DefaultWindowFlags); + + // 0 because the window list contains widgets and not actual + // windows. Silly, but that's the behavior. + QCOMPARE(workspace.subWindowList().count(), 0); + window.setWidget(new QWidget); + qApp->processEvents(); + + QCOMPARE(workspace.subWindowList().count(), 1); + window.setParent(0); // Will also reset window flags + QCOMPARE(workspace.subWindowList().count(), 0); + window.setParent(&workspace); + QCOMPARE(workspace.subWindowList().count(), 1); + QVERIFY(window.windowFlags() == DefaultWindowFlags); + + QTest::ignoreMessage(QtWarningMsg, "QMdiArea::addSubWindow: window is already added"); + workspace.addSubWindow(&window); + QCOMPARE(workspace.subWindowList().count(), 1); +} + +class MySubWindow : public QMdiSubWindow +{ +public: + using QObject::receivers; +}; + +static int numberOfConnectedSignals(MySubWindow *subWindow) +{ + if (!subWindow) + return 0; + + int numConnectedSignals = 0; + for (int i = 0; i < subWindow->metaObject()->methodCount(); ++i) { + QMetaMethod method = subWindow->metaObject()->method(i); + if (method.methodType() == QMetaMethod::Signal) { + QString signature(QLatin1String("2")); + signature += QLatin1String(method.signature()); + numConnectedSignals += subWindow->receivers(signature.toLatin1()); + } + } + return numConnectedSignals; +} + +void tst_QMdiArea::removeSubWindow_2() +{ + QMdiArea mdiArea; + MySubWindow *subWindow = new MySubWindow; + QCOMPARE(numberOfConnectedSignals(subWindow), 0); + + // Connected to aboutToActivate() and windowStateChanged(). + mdiArea.addSubWindow(subWindow); + QVERIFY(numberOfConnectedSignals(subWindow) >= 2); + + // Ensure we disconnect from all signals. + mdiArea.removeSubWindow(subWindow); + QCOMPARE(numberOfConnectedSignals(subWindow), 0); + + mdiArea.addSubWindow(subWindow); + QVERIFY(numberOfConnectedSignals(subWindow) >= 2); + subWindow->setParent(0); + QCOMPARE(numberOfConnectedSignals(subWindow), 0); +} + +void tst_QMdiArea::closeWindows() +{ + QMdiArea workspace; + workspace.show(); + qApp->setActiveWindow(&workspace); + + // Close widget + QWidget *widget = new QWidget; + QMdiSubWindow *subWindow = workspace.addSubWindow(widget); + qApp->processEvents(); + QCOMPARE(workspace.subWindowList().count(), 1); + subWindow->close(); + QCOMPARE(workspace.subWindowList().count(), 0); + + // Close window + QWidget *window = workspace.addSubWindow(new QWidget); + qApp->processEvents(); + QCOMPARE(workspace.subWindowList().count(), 1); + window->close(); + qApp->processEvents(); + QCOMPARE(workspace.subWindowList().count(), 0); + + const int windowCount = 10; + + // Close active window + for (int i = 0; i < windowCount; ++i) + workspace.addSubWindow(new QWidget)->show(); + qApp->processEvents(); + QCOMPARE(workspace.subWindowList().count(), windowCount); + int activeSubWindowCount = 0; + while (workspace.activeSubWindow()) { + workspace.activeSubWindow()->close(); + qApp->processEvents(); + ++activeSubWindowCount; + } + QCOMPARE(activeSubWindowCount, windowCount); + QCOMPARE(workspace.subWindowList().count(), 0); + + // Close all windows + for (int i = 0; i < windowCount; ++i) + workspace.addSubWindow(new QWidget)->show(); + qApp->processEvents(); + QCOMPARE(workspace.subWindowList().count(), windowCount); + QSignalSpy spy(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *))); + connect(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(activeChanged(QMdiSubWindow *))); + workspace.closeAllSubWindows(); + qApp->processEvents(); + QCOMPARE(workspace.subWindowList().count(), 0); + QCOMPARE(spy.count(), 1); + QVERIFY(!activeWindow); +} + +void tst_QMdiArea::activateNextAndPreviousWindow() +{ + QMdiArea workspace; + workspace.show(); + qApp->setActiveWindow(&workspace); + + const int windowCount = 10; + QMdiSubWindow *windows[windowCount]; + for (int i = 0; i < windowCount; ++i) { + windows[i] = qobject_cast(workspace.addSubWindow(new QWidget)); + windows[i]->show(); + qApp->processEvents(); + } + + QSignalSpy spy(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *))); + connect(&workspace, SIGNAL(subWindowActivated(QMdiSubWindow *)), this, SLOT(activeChanged(QMdiSubWindow *))); + + // activateNextSubWindow + for (int i = 0; i < windowCount; ++i) { + workspace.activateNextSubWindow(); + qApp->processEvents(); + QCOMPARE(workspace.activeSubWindow(), windows[i]); + QCOMPARE(spy.count(), 1); + spy.clear(); + } + QVERIFY(activeWindow); + QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]); + QCOMPARE(workspace.activeSubWindow(), activeWindow); + + // activatePreviousSubWindow + for (int i = windowCount - 2; i >= 0; --i) { + workspace.activatePreviousSubWindow(); + qApp->processEvents(); + QCOMPARE(workspace.activeSubWindow(), windows[i]); + QCOMPARE(spy.count(), 1); + spy.clear(); + if (i % 2 == 0) + windows[i]->hide(); // 10, 8, 6, 4, 2, 0 + } + QVERIFY(activeWindow); + QCOMPARE(workspace.activeSubWindow(), windows[0]); + QCOMPARE(workspace.activeSubWindow(), activeWindow); + + // activateNextSubWindow with every 2nd window hidden + for (int i = 0; i < windowCount / 2; ++i) { + workspace.activateNextSubWindow(); // 1, 3, 5, 7, 9 + QCOMPARE(spy.count(), 1); + spy.clear(); + } + QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]); + + // activatePreviousSubWindow with every 2nd window hidden + for (int i = 0; i < windowCount / 2; ++i) { + workspace.activatePreviousSubWindow(); // 7, 5, 3, 1, 9 + QCOMPARE(spy.count(), 1); + spy.clear(); + } + QCOMPARE(workspace.activeSubWindow(), windows[windowCount - 1]); + + workspace.setActiveSubWindow(0); + QVERIFY(!activeWindow); +} + +void tst_QMdiArea::subWindowList_data() +{ + QTest::addColumn("windowOrder"); + QTest::addColumn("windowCount"); + QTest::addColumn("activeSubWindow"); + QTest::addColumn("staysOnTop1"); + QTest::addColumn("staysOnTop2"); + + QTest::newRow("CreationOrder") << QMdiArea::CreationOrder << 10 << 4 << 8 << 5; + QTest::newRow("StackingOrder") << QMdiArea::StackingOrder << 10 << 6 << 3 << 9; + QTest::newRow("ActivationHistoryOrder") << QMdiArea::ActivationHistoryOrder << 10 << 7 << 2 << 1; +} +void tst_QMdiArea::subWindowList() +{ + QFETCH(QMdiArea::WindowOrder, windowOrder); + QFETCH(int, windowCount); + QFETCH(int, activeSubWindow); + QFETCH(int, staysOnTop1); + QFETCH(int, staysOnTop2); + + QMdiArea workspace; + workspace.show(); + qApp->setActiveWindow(&workspace); + + QList activationOrder; + QVector windows; + for (int i = 0; i < windowCount; ++i) { + windows.append(qobject_cast(workspace.addSubWindow(new QWidget))); + windows[i]->show(); + activationOrder.append(windows[i]); + } + + { + QList widgets = workspace.subWindowList(windowOrder); + QCOMPARE(widgets.count(), windowCount); + for (int i = 0; i < widgets.count(); ++i) + QCOMPARE(widgets.at(i), windows[i]); + } + + windows[staysOnTop1]->setWindowFlags(windows[staysOnTop1]->windowFlags() | Qt::WindowStaysOnTopHint); + workspace.setActiveSubWindow(windows[activeSubWindow]); + qApp->processEvents(); + QCOMPARE(workspace.activeSubWindow(), windows[activeSubWindow]); + activationOrder.move(activationOrder.indexOf(windows[activeSubWindow]), windowCount - 1); + + QList subWindows = workspace.subWindowList(windowOrder); + if (windowOrder == QMdiArea::CreationOrder) { + QCOMPARE(subWindows.at(activeSubWindow), windows[activeSubWindow]); + QCOMPARE(subWindows.at(staysOnTop1), windows[staysOnTop1]); + for (int i = 0; i < windowCount; ++i) + QCOMPARE(subWindows.at(i), windows[i]); + return; + } + + if (windowOrder == QMdiArea::StackingOrder) { + QCOMPARE(subWindows.at(subWindows.count() - 1), windows[staysOnTop1]); + QCOMPARE(subWindows.at(subWindows.count() - 2), windows[activeSubWindow]); + QCOMPARE(subWindows.count(), windowCount); + } else { // ActivationHistoryOrder + QCOMPARE(subWindows, activationOrder); + } + + windows[staysOnTop2]->setWindowFlags(windows[staysOnTop2]->windowFlags() | Qt::WindowStaysOnTopHint); + workspace.setActiveSubWindow(windows[staysOnTop2]); + qApp->processEvents(); + QCOMPARE(workspace.activeSubWindow(), windows[staysOnTop2]); + activationOrder.move(activationOrder.indexOf(windows[staysOnTop2]), windowCount - 1); + + workspace.setActiveSubWindow(windows[activeSubWindow]); + qApp->processEvents(); + QCOMPARE(workspace.activeSubWindow(), windows[activeSubWindow]); + activationOrder.move(activationOrder.indexOf(windows[activeSubWindow]), windowCount - 1); + + QList widgets = workspace.subWindowList(windowOrder); + QCOMPARE(widgets.count(), windowCount); + if (windowOrder == QMdiArea::StackingOrder) { + QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop2]); + QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]); + QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]); + } else { // ActivationHistory + QCOMPARE(widgets, activationOrder); + } + + windows[activeSubWindow]->raise(); + windows[staysOnTop2]->lower(); + + widgets = workspace.subWindowList(windowOrder); + if (windowOrder == QMdiArea::StackingOrder) { + QCOMPARE(widgets.at(widgets.count() - 1), windows[activeSubWindow]); + QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]); + QCOMPARE(widgets.at(0), windows[staysOnTop2]); + } else { // ActivationHistoryOrder + QCOMPARE(widgets, activationOrder); + } + + windows[activeSubWindow]->stackUnder(windows[staysOnTop1]); + windows[staysOnTop2]->raise(); + + widgets = workspace.subWindowList(windowOrder); + if (windowOrder == QMdiArea::StackingOrder) { + QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop2]); + QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop1]); + QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]); + } else { // ActivationHistoryOrder + QCOMPARE(widgets, activationOrder); + } + + workspace.setActiveSubWindow(windows[staysOnTop1]); + activationOrder.move(activationOrder.indexOf(windows[staysOnTop1]), windowCount - 1); + + widgets = workspace.subWindowList(windowOrder); + if (windowOrder == QMdiArea::StackingOrder) { + QCOMPARE(widgets.at(widgets.count() - 1), windows[staysOnTop1]); + QCOMPARE(widgets.at(widgets.count() - 2), windows[staysOnTop2]); + QCOMPARE(widgets.at(widgets.count() - 3), windows[activeSubWindow]); + } else { // ActivationHistoryOrder + QCOMPARE(widgets, activationOrder); + } +} + +void tst_QMdiArea::setBackground() +{ + QMdiArea workspace; + QCOMPARE(workspace.background(), workspace.palette().brush(QPalette::Dark)); + workspace.setBackground(QBrush(Qt::green)); + QCOMPARE(workspace.background(), QBrush(Qt::green)); +} + +void tst_QMdiArea::setViewport() +{ + QMdiArea workspace; + workspace.show(); + + QWidget *firstViewport = workspace.viewport(); + QVERIFY(firstViewport); + + const int windowCount = 10; + for (int i = 0; i < windowCount; ++i) { + QMdiSubWindow *window = workspace.addSubWindow(new QWidget); + window->show(); + if (i % 2 == 0) { + window->showMinimized(); + QVERIFY(window->isMinimized()); + } else { + window->showMaximized(); + QVERIFY(window->isMaximized()); + } + } + + qApp->processEvents(); + QList windowsBeforeViewportChange = workspace.subWindowList(); + QCOMPARE(windowsBeforeViewportChange.count(), windowCount); + + workspace.setViewport(new QWidget); + qApp->processEvents(); + QVERIFY(workspace.viewport() != firstViewport); + + QList windowsAfterViewportChange = workspace.subWindowList(); + QCOMPARE(windowsAfterViewportChange.count(), windowCount); + QCOMPARE(windowsAfterViewportChange, windowsBeforeViewportChange); + + // for (int i = 0; i < windowCount; ++i) { + // QMdiSubWindow *window = windowsAfterViewportChange.at(i); + // if (i % 2 == 0) + // QVERIFY(!window->isMinimized()); + //else + // QVERIFY(!window->isMaximized()); + // } + + QTest::ignoreMessage(QtWarningMsg, "QMdiArea: Deleting the view port is undefined, " + "use setViewport instead."); + delete workspace.viewport(); + qApp->processEvents(); + + QCOMPARE(workspace.subWindowList().count(), 0); + QVERIFY(!workspace.activeSubWindow()); +} + +void tst_QMdiArea::tileSubWindows() +{ + QMdiArea workspace; + workspace.resize(600,480); + if (PlatformQuirks::isAutoMaximizing()) + workspace.setWindowFlags(workspace.windowFlags() | Qt::X11BypassWindowManagerHint); + workspace.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&workspace); +#endif + + const int windowCount = 10; + for (int i = 0; i < windowCount; ++i) { + QMdiSubWindow *subWindow = workspace.addSubWindow(new QWidget); + subWindow->setMinimumSize(50, 30); + subWindow->show(); + } + workspace.tileSubWindows(); + workspace.setActiveSubWindow(0); + QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect()); + + QList windows = workspace.subWindowList(); + for (int i = 0; i < windowCount; ++i) { + QMdiSubWindow *window = windows.at(i); + for (int j = 0; j < windowCount; ++j) { + if (i == j) + continue; + QVERIFY(!window->geometry().intersects(windows.at(j)->geometry())); + } + } + + // Keep the views tiled through any subsequent resize events. + for (int i = 0; i < 5; ++i) { + workspace.resize(workspace.size() - QSize(10, 10)); + qApp->processEvents(); + } + workspace.setActiveSubWindow(0); +#ifndef Q_OS_WINCE //See Task 197453 ToDo + QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect()); +#endif + + QMdiSubWindow *window = windows.at(0); + + // Change the geometry of one of the children and verify + // that the views are not tiled anymore. + window->move(window->x() + 1, window->y()); + workspace.resize(workspace.size() - QSize(10, 10)); + workspace.setActiveSubWindow(0); + QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect()); + qApp->processEvents(); + + // Re-tile. + workspace.tileSubWindows(); + workspace.setActiveSubWindow(0); + QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect()); + + // Close one of the children and verify that the views + // are not tiled anymore. + window->close(); + workspace.resize(workspace.size() - QSize(10, 10)); + workspace.setActiveSubWindow(0); + QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect()); + qApp->processEvents(); + + // Re-tile. + workspace.tileSubWindows(); + workspace.setActiveSubWindow(0); + QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect()); + + window = windows.at(1); + + // Maximize one of the children and verify that the views + // are not tiled anymore. + workspace.tileSubWindows(); + window->showMaximized(); + workspace.resize(workspace.size() - QSize(10, 10)); + workspace.setActiveSubWindow(0); + QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect()); + qApp->processEvents(); + + // Re-tile. + workspace.tileSubWindows(); + workspace.setActiveSubWindow(0); + QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect()); + + // Minimize one of the children and verify that the views + // are not tiled anymore. + workspace.tileSubWindows(); + window->showMinimized(); + workspace.resize(workspace.size() - QSize(10, 10)); + workspace.setActiveSubWindow(0); + QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect()); + qApp->processEvents(); + + // Re-tile. + workspace.tileSubWindows(); + workspace.setActiveSubWindow(0); + QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect()); + + // Active/deactivate windows and verify that the views are tiled. + workspace.setActiveSubWindow(windows.at(5)); + workspace.resize(workspace.size() - QSize(10, 10)); + workspace.setActiveSubWindow(0); + QTest::qWait(250); // delayed re-arrange of minimized windows + QTRY_COMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect()); + + // Add another window and verify that the views are not tiled anymore. + workspace.addSubWindow(new QPushButton(QLatin1String("I'd like to mess up tiled views")))->show(); + workspace.resize(workspace.size() - QSize(10, 10)); + workspace.setActiveSubWindow(0); + QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect()); + + // Re-tile. + workspace.tileSubWindows(); + workspace.setActiveSubWindow(0); + QCOMPARE(workspace.viewport()->childrenRect(), workspace.viewport()->rect()); + + // Cascade and verify that the views are not tiled anymore. + workspace.cascadeSubWindows(); + workspace.resize(workspace.size() - QSize(10, 10)); + workspace.setActiveSubWindow(0); + QVERIFY(workspace.viewport()->childrenRect() != workspace.viewport()->rect()); + + // Make sure the active window is placed in top left corner regardless + // of whether we have any windows with staysOnTopHint or not. + windows.at(3)->setWindowFlags(windows.at(3)->windowFlags() | Qt::WindowStaysOnTopHint); + QMdiSubWindow *activeSubWindow = windows.at(6); + workspace.setActiveSubWindow(activeSubWindow); + QCOMPARE(workspace.activeSubWindow(), activeSubWindow); + workspace.tileSubWindows(); + QCOMPARE(activeSubWindow->geometry().topLeft(), QPoint(0, 0)); + + // Verify that we try to resize the area such that all sub-windows are visible. + // It's important that tiled windows are NOT overlapping. + workspace.resize(350, 150); + qApp->processEvents(); + QTRY_COMPARE(workspace.size(), QSize(350, 150)); + + const QSize minSize(300, 100); + foreach (QMdiSubWindow *subWindow, workspace.subWindowList()) + subWindow->setMinimumSize(minSize); + + QCOMPARE(workspace.size(), QSize(350, 150)); + workspace.tileSubWindows(); + // The sub-windows are now tiled like this: + // | win 1 || win 2 || win 3 | + // +-------++-------++-------+ + // +-------++-------++-------+ + // | win 4 || win 5 || win 6 | + // +-------++-------++-------+ + // +-------++-------++-------+ + // | win 7 || win 8 || win 9 | + workspace.setActiveSubWindow(0); + int frameWidth = 0; + if (workspace.style()->styleHint(QStyle::SH_ScrollView_FrameOnlyAroundContents, 0, &workspace)) + frameWidth = workspace.style()->pixelMetric(QStyle::PM_DefaultFrameWidth); + const int spacing = 2 * frameWidth + 2; + const QSize expectedViewportSize(3 * minSize.width() + spacing, 3 * minSize.height() + spacing); +#ifdef Q_OS_WINCE + QSKIP("Not fixed yet! See task 197453", SkipAll); +#endif + QTRY_COMPARE(workspace.viewport()->rect().size(), expectedViewportSize); + + // Not enough space for all sub-windows to be visible -> provide scroll bars. + workspace.resize(150, 150); + qApp->processEvents(); + QTRY_COMPARE(workspace.size(), QSize(150, 150)); + + // Horizontal scroll bar. + QScrollBar *hBar = workspace.horizontalScrollBar(); + QCOMPARE(workspace.horizontalScrollBarPolicy(), Qt::ScrollBarAsNeeded); + QTRY_VERIFY(hBar->isVisible()); + QCOMPARE(hBar->value(), 0); + QCOMPARE(hBar->minimum(), 0); + + // Vertical scroll bar. + QScrollBar *vBar = workspace.verticalScrollBar(); + QCOMPARE(workspace.verticalScrollBarPolicy(), Qt::ScrollBarAsNeeded); + QVERIFY(vBar->isVisible()); + QCOMPARE(vBar->value(), 0); + QCOMPARE(vBar->minimum(), 0); + + workspace.tileSubWindows(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&workspace); +#endif + qApp->processEvents(); + + QTRY_VERIFY(workspace.size() != QSize(150, 150)); + QTRY_VERIFY(!vBar->isVisible()); + QTRY_VERIFY(!hBar->isVisible()); +} + +void tst_QMdiArea::cascadeAndTileSubWindows() +{ + QMdiArea workspace; + workspace.resize(400, 400); + workspace.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&workspace); +#endif + + const int windowCount = 10; + QList windows; + for (int i = 0; i < windowCount; ++i) { + QMdiSubWindow *window = workspace.addSubWindow(new MyChild); + if (i % 3 == 0) { + window->showMinimized(); + QVERIFY(window->isMinimized()); + } else { + window->showMaximized(); + QVERIFY(window->isMaximized()); + } + windows.append(window); + } + + // cascadeSubWindows + qApp->processEvents(); + workspace.cascadeSubWindows(); + qApp->processEvents(); + + // Check dy between two cascaded windows + QStyleOptionTitleBar options; + options.initFrom(windows.at(1)); + int titleBarHeight = windows.at(1)->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options); + // ### Remove this after the mac style has been fixed + if (windows.at(1)->style()->inherits("QMacStyle")) + titleBarHeight -= 4; + const QFontMetrics fontMetrics = QFontMetrics(QApplication::font("QWorkspaceTitleBar")); + const int dy = qMax(titleBarHeight - (titleBarHeight - fontMetrics.height()) / 2, 1); + QCOMPARE(windows.at(2)->geometry().top() - windows.at(1)->geometry().top(), dy); + + for (int i = 0; i < windows.count(); ++i) { + QMdiSubWindow *window = windows.at(i); + if (i % 3 == 0) { + QVERIFY(window->isMinimized()); + } else { + QVERIFY(!window->isMaximized()); + QCOMPARE(window->size(), window->sizeHint()); + window->showMaximized(); + QVERIFY(window->isMaximized()); + } + } +} + +void tst_QMdiArea::resizeMaximizedChildWindows_data() +{ + QTest::addColumn("startSize"); + QTest::addColumn("increment"); + QTest::addColumn("windowCount"); + + QTest::newRow("multiple children") << 400 << 20 << 10; +} + +void tst_QMdiArea::resizeMaximizedChildWindows() +{ + QFETCH(int, startSize); + QFETCH(int, increment); + QFETCH(int, windowCount); + + QWidget topLevel; + QMdiArea workspace(&topLevel); + topLevel.show(); +#if defined(Q_WS_X11) + qt_x11_wait_for_window_manager(&workspace); +#endif + QTest::qWait(100); + workspace.resize(startSize, startSize); + workspace.setOption(QMdiArea::DontMaximizeSubWindowOnActivation); + QSize workspaceSize = workspace.size(); + QVERIFY(workspaceSize.isValid()); + QCOMPARE(workspaceSize, QSize(startSize, startSize)); + + QList windows; + for (int i = 0; i < windowCount; ++i) { + QMdiSubWindow *window = workspace.addSubWindow(new QWidget); + windows.append(window); + qApp->processEvents(); + window->showMaximized(); + QTest::qWait(100); + QVERIFY(window->isMaximized()); + QSize windowSize = window->size(); + QVERIFY(windowSize.isValid()); + QCOMPARE(window->rect(), workspace.contentsRect()); + + workspace.resize(workspaceSize + QSize(increment, increment)); + QTest::qWait(100); + qApp->processEvents(); + QTRY_COMPARE(workspace.size(), workspaceSize + QSize(increment, increment)); + QTRY_COMPARE(window->size(), windowSize + QSize(increment, increment)); + workspaceSize = workspace.size(); + } + + int newSize = startSize + increment * windowCount; + QCOMPARE(workspaceSize, QSize(newSize, newSize)); + foreach (QWidget *window, windows) + QCOMPARE(window->rect(), workspace.contentsRect()); +} + +// QWidget::setParent clears focusWidget so make sure +// we restore it after QMdiArea::addSubWindow. +void tst_QMdiArea::focusWidgetAfterAddSubWindow() +{ + QWidget *view = new QWidget; + view->setLayout(new QVBoxLayout); + + QLineEdit *lineEdit1 = new QLineEdit; + QLineEdit *lineEdit2 = new QLineEdit; + view->layout()->addWidget(lineEdit1); + view->layout()->addWidget(lineEdit2); + + lineEdit2->setFocus(); + QCOMPARE(view->focusWidget(), static_cast(lineEdit2)); + + QMdiArea mdiArea; + mdiArea.addSubWindow(view); + QCOMPARE(view->focusWidget(), static_cast(lineEdit2)); + + mdiArea.show(); + view->show(); + qApp->setActiveWindow(&mdiArea); + QCOMPARE(qApp->focusWidget(), static_cast(lineEdit2)); +} + +void tst_QMdiArea::dontMaximizeSubWindowOnActivation() +{ + QMdiArea mdiArea; + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + qApp->setActiveWindow(&mdiArea); + + // Add one maximized window. + mdiArea.addSubWindow(new QWidget)->showMaximized(); + QVERIFY(mdiArea.activeSubWindow()); + QVERIFY(mdiArea.activeSubWindow()->isMaximized()); + + // Add few more windows and verify that they are maximized. + for (int i = 0; i < 5; ++i) { + QMdiSubWindow *window = mdiArea.addSubWindow(new QWidget); + window->show(); + QVERIFY(window->isMaximized()); + qApp->processEvents(); + } + + // Verify that activated windows still are maximized on activation. + QList subWindows = mdiArea.subWindowList(); + for (int i = 0; i < subWindows.count(); ++i) { + mdiArea.activateNextSubWindow(); + QMdiSubWindow *window = subWindows.at(i); + QCOMPARE(mdiArea.activeSubWindow(), window); + QVERIFY(window->isMaximized()); + qApp->processEvents(); + } + + // Restore active window and verify that other windows aren't + // maximized on activation. + mdiArea.activeSubWindow()->showNormal(); + for (int i = 0; i < subWindows.count(); ++i) { + mdiArea.activateNextSubWindow(); + QMdiSubWindow *window = subWindows.at(i); + QCOMPARE(mdiArea.activeSubWindow(), window); + QVERIFY(!window->isMaximized()); + qApp->processEvents(); + } + + // Enable 'DontMaximizedSubWindowOnActivation' and maximize the active window. + mdiArea.setOption(QMdiArea::DontMaximizeSubWindowOnActivation); + mdiArea.activeSubWindow()->showMaximized(); + int indexOfMaximized = subWindows.indexOf(mdiArea.activeSubWindow()); + + // Verify that windows are not maximized on activation. + for (int i = 0; i < subWindows.count(); ++i) { + mdiArea.activateNextSubWindow(); + QMdiSubWindow *window = subWindows.at(i); + QCOMPARE(mdiArea.activeSubWindow(), window); + if (indexOfMaximized != i) + QVERIFY(!window->isMaximized()); + qApp->processEvents(); + } + QVERIFY(mdiArea.activeSubWindow()->isMaximized()); + + // Minimize all windows. + foreach (QMdiSubWindow *window, subWindows) { + window->showMinimized(); + QVERIFY(window->isMinimized()); + qApp->processEvents(); + } + + // Disable 'DontMaximizedSubWindowOnActivation' and maximize the active window. + mdiArea.setOption(QMdiArea::DontMaximizeSubWindowOnActivation, false); + mdiArea.activeSubWindow()->showMaximized(); + + // Verify that minimized windows are maximized on activation. + for (int i = 0; i < subWindows.count(); ++i) { + mdiArea.activateNextSubWindow(); + QMdiSubWindow *window = subWindows.at(i); + QCOMPARE(mdiArea.activeSubWindow(), window); + QVERIFY(window->isMaximized()); + qApp->processEvents(); + } + + // Verify that activated windows are maximized after closing + // the active window + for (int i = 0; i < subWindows.count(); ++i) { + QVERIFY(mdiArea.activeSubWindow()); + QVERIFY(mdiArea.activeSubWindow()->isMaximized()); + mdiArea.activeSubWindow()->close(); + qApp->processEvents(); + } + + QVERIFY(!mdiArea.activeSubWindow()); + QCOMPARE(mdiArea.subWindowList().size(), 0); + + // Verify that new windows are not maximized. + mdiArea.addSubWindow(new QWidget)->show(); + QVERIFY(mdiArea.activeSubWindow()); + QVERIFY(!mdiArea.activeSubWindow()->isMaximized()); +} + +void tst_QMdiArea::delayedPlacement() +{ + QMdiArea mdiArea; + + QMdiSubWindow *window1 = mdiArea.addSubWindow(new QWidget); + QCOMPARE(window1->geometry().topLeft(), QPoint(0, 0)); + + QMdiSubWindow *window2 = mdiArea.addSubWindow(new QWidget); + QCOMPARE(window2->geometry().topLeft(), QPoint(0, 0)); + + QMdiSubWindow *window3 = mdiArea.addSubWindow(new QWidget); + QCOMPARE(window3->geometry().topLeft(), QPoint(0, 0)); + + mdiArea.resize(window3->minimumSizeHint().width() * 3, 400); + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + + QCOMPARE(window1->geometry().topLeft(), QPoint(0, 0)); + QCOMPARE(window2->geometry().topLeft(), window1->geometry().topRight() + QPoint(1, 0)); + QCOMPARE(window3->geometry().topLeft(), window2->geometry().topRight() + QPoint(1, 0)); +} + +void tst_QMdiArea::iconGeometryInMenuBar() +{ +#if !defined (Q_WS_MAC) && !defined(Q_OS_WINCE) + QMainWindow mainWindow; + QMenuBar *menuBar = mainWindow.menuBar(); + QMdiArea *mdiArea = new QMdiArea; + QMdiSubWindow *subWindow = mdiArea->addSubWindow(new QWidget); + mainWindow.setCentralWidget(mdiArea); + mainWindow.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mainWindow); +#endif + + subWindow->showMaximized(); + QVERIFY(subWindow->isMaximized()); + + QWidget *leftCornerWidget = menuBar->cornerWidget(Qt::TopLeftCorner); + QVERIFY(leftCornerWidget); + int topMargin = (menuBar->height() - leftCornerWidget->height()) / 2; + int leftMargin = qApp->style()->pixelMetric(QStyle::PM_MenuBarHMargin) + + qApp->style()->pixelMetric(QStyle::PM_MenuBarPanelWidth); + QPoint pos(leftMargin, topMargin); + QRect geometry = QStyle::visualRect(qApp->layoutDirection(), menuBar->rect(), + QRect(pos, leftCornerWidget->size())); + QCOMPARE(leftCornerWidget->geometry(), geometry); +#endif +} + +class EventSpy : public QObject +{ +public: + EventSpy(QObject *object, QEvent::Type event) + : eventToSpy(event), _count(0) + { + if (object) + object->installEventFilter(this); + } + + int count() const { return _count; } + void clear() { _count = 0; } + +protected: + bool eventFilter(QObject *object, QEvent *event) + { + if (event->type() == eventToSpy) + ++_count; + return QObject::eventFilter(object, event); + } + +private: + QEvent::Type eventToSpy; + int _count; +}; + +void tst_QMdiArea::resizeTimer() +{ + QMdiArea mdiArea; + QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QWidget); + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + QTest::qWaitForWindowShown(&mdiArea); + +#ifndef Q_OS_WINCE + int time = 250; +#else + int time = 1000; +#endif + + QTest::qWait(time); + + EventSpy timerEventSpy(subWindow, QEvent::Timer); + QCOMPARE(timerEventSpy.count(), 0); + + mdiArea.tileSubWindows(); + QTest::qWait(time); // Wait for timer events to occur. + QCOMPARE(timerEventSpy.count(), 1); + timerEventSpy.clear(); + + mdiArea.resize(mdiArea.size() + QSize(2, 2)); + QTest::qWait(time); // Wait for timer events to occur. + QCOMPARE(timerEventSpy.count(), 1); + timerEventSpy.clear(); + + // Check that timers are killed. + QTest::qWait(time); // Wait for timer events to occur. + QCOMPARE(timerEventSpy.count(), 0); +} + +void tst_QMdiArea::updateScrollBars() +{ + QMdiArea mdiArea; + mdiArea.setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + mdiArea.setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + + QMdiSubWindow *subWindow1 = mdiArea.addSubWindow(new QWidget); + QMdiSubWindow *subWindow2 = mdiArea.addSubWindow(new QWidget); + + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + qApp->processEvents(); + + QScrollBar *hbar = mdiArea.horizontalScrollBar(); + QVERIFY(hbar); + QVERIFY(!hbar->isVisible()); + + QScrollBar *vbar = mdiArea.verticalScrollBar(); + QVERIFY(vbar); + QVERIFY(!vbar->isVisible()); + + // Move sub-window 2 away. + subWindow2->move(10000, 10000); + qApp->processEvents(); + QVERIFY(hbar->isVisible()); + QVERIFY(vbar->isVisible()); + + for (int i = 0; i < 2; ++i) { + // Maximize sub-window 1 and make sure we don't have any scroll bars. + subWindow1->showMaximized(); + qApp->processEvents(); + QVERIFY(subWindow1->isMaximized()); + QVERIFY(!hbar->isVisible()); + QVERIFY(!vbar->isVisible()); + + // We still shouldn't get any scroll bars. + mdiArea.resize(mdiArea.size() - QSize(20, 20)); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + qApp->processEvents(); + QVERIFY(subWindow1->isMaximized()); + QVERIFY(!hbar->isVisible()); + QVERIFY(!vbar->isVisible()); + + // Restore sub-window 1 and make sure we have scroll bars again. + subWindow1->showNormal(); + qApp->processEvents(); + QVERIFY(!subWindow1->isMaximized()); + QVERIFY(hbar->isVisible()); + QVERIFY(vbar->isVisible()); + if (i == 0) { + // Now, do the same when the viewport is scrolled. + hbar->setValue(1000); + vbar->setValue(1000); + } + } +} + +void tst_QMdiArea::setActivationOrder_data() +{ + QTest::addColumn("activationOrder"); + QTest::addColumn("subWindowCount"); + QTest::addColumn("staysOnTopIndex"); + QTest::addColumn("firstActiveIndex"); + QTest::addColumn >("expectedActivationIndices"); + // The order of expectedCascadeIndices: + // window 1 -> (index 0) + // window 2 -> (index 1) + // window 3 -> (index 2) + // .... + QTest::addColumn >("expectedCascadeIndices"); + + // The order of expectedTileIndices (the same as reading a book LTR). + // +--------------------+--------------------+--------------------+ + // | window 1 (index 0) | window 2 (index 1) | window 3 (index 2) | + // | +--------------------+--------------------+ + // | (index 3) | window 4 (index 4) | window 5 (index 5) | + // +--------------------------------------------------------------+ + QTest::addColumn >("expectedTileIndices"); + + QList list; + QList list2; + QList list3; + + list << 2 << 1 << 0 << 1 << 2 << 3 << 4; + list2 << 0 << 1 << 2 << 3 << 4; + list3 << 1 << 4 << 3 << 1 << 2 << 0; + QTest::newRow("CreationOrder") << QMdiArea::CreationOrder << 5 << 3 << 1 << list << list2 << list3; + + list = QList(); + list << 3 << 1 << 4 << 3 << 1 << 2 << 0; + list2 = QList(); + list2 << 0 << 2 << 4 << 1 << 3; + list3 = QList(); + list3 << 1 << 3 << 4 << 1 << 2 << 0; + QTest::newRow("StackingOrder") << QMdiArea::StackingOrder << 5 << 3 << 1 << list << list2 << list3; + + list = QList(); + list << 0 << 1 << 0 << 1 << 4 << 3 << 2; + list2 = QList(); + list2 << 0 << 2 << 3 << 4 << 1; + list3 = QList(); + list3 << 1 << 4 << 3 << 1 << 2 << 0; + QTest::newRow("ActivationHistoryOrder") << QMdiArea::ActivationHistoryOrder << 5 << 3 << 1 << list << list2 << list3; +} + +void tst_QMdiArea::setActivationOrder() +{ + QFETCH(QMdiArea::WindowOrder, activationOrder); + QFETCH(int, subWindowCount); + QFETCH(int, staysOnTopIndex); + QFETCH(int, firstActiveIndex); + QFETCH(QList, expectedActivationIndices); + QFETCH(QList, expectedCascadeIndices); + QFETCH(QList, expectedTileIndices); + + // Default order. + QMdiArea mdiArea; + QCOMPARE(mdiArea.activationOrder(), QMdiArea::CreationOrder); + + // New order. + mdiArea.setActivationOrder(activationOrder); + QCOMPARE(mdiArea.activationOrder(), activationOrder); + + QList subWindows; + for (int i = 0; i < subWindowCount; ++i) + subWindows << mdiArea.addSubWindow(new QPushButton(tr("%1").arg(i))); + QCOMPARE(mdiArea.subWindowList(activationOrder), subWindows); + + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + + for (int i = 0; i < subWindows.count(); ++i) { + mdiArea.activateNextSubWindow(); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(i)); + qApp->processEvents(); + } + + QMdiSubWindow *staysOnTop = subWindows.at(staysOnTopIndex); + staysOnTop->setWindowFlags(staysOnTop->windowFlags() | Qt::WindowStaysOnTopHint); + staysOnTop->raise(); + + mdiArea.setActiveSubWindow(subWindows.at(firstActiveIndex)); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(firstActiveIndex)); + + // Verify the actual arrangement/geometry. + mdiArea.tileSubWindows(); + QTest::qWait(100); + QVERIFY(verifyArrangement(&mdiArea, Tiled, expectedTileIndices)); + + mdiArea.cascadeSubWindows(); + QVERIFY(verifyArrangement(&mdiArea, Cascaded, expectedCascadeIndices)); + QTest::qWait(100); + + mdiArea.activateNextSubWindow(); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst())); + + mdiArea.activatePreviousSubWindow(); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst())); + + mdiArea.activatePreviousSubWindow(); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst())); + + for (int i = 0; i < subWindowCount; ++i) { + mdiArea.closeActiveSubWindow(); + qApp->processEvents(); + if (i == subWindowCount - 1) { // Last window closed. + QVERIFY(!mdiArea.activeSubWindow()); + break; + } + QVERIFY(mdiArea.activeSubWindow()); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(expectedActivationIndices.takeFirst())); + } + + QVERIFY(mdiArea.subWindowList(activationOrder).isEmpty()); + QVERIFY(expectedActivationIndices.isEmpty()); +} + +void tst_QMdiArea::tabBetweenSubWindows() +{ + QMdiArea mdiArea; + QList subWindows; + for (int i = 0; i < 5; ++i) + subWindows << mdiArea.addSubWindow(new QLineEdit); + + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + + qApp->setActiveWindow(&mdiArea); + QWidget *focusWidget = subWindows.back()->widget(); + QCOMPARE(qApp->focusWidget(), focusWidget); + + QSignalSpy spy(&mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow *))); + QCOMPARE(spy.count(), 0); + + // Walk through the entire list of sub windows. + QVERIFY(tabBetweenSubWindowsIn(&mdiArea)); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.back()); + QCOMPARE(spy.count(), 0); + + mdiArea.setActiveSubWindow(subWindows.front()); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.front()); + spy.clear(); + + // Walk through the entire list of sub windows in the opposite direction (Ctrl-Shift-Tab). + QVERIFY(tabBetweenSubWindowsIn(&mdiArea, -1, true)); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.front()); + QCOMPARE(spy.count(), 0); + + // Ctrl-Tab-Tab-Tab + QVERIFY(tabBetweenSubWindowsIn(&mdiArea, 3)); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(3)); + QCOMPARE(spy.count(), 1); + + mdiArea.setActiveSubWindow(subWindows.at(1)); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(1)); + spy.clear(); + + // Quick switch (Ctrl-Tab once) -> switch back to the previously active sub-window. + QVERIFY(tabBetweenSubWindowsIn(&mdiArea, 1)); + QCOMPARE(mdiArea.activeSubWindow(), subWindows.at(3)); + QCOMPARE(spy.count(), 1); +} + +void tst_QMdiArea::setViewMode() +{ + QMdiArea mdiArea; + + QPixmap iconPixmap(16, 16); + iconPixmap.fill(Qt::red); + for (int i = 0; i < 5; ++i) { + QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QWidget); + subWindow->setWindowTitle(QString(QLatin1String("Title %1")).arg(i)); + subWindow->setWindowIcon(iconPixmap); + } + + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + + QMdiSubWindow *activeSubWindow = mdiArea.activeSubWindow(); + const QList subWindows = mdiArea.subWindowList(); + + // Default. + QVERIFY(!activeSubWindow->isMaximized()); + QTabBar *tabBar = qFindChild(&mdiArea); + QVERIFY(!tabBar); + QCOMPARE(mdiArea.viewMode(), QMdiArea::SubWindowView); + + // Tabbed view. + mdiArea.setViewMode(QMdiArea::TabbedView); + QCOMPARE(mdiArea.viewMode(), QMdiArea::TabbedView); + tabBar = qFindChild(&mdiArea); + QVERIFY(tabBar); + QVERIFY(tabBar->isVisible()); + + QCOMPARE(tabBar->count(), subWindows.count()); + QVERIFY(activeSubWindow->isMaximized()); + QCOMPARE(tabBar->currentIndex(), subWindows.indexOf(activeSubWindow)); + + // Check that tabIcon and tabText are set properly. + for (int i = 0; i < subWindows.size(); ++i) { + QMdiSubWindow *subWindow = subWindows.at(i); + QCOMPARE(tabBar->tabText(i), subWindow->windowTitle()); + QCOMPARE(tabBar->tabIcon(i), subWindow->windowIcon()); + } + + // Check that tabText and tabIcon are updated. + activeSubWindow->setWindowTitle(QLatin1String("Dude, I want another window title")); + QCOMPARE(tabBar->tabText(tabBar->currentIndex()), activeSubWindow->windowTitle()); + iconPixmap.fill(Qt::green); + activeSubWindow->setWindowIcon(iconPixmap); + QCOMPARE(tabBar->tabIcon(tabBar->currentIndex()), activeSubWindow->windowIcon()); + + // If there's an empty window title, tabText should return "(Untitled)" (as in firefox). + activeSubWindow->setWindowTitle(QString()); + QCOMPARE(tabBar->tabText(tabBar->currentIndex()), QLatin1String("(Untitled)")); + + // If there's no window icon, tabIcon should return ... an empty icon :) + activeSubWindow->setWindowIcon(QIcon()); + QCOMPARE(tabBar->tabIcon(tabBar->currentIndex()), QIcon()); + + // Check that the current tab changes when activating another sub-window. + for (int i = 0; i < subWindows.size(); ++i) { + mdiArea.activateNextSubWindow(); + activeSubWindow = mdiArea.activeSubWindow(); + QCOMPARE(tabBar->currentIndex(), subWindows.indexOf(activeSubWindow)); + } + + activeSubWindow = mdiArea.activeSubWindow(); + const int tabIndex = tabBar->currentIndex(); + + // The current tab should not change when the sub-window is hidden. + activeSubWindow->hide(); + QCOMPARE(tabBar->currentIndex(), tabIndex); + activeSubWindow->show(); + QCOMPARE(tabBar->currentIndex(), tabIndex); + + // Disable the tab when the sub-window is hidden and another sub-window is activated. + activeSubWindow->hide(); + mdiArea.activateNextSubWindow(); + QVERIFY(tabBar->currentIndex() != tabIndex); + QVERIFY(!tabBar->isTabEnabled(tabIndex)); + + // Enable it again. + activeSubWindow->show(); + QCOMPARE(tabBar->currentIndex(), tabIndex); + QVERIFY(tabBar->isTabEnabled(tabIndex)); + + // Remove sub-windows and make sure the tab is removed. + foreach (QMdiSubWindow *subWindow, subWindows) { + if (subWindow != activeSubWindow) + mdiArea.removeSubWindow(subWindow); + } + QCOMPARE(tabBar->count(), 1); + + // Go back to default (QMdiArea::SubWindowView). + mdiArea.setViewMode(QMdiArea::SubWindowView); + QVERIFY(!activeSubWindow->isMaximized()); + tabBar = qFindChild(&mdiArea); + QVERIFY(!tabBar); + QCOMPARE(mdiArea.viewMode(), QMdiArea::SubWindowView); +} + +void tst_QMdiArea::setTabsClosable() +{ + QMdiArea mdiArea; + mdiArea.addSubWindow(new QWidget); + + // test default + QCOMPARE(mdiArea.tabsClosable(), false); + + // change value before tab bar exists + QTabBar *tabBar = qFindChild(&mdiArea); + QVERIFY(!tabBar); + mdiArea.setTabsClosable(true); + QCOMPARE(mdiArea.tabsClosable(), true); + + // force tab bar creation + mdiArea.setViewMode(QMdiArea::TabbedView); + tabBar = qFindChild(&mdiArea); + QVERIFY(tabBar); + + // value must've been propagated + QCOMPARE(tabBar->tabsClosable(), true); + + // change value when tab bar exists + mdiArea.setTabsClosable(false); + QCOMPARE(mdiArea.tabsClosable(), false); + QCOMPARE(tabBar->tabsClosable(), false); +} + +void tst_QMdiArea::setTabsMovable() +{ + QMdiArea mdiArea; + QMdiSubWindow *subWindow1 = mdiArea.addSubWindow(new QWidget); + QMdiSubWindow *subWindow2 = mdiArea.addSubWindow(new QWidget); + QMdiSubWindow *subWindow3 = mdiArea.addSubWindow(new QWidget); + + // test default + QCOMPARE(mdiArea.tabsMovable(), false); + + // change value before tab bar exists + QTabBar *tabBar = qFindChild(&mdiArea); + QVERIFY(!tabBar); + mdiArea.setTabsMovable(true); + QCOMPARE(mdiArea.tabsMovable(), true); + + // force tab bar creation + mdiArea.setViewMode(QMdiArea::TabbedView); + tabBar = qFindChild(&mdiArea); + QVERIFY(tabBar); + + // value must've been propagated + QCOMPARE(tabBar->isMovable(), true); + + // test tab moving + QList subWindows; + subWindows << subWindow1 << subWindow2 << subWindow3; + QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows); + tabBar->moveTab(1, 2); // 1,3,2 + subWindows.clear(); + subWindows << subWindow1 << subWindow3 << subWindow2; + QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows); + tabBar->moveTab(0, 2); // 3,2,1 + subWindows.clear(); + subWindows << subWindow3 << subWindow2 << subWindow1; + QCOMPARE(mdiArea.subWindowList(QMdiArea::CreationOrder), subWindows); + + // change value when tab bar exists + mdiArea.setTabsMovable(false); + QCOMPARE(mdiArea.tabsMovable(), false); + QCOMPARE(tabBar->isMovable(), false); +} + +void tst_QMdiArea::setTabShape() +{ + QMdiArea mdiArea; + mdiArea.addSubWindow(new QWidget); + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + + // Default. + QCOMPARE(mdiArea.tabShape(), QTabWidget::Rounded); + + // Triangular. + mdiArea.setTabShape(QTabWidget::Triangular); + QCOMPARE(mdiArea.tabShape(), QTabWidget::Triangular); + + mdiArea.setViewMode(QMdiArea::TabbedView); + + QTabBar *tabBar = qFindChild(&mdiArea); + QVERIFY(tabBar); + QCOMPARE(tabBar->shape(), QTabBar::TriangularNorth); + + // Back to default (Rounded). + mdiArea.setTabShape(QTabWidget::Rounded); + QCOMPARE(mdiArea.tabShape(), QTabWidget::Rounded); + QCOMPARE(tabBar->shape(), QTabBar::RoundedNorth); +} + +void tst_QMdiArea::setTabPosition_data() +{ + QTest::addColumn("tabPosition"); + QTest::addColumn("hasLeftMargin"); + QTest::addColumn("hasTopMargin"); + QTest::addColumn("hasRightMargin"); + QTest::addColumn("hasBottomMargin"); + + QTest::newRow("North") << QTabWidget::North << false << true << false << false; + QTest::newRow("South") << QTabWidget::South << false << false << false << true; + QTest::newRow("East") << QTabWidget::East << false << false << true << false; + QTest::newRow("West") << QTabWidget::West << true << false << false << false; +} + +void tst_QMdiArea::setTabPosition() +{ + QFETCH(QTabWidget::TabPosition, tabPosition); + QFETCH(bool, hasLeftMargin); + QFETCH(bool, hasTopMargin); + QFETCH(bool, hasRightMargin); + QFETCH(bool, hasBottomMargin); + + QMdiArea mdiArea; + mdiArea.addSubWindow(new QWidget); + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + + // Make sure there are no margins. + mdiArea.setContentsMargins(0, 0, 0, 0); + + // Default. + QCOMPARE(mdiArea.tabPosition(), QTabWidget::North); + mdiArea.setViewMode(QMdiArea::TabbedView); + QTabBar *tabBar = qFindChild(&mdiArea); + QVERIFY(tabBar); + QCOMPARE(tabBar->shape(), QTabBar::RoundedNorth); + + // New position. + mdiArea.setTabPosition(tabPosition); + QCOMPARE(mdiArea.tabPosition(), tabPosition); + QCOMPARE(tabBar->shape(), tabBarShapeFrom(QTabWidget::Rounded, tabPosition)); + + const Qt::LayoutDirection originalLayoutDirection = qApp->layoutDirection(); + + // Check that we have correct geometry in both RightToLeft and LeftToRight. + for (int i = 0; i < 2; ++i) { + // Check viewportMargins. + const QRect viewportGeometry = mdiArea.viewport()->geometry(); + const int left = viewportGeometry.left(); + const int top = viewportGeometry.y(); + const int right = mdiArea.width() - viewportGeometry.width(); + const int bottom = mdiArea.height() - viewportGeometry.height(); + + const QSize sizeHint = tabBar->sizeHint(); + + if (hasLeftMargin) + QCOMPARE(qApp->isLeftToRight() ? left : right, sizeHint.width()); + if (hasRightMargin) + QCOMPARE(qApp->isLeftToRight() ? right : left, sizeHint.width()); + if (hasTopMargin || hasBottomMargin) + QCOMPARE(hasTopMargin ? top : bottom, sizeHint.height()); + + // Check actual tab bar geometry. + const QRegion expectedTabBarGeometry = QRegion(mdiArea.rect()).subtracted(viewportGeometry); + QVERIFY(!expectedTabBarGeometry.isEmpty()); + QCOMPARE(QRegion(tabBar->geometry()), expectedTabBarGeometry); + + if (i == 0) + qApp->setLayoutDirection(originalLayoutDirection == Qt::LeftToRight ? Qt::RightToLeft : Qt::LeftToRight); + qApp->processEvents(); + } + + qApp->setLayoutDirection(originalLayoutDirection); +} + +#if defined(Q_WS_WIN) || defined(Q_WS_X11) +void tst_QMdiArea::nativeSubWindows() +{ + { // Add native widgets after show. + QMdiArea mdiArea; + mdiArea.addSubWindow(new QWidget); + mdiArea.addSubWindow(new QWidget); + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + + // No native widgets. + QVERIFY(!mdiArea.viewport()->internalWinId()); + foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList()) + QVERIFY(!subWindow->internalWinId()); + + QWidget *nativeWidget = new QWidget; + QVERIFY(nativeWidget->winId()); // enforce native window. + mdiArea.addSubWindow(nativeWidget); + + // The viewport and all the sub-windows must be native. + QVERIFY(mdiArea.viewport()->internalWinId()); + foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList()) + QVERIFY(subWindow->internalWinId()); + + // Add a non-native widget. This should become native. + QMdiSubWindow *subWindow = new QMdiSubWindow; + subWindow->setWidget(new QWidget); + QVERIFY(!subWindow->internalWinId()); + mdiArea.addSubWindow(subWindow); + QVERIFY(subWindow->internalWinId()); + } + + { // Add native widgets before show. + QMdiArea mdiArea; + mdiArea.addSubWindow(new QWidget); + QWidget *nativeWidget = new QWidget; + (void)nativeWidget->winId(); + mdiArea.addSubWindow(nativeWidget); + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + + // The viewport and all the sub-windows must be native. + QVERIFY(mdiArea.viewport()->internalWinId()); + foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList()) + QVERIFY(subWindow->internalWinId()); + } + + { // Make a sub-window native *after* it's added to the area. + QMdiArea mdiArea; + mdiArea.addSubWindow(new QWidget); + mdiArea.addSubWindow(new QWidget); + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + + QMdiSubWindow *nativeSubWindow = mdiArea.subWindowList().last(); + QVERIFY(!nativeSubWindow->internalWinId()); + (void)nativeSubWindow->winId(); + + // All the sub-windows should be native at this point + QVERIFY(mdiArea.viewport()->internalWinId()); + foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList()) + QVERIFY(subWindow->internalWinId()); + } + +#ifndef QT_NO_OPENGL + { + if (!QGLFormat::hasOpenGL()) + QSKIP("QGL not supported on this platform", SkipAll); + + QMdiArea mdiArea; + QGLWidget *glViewport = new QGLWidget; + mdiArea.setViewport(glViewport); + mdiArea.addSubWindow(new QWidget); + mdiArea.addSubWindow(new QWidget); + mdiArea.show(); +#ifdef Q_WS_X11 + qt_x11_wait_for_window_manager(&mdiArea); +#endif + + const QGLContext *context = glViewport->context(); + if (!context || !context->isValid()) + QSKIP("QGL is broken, cannot continue test", SkipAll); + + // The viewport and all the sub-windows must be native. + QVERIFY(mdiArea.viewport()->internalWinId()); + foreach (QMdiSubWindow *subWindow, mdiArea.subWindowList()) + QVERIFY(subWindow->internalWinId()); + } +#endif +} +#endif + +void tst_QMdiArea::task_209615() +{ + QTabWidget tabWidget; + QMdiArea *mdiArea1 = new QMdiArea; + QMdiArea *mdiArea2 = new QMdiArea; + QMdiSubWindow *subWindow = mdiArea1->addSubWindow(new QLineEdit); + + tabWidget.addTab(mdiArea1, QLatin1String("1")); + tabWidget.addTab(mdiArea2, QLatin1String("2")); + tabWidget.show(); + + mdiArea1->removeSubWindow(subWindow); + mdiArea2->addSubWindow(subWindow); + + // Please do not assert/crash. + tabWidget.setCurrentIndex(1); +} + +void tst_QMdiArea::task_236750() +{ + QMdiArea mdiArea; + QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QTextEdit); + mdiArea.show(); + + subWindow->setWindowFlags(subWindow->windowFlags() | Qt::FramelessWindowHint); + // Please do not crash (floating point exception). + subWindow->showMinimized(); +} + +QTEST_MAIN(tst_QMdiArea) +#include "tst_qmdiarea.moc" + -- cgit v1.2.3