QGraphicsProxyWidget: forward Window(De)Activate events

The nested widget might be a QGraphicsView as well (documented to be
supported), and QGraphicsScene maintains it's own activation status by
counting Window(De)Activate events. We need to make sure that the
embedded widget is informed about its activation status so that deeper
nested children can receive focus.

Forward WindowActivate/Deactivate events to the nested widget, which
will pass it on to all its children. Add test case, which without this
fix fails when verifying the inner scene's isActive state, or later
when testing that focusInEvent is delivered to the embedded widget.

Fixes: QTBUG-94091
Pick-to: 5.15 6.1 6.2
Change-Id: I4e0ecef50685ed081d15c7f76b6c1a4a40ed2682
Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io>
This commit is contained in:
Volker Hilsheimer 2021-08-20 10:41:06 +02:00
parent d48058f197
commit 01aeb5f7e4
2 changed files with 59 additions and 0 deletions

View File

@ -832,6 +832,10 @@ bool QGraphicsProxyWidget::event(QEvent *event)
return QGraphicsWidget::event(event);
switch (event->type()) {
case QEvent::WindowActivate:
case QEvent::WindowDeactivate:
QCoreApplication::sendEvent(d->widget, event);
break;
case QEvent::StyleChange:
// Propagate style changes to the embedded widget.
if (!d->styleChangeMode) {

View File

@ -227,6 +227,7 @@ private slots:
void replayMouseMove();
void itemsUnderMouse();
void embeddedViews();
void embeddedViewsWithFocus();
void scrollAfterResize_data();
void scrollAfterResize();
void moveItemWhileScrolling_data();
@ -3668,6 +3669,60 @@ void tst_QGraphicsView::embeddedViews()
delete v1;
}
/*!
Verify that a nested graphics view and embedded widgets receive window
activation and focus correctly.
See QTBUG-94091.
*/
void tst_QGraphicsView::embeddedViewsWithFocus()
{
class FocusWidget : public QWidget
{
public:
FocusWidget() { setFocusPolicy(Qt::StrongFocus); }
QSize sizeHint() const override { return QSize(100, 100); }
int focusCount = 0;
protected:
void mousePressEvent(QMouseEvent *) override {} // accept event to avoid warning
void focusInEvent(QFocusEvent *) override { ++focusCount; }
void focusOutEvent(QFocusEvent *) override { --focusCount; }
};
QGraphicsScene *innerScene = new QGraphicsScene;
FocusWidget *innerWidget = new FocusWidget;
innerScene->addWidget(innerWidget);
QGraphicsView *innerView = new QGraphicsView(innerScene);
QGraphicsScene outerScene;
FocusWidget *outerWidget = new FocusWidget;
QGraphicsProxyWidget *outerProxy = outerScene.addWidget(outerWidget);
QGraphicsProxyWidget *nestedProxy = outerScene.addWidget(innerView);
outerProxy->setPos(0, 0);
nestedProxy->setPos(0, outerWidget->sizeHint().height());
QGraphicsView outerView(&outerScene);
outerView.show();
outerView.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&outerView));
const QPoint outerCenter(QPoint(innerWidget->sizeHint().width() / 2,
innerWidget->sizeHint().height() / 2));
const QPoint innerCenter(outerCenter + QPoint(0, innerWidget->sizeHint().height()));
QCOMPARE(outerView.itemAt(outerCenter), outerProxy);
QCOMPARE(outerView.itemAt(innerCenter), nestedProxy);
QVERIFY(outerScene.isActive());
QVERIFY(innerScene->isActive());
QCOMPARE(outerWidget->focusCount, 0);
QCOMPARE(innerWidget->focusCount, 0);
QTest::mouseClick(outerView.viewport(), Qt::LeftButton, {}, outerCenter);
QCOMPARE(outerWidget->focusCount, 1);
QCOMPARE(innerWidget->focusCount, 0);
QTest::mouseClick(outerView.viewport(), Qt::LeftButton, {}, innerCenter);
QCOMPARE(outerWidget->focusCount, 0);
QCOMPARE(innerWidget->focusCount, 1);
}
void tst_QGraphicsView::scrollAfterResize_data()
{
QTest::addColumn<bool>("reverse");