QStackedLayout: Fix crash when focus widget is destroyed in hide()
We also have to make sure that when moving back to a page that has a focusWidget(), the focus should go to the focusWidget() Task-number: QTBUG-18242 Change-Id: Ibfa7d6361c1a456480b2f1584a88ef4c4f405709 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>bb10
parent
64106705e7
commit
18f9eb797b
|
|
@ -300,7 +300,9 @@ void QStackedLayout::setCurrentIndex(int index)
|
|||
parent->setUpdatesEnabled(false);
|
||||
}
|
||||
|
||||
QWidget *fw = parent ? parent->window()->focusWidget() : 0;
|
||||
QPointer<QWidget> fw = parent ? parent->window()->focusWidget() : 0;
|
||||
const bool focusWasOnOldPage = fw && (prev && prev->isAncestorOf(fw));
|
||||
|
||||
if (prev) {
|
||||
prev->clearFocus();
|
||||
if (d->stackingMode == StackOne)
|
||||
|
|
@ -315,24 +317,25 @@ void QStackedLayout::setCurrentIndex(int index)
|
|||
// was somewhere on the outgoing widget.
|
||||
|
||||
if (parent) {
|
||||
if (fw && (prev && prev->isAncestorOf(fw))) { // focus was on old page
|
||||
if (focusWasOnOldPage) {
|
||||
// look for the best focus widget we can find
|
||||
if (QWidget *nfw = next->focusWidget())
|
||||
nfw->setFocus();
|
||||
else {
|
||||
// second best: first child widget in the focus chain
|
||||
QWidget *i = fw;
|
||||
while ((i = i->nextInFocusChain()) != fw) {
|
||||
if (((i->focusPolicy() & Qt::TabFocus) == Qt::TabFocus)
|
||||
&& !i->focusProxy() && i->isVisibleTo(next) && i->isEnabled()
|
||||
&& next->isAncestorOf(i)) {
|
||||
i->setFocus();
|
||||
break;
|
||||
if (QWidget *i = fw) {
|
||||
while ((i = i->nextInFocusChain()) != fw) {
|
||||
if (((i->focusPolicy() & Qt::TabFocus) == Qt::TabFocus)
|
||||
&& !i->focusProxy() && i->isVisibleTo(next) && i->isEnabled()
|
||||
&& next->isAncestorOf(i)) {
|
||||
i->setFocus();
|
||||
break;
|
||||
}
|
||||
}
|
||||
// third best: incoming widget
|
||||
if (i == fw )
|
||||
next->setFocus();
|
||||
}
|
||||
// third best: incoming widget
|
||||
if (i == fw )
|
||||
next->setFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
#include <qstackedwidget.h>
|
||||
#include <qpushbutton.h>
|
||||
#include <QHBoxLayout>
|
||||
#include <qlineedit.h>
|
||||
|
||||
class tst_QStackedWidget : public QObject
|
||||
{
|
||||
|
|
@ -59,6 +60,7 @@ public:
|
|||
private slots:
|
||||
void getSetCheck();
|
||||
void testMinimumSize();
|
||||
void dynamicPages();
|
||||
};
|
||||
|
||||
tst_QStackedWidget::tst_QStackedWidget()
|
||||
|
|
@ -117,5 +119,91 @@ void tst_QStackedWidget::getSetCheck()
|
|||
delete var2;
|
||||
}
|
||||
|
||||
// QTBUG-18242, a widget that deletes its children in hideEvent().
|
||||
// This caused a crash in QStackedLayout::setCurrentIndex() since
|
||||
// the focus widget was destroyed while hiding the previous page.
|
||||
class TestPage : public QWidget
|
||||
{
|
||||
public:
|
||||
TestPage (bool staticWidgets = false) : QWidget(0), m_staticWidgets(staticWidgets)
|
||||
{
|
||||
new QVBoxLayout (this);
|
||||
}
|
||||
|
||||
~TestPage() {
|
||||
destroyWidgets();
|
||||
}
|
||||
|
||||
void setN(int n)
|
||||
{
|
||||
m_n = n;
|
||||
if (m_staticWidgets)
|
||||
createWidgets();
|
||||
}
|
||||
|
||||
virtual void showEvent (QShowEvent *)
|
||||
{
|
||||
if (!m_staticWidgets)
|
||||
createWidgets();
|
||||
}
|
||||
|
||||
virtual void hideEvent (QHideEvent *)
|
||||
{
|
||||
if (!m_staticWidgets)
|
||||
destroyWidgets();
|
||||
}
|
||||
|
||||
private:
|
||||
void createWidgets() {
|
||||
for (int i = 0; i < m_n; ++i) {
|
||||
QLineEdit *le = new QLineEdit(this);
|
||||
le->setObjectName(QString::fromLatin1("lineEdit%1").arg(i));
|
||||
layout ()->addWidget(le);
|
||||
m_les << le;
|
||||
}
|
||||
}
|
||||
|
||||
void destroyWidgets()
|
||||
{
|
||||
qDeleteAll(m_les);
|
||||
m_les.clear ();
|
||||
}
|
||||
|
||||
int m_n;
|
||||
const bool m_staticWidgets;
|
||||
QList<QLineEdit*> m_les;
|
||||
};
|
||||
|
||||
void tst_QStackedWidget::dynamicPages()
|
||||
{
|
||||
QStackedWidget *sw = new QStackedWidget;
|
||||
|
||||
TestPage *w1 = new TestPage(true);
|
||||
w1->setN(3);
|
||||
|
||||
TestPage *w2 = new TestPage;
|
||||
w2->setN(3);
|
||||
|
||||
sw->addWidget(w1);
|
||||
sw->addWidget(w2);
|
||||
|
||||
QLineEdit *le11 = w1->findChild<QLineEdit*>(QLatin1String("lineEdit1"));
|
||||
le11->setFocus(); // set focus to second widget in the page
|
||||
sw->resize(200, 200);
|
||||
sw->show();
|
||||
qApp->setActiveWindow(sw);
|
||||
QTest::qWaitForWindowActive(sw);
|
||||
QTRY_COMPARE(QApplication::focusWidget(), le11);
|
||||
|
||||
sw->setCurrentIndex(1);
|
||||
QLineEdit *le22 = w2->findChild<QLineEdit*>(QLatin1String("lineEdit2"));
|
||||
le22->setFocus();
|
||||
QTRY_COMPARE(QApplication::focusWidget(), le22);
|
||||
// Going back should move focus back to le11
|
||||
sw->setCurrentIndex(0);
|
||||
QTRY_COMPARE(QApplication::focusWidget(), le11);
|
||||
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QStackedWidget)
|
||||
#include "tst_qstackedwidget.moc"
|
||||
|
|
|
|||
Loading…
Reference in New Issue