diff --git a/src/presentation/contextpagemodel.h b/src/presentation/contextpagemodel.h --- a/src/presentation/contextpagemodel.h +++ b/src/presentation/contextpagemodel.h @@ -47,6 +47,7 @@ public slots: Domain::Artifact::Ptr addItem(const QString &title) Q_DECL_OVERRIDE; void removeItem(const QModelIndex &index) Q_DECL_OVERRIDE; + void promoteItem(const QModelIndex &index) Q_DECL_OVERRIDE; private: QAbstractItemModel *createCentralListModel() Q_DECL_OVERRIDE; diff --git a/src/presentation/contextpagemodel.cpp b/src/presentation/contextpagemodel.cpp --- a/src/presentation/contextpagemodel.cpp +++ b/src/presentation/contextpagemodel.cpp @@ -74,6 +74,16 @@ installHandler(job, tr("Cannot remove task %1 from context %2").arg(task->title()).arg(m_context->name())); } +void ContextPageModel::promoteItem(const QModelIndex &index) +{ + QVariant data = index.data(QueryTreeModel::ObjectRole); + auto artifact = data.value(); + auto task = artifact.objectCast(); + Q_ASSERT(task); + const auto job = m_taskRepository->promoteToProject(task); + installHandler(job, tr("Cannot promote task %1 to be a project").arg(task->title())); +} + QAbstractItemModel *ContextPageModel::createCentralListModel() { auto query = [this] (const Domain::Task::Ptr &task) -> Domain::QueryResultInterface::Ptr { diff --git a/src/presentation/noteinboxpagemodel.h b/src/presentation/noteinboxpagemodel.h --- a/src/presentation/noteinboxpagemodel.h +++ b/src/presentation/noteinboxpagemodel.h @@ -42,6 +42,7 @@ Domain::Artifact::Ptr addItem(const QString &title) Q_DECL_OVERRIDE; void removeItem(const QModelIndex &index) Q_DECL_OVERRIDE; + void promoteItem(const QModelIndex &index) Q_DECL_OVERRIDE; private: QAbstractItemModel *createCentralListModel() Q_DECL_OVERRIDE; diff --git a/src/presentation/noteinboxpagemodel.cpp b/src/presentation/noteinboxpagemodel.cpp --- a/src/presentation/noteinboxpagemodel.cpp +++ b/src/presentation/noteinboxpagemodel.cpp @@ -59,6 +59,11 @@ installHandler(job, tr("Cannot remove note %1 from Inbox").arg(note->title())); } +void NoteInboxPageModel::promoteItem(const QModelIndex &) +{ + qFatal("Not supported"); +} + QAbstractItemModel *NoteInboxPageModel::createCentralListModel() { auto query = [this](const Domain::Note::Ptr ¬e) -> Domain::QueryResultInterface::Ptr { diff --git a/src/presentation/pagemodel.h b/src/presentation/pagemodel.h --- a/src/presentation/pagemodel.h +++ b/src/presentation/pagemodel.h @@ -48,6 +48,7 @@ public slots: virtual Domain::Artifact::Ptr addItem(const QString &title) = 0; virtual void removeItem(const QModelIndex &index) = 0; + virtual void promoteItem(const QModelIndex &index) = 0; private: virtual QAbstractItemModel *createCentralListModel() = 0; diff --git a/src/presentation/projectpagemodel.h b/src/presentation/projectpagemodel.h --- a/src/presentation/projectpagemodel.h +++ b/src/presentation/projectpagemodel.h @@ -47,6 +47,7 @@ Domain::Artifact::Ptr addItem(const QString &title) Q_DECL_OVERRIDE; void removeItem(const QModelIndex &index) Q_DECL_OVERRIDE; + void promoteItem(const QModelIndex &index) Q_DECL_OVERRIDE; private: QAbstractItemModel *createCentralListModel() Q_DECL_OVERRIDE; diff --git a/src/presentation/projectpagemodel.cpp b/src/presentation/projectpagemodel.cpp --- a/src/presentation/projectpagemodel.cpp +++ b/src/presentation/projectpagemodel.cpp @@ -68,6 +68,16 @@ installHandler(job, tr("Cannot remove task %1 from project %2").arg(task->title()).arg(m_project->name())); } +void ProjectPageModel::promoteItem(const QModelIndex &index) +{ + QVariant data = index.data(QueryTreeModel::ObjectRole); + auto artifact = data.value(); + auto task = artifact.objectCast(); + Q_ASSERT(task); + const auto job = m_taskRepository->promoteToProject(task); + installHandler(job, tr("Cannot promote task %1 to be a project").arg(task->title())); +} + QAbstractItemModel *ProjectPageModel::createCentralListModel() { auto query = [this](const Domain::Task::Ptr &task) -> Domain::QueryResultInterface::Ptr { diff --git a/src/presentation/tagpagemodel.h b/src/presentation/tagpagemodel.h --- a/src/presentation/tagpagemodel.h +++ b/src/presentation/tagpagemodel.h @@ -49,6 +49,7 @@ Domain::Artifact::Ptr addItem(const QString &title) Q_DECL_OVERRIDE; void removeItem(const QModelIndex &index) Q_DECL_OVERRIDE; + void promoteItem(const QModelIndex &index) Q_DECL_OVERRIDE; private: QAbstractItemModel *createCentralListModel() Q_DECL_OVERRIDE; diff --git a/src/presentation/tagpagemodel.cpp b/src/presentation/tagpagemodel.cpp --- a/src/presentation/tagpagemodel.cpp +++ b/src/presentation/tagpagemodel.cpp @@ -75,6 +75,11 @@ installHandler(job, tr("Cannot remove note %1 from tag %2").arg(note->title()).arg(m_tag->name())); } +void TagPageModel::promoteItem(const QModelIndex &) +{ + qFatal("Not supported"); +} + QAbstractItemModel *TagPageModel::createCentralListModel() { auto query = [this] (const Domain::Note::Ptr ¬e) -> Domain::QueryResultInterface::Ptr { diff --git a/src/presentation/taskinboxpagemodel.h b/src/presentation/taskinboxpagemodel.h --- a/src/presentation/taskinboxpagemodel.h +++ b/src/presentation/taskinboxpagemodel.h @@ -42,6 +42,7 @@ Domain::Artifact::Ptr addItem(const QString &title) Q_DECL_OVERRIDE; void removeItem(const QModelIndex &index) Q_DECL_OVERRIDE; + void promoteItem(const QModelIndex &index) Q_DECL_OVERRIDE; private: QAbstractItemModel *createCentralListModel() Q_DECL_OVERRIDE; diff --git a/src/presentation/taskinboxpagemodel.cpp b/src/presentation/taskinboxpagemodel.cpp --- a/src/presentation/taskinboxpagemodel.cpp +++ b/src/presentation/taskinboxpagemodel.cpp @@ -59,6 +59,16 @@ installHandler(job, tr("Cannot remove task %1 from Inbox").arg(task->title())); } +void TaskInboxPageModel::promoteItem(const QModelIndex &index) +{ + QVariant data = index.data(QueryTreeModel::ObjectRole); + auto artifact = data.value(); + auto task = artifact.objectCast(); + Q_ASSERT(task); + const auto job = m_taskRepository->promoteToProject(task); + installHandler(job, tr("Cannot promote task %1 to be a project").arg(task->title())); +} + QAbstractItemModel *TaskInboxPageModel::createCentralListModel() { auto query = [this](const Domain::Task::Ptr &task) -> Domain::QueryResultInterface::Ptr { diff --git a/src/presentation/workdaypagemodel.h b/src/presentation/workdaypagemodel.h --- a/src/presentation/workdaypagemodel.h +++ b/src/presentation/workdaypagemodel.h @@ -42,6 +42,7 @@ Domain::Artifact::Ptr addItem(const QString &title) Q_DECL_OVERRIDE; void removeItem(const QModelIndex &index) Q_DECL_OVERRIDE; + void promoteItem(const QModelIndex &index) Q_DECL_OVERRIDE; private: QAbstractItemModel *createCentralListModel() Q_DECL_OVERRIDE; diff --git a/src/presentation/workdaypagemodel.cpp b/src/presentation/workdaypagemodel.cpp --- a/src/presentation/workdaypagemodel.cpp +++ b/src/presentation/workdaypagemodel.cpp @@ -67,6 +67,16 @@ } } +void WorkdayPageModel::promoteItem(const QModelIndex &index) +{ + QVariant data = index.data(QueryTreeModel::ObjectRole); + auto artifact = data.value(); + auto task = artifact.objectCast(); + Q_ASSERT(task); + const auto job = m_taskRepository->promoteToProject(task); + installHandler(job, tr("Cannot promote task %1 to be a project").arg(task->title())); +} + QAbstractItemModel *WorkdayPageModel::createCentralListModel() { auto query = [this](const Domain::Artifact::Ptr &artifact) -> Domain::QueryResultInterface::Ptr { diff --git a/tests/units/presentation/contextpagemodeltest.cpp b/tests/units/presentation/contextpagemodeltest.cpp --- a/tests/units/presentation/contextpagemodeltest.cpp +++ b/tests/units/presentation/contextpagemodeltest.cpp @@ -271,6 +271,41 @@ QVERIFY(contextRepositoryMock(&Domain::ContextRepository::dissociate).when(context, task).exactly(1)); } + void shouldPromoteItem() + { + // GIVEN + + // One context + auto context = Domain::Context::Ptr::create(); + + // A task + auto task = Domain::Task::Ptr::create(); + + auto taskProvider = Domain::QueryResultProvider::Ptr::create(); + auto taskResult = Domain::QueryResult::create(taskProvider); + taskProvider->append(task); + + Utils::MockObject contextQueriesMock; + contextQueriesMock(&Domain::ContextQueries::findTopLevelTasks).when(context).thenReturn(taskResult); + + Utils::MockObject contextRepositoryMock; + + Utils::MockObject taskRepositoryMock; + taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task).thenReturn(new FakeJob(this)); + + Presentation::ContextPageModel page(context, + contextQueriesMock.getInstance(), + contextRepositoryMock.getInstance(), + taskRepositoryMock.getInstance()); + + // WHEN + const QModelIndex indexTask = page.centralListModel()->index(0, 0); + page.promoteItem(indexTask); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task).exactly(1)); + } + void shouldGetAnErrorMessageWhenAddTaskFailed() { // GIVEN diff --git a/tests/units/presentation/pagemodeltest.cpp b/tests/units/presentation/pagemodeltest.cpp --- a/tests/units/presentation/pagemodeltest.cpp +++ b/tests/units/presentation/pagemodeltest.cpp @@ -40,6 +40,7 @@ Domain::Artifact::Ptr addItem(const QString &) { return Domain::Artifact::Ptr::create(); } void removeItem(const QModelIndex &) {} + void promoteItem(const QModelIndex &) {} private: QAbstractItemModel *createCentralListModel() diff --git a/tests/units/presentation/projectpagemodeltest.cpp b/tests/units/presentation/projectpagemodeltest.cpp --- a/tests/units/presentation/projectpagemodeltest.cpp +++ b/tests/units/presentation/projectpagemodeltest.cpp @@ -325,6 +325,89 @@ QCOMPARE(errorHandler.m_message, QString("Cannot remove task Task2 from project Project1: Foo")); } + void shouldPromoteItem() + { + // GIVEN + + // One project + auto project = Domain::Project::Ptr::create(); + + // Two tasks + auto task1 = Domain::Task::Ptr::create(); + auto task2 = Domain::Task::Ptr::create(); + auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); + auto topLevelResult = Domain::QueryResult::create(topLevelProvider); + topLevelProvider->append(task1); + topLevelProvider->append(task2); + + Utils::MockObject projectQueriesMock; + projectQueriesMock(&Domain::ProjectQueries::findTopLevel).when(project).thenReturn(topLevelResult); + + Utils::MockObject taskQueriesMock; + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); + + Utils::MockObject taskRepositoryMock; + taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).thenReturn(new FakeJob(this)); + + Presentation::ProjectPageModel page(project, + projectQueriesMock.getInstance(), + taskQueriesMock.getInstance(), + taskRepositoryMock.getInstance()); + + // WHEN + const QModelIndex index = page.centralListModel()->index(1, 0); + page.promoteItem(index); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).exactly(1)); + } + + void shouldGetAnErrorMessageWhenPromoteItemFailed() + { + // GIVEN + + // One project + auto project = Domain::Project::Ptr::create(); + project->setName("Project1"); + + // Two tasks + auto task1 = Domain::Task::Ptr::create(); + auto task2 = Domain::Task::Ptr::create(); + task2->setTitle("Task2"); + auto topLevelProvider = Domain::QueryResultProvider::Ptr::create(); + auto topLevelResult = Domain::QueryResult::create(topLevelProvider); + topLevelProvider->append(task1); + topLevelProvider->append(task2); + + Utils::MockObject projectQueriesMock; + projectQueriesMock(&Domain::ProjectQueries::findTopLevel).when(project).thenReturn(topLevelResult); + + Utils::MockObject taskQueriesMock; + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); + + Utils::MockObject taskRepositoryMock; + auto job = new FakeJob(this); + job->setExpectedError(KJob::KilledJobError, "Foo"); + taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).thenReturn(job); + + Presentation::ProjectPageModel page(project, + projectQueriesMock.getInstance(), + taskQueriesMock.getInstance(), + taskRepositoryMock.getInstance()); + FakeErrorHandler errorHandler; + page.setErrorHandler(&errorHandler); + + // WHEN + const QModelIndex index = page.centralListModel()->index(1, 0); + page.promoteItem(index); + + // THEN + QTest::qWait(150); + QCOMPARE(errorHandler.m_message, QString("Cannot promote task Task2 to be a project: Foo")); + } + void shouldGetAnErrorMessageWhenUpdateTaskFailed() { // GIVEN diff --git a/tests/units/presentation/taskinboxpagemodeltest.cpp b/tests/units/presentation/taskinboxpagemodeltest.cpp --- a/tests/units/presentation/taskinboxpagemodeltest.cpp +++ b/tests/units/presentation/taskinboxpagemodeltest.cpp @@ -284,6 +284,74 @@ QCOMPARE(errorHandler.m_message, QString("Cannot remove task task2 from Inbox: Foo")); } + 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::findInboxTopLevel).when().thenReturn(taskResult); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); + + Utils::MockObject taskRepositoryMock; + taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).thenReturn(new FakeJob(this)); + + Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), + taskRepositoryMock.getInstance()); + + // WHEN + const QModelIndex index = inbox.centralListModel()->index(1, 0); + inbox.promoteItem(index); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).exactly(1)); + } + + void shouldGetAnErrorMessageWhenPromoteItemFailed() + { + // GIVEN + + // Two tasks + auto task1 = Domain::Task::Ptr::create(); + auto task2 = Domain::Task::Ptr::create(); + task2->setTitle("task2"); + auto inboxProvider = Domain::QueryResultProvider::Ptr::create(); + auto inboxResult = Domain::QueryResult::create(inboxProvider); + inboxProvider->append(task1); + inboxProvider->append(task2); + + Utils::MockObject taskQueriesMock; + taskQueriesMock(&Domain::TaskQueries::findInboxTopLevel).when().thenReturn(inboxResult); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); + + Utils::MockObject taskRepositoryMock; + auto job = new FakeJob(this); + job->setExpectedError(KJob::KilledJobError, "Foo"); + taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).thenReturn(job); + + Presentation::TaskInboxPageModel inbox(taskQueriesMock.getInstance(), + taskRepositoryMock.getInstance()); + FakeErrorHandler errorHandler; + inbox.setErrorHandler(&errorHandler); + + // WHEN + const QModelIndex index = inbox.centralListModel()->index(1, 0); + inbox.promoteItem(index); + + // THEN + QTest::qWait(150); + QCOMPARE(errorHandler.m_message, QString("Cannot promote task task2 to be a project: Foo")); + } + void shouldGetAnErrorMessageWhenUpdateTaskFailed() { // GIVEN diff --git a/tests/units/presentation/workdaypagemodeltest.cpp b/tests/units/presentation/workdaypagemodeltest.cpp --- a/tests/units/presentation/workdaypagemodeltest.cpp +++ b/tests/units/presentation/workdaypagemodeltest.cpp @@ -249,6 +249,37 @@ // 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::findWorkdayTopLevel).when().thenReturn(taskResult); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task1).thenReturn(Domain::QueryResult::Ptr()); + taskQueriesMock(&Domain::TaskQueries::findChildren).when(task2).thenReturn(Domain::QueryResult::Ptr()); + + Utils::MockObject taskRepositoryMock; + taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).thenReturn(new FakeJob(this)); + + Presentation::WorkdayPageModel workday(taskQueriesMock.getInstance(), + taskRepositoryMock.getInstance()); + + // WHEN + const QModelIndex index = workday.centralListModel()->index(1, 0); + workday.promoteItem(index); + + // THEN + QVERIFY(taskRepositoryMock(&Domain::TaskRepository::promoteToProject).when(task2).exactly(1)); + } }; QTEST_MAIN(WorkdayPageModelTest)