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)
: 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()
@ -171,7 +187,7 @@ void QDialogButtonBoxPrivate::layoutButtons()
Q_Q(QDialogButtonBox);
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) {
QLayoutItem *item = buttonLayout->takeAt(i);
if (QWidget *widget = item->widget())
@ -369,7 +385,6 @@ QPushButton *QDialogButtonBoxPrivate::createButton(QDialogButtonBox::StandardBut
void QDialogButtonBoxPrivate::addButton(QAbstractButton *button, QDialogButtonBox::ButtonRole role,
LayoutRule layoutRule, AddRule addRule)
{
Q_Q(QDialogButtonBox);
buttonLists[role].append(button);
switch (addRule) {
case AddRule::Connect:
@ -377,7 +392,7 @@ void QDialogButtonBoxPrivate::addButton(QAbstractButton *button, QDialogButtonBo
this, &QDialogButtonBoxPrivate::handleButtonClicked);
QObjectPrivate::connect(button, &QAbstractButton::destroyed,
this, &QDialogButtonBoxPrivate::handleButtonDestroyed);
button->installEventFilter(q);
button->installEventFilter(filter.get());
break;
case AddRule::SkipConnect:
break;
@ -466,7 +481,7 @@ QDialogButtonBox::~QDialogButtonBox()
{
Q_D(QDialogButtonBox);
d->byPassEventFilter = true;
d->ignoreShowAndHide = true;
// QObjectPrivate::connect requires explicit disconnect in destructor
// 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)
{
Q_Q(QDialogButtonBox);
if (!button)
return;
@ -713,7 +727,7 @@ void QDialogButtonBoxPrivate::removeButton(QAbstractButton *button, RemoveRule r
this, &QDialogButtonBoxPrivate::handleButtonClicked);
QObjectPrivate::disconnect(button, &QAbstractButton::destroyed,
this, &QDialogButtonBoxPrivate::handleButtonDestroyed);
button->removeEventFilter(q);
button->removeEventFilter(filter.get());
break;
case RemoveRule::KeepConnections:
break;
@ -870,30 +884,15 @@ void QDialogButtonBoxPrivate::handleButtonDestroyed()
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)
{
Q_Q(QDialogButtonBox);
const QEvent::Type type = event->type();
if ((type != QEvent::HideToParent && type != QEvent::ShowToParent) || ignoreShowAndHide)
return false;
switch (type) {
case QEvent::HideToParent: {
const QDialogButtonBox::ButtonRole role = q->buttonRole(button);

View File

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

View File

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