File indexing completed on 2024-04-14 03:57:04

0001 #include "kactioncollectiontest.h"
0002 
0003 #include <QAction>
0004 #include <QPointer>
0005 #include <QSignalSpy>
0006 #include <QtTestWidgets>
0007 
0008 #include <KSharedConfig>
0009 #include <KStandardAction>
0010 
0011 void tst_KActionCollection::init()
0012 {
0013     collection = new KActionCollection(static_cast<QObject *>(nullptr));
0014 }
0015 
0016 void tst_KActionCollection::cleanup()
0017 {
0018     delete collection;
0019     collection = nullptr;
0020 }
0021 
0022 void tst_KActionCollection::clear()
0023 {
0024     QPointer<QAction> action1 = collection->add<QAction>(QStringLiteral("test1"));
0025     QPointer<QAction> action2 = collection->add<QAction>(QStringLiteral("test2"));
0026     QPointer<QAction> action3 = collection->add<QAction>(QStringLiteral("test3"));
0027     QPointer<QAction> action4 = collection->add<QAction>(QStringLiteral("test4"));
0028     QPointer<QAction> action5 = collection->add<QAction>(QStringLiteral("test5"));
0029     QPointer<QAction> action6 = collection->add<QAction>(QStringLiteral("test6"));
0030     QPointer<QAction> action7 = collection->add<QAction>(QStringLiteral("test7"));
0031 
0032     collection->clear();
0033     QVERIFY(collection->isEmpty());
0034 
0035     QVERIFY(action1.isNull());
0036     QVERIFY(action2.isNull());
0037     QVERIFY(action3.isNull());
0038     QVERIFY(action4.isNull());
0039     QVERIFY(action5.isNull());
0040     QVERIFY(action6.isNull());
0041     QVERIFY(action7.isNull());
0042 }
0043 
0044 void tst_KActionCollection::addStandardActionFunctorSignal()
0045 {
0046     bool received = false;
0047     QAction *a = collection->addAction(KStandardAction::New, QStringLiteral("test"), this, [&]() {
0048         received = true;
0049     });
0050     a->trigger();
0051     QVERIFY(received);
0052     delete a;
0053     QVERIFY(collection->isEmpty());
0054 }
0055 
0056 void tst_KActionCollection::deleted()
0057 {
0058     // Delete action -> automatically removed from collection
0059     QAction *a = collection->add<QAction>(QStringLiteral("test"));
0060     delete a;
0061     QVERIFY(collection->isEmpty());
0062 
0063     // Delete action's parent -> automatically removed from collection
0064     QWidget *myWidget = new QWidget(nullptr);
0065     QPointer<QAction> action = new QAction(/*i18n()*/ QStringLiteral("Foo"), myWidget);
0066     collection->addAction(QStringLiteral("foo"), action);
0067     delete myWidget;
0068     QVERIFY(collection->isEmpty());
0069     QVERIFY(action.isNull());
0070 
0071     // Delete action's parent, but the action was added to another widget with setAssociatedWidget
0072     // and that widget gets deleted first.
0073     myWidget = new QWidget(nullptr);
0074     QWidget *myAssociatedWidget = new QWidget(myWidget); // child widget
0075     action = new QAction(/*i18n()*/ QStringLiteral("Foo"), myWidget); // child action
0076     collection->addAction(QStringLiteral("foo"), action);
0077     collection->addAssociatedWidget(myAssociatedWidget);
0078     QVERIFY(myAssociatedWidget->actions().contains(action));
0079     delete myAssociatedWidget; // would be done by the line below, but let's make sure it happens first
0080     delete myWidget;
0081     QVERIFY(collection->isEmpty());
0082     QVERIFY(action.isNull());
0083 }
0084 
0085 void tst_KActionCollection::take()
0086 {
0087     QAction *a = collection->add<QAction>(QStringLiteral("test"));
0088     collection->takeAction(a);
0089     QVERIFY(collection->isEmpty());
0090     delete a;
0091 }
0092 
0093 void tst_KActionCollection::writeSettings()
0094 {
0095     KConfigGroup cfg = clearConfig();
0096 
0097     QList<QKeySequence> defaultShortcut;
0098     defaultShortcut << Qt::Key_A << Qt::Key_B;
0099 
0100     QList<QKeySequence> temporaryShortcut;
0101     temporaryShortcut << Qt::Key_C << Qt::Key_D;
0102 
0103     QAction *actionWithDifferentShortcut = new QAction(this);
0104     KActionCollection::setDefaultShortcuts(actionWithDifferentShortcut, defaultShortcut);
0105     actionWithDifferentShortcut->setShortcuts(temporaryShortcut);
0106     collection->addAction(QStringLiteral("actionWithDifferentShortcut"), actionWithDifferentShortcut);
0107 
0108     QAction *immutableAction = new QAction(this);
0109     KActionCollection::setDefaultShortcuts(immutableAction, defaultShortcut);
0110     immutableAction->setShortcuts(temporaryShortcut);
0111     KActionCollection::setShortcutsConfigurable(immutableAction, false);
0112     collection->addAction(QStringLiteral("immutableAction"), immutableAction);
0113 
0114     QAction *actionWithSameShortcut = new QAction(this);
0115     KActionCollection::setDefaultShortcuts(actionWithSameShortcut, defaultShortcut);
0116     collection->addAction(QStringLiteral("actionWithSameShortcut"), actionWithSameShortcut);
0117 
0118     cfg.writeEntry("actionToDelete", QStringLiteral("Foobar"));
0119     QAction *actionToDelete = new QAction(this);
0120     KActionCollection::setDefaultShortcuts(actionToDelete, defaultShortcut);
0121     collection->addAction(QStringLiteral("actionToDelete"), actionToDelete);
0122 
0123     collection->writeSettings(&cfg);
0124 
0125     QCOMPARE(cfg.readEntry("actionWithDifferentShortcut", QString()), QKeySequence::listToString(actionWithDifferentShortcut->shortcuts()));
0126     QCOMPARE(cfg.readEntry("immutableAction", QString()), QString());
0127     QCOMPARE(cfg.readEntry("actionWithSameShortcut", QString()), QString());
0128     QCOMPARE(cfg.readEntry("actionToDelete", QString()), QString());
0129 
0130     qDeleteAll(collection->actions());
0131 }
0132 
0133 void tst_KActionCollection::readSettings()
0134 {
0135     KConfigGroup cfg = clearConfig();
0136 
0137     QList<QKeySequence> defaultShortcut;
0138     defaultShortcut << Qt::Key_A << Qt::Key_B;
0139 
0140     QList<QKeySequence> temporaryShortcut;
0141     temporaryShortcut << Qt::Key_C << Qt::Key_D;
0142 
0143     cfg.writeEntry("normalAction", QKeySequence::listToString(defaultShortcut));
0144     cfg.writeEntry("immutable", QKeySequence::listToString(defaultShortcut));
0145     cfg.writeEntry("empty", QString());
0146 
0147     QAction *normal = new QAction(this);
0148     collection->addAction(QStringLiteral("normalAction"), normal);
0149 
0150     QAction *immutable = new QAction(this);
0151     immutable->setShortcuts(temporaryShortcut);
0152     KActionCollection::setDefaultShortcuts(immutable, temporaryShortcut);
0153     KActionCollection::setShortcutsConfigurable(immutable, false);
0154     collection->addAction(QStringLiteral("immutable"), immutable);
0155 
0156     QAction *empty = new QAction(this);
0157     collection->addAction(QStringLiteral("empty"), empty);
0158     KActionCollection::setDefaultShortcuts(empty, defaultShortcut);
0159     empty->setShortcuts(temporaryShortcut);
0160     QCOMPARE(QKeySequence::listToString(empty->shortcuts()), QKeySequence::listToString(temporaryShortcut));
0161 
0162     collection->readSettings(&cfg);
0163 
0164     QCOMPARE(QKeySequence::listToString(normal->shortcuts()), QKeySequence::listToString(defaultShortcut));
0165     QCOMPARE(QKeySequence::listToString(empty->shortcuts()), QKeySequence::listToString(defaultShortcut));
0166 
0167     QCOMPARE(QKeySequence::listToString(immutable->shortcuts()), QKeySequence::listToString(temporaryShortcut));
0168 
0169     qDeleteAll(collection->actions());
0170 }
0171 
0172 void tst_KActionCollection::insertReplaces1()
0173 {
0174     QAction *a = new QAction(nullptr);
0175     QAction *b = new QAction(nullptr);
0176 
0177     collection->addAction(QStringLiteral("a"), a);
0178     QVERIFY(collection->actions().contains(a));
0179     QVERIFY(collection->action(QStringLiteral("a")) == a);
0180 
0181     collection->addAction(QStringLiteral("a"), b);
0182     QVERIFY(!collection->actions().contains(a));
0183     QVERIFY(collection->actions().contains(b));
0184     QVERIFY(collection->action(QStringLiteral("a")) == b);
0185 
0186     delete a;
0187     delete b;
0188 }
0189 
0190 /**
0191  * Check that a action added twice under different names only ends up once in
0192  * the collection
0193  */
0194 void tst_KActionCollection::insertReplaces2()
0195 {
0196     QAction *a = new QAction(nullptr);
0197 
0198     collection->addAction(QStringLiteral("a"), a);
0199     QVERIFY(collection->actions().contains(a));
0200     QVERIFY(collection->action(QStringLiteral("a")) == a);
0201 
0202     // Simple test: Just add it twice
0203     collection->addAction(QStringLiteral("b"), a);
0204     QVERIFY(collection->actions().contains(a));
0205     QVERIFY(!collection->action(QStringLiteral("a")));
0206     QVERIFY(collection->action(QStringLiteral("b")) == a);
0207 
0208     // Complex text: Mesh with the objectname
0209     a->setObjectName(QStringLiteral("c"));
0210     collection->addAction(QStringLiteral("d"), a);
0211     QVERIFY(collection->actions().contains(a));
0212     QVERIFY(!collection->action(QStringLiteral("b")));
0213     QVERIFY(!collection->action(QStringLiteral("c")));
0214     QVERIFY(collection->action(QStringLiteral("d")) == a);
0215 
0216     delete a;
0217 }
0218 
0219 KConfigGroup tst_KActionCollection::clearConfig()
0220 {
0221     KSharedConfig::Ptr cfg = KSharedConfig::openConfig();
0222     cfg->deleteGroup(collection->configGroup());
0223     return KConfigGroup(cfg, collection->configGroup());
0224 }
0225 
0226 void tst_KActionCollection::testSetShortcuts()
0227 {
0228     QAction *action = new QAction(/*i18n*/ (QStringLiteral("Next Unread &Folder")), this);
0229     collection->addAction(QStringLiteral("go_next_unread_folder"), action);
0230     KActionCollection::setDefaultShortcut(action, QKeySequence(Qt::ALT | Qt::Key_Plus));
0231     QList<QKeySequence> shortcut = action->shortcuts();
0232     shortcut << QKeySequence(Qt::CTRL | Qt::Key_Plus);
0233     action->setShortcuts(shortcut);
0234     QCOMPARE(QKeySequence::listToString(action->shortcuts()), QStringLiteral("Alt++; Ctrl++"));
0235 
0236     // Simpler way:
0237     QList<QKeySequence> shortcut2;
0238     shortcut2 << QKeySequence(Qt::ALT | Qt::Key_Plus) << QKeySequence(Qt::CTRL | Qt::Key_Plus);
0239     QCOMPARE(QKeySequence::listToString(shortcut2), QStringLiteral("Alt++; Ctrl++"));
0240 }
0241 
0242 void tst_KActionCollection::implicitStandardActionInsertionUsingCreate()
0243 {
0244     KActionCollection collection(static_cast<QObject *>(nullptr));
0245     QAction *a = KStandardAction::create(KStandardAction::Undo, qApp, &QCoreApplication::quit, &collection);
0246     QVERIFY(a);
0247 
0248     QVERIFY(a->parent() == &collection);
0249     QVERIFY(collection.action(KStandardAction::name(KStandardAction::Undo)) == a);
0250 }
0251 
0252 void tst_KActionCollection::implicitStandardActionInsertionUsingCut()
0253 {
0254     KActionCollection collection(static_cast<QObject *>(nullptr));
0255     QAction *cut = KStandardAction::cut(&collection);
0256     QAction *a = collection.action(KStandardAction::name(KStandardAction::Cut));
0257     QVERIFY(a);
0258     QVERIFY(a == cut);
0259 }
0260 
0261 void tst_KActionCollection::shouldEmitSignals()
0262 {
0263     QAction *a = new QAction(nullptr);
0264     QAction *b = new QAction(nullptr);
0265 
0266     QSignalSpy insertedSpy(collection, &KActionCollection::inserted);
0267     QSignalSpy changedSpy(collection, &KActionCollection::changed);
0268 
0269     // Insert "first"
0270     collection->addAction(QStringLiteral("first"), a);
0271     QVERIFY(collection->actions().contains(a));
0272     QCOMPARE(insertedSpy.count(), 1);
0273     QCOMPARE(insertedSpy.at(0).at(0).value<QAction *>(), a);
0274     QCOMPARE(changedSpy.count(), 1);
0275     insertedSpy.clear();
0276     changedSpy.clear();
0277 
0278     // Replace "first"
0279     collection->addAction(QStringLiteral("first"), b);
0280     QVERIFY(!collection->actions().contains(a));
0281     QVERIFY(collection->actions().contains(b));
0282     QCOMPARE(insertedSpy.count(), 1);
0283     QCOMPARE(insertedSpy.at(0).at(0).value<QAction *>(), b);
0284     QCOMPARE(changedSpy.count(), 2); // once for removing a, once for inserting b
0285     insertedSpy.clear();
0286     changedSpy.clear();
0287 
0288     // Insert "second"
0289     collection->addAction(QStringLiteral("second"), a);
0290     QCOMPARE(insertedSpy.count(), 1);
0291     QCOMPARE(insertedSpy.at(0).at(0).value<QAction *>(), a);
0292     QCOMPARE(changedSpy.count(), 1);
0293     insertedSpy.clear();
0294     changedSpy.clear();
0295 
0296     // Remove and delete "second" (which is a)
0297     collection->removeAction(a);
0298     QCOMPARE(changedSpy.count(), 1);
0299     changedSpy.clear();
0300 
0301     // Delete b directly, should automatically remove it from the collection and emit changed
0302     delete b;
0303     QCOMPARE(changedSpy.count(), 1);
0304     changedSpy.clear();
0305 }
0306 
0307 QTEST_MAIN(tst_KActionCollection)
0308 
0309 #include "moc_kactioncollectiontest.cpp"