diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e19fb870..095111f9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,15 +1,16 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) # icons add_subdirectory(icons) # frontends add_subdirectory(zanshin) # modules add_subdirectory(akonadi) add_subdirectory(domain) add_subdirectory(presentation) +add_subdirectory(integration) add_subdirectory(utils) add_subdirectory(widgets) diff --git a/src/integration/CMakeLists.txt b/src/integration/CMakeLists.txt new file mode 100644 index 00000000..c9e6974d --- /dev/null +++ b/src/integration/CMakeLists.txt @@ -0,0 +1,11 @@ +set(integration_SRCS + dependencies.cpp +) + +add_library(integration STATIC ${integration_SRCS}) +target_link_libraries(integration + akonadi + domain + presentation + utils +) diff --git a/src/zanshin/app/dependencies.cpp b/src/integration/dependencies.cpp similarity index 99% rename from src/zanshin/app/dependencies.cpp rename to src/integration/dependencies.cpp index f566cd70..8c2ec5b2 100644 --- a/src/zanshin/app/dependencies.cpp +++ b/src/integration/dependencies.cpp @@ -1,126 +1,126 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "dependencies.h" #include "akonadi/akonadicontextqueries.h" #include "akonadi/akonadicontextrepository.h" #include "akonadi/akonadidatasourcequeries.h" #include "akonadi/akonadidatasourcerepository.h" #include "akonadi/akonadiprojectqueries.h" #include "akonadi/akonadiprojectrepository.h" #include "akonadi/akonaditaskqueries.h" #include "akonadi/akonaditaskrepository.h" #include "akonadi/akonadicache.h" #include "akonadi/akonadicachingstorage.h" #include "akonadi/akonadimonitorimpl.h" #include "akonadi/akonadiserializer.h" #include "akonadi/akonadistorage.h" #include "presentation/availablepagesmodel.h" #include "presentation/availablesourcesmodel.h" #include "presentation/editormodel.h" #include "presentation/runningtaskmodel.h" #include "utils/dependencymanager.h" -void App::initializeDependencies() +void Integration::initializeGlobalAppDependencies() { auto &deps = Utils::DependencyManager::globalInstance(); deps.add(); deps.add(); deps.add(); deps.add([] (Utils::DependencyManager *deps) { return new Akonadi::CachingStorage(deps->create(), Akonadi::StorageInterface::Ptr(new Akonadi::Storage)); }); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add(); deps.add([] (Utils::DependencyManager *deps) { auto model = new Presentation::EditorModel; auto repository = deps->create(); model->setSaveFunction([repository] (const Domain::Task::Ptr &task) { Q_ASSERT(task); return repository->update(task); }); return model; }); deps.add(); deps.add(); deps.add(); } diff --git a/src/zanshin/app/dependencies.h b/src/integration/dependencies.h similarity index 88% rename from src/zanshin/app/dependencies.h rename to src/integration/dependencies.h index e9683c86..79c49b88 100644 --- a/src/zanshin/app/dependencies.h +++ b/src/integration/dependencies.h @@ -1,33 +1,33 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef APP_DEPENDENCIES_H -#define APP_DEPENDENCIES_H +#ifndef INTEGRATION_DEPENDENCIES_H +#define INTEGRATION_DEPENDENCIES_H -namespace App +namespace Integration { - void initializeDependencies(); + void initializeGlobalAppDependencies(); } #endif diff --git a/src/zanshin/app/CMakeLists.txt b/src/zanshin/app/CMakeLists.txt index c1230f17..b2f9c60b 100644 --- a/src/zanshin/app/CMakeLists.txt +++ b/src/zanshin/app/CMakeLists.txt @@ -1,22 +1,18 @@ set(app_SRCS aboutdata.cpp - dependencies.cpp main.cpp ) ecm_create_qm_loader(app_SRCS zanshin_qt) qt5_add_resources(app_SRCS zanshin.qrc) add_executable(zanshin ${app_SRCS}) kde_enable_exceptions() target_link_libraries(zanshin KF5::XmlGui - akonadi - domain - presentation - utils + integration widgets ) install(TARGETS zanshin DESTINATION ${KDE_INSTALL_BINDIR}) install(PROGRAMS org.kde.zanshin.desktop DESTINATION ${KDE_INSTALL_APPDIR}) install(FILES org.kde.zanshin.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR}) diff --git a/src/zanshin/app/main.cpp b/src/zanshin/app/main.cpp index a10dfa31..30db0c2a 100644 --- a/src/zanshin/app/main.cpp +++ b/src/zanshin/app/main.cpp @@ -1,148 +1,148 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include "widgets/applicationcomponents.h" #include "widgets/availablepagesview.h" #include "widgets/availablesourcesview.h" #include "widgets/editorview.h" #include "widgets/pageview.h" #include "presentation/applicationmodel.h" #include "utils/dependencymanager.h" +#include "integration/dependencies.h" #include "aboutdata.h" -#include "dependencies.h" #include #include #include #include int main(int argc, char **argv) { KLocalizedString::setApplicationDomain("zanshin"); QApplication app(argc, argv); - App::initializeDependencies(); + Integration::initializeGlobalAppDependencies(); auto aboutData = App::getAboutData(); QCommandLineParser parser; KAboutData::setApplicationData(aboutData); parser.addVersionOption(); parser.addHelpOption(); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); KSharedConfig::Ptr config = KSharedConfig::openConfig(QStringLiteral("zanshin-migratorrc")); KConfigGroup group = config->group("Migrations"); if (!group.readEntry("MigratedTags", false)) { std::cerr << "Migrating tags, please wait..." << std::endl; QProcess proc; proc.start(QStringLiteral("zanshin-migrator")); proc.waitForFinished(-1); if (proc.exitStatus() == QProcess::CrashExit) { std::cerr << "Migrator crashed!" << std::endl; } else if (proc.exitCode() == 0) { std::cerr << "Migration done" << std::endl; } else { std::cerr << "Migration error, code" << proc.exitCode() << std::endl; } } auto widget = new QWidget; auto components = new Widgets::ApplicationComponents(widget); components->setModel(Presentation::ApplicationModel::Ptr::create()); auto layout = new QVBoxLayout; layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(components->pageView()); widget->setLayout(layout); auto sourcesDock = new QDockWidget(i18n("Sources")); sourcesDock->setObjectName(QStringLiteral("sourcesDock")); sourcesDock->setWidget(components->availableSourcesView()); auto pagesDock = new QDockWidget(i18n("Pages")); pagesDock->setObjectName(QStringLiteral("pagesDock")); pagesDock->setWidget(components->availablePagesView()); auto editorDock = new QDockWidget(i18n("Editor")); editorDock->setObjectName(QStringLiteral("editorDock")); editorDock->setWidget(components->editorView()); auto window = new KXmlGuiWindow; window->setCentralWidget(widget); window->addDockWidget(Qt::RightDockWidgetArea, editorDock); window->addDockWidget(Qt::LeftDockWidgetArea, pagesDock); window->addDockWidget(Qt::LeftDockWidgetArea, sourcesDock); auto actions = components->globalActions(); actions.insert(QStringLiteral("dock_sources"), sourcesDock->toggleViewAction()); actions.insert(QStringLiteral("dock_pages"), pagesDock->toggleViewAction()); actions.insert(QStringLiteral("dock_editor"), editorDock->toggleViewAction()); auto ac = window->actionCollection(); ac->addAction(KStandardAction::Quit, window, SLOT(close())); for (auto it = actions.constBegin(); it != actions.constEnd(); ++it) { auto shortcut = it.value()->shortcut(); if (!shortcut.isEmpty()) { ac->setDefaultShortcut(it.value(), shortcut); } ac->addAction(it.key(), it.value()); } window->setupGUI(QSize(1024, 600), KXmlGuiWindow::ToolBar | KXmlGuiWindow::Keys | KXmlGuiWindow::Save | KXmlGuiWindow::Create); delete window->findChild("help_contents"); delete window->findChild("help_whats_this"); window->show(); { auto &deps = Utils::DependencyManager::globalInstance(); auto repo = deps.create(); repo->windowNeedsDataBackend(window); } return app.exec(); } diff --git a/src/zanshin/kontact/CMakeLists.txt b/src/zanshin/kontact/CMakeLists.txt index 6be58c01..60913156 100644 --- a/src/zanshin/kontact/CMakeLists.txt +++ b/src/zanshin/kontact/CMakeLists.txt @@ -1,33 +1,29 @@ set(part_SRCS ../app/aboutdata.cpp - ../app/dependencies.cpp part.cpp ) add_library(zanshin_part MODULE ${part_SRCS}) kde_enable_exceptions() target_link_libraries(zanshin_part KF5::Parts - akonadi - domain - presentation - utils + integration widgets ) install(TARGETS zanshin_part DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(FILES zanshin_part.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}) ########################## set(kontact_SRCS kontact_plugin.cpp ) add_library(kontact_zanshinplugin MODULE ${kontact_SRCS}) target_link_libraries(kontact_zanshinplugin KF5::Parts KF5::KontactInterface) install(TARGETS kontact_zanshinplugin DESTINATION ${KDE_INSTALL_PLUGINDIR}) install(FILES zanshin_plugin.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR}/kontact) install(FILES zanshin_part.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/zanshin) diff --git a/src/zanshin/kontact/part.cpp b/src/zanshin/kontact/part.cpp index 56aefa61..64ddf0ad 100644 --- a/src/zanshin/kontact/part.cpp +++ b/src/zanshin/kontact/part.cpp @@ -1,92 +1,92 @@ /* This file is part of Zanshin Copyright 2011 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "part.h" #include #include #include #include #include #include #include "../app/aboutdata.h" -#include "../app/dependencies.h" #include "presentation/applicationmodel.h" #include "widgets/applicationcomponents.h" #include "widgets/availablepagesview.h" #include "widgets/availablesourcesview.h" #include "widgets/editorview.h" #include "widgets/pageview.h" #include "utils/dependencymanager.h" +#include "integration/dependencies.h" K_PLUGIN_FACTORY(PartFactory, registerPlugin();) Part::Part(QWidget *parentWidget, QObject *parent, const QVariantList &) : KParts::ReadOnlyPart(parent) { - App::initializeDependencies(); + Integration::initializeGlobalAppDependencies(); setComponentName(QStringLiteral("zanshin"), QStringLiteral("zanshin")); auto splitter = new QSplitter(parentWidget); auto sidebar = new QSplitter(Qt::Vertical, parentWidget); auto components = new Widgets::ApplicationComponents(parentWidget); components->setModel(Presentation::ApplicationModel::Ptr::create()); sidebar->addWidget(components->availablePagesView()); sidebar->addWidget(components->availableSourcesView()); splitter->addWidget(sidebar); splitter->addWidget(components->pageView()); splitter->addWidget(components->editorView()); setWidget(splitter); auto actions = components->globalActions(); auto ac = actionCollection(); for (auto it = actions.constBegin(); it != actions.constEnd(); ++it) { auto shortcut = it.value()->shortcut(); if (!shortcut.isEmpty()) { ac->setDefaultShortcut(it.value(), shortcut); } ac->addAction(it.key(), it.value()); } setXMLFile(QStringLiteral("zanshin_part.rc"), true); } Part::~Part() { } bool Part::openFile() { return false; } #include "part.moc" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6186ce30..7093ee38 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -1,91 +1,82 @@ include_directories(${CMAKE_SOURCE_DIR}/src) include_directories(${CMAKE_SOURCE_DIR}/3rdparty) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/testlib") MACRO(ZANSHIN_MANUAL_TESTS) set(prefix "${CMAKE_CURRENT_SOURCE_DIR}") string(REPLACE "${CMAKE_SOURCE_DIR}" "" prefix "${prefix}") string(REPLACE "/" "-" prefix "${prefix}") string(REPLACE "\\" "-" prefix "${prefix}") string(LENGTH "${prefix}" prefix_length) string(SUBSTRING "${prefix}" 1 ${prefix_length}-1 prefix) FOREACH(_testname ${ARGN}) set(_prefixed_testname "${prefix}-${_testname}") - add_executable(${_prefixed_testname} ${_testname}.cpp ${CMAKE_SOURCE_DIR}/src/zanshin/app/dependencies.cpp) + add_executable(${_prefixed_testname} ${_testname}.cpp) kde_enable_exceptions() target_link_libraries(${_prefixed_testname} Qt5::Test - akonadi - domain - presentation - utils + integration widgets ) ENDFOREACH(_testname) ENDMACRO(ZANSHIN_MANUAL_TESTS) MACRO(ZANSHIN_AUTO_TESTS) set(prefix "${CMAKE_CURRENT_SOURCE_DIR}") string(REPLACE "${CMAKE_SOURCE_DIR}" "" prefix "${prefix}") string(REPLACE "/" "-" prefix "${prefix}") string(REPLACE "\\" "-" prefix "${prefix}") string(LENGTH "${prefix}" prefix_length) string(SUBSTRING "${prefix}" 1 ${prefix_length}-1 prefix) FOREACH(_testname ${ARGN}) set(_prefixed_testname "${prefix}-${_testname}") add_executable(${_prefixed_testname} ${_testname}.cpp) add_test(NAME ${_prefixed_testname} COMMAND ${_prefixed_testname}) kde_enable_exceptions() target_link_libraries(${_prefixed_testname} Qt5::Test testlib - akonadi - domain - presentation - utils + integration widgets KF5::AkonadiXml ) ENDFOREACH(_testname) ENDMACRO(ZANSHIN_AUTO_TESTS) MACRO(ZANSHIN_FEATURE_TESTS) set(prefix "${CMAKE_CURRENT_SOURCE_DIR}") string(REPLACE "${CMAKE_SOURCE_DIR}" "" prefix "${prefix}") string(REPLACE "/" "-" prefix "${prefix}") string(REPLACE "\\" "-" prefix "${prefix}") string(LENGTH "${prefix}" prefix_length) string(SUBSTRING "${prefix}" 1 ${prefix_length}-1 prefix) FOREACH(_testname ${ARGN}) set(_prefixed_testname "${prefix}-${_testname}") add_executable(${_prefixed_testname} ${_testname}.cpp) add_test(NAME ${_prefixed_testname} COMMAND ${_prefixed_testname}) kde_enable_exceptions() target_link_libraries(${_prefixed_testname} Qt5::Test featurelib testlib - akonadi - domain - presentation - utils + integration widgets KF5::AkonadiXml ) ENDFOREACH(_testname) ENDMACRO(ZANSHIN_FEATURE_TESTS) add_subdirectory(featurelib) add_subdirectory(features) add_subdirectory(manual) add_subdirectory(benchmarks) add_subdirectory(testlib) add_subdirectory(units) diff --git a/tests/featurelib/CMakeLists.txt b/tests/featurelib/CMakeLists.txt index cb3c9863..aafbf817 100644 --- a/tests/featurelib/CMakeLists.txt +++ b/tests/featurelib/CMakeLists.txt @@ -1,15 +1,14 @@ set(featurelib_SRCS zanshincontext.cpp - "${CMAKE_SOURCE_DIR}/src/zanshin/app/dependencies.cpp" ) add_definitions(-DZANSHIN_USER_XMLDATA="${CMAKE_SOURCE_DIR}/tests/features/testenv/data/testdata.xml") include_directories(${CMAKE_SOURCE_DIR}/tests ${CMAKE_SOURCE_DIR}/src) add_library(featurelib STATIC ${featurelib_SRCS}) target_link_libraries(featurelib Qt5::Test KF5::ConfigCore - presentation + integration ) diff --git a/tests/featurelib/zanshincontext.cpp b/tests/featurelib/zanshincontext.cpp index 5a3cfb00..2a396c23 100644 --- a/tests/featurelib/zanshincontext.cpp +++ b/tests/featurelib/zanshincontext.cpp @@ -1,868 +1,864 @@ /* This file is part of Zanshin Copyright 2014-2019 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "zanshincontext.h" #include "akonadi/akonadiapplicationselectedattribute.h" #include "akonadi/akonadicachingstorage.h" #include "akonadi/akonadistorageinterface.h" #include "akonadi/akonaditimestampattribute.h" #include "presentation/applicationmodel.h" #include "presentation/errorhandler.h" #include "presentation/querytreemodelbase.h" #include "testlib/akonadifakedataxmlloader.h" #include "testlib/monitorspy.h" #include "utils/dependencymanager.h" #include "utils/jobhandler.h" +#include "integration/dependencies.h" #include #include #include #include #include #include -namespace App -{ - void initializeDependencies(); -} - void FakeErrorHandler::doDisplayMessage(const QString &) { } ZanshinContext::ZanshinContext(QObject *parent) : QObject(parent), m_presentation(nullptr), m_editor(nullptr), m_proxyModel(new QSortFilterProxyModel(this)), m_model(nullptr), m_sourceModel(nullptr), m_monitorSpy(nullptr) { qputenv("ZANSHIN_OVERRIDE_DATE", "2015-03-10"); static bool initializedDependencies = false; if (!initializedDependencies) { - App::initializeDependencies(); + Integration::initializeGlobalAppDependencies(); MonitorSpy::setExpirationDelay(200); initializedDependencies = true; } Akonadi::AttributeFactory::registerAttribute(); Akonadi::AttributeFactory::registerAttribute(); const auto xmlFile = QString::fromLocal8Bit(ZANSHIN_USER_XMLDATA); if (xmlFile.isEmpty()) { qDebug() << "FATAL ERROR! ZANSHIN_USER_XMLDATA WAS NOT PROVIDED\n\n"; exit(1); } auto searchCollection = Akonadi::Collection(1); searchCollection.setParentCollection(Akonadi::Collection::root()); searchCollection.setName(QStringLiteral("Search")); m_data.createCollection(searchCollection); auto loader = Testlib::AkonadiFakeDataXmlLoader(&m_data); loader.load(xmlFile); // Sanity checks QVERIFY(m_data.collections().size() > 1); QVERIFY(m_data.items().size() > 1); QVERIFY(m_data.contexts().size() > 1); // Swap regular dependencies for the fake data ones auto &deps = Utils::DependencyManager::globalInstance(); deps.add( [this] (Utils::DependencyManager *) { return m_data.createMonitor(); } ); deps.add( [this] (Utils::DependencyManager *deps) { return new Akonadi::CachingStorage(deps->create(), Akonadi::StorageInterface::Ptr(m_data.createStorage())); } ); using namespace Presentation; m_proxyModel->setDynamicSortFilter(true); auto appModel = ApplicationModel::Ptr::create(); appModel->setErrorHandler(&m_errorHandler); m_appModel = appModel; auto monitor = Utils::DependencyManager::globalInstance().create(); m_monitorSpy = new MonitorSpy(monitor.data(), this); } // Note that setModel might invalidate the 'index' member variable, due to proxyModel->setSourceModel. void ZanshinContext::setModel(QAbstractItemModel *model) { if (m_sourceModel == model) return; m_sourceModel = model; if (!qobject_cast(model)) { m_proxyModel->setObjectName(QStringLiteral("m_proxyModel_in_ZanshinContext")); m_proxyModel->setSourceModel(model); m_proxyModel->setSortRole(Qt::DisplayRole); m_proxyModel->sort(0); m_model = m_proxyModel; } else { m_model = model; } } QAbstractItemModel *ZanshinContext::sourceModel() const { return m_sourceModel; } QAbstractItemModel *ZanshinContext::model() const { return m_model; } Domain::Task::Ptr ZanshinContext::currentTask() const { return m_index.data(Presentation::QueryTreeModelBase::ObjectRole) .value(); } void ZanshinContext::waitForEmptyJobQueue() { while (Utils::JobHandler::jobCount() != 0) { QTest::qWait(20); } } void ZanshinContext::waitForStableState() { waitForEmptyJobQueue(); m_monitorSpy->waitForStableState(); } void ZanshinContext::collectIndicesImpl(const QModelIndex &root) { QAbstractItemModel *model = m_model; for (int row = 0; row < model->rowCount(root); row++) { const QModelIndex index = model->index(row, 0, root); m_indices << index; if (model->rowCount(index) > 0) collectIndicesImpl(index); } } void ZanshinContext::collectIndices() { m_indices.clear(); collectIndicesImpl(); } namespace Zanshin { QString indexString(const QModelIndex &index, int role = Qt::DisplayRole) { if (role != Qt::DisplayRole) return index.data(role).toString(); QString data = index.data(role).toString(); if (index.parent().isValid()) return indexString(index.parent(), role) + " / " + data; else return data; } QModelIndex findIndex(QAbstractItemModel *model, const QString &string, int role = Qt::DisplayRole, const QModelIndex &root = QModelIndex()) { for (int row = 0; row < model->rowCount(root); row++) { const QModelIndex index = model->index(row, 0, root); if (indexString(index, role) == string) return index; if (model->rowCount(index) > 0) { const QModelIndex found = findIndex(model, string, role, index); if (found.isValid()) return found; } } return QModelIndex(); } void dumpIndices(const QList &indices) { qDebug() << "Dumping list of size:" << indices.size(); for (int row = 0; row < indices.size(); row++) { qDebug() << row << indexString(indices.at(row)); } } inline bool verify(bool statement, const char *str, const char *file, int line) { if (statement) return true; qDebug() << "Statement" << str << "returned FALSE"; qDebug() << "Loc:" << file << line; return false; } template inline bool compare(T const &t1, T const &t2, const char *actual, const char *expected, const char *file, int line) { if (t1 == t2) return true; qDebug() << "Compared values are not the same"; qDebug() << "Actual (" << actual << ") :" << QTest::toString(t1); qDebug() << "Expected (" << expected << ") :" << QTest::toString(t2); qDebug() << "Loc:" << file << line; return false; } } // namespace Zanshin #define COMPARE(actual, expected) \ do {\ if (!Zanshin::compare(actual, expected, #actual, #expected, __FILE__, __LINE__))\ return false;\ } while (0) // Note: you should make sure that m_indices is filled in before calling this, // e.g. calling Zanshin::collectIndices(context.get()) if not already done. #define COMPARE_OR_DUMP(actual, expected) \ do {\ if (!Zanshin::compare(actual, expected, #actual, #expected, __FILE__, __LINE__)) {\ Zanshin::dumpIndices(m_indices); \ return false;\ }\ } while (0) #define VERIFY(statement) \ do {\ if (!Zanshin::verify((statement), #statement, __FILE__, __LINE__))\ return false;\ } while (0) // Note: you should make sure that m_indices is filled in before calling this, // e.g. calling Zanshin::collectIndices(context.get()) if not already done. #define VERIFY_OR_DUMP(statement) \ do {\ if (!Zanshin::verify((statement), #statement, __FILE__, __LINE__)) {\ Zanshin::dumpIndices(m_indices); \ return false;\ }\ } while (0) #define VERIFY_OR_DO(statement, whatToDo) \ do {\ if (!Zanshin::verify((statement), #statement, __FILE__, __LINE__)) {\ whatToDo; \ return false;\ }\ } while (0) bool ZanshinContext::I_display_the_available_data_sources() { auto availableSources = m_appModel->property("availableSources").value(); VERIFY(availableSources); auto sourceListModel = availableSources->property("sourceListModel").value(); VERIFY(sourceListModel); m_presentation = availableSources; setModel(sourceListModel); return true; } bool ZanshinContext::I_display_the_available_pages() { m_presentation = m_appModel->property("availablePages").value(); setModel(m_presentation->property("pageListModel").value()); return true; } bool ZanshinContext::I_display_the_page(const QString &pageName) { if (m_editor) { // save pending changes VERIFY(m_editor->setProperty("task", QVariant::fromValue(Domain::Task::Ptr()))); } auto availablePages = m_appModel->property("availablePages").value(); VERIFY(availablePages); auto pageListModel = availablePages->property("pageListModel").value(); VERIFY(pageListModel); waitForEmptyJobQueue(); QModelIndex pageIndex = Zanshin::findIndex(pageListModel, pageName); VERIFY_OR_DUMP(pageIndex.isValid()); QObject *page = nullptr; QMetaObject::invokeMethod(availablePages, "createPageForIndex", Q_RETURN_ARG(QObject*, page), Q_ARG(QModelIndex, pageIndex)); VERIFY(page); VERIFY(m_appModel->setProperty("currentPage", QVariant::fromValue(page))); m_presentation = m_appModel->property("currentPage").value(); return true; } bool ZanshinContext::there_is_an_item_in_the_central_list(const QString &taskName) { auto m = m_presentation->property("centralListModel").value(); setModel(m); waitForEmptyJobQueue(); collectIndices(); m_index = Zanshin::findIndex(model(), taskName); VERIFY_OR_DUMP(m_index.isValid()); return true; } bool ZanshinContext::there_is_an_item_in_the_available_data_sources(const QString &sourceName) { auto availableSources = m_appModel->property("availableSources").value(); VERIFY(availableSources); auto m = availableSources->property("sourceListModel").value(); VERIFY(m); waitForEmptyJobQueue(); setModel(m); collectIndices(); m_index = Zanshin::findIndex(model(), sourceName); VERIFY_OR_DUMP(m_index.isValid()); return true; } bool ZanshinContext::the_central_list_contains_items_named(const QStringList &taskNames) { m_dragIndices.clear(); auto m = m_presentation->property("centralListModel").value(); waitForEmptyJobQueue(); setModel(m); for (const auto &taskName : taskNames) { QModelIndex index = Zanshin::findIndex(model(), taskName); VERIFY_OR_DO(index.isValid(), Zanshin::dumpIndices(m_dragIndices)); m_dragIndices << index; } return true; } bool ZanshinContext::I_look_at_the_central_list() { auto m = m_presentation->property("centralListModel").value(); setModel(m); waitForStableState(); return true; } bool ZanshinContext::I_check_the_item() { VERIFY(model()->setData(m_index, Qt::Checked, Qt::CheckStateRole)); waitForStableState(); return true; } bool ZanshinContext::I_uncheck_the_item() { VERIFY(model()->setData(m_index, Qt::Unchecked, Qt::CheckStateRole)); waitForStableState(); return true; } bool ZanshinContext::I_remove_the_item() { VERIFY(QMetaObject::invokeMethod(m_presentation, "removeItem", Q_ARG(QModelIndex, m_index))); waitForStableState(); return true; } bool ZanshinContext::I_promote_the_item() { VERIFY(QMetaObject::invokeMethod(m_presentation, "promoteItem", Q_ARG(QModelIndex, m_index))); waitForStableState(); return true; } bool ZanshinContext::I_add_a_project(const QString &projectName, const QString &parentSourceName) { auto source = dataSourceFromName(parentSourceName); VERIFY(source); VERIFY(QMetaObject::invokeMethod(m_presentation, "addProject", Q_ARG(QString, projectName), Q_ARG(Domain::DataSource::Ptr, source))); waitForStableState(); return true; } bool ZanshinContext::I_add_a_context(const QString &contextName, const QString &parentSourceName) { auto source = dataSourceFromName(parentSourceName); VERIFY(source); VERIFY(QMetaObject::invokeMethod(m_presentation, "addContext", Q_ARG(QString, contextName), Q_ARG(Domain::DataSource::Ptr, source))); waitForStableState(); return true; } bool ZanshinContext::I_add_a_task(const QString &taskName) { waitForStableState(); VERIFY(QMetaObject::invokeMethod(m_presentation, "addItem", Q_ARG(QString, taskName))); waitForStableState(); return true; } bool ZanshinContext::I_rename_a_page(const QString &path, const QString &oldName, const QString &newName) { const QString pageNodeName = path + " / "; VERIFY(!pageNodeName.isEmpty()); auto availablePages = m_appModel->property("availablePages").value(); VERIFY(availablePages); auto pageListModel = availablePages->property("pageListModel").value(); VERIFY(pageListModel); waitForStableState(); QModelIndex pageIndex = Zanshin::findIndex(pageListModel, pageNodeName + oldName); VERIFY(pageIndex.isValid()); pageListModel->setData(pageIndex, newName); waitForStableState(); return true; } bool ZanshinContext::I_remove_a_page(const QString &path, const QString &pageName) { const QString pageNodeName = path + " / "; VERIFY(!pageNodeName.isEmpty()); auto availablePages = m_appModel->property("availablePages").value(); VERIFY(availablePages); auto pageListModel = availablePages->property("pageListModel").value(); VERIFY(pageListModel); waitForStableState(); QModelIndex pageIndex = Zanshin::findIndex(pageListModel, pageNodeName + pageName); VERIFY(pageIndex.isValid()); VERIFY(QMetaObject::invokeMethod(availablePages, "removeItem", Q_ARG(QModelIndex, pageIndex))); waitForStableState(); return true; } bool ZanshinContext::I_add_a_task_child(const QString &childName, const QString &parentName) { waitForStableState(); auto parentIndex = QModelIndex(); for (int row = 0; row < m_indices.size(); row++) { auto index = m_indices.at(row); if (Zanshin::indexString(index) == parentName) { parentIndex = index; break; } } VERIFY_OR_DUMP(parentIndex.isValid()); VERIFY(QMetaObject::invokeMethod(m_presentation, "addItem", Q_ARG(QString, childName), Q_ARG(QModelIndex, parentIndex))); waitForStableState(); return true; } bool ZanshinContext::I_list_the_items() { waitForStableState(); collectIndices(); waitForStableState(); return true; } bool ZanshinContext::I_open_the_item_in_the_editor() { auto task = currentTask(); VERIFY(task); m_editor = m_appModel->property("editor").value(); VERIFY(m_editor); VERIFY(m_editor->setProperty("task", QVariant::fromValue(task))); return true; } bool ZanshinContext::I_mark_the_item_done_in_the_editor() { VERIFY(m_editor->setProperty("done", true)); return true; } bool ZanshinContext::I_change_the_editor_field(const QString &field, const QVariant &value) { const QByteArray property = (field == QStringLiteral("text")) ? field.toUtf8() : (field == QStringLiteral("title")) ? field.toUtf8() : (field == QStringLiteral("start date")) ? "startDate" : (field == QStringLiteral("due date")) ? "dueDate" : QByteArray(); VERIFY(value.isValid()); VERIFY(!property.isEmpty()); VERIFY(m_editor->setProperty("editingInProgress", true)); VERIFY(m_editor->setProperty(property, value)); return true; } bool ZanshinContext::I_rename_the_item(const QString &taskName) { VERIFY(m_editor->setProperty("editingInProgress", false)); VERIFY(model()->setData(m_index, taskName, Qt::EditRole)); waitForStableState(); return true; } bool ZanshinContext::I_open_the_item_in_the_editor_again() { auto task = currentTask(); VERIFY(task); VERIFY(m_editor->setProperty("task", QVariant::fromValue(Domain::Task::Ptr()))); VERIFY(m_editor->setProperty("task", QVariant::fromValue(task))); waitForStableState(); return true; } bool ZanshinContext::I_drop_the_item_on_the_central_list(const QString &dropSiteName) { VERIFY(m_index.isValid()); const QMimeData *data = model()->mimeData(QModelIndexList() << m_index); QAbstractItemModel *destModel = model(); QModelIndex dropIndex = Zanshin::findIndex(destModel, dropSiteName); VERIFY(dropIndex.isValid()); VERIFY(destModel->dropMimeData(data, Qt::MoveAction, -1, -1, dropIndex)); waitForStableState(); return true; } bool ZanshinContext::I_drop_the_item_on_the_blank_area_of_the_central_list() { VERIFY(m_index.isValid()); const QMimeData *data = model()->mimeData(QModelIndexList() << m_index); QAbstractItemModel *destModel = model(); VERIFY(destModel->dropMimeData(data, Qt::MoveAction, -1, -1, QModelIndex())); waitForStableState(); return true; } bool ZanshinContext::I_drop_items_on_the_central_list(const QString &dropSiteName) { VERIFY(!m_dragIndices.isEmpty()); QModelIndexList indexes; bool allValid = true; std::transform(m_dragIndices.constBegin(), m_dragIndices.constEnd(), std::back_inserter(indexes), [&allValid] (const QPersistentModelIndex &index) { allValid &= index.isValid(); return index; }); VERIFY(allValid); const QMimeData *data = model()->mimeData(indexes); QAbstractItemModel *destModel = model(); QModelIndex dropIndex = Zanshin::findIndex(destModel, dropSiteName); VERIFY(dropIndex.isValid()); VERIFY(destModel->dropMimeData(data, Qt::MoveAction, -1, -1, dropIndex)); waitForStableState(); return true; } bool ZanshinContext::I_drop_the_item_on_the_page_list(const QString &pageName) { VERIFY(m_index.isValid()); const QMimeData *data = model()->mimeData(QModelIndexList() << m_index); auto availablePages = m_appModel->property("availablePages").value(); VERIFY(availablePages); auto destModel = availablePages->property("pageListModel").value(); VERIFY(destModel); waitForStableState(); QModelIndex dropIndex = Zanshin::findIndex(destModel, pageName); VERIFY(dropIndex.isValid()); VERIFY(destModel->dropMimeData(data, Qt::MoveAction, -1, -1, dropIndex)); waitForStableState(); return true; } bool ZanshinContext::I_drop_items_on_the_page_list(const QString &pageName) { VERIFY(!m_dragIndices.isEmpty()); QModelIndexList indexes; bool allValid = true; std::transform(m_dragIndices.constBegin(), m_dragIndices.constEnd(), std::back_inserter(indexes), [&allValid] (const QPersistentModelIndex &index) { allValid &= index.isValid(); return index; }); VERIFY(allValid); const QMimeData *data = model()->mimeData(indexes); auto availablePages = m_appModel->property("availablePages").value(); VERIFY(availablePages); auto destModel = availablePages->property("pageListModel").value(); VERIFY(destModel); waitForStableState(); QModelIndex dropIndex = Zanshin::findIndex(destModel, pageName); VERIFY(dropIndex.isValid()); VERIFY(destModel->dropMimeData(data, Qt::MoveAction, -1, -1, dropIndex)); waitForStableState(); return true; } bool ZanshinContext::I_change_the_setting(const QString &key, qint64 id) { KConfigGroup config(KSharedConfig::openConfig(), "General"); config.writeEntry(key, id); return true; } bool ZanshinContext::I_change_the_default_data_source(const QString &sourceName) { waitForStableState(); auto sourceIndex = Zanshin::findIndex(model(), sourceName); auto availableSources = m_appModel->property("availableSources").value(); VERIFY(availableSources); VERIFY(QMetaObject::invokeMethod(availableSources, "setDefaultItem", Q_ARG(QModelIndex, sourceIndex))); waitForStableState(); return true; } bool ZanshinContext::the_list_is(const TableData &data) { auto roleNames = model()->roleNames(); QVector usedRoles; for (const auto &roleName : data.roles) { const int role = roleNames.key(roleName, -1); VERIFY_OR_DUMP(role != -1 && !usedRoles.contains(role)); usedRoles << role; } QStandardItemModel inputModel; for (const auto &row : data.rows) { VERIFY_OR_DUMP(usedRoles.size() == row.size()); QStandardItem *item = new QStandardItem; for (int i = 0; i < row.size(); ++i) { const auto role = usedRoles.at(i); const auto value = row.at(i); item->setData(value, role); } inputModel.appendRow(item); } QSortFilterProxyModel proxy; QAbstractItemModel *referenceModel; if (!qobject_cast(sourceModel())) { referenceModel = &proxy; proxy.setSourceModel(&inputModel); proxy.setSortRole(Qt::DisplayRole); proxy.sort(0); proxy.setObjectName(QStringLiteral("the_list_is_proxy")); } else { referenceModel = &inputModel; } for (int row = 0; row < m_indices.size(); row++) { QModelIndex expectedIndex = referenceModel->index(row, 0); QModelIndex resultIndex = m_indices.at(row); foreach (const auto &role, usedRoles) { COMPARE_OR_DUMP(Zanshin::indexString(resultIndex, role), Zanshin::indexString(expectedIndex, role)); } } COMPARE_OR_DUMP(m_indices.size(), referenceModel->rowCount()); return true; } bool ZanshinContext::the_list_contains(const QString &itemName) { for (int row = 0; row < m_indices.size(); row++) { if (Zanshin::indexString(m_indices.at(row)) == itemName) return true; } VERIFY_OR_DUMP(false); return false; } bool ZanshinContext::the_list_does_not_contain(const QString &itemName) { for (int row = 0; row < m_indices.size(); row++) { VERIFY_OR_DUMP(Zanshin::indexString(m_indices.at(row)) != itemName); } return true; } bool ZanshinContext::the_task_corresponding_to_the_item_is_done() { auto task = currentTask(); VERIFY(task); VERIFY(task->isDone()); return true; } bool ZanshinContext::the_editor_shows_the_task_as_done() { VERIFY(m_editor->property("done").toBool()); return true; } bool ZanshinContext::the_editor_shows_the_field(const QString &field, const QVariant &expectedValue) { const QByteArray property = (field == QStringLiteral("text")) ? field.toUtf8() : (field == QStringLiteral("title")) ? field.toUtf8() : (field == QStringLiteral("start date")) ? "startDate" : (field == QStringLiteral("due date")) ? "dueDate" : QByteArray(); VERIFY(expectedValue.isValid()); VERIFY(!property.isEmpty()); COMPARE(m_editor->property(property), expectedValue); return true; } bool ZanshinContext::the_default_data_source_is(const QString &expectedName) { waitForStableState(); auto expectedIndex = Zanshin::findIndex(model(), expectedName); VERIFY(expectedIndex.isValid()); auto defaultRole = model()->roleNames().key("default", -1); VERIFY(expectedIndex.data(defaultRole).toBool()); return true; } bool ZanshinContext::the_setting_is(const QString &key, qint64 expectedId) { KConfigGroup config(KSharedConfig::openConfig(), "General"); const qint64 id = config.readEntry(key, -1); COMPARE(id, expectedId); return true; } Domain::DataSource::Ptr ZanshinContext::dataSourceFromName(const QString &sourceName) { auto availableSources = m_appModel->property("availableSources").value(); if (!availableSources) return nullptr; auto sourceList = availableSources->property("sourceListModel").value(); if (!sourceList) return nullptr; waitForStableState(); QModelIndex index = Zanshin::findIndex(sourceList, sourceName); if (!index.isValid()) { qWarning() << "source" << sourceName << "not found."; for (int row = 0; row < sourceList->rowCount(); row++) { qDebug() << sourceList->index(row, 0).data().toString(); } return nullptr; } return index.data(Presentation::QueryTreeModelBase::ObjectRole) .value(); } diff --git a/tests/manual/tasktreeviewer.cpp b/tests/manual/tasktreeviewer.cpp index d1725797..ae85907a 100644 --- a/tests/manual/tasktreeviewer.cpp +++ b/tests/manual/tasktreeviewer.cpp @@ -1,106 +1,106 @@ /* This file is part of Zanshin Copyright 2014 Mario Bensi Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include -#include "zanshin/app/dependencies.h" +#include "integration/dependencies.h" #include "domain/taskqueries.h" #include "domain/taskrepository.h" #include "presentation/querytreemodel.h" #include "utils/dependencymanager.h" int main(int argc, char **argv) { QApplication app(argc, argv); - App::initializeDependencies(); + Integration::initializeGlobalAppDependencies(); KAboutData aboutData(QStringLiteral("tasktreeviewer"), QStringLiteral("Show all the tasks in tree"), QStringLiteral("1.0")); QCommandLineParser parser; KAboutData::setApplicationData(aboutData); parser.addVersionOption(); parser.addHelpOption(); aboutData.setupCommandLine(&parser); parser.process(app); aboutData.processCommandLine(&parser); auto repository = Utils::DependencyManager::globalInstance().create(); auto queries = Utils::DependencyManager::globalInstance().create(); auto treeQuery = [&](const Domain::Task::Ptr &task) { if (!task) return queries->findTopLevel(); else return queries->findChildren(task); }; auto treeFlags = [](const Domain::Task::Ptr &) { return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsUserCheckable; }; auto treeData = [](const Domain::Task::Ptr &task, int role, int) -> QVariant { if (role != Qt::DisplayRole && role != Qt::CheckStateRole) { return QVariant(); } if (role == Qt::DisplayRole) return task->title(); else return task->isDone() ? Qt::Checked : Qt::Unchecked; }; auto treeSetData = [&](const Domain::Task::Ptr &task, const QVariant &value, int role) { if (role != Qt::EditRole && role != Qt::CheckStateRole) { return false; } if (role == Qt::EditRole) { task->setTitle(value.toString()); } else { task->setDone(value.toInt() == Qt::Checked); } repository->update(task); return true; }; QTreeView view; view.setModel(new Presentation::QueryTreeModel(treeQuery, treeFlags, treeData, treeSetData, &view)); view.resize(640, 480); view.show(); return app.exec(); }