QDialogButtonBox: Use separate eventFilter class

bbb71e7e80 added an eventFilter override
to QDialogButtonBox, in order to fix QTBUG-114377. The approach added
a symbol to QDialogButtonBox, which breaks binary compatibility between
patch releases.

=> Use a separate class to install an event filter
=> Remove the symbol (eventFilter override) in QDialogButtonBox

Fixes: QTBUG-116287
Pick-to: 6.6 6.5
Change-Id: I920deca9f45f6246ed1fcbf5346f681dd5dd12f6
Reviewed-by: Marc Mutz <marc.mutz@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Axel Spoerl 2023-08-21 15:43:12 +02:00
parent 2da366fbba
commit aff0915352
3 changed files with 26 additions and 27 deletions

View File

@ -115,6 +115,22 @@ QT_BEGIN_NAMESPACE
QDialogButtonBoxPrivate::QDialogButtonBoxPrivate(Qt::Orientation orient) QDialogButtonBoxPrivate::QDialogButtonBoxPrivate(Qt::Orientation orient)
: orientation(orient), buttonLayout(nullptr), center(false) : orientation(orient), buttonLayout(nullptr), center(false)
{ {
struct EventFilter : public QObject
{
EventFilter(QDialogButtonBoxPrivate *d) : d(d) {};
bool eventFilter(QObject *obj, QEvent *event) override
{
QAbstractButton *button = qobject_cast<QAbstractButton *>(obj);
return button ? d->handleButtonShowAndHide(button, event) : false;
}
private:
QDialogButtonBoxPrivate *d;
};
filter.reset(new EventFilter(this));
} }
void QDialogButtonBoxPrivate::initLayout() void QDialogButtonBoxPrivate::initLayout()
@ -171,7 +187,7 @@ void QDialogButtonBoxPrivate::layoutButtons()
Q_Q(QDialogButtonBox); Q_Q(QDialogButtonBox);
const int MacGap = 36 - 8; // 8 is the default gap between a widget and a spacer item const int MacGap = 36 - 8; // 8 is the default gap between a widget and a spacer item
QBoolBlocker blocker(byPassEventFilter); QBoolBlocker blocker(ignoreShowAndHide);
for (int i = buttonLayout->count() - 1; i >= 0; --i) { for (int i = buttonLayout->count() - 1; i >= 0; --i) {
QLayoutItem *item = buttonLayout->takeAt(i); QLayoutItem *item = buttonLayout->takeAt(i);
if (QWidget *widget = item->widget()) if (QWidget *widget = item->widget())
@ -369,7 +385,6 @@ QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardBut
void QDialogButtonBoxPrivate::addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role, void QDialogButtonBoxPrivate::addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role,
LayoutRule layoutRule, AddRule addRule) LayoutRule layoutRule, AddRule addRule)
{ {
Q_Q(QDialogButtonBox);
buttonLists[role].append(button); buttonLists[role].append(button);
switch (addRule) { switch (addRule) {
case AddRule::Connect: case AddRule::Connect:
@ -377,7 +392,7 @@ void QDialogButtonBoxPrivate::addButton(QAbstractButton *button, QDialogButtonBo
this, &QDialogButtonBoxPrivate::handleButtonClicked); this, &QDialogButtonBoxPrivate::handleButtonClicked);
QObjectPrivate::connect(button, &QAbstractButton::destroyed, QObjectPrivate::connect(button, &QAbstractButton::destroyed,
this, &QDialogButtonBoxPrivate::handleButtonDestroyed); this, &QDialogButtonBoxPrivate::handleButtonDestroyed);
button->installEventFilter(q); button->installEventFilter(filter.get());
break; break;
case AddRule::SkipConnect: case AddRule::SkipConnect:
break; break;
@ -466,7 +481,7 @@ QDialogButtonBox::~QDialogButtonBox()
{ {
Q_D(QDialogButtonBox); Q_D(QDialogButtonBox);
d->byPassEventFilter = true; d->ignoreShowAndHide = true;
// QObjectPrivate::connect requires explicit disconnect in destructor // QObjectPrivate::connect requires explicit disconnect in destructor
// otherwise the connection may kick in on child destruction and reach // otherwise the connection may kick in on child destruction and reach
@ -694,7 +709,6 @@ void QDialogButtonBox::removeButton(QAbstractButton *button)
void QDialogButtonBoxPrivate::removeButton(QAbstractButton *button, RemoveRule rule) void QDialogButtonBoxPrivate::removeButton(QAbstractButton *button, RemoveRule rule)
{ {
Q_Q(QDialogButtonBox);
if (!button) if (!button)
return; return;
@ -713,7 +727,7 @@ void QDialogButtonBoxPrivate::removeButton(QAbstractButton *button, RemoveRule r
this, &QDialogButtonBoxPrivate::handleButtonClicked); this, &QDialogButtonBoxPrivate::handleButtonClicked);
QObjectPrivate::disconnect(button, &QAbstractButton::destroyed, QObjectPrivate::disconnect(button, &QAbstractButton::destroyed,
this, &QDialogButtonBoxPrivate::handleButtonDestroyed); this, &QDialogButtonBoxPrivate::handleButtonDestroyed);
button->removeEventFilter(q); button->removeEventFilter(filter.get());
break; break;
case RemoveRule::KeepConnections: case RemoveRule::KeepConnections:
break; break;
@ -870,30 +884,15 @@ void QDialogButtonBoxPrivate::handleButtonDestroyed()
removeButton(reinterpret_cast<QAbstractButton *>(object), RemoveRule::KeepConnections); removeButton(reinterpret_cast<QAbstractButton *>(object), RemoveRule::KeepConnections);
} }
bool QDialogButtonBox::eventFilter(QObject *object, QEvent *event)
{
Q_D(QDialogButtonBox);
if (d->byPassEventFilter)
return false;
QAbstractButton *button = qobject_cast<QAbstractButton *>(object);
if (!button)
return false;
const QEvent::Type type = event->type();
if (type == QEvent::HideToParent || type == QEvent::ShowToParent)
return d->handleButtonShowAndHide(button, event);
return false;
}
bool QDialogButtonBoxPrivate::handleButtonShowAndHide(QAbstractButton *button, QEvent *event) bool QDialogButtonBoxPrivate::handleButtonShowAndHide(QAbstractButton *button, QEvent *event)
{ {
Q_Q(QDialogButtonBox); Q_Q(QDialogButtonBox);
const QEvent::Type type = event->type(); const QEvent::Type type = event->type();
if ((type != QEvent::HideToParent && type != QEvent::ShowToParent) || ignoreShowAndHide)
return false;
switch (type) { switch (type) {
case QEvent::HideToParent: { case QEvent::HideToParent: {
const QDialogButtonBox::ButtonRole role = q->buttonRole(button); const QDialogButtonBox::ButtonRole role = q->buttonRole(button);

View File

@ -107,8 +107,6 @@ public:
void setCenterButtons(bool center); void setCenterButtons(bool center);
bool centerButtons() const; bool centerButtons() const;
bool eventFilter(QObject *object, QEvent *event) override;
Q_SIGNALS: Q_SIGNALS:
void clicked(QAbstractButton *button); void clicked(QAbstractButton *button);
void accepted(); void accepted();

View File

@ -19,6 +19,7 @@
#include <qdialogbuttonbox.h> #include <qdialogbuttonbox.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class Q_AUTOTEST_EXPORT QDialogButtonBoxPrivate : public QWidgetPrivate class Q_AUTOTEST_EXPORT QDialogButtonBoxPrivate : public QWidgetPrivate
{ {
Q_DECLARE_PUBLIC(QDialogButtonBox) Q_DECLARE_PUBLIC(QDialogButtonBox)
@ -46,8 +47,9 @@ public:
Qt::Orientation orientation; Qt::Orientation orientation;
QDialogButtonBox::ButtonLayout layoutPolicy; QDialogButtonBox::ButtonLayout layoutPolicy;
QBoxLayout *buttonLayout; QBoxLayout *buttonLayout;
std::unique_ptr<QObject> filter;
bool center; bool center;
bool byPassEventFilter = false; bool ignoreShowAndHide = false;
void createStandardButtons(QDialogButtonBox::StandardButtons buttons); void createStandardButtons(QDialogButtonBox::StandardButtons buttons);