QMdiArea: Store focus widget when new QMdiSubWindow is added.

Introduce function QMdiSubWindowPrivate::storeFocusWidget()
to store focus widget and call this when de-activating a
sub window. Change restoreFocus() to return a bool and call
it from QMdiSubWindowPrivate::setActive().

Task-number: QTBUG-38378
Change-Id: I18dbe66ce85213ca5b4907b5a09126544415351a
Reviewed-by: Marc Mutz <marc.mutz@kdab.com>
This commit is contained in:
Friedemann Kleint 2014-06-18 14:53:53 +02:00
parent cd89ec830d
commit 0240110c58
3 changed files with 75 additions and 17 deletions

View File

@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal ** Contact: http://www.qt-project.org/legal
** **
** This file is part of the QtWidgets module of the Qt Toolkit. ** This file is part of the QtWidgets module of the Qt Toolkit.
@ -1321,6 +1321,14 @@ void QMdiSubWindowPrivate::setNormalMode()
updateMask(); updateMask();
} }
inline void QMdiSubWindowPrivate::storeFocusWidget()
{
if (QWidget *focus = QApplication::focusWidget()) {
if (!restoreFocusWidget && q_func()->isAncestorOf(focus))
restoreFocusWidget = focus;
}
}
/*! /*!
\internal \internal
*/ */
@ -1333,8 +1341,7 @@ void QMdiSubWindowPrivate::setMaximizeMode()
isShadeMode = false; isShadeMode = false;
isMaximizeMode = true; isMaximizeMode = true;
if (!restoreFocusWidget && q->isAncestorOf(QApplication::focusWidget())) storeFocusWidget();
restoreFocusWidget = QApplication::focusWidget();
#ifndef QT_NO_SIZEGRIP #ifndef QT_NO_SIZEGRIP
setSizeGripVisible(false); setSizeGripVisible(false);
@ -1436,6 +1443,7 @@ void QMdiSubWindowPrivate::setActive(bool activate, bool changeFocus)
Qt::WindowStates oldWindowState = q->windowState(); Qt::WindowStates oldWindowState = q->windowState();
q->overrideWindowState(q->windowState() & ~Qt::WindowActive); q->overrideWindowState(q->windowState() & ~Qt::WindowActive);
if (changeFocus) { if (changeFocus) {
storeFocusWidget();
QWidget *focusWidget = QApplication::focusWidget(); QWidget *focusWidget = QApplication::focusWidget();
if (focusWidget && (focusWidget == q || q->isAncestorOf(focusWidget))) if (focusWidget && (focusWidget == q || q->isAncestorOf(focusWidget)))
focusWidget->clearFocus(); focusWidget->clearFocus();
@ -2026,6 +2034,9 @@ void QMdiSubWindowPrivate::setFocusWidget()
return; return;
} }
if (!(q->windowState() & Qt::WindowMinimized) && restoreFocus())
return;
if (QWidget *focusWidget = baseWidget->focusWidget()) { if (QWidget *focusWidget = baseWidget->focusWidget()) {
if (!focusWidget->hasFocus() && q->isAncestorOf(focusWidget) if (!focusWidget->hasFocus() && q->isAncestorOf(focusWidget)
&& focusWidget->isVisible() && !q->isMinimized() && focusWidget->isVisible() && !q->isMinimized()
@ -2048,16 +2059,19 @@ void QMdiSubWindowPrivate::setFocusWidget()
q->setFocus(); q->setFocus();
} }
void QMdiSubWindowPrivate::restoreFocus() bool QMdiSubWindowPrivate::restoreFocus()
{ {
if (!restoreFocusWidget) if (restoreFocusWidget.isNull())
return; return false;
if (!restoreFocusWidget->hasFocus() && q_func()->isAncestorOf(restoreFocusWidget) QWidget *candidate = restoreFocusWidget;
&& restoreFocusWidget->isVisible() restoreFocusWidget.clear();
&& restoreFocusWidget->focusPolicy() != Qt::NoFocus) { if (!candidate->hasFocus() && q_func()->isAncestorOf(candidate)
restoreFocusWidget->setFocus(); && candidate->isVisible()
&& candidate->focusPolicy() != Qt::NoFocus) {
candidate->setFocus();
return true;
} }
restoreFocusWidget = 0; return candidate->hasFocus();
} }
/*! /*!
@ -2605,9 +2619,7 @@ void QMdiSubWindow::showShaded()
d->isMaximizeMode = false; d->isMaximizeMode = false;
QWidget *currentFocusWidget = QApplication::focusWidget(); d->storeFocusWidget();
if (!d->restoreFocusWidget && isAncestorOf(currentFocusWidget))
d->restoreFocusWidget = currentFocusWidget;
if (!d->isShadeRequestFromMinimizeMode) { if (!d->isShadeRequestFromMinimizeMode) {
d->isShadeMode = true; d->isShadeMode = true;
@ -2621,7 +2633,7 @@ void QMdiSubWindow::showShaded()
// showMinimized() will reset Qt::WindowActive, which makes sense // showMinimized() will reset Qt::WindowActive, which makes sense
// for top level widgets, but in MDI it makes sense to have an // for top level widgets, but in MDI it makes sense to have an
// active window which is minimized. // active window which is minimized.
if (hasFocus() || isAncestorOf(currentFocusWidget)) if (hasFocus() || isAncestorOf(QApplication::focusWidget()))
d->ensureWindowState(Qt::WindowActive); d->ensureWindowState(Qt::WindowActive);
#ifndef QT_NO_SIZEGRIP #ifndef QT_NO_SIZEGRIP

View File

@ -266,7 +266,8 @@ public:
QPalette desktopPalette() const; QPalette desktopPalette() const;
void updateActions(); void updateActions();
void setFocusWidget(); void setFocusWidget();
void restoreFocus(); bool restoreFocus();
void storeFocusWidget();
void setWindowFlags(Qt::WindowFlags windowFlags); void setWindowFlags(Qt::WindowFlags windowFlags);
void setVisible(WindowStateAction, bool visible = true); void setVisible(WindowStateAction, bool visible = true);
#ifndef QT_NO_ACTION #ifndef QT_NO_ACTION

View File

@ -1,6 +1,6 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal ** Contact: http://www.qt-project.org/legal
** **
** This file is part of the test suite of the Qt Toolkit. ** This file is part of the test suite of the Qt Toolkit.
@ -58,6 +58,7 @@
#include <QStyle> #include <QStyle>
#include <QStyleOptionTitleBar> #include <QStyleOptionTitleBar>
#include <QPushButton> #include <QPushButton>
#include <QScreen>
#include <QSizeGrip> #include <QSizeGrip>
#include "../../../qtest-config.h" #include "../../../qtest-config.h"
@ -182,6 +183,7 @@ private slots:
void mouseDoubleClick(); void mouseDoubleClick();
void setSystemMenu(); void setSystemMenu();
void restoreFocus(); void restoreFocus();
void restoreFocusOverCreation();
void changeFocusWithTab(); void changeFocusWithTab();
void closeEvent(); void closeEvent();
void setWindowTitle(); void setWindowTitle();
@ -1126,6 +1128,7 @@ void tst_QMdiSubWindow::restoreFocus()
expectedFocusWindow->showMinimized(); expectedFocusWindow->showMinimized();
qApp->processEvents(); qApp->processEvents();
QVERIFY(expectedFocusWindow->isMinimized()); QVERIFY(expectedFocusWindow->isMinimized());
qDebug() << expectedFocusWindow<< qApp->focusWidget();
QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(expectedFocusWindow)); QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(expectedFocusWindow));
// Minimized -> normal // Minimized -> normal
@ -1178,6 +1181,48 @@ void tst_QMdiSubWindow::restoreFocus()
QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(expectedFocusWindow)); QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(expectedFocusWindow));
} }
class MultiWidget : public QWidget {
public:
explicit MultiWidget(QWidget *parent = 0) : QWidget(parent)
, m_lineEdit1(new QLineEdit(this)), m_lineEdit2(new QLineEdit(this))
{
QVBoxLayout *lt = new QVBoxLayout(this);
lt->addWidget(m_lineEdit1);
lt->addWidget(m_lineEdit2);
}
QLineEdit *m_lineEdit1;
QLineEdit *m_lineEdit2;
};
void tst_QMdiSubWindow::restoreFocusOverCreation()
{
// QTBUG-38378, verify that the focus child of a subwindow
// is not "forgotten" when adding yet another subwindow.
QMdiArea mdiArea;
mdiArea.resize(800, 800);
mdiArea.move(QGuiApplication::primaryScreen()->availableGeometry().center() - QPoint(400, 400));
mdiArea.setWindowTitle(QStringLiteral("restoreFocusOverCreation"));
MultiWidget *subWidget1 = new MultiWidget;
MultiWidget *subWidget2 = new MultiWidget;
QMdiSubWindow *subWindow1 = mdiArea.addSubWindow(subWidget1);
subWidget1->m_lineEdit2->setFocus();
subWindow1->show();
mdiArea.show();
QApplication::setActiveWindow(&mdiArea);
QVERIFY(QTest::qWaitForWindowActive(&mdiArea));
QCOMPARE(QApplication::focusWidget(), subWidget1->m_lineEdit2);
QMdiSubWindow *subWindow2 = mdiArea.addSubWindow(subWidget2);
subWindow2->show();
QTRY_COMPARE(QApplication::focusWidget(), subWidget2->m_lineEdit1);
mdiArea.setActiveSubWindow(subWindow1);
QTRY_COMPARE(QApplication::focusWidget(), subWidget1->m_lineEdit2);
}
void tst_QMdiSubWindow::changeFocusWithTab() void tst_QMdiSubWindow::changeFocusWithTab()
{ {
QWidget *widget = new QWidget; QWidget *widget = new QWidget;