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

View File

@ -266,7 +266,8 @@ public:
QPalette desktopPalette() const;
void updateActions();
void setFocusWidget();
void restoreFocus();
bool restoreFocus();
void storeFocusWidget();
void setWindowFlags(Qt::WindowFlags windowFlags);
void setVisible(WindowStateAction, bool visible = true);
#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
**
** This file is part of the test suite of the Qt Toolkit.
@ -58,6 +58,7 @@
#include <QStyle>
#include <QStyleOptionTitleBar>
#include <QPushButton>
#include <QScreen>
#include <QSizeGrip>
#include "../../../qtest-config.h"
@ -182,6 +183,7 @@ private slots:
void mouseDoubleClick();
void setSystemMenu();
void restoreFocus();
void restoreFocusOverCreation();
void changeFocusWithTab();
void closeEvent();
void setWindowTitle();
@ -1126,6 +1128,7 @@ void tst_QMdiSubWindow::restoreFocus()
expectedFocusWindow->showMinimized();
qApp->processEvents();
QVERIFY(expectedFocusWindow->isMinimized());
qDebug() << expectedFocusWindow<< qApp->focusWidget();
QCOMPARE(qApp->focusWidget(), static_cast<QWidget *>(expectedFocusWindow));
// Minimized -> normal
@ -1178,6 +1181,48 @@ void tst_QMdiSubWindow::restoreFocus()
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()
{
QWidget *widget = new QWidget;