File indexing completed on 2024-10-06 03:43:14
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"