/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** 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 #include "qmdisubwindow.h" #include "qmdiarea.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) #include #endif QT_BEGIN_NAMESPACE #if defined(Q_WS_X11) extern void qt_x11_wait_for_window_manager(QWidget *w); #endif #if !defined(Q_WS_WIN) extern bool qt_tab_all_widgets; #endif QT_END_NAMESPACE static inline bool tabAllWidgets() { #if !defined(Q_WS_WIN) if (qApp->style()->inherits("QMacStyle")) return qt_tab_all_widgets; #endif return true; } static inline void triggerSignal(QMdiSubWindow *window, QMdiArea *workspace, const QByteArray &signal) { if (signal == SIGNAL(windowMaximized())) { window->showMaximized(); qApp->processEvents(); if (window->parent()) QVERIFY(window->isMaximized()); } else if (signal == SIGNAL(windowMinimized())) { window->showMinimized(); qApp->processEvents(); if (window->parent()) QVERIFY(window->isMinimized()); } else if (signal == SIGNAL(windowRestored())) { window->showMaximized(); qApp->processEvents(); window->showNormal(); qApp->processEvents(); QVERIFY(!window->isMinimized()); QVERIFY(!window->isMaximized()); QVERIFY(!window->isShaded()); } else if (signal == SIGNAL(aboutToActivate())) { if (window->parent()) { workspace->setActiveSubWindow(window); qApp->processEvents(); } } else if (signal == SIGNAL(windowActivated())) { if (window->parent()) { workspace->setActiveSubWindow(window); qApp->processEvents(); } } else if (signal == SIGNAL(windowDeactivated())) { if (!window->parent()) return; workspace->setActiveSubWindow(window); qApp->processEvents(); workspace->setActiveSubWindow(0); qApp->processEvents(); } } // --- from tst_qgraphicsview.cpp --- static void sendMousePress(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton) { QMouseEvent event(QEvent::MouseButtonPress, point, widget->mapToGlobal(point), button, 0, 0); QApplication::sendEvent(widget, &event); } static void sendMouseMove(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton) { QMouseEvent event(QEvent::MouseMove, point, widget->mapToGlobal(point), button, button, 0); QApplication::sendEvent(widget, &event); } static void sendMouseRelease(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton) { QMouseEvent event(QEvent::MouseButtonRelease, point, widget->mapToGlobal(point), button, 0, 0); QApplication::sendEvent(widget, &event); } // --- static void sendMouseDoubleClick(QWidget *widget, const QPoint &point, Qt::MouseButton button = Qt::LeftButton) { sendMousePress(widget, point, button); sendMouseRelease(widget, point, button); QMouseEvent event(QEvent::MouseButtonDblClick, point, widget->mapToGlobal(point), button, 0, 0); QApplication::sendEvent(widget, &event); } static const Qt::WindowFlags StandardWindowFlags = Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint; static const Qt::WindowFlags DialogWindowFlags = Qt::WindowTitleHint | Qt::WindowSystemMenuHint; Q_DECLARE_METATYPE(Qt::WindowState); Q_DECLARE_METATYPE(Qt::WindowStates); Q_DECLARE_METATYPE(Qt::WindowType); Q_DECLARE_METATYPE(Qt::WindowFlags); //TESTED_CLASS= //TESTED_FILES= class tst_QMdiSubWindow : public QObject { Q_OBJECT private slots: void initTestCase(); void sizeHint(); void minimumSizeHint(); void minimumSize(); void setWidget(); void setWindowState_data(); void setWindowState(); void mainWindowSupport(); void emittingOfSignals_data(); void emittingOfSignals(); void showShaded(); void showNormal_data(); void showNormal(); void setOpaqueResizeAndMove_data(); void setOpaqueResizeAndMove(); void setWindowFlags_data(); void setWindowFlags(); void mouseDoubleClick(); void setSystemMenu(); void restoreFocus(); void changeFocusWithTab(); void closeEvent(); void setWindowTitle(); void resizeEvents_data(); void resizeEvents(); #if defined(Q_WS_MAC) void defaultSizeGrip(); #endif void hideAndShow(); void keepWindowMaximizedState(); void explicitlyHiddenWidget(); void resizeTimer(); void fixedMinMaxSize(); #if !defined (Q_WS_MAC) && !defined (Q_OS_WINCE) void replaceMenuBarWhileMaximized(); void closeOnDoubleClick(); #endif void setFont(); void task_188849(); void mdiArea(); void task_182852(); void task_233197(); void task_226929(); }; void tst_QMdiSubWindow::initTestCase() { qRegisterMetaType("Qt::WindowStates"); } void tst_QMdiSubWindow::sizeHint() { QMdiSubWindow *window = new QMdiSubWindow; QCOMPARE(window->sizeHint(), window->minimumSizeHint()); window->show(); QCOMPARE(window->sizeHint(), window->minimumSizeHint()); QMdiArea workspace; workspace.addSubWindow(window); QCOMPARE(window->sizeHint(), window->minimumSizeHint()); } void tst_QMdiSubWindow::minimumSizeHint() { QMdiSubWindow window; window.show(); QCOMPARE(window.minimumSizeHint(), qApp->globalStrut()); window.setWidget(new QWidget); QCOMPARE(window.minimumSizeHint(), window.layout()->minimumSize() .expandedTo(qApp->globalStrut())); delete window.widget(); delete window.layout(); window.setWidget(new QWidget); QCOMPARE(window.minimumSizeHint(), qApp->globalStrut()); window.widget()->show(); QCOMPARE(window.minimumSizeHint(), window.widget()->minimumSizeHint() .expandedTo(qApp->globalStrut())); } void tst_QMdiSubWindow::minimumSize() { QMdiArea mdiArea; mdiArea.resize(200, 200); // Check that we respect the minimum size set on the sub-window itself. QMdiSubWindow *subWindow1 = mdiArea.addSubWindow(new QWidget); subWindow1->setMinimumSize(1000, 1000); mdiArea.show(); #if defined(Q_WS_X11) qt_x11_wait_for_window_manager(&mdiArea); #endif QCOMPARE(subWindow1->size(), QSize(1000, 1000)); // Check that we respect the minimum size set on the internal widget. QWidget *widget = new QWidget; widget->setMinimumSize(1000, 1000); QMdiSubWindow *subWindow2 = mdiArea.addSubWindow(widget); QVERIFY(subWindow2->size() != mdiArea.viewport()->size()); QCOMPARE(subWindow2->size(), subWindow2->minimumSizeHint()); } void tst_QMdiSubWindow::setWidget() { QMdiSubWindow window; window.show(); QVERIFY(window.layout()); QVERIFY(!window.widget()); // QPointer so we can check if the widget is deleted QPointer widget = new QWidget; widget->setWindowTitle(QString::fromLatin1("DummyTitle")); QCOMPARE(widget->windowTitle(), QString::fromLatin1("DummyTitle")); window.setWidget(widget); QCOMPARE(window.windowTitle(), window.widget()->windowTitle()); QCOMPARE(widget->parentWidget(), static_cast(&window)); QVERIFY(!widget->isVisible()); QCOMPARE(window.layout()->count(), 1); QTest::ignoreMessage(QtWarningMsg,"QMdiSubWindow::setWidget: widget is already set"); window.setWidget(widget); QCOMPARE(window.widget(), static_cast(widget)); QCOMPARE(widget->parentWidget(), static_cast(&window)); window.setWidget(0); QVERIFY(widget); QVERIFY(!widget->parent()); QVERIFY(!window.widget()); QCOMPARE(window.layout()->count(), 0); window.setWidget(widget); delete window.layout(); QVERIFY(!window.layout()); QVERIFY(window.widget()); QCOMPARE(window.widget()->parentWidget(), static_cast(&window)); delete window.widget(); QVERIFY(!widget); QVERIFY(!window.widget()); } void tst_QMdiSubWindow::setWindowState_data() { QTest::addColumn("windowState"); QTest::newRow("maximized") << Qt::WindowMaximized; QTest::newRow("minimized") << Qt::WindowMinimized; QTest::newRow("normalized") << Qt::WindowNoState; } void tst_QMdiSubWindow::setWindowState() { QFETCH(Qt::WindowState, windowState); QMdiArea workspace; QMdiSubWindow *window = qobject_cast(workspace.addSubWindow(new QLineEdit)); window->show(); workspace.show(); #if defined(Q_WS_X11) qt_x11_wait_for_window_manager(&workspace); #endif QWidget *testWidget = 0; for (int iteration = 0; iteration < 2; ++iteration) { if (iteration == 0) testWidget = window; else testWidget = window->widget(); testWidget->setWindowState(windowState); Qt::WindowStates windowStateWindow = window->windowState(); windowStateWindow &= ~Qt::WindowActive; Qt::WindowStates windowStateWidget = window->widget()->windowState(); windowStateWidget &= ~Qt::WindowActive; QCOMPARE(windowStateWindow, windowStateWidget); switch (windowState) { case Qt::WindowNoState: QVERIFY(!window->widget()->isMinimized()); QVERIFY(!window->widget()->isMaximized()); QVERIFY(!window->isMinimized()); QVERIFY(!window->isMaximized()); break; case Qt::WindowMinimized: QVERIFY(window->widget()->isMinimized()); QVERIFY(window->isMinimized()); break; case Qt::WindowMaximized: QVERIFY(window->widget()->isMaximized()); QVERIFY(window->isMaximized()); break; default: break; } } } void tst_QMdiSubWindow::mainWindowSupport() { QList windows; QMdiArea *workspace = new QMdiArea; QMainWindow mainWindow; mainWindow.setCentralWidget(workspace); mainWindow.show(); mainWindow.menuBar()->setVisible(true); qApp->setActiveWindow(&mainWindow); // QMainWindow's window title is empty #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) { QCOMPARE(mainWindow.windowTitle(), QString()); QMdiSubWindow *window = workspace->addSubWindow(new QPushButton(QLatin1String("Test"))); QString expectedTitle = QLatin1String("MainWindow's title is empty"); window->setWindowTitle(expectedTitle); QCOMPARE(window->windowTitle(), expectedTitle); window->showMaximized(); QVERIFY(window->isMaximized()); QCOMPARE(window->windowTitle(), expectedTitle); QCOMPARE(mainWindow.windowTitle(), expectedTitle); window->showNormal(); QCOMPARE(window->windowTitle(), expectedTitle); QCOMPARE(mainWindow.windowTitle(), QString()); window->close(); } #endif QString originalWindowTitle = QString::fromLatin1("MainWindow"); mainWindow.setWindowTitle(originalWindowTitle); for (int i = 0; i < 5; ++i) { mainWindow.menuBar()->setVisible(false); QMdiSubWindow *window = new QMdiSubWindow; windows.append(window); QVERIFY(!window->maximizedButtonsWidget()); QVERIFY(!window->maximizedSystemMenuIconWidget()); QMdiArea *nestedWorkspace = new QMdiArea; // :-) window->setWidget(nestedWorkspace); window->widget()->setWindowTitle(QString::fromLatin1("Window %1").arg(i)); workspace->addSubWindow(window); QVERIFY(!window->maximizedButtonsWidget()); QVERIFY(!window->maximizedSystemMenuIconWidget()); window->show(); // mainWindow.menuBar() is not visible window->showMaximized(); qApp->processEvents(); QVERIFY(window->isMaximized()); QVERIFY(!window->maximizedButtonsWidget()); QVERIFY(!window->maximizedSystemMenuIconWidget()); window->showNormal(); // Now it is mainWindow.menuBar()->setVisible(true); window->showMaximized(); qApp->processEvents(); QVERIFY(window->isMaximized()); #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) QVERIFY(window->maximizedButtonsWidget()); QCOMPARE(window->maximizedButtonsWidget(), mainWindow.menuBar()->cornerWidget(Qt::TopRightCorner)); QVERIFY(window->maximizedSystemMenuIconWidget()); QCOMPARE(window->maximizedSystemMenuIconWidget(), qobject_cast(mainWindow.menuBar() ->cornerWidget(Qt::TopLeftCorner))); QCOMPARE(mainWindow.windowTitle(), QString::fromLatin1("%1 - [%2]") .arg(originalWindowTitle, window->widget()->windowTitle())); #endif // Check that nested child windows don't set window title nestedWorkspace->show(); QMdiSubWindow *nestedWindow = new QMdiSubWindow; nestedWindow->setWidget(new QWidget); nestedWorkspace->addSubWindow(nestedWindow); nestedWindow->widget()->setWindowTitle(QString::fromLatin1("NestedWindow %1").arg(i)); nestedWindow->showMaximized(); qApp->processEvents(); QVERIFY(nestedWindow->isMaximized()); QVERIFY(!nestedWindow->maximizedButtonsWidget()); QVERIFY(!nestedWindow->maximizedSystemMenuIconWidget()); #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) QCOMPARE(mainWindow.windowTitle(), QString::fromLatin1("%1 - [%2]") .arg(originalWindowTitle, window->widget()->windowTitle())); #endif } #if defined(Q_WS_MAC) || defined(Q_OS_WINCE) return; #endif workspace->activateNextSubWindow(); qApp->processEvents(); foreach (QMdiSubWindow *window, windows) { QCOMPARE(workspace->activeSubWindow(), window); QVERIFY(window->isMaximized()); QVERIFY(window->maximizedButtonsWidget()); QCOMPARE(window->maximizedButtonsWidget(), mainWindow.menuBar()->cornerWidget(Qt::TopRightCorner)); QVERIFY(window->maximizedSystemMenuIconWidget()); QCOMPARE(window->maximizedSystemMenuIconWidget(), qobject_cast(mainWindow.menuBar() ->cornerWidget(Qt::TopLeftCorner))); QCOMPARE(mainWindow.windowTitle(), QString::fromLatin1("%1 - [%2]") .arg(originalWindowTitle, window->widget()->windowTitle())); workspace->activateNextSubWindow(); qApp->processEvents(); } } // This test was written when QMdiSubWindow emitted separate signals void tst_QMdiSubWindow::emittingOfSignals_data() { QTest::addColumn("signal"); QTest::addColumn("watchedState"); QTest::newRow("windowMaximized") << QByteArray(SIGNAL(windowMaximized())) << Qt::WindowMaximized; QTest::newRow("windowMinimized") << QByteArray(SIGNAL(windowMinimized())) << Qt::WindowMinimized; QTest::newRow("windowRestored") << QByteArray(SIGNAL(windowRestored())) << Qt::WindowNoState; QTest::newRow("aboutToActivate") << QByteArray(SIGNAL(aboutToActivate())) << Qt::WindowNoState; QTest::newRow("windowActivated") << QByteArray(SIGNAL(windowActivated())) << Qt::WindowActive; QTest::newRow("windowDeactivated") << QByteArray(SIGNAL(windowDeactivated())) << Qt::WindowActive; } void tst_QMdiSubWindow::emittingOfSignals() { QFETCH(QByteArray, signal); QFETCH(Qt::WindowState, watchedState); QMdiArea workspace; workspace.show(); qApp->processEvents(); qApp->setActiveWindow(&workspace); QMdiSubWindow *window = qobject_cast(workspace.addSubWindow(new QWidget)); qApp->processEvents(); window->show(); if (signal != SIGNAL(windowRestored())) workspace.setActiveSubWindow(0); qApp->processEvents(); QSignalSpy spy(window, signal == SIGNAL(aboutToActivate()) ? signal.data() : SIGNAL(windowStateChanged(Qt::WindowStates, Qt::WindowStates))); QVERIFY(spy.isEmpty()); triggerSignal(window, &workspace, signal); // Unless the signal is windowRestored or windowDeactivated, // we're already in correct state and nothing should happen. if (signal != SIGNAL(windowRestored()) && signal != SIGNAL(windowDeactivated())) triggerSignal(window, &workspace, signal); int count = 0; if (signal == SIGNAL(aboutToActivate())) { count += spy.count(); } else { for (int i = 0; i < spy.count(); ++i) { Qt::WindowStates oldState = qvariant_cast(spy.at(i).at(0)); Qt::WindowStates newState = qvariant_cast(spy.at(i).at(1)); if (watchedState != Qt::WindowNoState) { if (!(oldState & watchedState) && (newState & watchedState)) ++count; } else { if ((oldState & (Qt::WindowMinimized | Qt::WindowMaximized)) && (newState & (watchedState | Qt::WindowActive))) { ++count; } } } } QCOMPARE(count, 1); window->setParent(0); window->showNormal(); #if defined(Q_WS_X11) qt_x11_wait_for_window_manager(window); #endif qApp->processEvents(); spy.clear(); triggerSignal(window, &workspace, signal); QCOMPARE(spy.count(), 0); delete window; window = 0; } void tst_QMdiSubWindow::showShaded() { QMdiArea workspace; QMdiSubWindow *window = workspace.addSubWindow(new QLineEdit); window->resize(300, 300); qApp->processEvents(); workspace.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&workspace); #endif QVERIFY(!window->isShaded()); QVERIFY(!window->isMaximized()); QCOMPARE(window->size(), QSize(300, 300)); QRect restoreGeometry = window->geometry(); window->showShaded(); QVERIFY(window->isShaded()); QVERIFY(window->isMinimized()); window->showNormal(); QVERIFY(!window->isShaded()); QVERIFY(!window->isMinimized()); QCOMPARE(window->geometry(), restoreGeometry); window->showShaded(); window->showNormal(); QVERIFY(!window->isShaded()); QVERIFY(!window->isMinimized()); QCOMPARE(window->geometry(), restoreGeometry); window->showMinimized(); window->showMaximized(); window->showShaded(); QCOMPARE(window->width(), workspace.contentsRect().width()); window->showNormal(); QCOMPARE(window->geometry(), workspace.contentsRect()); window->resize(300, 300); QCOMPARE(window->size(), QSize(300, 300)); window->showShaded(); window->showNormal(); QTest::qWait(250); #ifdef Q_OS_WINCE QSKIP("Until we have a QEvent::WindowFlagsChange event, this will skip", SkipAll); #endif const QSize minimumSizeHint = window->minimumSizeHint(); QVERIFY(minimumSizeHint.height() < 300); const int maxHeightDiff = 300 - minimumSizeHint.height(); // Calculate mouse position for bottom right corner and simulate a // vertical resize with the mouse. int offset = window->style()->pixelMetric(QStyle::PM_MDIFrameWidth) / 2; QPoint mousePosition(window->width() - qMax(offset, 2), window->height() - qMax(offset, 2)); QWidget *mouseReceiver = 0; #ifdef Q_WS_MAC if (qobject_cast(window->style())) mouseReceiver = qFindChild(window); else #endif mouseReceiver = window; QVERIFY(mouseReceiver); sendMouseMove(mouseReceiver, mousePosition, Qt::NoButton); sendMousePress(mouseReceiver, mousePosition); for (int i = 0; i < maxHeightDiff + 20; ++i) { --mousePosition.ry(); sendMouseMove(mouseReceiver, mousePosition); } sendMouseRelease(mouseReceiver, mousePosition); // Make sure we respect the minimumSizeHint! QCOMPARE(window->height(), minimumSizeHint.height()); window->showShaded(); window->setParent(0); window->show(); QVERIFY(!window->isShaded()); delete window; } void tst_QMdiSubWindow::showNormal_data() { QTest::addColumn("slot"); QTest::newRow("showMinimized") << QByteArray("showMinimized"); QTest::newRow("showMaximized") << QByteArray("showMaximized"); QTest::newRow("showShaded") << QByteArray("showShaded"); } void tst_QMdiSubWindow::showNormal() { QFETCH(QByteArray, slot); QMdiArea workspace; QWidget *window = workspace.addSubWindow(new QWidget); qApp->processEvents(); workspace.show(); window->show(); #if defined(Q_WS_X11) qt_x11_wait_for_window_manager(&workspace); #endif QRect originalGeometry = window->geometry(); QVERIFY(QMetaObject::invokeMethod(window, slot.data())); qApp->processEvents(); window->showNormal(); qApp->processEvents(); QCOMPARE(window->geometry(), originalGeometry); } 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_QMdiSubWindow::setOpaqueResizeAndMove_data() { QTest::addColumn("opaqueMode"); QTest::addColumn("geometryCount"); QTest::addColumn("expectedGeometryCount"); QTest::addColumn("workspaceSize"); QTest::addColumn("windowSize"); QTest::newRow("normal mode") << true<< 20 << 20 << QSize(400, 400) << QSize(200, 200); QTest::newRow("rubberband mode") << false << 20 << 1 << QSize(400, 400) << QSize(200, 200); } void tst_QMdiSubWindow::setOpaqueResizeAndMove() { #if defined (QT_NO_CURSOR) || defined (Q_OS_WINCE_WM) //For Windows CE we will set QT_NO_CURSOR if there is no cursor support QSKIP("No cursor available", SkipAll); #endif QFETCH(bool, opaqueMode); QFETCH(int, geometryCount); QFETCH(int, expectedGeometryCount); QFETCH(QSize, workspaceSize); QFETCH(QSize, windowSize); QMdiArea workspace; QMdiSubWindow *window = qobject_cast(workspace.addSubWindow(new QWidget)); qApp->processEvents(); workspace.resize(workspaceSize); workspace.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&workspace); #endif QWidget *mouseReceiver = 0; if (window->style()->inherits("QMacStyle")) mouseReceiver = qFindChild(window); else mouseReceiver = window; QVERIFY(mouseReceiver); // ----------------------------- resize ----------------------------- { // setOpaqueResize window->setOption(QMdiSubWindow::RubberBandResize, !opaqueMode); QCOMPARE(window->testOption(QMdiSubWindow::RubberBandResize), !opaqueMode); // Check that the event spy actually works EventSpy resizeSpy(window, QEvent::Resize); QCOMPARE(resizeSpy.count(), 0); window->resize(windowSize); QCOMPARE(window->size(), windowSize); QCOMPARE(resizeSpy.count(), 1); resizeSpy.clear(); QCOMPARE(resizeSpy.count(), 0); QTest::qWait(250); // delayed update of dirty regions // Enter resize mode. int offset = window->style()->pixelMetric(QStyle::PM_MDIFrameWidth) / 2; QPoint mousePosition(mouseReceiver->width() - qMax(offset, 2), mouseReceiver->height() - qMax(offset, 2)); sendMouseMove(mouseReceiver, mousePosition, Qt::NoButton); sendMousePress(mouseReceiver, mousePosition); // The window itself is the grabber in rubberband mode if (!opaqueMode) { mouseReceiver = window; mousePosition = QPoint(window->width() - qMax(offset, 2), window->height() - qMax(offset, 2)); } // Trigger resize events for (int i = 0; i < geometryCount; ++i) { if (mouseReceiver == window) { ++mousePosition.rx(); ++mousePosition.ry(); sendMouseMove(mouseReceiver, mousePosition); } else { sendMouseMove(mouseReceiver, mousePosition + QPoint(1, 1)); } } // Leave resize mode sendMouseRelease(mouseReceiver, mousePosition); QCOMPARE(resizeSpy.count(), expectedGeometryCount); QCOMPARE(window->size(), windowSize + QSize(geometryCount, geometryCount)); } // ------------------------------ move ------------------------------ { // setOpaqueMove window->setOption(QMdiSubWindow::RubberBandMove, !opaqueMode); QCOMPARE(window->testOption(QMdiSubWindow::RubberBandMove), !opaqueMode); EventSpy moveSpy(window, QEvent::Move); QCOMPARE(moveSpy.count(), 0); window->move(30, 30); QCOMPARE(moveSpy.count(), 1); moveSpy.clear(); // Enter move mode QStyleOptionTitleBar options; options.initFrom(window); int height = window->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options); #if defined(Q_WS_MAC) // ### Remove this after mac style has been fixed height -= 4; #endif QPoint mousePosition(window->width() / 2, height - 1); sendMouseMove(window, mousePosition, Qt::NoButton); sendMousePress(window, mousePosition); // Trigger move events for (int i = 0; i < geometryCount; ++i) { ++mousePosition.rx(); ++mousePosition.ry(); sendMouseMove(window, mousePosition); } // Leave move mode sendMouseRelease(window, mousePosition); QCOMPARE(moveSpy.count(), expectedGeometryCount); QCOMPARE(window->size(), windowSize + QSize(geometryCount, geometryCount)); } } void tst_QMdiSubWindow::setWindowFlags_data() { QTest::addColumn("windowType"); QTest::addColumn("expectedWindowType"); QTest::addColumn("customFlags"); QTest::addColumn("expectedCustomFlags"); // NB! If 'expectedCustomFlags' is set to 'Qt::WindowFlags(0)' // and nothing else, it means we're expecting the same as customFlags. // Standard window types with no custom flags set. QTest::newRow("Qt::Widget") << Qt::Widget << Qt::SubWindow << Qt::WindowFlags(0) << StandardWindowFlags; QTest::newRow("Qt::Window") << Qt::Window << Qt::SubWindow << Qt::WindowFlags(0) << StandardWindowFlags; QTest::newRow("Qt::Dialog") << Qt::Dialog << Qt::SubWindow << Qt::WindowFlags(0) << DialogWindowFlags; QTest::newRow("Qt::Sheet") << Qt::Sheet << Qt::SubWindow << Qt::WindowFlags(0) << StandardWindowFlags; QTest::newRow("Qt::Drawer") << Qt::Drawer << Qt::SubWindow << Qt::WindowFlags(0) << StandardWindowFlags; QTest::newRow("Qt::Popup") << Qt::Popup << Qt::SubWindow << Qt::WindowFlags(0) << StandardWindowFlags; QTest::newRow("Qt::Tool") << Qt::Tool << Qt::SubWindow << Qt::WindowFlags(0) << StandardWindowFlags; QTest::newRow("Qt::ToolTip") << Qt::ToolTip << Qt::SubWindow << Qt::WindowFlags(0) << StandardWindowFlags; QTest::newRow("Qt::SplashScreen") << Qt::SplashScreen << Qt::SubWindow << Qt::WindowFlags(0) << StandardWindowFlags; QTest::newRow("Qt::Desktop") << Qt::Desktop << Qt::SubWindow << Qt::WindowFlags(0) << StandardWindowFlags; QTest::newRow("Qt::SubWindow") << Qt::SubWindow << Qt::SubWindow << Qt::WindowFlags(0) << StandardWindowFlags; // Custom flags QTest::newRow("Title") << Qt::SubWindow << Qt::SubWindow << (Qt::WindowTitleHint | Qt::WindowFlags(0)) << Qt::WindowFlags(0); QTest::newRow("TitleAndMin") << Qt::SubWindow << Qt::SubWindow << (Qt::WindowTitleHint | Qt::WindowMinimizeButtonHint) << Qt::WindowFlags(0); QTest::newRow("TitleAndMax") << Qt::SubWindow << Qt::SubWindow << (Qt::WindowTitleHint | Qt::WindowMaximizeButtonHint) << Qt::WindowFlags(0); QTest::newRow("TitleAndMinMax") << Qt::SubWindow << Qt::SubWindow << (Qt::WindowTitleHint | Qt::WindowMinMaxButtonsHint) << Qt::WindowFlags(0); QTest::newRow("Standard") << Qt::SubWindow << Qt::SubWindow << StandardWindowFlags << Qt::WindowFlags(0); QTest::newRow("StandardAndShade") << Qt::SubWindow << Qt::SubWindow << (StandardWindowFlags | Qt::WindowShadeButtonHint) << Qt::WindowFlags(0); QTest::newRow("StandardAndContext") << Qt::SubWindow << Qt::SubWindow << (StandardWindowFlags | Qt::WindowContextHelpButtonHint) << Qt::WindowFlags(0); QTest::newRow("StandardAndStaysOnTop") << Qt::SubWindow << Qt::SubWindow << (StandardWindowFlags | Qt::WindowStaysOnTopHint) << Qt::WindowFlags(0); QTest::newRow("StandardAndFrameless") << Qt::SubWindow << Qt::SubWindow << (StandardWindowFlags | Qt::FramelessWindowHint) << (Qt::FramelessWindowHint | Qt::WindowFlags(0)); QTest::newRow("StandardAndFramelessAndStaysOnTop") << Qt::SubWindow << Qt::SubWindow << (StandardWindowFlags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) << (Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); QTest::newRow("Shade") << Qt::SubWindow << Qt::SubWindow << (Qt::WindowShadeButtonHint | Qt::WindowFlags(0)) << (StandardWindowFlags | Qt::WindowShadeButtonHint); QTest::newRow("ShadeAndCustomize") << Qt::SubWindow << Qt::SubWindow << (Qt::WindowShadeButtonHint | Qt::CustomizeWindowHint) << Qt::WindowFlags(0); QTest::newRow("Context") << Qt::SubWindow << Qt::SubWindow << (Qt::WindowContextHelpButtonHint | Qt::WindowFlags(0)) << (StandardWindowFlags | Qt::WindowContextHelpButtonHint); QTest::newRow("ContextAndCustomize") << Qt::SubWindow << Qt::SubWindow << (Qt::WindowContextHelpButtonHint | Qt::CustomizeWindowHint) << Qt::WindowFlags(0); QTest::newRow("ShadeAndContext") << Qt::SubWindow << Qt::SubWindow << (Qt::WindowShadeButtonHint | Qt::WindowContextHelpButtonHint) << (StandardWindowFlags | Qt::WindowShadeButtonHint | Qt::WindowContextHelpButtonHint); QTest::newRow("ShadeAndContextAndCustomize") << Qt::SubWindow << Qt::SubWindow << (Qt::WindowShadeButtonHint | Qt::WindowContextHelpButtonHint | Qt::CustomizeWindowHint) << Qt::WindowFlags(0); QTest::newRow("OnlyCustomize") << Qt::SubWindow << Qt::SubWindow << (Qt::CustomizeWindowHint | Qt::WindowFlags(0)) << Qt::WindowFlags(0); } void tst_QMdiSubWindow::setWindowFlags() { QSKIP("Until we have a QEvent::WindowFlagsChange event, this will skip", SkipAll); QFETCH(Qt::WindowType, windowType); QFETCH(Qt::WindowType, expectedWindowType); QFETCH(Qt::WindowFlags, customFlags); QFETCH(Qt::WindowFlags, expectedCustomFlags); QMdiArea workspace; QMdiSubWindow *window = qobject_cast(workspace.addSubWindow(new QWidget)); qApp->processEvents(); workspace.show(); window->show(); #if defined(Q_WS_X11) qt_x11_wait_for_window_manager(&workspace); #endif window->setWindowFlags(windowType | customFlags); QCOMPARE(window->windowType(), expectedWindowType); if (!expectedCustomFlags) // We expect the same as 'customFlags' QCOMPARE(window->windowFlags() & ~expectedWindowType, customFlags); else QCOMPARE(window->windowFlags() & ~expectedWindowType, expectedCustomFlags); } void tst_QMdiSubWindow::mouseDoubleClick() { QMdiArea workspace; QMdiSubWindow *window = qobject_cast(workspace.addSubWindow(new QWidget)); qApp->processEvents(); workspace.show(); window->show(); QVERIFY(!window->isMaximized()); QVERIFY(!window->isShaded()); QRect originalGeometry = window->geometry(); // Calculate mouse position QStyleOptionTitleBar options; options.initFrom(window); int height = window->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options); // ### Remove this after mac style has been fixed if (window->style()->inherits("QMacStyle")) height -= 4; // has border if (!window->style()->styleHint(QStyle::SH_TitleBar_NoBorder, &options, window)) height += window->isMinimized() ? 8 : 4; QPoint mousePosition(window->width() / 2, height - 1); sendMouseMove(window, mousePosition, Qt::NoButton); // Without Qt::WindowShadeButtonHint flag set sendMouseDoubleClick(window, mousePosition); qApp->processEvents(); QVERIFY(window->isMaximized()); sendMouseDoubleClick(window, mousePosition); qApp->processEvents(); QVERIFY(!window->isMaximized()); QCOMPARE(window->geometry(), originalGeometry); // With Qt::WindowShadeButtonHint flag set QSKIP("Until we have a QEvent::WindowFlagsChange event, this will skip", SkipAll); window->setWindowFlags(window->windowFlags() | Qt::WindowShadeButtonHint); QVERIFY(window->windowFlags() & Qt::WindowShadeButtonHint); originalGeometry = window->geometry(); sendMouseDoubleClick(window, mousePosition); qApp->processEvents(); QVERIFY(window->isShaded()); sendMouseDoubleClick(window, mousePosition); qApp->processEvents(); QVERIFY(!window->isShaded()); QCOMPARE(window->geometry(), originalGeometry); window->showMinimized(); QVERIFY(window->isMinimized()); sendMouseDoubleClick(window, mousePosition); QVERIFY(!window->isMinimized()); QCOMPARE(window->geometry(), originalGeometry); } void tst_QMdiSubWindow::setSystemMenu() { QMdiSubWindow *subWindow = new QMdiSubWindow; subWindow->resize(200, 50); QPointersystemMenu = subWindow->systemMenu(); QVERIFY(systemMenu); QCOMPARE(subWindow->actions(), systemMenu->actions()); QMainWindow mainWindow; QMdiArea *mdiArea = new QMdiArea; mdiArea->addSubWindow(subWindow); mainWindow.setCentralWidget(mdiArea); mainWindow.menuBar(); mainWindow.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&mainWindow); #endif QVERIFY(subWindow->isVisible()); QPoint globalPopupPos = subWindow->mapToGlobal(subWindow->contentsRect().topLeft()); // Show system menu QVERIFY(!qApp->activePopupWidget()); subWindow->showSystemMenu(); QTest::qWait(250); QCOMPARE(qApp->activePopupWidget(), qobject_cast(systemMenu)); QCOMPARE(systemMenu->mapToGlobal(QPoint(0, 0)), globalPopupPos); systemMenu->hide(); QVERIFY(!qApp->activePopupWidget()); QTest::ignoreMessage(QtWarningMsg, "QMdiSubWindow::setSystemMenu: system menu is already set"); subWindow->setSystemMenu(systemMenu); subWindow->setSystemMenu(0); QVERIFY(!systemMenu); // systemMenu is QPointer systemMenu = new QMenu(subWindow); systemMenu->addAction(QIcon(subWindow->style()->standardIcon(QStyle::SP_TitleBarCloseButton)), QObject::tr("&Close"), subWindow, SLOT(close())); subWindow->setSystemMenu(systemMenu); QCOMPARE(subWindow->systemMenu(), qobject_cast(systemMenu)); QCOMPARE(subWindow->systemMenu()->parentWidget(), static_cast(subWindow)); QCOMPARE(subWindow->systemMenu()->actions().count(), 1); // Show the new system menu QVERIFY(!qApp->activePopupWidget()); subWindow->showSystemMenu(); QTest::qWait(250); QCOMPARE(qApp->activePopupWidget(), qobject_cast(systemMenu)); QCOMPARE(systemMenu->mapToGlobal(QPoint(0, 0)), globalPopupPos); systemMenu->hide(); QVERIFY(!qApp->activePopupWidget()); #if !defined (Q_WS_MAC) && !defined (Q_OS_WINCE) // System menu in menu bar. subWindow->showMaximized(); QVERIFY(subWindow->isMaximized()); QWidget *menuLabel = subWindow->maximizedSystemMenuIconWidget(); QVERIFY(menuLabel); subWindow->showSystemMenu(); QTest::qWait(250); QCOMPARE(qApp->activePopupWidget(), qobject_cast(systemMenu)); globalPopupPos = menuLabel->mapToGlobal(QPoint(0, menuLabel->y() + menuLabel->height())); QCOMPARE(systemMenu->mapToGlobal(QPoint(0, 0)), globalPopupPos); systemMenu->hide(); QVERIFY(!qApp->activePopupWidget()); subWindow->showNormal(); #endif // Reverse qApp->setLayoutDirection(Qt::RightToLeft); qApp->processEvents(); mainWindow.updateGeometry(); subWindow->showSystemMenu(); QTest::qWait(250); QCOMPARE(qApp->activePopupWidget(), qobject_cast(systemMenu)); // + QPoint(1, 0) because topRight() == QPoint(left() + width() -1, top()) globalPopupPos = subWindow->mapToGlobal(subWindow->contentsRect().topRight()) + QPoint(1, 0); globalPopupPos -= QPoint(systemMenu->sizeHint().width(), 0); QCOMPARE(systemMenu->mapToGlobal(QPoint(0, 0)), globalPopupPos); systemMenu->hide(); QVERIFY(!qApp->activePopupWidget()); #if !defined (Q_WS_MAC) && !defined (Q_OS_WINCE) // System menu in menu bar in reverse mode. subWindow->showMaximized(); QVERIFY(subWindow->isMaximized()); menuLabel = subWindow->maximizedSystemMenuIconWidget(); QVERIFY(menuLabel); subWindow->showSystemMenu(); QTest::qWait(250); QCOMPARE(qApp->activePopupWidget(), qobject_cast(systemMenu)); globalPopupPos = menuLabel->mapToGlobal(QPoint(menuLabel->width(), menuLabel->y() + menuLabel->height())); globalPopupPos -= QPoint(systemMenu->sizeHint().width(), 0); QCOMPARE(systemMenu->mapToGlobal(QPoint(0, 0)), globalPopupPos); #endif delete systemMenu; QVERIFY(!qApp->activePopupWidget()); QVERIFY(!subWindow->systemMenu()); // Restore layout direction. qApp->setLayoutDirection(Qt::LeftToRight); } void tst_QMdiSubWindow::restoreFocus() { // Create complex layout. QGroupBox *box = new QGroupBox(tr("GroupBox")); box->setCheckable(true); QGroupBox *box1 = new QGroupBox(tr("&TopLeft")); box1->setLayout(new QHBoxLayout); box1->layout()->addWidget(new QTextEdit); QGroupBox *box2 = new QGroupBox(tr("&TopRight")); box2->setLayout(new QHBoxLayout); box2->layout()->addWidget(new QTextEdit); QGroupBox *box3 = new QGroupBox(tr("&BottomLeft")); box3->setLayout(new QHBoxLayout); box3->layout()->addWidget(new QTextEdit); QGroupBox *box4 = new QGroupBox(tr("&BottomRight")); box4->setLayout(new QHBoxLayout); QMdiArea *nestedWorkspace = new QMdiArea; for (int i = 0; i < 4; ++i) nestedWorkspace->addSubWindow(new QTextEdit)->show(); qApp->processEvents(); nestedWorkspace->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); nestedWorkspace->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); box4->layout()->addWidget(nestedWorkspace); QGridLayout *layout = new QGridLayout; layout->addWidget(box1, 0, 0); layout->addWidget(box2, 0, 1); layout->addWidget(box3, 1, 0); layout->addWidget(box4, 1, 1); box->setLayout(layout); // Add complex widget to workspace. QMdiArea topArea; QMdiSubWindow *complexWindow = topArea.addSubWindow(box); topArea.show(); box->show(); qApp->setActiveWindow(&topArea); QMdiSubWindow *expectedFocusWindow = nestedWorkspace->subWindowList().last(); QVERIFY(expectedFocusWindow); QVERIFY(expectedFocusWindow->widget()); QCOMPARE(qApp->focusWidget(), expectedFocusWindow->widget()); // Normal -> minimized expectedFocusWindow->showMinimized(); qApp->processEvents(); QVERIFY(expectedFocusWindow->isMinimized()); QCOMPARE(qApp->focusWidget(), static_cast(expectedFocusWindow)); // Minimized -> normal expectedFocusWindow->showNormal(); qApp->processEvents(); QVERIFY(!expectedFocusWindow->isMinimized()); QCOMPARE(qApp->focusWidget(), expectedFocusWindow->widget()); // Normal -> maximized expectedFocusWindow->showMaximized(); qApp->processEvents(); QVERIFY(expectedFocusWindow->isMaximized()); QCOMPARE(qApp->focusWidget(), expectedFocusWindow->widget()); // Maximized -> normal expectedFocusWindow->showNormal(); qApp->processEvents(); QVERIFY(!expectedFocusWindow->isMaximized()); QCOMPARE(qApp->focusWidget(), expectedFocusWindow->widget()); // Minimized -> maximized expectedFocusWindow->showMinimized(); qApp->processEvents(); QVERIFY(expectedFocusWindow->isMinimized()); expectedFocusWindow->showMaximized(); qApp->processEvents(); QVERIFY(expectedFocusWindow->isMaximized()); QCOMPARE(qApp->focusWidget(), expectedFocusWindow->widget()); // Maximized -> minimized expectedFocusWindow->showNormal(); qApp->processEvents(); QVERIFY(!expectedFocusWindow->isMaximized()); expectedFocusWindow->showMaximized(); qApp->processEvents(); QVERIFY(expectedFocusWindow->isMaximized()); expectedFocusWindow->showMinimized(); qApp->processEvents(); QVERIFY(expectedFocusWindow->isMinimized()); QCOMPARE(qApp->focusWidget(), static_cast(expectedFocusWindow)); complexWindow->showMinimized(); qApp->processEvents(); QVERIFY(complexWindow->isMinimized()); QCOMPARE(qApp->focusWidget(), static_cast(complexWindow)); complexWindow->showNormal(); qApp->processEvents(); QVERIFY(!complexWindow->isMinimized()); QCOMPARE(qApp->focusWidget(), static_cast(expectedFocusWindow)); } void tst_QMdiSubWindow::changeFocusWithTab() { QWidget *widget = new QWidget; widget->setLayout(new QVBoxLayout); QLineEdit *firstLineEdit = new QLineEdit; widget->layout()->addWidget(firstLineEdit); QLineEdit *secondLineEdit = new QLineEdit; widget->layout()->addWidget(secondLineEdit); QLineEdit *thirdLineEdit = new QLineEdit; widget->layout()->addWidget(thirdLineEdit); QMdiArea mdiArea; mdiArea.addSubWindow(widget); mdiArea.show(); QCOMPARE(mdiArea.subWindowList().count(), 1); qApp->setActiveWindow(&mdiArea); QCOMPARE(qApp->focusWidget(), static_cast(firstLineEdit)); // Next QTest::keyPress(widget, Qt::Key_Tab); QCOMPARE(qApp->focusWidget(), static_cast(secondLineEdit)); // Next QTest::keyPress(widget, Qt::Key_Tab); QCOMPARE(qApp->focusWidget(), static_cast(thirdLineEdit)); // Previous QTest::keyPress(widget, Qt::Key_Backtab); QCOMPARE(qApp->focusWidget(), static_cast(secondLineEdit)); // Previous QTest::keyPress(widget, Qt::Key_Backtab); QCOMPARE(qApp->focusWidget(), static_cast(firstLineEdit)); QMdiSubWindow *window = mdiArea.addSubWindow(new QPushButton); window->show(); QCOMPARE(mdiArea.activeSubWindow(), window); // Check that we don't give away focus to another window by // just hitting tab if the child widget does not accept // focus (which is the case for a QPushButton). QTest::keyPress(window, Qt::Key_Tab); QCOMPARE(mdiArea.activeSubWindow(), window); QCOMPARE(qApp->focusWidget(), tabAllWidgets() ? window->widget() : window); QTest::keyPress(window, Qt::Key_Tab); QCOMPARE(mdiArea.activeSubWindow(), window); QCOMPARE(qApp->focusWidget(), tabAllWidgets() ? window->widget() : window); } class MyTextEdit : public QTextEdit { public: MyTextEdit(QWidget *parent = 0) : QTextEdit(parent), acceptClose(false) {} void setAcceptClose(bool enable = true) { acceptClose = enable; } protected: void closeEvent(QCloseEvent *closeEvent) { if (!acceptClose) closeEvent->ignore(); } private: bool acceptClose; }; void tst_QMdiSubWindow::closeEvent() { QMdiArea mdiArea; mdiArea.show(); MyTextEdit *textEdit = new MyTextEdit; textEdit->setAcceptClose(false); QMdiSubWindow *window = mdiArea.addSubWindow(textEdit); EventSpy closeSpy(window->widget(), QEvent::Close); window->show(); QCOMPARE(closeSpy.count(), 0); QVERIFY(window->isVisible()); QVERIFY(textEdit->isVisible()); QVERIFY(!window->close()); QCOMPARE(closeSpy.count(), 1); QVERIFY(window->isVisible()); QVERIFY(textEdit->isVisible()); QVERIFY(!textEdit->close()); QCOMPARE(closeSpy.count(), 2); QVERIFY(window->isVisible()); QVERIFY(textEdit->isVisible()); textEdit->setAcceptClose(true); QVERIFY(window->close()); QCOMPARE(closeSpy.count(), 3); QCOMPARE(mdiArea.subWindowList().count(), 0); } // There exists more tests in QMdiArea which covers window title support // related to QMainWindow. This test is specific for QMdiSubWindow and its // widget. void tst_QMdiSubWindow::setWindowTitle() { QString expectedWindowTitle = QLatin1String("This is teh shit[*]"); QTextEdit *textEdit = new QTextEdit; textEdit->setWindowTitle(expectedWindowTitle); QCOMPARE(textEdit->windowTitle(), expectedWindowTitle); textEdit->setWindowModified(true); QCOMPARE(textEdit->isWindowModified(), true); QMdiArea mdiArea; QMdiSubWindow *window = new QMdiSubWindow; mdiArea.addSubWindow(window); QCOMPARE(window->windowTitle(), QString()); QVERIFY(!window->isWindowModified()); window->setWidget(textEdit); QVERIFY(window->isWindowModified()); QCOMPARE(textEdit->windowTitle(), expectedWindowTitle); QCOMPARE(window->windowTitle(), window->widget()->windowTitle()); textEdit->setWindowModified(false); QVERIFY(!textEdit->isWindowModified()); QVERIFY(!window->isWindowModified()); // This will return the title including the astrix, but the // actual window title does not contain the astrix. This behavior // seems a bit odd, but is equal to e.g. QTextEdit (and probably all // other widgets which are not real top-level widgets). QCOMPARE(window->windowTitle(), expectedWindowTitle); textEdit->setWindowModified(true);; expectedWindowTitle = QLatin1String("Override child title"); window->setWindowTitle(expectedWindowTitle); QVERIFY(window->isWindowModified()); QCOMPARE(window->windowTitle(), expectedWindowTitle); textEdit->setWindowTitle(QLatin1String("My parent overrides me")); QCOMPARE(window->windowTitle(), expectedWindowTitle); textEdit->setWindowModified(false); QVERIFY(window->isWindowModified()); QCOMPARE(window->windowTitle(), expectedWindowTitle); window->setWindowModified(false); QVERIFY(!window->isWindowModified()); window->setWindowTitle(QString()); QCOMPARE(window->windowTitle(), QString()); expectedWindowTitle = QLatin1String("My parent doesn't have any title so now I can set one[*]"); textEdit->setWindowTitle(expectedWindowTitle); QCOMPARE(window->windowTitle(), expectedWindowTitle); textEdit->setWindowModified(true); QVERIFY(window->isWindowModified()); window->setWidget(0); QCOMPARE(window->windowTitle(), QString()); QVERIFY(!window->isWindowModified()); delete textEdit; } void tst_QMdiSubWindow::resizeEvents_data() { QTest::addColumn("windowState"); QTest::addColumn("expectedWindowResizeEvents"); QTest::addColumn("expectedWidgetResizeEvents"); QTest::addColumn("isShadeMode"); QTest::newRow("minimized") << Qt::WindowMinimized << 1 << 0 << false; QTest::newRow("maximized") << Qt::WindowMaximized << 1 << 1 << false; QTest::newRow("shaded") << Qt::WindowMinimized << 1 << 0 << true; } void tst_QMdiSubWindow::resizeEvents() { QFETCH(Qt::WindowState, windowState); QFETCH(int, expectedWindowResizeEvents); QFETCH(int, expectedWidgetResizeEvents); QFETCH(bool, isShadeMode); QMainWindow mainWindow; QMdiArea *mdiArea = new QMdiArea; mainWindow.setCentralWidget(mdiArea); mainWindow.show(); #if defined(Q_WS_X11) qt_x11_wait_for_window_manager(&mainWindow); #endif QMdiSubWindow *window = mdiArea->addSubWindow(new QTextEdit); window->show(); EventSpy windowResizeEventSpy(window, QEvent::Resize); QCOMPARE(windowResizeEventSpy.count(), 0); EventSpy widgetResizeEventSpy(window->widget(), QEvent::Resize); QCOMPARE(widgetResizeEventSpy.count(), 0); // Set the window state. if (!isShadeMode) window->setWindowState(windowState); else window->showShaded(); // Check that the window state is correct. QCOMPARE(window->windowState(), windowState | Qt::WindowActive); QCOMPARE(window->widget()->windowState(), windowState); // Make sure we got as many resize events as expected. QCOMPARE(windowResizeEventSpy.count(), expectedWindowResizeEvents); QCOMPARE(widgetResizeEventSpy.count(), expectedWidgetResizeEvents); windowResizeEventSpy.clear(); widgetResizeEventSpy.clear(); // Normalize. window->showNormal(); // Check that the window state is correct. QCOMPARE(window->windowState(), Qt::WindowNoState | Qt::WindowActive); QCOMPARE(window->widget()->windowState(), Qt::WindowNoState); // Make sure we got as many resize events as expected. QCOMPARE(windowResizeEventSpy.count(), expectedWindowResizeEvents); QCOMPARE(widgetResizeEventSpy.count(), expectedWidgetResizeEvents); } #if defined(Q_WS_MAC) void tst_QMdiSubWindow::defaultSizeGrip() { if (!qApp->style()->inherits("QMacStyle")) return; QMdiArea mdiArea; mdiArea.show(); // QSizeGrip on windows with decoration. QMdiSubWindow *windowWithDecoration = mdiArea.addSubWindow(new QWidget); windowWithDecoration->show(); QVERIFY(qFindChild(windowWithDecoration)); // ...but not on windows without decoration (Qt::FramelessWindowHint). QMdiSubWindow *windowWithoutDecoration = mdiArea.addSubWindow(new QWidget, Qt::FramelessWindowHint); windowWithoutDecoration->show(); QVERIFY(!qFindChild(windowWithoutDecoration)); } #endif void tst_QMdiSubWindow::hideAndShow() { // Create a QTabWidget with two tabs; QMdiArea and QTextEdit. QTabWidget *tabWidget = new QTabWidget; QMdiArea *mdiArea = new QMdiArea; tabWidget->addTab(mdiArea, QLatin1String("QMdiArea")); tabWidget->addTab(new QTextEdit, QLatin1String("Dummy")); // Set the tab widget as the central widget in QMainWindow. QMainWindow mainWindow; mainWindow.setGeometry(0, 0, 640, 480); QMenuBar *menuBar = mainWindow.menuBar(); mainWindow.setCentralWidget(tabWidget); mainWindow.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&mainWindow); #endif QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner)); QMdiSubWindow *subWindow = mdiArea->addSubWindow(new QTextEdit); subWindow->showMaximized(); #if !defined (Q_WS_MAC) && !defined (Q_OS_WINCE) QVERIFY(menuBar->cornerWidget(Qt::TopRightCorner)); QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget()); #endif // Hide QMdiArea. tabWidget->setCurrentIndex(1); QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner)); QVERIFY(!subWindow->maximizedButtonsWidget()); QVERIFY(!subWindow->maximizedSystemMenuIconWidget()); // Show QMdiArea. tabWidget->setCurrentIndex(0); #if !defined (Q_WS_MAC) && !defined (Q_OS_WINCE) QVERIFY(menuBar->cornerWidget(Qt::TopRightCorner)); QVERIFY(subWindow->maximizedButtonsWidget()); QVERIFY(subWindow->maximizedSystemMenuIconWidget()); QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget()); #endif // Hide QMdiArea. tabWidget->setCurrentIndex(1); // Add few more windows. for (int i = 0; i < 5; ++i) mdiArea->addSubWindow(new QTextEdit); // Show QMdiArea. tabWidget->setCurrentIndex(0); qApp->processEvents(); subWindow = mdiArea->subWindowList().back(); QVERIFY(subWindow); QCOMPARE(mdiArea->activeSubWindow(), subWindow); #if !defined (Q_WS_MAC) && !defined (Q_OS_WINCE) QVERIFY(menuBar->cornerWidget(Qt::TopRightCorner)); QVERIFY(subWindow->maximizedButtonsWidget()); QVERIFY(subWindow->maximizedSystemMenuIconWidget()); QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget()); #endif subWindow->showNormal(); QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner)); // Check that newly added windows got right sizes. foreach (QMdiSubWindow *window, mdiArea->subWindowList()) QCOMPARE(window->size(), window->sizeHint()); subWindow->showMaximized(); #ifndef Q_WS_MAC QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget()); #endif subWindow->hide(); QVERIFY(!subWindow->maximizedButtonsWidget()); QVERIFY(!subWindow->maximizedSystemMenuIconWidget()); QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner)); subWindow->show(); #if !defined (Q_WS_MAC) && !defined (Q_OS_WINCE) QVERIFY(subWindow->maximizedButtonsWidget()); QVERIFY(subWindow->maximizedSystemMenuIconWidget()); QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget()); #endif // Hide QMainWindow. mainWindow.hide(); QVERIFY(!subWindow->maximizedButtonsWidget()); QVERIFY(!subWindow->maximizedSystemMenuIconWidget()); QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner)); // Show QMainWindow. mainWindow.show(); #if !defined (Q_WS_MAC) && !defined (Q_OS_WINCE) QVERIFY(subWindow->maximizedButtonsWidget()); QVERIFY(subWindow->maximizedSystemMenuIconWidget()); QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget()); #endif } void tst_QMdiSubWindow::keepWindowMaximizedState() { QMdiArea mdiArea; QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QTextEdit); mdiArea.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&mdiArea); #endif subWindow->showMaximized(); QVERIFY(subWindow->isMaximized()); // move const QPoint newPosition = subWindow->pos() + QPoint(10, 10); subWindow->move(newPosition); QCOMPARE(subWindow->pos(), newPosition); QVERIFY(subWindow->isMaximized()); // resize const QSize newSize = subWindow->size() - QSize(10, 10); subWindow->resize(newSize); QCOMPARE(subWindow->size(), newSize); QVERIFY(subWindow->isMaximized()); // setGeometry const QRect newGeometry = QRect(newPosition - QPoint(10, 10), newSize + QSize(10, 10)); subWindow->setGeometry(newGeometry); QCOMPARE(subWindow->geometry(), newGeometry); QVERIFY(subWindow->isMaximized()); subWindow->showNormal(); // Verify that we don't force Qt::WindowMaximized. QVERIFY(!subWindow->isMaximized()); subWindow->setGeometry(QRect(newPosition, newSize)); QCOMPARE(subWindow->geometry(), QRect(newPosition, newSize)); QVERIFY(!subWindow->isMaximized()); } void tst_QMdiSubWindow::explicitlyHiddenWidget() { QMdiArea mdiArea; QTextEdit *textEdit = new QTextEdit; textEdit->hide(); QMdiSubWindow *subWindow = mdiArea.addSubWindow(textEdit); mdiArea.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&mdiArea); #endif QVERIFY(subWindow->isVisible()); QVERIFY(!textEdit->isVisible()); textEdit->show(); QVERIFY(textEdit->isVisible()); // normal -> minimized subWindow->showMinimized(); QVERIFY(subWindow->isVisible()); QVERIFY(!textEdit->isVisible()); // minimized -> normal subWindow->showNormal(); QVERIFY(subWindow->isVisible()); QVERIFY(textEdit->isVisible()); // minimized -> maximized subWindow->showMinimized(); subWindow->showMaximized(); QVERIFY(subWindow->isVisible()); QVERIFY(textEdit->isVisible()); textEdit->hide(); // maximized -> normal subWindow->showNormal(); QVERIFY(subWindow->isVisible()); QVERIFY(!textEdit->isVisible()); textEdit->show(); subWindow->showMinimized(); subWindow->setWidget(0); delete textEdit; textEdit = new QTextEdit; textEdit->hide(); subWindow->setWidget(textEdit); subWindow->showNormal(); QVERIFY(subWindow->isVisible()); QVERIFY(!textEdit->isVisible()); } void tst_QMdiSubWindow::resizeTimer() { QMdiArea mdiArea; QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QWidget); mdiArea.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&mdiArea); #endif EventSpy timerEventSpy(subWindow, QEvent::Timer); QCOMPARE(timerEventSpy.count(), 0); for (int i = 0; i < 20; ++i) { subWindow->resize(subWindow->size() + QSize(2, 2)); qApp->processEvents(); } QTest::qWait(500); // Wait for timer events to occur. QVERIFY(timerEventSpy.count() > 0); } void tst_QMdiSubWindow::fixedMinMaxSize() { QMdiArea mdiArea; mdiArea.setGeometry(0, 0, 640, 480); mdiArea.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&mdiArea); #endif const QSize minimumSize = QSize(250, 150); const QSize maximumSize = QSize(300, 200); // Add the sub window to QMdiArea and set min/max size. QMdiSubWindow *subWindow = new QMdiSubWindow; subWindow->setMinimumSize(minimumSize); QCOMPARE(subWindow->minimumSize(), minimumSize); subWindow->setMaximumSize(maximumSize); QCOMPARE(subWindow->maximumSize(), maximumSize); mdiArea.addSubWindow(subWindow); subWindow->show(); QCOMPARE(subWindow->size(), minimumSize); // Calculate the size of a minimized sub window. QStyleOptionTitleBar options; options.initFrom(subWindow); int minimizedHeight = subWindow->style()->pixelMetric(QStyle::PM_TitleBarHeight, &options); #if defined(Q_WS_MAC) && !defined(QT_NO_STYLE_MAC) // ### Remove this after mac style has been fixed if (qobject_cast(subWindow->style())) minimizedHeight -= 4; #endif if (!subWindow->style()->styleHint(QStyle::SH_TitleBar_NoBorder, &options, subWindow)) minimizedHeight += 8; int minimizedWidth = subWindow->style()->pixelMetric(QStyle::PM_MDIMinimizedWidth, &options); const QSize minimizedSize = QSize(minimizedWidth, minimizedHeight); // Even though the sub window has a minimum size set, it should be possible // to minimize the window. subWindow->showMinimized(); QVERIFY(subWindow->isMinimized()); QCOMPARE(subWindow->size(), minimizedSize); QCOMPARE(subWindow->minimumSize(), minimizedSize); // Restore minimum size. subWindow->showNormal(); QVERIFY(!subWindow->isMinimized()); QCOMPARE(subWindow->size(), minimumSize); QCOMPARE(subWindow->minimumSize(), minimumSize); // Well, the logic here is of course broken (calling showMaximized on a window with // maximum size set), but we should handle it :) subWindow->showMaximized(); QVERIFY(subWindow->isMaximized()); QCOMPARE(subWindow->size(), maximumSize); subWindow->showNormal(); QVERIFY(!subWindow->isMaximized()); QCOMPARE(subWindow->size(), minimumSize); } #if !defined( Q_WS_MAC) && !defined( Q_OS_WINCE) void tst_QMdiSubWindow::replaceMenuBarWhileMaximized() { QMainWindow mainWindow; QMdiArea *mdiArea = new QMdiArea; QMdiSubWindow *subWindow = mdiArea->addSubWindow(new QTextEdit); subWindow->showMaximized(); mainWindow.setCentralWidget(mdiArea); QMenuBar *menuBar = mainWindow.menuBar(); mainWindow.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&mainWindow); #endif qApp->processEvents(); QVERIFY(subWindow->maximizedButtonsWidget()); QVERIFY(subWindow->maximizedSystemMenuIconWidget()); QCOMPARE(menuBar->cornerWidget(Qt::TopLeftCorner), subWindow->maximizedSystemMenuIconWidget()); QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget()); // Replace. mainWindow.setMenuBar(new QMenuBar); menuBar = mainWindow.menuBar(); qApp->processEvents(); QVERIFY(subWindow->maximizedButtonsWidget()); QVERIFY(subWindow->maximizedSystemMenuIconWidget()); QCOMPARE(menuBar->cornerWidget(Qt::TopLeftCorner), subWindow->maximizedSystemMenuIconWidget()); QCOMPARE(menuBar->cornerWidget(Qt::TopRightCorner), subWindow->maximizedButtonsWidget()); subWindow->showNormal(); QVERIFY(!subWindow->maximizedButtonsWidget()); QVERIFY(!subWindow->maximizedSystemMenuIconWidget()); QVERIFY(!menuBar->cornerWidget(Qt::TopLeftCorner)); QVERIFY(!menuBar->cornerWidget(Qt::TopRightCorner)); // Delete and replace. subWindow->showMaximized(); delete menuBar; mainWindow.setMenuBar(new QMenuBar); qApp->processEvents(); QVERIFY(!subWindow->maximizedButtonsWidget()); QVERIFY(!subWindow->maximizedSystemMenuIconWidget()); subWindow->showNormal(); QVERIFY(!subWindow->maximizedButtonsWidget()); QVERIFY(!subWindow->maximizedSystemMenuIconWidget()); // Delete. subWindow->showMaximized(); mainWindow.setMenuBar(0); qApp->processEvents(); QVERIFY(!mainWindow.menuWidget()); QVERIFY(!subWindow->maximizedButtonsWidget()); QVERIFY(!subWindow->maximizedSystemMenuIconWidget()); subWindow->showNormal(); QVERIFY(!subWindow->maximizedButtonsWidget()); QVERIFY(!subWindow->maximizedSystemMenuIconWidget()); } void tst_QMdiSubWindow::closeOnDoubleClick() { QMdiArea mdiArea; QPointer subWindow = mdiArea.addSubWindow(new QWidget); mdiArea.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&mdiArea); #endif subWindow->showSystemMenu(); QTest::qWait(200); QPointer systemMenu = subWindow->systemMenu(); QVERIFY(systemMenu); QVERIFY(systemMenu->isVisible()); sendMouseDoubleClick(systemMenu, QPoint(10, 10)); if (qApp->activePopupWidget() == static_cast(systemMenu)) systemMenu->hide(); qApp->processEvents(); QVERIFY(!subWindow || !subWindow->isVisible()); QVERIFY(!systemMenu || !systemMenu->isVisible()); } #endif void tst_QMdiSubWindow::setFont() { QMdiArea mdiArea; QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QPushButton(QLatin1String("test"))); subWindow->resize(300, 100); subWindow->setWindowTitle(QLatin1String("Window title")); mdiArea.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&mdiArea); #endif const QFont originalFont = QApplication::font("QWorkspaceTitleBar"); QStyleOptionTitleBar opt; opt.initFrom(subWindow); const int titleBarHeight = subWindow->style()->pixelMetric(QStyle::PM_TitleBarHeight, &opt); const QRect titleBarRect = QRect(0, 0, subWindow->width(), titleBarHeight); const QImage originalTitleBar = QPixmap::grabWidget(subWindow, titleBarRect).toImage(); QFont newFont(QLatin1String("Helvetica"), 16); newFont.setBold(true); subWindow->setFont(newFont); qApp->processEvents(); QCOMPARE(subWindow->font(), newFont); QImage newTitleBar = QPixmap::grabWidget(subWindow, titleBarRect).toImage(); QVERIFY(newTitleBar != originalTitleBar); subWindow->setFont(originalFont); qApp->processEvents(); QCOMPARE(subWindow->font(), originalFont); newTitleBar = QPixmap::grabWidget(subWindow, titleBarRect).toImage(); QCOMPARE(newTitleBar, originalTitleBar); } void tst_QMdiSubWindow::task_188849() { QMainWindow mainWindow; // Sets a regular QWidget (and NOT a QMenuBar) as the menu bar. mainWindow.setMenuWidget(new QWidget); QMdiArea *mdiArea = new QMdiArea; QMdiSubWindow *subWindow = mdiArea->addSubWindow(new QWidget); mainWindow.setCentralWidget(mdiArea); mainWindow.show(); #if defined(Q_WS_X11) qt_x11_wait_for_window_manager(&mainWindow); #endif // QMdiSubWindow will now try to show its buttons in the menu bar. // Without checking that the menu bar is actually a QMenuBar // and not a regular QWidget, this will crash. subWindow->showMaximized(); } void tst_QMdiSubWindow::mdiArea() { QMdiArea mdiArea; QMdiSubWindow *subWindow = mdiArea.addSubWindow(new QWidget); QCOMPARE(subWindow->mdiArea(), &mdiArea); subWindow->setParent(0); QVERIFY(!subWindow->mdiArea()); // Child of the area's corner widget. mdiArea.setCornerWidget(new QWidget); subWindow->setParent(mdiArea.cornerWidget()); QVERIFY(!subWindow->mdiArea()); // Nested mdi area. QMdiArea *nestedArea = new QMdiArea; mdiArea.addSubWindow(nestedArea); nestedArea->addSubWindow(subWindow); QCOMPARE(subWindow->mdiArea(), nestedArea); nestedArea->setViewport(new QWidget); QCOMPARE(subWindow->mdiArea(), nestedArea); } void tst_QMdiSubWindow::task_182852() { #if !defined(Q_WS_MAC) && !defined(Q_OS_WINCE) QMdiArea *workspace = new QMdiArea; QMainWindow mainWindow; mainWindow.setCentralWidget(workspace); mainWindow.show(); mainWindow.menuBar()->setVisible(true); qApp->setActiveWindow(&mainWindow); QString originalWindowTitle = QString::fromLatin1("MainWindow - [foo]"); mainWindow.setWindowTitle(originalWindowTitle); QMdiSubWindow *window = new QMdiSubWindow; QMdiArea *nestedWorkspace = new QMdiArea; // :-) window->setWidget(nestedWorkspace); window->widget()->setWindowTitle(QString::fromLatin1("Window")); workspace->addSubWindow(window); window->showMaximized(); qApp->processEvents(); QVERIFY(window->isMaximized()); QCOMPARE(mainWindow.windowTitle(), QString::fromLatin1("%1 - [%2]") .arg(originalWindowTitle, window->widget()->windowTitle())); window->showNormal(); QCOMPARE(mainWindow.windowTitle(), originalWindowTitle); window->widget()->setWindowTitle(QString::fromLatin1("foo")); window->showMaximized(); QCOMPARE(mainWindow.windowTitle(), originalWindowTitle); window->showNormal(); QCOMPARE(mainWindow.windowTitle(), originalWindowTitle); window->widget()->setWindowTitle(QString::fromLatin1("bar")); window->showMaximized(); QCOMPARE(mainWindow.windowTitle(), QString::fromLatin1("%1 - [%2]") .arg(originalWindowTitle, window->widget()->windowTitle())); #endif } void tst_QMdiSubWindow::task_233197() { QMainWindow *mainWindow = new QMainWindow; mainWindow->setAttribute(Qt::WA_DeleteOnClose); mainWindow->resize(500, 200); mainWindow->show(); QMdiArea *mdiArea = new QMdiArea(mainWindow); mdiArea->setOption(QMdiArea::DontMaximizeSubWindowOnActivation, true); mainWindow->setCentralWidget(mdiArea); QMdiSubWindow *subWindow1 = new QMdiSubWindow(); mdiArea->addSubWindow(subWindow1); subWindow1->showMaximized(); QMdiSubWindow *subWindow2 = new QMdiSubWindow(); mdiArea->addSubWindow(subWindow2); subWindow2->showMaximized(); QMdiSubWindow *subWindow3 = new QMdiSubWindow(); mdiArea->addSubWindow(subWindow3); subWindow3->showMaximized(); QMenuBar *menuBar = mainWindow->menuBar(); // force creation of a menubar Q_UNUSED(menuBar); QPushButton *focus1 = new QPushButton(QLatin1String("Focus 1"), mainWindow); QObject::connect(focus1, SIGNAL(clicked()), subWindow1, SLOT(setFocus())); focus1->move(5, 30); focus1->show(); QPushButton *focus2 = new QPushButton(QLatin1String("Focus 2"), mainWindow); QObject::connect(focus2, SIGNAL(clicked()), subWindow2, SLOT(setFocus())); focus2->move(5, 60); focus2->show(); QPushButton *close = new QPushButton(QLatin1String("Close"), mainWindow); QObject::connect(close, SIGNAL(clicked()), mainWindow, SLOT(close())); close->move(5, 90); close->show(); QTest::qWait(200); sendMousePress(focus2, QPoint()); sendMouseRelease(focus2, QPoint()); sendMousePress(focus1, QPoint()); sendMouseRelease(focus1, QPoint()); sendMousePress(focus2, QPoint()); sendMouseRelease(focus2, QPoint()); sendMousePress(close, QPoint()); sendMouseRelease(close, QPoint()); QTest::qWait(200); } void tst_QMdiSubWindow::task_226929() { QMdiArea mdiArea; mdiArea.show(); #ifdef Q_WS_X11 qt_x11_wait_for_window_manager(&mdiArea); #endif QMdiSubWindow *sub1 = mdiArea.addSubWindow(new QTextEdit); sub1->showMinimized(); QMdiSubWindow *sub2 = mdiArea.addSubWindow(new QTextEdit); sub2->showMaximized(); QTest::qWait(100); // Do not assert. // This window will now be activated and automatically maximized // (if not QMdiArea::DontMaximizeSubWindowOnActionvation is set). sub1->showNormal(); QVERIFY(sub1->isMaximized()); } QTEST_MAIN(tst_QMdiSubWindow) #include "tst_qmdisubwindow.moc"