File indexing completed on 2025-01-05 04:59:48
0001 /* 0002 * SPDX-FileCopyrightText: 2014-2019 Kevin Ottens <ervin@kde.org> 0003 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0004 */ 0005 0006 0007 #include "zanshincontext.h" 0008 0009 #include "akonadi/akonadiapplicationselectedattribute.h" 0010 #include "akonadi/akonadicachingstorage.h" 0011 #include "akonadi/akonadistorageinterface.h" 0012 #include "akonadi/akonaditimestampattribute.h" 0013 0014 #include "presentation/applicationmodel.h" 0015 #include "presentation/querytreemodelbase.h" 0016 0017 #include "testlib/akonadifakedataxmlloader.h" 0018 #include "testlib/monitorspy.h" 0019 0020 #include "utils/dependencymanager.h" 0021 #include "utils/jobhandler.h" 0022 #include "integration/dependencies.h" 0023 0024 #include <Akonadi/AttributeFactory> 0025 0026 #include <KConfigGroup> 0027 #include <KSharedConfig> 0028 0029 #include <QSortFilterProxyModel> 0030 #include <QStandardItemModel> 0031 #include <QTest> 0032 0033 void FakeErrorHandler::doDisplayMessage(const QString &) 0034 { 0035 } 0036 0037 ZanshinContext::ZanshinContext(QObject *parent) 0038 : QObject(parent), 0039 m_presentation(nullptr), 0040 m_editor(nullptr), 0041 m_proxyModel(new QSortFilterProxyModel(this)), 0042 m_model(nullptr), 0043 m_sourceModel(nullptr), 0044 m_monitorSpy(nullptr) 0045 { 0046 qputenv("ZANSHIN_OVERRIDE_DATE", "2015-03-10"); 0047 0048 static bool initializedDependencies = false; 0049 0050 if (!initializedDependencies) { 0051 Integration::initializeGlobalAppDependencies(); 0052 MonitorSpy::setExpirationDelay(200); 0053 initializedDependencies = true; 0054 } 0055 0056 Akonadi::AttributeFactory::registerAttribute<Akonadi::ApplicationSelectedAttribute>(); 0057 Akonadi::AttributeFactory::registerAttribute<Akonadi::TimestampAttribute>(); 0058 0059 const auto xmlFile = QString::fromLocal8Bit(ZANSHIN_USER_XMLDATA); 0060 if (xmlFile.isEmpty()) { 0061 qDebug() << "FATAL ERROR! ZANSHIN_USER_XMLDATA WAS NOT PROVIDED\n\n"; 0062 exit(1); 0063 } 0064 0065 auto searchCollection = Akonadi::Collection(1); 0066 searchCollection.setParentCollection(Akonadi::Collection::root()); 0067 searchCollection.setName(QStringLiteral("Search")); 0068 m_data.createCollection(searchCollection); 0069 0070 auto loader = Testlib::AkonadiFakeDataXmlLoader(&m_data); 0071 loader.load(xmlFile); 0072 0073 // Sanity checks 0074 QVERIFY(m_data.collections().size() > 1); 0075 QVERIFY(m_data.items().size() > 1); 0076 QVERIFY(m_data.contexts().size() > 1); 0077 0078 // Swap regular dependencies for the fake data ones 0079 auto &deps = Utils::DependencyManager::globalInstance(); 0080 deps.add<Akonadi::MonitorInterface, 0081 Utils::DependencyManager::UniqueInstance>( 0082 [this] (Utils::DependencyManager *) { 0083 return m_data.createMonitor(); 0084 } 0085 ); 0086 deps.add<Akonadi::StorageInterface, 0087 Utils::DependencyManager::UniqueInstance>( 0088 [this] (Utils::DependencyManager *deps) { 0089 return new Akonadi::CachingStorage(deps->create<Akonadi::Cache>(), 0090 Akonadi::StorageInterface::Ptr(m_data.createStorage())); 0091 } 0092 ); 0093 0094 using namespace Presentation; 0095 m_proxyModel->setDynamicSortFilter(true); 0096 0097 auto appModel = ApplicationModel::Ptr::create(); 0098 0099 appModel->setErrorHandler(&m_errorHandler); 0100 0101 m_appModel = appModel; 0102 0103 auto monitor = Utils::DependencyManager::globalInstance().create<Akonadi::MonitorInterface>(); 0104 m_monitorSpy = new MonitorSpy(monitor.data(), this); 0105 } 0106 0107 // Note that setModel might invalidate the 'index' member variable, due to proxyModel->setSourceModel. 0108 void ZanshinContext::setModel(QAbstractItemModel *model) 0109 { 0110 if (m_sourceModel == model) 0111 return; 0112 m_sourceModel = model; 0113 if (!qobject_cast<QSortFilterProxyModel *>(model)) { 0114 m_proxyModel->setObjectName(QLatin1StringView("m_proxyModel_in_ZanshinContext")); 0115 m_proxyModel->setSourceModel(model); 0116 m_proxyModel->setSortRole(Qt::DisplayRole); 0117 m_proxyModel->sort(0); 0118 m_model = m_proxyModel; 0119 } else { 0120 m_model = model; 0121 } 0122 } 0123 0124 QAbstractItemModel *ZanshinContext::sourceModel() const 0125 { 0126 return m_sourceModel; 0127 } 0128 0129 QAbstractItemModel *ZanshinContext::model() const 0130 { 0131 return m_model; 0132 } 0133 0134 Domain::Task::Ptr ZanshinContext::currentTask() const 0135 { 0136 return m_index.data(Presentation::QueryTreeModelBase::ObjectRole) 0137 .value<Domain::Task::Ptr>(); 0138 } 0139 0140 void ZanshinContext::waitForEmptyJobQueue() 0141 { 0142 while (Utils::JobHandler::jobCount() != 0) { 0143 QTest::qWait(20); 0144 } 0145 } 0146 0147 void ZanshinContext::waitForStableState() 0148 { 0149 waitForEmptyJobQueue(); 0150 m_monitorSpy->waitForStableState(); 0151 } 0152 0153 void ZanshinContext::collectIndicesImpl(const QModelIndex &root) 0154 { 0155 QAbstractItemModel *model = m_model; 0156 for (int row = 0; row < model->rowCount(root); row++) { 0157 const QModelIndex index = model->index(row, 0, root); 0158 m_indices << index; 0159 if (model->rowCount(index) > 0) 0160 collectIndicesImpl(index); 0161 } 0162 } 0163 0164 void ZanshinContext::collectIndices() 0165 { 0166 m_indices.clear(); 0167 collectIndicesImpl(); 0168 } 0169 0170 namespace Zanshin { 0171 0172 QString indexString(const QModelIndex &index, int role = Qt::DisplayRole) 0173 { 0174 if (role != Qt::DisplayRole) 0175 return index.data(role).toString(); 0176 0177 QString data = index.data(role).toString(); 0178 0179 if (index.parent().isValid()) 0180 return indexString(index.parent(), role) + " / " + data; 0181 else 0182 return data; 0183 } 0184 0185 QModelIndex findIndex(QAbstractItemModel *model, 0186 const QString &string, 0187 int role = Qt::DisplayRole, 0188 const QModelIndex &root = QModelIndex()) 0189 { 0190 for (int row = 0; row < model->rowCount(root); row++) { 0191 const QModelIndex index = model->index(row, 0, root); 0192 if (indexString(index, role) == string) 0193 return index; 0194 0195 if (model->rowCount(index) > 0) { 0196 const QModelIndex found = findIndex(model, string, role, index); 0197 if (found.isValid()) 0198 return found; 0199 } 0200 } 0201 0202 return QModelIndex(); 0203 } 0204 0205 void dumpIndices(const QList<QPersistentModelIndex> &indices) 0206 { 0207 qDebug() << "Dumping list of size:" << indices.size(); 0208 for (int row = 0; row < indices.size(); row++) { 0209 qDebug() << row << indexString(indices.at(row)); 0210 } 0211 } 0212 0213 inline bool verify(bool statement, const char *str, 0214 const char *file, int line) 0215 { 0216 if (statement) 0217 return true; 0218 0219 qDebug() << "Statement" << str << "returned FALSE"; 0220 qDebug() << "Loc:" << file << line; 0221 return false; 0222 } 0223 0224 template <typename T> 0225 inline bool compare(T const &t1, T const &t2, 0226 const char *actual, const char *expected, 0227 const char *file, int line) 0228 { 0229 if (t1 == t2) 0230 return true; 0231 0232 qDebug() << "Compared values are not the same"; 0233 qDebug() << "Actual (" << actual << ") :" << QTest::toString<T>(t1); 0234 qDebug() << "Expected (" << expected << ") :" << QTest::toString<T>(t2); 0235 qDebug() << "Loc:" << file << line; 0236 return false; 0237 } 0238 0239 } // namespace Zanshin 0240 0241 #define COMPARE(actual, expected) \ 0242 do {\ 0243 if (!Zanshin::compare(actual, expected, #actual, #expected, __FILE__, __LINE__))\ 0244 return false;\ 0245 } while (0) 0246 0247 // Note: you should make sure that m_indices is filled in before calling this, 0248 // e.g. calling Zanshin::collectIndices(context.get()) if not already done. 0249 #define COMPARE_OR_DUMP(actual, expected) \ 0250 do {\ 0251 if (!Zanshin::compare(actual, expected, #actual, #expected, __FILE__, __LINE__)) {\ 0252 Zanshin::dumpIndices(m_indices); \ 0253 return false;\ 0254 }\ 0255 } while (0) 0256 0257 #define VERIFY(statement) \ 0258 do {\ 0259 if (!Zanshin::verify((statement), #statement, __FILE__, __LINE__))\ 0260 return false;\ 0261 } while (0) 0262 0263 // Note: you should make sure that m_indices is filled in before calling this, 0264 // e.g. calling Zanshin::collectIndices(context.get()) if not already done. 0265 #define VERIFY_OR_DUMP(statement) \ 0266 do {\ 0267 if (!Zanshin::verify((statement), #statement, __FILE__, __LINE__)) {\ 0268 Zanshin::dumpIndices(m_indices); \ 0269 return false;\ 0270 }\ 0271 } while (0) 0272 0273 #define VERIFY_OR_DO(statement, whatToDo) \ 0274 do {\ 0275 if (!Zanshin::verify((statement), #statement, __FILE__, __LINE__)) {\ 0276 whatToDo; \ 0277 return false;\ 0278 }\ 0279 } while (0) 0280 0281 0282 bool ZanshinContext::I_display_the_available_data_sources() 0283 { 0284 auto availableSources = m_appModel->property("availableSources").value<QObject*>(); 0285 VERIFY(availableSources); 0286 0287 auto sourceListModel = availableSources->property("sourceListModel").value<QAbstractItemModel*>(); 0288 VERIFY(sourceListModel); 0289 0290 m_presentation = availableSources; 0291 setModel(sourceListModel); 0292 0293 return true; 0294 } 0295 0296 bool ZanshinContext::I_display_the_available_pages() 0297 { 0298 m_presentation = m_appModel->property("availablePages").value<QObject*>(); 0299 setModel(m_presentation->property("pageListModel").value<QAbstractItemModel*>()); 0300 return true; 0301 } 0302 0303 bool ZanshinContext::I_display_the_page(const QString &pageName) 0304 { 0305 if (m_editor) { 0306 // save pending changes 0307 VERIFY(m_editor->setProperty("task", QVariant::fromValue(Domain::Task::Ptr()))); 0308 } 0309 auto availablePages = m_appModel->property("availablePages").value<QObject*>(); 0310 VERIFY(availablePages); 0311 0312 auto pageListModel = availablePages->property("pageListModel").value<QAbstractItemModel*>(); 0313 VERIFY(pageListModel); 0314 waitForEmptyJobQueue(); 0315 0316 QModelIndex pageIndex = Zanshin::findIndex(pageListModel, pageName); 0317 VERIFY_OR_DUMP(pageIndex.isValid()); 0318 0319 QObject *page = nullptr; 0320 QMetaObject::invokeMethod(availablePages, "createPageForIndex", 0321 Q_RETURN_ARG(QObject*, page), 0322 Q_ARG(QModelIndex, pageIndex)); 0323 VERIFY(page); 0324 0325 VERIFY(m_appModel->setProperty("currentPage", QVariant::fromValue(page))); 0326 m_presentation = m_appModel->property("currentPage").value<QObject*>(); 0327 0328 return true; 0329 } 0330 0331 bool ZanshinContext::there_is_an_item_in_the_central_list(const QString &taskName) 0332 { 0333 auto m = m_presentation->property("centralListModel").value<QAbstractItemModel*>(); 0334 setModel(m); 0335 waitForEmptyJobQueue(); 0336 0337 collectIndices(); 0338 m_index = Zanshin::findIndex(model(), taskName); 0339 VERIFY_OR_DUMP(m_index.isValid()); 0340 0341 return true; 0342 } 0343 0344 bool ZanshinContext::there_is_an_item_in_the_available_data_sources(const QString &sourceName) 0345 { 0346 auto availableSources = m_appModel->property("availableSources").value<QObject*>(); 0347 VERIFY(availableSources); 0348 auto m = availableSources->property("sourceListModel").value<QAbstractItemModel*>(); 0349 VERIFY(m); 0350 waitForEmptyJobQueue(); 0351 setModel(m); 0352 0353 collectIndices(); 0354 m_index = Zanshin::findIndex(model(), sourceName); 0355 VERIFY_OR_DUMP(m_index.isValid()); 0356 0357 return true; 0358 } 0359 0360 bool ZanshinContext::the_central_list_contains_items_named(const QStringList &taskNames) 0361 { 0362 m_dragIndices.clear(); 0363 0364 auto m = m_presentation->property("centralListModel").value<QAbstractItemModel*>(); 0365 waitForEmptyJobQueue(); 0366 setModel(m); 0367 0368 for (const auto &taskName : taskNames) { 0369 QModelIndex index = Zanshin::findIndex(model(), taskName); 0370 VERIFY_OR_DO(index.isValid(), Zanshin::dumpIndices(m_dragIndices)); 0371 m_dragIndices << index; 0372 } 0373 0374 return true; 0375 } 0376 0377 bool ZanshinContext::I_look_at_the_central_list() 0378 { 0379 auto m = m_presentation->property("centralListModel").value<QAbstractItemModel*>(); 0380 setModel(m); 0381 waitForStableState(); 0382 return true; 0383 } 0384 0385 bool ZanshinContext::I_check_the_item() 0386 { 0387 VERIFY(model()->setData(m_index, Qt::Checked, Qt::CheckStateRole)); 0388 waitForStableState(); 0389 return true; 0390 } 0391 0392 bool ZanshinContext::I_uncheck_the_item() 0393 { 0394 VERIFY(model()->setData(m_index, Qt::Unchecked, Qt::CheckStateRole)); 0395 waitForStableState(); 0396 return true; 0397 } 0398 0399 bool ZanshinContext::I_remove_the_item() 0400 { 0401 VERIFY(QMetaObject::invokeMethod(m_presentation, "removeItem", Q_ARG(QModelIndex, m_index))); 0402 waitForStableState(); 0403 return true; 0404 } 0405 0406 bool ZanshinContext::I_promote_the_item() 0407 { 0408 VERIFY(QMetaObject::invokeMethod(m_presentation, "promoteItem", Q_ARG(QModelIndex, m_index))); 0409 waitForStableState(); 0410 0411 return true; 0412 } 0413 0414 bool ZanshinContext::I_add_a_project(const QString &projectName, const QString &parentSourceName) 0415 { 0416 auto source = dataSourceFromName(parentSourceName); 0417 VERIFY(!source.isNull()); 0418 0419 VERIFY(QMetaObject::invokeMethod(m_presentation, "addProject", 0420 Q_ARG(QString, projectName), 0421 Q_ARG(Domain::DataSource::Ptr, source))); 0422 waitForStableState(); 0423 0424 return true; 0425 } 0426 0427 bool ZanshinContext::I_add_a_context(const QString &contextName, const QString &parentSourceName) 0428 { 0429 auto source = dataSourceFromName(parentSourceName); 0430 VERIFY(!source.isNull()); 0431 0432 VERIFY(QMetaObject::invokeMethod(m_presentation, 0433 "addContext", 0434 Q_ARG(QString, contextName), 0435 Q_ARG(Domain::DataSource::Ptr, source))); 0436 waitForStableState(); 0437 0438 return true; 0439 0440 } 0441 0442 bool ZanshinContext::I_add_a_task(const QString &taskName) 0443 { 0444 waitForStableState(); 0445 0446 VERIFY(QMetaObject::invokeMethod(m_presentation, 0447 "addItem", 0448 Q_ARG(QString, taskName))); 0449 waitForStableState(); 0450 0451 return true; 0452 } 0453 0454 bool ZanshinContext::I_rename_a_page(const QString &path, const QString &oldName, const QString &newName) 0455 { 0456 const QString pageNodeName = path + " / "; 0457 0458 VERIFY(!pageNodeName.isEmpty()); 0459 0460 auto availablePages = m_appModel->property("availablePages").value<QObject*>(); 0461 VERIFY(availablePages); 0462 0463 auto pageListModel = availablePages->property("pageListModel").value<QAbstractItemModel*>(); 0464 VERIFY(pageListModel); 0465 waitForStableState(); 0466 0467 QModelIndex pageIndex = Zanshin::findIndex(pageListModel, pageNodeName + oldName); 0468 VERIFY(pageIndex.isValid()); 0469 0470 pageListModel->setData(pageIndex, newName); 0471 waitForStableState(); 0472 0473 return true; 0474 } 0475 0476 bool ZanshinContext::I_remove_a_page(const QString &path, const QString &pageName) 0477 { 0478 const QString pageNodeName = path + " / "; 0479 0480 VERIFY(!pageNodeName.isEmpty()); 0481 0482 auto availablePages = m_appModel->property("availablePages").value<QObject*>(); 0483 VERIFY(availablePages); 0484 0485 auto pageListModel = availablePages->property("pageListModel").value<QAbstractItemModel*>(); 0486 VERIFY(pageListModel); 0487 waitForStableState(); 0488 0489 QModelIndex pageIndex = Zanshin::findIndex(pageListModel, pageNodeName + pageName); 0490 VERIFY(pageIndex.isValid()); 0491 0492 VERIFY(QMetaObject::invokeMethod(availablePages, "removeItem", 0493 Q_ARG(QModelIndex, pageIndex))); 0494 waitForStableState(); 0495 0496 return true; 0497 } 0498 0499 bool ZanshinContext::I_add_a_task_child(const QString &childName, const QString &parentName) 0500 { 0501 waitForStableState(); 0502 0503 auto parentIndex = QModelIndex(); 0504 for (int row = 0; row < m_indices.size(); row++) { 0505 auto index = m_indices.at(row); 0506 if (Zanshin::indexString(index) == parentName) { 0507 parentIndex = index; 0508 break; 0509 } 0510 } 0511 0512 VERIFY_OR_DUMP(parentIndex.isValid()); 0513 0514 VERIFY(QMetaObject::invokeMethod(m_presentation, 0515 "addItem", 0516 Q_ARG(QString, childName), 0517 Q_ARG(QModelIndex, parentIndex))); 0518 waitForStableState(); 0519 0520 return true; 0521 } 0522 0523 bool ZanshinContext::I_list_the_items() 0524 { 0525 waitForStableState(); 0526 collectIndices(); 0527 waitForStableState(); 0528 0529 return true; 0530 } 0531 0532 bool ZanshinContext::I_open_the_item_in_the_editor() 0533 { 0534 auto task = currentTask(); 0535 VERIFY(!task.isNull()); 0536 m_editor = m_appModel->property("editor").value<QObject*>(); 0537 VERIFY(m_editor); 0538 VERIFY(m_editor->setProperty("task", QVariant::fromValue(task))); 0539 0540 return true; 0541 } 0542 0543 bool ZanshinContext::I_mark_the_item_done_in_the_editor() 0544 { 0545 VERIFY(m_editor->setProperty("done", true)); 0546 return true; 0547 } 0548 0549 bool ZanshinContext::I_change_the_editor_field(const QString &field, const QVariant &value) 0550 { 0551 const QByteArray property = (field == QStringLiteral("text")) ? field.toUtf8() 0552 : (field == QStringLiteral("title")) ? field.toUtf8() 0553 : (field == QStringLiteral("start date")) ? "startDate" 0554 : (field == QStringLiteral("due date")) ? "dueDate" 0555 : QByteArray(); 0556 0557 VERIFY(value.isValid()); 0558 VERIFY(!property.isEmpty()); 0559 0560 VERIFY(m_editor->setProperty("editingInProgress", true)); 0561 VERIFY(m_editor->setProperty(property, value)); 0562 0563 return true; 0564 } 0565 0566 bool ZanshinContext::I_rename_the_item(const QString &taskName) 0567 { 0568 VERIFY(m_editor->setProperty("editingInProgress", false)); 0569 VERIFY(model()->setData(m_index, taskName, Qt::EditRole)); 0570 waitForStableState(); 0571 0572 return true; 0573 } 0574 0575 bool ZanshinContext::I_open_the_item_in_the_editor_again() 0576 { 0577 auto task = currentTask(); 0578 VERIFY(!task.isNull()); 0579 VERIFY(m_editor->setProperty("task", QVariant::fromValue(Domain::Task::Ptr()))); 0580 VERIFY(m_editor->setProperty("task", QVariant::fromValue(task))); 0581 waitForStableState(); 0582 0583 return true; 0584 } 0585 0586 bool ZanshinContext::I_drop_the_item_on_the_central_list(const QString &dropSiteName) 0587 { 0588 VERIFY(m_index.isValid()); 0589 const QMimeData *data = model()->mimeData(QModelIndexList() << m_index); 0590 0591 QAbstractItemModel *destModel = model(); 0592 QModelIndex dropIndex = Zanshin::findIndex(destModel, dropSiteName); 0593 VERIFY(dropIndex.isValid()); 0594 VERIFY(destModel->dropMimeData(data, Qt::MoveAction, -1, -1, dropIndex)); 0595 waitForStableState(); 0596 0597 return true; 0598 } 0599 0600 bool ZanshinContext::I_drop_the_item_on_the_blank_area_of_the_central_list() 0601 { 0602 VERIFY(m_index.isValid()); 0603 const QMimeData *data = model()->mimeData(QModelIndexList() << m_index); 0604 0605 QAbstractItemModel *destModel = model(); 0606 VERIFY(destModel->dropMimeData(data, Qt::MoveAction, -1, -1, QModelIndex())); 0607 waitForStableState(); 0608 0609 return true; 0610 } 0611 0612 bool ZanshinContext::I_drop_items_on_the_central_list(const QString &dropSiteName) 0613 { 0614 VERIFY(!m_dragIndices.isEmpty()); 0615 QModelIndexList indexes; 0616 bool allValid = true; 0617 std::transform(m_dragIndices.constBegin(), m_dragIndices.constEnd(), 0618 std::back_inserter(indexes), 0619 [&allValid] (const QPersistentModelIndex &index) { 0620 allValid &= index.isValid(); 0621 return index; 0622 }); 0623 VERIFY(allValid); 0624 0625 const QMimeData *data = model()->mimeData(indexes); 0626 0627 QAbstractItemModel *destModel = model(); 0628 QModelIndex dropIndex = Zanshin::findIndex(destModel, dropSiteName); 0629 VERIFY(dropIndex.isValid()); 0630 VERIFY(destModel->dropMimeData(data, Qt::MoveAction, -1, -1, dropIndex)); 0631 waitForStableState(); 0632 0633 return true; 0634 } 0635 0636 bool ZanshinContext::I_drop_the_item_on_the_page_list(const QString &pageName) 0637 { 0638 VERIFY(m_index.isValid()); 0639 const QMimeData *data = model()->mimeData(QModelIndexList() << m_index); 0640 0641 auto availablePages = m_appModel->property("availablePages").value<QObject*>(); 0642 VERIFY(availablePages); 0643 0644 auto destModel = availablePages->property("pageListModel").value<QAbstractItemModel*>(); 0645 VERIFY(destModel); 0646 waitForStableState(); 0647 0648 QModelIndex dropIndex = Zanshin::findIndex(destModel, pageName); 0649 VERIFY(dropIndex.isValid()); 0650 VERIFY(destModel->dropMimeData(data, Qt::MoveAction, -1, -1, dropIndex)); 0651 waitForStableState(); 0652 0653 return true; 0654 } 0655 0656 bool ZanshinContext::I_drop_items_on_the_page_list(const QString &pageName) 0657 { 0658 VERIFY(!m_dragIndices.isEmpty()); 0659 QModelIndexList indexes; 0660 bool allValid = true; 0661 std::transform(m_dragIndices.constBegin(), m_dragIndices.constEnd(), 0662 std::back_inserter(indexes), 0663 [&allValid] (const QPersistentModelIndex &index) { 0664 allValid &= index.isValid(); 0665 return index; 0666 }); 0667 VERIFY(allValid); 0668 0669 const QMimeData *data = model()->mimeData(indexes); 0670 0671 auto availablePages = m_appModel->property("availablePages").value<QObject*>(); 0672 VERIFY(availablePages); 0673 0674 auto destModel = availablePages->property("pageListModel").value<QAbstractItemModel*>(); 0675 VERIFY(destModel); 0676 waitForStableState(); 0677 0678 QModelIndex dropIndex = Zanshin::findIndex(destModel, pageName); 0679 VERIFY(dropIndex.isValid()); 0680 VERIFY(destModel->dropMimeData(data, Qt::MoveAction, -1, -1, dropIndex)); 0681 waitForStableState(); 0682 0683 return true; 0684 } 0685 0686 bool ZanshinContext::I_change_the_setting(const QString &key, qint64 id) 0687 { 0688 KConfigGroup config(KSharedConfig::openConfig(), "General"); 0689 config.writeEntry(key, id); 0690 return true; 0691 } 0692 0693 bool ZanshinContext::I_change_the_default_data_source(const QString &sourceName) 0694 { 0695 waitForStableState(); 0696 auto sourceIndex = Zanshin::findIndex(model(), sourceName); 0697 auto availableSources = m_appModel->property("availableSources").value<QObject*>(); 0698 VERIFY(availableSources); 0699 VERIFY(QMetaObject::invokeMethod(availableSources, "setDefaultItem", Q_ARG(QModelIndex, sourceIndex))); 0700 waitForStableState(); 0701 0702 return true; 0703 } 0704 0705 bool ZanshinContext::the_list_is(const TableData &data) 0706 { 0707 auto roleNames = model()->roleNames(); 0708 QList<int> usedRoles; 0709 0710 for (const auto &roleName : data.roles) { 0711 const int role = roleNames.key(roleName, -1); 0712 VERIFY_OR_DUMP(role != -1 && !usedRoles.contains(role)); 0713 usedRoles << role; 0714 } 0715 0716 QStandardItemModel inputModel; 0717 for (const auto &row : data.rows) { 0718 VERIFY_OR_DUMP(usedRoles.size() == row.size()); 0719 0720 QStandardItem *item = new QStandardItem; 0721 for (int i = 0; i < row.size(); ++i) { 0722 const auto role = usedRoles.at(i); 0723 const auto value = row.at(i); 0724 item->setData(value, role); 0725 } 0726 inputModel.appendRow(item); 0727 } 0728 0729 QSortFilterProxyModel proxy; 0730 0731 QAbstractItemModel *referenceModel; 0732 if (!qobject_cast<QSortFilterProxyModel *>(sourceModel())) { 0733 referenceModel = &proxy; 0734 proxy.setSourceModel(&inputModel); 0735 proxy.setSortRole(Qt::DisplayRole); 0736 proxy.sort(0); 0737 proxy.setObjectName(QLatin1StringView("the_list_is_proxy")); 0738 } else { 0739 referenceModel = &inputModel; 0740 } 0741 0742 for (int row = 0; row < m_indices.size(); row++) { 0743 QModelIndex expectedIndex = referenceModel->index(row, 0); 0744 QModelIndex resultIndex = m_indices.at(row); 0745 0746 foreach (const auto &role, usedRoles) { 0747 COMPARE_OR_DUMP(Zanshin::indexString(resultIndex, role), 0748 Zanshin::indexString(expectedIndex, role)); 0749 } 0750 } 0751 COMPARE_OR_DUMP((int)m_indices.size(), referenceModel->rowCount()); 0752 0753 return true; 0754 } 0755 0756 bool ZanshinContext::the_list_contains(const QString &itemName) 0757 { 0758 for (int row = 0; row < m_indices.size(); row++) { 0759 if (Zanshin::indexString(m_indices.at(row)) == itemName) 0760 return true; 0761 } 0762 0763 VERIFY_OR_DUMP(false); 0764 return false; 0765 } 0766 0767 bool ZanshinContext::the_list_does_not_contain(const QString &itemName) 0768 { 0769 for (int row = 0; row < m_indices.size(); row++) { 0770 VERIFY_OR_DUMP(Zanshin::indexString(m_indices.at(row)) != itemName); 0771 } 0772 0773 return true; 0774 } 0775 0776 bool ZanshinContext::the_task_corresponding_to_the_item_is_done() 0777 { 0778 auto task = currentTask(); 0779 VERIFY(!task.isNull()); 0780 VERIFY(task->isDone()); 0781 0782 return true; 0783 } 0784 0785 bool ZanshinContext::the_editor_shows_the_task_as_done() 0786 { 0787 VERIFY(m_editor->property("done").toBool()); 0788 return true; 0789 } 0790 0791 bool ZanshinContext::the_editor_shows_the_field(const QString &field, const QVariant &expectedValue) 0792 { 0793 const QByteArray property = (field == QStringLiteral("text")) ? field.toUtf8() 0794 : (field == QStringLiteral("title")) ? field.toUtf8() 0795 : (field == QStringLiteral("start date")) ? "startDate" 0796 : (field == QStringLiteral("due date")) ? "dueDate" 0797 : QByteArray(); 0798 0799 VERIFY(expectedValue.isValid()); 0800 VERIFY(!property.isEmpty()); 0801 0802 COMPARE(m_editor->property(property), expectedValue); 0803 0804 return true; 0805 } 0806 0807 bool ZanshinContext::the_default_data_source_is(const QString &expectedName) 0808 { 0809 waitForStableState(); 0810 auto expectedIndex = Zanshin::findIndex(model(), expectedName); 0811 VERIFY(expectedIndex.isValid()); 0812 auto defaultRole = model()->roleNames().key("default", -1); 0813 VERIFY(expectedIndex.data(defaultRole).toBool()); 0814 0815 return true; 0816 } 0817 0818 bool ZanshinContext::the_setting_is(const QString &key, qint64 expectedId) 0819 { 0820 KConfigGroup config(KSharedConfig::openConfig(), "General"); 0821 const qint64 id = config.readEntry(key, -1); 0822 COMPARE(id, expectedId); 0823 0824 return true; 0825 } 0826 0827 Domain::DataSource::Ptr ZanshinContext::dataSourceFromName(const QString &sourceName) 0828 { 0829 auto availableSources = m_appModel->property("availableSources").value<QObject*>(); 0830 if (!availableSources) 0831 return nullptr; 0832 auto sourceList = availableSources->property("sourceListModel").value<QAbstractItemModel*>(); 0833 if (!sourceList) 0834 return nullptr; 0835 waitForStableState(); 0836 QModelIndex index = Zanshin::findIndex(sourceList, sourceName); 0837 if (!index.isValid()) { 0838 qWarning() << "source" << sourceName << "not found."; 0839 for (int row = 0; row < sourceList->rowCount(); row++) { 0840 qDebug() << sourceList->index(row, 0).data().toString(); 0841 } 0842 return nullptr; 0843 } 0844 return index.data(Presentation::QueryTreeModelBase::ObjectRole) 0845 .value<Domain::DataSource::Ptr>(); 0846 } 0847 0848 #include "moc_zanshincontext.cpp"