QGraphicsProxyWidget: fix handling of proxy focus

If a widget inside a QGPW has a proxy focus, the code would keep
sending focus in events to the proxy even if the proxy was already
focused. Amend the check in place to prevent this from happening.

Change-Id: Id28d3bfe4f396da5c9477df713441ca7d506662f
Fixes: QTBUG-51856
Reviewed-by: Christian Ehrlicher <ch.ehrlicher@gmx.de>
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
Giuseppe D'Angelo 2020-01-25 00:48:48 +01:00
parent 382619de65
commit 78edc18057
2 changed files with 71 additions and 1 deletions

View File

@ -6309,7 +6309,7 @@ void QWidget::setFocus(Qt::FocusReason reason)
previousProxyFocus = topData->proxyWidget->widget()->focusWidget();
if (previousProxyFocus && previousProxyFocus->focusProxy())
previousProxyFocus = previousProxyFocus->focusProxy();
if (previousProxyFocus == this && !topData->proxyWidget->d_func()->proxyIsGivingFocus)
if (previousProxyFocus == f && !topData->proxyWidget->d_func()->proxyIsGivingFocus)
return;
}
}

View File

@ -89,6 +89,7 @@ private slots:
void focusNextPrevChild();
void focusOutEvent_data();
void focusOutEvent();
void focusProxy_QTBUG_51856();
void hoverEnterLeaveEvent_data();
void hoverEnterLeaveEvent();
void hoverMoveEvent_data();
@ -864,6 +865,75 @@ void tst_QGraphicsProxyWidget::focusOutEvent()
}
}
void tst_QGraphicsProxyWidget::focusProxy_QTBUG_51856()
{
// QSpinBox has an internal QLineEdit; this QLineEdit has the spinbox
// as its focus proxy.
struct FocusedSpinBox : QSpinBox
{
int focusCount = 0;
bool event(QEvent *event) override
{
switch (event->type()) {
case QEvent::FocusIn:
++focusCount;
break;
case QEvent::FocusOut:
--focusCount;
break;
default:
break;
}
return QSpinBox::event(event);
}
};
QGraphicsScene scene;
QGraphicsView view(&scene);
SubQGraphicsProxyWidget *proxy = new SubQGraphicsProxyWidget;
scene.addItem(proxy);
view.show();
view.raise();
view.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&view));
FocusedSpinBox *spinBox = new FocusedSpinBox;
proxy->setWidget(spinBox);
proxy->show();
proxy->setFocus();
QVERIFY(proxy->hasFocus());
QEXPECT_FAIL("", "Widget should have focus but doesn't", Continue);
QVERIFY(spinBox->hasFocus());
QEXPECT_FAIL("", "Widget should have focus but doesn't", Continue);
QCOMPARE(spinBox->focusCount, 1);
enum { Count = 10 };
for (int i = 0; i < Count; ++i) {
for (int clickCount = 0; clickCount < Count; ++clickCount) {
auto proxyCenter = proxy->boundingRect().center();
auto proxyCenterInScene = proxy->mapToScene(proxyCenter);
auto proxyCenterInView = view.mapFromScene(proxyCenterInScene);
QTest::mouseClick(view.viewport(), Qt::LeftButton, {}, proxyCenterInView);
QTRY_COMPARE(spinBox->focusCount, 1);
}
QLineEdit *edit = new QLineEdit(&view);
edit->show();
QTRY_VERIFY(edit->isVisible());
edit->setFocus();
QTRY_VERIFY(edit->hasFocus());
QTRY_VERIFY(!proxy->hasFocus());
QTRY_COMPARE(proxy->focusOut, i + 1);
QTRY_VERIFY(!spinBox->hasFocus());
QTRY_COMPARE(spinBox->focusCount, 0);
delete edit;
}
}
class EventLogger : public QWidget
{
public: