diff --git a/src/presentation/CMakeLists.txt b/src/presentation/CMakeLists.txt --- a/src/presentation/CMakeLists.txt +++ b/src/presentation/CMakeLists.txt @@ -11,6 +11,7 @@ metatypes.cpp pagemodel.cpp projectpagemodel.cpp + alltaskspagemodel.cpp querytreemodelbase.cpp runningtaskmodelinterface.cpp runningtaskmodel.cpp diff --git a/src/presentation/pagemodel.h b/src/presentation/alltaskspagemodel.h copy from src/presentation/pagemodel.h copy to src/presentation/alltaskspagemodel.h --- a/src/presentation/pagemodel.h +++ b/src/presentation/alltaskspagemodel.h @@ -1,6 +1,6 @@ /* This file is part of Zanshin - Copyright 2014 Kevin Ottens + Copyright 2019 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 @@ -22,40 +22,35 @@ */ -#ifndef PRESENTATION_PAGEMODEL_H -#define PRESENTATION_PAGEMODEL_H +#ifndef PRESENTATION_ALLTASKSPAGEMODEL_H +#define PRESENTATION_ALLTASKSPAGEMODEL_H -#include +#include "presentation/pagemodel.h" -#include - -#include "domain/task.h" - -#include "presentation/metatypes.h" -#include "presentation/errorhandlingmodelbase.h" +#include "domain/taskqueries.h" +#include "domain/taskrepository.h" namespace Presentation { -class PageModel : public QObject, public ErrorHandlingModelBase +class AllTasksPageModel : public PageModel { Q_OBJECT - Q_PROPERTY(QAbstractItemModel* centralListModel READ centralListModel) public: - explicit PageModel(QObject *parent = nullptr); - - QAbstractItemModel *centralListModel(); + explicit AllTasksPageModel(const Domain::TaskQueries::Ptr &taskQueries, + const Domain::TaskRepository::Ptr &taskRepository, + QObject *parent = nullptr); -public slots: - virtual Domain::Task::Ptr addItem(const QString &title, const QModelIndex &parentIndex = QModelIndex()) = 0; - virtual void removeItem(const QModelIndex &index) = 0; - virtual void promoteItem(const QModelIndex &index) = 0; + Domain::Task::Ptr addItem(const QString &title, const QModelIndex &parentIndex = QModelIndex()) override; + void removeItem(const QModelIndex &index) override; + void promoteItem(const QModelIndex &index) override; private: - virtual QAbstractItemModel *createCentralListModel() = 0; + QAbstractItemModel *createCentralListModel() override; - QAbstractItemModel *m_centralListModel; + Domain::TaskQueries::Ptr m_taskQueries; + Domain::TaskRepository::Ptr m_taskRepository; }; } -#endif // PRESENTATION_PAGEMODEL_H +#endif // PRESENTATION_ALLTASKSPAGEMODEL_H diff --git a/src/presentation/workdaypagemodel.cpp b/src/presentation/alltaskspagemodel.cpp copy from src/presentation/workdaypagemodel.cpp copy to src/presentation/alltaskspagemodel.cpp --- a/src/presentation/workdaypagemodel.cpp +++ b/src/presentation/alltaskspagemodel.cpp @@ -1,6 +1,6 @@ /* This file is part of Zanshin - Copyright 2015 Theo Vaucher + Copyright 2019 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 @@ -22,129 +22,82 @@ */ -#include "workdaypagemodel.h" +#include "alltaskspagemodel.h" #include #include -#include "domain/taskqueries.h" -#include "domain/taskrepository.h" - #include "presentation/querytreemodel.h" -#include "utils/datetime.h" - using namespace Presentation; -WorkdayPageModel::WorkdayPageModel(const Domain::TaskQueries::Ptr &taskQueries, - const Domain::TaskRepository::Ptr &taskRepository, - QObject *parent) +AllTasksPageModel::AllTasksPageModel(const Domain::TaskQueries::Ptr &taskQueries, + const Domain::TaskRepository::Ptr &taskRepository, + QObject *parent) : PageModel(parent), m_taskQueries(taskQueries), m_taskRepository(taskRepository) { } -Domain::Task::Ptr WorkdayPageModel::addItem(const QString &title, const QModelIndex &parentIndex) +Domain::Task::Ptr AllTasksPageModel::addItem(const QString &title, const QModelIndex &parentIndex) { const auto parentData = parentIndex.data(QueryTreeModelBase::ObjectRole); const auto parentTask = parentData.value(); auto task = Domain::Task::Ptr::create(); task->setTitle(title); - if (!parentTask) - task->setStartDate(Utils::DateTime::currentDate()); const auto job = parentTask ? m_taskRepository->createChild(task, parentTask) : m_taskRepository->create(task); - installHandler(job, i18n("Cannot add task %1 in Workday", title)); + installHandler(job, i18n("Cannot add task %1", title)); return task; } -void WorkdayPageModel::removeItem(const QModelIndex &index) +void AllTasksPageModel::removeItem(const QModelIndex &index) { QVariant data = index.data(QueryTreeModelBase::ObjectRole); auto task = data.value(); if (task) { const auto job = m_taskRepository->remove(task); - installHandler(job, i18n("Cannot remove task %1 from Workday", task->title())); + installHandler(job, i18n("Cannot remove task %1", task->title())); } } -void WorkdayPageModel::promoteItem(const QModelIndex &index) +void AllTasksPageModel::promoteItem(const QModelIndex &index) { QVariant data = index.data(QueryTreeModelBase::ObjectRole); auto task = data.value(); Q_ASSERT(task); const auto job = m_taskRepository->promoteToProject(task); installHandler(job, i18n("Cannot promote task %1 to be a project", task->title())); } -QAbstractItemModel *WorkdayPageModel::createCentralListModel() +QAbstractItemModel *AllTasksPageModel::createCentralListModel() { auto query = [this](const Domain::Task::Ptr &task) -> Domain::QueryResultInterface::Ptr { if (!task) - return m_taskQueries->findWorkdayTopLevel(); + return m_taskQueries->findTopLevel(); else return m_taskQueries->findChildren(task); }; - auto flags = [](const Domain::Task::Ptr &task) { - const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable - | Qt::ItemIsEnabled - | Qt::ItemIsEditable - | Qt::ItemIsDragEnabled; - - return task ? (defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled) : defaultFlags; + auto flags = [](const Domain::Task::Ptr &) { + return Qt::ItemIsSelectable + | Qt::ItemIsEnabled + | Qt::ItemIsEditable + | Qt::ItemIsDragEnabled + | Qt::ItemIsUserCheckable + | Qt::ItemIsDropEnabled; }; - struct AdditionalData - { - bool childTask = false; - Domain::QueryResult::Ptr projectQueryResult; - // later on we'll want the context query as well - }; - using AdditionalInfo = QSharedPointer; - - auto data = [](const Domain::Task::Ptr &task, int role, const AdditionalInfo &info) -> QVariant { - switch (role) { - case Qt::DisplayRole: - case Qt::EditRole: - return task->title(); - case Qt::CheckStateRole: - return task->isDone() ? Qt::Checked : Qt::Unchecked; - case Presentation::QueryTreeModelBase::AdditionalInfoRole: - if (!info || info->childTask) - return QString(); - if (info->projectQueryResult && !info->projectQueryResult->data().isEmpty()) { - Domain::Project::Ptr project = info->projectQueryResult->data().at(0); - return i18n("Project: %1", project->name()); - } - return i18n("Inbox"); // TODO add source name - default: - break; - } - return QVariant(); + auto data = [](const Domain::Task::Ptr &task, int role, const TaskExtraDataPtr &info) -> QVariant { + return dataForTaskWithProject(task, role, info); }; - auto fetchAdditionalInfo = [this](const QModelIndex &index, const Domain::Task::Ptr &task) -> AdditionalInfo { - AdditionalInfo info = AdditionalInfo::create(); - if (index.parent().isValid()) { // children are in the same collection as their parent, so the same project - info->childTask = true; - return info; - } - - info->projectQueryResult = m_taskQueries->findProject(task); - if (info->projectQueryResult) { - QPersistentModelIndex persistentIndex(index); - info->projectQueryResult->addPostInsertHandler([persistentIndex](const Domain::Project::Ptr &, int) { - // When a project was found (inserted into the result), update the rendering of the item - auto model = const_cast(persistentIndex.model()); - model->dataChanged(persistentIndex, persistentIndex); - }); - } - return info; + auto fetchAdditionalInfo = [this](const QModelIndex &index, const Domain::Task::Ptr &task) { + return fetchTaskExtraData(m_taskQueries, index, task); }; auto setData = [this](const Domain::Task::Ptr &task, const QVariant &value, int role) { @@ -159,10 +112,20 @@ task->setDone(value.toInt() == Qt::Checked); const auto job = m_taskRepository->update(task); - installHandler(job, i18n("Cannot modify task %1 in Workday", currentTitle)); + installHandler(job, i18n("Cannot modify task %1", currentTitle)); return true; }; + auto drag = [](const Domain::Task::List &tasks) -> QMimeData* { + if (tasks.isEmpty()) + return nullptr; + + auto data = new QMimeData; + data->setData(QStringLiteral("application/x-zanshin-object"), "object"); + data->setProperty("objects", QVariant::fromValue(tasks)); + return data; + }; + auto drop = [this](const QMimeData *mimeData, Qt::DropAction, const Domain::Task::Ptr &parentTask) { if (!mimeData->hasFormat(QStringLiteral("application/x-zanshin-object"))) return false; @@ -176,28 +139,14 @@ const auto job = m_taskRepository->associate(parentTask, childTask); installHandler(job, i18n("Cannot move task %1 as sub-task of %2", childTask->title(), parentTask->title())); } else { - childTask->setStartDate(Utils::DateTime::currentDate()); - // TODO something like m_taskRepository->update(childTask) is missing here - // It was removed in commit c97a99bf because it led to a LLCONFLICT in akonadi (due to dissociate below). - // The removal broke tests-features-workday-workdaydraganddropfeature (date not changed). - auto job = m_taskRepository->dissociate(childTask); installHandler(job, i18n("Cannot deparent task %1 from its parent", childTask->title())); } } return true; }; - auto drag = [](const Domain::Task::List &tasks) -> QMimeData* { - if (tasks.isEmpty()) - return nullptr; - - auto data = new QMimeData; - data->setData(QStringLiteral("application/x-zanshin-object"), "object"); - data->setProperty("objects", QVariant::fromValue(tasks)); - return data; - }; - return new QueryTreeModel(query, flags, data, setData, drop, drag, fetchAdditionalInfo, this); + return new QueryTreeModel(query, flags, data, setData, drop, drag, fetchAdditionalInfo, this); } diff --git a/src/presentation/availablepagesmodel.h b/src/presentation/availablepagesmodel.h --- a/src/presentation/availablepagesmodel.h +++ b/src/presentation/availablepagesmodel.h @@ -87,6 +87,7 @@ QObjectPtr m_workdayObject; QObjectPtr m_projectsObject; QObjectPtr m_contextsObject; + QObjectPtr m_allTasksObject; }; } diff --git a/src/presentation/availablepagesmodel.cpp b/src/presentation/availablepagesmodel.cpp --- a/src/presentation/availablepagesmodel.cpp +++ b/src/presentation/availablepagesmodel.cpp @@ -35,6 +35,7 @@ #include "domain/projectrepository.h" #include "domain/taskrepository.h" +#include "presentation/alltaskspagemodel.h" #include "presentation/availablepagessortfilterproxymodel.h" #include "presentation/contextpagemodel.h" #include "presentation/inboxpagemodel.h" @@ -116,6 +117,12 @@ this); contextPageModel->setErrorHandler(errorHandler()); return contextPageModel; + } else if (object == m_allTasksObject) { + auto allTasksPageModel = new AllTasksPageModel(m_taskQueries, + m_taskRepository, + this); + allTasksPageModel->setErrorHandler(errorHandler()); + return allTasksPageModel; } return nullptr; @@ -161,12 +168,15 @@ m_projectsObject->setProperty("name", i18n("Projects")); m_contextsObject = QObjectPtr::create(); m_contextsObject->setProperty("name", i18n("Contexts")); + m_allTasksObject = QObjectPtr::create(); + m_allTasksObject->setProperty("name", i18n("All Tasks")); 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); + m_rootsProvider->append(m_allTasksObject); auto query = [this](const QObjectPtr &object) -> Domain::QueryResultInterface::Ptr { if (!object) @@ -189,12 +199,15 @@ const Qt::ItemFlags immutableNodeFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDropEnabled; + const Qt::ItemFlags nonDroppableNodeFlags = Qt::ItemIsSelectable + | Qt::ItemIsEnabled; const Qt::ItemFlags structureNodeFlags = Qt::NoItemFlags; return object.objectCast() ? defaultFlags : object.objectCast() ? defaultFlags : object == m_inboxObject ? immutableNodeFlags : object == m_workdayObject ? immutableNodeFlags + : object == m_allTasksObject ? nonDroppableNodeFlags : structureNodeFlags; }; @@ -211,6 +224,7 @@ || object == m_workdayObject || object == m_projectsObject || object == m_contextsObject + || object == m_allTasksObject || object.objectCast())) { return QVariant(); } @@ -222,6 +236,7 @@ : (object == m_workdayObject) ? QStringLiteral("go-jump-today") : (object == m_projectsObject) ? QStringLiteral("folder") : (object == m_contextsObject) ? QStringLiteral("folder") + : (object == m_allTasksObject) ? QStringLiteral("view-pim-tasks") : object.objectCast() ? QStringLiteral("folder") : object.objectCast() ? QStringLiteral("view-pim-notes") : QStringLiteral("view-pim-tasks"); @@ -244,6 +259,7 @@ || object == m_workdayObject || object == m_projectsObject || object == m_contextsObject + || object == m_allTasksObject || object.objectCast()) { return false; } diff --git a/src/presentation/pagemodel.h b/src/presentation/pagemodel.h --- a/src/presentation/pagemodel.h +++ b/src/presentation/pagemodel.h @@ -29,7 +29,9 @@ #include +#include "domain/project.h" #include "domain/task.h" +#include "domain/taskqueries.h" #include "presentation/metatypes.h" #include "presentation/errorhandlingmodelbase.h" @@ -50,6 +52,20 @@ virtual void removeItem(const QModelIndex &index) = 0; virtual void promoteItem(const QModelIndex &index) = 0; +protected: + struct TaskExtraData + { + bool childTask = false; + Domain::QueryResult::Ptr projectQueryResult; + // later on we'll want the context query as well + }; + using TaskExtraDataPtr = QSharedPointer; + + using ProjectQueryPtr = Domain::QueryResult::Ptr; + static TaskExtraDataPtr fetchTaskExtraData(Domain::TaskQueries::Ptr taskQueries, + const QModelIndex &index, const Domain::Task::Ptr &task); + static QVariant dataForTaskWithProject(const Domain::Task::Ptr &task, int role, const TaskExtraDataPtr &info); + private: virtual QAbstractItemModel *createCentralListModel() = 0; diff --git a/src/presentation/pagemodel.cpp b/src/presentation/pagemodel.cpp --- a/src/presentation/pagemodel.cpp +++ b/src/presentation/pagemodel.cpp @@ -24,6 +24,10 @@ #include "pagemodel.h" +#include "presentation/querytreemodel.h" + +#include + using namespace Presentation; PageModel::PageModel(QObject *parent) @@ -38,3 +42,46 @@ m_centralListModel = createCentralListModel(); return m_centralListModel; } + +PageModel::TaskExtraDataPtr PageModel::fetchTaskExtraData(Domain::TaskQueries::Ptr taskQueries, + const QModelIndex &index, const Domain::Task::Ptr &task) +{ + TaskExtraDataPtr info = TaskExtraDataPtr::create(); + if (index.parent().isValid()) { // children are in the same collection as their parent, so the same project + info->childTask = true; + return info; + } + + info->projectQueryResult = taskQueries->findProject(task); + if (info->projectQueryResult) { + QPersistentModelIndex persistentIndex(index); + info->projectQueryResult->addPostInsertHandler([persistentIndex](const Domain::Project::Ptr &, int) { + // When a project was found (inserted into the result), update the rendering of the item + auto model = const_cast(persistentIndex.model()); + model->dataChanged(persistentIndex, persistentIndex); + }); + } + return info; +} + +QVariant PageModel::dataForTaskWithProject(const Domain::Task::Ptr &task, int role, const TaskExtraDataPtr &info) +{ + switch (role) { + case Qt::DisplayRole: + case Qt::EditRole: + return task->title(); + case Qt::CheckStateRole: + return task->isDone() ? Qt::Checked : Qt::Unchecked; + case Presentation::QueryTreeModelBase::AdditionalInfoRole: + if (!info || info->childTask) + return QString(); + if (info->projectQueryResult && !info->projectQueryResult->data().isEmpty()) { + Domain::Project::Ptr project = info->projectQueryResult->data().at(0); + return i18n("Project: %1", project->name()); + } + return i18n("Inbox"); // TODO add source name + default: + break; + } + return QVariant(); +} diff --git a/src/presentation/workdaypagemodel.cpp b/src/presentation/workdaypagemodel.cpp --- a/src/presentation/workdaypagemodel.cpp +++ b/src/presentation/workdaypagemodel.cpp @@ -99,52 +99,12 @@ return task ? (defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled) : defaultFlags; }; - struct AdditionalData - { - bool childTask = false; - Domain::QueryResult::Ptr projectQueryResult; - // later on we'll want the context query as well - }; - using AdditionalInfo = QSharedPointer; - - auto data = [](const Domain::Task::Ptr &task, int role, const AdditionalInfo &info) -> QVariant { - switch (role) { - case Qt::DisplayRole: - case Qt::EditRole: - return task->title(); - case Qt::CheckStateRole: - return task->isDone() ? Qt::Checked : Qt::Unchecked; - case Presentation::QueryTreeModelBase::AdditionalInfoRole: - if (!info || info->childTask) - return QString(); - if (info->projectQueryResult && !info->projectQueryResult->data().isEmpty()) { - Domain::Project::Ptr project = info->projectQueryResult->data().at(0); - return i18n("Project: %1", project->name()); - } - return i18n("Inbox"); // TODO add source name - default: - break; - } - return QVariant(); + auto data = [](const Domain::Task::Ptr &task, int role, const TaskExtraDataPtr &info) { + return dataForTaskWithProject(task, role, info); }; - auto fetchAdditionalInfo = [this](const QModelIndex &index, const Domain::Task::Ptr &task) -> AdditionalInfo { - AdditionalInfo info = AdditionalInfo::create(); - if (index.parent().isValid()) { // children are in the same collection as their parent, so the same project - info->childTask = true; - return info; - } - - info->projectQueryResult = m_taskQueries->findProject(task); - if (info->projectQueryResult) { - QPersistentModelIndex persistentIndex(index); - info->projectQueryResult->addPostInsertHandler([persistentIndex](const Domain::Project::Ptr &, int) { - // When a project was found (inserted into the result), update the rendering of the item - auto model = const_cast(persistentIndex.model()); - model->dataChanged(persistentIndex, persistentIndex); - }); - } - return info; + auto fetchAdditionalInfo = [this](const QModelIndex &index, const Domain::Task::Ptr &task) { + return fetchTaskExtraData(m_taskQueries, index, task); }; auto setData = [this](const Domain::Task::Ptr &task, const QVariant &value, int role) { @@ -199,5 +159,5 @@ return data; }; - return new QueryTreeModel(query, flags, data, setData, drop, drag, fetchAdditionalInfo, this); + return new QueryTreeModel(query, flags, data, setData, drop, drag, fetchAdditionalInfo, this); } diff --git a/tests/features/contexts/contextaddfeature.cpp b/tests/features/contexts/contextaddfeature.cpp --- a/tests/features/contexts/contextaddfeature.cpp +++ b/tests/features/contexts/contextaddfeature.cpp @@ -56,6 +56,7 @@ { "Contexts / Errands", "view-pim-notes" }, { "Contexts / Internet", "view-pim-notes" }, { "Contexts / Online", "view-pim-notes" }, + { "All Tasks", "view-pim-tasks" }, } })); } diff --git a/tests/features/contexts/contexteditfeature.cpp b/tests/features/contexts/contexteditfeature.cpp --- a/tests/features/contexts/contexteditfeature.cpp +++ b/tests/features/contexts/contexteditfeature.cpp @@ -55,6 +55,7 @@ { "Contexts", "folder" }, { "Contexts / Chores", "view-pim-notes" }, { "Contexts / Online", "view-pim-notes" }, + { "All Tasks", "view-pim-tasks" }, } })); } diff --git a/tests/features/contexts/contextremovefeature.cpp b/tests/features/contexts/contextremovefeature.cpp --- a/tests/features/contexts/contextremovefeature.cpp +++ b/tests/features/contexts/contextremovefeature.cpp @@ -54,6 +54,7 @@ { "Projects / TestData » Calendar1 » Calendar2 / Backlog", "view-pim-tasks" }, { "Contexts", "folder" }, { "Contexts / Errands", "view-pim-notes" }, + { "All Tasks", "view-pim-tasks" }, } })); } diff --git a/tests/features/datasource/datasourceselectionfeature.cpp b/tests/features/datasource/datasourceselectionfeature.cpp --- a/tests/features/datasource/datasourceselectionfeature.cpp +++ b/tests/features/datasource/datasourceselectionfeature.cpp @@ -94,6 +94,7 @@ { "Contexts" }, { "Contexts / Errands" }, { "Contexts / Online" }, + { "All Tasks" }, } })); } @@ -119,6 +120,7 @@ { "Contexts" }, { "Contexts / Errands" }, { "Contexts / Online" }, + { "All Tasks" }, } })); } diff --git a/tests/features/pages/pagesdisplayfeature.cpp b/tests/features/pages/pagesdisplayfeature.cpp --- a/tests/features/pages/pagesdisplayfeature.cpp +++ b/tests/features/pages/pagesdisplayfeature.cpp @@ -54,6 +54,7 @@ { "Contexts", "folder" }, { "Contexts / Errands", "view-pim-notes" }, { "Contexts / Online", "view-pim-notes" }, + { "All Tasks", "view-pim-tasks" }, } })); } diff --git a/tests/features/projects/projectaddfeature.cpp b/tests/features/projects/projectaddfeature.cpp --- a/tests/features/projects/projectaddfeature.cpp +++ b/tests/features/projects/projectaddfeature.cpp @@ -56,6 +56,7 @@ { "Contexts", "folder" }, { "Contexts / Errands", "view-pim-notes" }, { "Contexts / Online", "view-pim-notes" }, + { "All Tasks", "view-pim-tasks" }, } })); } diff --git a/tests/features/projects/projecteditfeature.cpp b/tests/features/projects/projecteditfeature.cpp --- a/tests/features/projects/projecteditfeature.cpp +++ b/tests/features/projects/projecteditfeature.cpp @@ -55,6 +55,7 @@ { "Contexts", "folder" }, { "Contexts / Errands", "view-pim-notes" }, { "Contexts / Online", "view-pim-notes" }, + { "All Tasks", "view-pim-tasks" }, } })); } diff --git a/tests/features/projects/projectremovefeature.cpp b/tests/features/projects/projectremovefeature.cpp --- a/tests/features/projects/projectremovefeature.cpp +++ b/tests/features/projects/projectremovefeature.cpp @@ -54,6 +54,7 @@ { "Contexts", "folder" }, { "Contexts / Errands", "view-pim-notes" }, { "Contexts / Online", "view-pim-notes" }, + { "All Tasks", "view-pim-tasks" }, } })); } diff --git a/tests/features/projects/projecttaskpromotefeature.cpp b/tests/features/projects/projecttaskpromotefeature.cpp --- a/tests/features/projects/projecttaskpromotefeature.cpp +++ b/tests/features/projects/projecttaskpromotefeature.cpp @@ -60,6 +60,7 @@ { "Contexts", "folder" }, { "Contexts / Errands", "view-pim-notes" }, { "Contexts / Online", "view-pim-notes" }, + { "All Tasks", "view-pim-tasks" }, } })); } diff --git a/tests/units/presentation/CMakeLists.txt b/tests/units/presentation/CMakeLists.txt --- a/tests/units/presentation/CMakeLists.txt +++ b/tests/units/presentation/CMakeLists.txt @@ -15,4 +15,5 @@ taskfilterproxymodeltest contextpagemodeltest workdaypagemodeltest + alltaskspagemodeltest ) diff --git a/tests/units/presentation/alltaskspagemodeltest.cpp b/tests/units/presentation/alltaskspagemodeltest.cpp new file mode 100644 --- /dev/null +++ b/tests/units/presentation/alltaskspagemodeltest.cpp @@ -0,0 +1,400 @@ +/* This file is part of Zanshin + + Copyright 2019 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 + +#include "utils/datetime.h" +#include "utils/mockobject.h" + +#include "domain/taskqueries.h" +#include "domain/taskrepository.h" +#include "presentation/alltaskspagemodel.h" +#include "presentation/querytreemodelbase.h" + +using namespace mockitopp; +using namespace mockitopp::matcher; + +class AllTasksPageModelTest : public QObject +{ + Q_OBJECT +private slots: + void shouldListAllTasksInCentralListModel() + { + // GIVEN + + const auto today = Utils::DateTime::currentDate(); + + // Three tasks + auto task1 = Domain::Task::Ptr::create(); + task1->setTitle(QStringLiteral("task1")); + task1->setStartDate(today.addDays(-10)); + task1->setDueDate(today); + auto task2 = Domain::Task::Ptr::create(); + task2->setTitle(QStringLiteral("task2")); + task2->setStartDate(today); + task2->setDueDate(today.addDays(10)); + auto task3 = Domain::Task::Ptr::create(); + task3->setTitle(QStringLiteral("task3")); + task3->setStartDate(today.addYears(-4)); + task3->setDueDate(today.addYears(-3)); + auto taskProvider = Domain::QueryResultProvider::Ptr::create(); + auto taskResult = Domain::QueryResult::create(taskProvider); + taskProvider->append(task1); + taskProvider->append(task2); + taskProvider->append(task3); + + // Two tasks under the task1 + auto childTask11 = Domain::Task::Ptr::create(); + childTask11->setTitle(QStringLiteral("childTask11")); + auto childTask12 = Domain::Task::Ptr::create(); + childTask12->setTitle(QStringLiteral("childTask12")); + childTask12->setStartDate(today); + childTask12->setDueDate(today); + auto childTaskProvider = Domain::QueryResultProvider::Ptr::create(); + auto childTaskResult = Domain::QueryResult::create(childTaskProvider); + taskProvider->append(childTask12); + childTaskProvider->append(childTask11); + childTaskProvider->append(childTask12); + + // One project + auto project = Domain::Project::Ptr::create(); + project->setName("KDE"); + auto projectProvider = Domain::QueryResultProvider::Ptr::create(); + auto projectResult = Domain::QueryResult::create(projectProvider); + projectProvider->append(project); + + Utils::MockObject taskQueriesMock; + taskQueriesMock(&Domain::TaskQueries::findTopLevel).when().thenReturn(taskResult); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(childTaskResult); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task3).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask11).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(childTask12).thenReturn(Domain::QueryResult::Ptr()); + + taskQueriesMock(&Domain::TaskQueries::findProject).when(task1).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findProject).when(task2).thenReturn(projectResult); + taskQueriesMock(&Domain::TaskQueries::findProject).when(task3).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findProject).when(childTask11).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findProject).when(childTask12).thenReturn(Domain::QueryResult::Ptr()); + + Utils::MockObject taskRepositoryMock; + + Presentation::AllTasksPageModel pageModel(taskQueriesMock.getInstance(), + taskRepositoryMock.getInstance()); + + // WHEN + QAbstractItemModel *model = pageModel.centralListModel(); + + // THEN + const QModelIndex task1Index = model->index(0, 0); + const QModelIndex task2Index = model->index(1, 0); + const QModelIndex task3Index = model->index(2, 0); + const QModelIndex taskChildTask12Index = model->index(3, 0); + + const QModelIndex childTask11Index = model->index(0, 0, task1Index); + const QModelIndex childTask12Index = model->index(1, 0, task1Index); + + QCOMPARE(model->rowCount(), 4); + QCOMPARE(model->rowCount(task1Index), 2); + QCOMPARE(model->rowCount(task2Index), 0); + QCOMPARE(model->rowCount(task3Index), 0); + QCOMPARE(model->rowCount(taskChildTask12Index), 0); + + QVERIFY(childTask11Index.isValid()); + QVERIFY(childTask12Index.isValid()); + QCOMPARE(model->rowCount(childTask11Index), 0); + QCOMPARE(model->rowCount(childTask12Index), 0); + + const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable + | Qt::ItemIsEnabled + | Qt::ItemIsEditable + | Qt::ItemIsDragEnabled; + QCOMPARE(model->flags(task1Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); + QCOMPARE(model->flags(childTask11Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); + QCOMPARE(model->flags(childTask12Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); + QCOMPARE(model->flags(task2Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); + QCOMPARE(model->flags(task3Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); + QCOMPARE(model->flags(taskChildTask12Index), defaultFlags | Qt::ItemIsUserCheckable | Qt::ItemIsDropEnabled); + + QCOMPARE(model->data(task1Index).toString(), task1->title()); + QCOMPARE(model->data(childTask11Index).toString(), childTask11->title()); + QCOMPARE(model->data(childTask12Index).toString(), childTask12->title()); + QCOMPARE(model->data(task2Index).toString(), task2->title()); + QCOMPARE(model->data(task3Index).toString(), task3->title()); + QCOMPARE(model->data(taskChildTask12Index).toString(), childTask12->title()); + + QCOMPARE(model->data(task1Index, Qt::EditRole).toString(), task1->title()); + QCOMPARE(model->data(childTask11Index, Qt::EditRole).toString(), childTask11->title()); + QCOMPARE(model->data(childTask12Index, Qt::EditRole).toString(), childTask12->title()); + QCOMPARE(model->data(task2Index, Qt::EditRole).toString(), task2->title()); + QCOMPARE(model->data(task3Index, Qt::EditRole).toString(), task3->title()); + QCOMPARE(model->data(taskChildTask12Index, Qt::EditRole).toString(), childTask12->title()); + + QVERIFY(model->data(task1Index, Qt::CheckStateRole).isValid()); + QVERIFY(model->data(childTask11Index, Qt::CheckStateRole).isValid()); + QVERIFY(model->data(childTask12Index, Qt::CheckStateRole).isValid()); + QVERIFY(model->data(task2Index, Qt::CheckStateRole).isValid()); + QVERIFY(model->data(task3Index, Qt::CheckStateRole).isValid()); + QVERIFY(model->data(taskChildTask12Index, Qt::CheckStateRole).isValid()); + + QCOMPARE(model->data(task1Index, Qt::CheckStateRole).toBool(), task1->isDone()); + QCOMPARE(model->data(childTask11Index, Qt::CheckStateRole).toBool(), childTask11->isDone()); + QCOMPARE(model->data(childTask12Index, Qt::CheckStateRole).toBool(), childTask12->isDone()); + QCOMPARE(model->data(task2Index, Qt::CheckStateRole).toBool(), task2->isDone()); + QCOMPARE(model->data(task3Index, Qt::CheckStateRole).toBool(), task3->isDone()); + QCOMPARE(model->data(taskChildTask12Index, Qt::CheckStateRole).toBool(), childTask12->isDone()); + + QCOMPARE(model->data(task1Index, Presentation::QueryTreeModelBase::AdditionalInfoRole).toString(), QString("Inbox")); + QCOMPARE(model->data(task2Index, Presentation::QueryTreeModelBase::AdditionalInfoRole).toString(), QString("Project: KDE")); + QCOMPARE(model->data(childTask11Index, Presentation::QueryTreeModelBase::AdditionalInfoRole).toString(), QString()); + QCOMPARE(model->data(childTask12Index, Presentation::QueryTreeModelBase::AdditionalInfoRole).toString(), QString()); + + // WHEN + taskRepositoryMock(&Domain::TaskRepository::update).when(task1).thenReturn(new FakeJob(this)); + taskRepositoryMock(&Domain::TaskRepository::update).when(childTask11).thenReturn(new FakeJob(this)); + taskRepositoryMock(&Domain::TaskRepository::update).when(childTask12).thenReturn(new FakeJob(this)); + taskRepositoryMock(&Domain::TaskRepository::update).when(task2).thenReturn(new FakeJob(this)); + taskRepositoryMock(&Domain::TaskRepository::update).when(task3).thenReturn(new FakeJob(this)); + + QVERIFY(model->setData(task1Index, "newTask1")); + QVERIFY(model->setData(childTask11Index, "newChildTask11")); + QVERIFY(model->setData(task2Index, "newTask2")); + QVERIFY(model->setData(task3Index, "newTask3")); + QVERIFY(model->setData(taskChildTask12Index, "newChildTask12")); + + QVERIFY(model->setData(task1Index, Qt::Unchecked, Qt::CheckStateRole)); + QVERIFY(model->setData(childTask11Index, Qt::Unchecked, Qt::CheckStateRole)); + QVERIFY(model->setData(task2Index, Qt::Checked, Qt::CheckStateRole)); + QVERIFY(model->setData(task3Index, Qt::Unchecked, Qt::CheckStateRole)); + QVERIFY(model->setData(taskChildTask12Index, Qt::Checked, Qt::CheckStateRole)); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(task1).exactly(2)); + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(childTask11).exactly(2)); + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(childTask12).exactly(2)); + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(task2).exactly(2)); + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(task3).exactly(2)); + + QCOMPARE(task1->title(), QStringLiteral("newTask1")); + QCOMPARE(childTask11->title(), QStringLiteral("newChildTask11")); + QCOMPARE(childTask12->title(), QStringLiteral("newChildTask12")); + QCOMPARE(task2->title(), QStringLiteral("newTask2")); + QCOMPARE(task3->title(), QStringLiteral("newTask3")); + + QCOMPARE(task1->isDone(), false); + QCOMPARE(childTask11->isDone(), false); + QCOMPARE(childTask12->isDone(), true); + QCOMPARE(task2->isDone(), true); + QCOMPARE(task3->isDone(), false); + + // WHEN + auto data = std::unique_ptr(model->mimeData(QModelIndexList() << childTask12Index)); + + // THEN + QVERIFY(data->hasFormat(QStringLiteral("application/x-zanshin-object"))); + QCOMPARE(data->property("objects").value(), + Domain::Task::List() << childTask12); + + // WHEN + auto childTask2 = Domain::Task::Ptr::create(); + taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask11, childTask2).thenReturn(new FakeJob(this)); + data.reset(new QMimeData); + data->setData(QStringLiteral("application/x-zanshin-object"), "object"); + data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << childTask2)); + model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, childTask11Index); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask11, childTask2).exactly(1)); + + + // WHEN + auto childTask3 = Domain::Task::Ptr::create(); + auto childTask4 = Domain::Task::Ptr::create(); + taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask12, childTask3).thenReturn(new FakeJob(this)); + taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask12, childTask4).thenReturn(new FakeJob(this)); + data.reset(new QMimeData); + data->setData(QStringLiteral("application/x-zanshin-object"), "object"); + data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << childTask3 << childTask4)); + model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, childTask12Index); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask12, childTask3).exactly(1)); + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::associate).when(childTask12, childTask4).exactly(1)); + + // WHEN + auto childTask5 = Domain::Task::Ptr::create(); + QVERIFY(!childTask5->startDate().isValid()); + taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask5).thenReturn(new FakeJob(this)); + data.reset(new QMimeData); + data->setData(QStringLiteral("application/x-zanshin-object"), "object"); + data->setProperty("objects", QVariant::fromValue(Domain::Task::List() << childTask5)); + model->dropMimeData(data.get(), Qt::MoveAction, -1, -1, QModelIndex()); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::dissociate).when(childTask5).exactly(1)); + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::update).when(childTask5).exactly(0)); + QCOMPARE(childTask5->startDate(), QDate()); // unlike the workday + } + + void shouldAddTasksInAllTasksPage() + { + // GIVEN + + // ... in fact we won't list any model + Utils::MockObject taskQueriesMock; + + // We'll gladly create a task though + Utils::MockObject taskRepositoryMock; + taskRepositoryMock(&Domain::TaskRepository::create).when(any()).thenReturn(new FakeJob(this)); + + Presentation::AllTasksPageModel pageModel(taskQueriesMock.getInstance(), + taskRepositoryMock.getInstance()); + + // WHEN + auto title = QStringLiteral("New task"); + auto task = pageModel.addItem(title); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::create).when(any()).exactly(1)); + + QVERIFY(task); + QCOMPARE(task->title(), title); + QCOMPARE(task->startDate(), QDate()); // that's one difference with the workday, which would set it to Utils::DateTime::currentDate() + } + + void shouldAddChildTask() + { + // GIVEN + + // Two tasks + auto task1 = Domain::Task::Ptr::create(); + auto task2 = Domain::Task::Ptr::create(); + auto taskProvider = Domain::QueryResultProvider::Ptr::create(); + auto taskResult = Domain::QueryResult::create(taskProvider); + taskProvider->append(task1); + taskProvider->append(task2); + + Utils::MockObject taskQueriesMock; + taskQueriesMock(&Domain::TaskQueries::findTopLevel).when().thenReturn(taskResult); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findProject).when(any()).thenReturn(Domain::QueryResult::Ptr()); + + Utils::MockObject taskRepositoryMock; + taskRepositoryMock(&Domain::TaskRepository::createChild).when(any(), + any()) + .thenReturn(new FakeJob(this)); + + Presentation::AllTasksPageModel pageModel(taskQueriesMock.getInstance(), + taskRepositoryMock.getInstance()); + + // WHEN + const auto title = QStringLiteral("New task"); + const auto parentIndex = pageModel.centralListModel()->index(0, 0); + const auto createdTask = pageModel.addItem(title, parentIndex); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::createChild).when(any(), + any()) + .exactly(1)); + + QVERIFY(createdTask); + QCOMPARE(createdTask->title(), title); + QVERIFY(!createdTask->startDate().isValid()); + } + + void shouldDeleteItems() + { + // GIVEN + + // Two tasks + auto task1 = Domain::Task::Ptr::create(); + auto task2 = Domain::Task::Ptr::create(); + auto taskProvider = Domain::QueryResultProvider::Ptr::create(); + auto taskResult = Domain::QueryResult::create(taskProvider); + taskProvider->append(task1); + taskProvider->append(task2); + + Utils::MockObject taskQueriesMock; + taskQueriesMock(&Domain::TaskQueries::findTopLevel).when().thenReturn(taskResult); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findProject).when(any()).thenReturn(Domain::QueryResult::Ptr()); + + Utils::MockObject taskRepositoryMock; + taskRepositoryMock(&Domain::TaskRepository::remove).when(task2).thenReturn(new FakeJob(this)); + + Presentation::AllTasksPageModel pageModel(taskQueriesMock.getInstance(), + taskRepositoryMock.getInstance()); + + // WHEN + const QModelIndex index = pageModel.centralListModel()->index(1, 0); + pageModel.removeItem(index); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::remove).when(task2).exactly(1)); + } + + void shouldPromoteItem() + { + // GIVEN + + // Two tasks + auto task1 = Domain::Task::Ptr::create(); + auto task2 = Domain::Task::Ptr::create(); + auto taskProvider = Domain::QueryResultProvider::Ptr::create(); + auto taskResult = Domain::QueryResult::create(taskProvider); + taskProvider->append(task1); + taskProvider->append(task2); + + Utils::MockObject taskQueriesMock; + taskQueriesMock(&Domain::TaskQueries::findTopLevel).when().thenReturn(taskResult); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findDataSource).when(any()).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findProject).when(task2).thenReturn(Domain::QueryResult::Ptr()); + + Utils::MockObject taskRepositoryMock; + taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).thenReturn(new FakeJob(this)); + + Presentation::AllTasksPageModel pageModel(taskQueriesMock.getInstance(), + taskRepositoryMock.getInstance()); + + // WHEN + const QModelIndex index = pageModel.centralListModel()->index(1, 0); + pageModel.promoteItem(index); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).exactly(1)); + } +}; + +ZANSHIN_TEST_MAIN(AllTasksPageModelTest) + +#include "alltaskspagemodeltest.moc" diff --git a/tests/units/presentation/availablepagesmodeltest.cpp b/tests/units/presentation/availablepagesmodeltest.cpp --- a/tests/units/presentation/availablepagesmodeltest.cpp +++ b/tests/units/presentation/availablepagesmodeltest.cpp @@ -32,6 +32,7 @@ #include "utils/mockobject.h" #include "utils/datetime.h" +#include "presentation/alltaskspagemodel.h" #include "presentation/availablepagesmodel.h" #include "presentation/contextpagemodel.h" #include "presentation/errorhandler.h" @@ -56,6 +57,10 @@ QString m_message; }; +static const int s_projectsRow = 2; +static const int s_contextRow = 3; +static const int s_allTasksRow = 4; + class AvailablePagesModelTest : public QObject { Q_OBJECT @@ -134,18 +139,19 @@ // THEN const QModelIndex inboxIndex = model->index(0, 0); const QModelIndex workdayIndex = model->index(1, 0); - const QModelIndex projectsIndex = model->index(2, 0); + const QModelIndex projectsIndex = model->index(s_projectsRow, 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 contextsIndex = model->index(s_contextRow, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); const QModelIndex context2Index = model->index(1, 0, contextsIndex); + const QModelIndex allTasksIndex = model->index(s_allTasksRow, 0); - QCOMPARE(model->rowCount(), 4); + QCOMPARE(model->rowCount(), 5); QCOMPARE(model->rowCount(inboxIndex), 0); QCOMPARE(model->rowCount(workdayIndex), 0); QCOMPARE(model->rowCount(projectsIndex), 2); @@ -158,6 +164,7 @@ QCOMPARE(model->rowCount(contextsIndex), 2); QCOMPARE(model->rowCount(context1Index), 0); QCOMPARE(model->rowCount(context2Index), 0); + QCOMPARE(model->rowCount(allTasksIndex), 0); const Qt::ItemFlags defaultFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled @@ -174,6 +181,7 @@ QCOMPARE(model->flags(contextsIndex), Qt::NoItemFlags); QCOMPARE(model->flags(context1Index), defaultFlags | Qt::ItemIsDropEnabled); QCOMPARE(model->flags(context2Index), defaultFlags | Qt::ItemIsDropEnabled); + QCOMPARE(model->flags(allTasksIndex), (defaultFlags & ~(Qt::ItemIsEditable))); QCOMPARE(model->data(inboxIndex).toString(), i18n("Inbox")); QCOMPARE(model->data(workdayIndex).toString(), i18n("Workday")); @@ -187,6 +195,7 @@ QCOMPARE(model->data(contextsIndex).toString(), i18n("Contexts")); QCOMPARE(model->data(context1Index).toString(), context1->name()); QCOMPARE(model->data(context2Index).toString(), context2->name()); + QCOMPARE(model->data(allTasksIndex).toString(), i18n("All Tasks")); QVERIFY(!model->data(inboxIndex, Qt::EditRole).isValid()); QVERIFY(!model->data(workdayIndex, Qt::EditRole).isValid()); @@ -200,6 +209,7 @@ 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()); + QVERIFY(!model->data(allTasksIndex, Qt::EditRole).isValid()); QCOMPARE(model->data(inboxIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("mail-folder-inbox")); QCOMPARE(model->data(workdayIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("go-jump-today")); @@ -213,6 +223,7 @@ 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")); + QCOMPARE(model->data(allTasksIndex, Presentation::QueryTreeModelBase::IconNameRole).toString(), QStringLiteral("view-pim-tasks")); QVERIFY(!model->data(inboxIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(workdayIndex, Qt::CheckStateRole).isValid()); @@ -226,6 +237,7 @@ QVERIFY(!model->data(contextsIndex, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(context1Index, Qt::CheckStateRole).isValid()); QVERIFY(!model->data(context2Index, Qt::CheckStateRole).isValid()); + QVERIFY(!model->data(allTasksIndex, Qt::CheckStateRole).isValid()); // WHEN projectRepositoryMock(&Domain::ProjectRepository::update).when(project11).thenReturn(new FakeJob(this)); @@ -430,6 +442,47 @@ QVERIFY(qobject_cast(workdayPage)); } + void shouldCreateAllTasksPage() + { + // 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::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 allTasksIndex = model->index(s_allTasksRow, 0); + + QObject *workdayPage = pages.createPageForIndex(allTasksIndex); + QVERIFY(qobject_cast(workdayPage)); + } + void shouldCreateProjectsPage() { // GIVEN @@ -479,7 +532,7 @@ QAbstractItemModel *model = pages.pageListModel(); // THEN - const QModelIndex projectsIndex = model->index(2, 0); + const QModelIndex projectsIndex = model->index(s_projectsRow, 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); @@ -541,7 +594,7 @@ QAbstractItemModel *model = pages.pageListModel(); // THEN - const QModelIndex contextsIndex = model->index(3, 0); + const QModelIndex contextsIndex = model->index(s_contextRow, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); const QModelIndex context2Index = model->index(1, 0, contextsIndex); @@ -719,7 +772,7 @@ QAbstractItemModel *model = pages.pageListModel(); - const QModelIndex projectsIndex = model->index(2, 0); + const QModelIndex projectsIndex = model->index(s_projectsRow, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); @@ -781,7 +834,7 @@ QAbstractItemModel *model = pages.pageListModel(); - const QModelIndex projectsIndex = model->index(2, 0); + const QModelIndex projectsIndex = model->index(s_projectsRow, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); @@ -833,7 +886,7 @@ QAbstractItemModel *model = pages.pageListModel(); - const QModelIndex contextsIndex = model->index(3, 0); + const QModelIndex contextsIndex = model->index(s_contextRow, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); contextRepositoryMock(&Domain::ContextRepository::remove).when(context1).thenReturn(new FakeJob(this)); @@ -883,7 +936,7 @@ QAbstractItemModel *model = pages.pageListModel(); - const QModelIndex contextsIndex = model->index(3, 0); + const QModelIndex contextsIndex = model->index(s_contextRow, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); auto job = new FakeJob(this); @@ -951,7 +1004,7 @@ FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); - const QModelIndex projectsIndex = model->index(2, 0); + const QModelIndex projectsIndex = model->index(s_projectsRow, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); @@ -1020,7 +1073,7 @@ FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); - const QModelIndex contextsIndex = model->index(3, 0); + const QModelIndex contextsIndex = model->index(s_contextRow, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); // WHEN @@ -1094,7 +1147,7 @@ FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); - const QModelIndex projectsIndex = model->index(2, 0); + const QModelIndex projectsIndex = model->index(s_projectsRow, 0); const QModelIndex sourceIndex = model->index(0, 0, projectsIndex); const QModelIndex project1Index = model->index(0, 0, sourceIndex); @@ -1171,7 +1224,7 @@ FakeErrorHandler errorHandler; pages.setErrorHandler(&errorHandler); QAbstractItemModel *model = pages.pageListModel(); - const QModelIndex contextsIndex = model->index(3, 0); + const QModelIndex contextsIndex = model->index(s_contextRow, 0); const QModelIndex context1Index = model->index(0, 0, contextsIndex); // WHEN