diff --git a/autotests/kactioncollectiontest.h b/autotests/kactioncollectiontest.h --- a/autotests/kactioncollectiontest.h +++ b/autotests/kactioncollectiontest.h @@ -24,6 +24,7 @@ void testSetShortcuts(); void implicitStandardActionInsertionUsingCreate(); void implicitStandardActionInsertionUsingCut(); + void shouldEmitSignals(); private: KConfigGroup clearConfig(); diff --git a/autotests/kactioncollectiontest.cpp b/autotests/kactioncollectiontest.cpp --- a/autotests/kactioncollectiontest.cpp +++ b/autotests/kactioncollectiontest.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -245,5 +246,51 @@ QVERIFY(a == cut); } +void tst_KActionCollection::shouldEmitSignals() +{ + QAction *a = new QAction(nullptr); + QAction *b = new QAction(nullptr); + + QSignalSpy insertedSpy(collection, &KActionCollection::inserted); + QSignalSpy changedSpy(collection, &KActionCollection::changed); + + // Insert "first" + collection->addAction(QStringLiteral("first"), a); + QVERIFY(collection->actions().contains(a)); + QCOMPARE(insertedSpy.count(), 1); + QCOMPARE(insertedSpy.at(0).at(0).value(), a); + QCOMPARE(changedSpy.count(), 1); + insertedSpy.clear(); + changedSpy.clear(); + + // Replace "first" + collection->addAction(QStringLiteral("first"), b); + QVERIFY(!collection->actions().contains(a)); + QVERIFY(collection->actions().contains(b)); + QCOMPARE(insertedSpy.count(), 1); + QCOMPARE(insertedSpy.at(0).at(0).value(), b); + QCOMPARE(changedSpy.count(), 2); // once for removing a, once for inserting b + insertedSpy.clear(); + changedSpy.clear(); + + // Insert "second" + collection->addAction(QStringLiteral("second"), a); + QCOMPARE(insertedSpy.count(), 1); + QCOMPARE(insertedSpy.at(0).at(0).value(), a); + QCOMPARE(changedSpy.count(), 1); + insertedSpy.clear(); + changedSpy.clear(); + + // Remove and delete "second" (which is a) + collection->removeAction(a); + QCOMPARE(changedSpy.count(), 1); + changedSpy.clear(); + + // Delete b directly, should automatically remove it from the collection and emit changed + delete b; + QCOMPARE(changedSpy.count(), 1); + changedSpy.clear(); +} + QTEST_MAIN(tst_KActionCollection) diff --git a/src/kactioncollection.h b/src/kactioncollection.h --- a/src/kactioncollection.h +++ b/src/kactioncollection.h @@ -273,12 +273,18 @@ #if KXMLGUI_ENABLE_DEPRECATED_SINCE(5, 0) /** * Indicates that @p action was removed from this action collection. - * @deprecated Since 5.0 + * @deprecated Since 5.0, use changed() (added in 5.65) instead. */ - KXMLGUI_DEPRECATED_VERSION(5, 0, "Do not rely on") + KXMLGUI_DEPRECATED_VERSION(5, 0, "removed() is sometimes emitted with partially destroyed objects; use changed() instead (added in 5.65)") QT_MOC_COMPAT void removed(QAction *action); #endif + /** + * Emitted when an action has been inserted into, or removed from, this action collection. + * @since 5.65 + */ + void changed(); + #if KXMLGUI_ENABLE_DEPRECATED_SINCE(5, 0) /** * Indicates that @p action was highlighted (hovered over). diff --git a/src/kactioncollection.cpp b/src/kactioncollection.cpp --- a/src/kactioncollection.cpp +++ b/src/kactioncollection.cpp @@ -342,6 +342,7 @@ } emit inserted(action); + emit changed(); return action; } @@ -373,6 +374,7 @@ #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0) emit removed(action); //deprecated #endif + emit changed(); return action; } @@ -763,6 +765,7 @@ #if KXMLGUI_BUILD_DEPRECATED_SINCE(5, 0) emit q->removed(action); //deprecated. remove in KDE5 #endif + emit q->changed(); } void KActionCollection::connectNotify(const QMetaMethod &signal)