diff --git a/src/presentation/CMakeLists.txt b/src/presentation/CMakeLists.txt index 737efeca..54ce205e 100644 --- a/src/presentation/CMakeLists.txt +++ b/src/presentation/CMakeLists.txt @@ -1,25 +1,24 @@ set(presentation_SRCS applicationmodel.cpp editormodel.cpp - availablepagesmodelinterface.cpp + availablepagesmodel.cpp availablepagessortfilterproxymodel.cpp - availabletaskpagesmodel.cpp availablesourcesmodel.cpp contextpagemodel.cpp errorhandler.cpp errorhandlingmodelbase.cpp metatypes.cpp pagemodel.cpp projectpagemodel.cpp querytreemodelbase.cpp runningtaskmodelinterface.cpp runningtaskmodel.cpp taskfilterproxymodel.cpp taskinboxpagemodel.cpp tasklistmodel.cpp taskapplicationmodel.cpp workdaypagemodel.cpp ) add_library(presentation STATIC ${presentation_SRCS}) target_link_libraries(presentation Qt5::Core Qt5::Gui KF5::I18n domain utils) diff --git a/src/presentation/applicationmodel.cpp b/src/presentation/applicationmodel.cpp index 34ed955b..b76aa0d3 100644 --- a/src/presentation/applicationmodel.cpp +++ b/src/presentation/applicationmodel.cpp @@ -1,120 +1,120 @@ /* 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 "applicationmodel.h" -#include "presentation/availablepagesmodelinterface.h" +#include "presentation/availablepagesmodel.h" #include "presentation/availablesourcesmodel.h" #include "presentation/editormodel.h" #include "presentation/errorhandler.h" #include "presentation/pagemodel.h" #include "utils/dependencymanager.h" #include "utils/jobhandler.h" using namespace Presentation; ApplicationModel::ApplicationModel(QObject *parent) : QObject(parent), m_errorHandler(Q_NULLPTR) { MetaTypes::registerAll(); } ApplicationModel::~ApplicationModel() { Utils::JobHandler::clear(); } QObject *ApplicationModel::availableSources() { if (!m_availableSources) { auto model = Utils::DependencyManager::globalInstance().create(); model->setErrorHandler(errorHandler()); m_availableSources = model; } return m_availableSources.data(); } QObject *ApplicationModel::availablePages() { if (!m_availablePages) { - auto model = Utils::DependencyManager::globalInstance().create(); + auto model = Utils::DependencyManager::globalInstance().create(); model->setErrorHandler(errorHandler()); m_availablePages = model; } return m_availablePages.data(); } QObject *ApplicationModel::currentPage() { return m_currentPage.data(); } QObject *ApplicationModel::editor() { if (!m_editor) { auto model = Utils::DependencyManager::globalInstance().create(); model->setErrorHandler(errorHandler()); m_editor = model; } return m_editor.data(); } ErrorHandler *ApplicationModel::errorHandler() const { return m_errorHandler; } void ApplicationModel::setCurrentPage(QObject *page) { if (page == m_currentPage) return; m_currentPage = QObjectPtr(page); if (m_currentPage) { m_currentPage->setParent(Q_NULLPTR); auto pageModel = m_currentPage.staticCast(); Q_ASSERT(pageModel); pageModel->setErrorHandler(errorHandler()); } emit currentPageChanged(page); } void ApplicationModel::setErrorHandler(ErrorHandler *errorHandler) { m_errorHandler = errorHandler; if (m_availableSources) m_availableSources.staticCast()->setErrorHandler(errorHandler); if (m_availablePages) - m_availablePages.staticCast()->setErrorHandler(errorHandler); + m_availablePages.staticCast()->setErrorHandler(errorHandler); if (m_editor) m_editor.staticCast()->setErrorHandler(errorHandler); if (m_currentPage) m_currentPage.staticCast()->setErrorHandler(errorHandler); } diff --git a/src/presentation/applicationmodel.h b/src/presentation/applicationmodel.h index 44e51a03..c177820d 100644 --- a/src/presentation/applicationmodel.h +++ b/src/presentation/applicationmodel.h @@ -1,80 +1,79 @@ /* 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 PRESENTATION_APPLICATIONMODEL_H #define PRESENTATION_APPLICATIONMODEL_H #include #include "domain/datasourcerepository.h" #include "domain/datasourcequeries.h" #include "domain/taskrepository.h" #include "presentation/metatypes.h" namespace Presentation { -class AvailablePagesModelInterface; class ErrorHandler; class ApplicationModel : public QObject { Q_OBJECT Q_PROPERTY(QObject* availableSources READ availableSources) Q_PROPERTY(QObject* availablePages READ availablePages) Q_PROPERTY(QObject* currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged) Q_PROPERTY(QObject* editor READ editor) Q_PROPERTY(Presentation::ErrorHandler* errorHandler READ errorHandler WRITE setErrorHandler) public: typedef QSharedPointer Ptr; explicit ApplicationModel(QObject *parent = Q_NULLPTR); ~ApplicationModel(); QObject *availableSources(); QObject *availablePages(); QObject *currentPage(); QObject *editor(); ErrorHandler *errorHandler() const; public slots: void setCurrentPage(QObject *page); void setErrorHandler(ErrorHandler *errorHandler); signals: void currentPageChanged(QObject *page); private: QObjectPtr m_availableSources; QObjectPtr m_availablePages; QObjectPtr m_currentPage; QObjectPtr m_editor; ErrorHandler *m_errorHandler; }; } #endif // PRESENTATION_APPLICATIONMODEL_H diff --git a/src/presentation/availabletaskpagesmodel.cpp b/src/presentation/availablepagesmodel.cpp similarity index 93% rename from src/presentation/availabletaskpagesmodel.cpp rename to src/presentation/availablepagesmodel.cpp index 34d17a94..3c9c52c9 100644 --- a/src/presentation/availabletaskpagesmodel.cpp +++ b/src/presentation/availablepagesmodel.cpp @@ -1,337 +1,317 @@ /* 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 "availabletaskpagesmodel.h" +#include "availablepagesmodel.h" #include #include #include #include "domain/contextqueries.h" #include "domain/contextrepository.h" #include "domain/projectqueries.h" #include "domain/projectrepository.h" #include "domain/taskrepository.h" #include "presentation/availablepagessortfilterproxymodel.h" #include "presentation/contextpagemodel.h" #include "presentation/metatypes.h" #include "presentation/projectpagemodel.h" #include "presentation/querytreemodel.h" #include "presentation/taskinboxpagemodel.h" #include "presentation/workdaypagemodel.h" #include "utils/jobhandler.h" #include "utils/datetime.h" using namespace Presentation; -AvailableTaskPagesModel::AvailableTaskPagesModel(const Domain::DataSourceQueries::Ptr &dataSourceQueries, +AvailablePagesModel::AvailablePagesModel(const Domain::DataSourceQueries::Ptr &dataSourceQueries, const Domain::ProjectQueries::Ptr &projectQueries, const Domain::ProjectRepository::Ptr &projectRepository, const Domain::ContextQueries::Ptr &contextQueries, const Domain::ContextRepository::Ptr &contextRepository, const Domain::TaskQueries::Ptr &taskQueries, const Domain::TaskRepository::Ptr &taskRepository, QObject *parent) - : AvailablePagesModelInterface(parent), + : QObject(parent), m_pageListModel(Q_NULLPTR), m_sortProxyModel(Q_NULLPTR), m_dataSourceQueries(dataSourceQueries), m_projectQueries(projectQueries), m_projectRepository(projectRepository), m_contextQueries(contextQueries), m_contextRepository(contextRepository), m_taskQueries(taskQueries), m_taskRepository(taskRepository) { } -QAbstractItemModel *AvailableTaskPagesModel::pageListModel() +QAbstractItemModel *AvailablePagesModel::pageListModel() { if (!m_pageListModel) m_pageListModel = createPageListModel(); if (!m_sortProxyModel) { m_sortProxyModel = new AvailablePagesSortFilterProxyModel(this); m_sortProxyModel->setSourceModel(m_pageListModel); } return m_sortProxyModel; } -bool AvailableTaskPagesModel::hasProjectPages() const -{ - return true; -} - -bool AvailableTaskPagesModel::hasContextPages() const -{ - return true; -} - -bool AvailableTaskPagesModel::hasTagPages() const -{ - return false; -} - -QObject *AvailableTaskPagesModel::createPageForIndex(const QModelIndex &index) +QObject *AvailablePagesModel::createPageForIndex(const QModelIndex &index) { QObjectPtr object = index.data(QueryTreeModelBase::ObjectRole).value(); if (object == m_inboxObject) { auto inboxPageModel = new TaskInboxPageModel(m_taskQueries, m_taskRepository, this); inboxPageModel->setErrorHandler(errorHandler()); return inboxPageModel; } else if (object == m_workdayObject) { auto workdayPageModel = new WorkdayPageModel(m_taskQueries, m_taskRepository, this); workdayPageModel->setErrorHandler(errorHandler()); return workdayPageModel; } else if (auto project = object.objectCast()) { auto projectPageModel = new ProjectPageModel(project, m_projectQueries, m_projectRepository, m_taskQueries, m_taskRepository, this); projectPageModel->setErrorHandler(errorHandler()); return projectPageModel; } else if (auto context = object.objectCast()) { auto contextPageModel = new ContextPageModel(context, m_contextQueries, m_contextRepository, m_taskQueries, m_taskRepository, this); contextPageModel->setErrorHandler(errorHandler()); return contextPageModel; } return Q_NULLPTR; } -void AvailableTaskPagesModel::addProject(const QString &name, const Domain::DataSource::Ptr &source) +void AvailablePagesModel::addProject(const QString &name, const Domain::DataSource::Ptr &source) { auto project = Domain::Project::Ptr::create(); project->setName(name); const auto job = m_projectRepository->create(project, source); installHandler(job, i18n("Cannot add project %1 in dataSource %2", name, source->name())); } -void AvailableTaskPagesModel::addContext(const QString &name) +void AvailablePagesModel::addContext(const QString &name) { auto context = Domain::Context::Ptr::create(); context->setName(name); const auto job = m_contextRepository->create(context); installHandler(job, i18n("Cannot add context %1", name)); } -void AvailableTaskPagesModel::addTag(const QString &) -{ - qFatal("Not supported"); -} - -void AvailableTaskPagesModel::removeItem(const QModelIndex &index) +void AvailablePagesModel::removeItem(const QModelIndex &index) { QObjectPtr object = index.data(QueryTreeModelBase::ObjectRole).value(); if (auto project = object.objectCast()) { const auto job = m_projectRepository->remove(project); installHandler(job, i18n("Cannot remove project %1", project->name())); } else if (auto context = object.objectCast()) { const auto job = m_contextRepository->remove(context); installHandler(job, i18n("Cannot remove context %1", context->name())); } else { Q_ASSERT(false); } } -QAbstractItemModel *AvailableTaskPagesModel::createPageListModel() +QAbstractItemModel *AvailablePagesModel::createPageListModel() { m_inboxObject = QObjectPtr::create(); m_inboxObject->setProperty("name", i18n("Inbox")); m_workdayObject = QObjectPtr::create(); m_workdayObject->setProperty("name", i18n("Workday")); m_projectsObject = QObjectPtr::create(); m_projectsObject->setProperty("name", i18n("Projects")); m_contextsObject = QObjectPtr::create(); m_contextsObject->setProperty("name", i18n("Contexts")); m_rootsProvider = Domain::QueryResultProvider::Ptr::create(); m_rootsProvider->append(m_inboxObject); m_rootsProvider->append(m_workdayObject); m_rootsProvider->append(m_projectsObject); m_rootsProvider->append(m_contextsObject); auto query = [this](const QObjectPtr &object) -> Domain::QueryResultInterface::Ptr { if (!object) return Domain::QueryResult::create(m_rootsProvider); else if (object == m_projectsObject) return Domain::QueryResult::copy(m_dataSourceQueries->findAllSelected()); else if (object == m_contextsObject) return Domain::QueryResult::copy(m_contextQueries->findAll()); else if (const auto source = object.objectCast()) return Domain::QueryResult::copy(m_dataSourceQueries->findProjects(source)); else return Domain::QueryResult::Ptr(); }; auto flags = [this](const QObjectPtr &object) { const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDropEnabled; const Qt::ItemFlags immutableNodeFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; const Qt::ItemFlags structureNodeFlags = Qt::NoItemFlags; return object.objectCast() ? defaultFlags : object.objectCast() ? defaultFlags : object == m_inboxObject ? immutableNodeFlags : object == m_workdayObject ? immutableNodeFlags : structureNodeFlags; }; auto data = [this](const QObjectPtr &object, int role, int) -> QVariant { if (role != Qt::DisplayRole && role != Qt::EditRole && role != Qt::DecorationRole && role != QueryTreeModelBase::IconNameRole) { return QVariant(); } if (role == Qt::EditRole && (object == m_inboxObject || object == m_workdayObject || object == m_projectsObject || object == m_contextsObject || object.objectCast())) { return QVariant(); } if (role == Qt::DisplayRole || role == Qt::EditRole) { return object->property("name").toString(); } else if (role == Qt::DecorationRole || role == QueryTreeModelBase::IconNameRole) { const QString iconName = object == m_inboxObject ? QStringLiteral("mail-folder-inbox") : (object == m_workdayObject) ? QStringLiteral("go-jump-today") : (object == m_projectsObject) ? QStringLiteral("folder") : (object == m_contextsObject) ? QStringLiteral("folder") : object.objectCast() ? QStringLiteral("folder") : object.objectCast() ? QStringLiteral("view-pim-notes") : QStringLiteral("view-pim-tasks"); if (role == Qt::DecorationRole) return QVariant::fromValue(QIcon::fromTheme(iconName)); else return iconName; } else { return QVariant(); } }; auto setData = [this](const QObjectPtr &object, const QVariant &value, int role) { if (role != Qt::EditRole) { return false; } if (object == m_inboxObject || object == m_workdayObject || object == m_projectsObject || object == m_contextsObject || object.objectCast()) { return false; } if (auto project = object.objectCast()) { const auto currentName = project->name(); project->setName(value.toString()); const auto job = m_projectRepository->update(project); installHandler(job, i18n("Cannot modify project %1", currentName)); } else if (auto context = object.objectCast()) { const auto currentName = context->name(); context->setName(value.toString()); const auto job = m_contextRepository->update(context); installHandler(job, i18n("Cannot modify context %1", currentName)); } else { Q_ASSERT(false); } return true; }; auto drop = [this](const QMimeData *mimeData, Qt::DropAction, const QObjectPtr &object) { if (!mimeData->hasFormat(QStringLiteral("application/x-zanshin-object"))) return false; auto droppedTasks = mimeData->property("objects").value(); if (droppedTasks.isEmpty()) return false; if (auto project = object.objectCast()) { foreach (const auto &task, droppedTasks) { const auto job = m_projectRepository->associate(project, task); installHandler(job, i18n("Cannot add %1 to project %2", task->title(), project->name())); } return true; } else if (auto context = object.objectCast()) { foreach (const auto &task, droppedTasks) { const auto job = m_contextRepository->associate(context, task); installHandler(job, i18n("Cannot add %1 to context %2", task->title(), context->name())); } return true; } else if (object == m_inboxObject) { foreach (const auto &task, droppedTasks) { const auto job = m_projectRepository->dissociate(task); installHandler(job, i18n("Cannot move %1 to Inbox", task->title())); Utils::JobHandler::install(job, [this, task] { const auto dissociateJob = m_taskRepository->dissociateAll(task); installHandler(dissociateJob, i18n("Cannot move task %1 to Inbox", task->title())); }); } return true; } else if (object == m_workdayObject) { foreach (const auto &task, droppedTasks) { task->setStartDate(Utils::DateTime::currentDate()); const auto job = m_taskRepository->update(task); installHandler(job, i18n("Cannot update task %1 to Workday", task->title())); } return true; } return false; }; auto drag = [](const QObjectPtrList &) -> QMimeData* { return Q_NULLPTR; }; return new QueryTreeModel(query, flags, data, setData, drop, drag, nullptr, this); } diff --git a/src/presentation/availabletaskpagesmodel.h b/src/presentation/availablepagesmodel.h similarity index 64% rename from src/presentation/availabletaskpagesmodel.h rename to src/presentation/availablepagesmodel.h index 0e746234..eef8c0dc 100644 --- a/src/presentation/availabletaskpagesmodel.h +++ b/src/presentation/availablepagesmodel.h @@ -1,97 +1,93 @@ /* 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 PRESENTATION_AVAILABLETASKPAGESMODEL_H #define PRESENTATION_AVAILABLETASKPAGESMODEL_H -#include "presentation/availablepagesmodelinterface.h" +#include "presentation/errorhandlingmodelbase.h" #include "domain/contextqueries.h" #include "domain/contextrepository.h" #include "domain/datasourcequeries.h" #include "domain/projectqueries.h" #include "domain/projectrepository.h" #include "domain/taskqueries.h" #include "domain/taskrepository.h" #include "presentation/metatypes.h" class QModelIndex; namespace Presentation { class AvailablePagesSortFilterProxyModel; -class AvailableTaskPagesModel : public AvailablePagesModelInterface +class AvailablePagesModel : public QObject, public ErrorHandlingModelBase { Q_OBJECT + Q_PROPERTY(QAbstractItemModel* pageListModel READ pageListModel) public: - explicit AvailableTaskPagesModel(const Domain::DataSourceQueries::Ptr &dataSourceQueries, - const Domain::ProjectQueries::Ptr &projectQueries, - const Domain::ProjectRepository::Ptr &projectRepository, - const Domain::ContextQueries::Ptr &contextQueries, - const Domain::ContextRepository::Ptr &contextRepository, - const Domain::TaskQueries::Ptr &taskQueries, - const Domain::TaskRepository::Ptr &taskRepository, - QObject *parent = Q_NULLPTR); - - QAbstractItemModel *pageListModel() Q_DECL_OVERRIDE; - - bool hasProjectPages() const Q_DECL_OVERRIDE; - bool hasContextPages() const Q_DECL_OVERRIDE; - bool hasTagPages() const Q_DECL_OVERRIDE; - - QObject *createPageForIndex(const QModelIndex &index) Q_DECL_OVERRIDE; - - void addProject(const QString &name, const Domain::DataSource::Ptr &source) Q_DECL_OVERRIDE; - void addContext(const QString &name) Q_DECL_OVERRIDE; - void addTag(const QString &name) Q_DECL_OVERRIDE; - void removeItem(const QModelIndex &index) Q_DECL_OVERRIDE; + explicit AvailablePagesModel(const Domain::DataSourceQueries::Ptr &dataSourceQueries, + const Domain::ProjectQueries::Ptr &projectQueries, + const Domain::ProjectRepository::Ptr &projectRepository, + const Domain::ContextQueries::Ptr &contextQueries, + const Domain::ContextRepository::Ptr &contextRepository, + const Domain::TaskQueries::Ptr &taskQueries, + const Domain::TaskRepository::Ptr &taskRepository, + QObject *parent = Q_NULLPTR); + + QAbstractItemModel *pageListModel(); + + Q_SCRIPTABLE QObject *createPageForIndex(const QModelIndex &index); + + void addProject(const QString &name, const Domain::DataSource::Ptr &source); + void addContext(const QString &name); + void removeItem(const QModelIndex &index); private: QAbstractItemModel *createPageListModel(); QAbstractItemModel *m_pageListModel; Presentation::AvailablePagesSortFilterProxyModel *m_sortProxyModel; Domain::DataSourceQueries::Ptr m_dataSourceQueries; Domain::ProjectQueries::Ptr m_projectQueries; Domain::ProjectRepository::Ptr m_projectRepository; Domain::ContextQueries::Ptr m_contextQueries; Domain::ContextRepository::Ptr m_contextRepository; Domain::TaskQueries::Ptr m_taskQueries; Domain::TaskRepository::Ptr m_taskRepository; Domain::QueryResultProvider::Ptr m_rootsProvider; QObjectPtr m_inboxObject; QObjectPtr m_workdayObject; QObjectPtr m_projectsObject; QObjectPtr m_contextsObject; }; } #endif // PRESENTATION_AVAILABLETASKPAGESMODEL_H diff --git a/src/presentation/availablepagesmodelinterface.cpp b/src/presentation/availablepagesmodelinterface.cpp deleted file mode 100644 index 8b866482..00000000 --- a/src/presentation/availablepagesmodelinterface.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/* This file is part of Zanshin - - Copyright 2015 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 "availablepagesmodelinterface.h" - -using namespace Presentation; - -AvailablePagesModelInterface::AvailablePagesModelInterface(QObject *parent) - : QObject(parent) -{ -} diff --git a/src/presentation/availablepagesmodelinterface.h b/src/presentation/availablepagesmodelinterface.h deleted file mode 100644 index a14d1ef9..00000000 --- a/src/presentation/availablepagesmodelinterface.h +++ /dev/null @@ -1,66 +0,0 @@ -/* This file is part of Zanshin - - Copyright 2015 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 PRESENTATION_AVAILABLEPAGESMODELINTERFACE_H -#define PRESENTATION_AVAILABLEPAGESMODELINTERFACE_H - -#include - -#include "domain/datasource.h" - -#include "presentation/errorhandlingmodelbase.h" - -class QAbstractItemModel; -class QModelIndex; - -namespace Presentation { - -class AvailablePagesModelInterface : public QObject, public ErrorHandlingModelBase -{ - Q_OBJECT - Q_PROPERTY(QAbstractItemModel* pageListModel READ pageListModel) - Q_PROPERTY(bool hasProjectPages READ hasProjectPages) - Q_PROPERTY(bool hasContextPages READ hasContextPages) - Q_PROPERTY(bool hasTagPages READ hasTagPages) -public: - explicit AvailablePagesModelInterface(QObject *parent = Q_NULLPTR); - - virtual QAbstractItemModel *pageListModel() = 0; - - virtual bool hasProjectPages() const = 0; - virtual bool hasContextPages() const = 0; - virtual bool hasTagPages() const = 0; - - Q_SCRIPTABLE virtual QObject *createPageForIndex(const QModelIndex &index) = 0; - -public slots: - virtual void addProject(const QString &name, const Domain::DataSource::Ptr &source) = 0; - virtual void addContext(const QString &name) = 0; - virtual void addTag(const QString &name) = 0; - virtual void removeItem(const QModelIndex &index) = 0; -}; - -} - -#endif // PRESENTATION_AVAILABLEPAGESMODELINTERFACE_H diff --git a/src/widgets/availablepagesview.cpp b/src/widgets/availablepagesview.cpp index 622bde65..e2030297 100644 --- a/src/widgets/availablepagesview.cpp +++ b/src/widgets/availablepagesview.cpp @@ -1,359 +1,338 @@ /* 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 "availablepagesview.h" #include #include #include #include #include #include #include #include #include "presentation/metatypes.h" #include "presentation/querytreemodelbase.h" #include "widgets/messagebox.h" #include "widgets/newprojectdialog.h" #include "widgets/quickselectdialog.h" #include "domain/project.h" #include "domain/context.h" using namespace Widgets; using namespace Presentation; AvailablePagesView::AvailablePagesView(QWidget *parent) : QWidget(parent), m_addProjectAction(new QAction(this)), m_addContextAction(new QAction(this)), - m_addTagAction(new QAction(this)), m_removeAction(new QAction(this)), m_model(Q_NULLPTR), m_sources(Q_NULLPTR), m_pagesView(new QTreeView(this)) { m_pagesView->setObjectName(QStringLiteral("pagesView")); m_pagesView->header()->hide(); m_pagesView->setDragDropMode(QTreeView::DropOnly); auto actionBar = new QToolBar(this); actionBar->setObjectName(QStringLiteral("actionBar")); actionBar->setIconSize(QSize(16, 16)); m_addProjectAction->setObjectName(QStringLiteral("addProjectAction")); m_addProjectAction->setText(i18n("New Project")); m_addProjectAction->setIcon(QIcon::fromTheme(QStringLiteral("view-pim-tasks"))); connect(m_addProjectAction, &QAction::triggered, this, &AvailablePagesView::onAddProjectTriggered); actionBar->addAction(m_addProjectAction); m_addContextAction->setObjectName(QStringLiteral("addContextAction")); m_addContextAction->setText(i18n("New Context")); m_addContextAction->setIcon(QIcon::fromTheme(QStringLiteral("view-pim-notes"))); connect(m_addContextAction, &QAction::triggered, this, &AvailablePagesView::onAddContextTriggered); actionBar->addAction(m_addContextAction); - m_addTagAction->setObjectName(QStringLiteral("addTagAction")); - m_addTagAction->setText(i18n("New Tag")); - m_addTagAction->setIcon(QIcon::fromTheme(QStringLiteral("view-pim-tasks"))); - connect(m_addTagAction, &QAction::triggered, this, &AvailablePagesView::onAddTagTriggered); - actionBar->addAction(m_addTagAction); - m_removeAction->setObjectName(QStringLiteral("removeAction")); m_removeAction->setText(i18n("Remove Page")); m_removeAction->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); connect(m_removeAction, &QAction::triggered, this, &AvailablePagesView::onRemoveTriggered); actionBar->addAction(m_removeAction); auto actionBarLayout = new QHBoxLayout; actionBarLayout->setContentsMargins(0, 0, 0, 0); actionBarLayout->setAlignment(Qt::AlignRight); actionBarLayout->addWidget(actionBar); auto layout = new QVBoxLayout; layout->addWidget(m_pagesView); layout->addLayout(actionBarLayout); setLayout(layout); auto margins = layout->contentsMargins(); margins.setBottom(0); layout->setContentsMargins(margins); m_projectDialogFactory = [] (QWidget *parent) { return NewProjectDialogPtr(new NewProjectDialog(parent)); }; m_quickSelectDialogFactory = [] (QWidget *parent) { return QuickSelectDialogPtr(new QuickSelectDialog(parent)); }; m_messageBoxInterface = MessageBox::Ptr::create(); auto goPreviousAction = new QAction(this); goPreviousAction->setObjectName(QStringLiteral("goPreviousAction")); goPreviousAction->setText(i18n("Previous Page")); goPreviousAction->setIcon(QIcon::fromTheme(QStringLiteral("go-up"))); goPreviousAction->setShortcut(Qt::ALT | Qt::Key_Up); connect(goPreviousAction, &QAction::triggered, this, &AvailablePagesView::onGoPreviousTriggered); auto goNextAction = new QAction(this); goNextAction->setObjectName(QStringLiteral("goNextAction")); goNextAction->setText(i18n("Next Page")); goNextAction->setIcon(QIcon::fromTheme(QStringLiteral("go-down"))); goNextAction->setShortcut(Qt::ALT | Qt::Key_Down); connect(goNextAction, &QAction::triggered, this, &AvailablePagesView::onGoNextTriggered); auto goToAction = new QAction(this); goToAction->setObjectName(QStringLiteral("goToAction")); goToAction->setText(i18n("Go to Page...")); goToAction->setShortcut(Qt::Key_J); connect(goToAction, &QAction::triggered, this, &AvailablePagesView::onGoToTriggered); m_actions.insert(QStringLiteral("pages_project_add"), m_addProjectAction); m_actions.insert(QStringLiteral("pages_context_add"), m_addContextAction); - m_actions.insert(QStringLiteral("pages_tag_add"), m_addTagAction); m_actions.insert(QStringLiteral("pages_remove"), m_removeAction); m_actions.insert(QStringLiteral("pages_go_previous"), goPreviousAction); m_actions.insert(QStringLiteral("pages_go_next"), goNextAction); m_actions.insert(QStringLiteral("pages_go_to"), goToAction); } QHash AvailablePagesView::globalActions() const { return m_actions; } QObject *AvailablePagesView::model() const { return m_model; } QAbstractItemModel *AvailablePagesView::projectSourcesModel() const { return m_sources; } Domain::DataSource::Ptr AvailablePagesView::defaultProjectSource() const { return m_defaultSource; } AvailablePagesView::ProjectDialogFactory AvailablePagesView::projectDialogFactory() const { return m_projectDialogFactory; } AvailablePagesView::QuickSelectDialogFactory AvailablePagesView::quickSelectDialogFactory() const { return m_quickSelectDialogFactory; } void AvailablePagesView::setModel(QObject *model) { if (model == m_model) return; if (m_pagesView->selectionModel()) { disconnect(m_pagesView->selectionModel(), Q_NULLPTR, this, Q_NULLPTR); } if (m_pagesView->model()) { disconnect(m_pagesView->model(), &QAbstractItemModel::rowsInserted, m_pagesView, &QTreeView::expand); disconnect(m_pagesView->model(), &QAbstractItemModel::layoutChanged, m_pagesView, &QTreeView::expandAll); disconnect(m_pagesView->model(), &QAbstractItemModel::modelReset, m_pagesView, &QTreeView::expandAll); } m_pagesView->setModel(Q_NULLPTR); m_model = model; setEnabled(m_model); if (!m_model) return; - m_addProjectAction->setVisible(m_model->property("hasProjectPages").toBool()); - m_addContextAction->setVisible(m_model->property("hasContextPages").toBool()); - m_addTagAction->setVisible(m_model->property("hasTagPages").toBool()); - QVariant modelProperty = m_model->property("pageListModel"); if (modelProperty.canConvert()) { m_pagesView->setModel(modelProperty.value()); connect(m_pagesView->model(), &QAbstractItemModel::rowsInserted, m_pagesView, &QTreeView::expand); connect(m_pagesView->model(), &QAbstractItemModel::layoutChanged, m_pagesView, &QTreeView::expandAll); connect(m_pagesView->model(), &QAbstractItemModel::modelReset, m_pagesView, &QTreeView::expandAll); } connect(m_pagesView->selectionModel(), &QItemSelectionModel::currentChanged, this, &AvailablePagesView::onCurrentChanged); QMetaObject::invokeMethod(this, "onInitTimeout", Qt::QueuedConnection); } void AvailablePagesView::setProjectSourcesModel(QAbstractItemModel *sources) { m_sources = sources; } void AvailablePagesView::setDefaultProjectSource(const Domain::DataSource::Ptr &source) { m_defaultSource = source; } void AvailablePagesView::setProjectDialogFactory(const AvailablePagesView::ProjectDialogFactory &factory) { m_projectDialogFactory = factory; } void AvailablePagesView::setQuickSelectDialogFactory(const AvailablePagesView::QuickSelectDialogFactory &factory) { m_quickSelectDialogFactory = factory; } void AvailablePagesView::setMessageBoxInterface(const MessageBoxInterface::Ptr &interface) { m_messageBoxInterface = interface; } void AvailablePagesView::onCurrentChanged(const QModelIndex ¤t) { QObject *page = Q_NULLPTR; QMetaObject::invokeMethod(m_model, "createPageForIndex", Q_RETURN_ARG(QObject*, page), Q_ARG(QModelIndex, current)); emit currentPageChanged(page); const auto object = current.data(QueryTreeModelBase::ObjectRole).value(); m_removeAction->setEnabled(object.objectCast() || object.objectCast()); } void AvailablePagesView::onAddProjectTriggered() { NewProjectDialogInterface::Ptr dialog = m_projectDialogFactory(this); dialog->setDataSourcesModel(m_sources); if (dialog->exec() == QDialog::Accepted) { m_defaultSource = dialog->dataSource(); QMetaObject::invokeMethod(m_model, "addProject", Q_ARG(QString, dialog->name()), Q_ARG(Domain::DataSource::Ptr, dialog->dataSource())); } } void AvailablePagesView::onAddContextTriggered() { const QString name = m_messageBoxInterface->askTextInput(this, i18n("Add Context"), i18n("Context name")); if (!name.isEmpty()) { QMetaObject::invokeMethod(m_model, "addContext", Q_ARG(QString, name)); } } -void AvailablePagesView::onAddTagTriggered() -{ - const QString name = m_messageBoxInterface->askTextInput(this, i18n("Add Tag"), i18n("Tag name")); - if (!name.isEmpty()) { - QMetaObject::invokeMethod(m_model, "addTag", - Q_ARG(QString, name)); - } -} - void AvailablePagesView::onRemoveTriggered() { const QModelIndex current = m_pagesView->currentIndex(); if (!current.isValid()) return; QString title; QString text; QObjectPtr object = current.data(QueryTreeModelBase::ObjectRole).value(); if (!object) { qDebug() << "Model doesn't have ObjectRole for" << current; return; } if (Domain::Project::Ptr project = object.objectCast()) { title = i18n("Delete Project"); text = i18n("Do you really want to delete the project '%1', with all its actions?", project->name()); } else if (Domain::Context::Ptr context = object.objectCast()) { title = i18n("Delete Context"); text = i18n("Do you really want to delete the context '%1'?", context->name()); } else { qFatal("Unrecognized object type"); return; } QMessageBox::Button button = m_messageBoxInterface->askConfirmation(this, title, text); if (button != QMessageBox::Yes) { return; } QMetaObject::invokeMethod(m_model, "removeItem", Q_ARG(QModelIndex, current)); } void AvailablePagesView::onGoPreviousTriggered() { auto index = m_pagesView->indexAbove(m_pagesView->currentIndex()); while (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { index = m_pagesView->indexAbove(index); } if (index.isValid()) m_pagesView->setCurrentIndex(index); } void AvailablePagesView::onGoNextTriggered() { auto index = m_pagesView->indexBelow(m_pagesView->currentIndex()); while (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { index = m_pagesView->indexBelow(index); } if (index.isValid()) m_pagesView->setCurrentIndex(index); } void AvailablePagesView::onGoToTriggered() { QuickSelectDialogInterface::Ptr dialog = m_quickSelectDialogFactory(this); dialog->setModel(m_pagesView->model()); if (dialog->exec() == QDialog::Accepted && dialog->selectedIndex().isValid()) { m_pagesView->setCurrentIndex(dialog->selectedIndex()); } } void AvailablePagesView::onInitTimeout() { if (m_pagesView->model()) { m_pagesView->setCurrentIndex(m_pagesView->model()->index(0, 0)); m_pagesView->expandAll(); } } diff --git a/src/widgets/availablepagesview.h b/src/widgets/availablepagesview.h index 073cbd98..56edc639 100644 --- a/src/widgets/availablepagesview.h +++ b/src/widgets/availablepagesview.h @@ -1,106 +1,104 @@ /* 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 WIDGETS_AVAILABLEPAGESVIEW_H #define WIDGETS_AVAILABLEPAGESVIEW_H #include #include #include #include #include "domain/datasource.h" #include "messageboxinterface.h" class QAbstractItemModel; class QModelIndex; class QTreeView; namespace Widgets { class NewProjectDialogInterface; class QuickSelectDialogInterface; class AvailablePagesView : public QWidget { Q_OBJECT public: typedef QSharedPointer NewProjectDialogPtr; typedef std::function ProjectDialogFactory; typedef QSharedPointer QuickSelectDialogPtr; typedef std::function QuickSelectDialogFactory; explicit AvailablePagesView(QWidget *parent = Q_NULLPTR); QHash globalActions() const; QObject *model() const; QAbstractItemModel *projectSourcesModel() const; Domain::DataSource::Ptr defaultProjectSource() const; ProjectDialogFactory projectDialogFactory() const; QuickSelectDialogFactory quickSelectDialogFactory() const; public slots: void setModel(QObject *model); void setProjectSourcesModel(QAbstractItemModel *sources); void setDefaultProjectSource(const Domain::DataSource::Ptr &source); void setProjectDialogFactory(const ProjectDialogFactory &factory); void setQuickSelectDialogFactory(const QuickSelectDialogFactory &factory); void setMessageBoxInterface(const MessageBoxInterface::Ptr &interface); signals: void currentPageChanged(QObject *page); private slots: void onCurrentChanged(const QModelIndex ¤t); void onAddProjectTriggered(); void onAddContextTriggered(); - void onAddTagTriggered(); void onRemoveTriggered(); void onGoPreviousTriggered(); void onGoNextTriggered(); void onGoToTriggered(); void onInitTimeout(); private: QAction *m_addProjectAction; QAction *m_addContextAction; - QAction *m_addTagAction; QAction *m_removeAction; QHash m_actions; QObject *m_model; QAbstractItemModel *m_sources; Domain::DataSource::Ptr m_defaultSource; QTreeView *m_pagesView; ProjectDialogFactory m_projectDialogFactory; QuickSelectDialogFactory m_quickSelectDialogFactory; MessageBoxInterface::Ptr m_messageBoxInterface; }; } #endif // WIDGETS_AVAILABLEPAGESVIEW_H diff --git a/src/zanshin/app/dependencies.cpp b/src/zanshin/app/dependencies.cpp index 50e0d92e..d710e89b 100644 --- a/src/zanshin/app/dependencies.cpp +++ b/src/zanshin/app/dependencies.cpp @@ -1,128 +1,128 @@ /* 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/availabletaskpagesmodel.h" #include "presentation/editormodel.h" #include "presentation/runningtaskmodel.h" #include "utils/dependencymanager.h" void App::initializeDependencies() { 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([] (Utils::DependencyManager *deps) { return new Akonadi::DataSourceQueries(deps->create(), deps->create(), deps->create()); }); deps.add([] (Utils::DependencyManager *deps) { return new Akonadi::DataSourceRepository(deps->create(), deps->create()); }); 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(); deps.add(); } diff --git a/tests/units/presentation/CMakeLists.txt b/tests/units/presentation/CMakeLists.txt index d10342c5..d3a12b53 100644 --- a/tests/units/presentation/CMakeLists.txt +++ b/tests/units/presentation/CMakeLists.txt @@ -1,20 +1,20 @@ zanshin_auto_tests( applicationmodeltest editormodeltest + availablepagesmodeltest availablepagessortfilterproxymodeltest availablesourcesmodeltest - availabletaskpagesmodeltest errorhandlertest errorhandlingmodelbasetest metatypestest pagemodeltest projectpagemodeltest querytreemodeltest runningtaskmodeltest taskapplicationmodeltest taskfilterproxymodeltest taskinboxpagemodeltest tasklistmodeltest contextpagemodeltest workdaypagemodeltest ) diff --git a/tests/units/presentation/applicationmodeltest.cpp b/tests/units/presentation/applicationmodeltest.cpp index b6a2aaaf..16cb8708 100644 --- a/tests/units/presentation/applicationmodeltest.cpp +++ b/tests/units/presentation/applicationmodeltest.cpp @@ -1,252 +1,239 @@ /* 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 "utils/dependencymanager.h" #include "utils/jobhandler.h" #include "utils/mockobject.h" #include "presentation/applicationmodel.h" -#include "presentation/availablepagesmodelinterface.h" +#include "presentation/availablepagesmodel.h" #include "presentation/availablesourcesmodel.h" #include "presentation/editormodel.h" #include "presentation/pagemodel.h" #include "presentation/errorhandler.h" #include "testlib/fakejob.h" using namespace mockitopp; using namespace mockitopp::matcher; class FakeErrorHandler : public Presentation::ErrorHandler { public: void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; -class FakeAvailablePagesModel : public Presentation::AvailablePagesModelInterface -{ - Q_OBJECT -public: - explicit FakeAvailablePagesModel(QObject *parent = Q_NULLPTR) - : Presentation::AvailablePagesModelInterface(parent) {} - - QAbstractItemModel *pageListModel() Q_DECL_OVERRIDE { return Q_NULLPTR; } - - bool hasProjectPages() const Q_DECL_OVERRIDE { return false; } - bool hasContextPages() const Q_DECL_OVERRIDE { return false; } - bool hasTagPages() const Q_DECL_OVERRIDE { return false; } - - QObject *createPageForIndex(const QModelIndex &) Q_DECL_OVERRIDE { return Q_NULLPTR; } - - void addProject(const QString &, const Domain::DataSource::Ptr &) Q_DECL_OVERRIDE {} - void addContext(const QString &) Q_DECL_OVERRIDE {} - void addTag(const QString &) Q_DECL_OVERRIDE {} - void removeItem(const QModelIndex &) Q_DECL_OVERRIDE {} -}; - class FakePageModel : public Presentation::PageModel { Q_OBJECT public: explicit FakePageModel(QObject *parent = Q_NULLPTR) : Presentation::PageModel(parent) {} Domain::Task::Ptr addItem(const QString &, const QModelIndex &) Q_DECL_OVERRIDE { return {}; } void removeItem(const QModelIndex &) Q_DECL_OVERRIDE {} void promoteItem(const QModelIndex &) Q_DECL_OVERRIDE {} private: QAbstractItemModel *createCentralListModel() Q_DECL_OVERRIDE { return {}; } }; class ApplicationModelTest : public QObject { Q_OBJECT public: explicit ApplicationModelTest(QObject *parent = Q_NULLPTR) : QObject(parent) { - Utils::DependencyManager::globalInstance().add(); + Utils::DependencyManager::globalInstance().add( + [] (Utils::DependencyManager *) { + return new Presentation::AvailablePagesModel(Domain::DataSourceQueries::Ptr(), + Domain::ProjectQueries::Ptr(), + Domain::ProjectRepository::Ptr(), + Domain::ContextQueries::Ptr(), + Domain::ContextRepository::Ptr(), + Domain::TaskQueries::Ptr(), + Domain::TaskRepository::Ptr()); + }); Utils::DependencyManager::globalInstance().add( [] (Utils::DependencyManager *) { return new Presentation::EditorModel; }); Utils::DependencyManager::globalInstance().add( [] (Utils::DependencyManager *) { return new Presentation::AvailableSourcesModel(Domain::DataSourceQueries::Ptr(), Domain::DataSourceRepository::Ptr()); }); } private slots: void shouldProvideAvailableSourcesModel() { // GIVEN Presentation::ApplicationModel app; // WHEN QObject *available = app.availableSources(); // THEN QVERIFY(qobject_cast(available)); } void shouldProvideAvailablePagesModel() { // GIVEN Presentation::ApplicationModel app; // WHEN QObject *available = app.availablePages(); // THEN - QVERIFY(qobject_cast(available)); + QVERIFY(qobject_cast(available)); } void shouldProvideCurrentPage() { // GIVEN Presentation::ApplicationModel app; QVERIFY(!app.currentPage()); QSignalSpy spy(&app, &Presentation::ApplicationModel::currentPageChanged); // WHEN auto page = new FakePageModel(this); app.setCurrentPage(page); // THEN QCOMPARE(app.currentPage(), page); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).value(), page); } void shouldSupportNullPage() { // GIVEN Presentation::ApplicationModel app; auto page = new FakePageModel(this); app.setCurrentPage(page); QCOMPARE(app.currentPage(), page); QSignalSpy spy(&app, &Presentation::ApplicationModel::currentPageChanged); // WHEN app.setCurrentPage(Q_NULLPTR); // THEN QVERIFY(!app.currentPage()); QCOMPARE(spy.count(), 1); QVERIFY(!spy.takeFirst().at(0).value()); } void shouldTakeOwnershipOfCurrentPage() { // GIVEN auto page = QPointer(new FakePageModel(this)); { Presentation::ApplicationModel app; // WHEN app.setCurrentPage(page.data()); // THEN QVERIFY(!page->parent()); QCOMPARE(app.currentPage(), page.data()); } // We don't crash and page is deleted QVERIFY(!page); } void shouldProvideEditorModel() { // GIVEN Presentation::ApplicationModel app; // WHEN QObject *page = app.editor(); // THEN QVERIFY(qobject_cast(page)); } void shouldSetErrorHandlerToAllModels() { // GIVEN // An ErrorHandler FakeErrorHandler errorHandler; Presentation::ApplicationModel app; app.setCurrentPage(new FakePageModel); // WHEN app.setErrorHandler(&errorHandler); // THEN auto availableSource = static_cast(app.availableSources()); - auto availablePages = static_cast(app.availablePages()); + auto availablePages = static_cast(app.availablePages()); auto editor = static_cast(app.editor()); auto page = static_cast(app.currentPage()); QCOMPARE(availableSource->errorHandler(), &errorHandler); QCOMPARE(availablePages->errorHandler(), &errorHandler); QCOMPARE(editor->errorHandler(), &errorHandler); QCOMPARE(page->errorHandler(), &errorHandler); // WHEN FakeErrorHandler errorHandler2; app.setErrorHandler(&errorHandler2); // THEN QCOMPARE(availableSource->errorHandler(), &errorHandler2); QCOMPARE(availablePages->errorHandler(), &errorHandler2); QCOMPARE(editor->errorHandler(), &errorHandler2); QCOMPARE(page->errorHandler(), &errorHandler2); } void shouldClearJobHandlersOnExit() { // GIVEN auto app = new Presentation::ApplicationModel; Utils::JobHandler::install(new FakeJob, [] { qFatal("Shouldn't happen"); }); QCOMPARE(Utils::JobHandler::jobCount(), 1); // WHEN delete app; // THEN QCOMPARE(Utils::JobHandler::jobCount(), 0); QTest::qWait(FakeJob::DURATION * 2); } }; ZANSHIN_TEST_MAIN(ApplicationModelTest) #include "applicationmodeltest.moc" diff --git a/tests/units/presentation/availabletaskpagesmodeltest.cpp b/tests/units/presentation/availablepagesmodeltest.cpp similarity index 96% rename from tests/units/presentation/availabletaskpagesmodeltest.cpp rename to tests/units/presentation/availablepagesmodeltest.cpp index 533268f5..47ed213b 100644 --- a/tests/units/presentation/availabletaskpagesmodeltest.cpp +++ b/tests/units/presentation/availablepagesmodeltest.cpp @@ -1,1258 +1,1247 @@ /* 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 "utils/mockobject.h" #include "utils/datetime.h" -#include "presentation/availabletaskpagesmodel.h" +#include "presentation/availablepagesmodel.h" #include "presentation/contextpagemodel.h" #include "presentation/errorhandler.h" #include "presentation/projectpagemodel.h" #include "presentation/querytreemodelbase.h" #include "presentation/taskinboxpagemodel.h" #include "presentation/workdaypagemodel.h" #include "testlib/fakejob.h" using namespace mockitopp; using namespace mockitopp::matcher; class FakeErrorHandler : public Presentation::ErrorHandler { public: void doDisplayMessage(const QString &message) override { m_message = message; } QString m_message; }; -class AvailableTaskPagesModelTest : public QObject +class AvailablePagesModelTest : public QObject { Q_OBJECT private slots: - void shouldDeclareOnlyProjectAndContextPages() - { - // GIVEN - Presentation::AvailableTaskPagesModel pages({}, {}, {}, {}, {}, {}, {}); - - // THEN - QVERIFY(pages.hasProjectPages()); - QVERIFY(pages.hasContextPages()); - QVERIFY(!pages.hasTagPages()); - } - void shouldListAvailablePages() { // GIVEN // Two selected data sources auto source1 = Domain::DataSource::Ptr::create(); source1->setName("source1"); auto source2 = Domain::DataSource::Ptr::create(); source2->setName("source2"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source1); sourceProvider->append(source2); // Two projects under source 1 auto project11 = Domain::Project::Ptr::create(); project11->setName(QStringLiteral("Project 11")); auto project12 = Domain::Project::Ptr::create(); project12->setName(QStringLiteral("Project 12")); auto project1Provider = Domain::QueryResultProvider::Ptr::create(); auto project1Result = Domain::QueryResult::create(project1Provider); project1Provider->append(project12); project1Provider->append(project11); // note: reversed order, to test sorting // Two projects under source 2 auto project21 = Domain::Project::Ptr::create(); project21->setName(QStringLiteral("Project 21")); auto project22 = Domain::Project::Ptr::create(); project22->setName(QStringLiteral("Project 22")); auto project2Provider = Domain::QueryResultProvider::Ptr::create(); auto project2Result = Domain::QueryResult::create(project2Provider); project2Provider->append(project22); project2Provider->append(project21); // note: reversed order, to test sorting // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); // One task (used for dropping later on) Domain::Task::Ptr taskToDrop(new Domain::Task); Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source1).thenReturn(project1Result); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source2).thenReturn(project2Result); Utils::MockObject projectRepositoryMock; Utils::MockObject taskRepositoryMock; Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), taskRepositoryMock.getInstance()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex inboxIndex = model->index(0, 0); const QModelIndex workdayIndex = model->index(1, 0); const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex source1Index = model->index(0, 0, projectsIndex); const QModelIndex project11Index = model->index(0, 0, source1Index); const QModelIndex project12Index = model->index(1, 0, source1Index); const QModelIndex source2Index = model->index(1, 0, projectsIndex); const QModelIndex project21Index = model->index(0, 0, source2Index); const QModelIndex project22Index = model->index(1, 0, source2Index); const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); const QModelIndex context2Index = model->index(1, 0, contextsIndex); QCOMPARE(model->rowCount(), 4); QCOMPARE(model->rowCount(inboxIndex), 0); QCOMPARE(model->rowCount(workdayIndex), 0); QCOMPARE(model->rowCount(projectsIndex), 2); QCOMPARE(model->rowCount(source1Index), 2); QCOMPARE(model->rowCount(project11Index), 0); QCOMPARE(model->rowCount(project12Index), 0); QCOMPARE(model->rowCount(source2Index), 2); QCOMPARE(model->rowCount(project21Index), 0); QCOMPARE(model->rowCount(project22Index), 0); QCOMPARE(model->rowCount(contextsIndex), 2); QCOMPARE(model->rowCount(context1Index), 0); QCOMPARE(model->rowCount(context2Index), 0); const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable; QCOMPARE(model->flags(inboxIndex), (defaultFlags & ~(Qt::ItemIsEditable)) | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(workdayIndex), (defaultFlags & ~(Qt::ItemIsEditable)) | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(projectsIndex), Qt::NoItemFlags); QCOMPARE(model->flags(source1Index), Qt::NoItemFlags); QCOMPARE(model->flags(project11Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(project12Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(source2Index), Qt::NoItemFlags); QCOMPARE(model->flags(project21Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(project22Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(contextsIndex), Qt::NoItemFlags); QCOMPARE(model->flags(context1Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(context2Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->data(inboxIndex).toString(), i18n("Inbox")); QCOMPARE(model->data(workdayIndex).toString(), i18n("Workday")); QCOMPARE(model->data(projectsIndex).toString(), i18n("Projects")); QCOMPARE(model->data(source1Index).toString(), source1->name()); QCOMPARE(model->data(project11Index).toString(), project11->name()); QCOMPARE(model->data(project12Index).toString(), project12->name()); QCOMPARE(model->data(source2Index).toString(), source2->name()); QCOMPARE(model->data(project21Index).toString(), project21->name()); QCOMPARE(model->data(project22Index).toString(), project22->name()); QCOMPARE(model->data(contextsIndex).toString(), i18n("Contexts")); QCOMPARE(model->data(context1Index).toString(), context1->name()); QCOMPARE(model->data(context2Index).toString(), context2->name()); QVERIFY(!model->data(inboxIndex, Qt::EditRole).isValid()); QVERIFY(!model->data(workdayIndex, Qt::EditRole).isValid()); QVERIFY(!model->data(projectsIndex, Qt::EditRole).isValid()); QVERIFY(!model->data(source1Index, Qt::EditRole).isValid()); QCOMPARE(model->data(project11Index, Qt::EditRole).toString(), project11->name()); QCOMPARE(model->data(project12Index, Qt::EditRole).toString(), project12->name()); QVERIFY(!model->data(source2Index, Qt::EditRole).isValid()); QCOMPARE(model->data(project21Index, Qt::EditRole).toString(), project21->name()); QCOMPARE(model->data(project22Index, Qt::EditRole).toString(), project22->name()); QVERIFY(!model->data(contextsIndex, Qt::EditRole).isValid()); QCOMPARE(model->data(context1Index, Qt::EditRole).toString(), context1->name()); QCOMPARE(model->data(context2Index, Qt::EditRole).toString(), context2->name()); QCOMPARE(model->data(inboxIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("mail-folder-inbox")); QCOMPARE(model->data(workdayIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("go-jump-today")); QCOMPARE(model->data(projectsIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(source1Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(project11Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks")); QCOMPARE(model->data(project12Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks")); QCOMPARE(model->data(source2Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(project21Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks")); QCOMPARE(model->data(project22Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks")); QCOMPARE(model->data(contextsIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("folder")); QCOMPARE(model->data(context1Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-notes")); QCOMPARE(model->data(context2Index, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-notes")); QVERIFY(!model->data(inboxIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(workdayIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(projectsIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(source1Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(project11Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(project12Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(source2Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(project21Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(project22Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(contextsIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(context1Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(context2Index, Qt::CheckStateRole).isValid()); // WHEN projectRepositoryMock(&Domain::ProjectRepository::update).when(project11).thenReturn(new FakeJob(this)); projectRepositoryMock(&Domain::ProjectRepository::update).when(project12).thenReturn(new FakeJob(this)); projectRepositoryMock(&Domain::ProjectRepository::update).when(project21).thenReturn(new FakeJob(this)); projectRepositoryMock(&Domain::ProjectRepository::update).when(project22).thenReturn(new FakeJob(this)); contextRepositoryMock(&Domain::ContextRepository::update).when(context1).thenReturn(new FakeJob(this)); contextRepositoryMock(&Domain::ContextRepository::update).when(context2).thenReturn(new FakeJob(this)); QVERIFY(!model->setData(inboxIndex, "Foo")); QVERIFY(!model->setData(projectsIndex, "Foo")); QVERIFY(!model->setData(source1Index, "Foo")); QVERIFY(model->setData(project11Index, "New Project 11")); QVERIFY(model->setData(project12Index, "New Project 12")); QVERIFY(!model->setData(source2Index, "Foo")); QVERIFY(model->setData(project21Index, "New Project 21")); QVERIFY(model->setData(project22Index, "New Project 22")); QVERIFY(!model->setData(contextsIndex, "Foo")); QVERIFY(model->setData(context1Index, "New Context 1")); QVERIFY(model->setData(context2Index, "New Context 2")); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project11).exactly(1)); QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project12).exactly(1)); QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project21).exactly(1)); QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::update).when(project22).exactly(1)); QVERIFY(contextRepositoryMock(&Domain::ContextRepository::update).when(context1).exactly(1)); QVERIFY(contextRepositoryMock(&Domain::ContextRepository::update).when(context2).exactly(1)); QCOMPARE(project11->name(), QStringLiteral("New Project 11")); QCOMPARE(project12->name(), QStringLiteral("New Project 12")); QCOMPARE(project21->name(), QStringLiteral("New Project 21")); QCOMPARE(project22->name(), QStringLiteral("New Project 22")); QCOMPARE(context1->name(), QStringLiteral("New Context 1")); QCOMPARE(context2->name(), QStringLiteral("New Context 2")); // WHEN projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop).thenReturn(new FakeJob(this)); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, project11Index); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop).exactly(1)); // WHEN a task is dropped on a context contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, context1Index); // THEN QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop).exactly(1)); // WHEN projectRepositoryMock(&Domain::ProjectRepository::dissociate).when(taskToDrop).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::dissociateAll).when(taskToDrop).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, inboxIndex); QTest::qWait(150); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::dissociate).when(taskToDrop).exactly(1)); QVERIFY(taskRepositoryMock(&Domain::TaskRepository::dissociateAll).when(taskToDrop).exactly(1)); // WHEN Domain::Task::Ptr taskToDrop2(new Domain::Task); projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop2).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop2)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, project11Index); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::associate).when(project11, taskToDrop2).exactly(1)); // WHEN two tasks are dropped on a context Domain::Task::Ptr taskToDrop3(new Domain::Task); Domain::Task::Ptr taskToDrop4(new Domain::Task); contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop3).thenReturn(new FakeJob(this)); contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop4).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop3 << taskToDrop4)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, context1Index); // THEN QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop3).exactly(1)); QVERIFY(contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop4).exactly(1)); // WHEN a task is drop on the workday Domain::Task::Ptr taskToDrop5(new Domain::Task); taskRepositoryMock(&Domain::TaskRepository::update).when(taskToDrop5).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop5)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, workdayIndex); // THEN QCOMPARE(taskToDrop5->startDate(), Utils::DateTime::currentDate()); // WHEN two task are drop on the workday Domain::Task::Ptr taskToDrop6(new Domain::Task); Domain::Task::Ptr taskToDrop7(new Domain::Task); taskRepositoryMock(&Domain::TaskRepository::update).when(taskToDrop6).thenReturn(new FakeJob(this)); taskRepositoryMock(&Domain::TaskRepository::update).when(taskToDrop7).thenReturn(new FakeJob(this)); data.reset(new QMimeData); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop6 << taskToDrop7)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, workdayIndex); // THEN QCOMPARE(taskToDrop6->startDate(), Utils::DateTime::currentDate()); QCOMPARE(taskToDrop7->startDate(), Utils::DateTime::currentDate()); } void shouldCreateInboxPage() { // GIVEN // Empty sources provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // Empty context provider auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // context mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); Utils::MockObject projectRepositoryMock; - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex inboxIndex = model->index(0, 0); QObject *inboxPage = pages.createPageForIndex(inboxIndex); QVERIFY(qobject_cast(inboxPage)); } void shouldCreateWorkdayPage() { // GIVEN // Empty sources provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // Empty context provider auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // context mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); Utils::MockObject projectRepositoryMock; - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex workdayIndex = model->index(1, 0); QObject *workdayPage = pages.createPageForIndex(workdayIndex); QVERIFY(qobject_cast(workdayPage)); } void shouldCreateProjectsPage() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 11")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 12")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // No contexts auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // data source mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); // projects mocking Utils::MockObject projectRepositoryMock; // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), Domain::ContextRepository::Ptr(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); const QModelIndex project2Index = model->index(1, 0, sourceIndex); QObject *projectsPage = pages.createPageForIndex(projectsIndex); QObject *sourcesPage = pages.createPageForIndex(sourceIndex); QObject *project1Page = pages.createPageForIndex(project1Index); QObject *project2Page = pages.createPageForIndex(project2Index); QVERIFY(!projectsPage); QVERIFY(!sourcesPage); QVERIFY(qobject_cast(project1Page)); QCOMPARE(qobject_cast(project1Page)->project(), project1); QVERIFY(qobject_cast(project2Page)); QCOMPARE(qobject_cast(project2Page)->project(), project2); } void shouldCreateContextsPage() { // GIVEN // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); // Empty sources provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); // projects mocking Utils::MockObject projectRepositoryMock; - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN QAbstractItemModel *model = pages.pageListModel(); // THEN const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); const QModelIndex context2Index = model->index(1, 0, contextsIndex); QObject *contextsPage = pages.createPageForIndex(contextsIndex); QObject *context1Page = pages.createPageForIndex(context1Index); QObject *context2Page = pages.createPageForIndex(context2Index); QVERIFY(!contextsPage); QVERIFY(qobject_cast(context1Page)); QCOMPARE(qobject_cast(context1Page)->context(), context1); QVERIFY(qobject_cast(context2Page)); QCOMPARE(qobject_cast(context2Page)->context(), context2); } void shouldAddProjects() { // GIVEN auto source = Domain::DataSource::Ptr::create(); Utils::MockObject projectRepositoryMock; projectRepositoryMock(&Domain::ProjectRepository::create).when(any(), any()) .thenReturn(new FakeJob(this)); - Presentation::AvailableTaskPagesModel pages(Domain::DataSourceQueries::Ptr(), + Presentation::AvailablePagesModel pages(Domain::DataSourceQueries::Ptr(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), Domain::ContextQueries::Ptr(), Domain::ContextRepository::Ptr(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN pages.addProject(QStringLiteral("Foo"), source); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::create).when(any(), any()) .exactly(1)); } void shouldGetAnErrorMessageWhenAddProjectFailed() { // GIVEN auto source = Domain::DataSource::Ptr::create(); source->setName(QStringLiteral("Source1")); Utils::MockObject projectRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); projectRepositoryMock(&Domain::ProjectRepository::create).when(any(), any()) .thenReturn(job); - Presentation::AvailableTaskPagesModel pages(Domain::DataSourceQueries::Ptr(), + Presentation::AvailablePagesModel pages(Domain::DataSourceQueries::Ptr(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), Domain::ContextQueries::Ptr(), Domain::ContextRepository::Ptr(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); // WHEN pages.addProject(QStringLiteral("Foo"), source); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add project Foo in dataSource Source1: Foo")); } void shouldAddContexts() { // GIVEN Utils::MockObject contextRepositoryMock; contextRepositoryMock(&Domain::ContextRepository::create).when(any()) .thenReturn(new FakeJob(this)); - Presentation::AvailableTaskPagesModel pages(Domain::DataSourceQueries::Ptr(), + Presentation::AvailablePagesModel pages(Domain::DataSourceQueries::Ptr(), Domain::ProjectQueries::Ptr(), Domain::ProjectRepository::Ptr(), Domain::ContextQueries::Ptr(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); // WHEN pages.addContext(QStringLiteral("Foo")); // THEN QVERIFY(contextRepositoryMock(&Domain::ContextRepository::create).when(any()) .exactly(1)); } void shouldGetAnErrorMessageWhenAddContextFailed() { // GIVEN Utils::MockObject contextRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); contextRepositoryMock(&Domain::ContextRepository::create).when(any()) .thenReturn(job); - Presentation::AvailableTaskPagesModel pages(Domain::DataSourceQueries::Ptr(), + Presentation::AvailablePagesModel pages(Domain::DataSourceQueries::Ptr(), Domain::ProjectQueries::Ptr(), Domain::ProjectRepository::Ptr(), Domain::ContextQueries::Ptr(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); // WHEN pages.addContext(QStringLiteral("Foo")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add context Foo: Foo")); } void shouldRemoveProject() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // No contexts auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // data source mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); // projects mocking Utils::MockObject projectRepositoryMock; // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), Domain::ContextRepository::Ptr(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); projectRepositoryMock(&Domain::ProjectRepository::remove).when(project1).thenReturn(new FakeJob(this)); // WHEN pages.removeItem(project1Index); // THEN QVERIFY(projectRepositoryMock(&Domain::ProjectRepository::remove).when(project1).exactly(1)); } void shouldGetAnErrorMessageWhenRemoveProjectFailed() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // No contexts auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // data source mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); // projects mocking Utils::MockObject projectRepositoryMock; // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), Domain::ContextRepository::Ptr(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); projectRepositoryMock(&Domain::ProjectRepository::remove).when(project1).thenReturn(job); // WHEN pages.removeItem(project1Index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove project Project 1: Foo")); } void shouldRemoveContext() { // GIVEN // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); // Empty sources provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), Domain::ProjectRepository::Ptr(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); contextRepositoryMock(&Domain::ContextRepository::remove).when(context1).thenReturn(new FakeJob(this)); // WHEN pages.removeItem(context1Index); // THEN QVERIFY(contextRepositoryMock(&Domain::ContextRepository::remove).when(context1).exactly(1)); } void shouldGetAnErrorMessageWhenRemoveContextFailed() { // GIVEN // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); // Empty sources provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // contexts mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), Domain::ProjectRepository::Ptr(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); contextRepositoryMock(&Domain::ContextRepository::remove).when(context1).thenReturn(job); // WHEN pages.removeItem(context1Index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot remove context context 1: Foo")); } void shouldGetAnErrorMessageWhenUpdateProjectFailed() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source1"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects under the source auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); Utils::MockObject projectRepositoryMock; Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); projectRepositoryMock(&Domain::ProjectRepository::update).when(project1).thenReturn(job); QVERIFY(model->setData(project1Index, "New Project 1")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify project Project 1: Foo")); } void shouldGetAnErrorMessageWhenUpdateContextFailed() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source1"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects under the source auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); Utils::MockObject projectRepositoryMock; Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), Domain::TaskRepository::Ptr()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); contextRepositoryMock(&Domain::ContextRepository::update).when(context1).thenReturn(job); QVERIFY(model->setData(context1Index, "New Context 1")); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot modify context context 1: Foo")); } void shouldGetAnErrorMessageWhenAssociateProjectFailed() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source1"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects under the source auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); // One task (used for dropping later on) Domain::Task::Ptr taskToDrop(new Domain::Task); taskToDrop->setTitle(QStringLiteral("taskDropped")); Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); Utils::MockObject projectRepositoryMock; Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; Utils::MockObject taskRepositoryMock; - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex projectsIndex = model->index(2, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); projectRepositoryMock(&Domain::ProjectRepository::associate).when(project1, taskToDrop).thenReturn(job); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, project1Index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add taskDropped to project Project 1: Foo")); } void shouldGetAnErrorMessageWhenAssociateContextFailed() { // GIVEN // One selected data source auto source = Domain::DataSource::Ptr::create(); source->setName("source1"); auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); sourceProvider->append(source); // Two projects under the source auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); auto project2 = Domain::Project::Ptr::create(); project2->setName(QStringLiteral("Project 2")); auto projectProvider = Domain::QueryResultProvider::Ptr::create(); auto projectResult = Domain::QueryResult::create(projectProvider); projectProvider->append(project1); projectProvider->append(project2); // Two contexts auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("context 1")); auto context2 = Domain::Context::Ptr::create(); context2->setName(QStringLiteral("context 2")); auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); contextProvider->append(context1); contextProvider->append(context2); // One task (used for dropping later on) Domain::Task::Ptr taskToDrop(new Domain::Task); taskToDrop->setTitle(QStringLiteral("taskDropped")); Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); dataSourceQueriesMock(&Domain::DataSourceQueries::findProjects).when(source).thenReturn(projectResult); Utils::MockObject projectRepositoryMock; Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; Utils::MockObject taskRepositoryMock; - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex contextsIndex = model->index(3, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); contextRepositoryMock(&Domain::ContextRepository::associate).when(context1, taskToDrop).thenReturn(job); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, context1Index); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot add taskDropped to context context 1: Foo")); } void shouldGetAnErrorMessageWhenDissociateFailed() { // GIVEN // Empty source provider auto sourceProvider = Domain::QueryResultProvider::Ptr::create(); auto sourceResult = Domain::QueryResult::create(sourceProvider); // Empty context provider auto contextProvider = Domain::QueryResultProvider::Ptr::create(); auto contextResult = Domain::QueryResult::create(contextProvider); // One task (used for dropping later on) Domain::Task::Ptr taskToDrop(new Domain::Task); taskToDrop->setTitle(QStringLiteral("taskDropped")); // context mocking Utils::MockObject contextQueriesMock; contextQueriesMock(&Domain::ContextQueries::findAll).when().thenReturn(contextResult); Utils::MockObject contextRepositoryMock; // sources mocking Utils::MockObject dataSourceQueriesMock; dataSourceQueriesMock(&Domain::DataSourceQueries::findAllSelected).when().thenReturn(sourceResult); Utils::MockObject projectRepositoryMock; Utils::MockObject taskRepositoryMock; - Presentation::AvailableTaskPagesModel pages(dataSourceQueriesMock.getInstance(), + Presentation::AvailablePagesModel pages(dataSourceQueriesMock.getInstance(), Domain::ProjectQueries::Ptr(), projectRepositoryMock.getInstance(), contextQueriesMock.getInstance(), contextRepositoryMock.getInstance(), Domain::TaskQueries::Ptr(), taskRepositoryMock.getInstance()); FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); const QModelIndex inboxIndex = model->index(0, 0); // WHEN auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); projectRepositoryMock(&Domain::ProjectRepository::dissociate).when(taskToDrop).thenReturn(job); taskRepositoryMock(&Domain::TaskRepository::dissociateAll).when(taskToDrop).thenReturn(new FakeJob(this)); auto data = std::make_unique(); data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << taskToDrop)); model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, inboxIndex); // THEN QTest::qWait(150); QCOMPARE(errorHandler.m_message, QStringLiteral("Cannot move taskDropped to Inbox: Foo")); } }; -ZANSHIN_TEST_MAIN(AvailableTaskPagesModelTest) +ZANSHIN_TEST_MAIN(AvailablePagesModelTest) -#include "availabletaskpagesmodeltest.moc" +#include "availablepagesmodeltest.moc" diff --git a/tests/units/presentation/availablepagessortfilterproxymodeltest.cpp b/tests/units/presentation/availablepagessortfilterproxymodeltest.cpp index c83b7b15..2056f73a 100644 --- a/tests/units/presentation/availablepagessortfilterproxymodeltest.cpp +++ b/tests/units/presentation/availablepagessortfilterproxymodeltest.cpp @@ -1,106 +1,106 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens Copyright 2015 David Faure 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 "utils/mockobject.h" #include "domain/contextqueries.h" #include "domain/contextrepository.h" #include "domain/projectqueries.h" #include "domain/projectrepository.h" #include "domain/task.h" #include "domain/taskrepository.h" +#include "presentation/availablepagesmodel.h" #include "presentation/availablepagessortfilterproxymodel.h" -#include "presentation/availabletaskpagesmodel.h" #include "presentation/contextpagemodel.h" #include "presentation/projectpagemodel.h" #include "presentation/querytreemodelbase.h" #include "testlib/fakejob.h" using namespace mockitopp; using namespace mockitopp::matcher; static QString extractChildRowsTexts( QAbstractItemModel *model, int row, const QModelIndex &parent = QModelIndex() ) { QString result; const QModelIndex index = model->index(row, 0, parent); const int children = model->rowCount(index); for (int row = 0; row < children; ++row) { const QString txt = model->index(row, 0, index).data().toString(); result += txt.isEmpty() ? QStringLiteral(" ") : txt; if ( row + 1 < children ) result += ';'; } return result; } class AvailablePagesSortFilterProxyModelTest : public QObject { Q_OBJECT private slots: void shouldSortSecondLevel() { // GIVEN a tree model as source QStandardItemModel sourceModel; sourceModel.appendRow(new QStandardItem(QStringLiteral("Projects"))); sourceModel.item(0, 0)->appendRow(new QStandardItem(QStringLiteral("D"))); sourceModel.item(0, 0)->appendRow(new QStandardItem(QStringLiteral("A"))); sourceModel.item(0, 0)->appendRow(new QStandardItem(QStringLiteral("F"))); sourceModel.appendRow(new QStandardItem(QStringLiteral("Contexts"))); sourceModel.item(1, 0)->appendRow(new QStandardItem(QStringLiteral("K"))); sourceModel.item(1, 0)->appendRow(new QStandardItem(QStringLiteral("D"))); sourceModel.item(1, 0)->appendRow(new QStandardItem(QStringLiteral("E"))); sourceModel.appendRow(new QStandardItem(QStringLiteral("Tags"))); QCOMPARE(sourceModel.index(0, 0).data().toString(), QStringLiteral("Projects")); QCOMPARE(extractChildRowsTexts(&sourceModel, 0), QStringLiteral("D;A;F")); QCOMPARE(sourceModel.index(1, 0).data().toString(), QStringLiteral("Contexts")); QCOMPARE(extractChildRowsTexts(&sourceModel, 1), QStringLiteral("K;D;E")); QCOMPARE(sourceModel.index(2, 0).data().toString(), QStringLiteral("Tags")); // WHEN putting an AvailablePagesSortFilterProxyModel on top Presentation::AvailablePagesSortFilterProxyModel proxy; proxy.setSourceModel(&sourceModel); // THEN the projects and contexts should be sorted (but not the toplevel items) QCOMPARE(proxy.index(0, 0).data().toString(), QStringLiteral("Projects")); QCOMPARE(extractChildRowsTexts(&proxy, 0), QStringLiteral("A;D;F")); QCOMPARE(proxy.index(1, 0).data().toString(), QStringLiteral("Contexts")); QCOMPARE(extractChildRowsTexts(&proxy, 1), QStringLiteral("D;E;K")); QCOMPARE(proxy.index(2, 0).data().toString(), QStringLiteral("Tags")); } private: }; ZANSHIN_TEST_MAIN(AvailablePagesSortFilterProxyModelTest) #include "availablepagessortfilterproxymodeltest.moc" diff --git a/tests/units/widgets/availablepagesviewtest.cpp b/tests/units/widgets/availablepagesviewtest.cpp index 28a90039..23842f13 100644 --- a/tests/units/widgets/availablepagesviewtest.cpp +++ b/tests/units/widgets/availablepagesviewtest.cpp @@ -1,593 +1,532 @@ /* 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 "domain/project.h" #include "domain/context.h" #include "presentation/metatypes.h" #include "presentation/querytreemodelbase.h" #include "widgets/availablepagesview.h" #include "widgets/newprojectdialog.h" #include "widgets/quickselectdialog.h" #include "messageboxstub.h" class NewProjectDialogStub : public Widgets::NewProjectDialogInterface { public: typedef QSharedPointer Ptr; explicit NewProjectDialogStub() : parent(Q_NULLPTR), execCount(0), sourceModel(Q_NULLPTR), source(Domain::DataSource::Ptr::create()) { } int exec() Q_DECL_OVERRIDE { execCount++; return QDialog::Accepted; } void setDataSourcesModel(QAbstractItemModel *model) Q_DECL_OVERRIDE { sourceModel = model; } QString name() const Q_DECL_OVERRIDE { return QStringLiteral("name"); } Domain::DataSource::Ptr dataSource() const Q_DECL_OVERRIDE { return source; } QWidget *parent; int execCount; QAbstractItemModel *sourceModel; Domain::DataSource::Ptr source; }; class QuickSelectDialogStub : public Widgets::QuickSelectDialogInterface { public: typedef QSharedPointer Ptr; explicit QuickSelectDialogStub() : parent(Q_NULLPTR), execCount(0), itemModel(Q_NULLPTR) { } int exec() Q_DECL_OVERRIDE { execCount++; return QDialog::Accepted; } void setModel(QAbstractItemModel *model) Q_DECL_OVERRIDE { itemModel = model; } QPersistentModelIndex selectedIndex() const Q_DECL_OVERRIDE { return index; } QWidget *parent; int execCount; QAbstractItemModel *itemModel; QPersistentModelIndex index; }; class AvailablePagesModelStub : public QObject { Q_OBJECT public: explicit AvailablePagesModelStub(QObject *parent = Q_NULLPTR) : QObject(parent) { } public slots: void addProject(const QString &name, const Domain::DataSource::Ptr &source) { projectNames << name; sources << source; } void addContext(const QString &name) { contextNames << name; } void addTag(const QString &name) { tagNames << name; } void removeItem(const QModelIndex &index) { projectRemoved = index.data().toString(); } public Q_SLOTS: QObject *createPageForIndex(const QModelIndex &) { return Q_NULLPTR; } public: QStringList projectNames; QStringList contextNames; QStringList tagNames; QList sources; QString projectRemoved; }; class AvailablePagesViewTest : public QObject { Q_OBJECT private slots: void shouldHaveDefaultState() { Widgets::AvailablePagesView available; QVERIFY(!available.model()); QVERIFY(!available.projectSourcesModel()); QVERIFY(available.defaultProjectSource().isNull()); auto pagesView = available.findChild(QStringLiteral("pagesView")); QVERIFY(pagesView); QVERIFY(pagesView->isVisibleTo(&available)); QVERIFY(!pagesView->header()->isVisibleTo(&available)); QCOMPARE(pagesView->dragDropMode(), QTreeView::DropOnly); auto actionBar = available.findChild(QStringLiteral("actionBar")); QVERIFY(actionBar); QVERIFY(actionBar->isVisibleTo(&available)); auto addProjectAction = available.findChild(QStringLiteral("addProjectAction")); QVERIFY(addProjectAction); auto addContextAction = available.findChild(QStringLiteral("addContextAction")); QVERIFY(addContextAction); - auto addTagAction = available.findChild(QStringLiteral("addTagAction")); - QVERIFY(addTagAction); auto removeAction = available.findChild(QStringLiteral("removeAction")); QVERIFY(removeAction); auto goPreviousAction = available.findChild(QStringLiteral("goPreviousAction")); QVERIFY(goPreviousAction); auto goNextAction = available.findChild(QStringLiteral("goNextAction")); QVERIFY(goNextAction); auto goToAction = available.findChild(QStringLiteral("goToAction")); QVERIFY(goToAction); auto projectDialogFactory = available.projectDialogFactory(); QVERIFY(projectDialogFactory(&available).dynamicCast()); auto quickSelectDialogFactory = available.quickSelectDialogFactory(); QVERIFY(quickSelectDialogFactory(&available).dynamicCast()); auto actions = available.globalActions(); QCOMPARE(actions.value(QStringLiteral("pages_project_add")), addProjectAction); QCOMPARE(actions.value(QStringLiteral("pages_context_add")), addContextAction); - QCOMPARE(actions.value(QStringLiteral("pages_tag_add")), addTagAction); QCOMPARE(actions.value(QStringLiteral("pages_remove")), removeAction); QCOMPARE(actions.value(QStringLiteral("pages_go_previous")), goPreviousAction); QCOMPARE(actions.value(QStringLiteral("pages_go_next")), goNextAction); QCOMPARE(actions.value(QStringLiteral("pages_go_to")), goToAction); } void shouldShowOnlyAddActionsNeededByTheModel_data() { QTest::addColumn("hasProjects"); QTest::addColumn("hasContexts"); QTest::addColumn("hasTags"); QTest::newRow("!projects !contexts !tags") << false << false << false; QTest::newRow("!projects !contexts tags") << false << false << true; QTest::newRow("!projects contexts !tags") << false << true << false; QTest::newRow("!projects contexts tags") << false << true << true; QTest::newRow("projects !contexts !tags") << true << false << false; QTest::newRow("projects !contexts tags") << true << false << true; QTest::newRow("projects contexts !tags") << true << true << false; QTest::newRow("projects contexts tags") << true << true << true; } - void shouldShowOnlyAddActionsNeededByTheModel() - { - // GIVEN - QFETCH(bool, hasProjects); - QFETCH(bool, hasContexts); - QFETCH(bool, hasTags); - - AvailablePagesModelStub stubPagesModel; - stubPagesModel.setProperty("hasProjectPages", hasProjects); - stubPagesModel.setProperty("hasContextPages", hasContexts); - stubPagesModel.setProperty("hasTagPages", hasTags); - - Widgets::AvailablePagesView available; - auto addProjectAction = available.findChild(QStringLiteral("addProjectAction")); - QVERIFY(addProjectAction); - auto addContextAction = available.findChild(QStringLiteral("addContextAction")); - QVERIFY(addContextAction); - auto addTagAction = available.findChild(QStringLiteral("addTagAction")); - QVERIFY(addTagAction); - - // WHEN - available.setModel(&stubPagesModel); - - // THEN - QCOMPARE(addProjectAction->isVisible(), hasProjects); - QCOMPARE(addContextAction->isVisible(), hasContexts); - QCOMPARE(addTagAction->isVisible(), hasTags); - } - void shouldDisplayListFromPageModel() { // GIVEN QStringListModel model(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C") ); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); Widgets::AvailablePagesView available; auto pagesView = available.findChild(QStringLiteral("pagesView")); QVERIFY(pagesView); QVERIFY(!pagesView->model()); // WHEN available.setModel(&stubPagesModel); QTest::qWait(10); // THEN QCOMPARE(pagesView->model(), &model); QCOMPARE(pagesView->selectionModel()->currentIndex(), model.index(0, 0)); } void shouldNotCrashWithNullModel() { // GIVEN QStringListModel model(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C") ); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); Widgets::AvailablePagesView available; available.setModel(&stubPagesModel); QTest::qWait(10); auto pagesView = available.findChild(QStringLiteral("pagesView")); QVERIFY(pagesView); QCOMPARE(pagesView->model(), &model); // WHEN available.setModel(Q_NULLPTR); QTest::qWait(10); // THEN QVERIFY(!available.isEnabled()); QVERIFY(!pagesView->model()); } void shouldAddNewProjects() { // GIVEN AvailablePagesModelStub model; QStringListModel sourceModel; auto dialogStub = NewProjectDialogStub::Ptr::create(); auto source = Domain::DataSource::Ptr::create(); Widgets::AvailablePagesView available; available.setModel(&model); available.setProjectSourcesModel(&sourceModel); available.setDefaultProjectSource(source); available.setProjectDialogFactory([dialogStub] (QWidget *parent) { dialogStub->parent = parent; return dialogStub; }); auto addProjectAction = available.findChild(QStringLiteral("addProjectAction")); // WHEN addProjectAction->trigger(); // THEN QCOMPARE(dialogStub->execCount, 1); QCOMPARE(dialogStub->parent, &available); QCOMPARE(dialogStub->sourceModel, &sourceModel); QCOMPARE(model.projectNames.size(), 1); QCOMPARE(model.projectNames.first(), dialogStub->name()); QCOMPARE(model.sources.size(), 1); QCOMPARE(model.sources.first(), dialogStub->dataSource()); QCOMPARE(available.defaultProjectSource(), dialogStub->dataSource()); } void shouldAddNewContexts() { // GIVEN AvailablePagesModelStub model; QStringListModel sourceModel; auto dialogStub = NewProjectDialogStub::Ptr::create(); auto source = Domain::DataSource::Ptr::create(); auto msgBoxStub = MessageBoxStub::Ptr::create(); msgBoxStub->setTextInput(QStringLiteral("Foo")); Widgets::AvailablePagesView available; available.setModel(&model); available.setProjectSourcesModel(&sourceModel); available.setDefaultProjectSource(source); available.setMessageBoxInterface(msgBoxStub); auto addContextAction = available.findChild(QStringLiteral("addContextAction")); // WHEN addContextAction->trigger(); // THEN QVERIFY(msgBoxStub->called()); QCOMPARE(model.contextNames.size(), 1); QCOMPARE(model.contextNames.first(), QStringLiteral("Foo")); } - void shouldAddNewTags() - { - // GIVEN - AvailablePagesModelStub model; - QStringListModel sourceModel; - auto dialogStub = NewProjectDialogStub::Ptr::create(); - - auto source = Domain::DataSource::Ptr::create(); - - auto msgBoxStub = MessageBoxStub::Ptr::create(); - msgBoxStub->setTextInput(QStringLiteral("Foo")); - - Widgets::AvailablePagesView available; - available.setModel(&model); - available.setProjectSourcesModel(&sourceModel); - available.setDefaultProjectSource(source); - available.setMessageBoxInterface(msgBoxStub); - - auto addTagAction = available.findChild(QStringLiteral("addTagAction")); - - // WHEN - addTagAction->trigger(); - - // THEN - QVERIFY(msgBoxStub->called()); - QCOMPARE(model.tagNames.size(), 1); - QCOMPARE(model.tagNames.first(), QStringLiteral("Foo")); - } - void shouldRemoveAPage_data() { QTest::addColumn("object"); QTest::addColumn("actionEnabled"); auto project1 = Domain::Project::Ptr::create(); project1->setName(QStringLiteral("Project 1")); QTest::newRow("project") << QObjectPtr(project1) << true; auto context1 = Domain::Context::Ptr::create(); context1->setName(QStringLiteral("Context 1")); QTest::newRow("context") << QObjectPtr(context1) << true; QTest::newRow("non removable") << QObjectPtr::create() << false; } void shouldRemoveAPage() { QFETCH(QObjectPtr, object); QFETCH(bool, actionEnabled); // GIVEN QStringList list; list << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C"); QStandardItemModel model; for (int row = 0; row < list.count(); ++row) { model.setItem(row, new QStandardItem(list.at(row))); } QVERIFY(model.setData(model.index(0, 0), QVariant::fromValue(object), Presentation::QueryTreeModelBase::ObjectRole)); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); Widgets::AvailablePagesView available; auto pagesView = available.findChild(QStringLiteral("pagesView")); QVERIFY(pagesView); QVERIFY(!pagesView->model()); available.setModel(&stubPagesModel); QTest::qWait(10); auto removeAction = available.findChild(QStringLiteral("removeAction")); auto msgbox = MessageBoxStub::Ptr::create(); available.setMessageBoxInterface(msgbox); // WHEN if (actionEnabled) removeAction->trigger(); // THEN QCOMPARE(removeAction->isEnabled(), actionEnabled); if (actionEnabled) { QCOMPARE(stubPagesModel.projectRemoved, list.first()); } } void shouldGoToPreviousSelectablePage() { // GIVEN QStandardItemModel model; model.appendRow(new QStandardItem(QStringLiteral("Inbox"))); auto projects = new QStandardItem(QStringLiteral("Projects")); projects->setFlags(Qt::NoItemFlags); model.appendRow(projects); projects->appendRow(new QStandardItem(QStringLiteral("Project 1"))); projects->appendRow(new QStandardItem(QStringLiteral("Project 2"))); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); Widgets::AvailablePagesView available; auto pagesView = available.findChild(QStringLiteral("pagesView")); QVERIFY(pagesView); QVERIFY(!pagesView->model()); available.setModel(&stubPagesModel); QTest::qWait(10); auto goPreviousAction = available.findChild(QStringLiteral("goPreviousAction")); pagesView->setCurrentIndex(model.index(1, 0, model.indexFromItem(projects))); // WHEN goPreviousAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(0, 0, model.indexFromItem(projects))); // WHEN goPreviousAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(0, 0)); // WHEN goPreviousAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(0, 0)); } void shouldGoToNextSelectablePage() { // GIVEN QStandardItemModel model; model.appendRow(new QStandardItem(QStringLiteral("Inbox"))); auto projects = new QStandardItem(QStringLiteral("Projects")); projects->setFlags(Qt::NoItemFlags); model.appendRow(projects); projects->appendRow(new QStandardItem(QStringLiteral("Project 1"))); projects->appendRow(new QStandardItem(QStringLiteral("Project 2"))); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); Widgets::AvailablePagesView available; auto pagesView = available.findChild(QStringLiteral("pagesView")); QVERIFY(pagesView); QVERIFY(!pagesView->model()); available.setModel(&stubPagesModel); QTest::qWait(10); auto goNextAction = available.findChild(QStringLiteral("goNextAction")); pagesView->setCurrentIndex(model.index(0, 0)); // WHEN goNextAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(0, 0, model.indexFromItem(projects))); // WHEN goNextAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(1, 0, model.indexFromItem(projects))); // WHEN goNextAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(1, 0, model.indexFromItem(projects))); } void shouldGoToUserSelectedIndex() { // GIVEN QStandardItemModel model; model.appendRow(new QStandardItem(QStringLiteral("Inbox"))); auto projects = new QStandardItem(QStringLiteral("Projects")); projects->setFlags(Qt::NoItemFlags); model.appendRow(projects); projects->appendRow(new QStandardItem(QStringLiteral("Project 1"))); projects->appendRow(new QStandardItem(QStringLiteral("Project 2"))); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); auto dialogStub = QuickSelectDialogStub::Ptr::create(); // Project 2 will be selected dialogStub->index = model.index(1, 0, model.index(1, 0)); Widgets::AvailablePagesView available; available.setModel(&stubPagesModel); available.setQuickSelectDialogFactory([dialogStub] (QWidget *parent) { dialogStub->parent = parent; return dialogStub; }); auto pagesView = available.findChild(QStringLiteral("pagesView")); QVERIFY(pagesView); QCOMPARE(pagesView->model(), &model); auto goToAction = available.findChild(QStringLiteral("goToAction")); // WHEN goToAction->trigger(); // THEN QCOMPARE(dialogStub->execCount, 1); QCOMPARE(dialogStub->parent, &available); QCOMPARE(dialogStub->itemModel, &model); QCOMPARE(QPersistentModelIndex(pagesView->currentIndex()), dialogStub->index); } }; ZANSHIN_TEST_MAIN(AvailablePagesViewTest) #include "availablepagesviewtest.moc"