Sync default action when checking tool button programmatically

QAbstractButton::setChecked is not virtual, so QToolButton cannot
override to synchronize the default action's checked state. This resulted
in button and default action not being in sync when the checked state
of the button was changed programmatically, while changing the checked
state on the action kept the button in sync.

Connect to the button's own toggled signal instead to keep the state of
the default action in sync. Make it a unique connection to allow multiple
calls to setDefaultAction, which are used by QToolButton to keep the
button updated if properties of the default action change.

Add a test that confirms that button and action are synchronized both
ways, and that we only get single signal emissions when changing either
programmatically.

Fixes: QTBUG-95255
Change-Id: I0e027faf1da763ef1878e46e85bfa70073c8bf82
Reviewed-by: Mitch Curtis <mitch.curtis@qt.io>
(cherry picked from commit 188d739400e10fc8571bbf2ec86d5cd338b04a5d)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Volker Hilsheimer 2021-07-21 16:31:29 +02:00 committed by Qt Cherry-pick Bot
parent 4a2c3d1183
commit f3138e9d53
2 changed files with 65 additions and 0 deletions

View File

@ -963,6 +963,12 @@ void QToolButton::setDefaultAction(QAction *action)
}
#endif
setCheckable(action->isCheckable());
if (action->isCheckable()) {
connect(this, &QAbstractButton::toggled, this, [this](bool checked) {
if (defaultAction())
defaultAction()->setChecked(checked);
}, Qt::UniqueConnection);
}
setChecked(action->isChecked());
setEnabled(action->isEnabled());
if (action->d_func()->fontSet)

View File

@ -56,6 +56,7 @@ private slots:
void task176137_autoRepeatOfAction();
void qtbug_26956_popupTimerDone();
void qtbug_34759_sizeHintResetWhenSettingMenu();
void defaultActionSynced();
protected slots:
void sendMouseClick();
@ -280,5 +281,63 @@ void tst_QToolButton::qtbug_34759_sizeHintResetWhenSettingMenu()
QTRY_COMPARE(button1.sizeHint(), button2.sizeHint());
}
void tst_QToolButton::defaultActionSynced()
{
QAction a;
a.setCheckable(true);
QToolButton tb;
tb.setDefaultAction(&a);
QVERIFY(tb.isCheckable());
QSignalSpy tbSpy(&tb, SIGNAL(toggled(bool)));
QSignalSpy aSpy(&a, SIGNAL(toggled(bool)));
int tbToggledCount = 0;
int aToggledCount = 0;
tb.setChecked(true);
QVERIFY(a.isChecked());
QCOMPARE(tbSpy.count(), ++tbToggledCount);
QCOMPARE(aSpy.count(), ++aToggledCount);
tb.setChecked(false);
QVERIFY(!a.isChecked());
QCOMPARE(tbSpy.count(), ++tbToggledCount);
QCOMPARE(aSpy.count(), ++aToggledCount);
a.setChecked(true);
QVERIFY(tb.isChecked());
QCOMPARE(tbSpy.count(), ++tbToggledCount);
QCOMPARE(aSpy.count(), ++aToggledCount);
a.setChecked(false);
QVERIFY(!tb.isChecked());
QCOMPARE(tbSpy.count(), ++tbToggledCount);
QCOMPARE(aSpy.count(), ++aToggledCount);
QAction b;
QSignalSpy bSpy(&b, SIGNAL(toggled(bool)));
int bToggledCount = 0;
tb.setDefaultAction(&b);
QVERIFY(!tb.isCheckable());
b.setCheckable(true);
QVERIFY(tb.isCheckable());
tb.setChecked(true);
QVERIFY(!a.isChecked());
QVERIFY(b.isChecked());
QCOMPARE(tbSpy.count(), ++tbToggledCount);
QCOMPARE(aSpy.count(), aToggledCount);
QCOMPARE(bSpy.count(), ++bToggledCount);
tb.click();
QVERIFY(!a.isChecked());
QVERIFY(!tb.isChecked());
QVERIFY(!b.isChecked());
QCOMPARE(tbSpy.count(), ++tbToggledCount);
QCOMPARE(aSpy.count(), aToggledCount);
QCOMPARE(bSpy.count(), ++bToggledCount);
}
QTEST_MAIN(tst_QToolButton)
#include "tst_qtoolbutton.moc"