summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAxel Spoerl <axel.spoerl@qt.io>2023-01-12 14:07:41 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2023-01-22 18:27:39 +0000
commit5baf644660cdc8a486be6180329f5ffb4960a63d (patch)
tree73617e8a9a188ada4e6339428f5b37afff67da37
parentbb6fba1834bc3c41a45a198aadd668b8fa58952c (diff)
QWidgetTextControl: Ignore unconsumed mouse release eventsv6.5.0-beta2
QWidgetTextControlPrivate::mouseReleaseEvent() has early returns implemented, e.g. when link has been right clicked or no selection anchor has been found. These early returns, however, still consume the event. This leads to events getting lost instead of getting propagated: As an example, a QLabel with rich text uses QWidgetTextControl. While it propagates mouse press events back to its parent, mouse release events get lost. A QLabel with plain text propagates both events back correctly. This patch adds QEvent::ignore() to the early return. Since no test class exists for QWidgetTextControl, it adds a test in tst_QLabel. Fixes: QTBUG-110055 Change-Id: I950f8c3f135793b01c59832835bb429db2282169 Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io> (cherry picked from commit 7689d4ad2f673317af432aae498da74d13703126) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/widgets/widgets/qwidgettextcontrol.cpp25
-rw-r--r--tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp82
2 files changed, 100 insertions, 7 deletions
diff --git a/src/widgets/widgets/qwidgettextcontrol.cpp b/src/widgets/widgets/qwidgettextcontrol.cpp
index 1b78442ed1..28d07dd6c8 100644
--- a/src/widgets/widgets/qwidgettextcontrol.cpp
+++ b/src/widgets/widgets/qwidgettextcontrol.cpp
@@ -1818,25 +1818,36 @@ void QWidgetTextControlPrivate::mouseReleaseEvent(QEvent *e, Qt::MouseButton but
}
if (interactionFlags & Qt::LinksAccessibleByMouse) {
- if (!(button & Qt::LeftButton))
+
+ // Ignore event unless left button has been pressed
+ if (!(button & Qt::LeftButton)) {
+ e->ignore();
return;
+ }
const QString anchor = q->anchorAt(pos);
- if (anchor.isEmpty())
+ // Ignore event without selection anchor
+ if (anchor.isEmpty()) {
+ e->ignore();
return;
+ }
if (!cursor.hasSelection()
|| (anchor == anchorOnMousePress && hadSelectionOnMousePress)) {
const int anchorPos = q->hitTest(pos, Qt::ExactHit);
- if (anchorPos != -1) {
- cursor.setPosition(anchorPos);
- QString anchor = anchorOnMousePress;
- anchorOnMousePress = QString();
- activateLinkUnderCursor(anchor);
+ // Ignore event without valid anchor position
+ if (anchorPos < 0) {
+ e->ignore();
+ return;
}
+
+ cursor.setPosition(anchorPos);
+ QString anchor = anchorOnMousePress;
+ anchorOnMousePress = QString();
+ activateLinkUnderCursor(anchor);
}
}
}
diff --git a/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp b/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp
index 891f22c1c9..77613341dd 100644
--- a/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp
+++ b/tests/auto/widgets/widgets/qlabel/tst_qlabel.cpp
@@ -83,6 +83,8 @@ private Q_SLOTS:
void taskQTBUG_48157_dprMovie();
void resourceProvider();
+ void mouseEventPropagation_data();
+ void mouseEventPropagation();
private:
QLabel *testWidget;
@@ -600,5 +602,85 @@ void tst_QLabel::resourceProvider()
QVERIFY(providerCalled > 0);
}
+// Test if mouse events are correctly propagated to the parent widget,
+// even if a label contains rich text (QTBUG-110055)
+void tst_QLabel::mouseEventPropagation_data()
+{
+ QTest::addColumn<const QString>("text");
+ QTest::addColumn<const Qt::TextInteractionFlag>("interaction");
+ QTest::addColumn<const bool>("expectPropagation");
+
+
+ QTest::newRow("RichText")
+ << QString("<b>This is a rich text propagating mouse events</b>")
+ << Qt::LinksAccessibleByMouse
+ << true;
+ QTest::newRow("PlainText")
+ << QString("This is a plain text propagating mouse events")
+ << Qt::LinksAccessibleByMouse
+ << true;
+ QTest::newRow("PlainTextConsume")
+ << QString("This is a plain text consuming mouse events")
+ << Qt::TextSelectableByMouse
+ << false;
+ QTest::newRow("RichTextConsume")
+ << QString("<b>This is a rich text consuming mouse events</b>")
+ << Qt::TextSelectableByMouse
+ << false;
+ QTest::newRow("PlainTextNoInteraction")
+ << QString("This is a text not interacting with mouse")
+ << Qt::NoTextInteraction
+ << true;
+ QTest::newRow("RichTextNoInteraction")
+ << QString("<b>This is a rich text not interacting with mouse</b>")
+ << Qt::NoTextInteraction
+ << true;
+}
+
+void tst_QLabel::mouseEventPropagation()
+{
+ class MouseEventWidget : public QWidget
+ {
+ public:
+ uint pressed() const { return m_pressed; }
+ uint released() const { return m_released; }
+
+ private:
+ uint m_pressed = 0;
+ uint m_released = 0;
+ void mousePressEvent(QMouseEvent *event) override
+ {
+ ++m_pressed;
+ return QWidget::mousePressEvent(event);
+ }
+
+ void mouseReleaseEvent(QMouseEvent *event) override
+ {
+ ++m_released;
+ return QWidget::mouseReleaseEvent(event);
+ }
+ };
+
+ QFETCH(const QString, text);
+ QFETCH(const Qt::TextInteractionFlag, interaction);
+ QFETCH(const bool, expectPropagation);
+
+ MouseEventWidget widget;
+ auto *layout = new QVBoxLayout(&widget);
+ auto *label = new QLabel(text);
+ label->setTextInteractionFlags(interaction);
+ const uint count = expectPropagation ? 1 : 0;
+
+ layout->addWidget(label);
+ widget.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&widget));
+
+ const QPoint labelCenter = label->rect().center();
+ QTest::mouseClick(label, Qt::LeftButton, Qt::KeyboardModifiers(), labelCenter);
+
+ QTRY_COMPARE(widget.pressed(), count);
+ QTRY_COMPARE(widget.released(), count);
+}
+
QTEST_MAIN(tst_QLabel)
#include "tst_qlabel.moc"