summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Arve Saether <jan-arve.saether@digia.com>2013-02-19 15:02:24 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-02-19 21:07:14 +0100
commit18f9eb797bffe8626f1edeca3c88f80dae0da8d7 (patch)
tree96e887b3661060e061b64990d834dc5a292832a1
parent64106705e7ca6132b1de15529c6206ebb0c58dfa (diff)
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>
-rw-r--r--src/widgets/kernel/qstackedlayout.cpp27
-rw-r--r--tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp88
2 files changed, 103 insertions, 12 deletions
diff --git a/src/widgets/kernel/qstackedlayout.cpp b/src/widgets/kernel/qstackedlayout.cpp
index cb2711c636..f38f0a6f08 100644
--- a/src/widgets/kernel/qstackedlayout.cpp
+++ b/src/widgets/kernel/qstackedlayout.cpp
@@ -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();
}
}
}
diff --git a/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp b/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp
index 5c9f46095c..c17db4c7f3 100644
--- a/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp
+++ b/tests/auto/widgets/widgets/qstackedwidget/tst_qstackedwidget.cpp
@@ -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"