qt5base-lts/tests/auto/qmdiarea/tst_qmdiarea.cpp

2775 lines
90 KiB
C++
Raw Normal View History

/****************************************************************************
**
** 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$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, 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.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QtTest/QtTest>
#include <QMdiSubWindow>
#include <QMdiArea>
#include <QApplication>
#include <QMainWindow>
#include <QMenuBar>
#include <QPushButton>
#include <QStyle>
#include <QStyleOption>
#include <QVBoxLayout>
#include <QLineEdit>
#include <QDesktopWidget>
#include <QDockWidget>
#include <QScrollBar>
#include <QTextEdit>
#ifndef QT_NO_OPENGL
#include <QtOpenGL>
#endif
#include <QMacStyle>
#include "../../shared/util.h"
#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<int>)
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<QMdiSubWindow *> 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<QRubberBand *>(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<int> &expectedIndices)
{
if (!mdiArea || expectedIndices.isEmpty() || mdiArea->subWindowList().isEmpty())
return false;
const QList<QMdiSubWindow *> 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<QMacStyle *>(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<QMdiSubWindow *> 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<QMdiSubWindow *>();
}
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<int>("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<QMdiSubWindow *> 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 <Security/AuthSession.h>
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<QMdiSubWindow *> 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<QMdiSubWindow *>(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<QMdiSubWindow *>(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<QMdiArea::WindowOrder>("windowOrder");
QTest::addColumn<int>("windowCount");
QTest::addColumn<int>("activeSubWindow");
QTest::addColumn<int>("staysOnTop1");
QTest::addColumn<int>("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<QMdiSubWindow *> activationOrder;
QVector<QMdiSubWindow *> windows;
for (int i = 0; i < windowCount; ++i) {
windows.append(qobject_cast<QMdiSubWindow *>(workspace.addSubWindow(new QWidget)));
windows[i]->show();
activationOrder.append(windows[i]);
}
{
QList<QMdiSubWindow *> 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<QMdiSubWindow *> 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<QMdiSubWindow *> 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<QMdiSubWindow *> windowsBeforeViewportChange = workspace.subWindowList();
QCOMPARE(windowsBeforeViewportChange.count(), windowCount);
workspace.setViewport(new QWidget);
qApp->processEvents();
QVERIFY(workspace.viewport() != firstViewport);
QList<QMdiSubWindow *> 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<QMdiSubWindow *> 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<QMdiSubWindow *> 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<int>("startSize");
QTest::addColumn<int>("increment");
QTest::addColumn<int>("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<QMdiSubWindow *> 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<QWidget *>(lineEdit2));
QMdiArea mdiArea;
mdiArea.addSubWindow(view);
QCOMPARE(view->focusWidget(), static_cast<QWidget *>(lineEdit2));
mdiArea.show();
view->show();
qApp->setActiveWindow(&mdiArea);
QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(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<QMdiSubWindow *> 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<QMdiArea::WindowOrder>("activationOrder");
QTest::addColumn<int>("subWindowCount");
QTest::addColumn<int>("staysOnTopIndex");
QTest::addColumn<int>("firstActiveIndex");
QTest::addColumn<QList<int> >("expectedActivationIndices");
// The order of expectedCascadeIndices:
// window 1 -> (index 0)
// window 2 -> (index 1)
// window 3 -> (index 2)
// ....
QTest::addColumn<QList<int> >("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<QList<int> >("expectedTileIndices");
QList<int> list;
QList<int> list2;
QList<int> 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<int>();
list << 3 << 1 << 4 << 3 << 1 << 2 << 0;
list2 = QList<int>();
list2 << 0 << 2 << 4 << 1 << 3;
list3 = QList<int>();
list3 << 1 << 3 << 4 << 1 << 2 << 0;
QTest::newRow("StackingOrder") << QMdiArea::StackingOrder << 5 << 3 << 1 << list << list2 << list3;
list = QList<int>();
list << 0 << 1 << 0 << 1 << 4 << 3 << 2;
list2 = QList<int>();
list2 << 0 << 2 << 3 << 4 << 1;
list3 = QList<int>();
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<int>, expectedActivationIndices);
QFETCH(QList<int>, expectedCascadeIndices);
QFETCH(QList<int>, expectedTileIndices);
// Default order.
QMdiArea mdiArea;
QCOMPARE(mdiArea.activationOrder(), QMdiArea::CreationOrder);
// New order.
mdiArea.setActivationOrder(activationOrder);
QCOMPARE(mdiArea.activationOrder(), activationOrder);
QList<QMdiSubWindow *> 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<QMdiSubWindow *> 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<QMdiSubWindow *> subWindows = mdiArea.subWindowList();
// Default.
QVERIFY(!activeSubWindow->isMaximized());
QTabBar *tabBar = qFindChild<QTabBar *>(&mdiArea);
QVERIFY(!tabBar);
QCOMPARE(mdiArea.viewMode(), QMdiArea::SubWindowView);
// Tabbed view.
mdiArea.setViewMode(QMdiArea::TabbedView);
QCOMPARE(mdiArea.viewMode(), QMdiArea::TabbedView);
tabBar = qFindChild<QTabBar *>(&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<QTabBar *>(&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<QTabBar *>(&mdiArea);
QVERIFY(!tabBar);
mdiArea.setTabsClosable(true);
QCOMPARE(mdiArea.tabsClosable(), true);
// force tab bar creation
mdiArea.setViewMode(QMdiArea::TabbedView);
tabBar = qFindChild<QTabBar *>(&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<QTabBar *>(&mdiArea);
QVERIFY(!tabBar);
mdiArea.setTabsMovable(true);
QCOMPARE(mdiArea.tabsMovable(), true);
// force tab bar creation
mdiArea.setViewMode(QMdiArea::TabbedView);
tabBar = qFindChild<QTabBar *>(&mdiArea);
QVERIFY(tabBar);
// value must've been propagated
QCOMPARE(tabBar->isMovable(), true);
// test tab moving
QList<QMdiSubWindow *> 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<QTabBar *>(&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<QTabWidget::TabPosition>("tabPosition");
QTest::addColumn<bool>("hasLeftMargin");
QTest::addColumn<bool>("hasTopMargin");
QTest::addColumn<bool>("hasRightMargin");
QTest::addColumn<bool>("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<QTabBar *>(&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"