diff --git a/src/akonadi/akonadicontextrepository.h b/src/akonadi/akonadicontextrepository.h --- a/src/akonadi/akonadicontextrepository.h +++ b/src/akonadi/akonadicontextrepository.h @@ -41,11 +41,11 @@ ContextRepository(const StorageInterface::Ptr &storage, const SerializerInterface::Ptr &serializer); - KJob *create(Domain::Context::Ptr context) override; + KJob *create(Domain::Context::Ptr context, Domain::DataSource::Ptr source) override; KJob *update(Domain::Context::Ptr context) override; KJob *remove(Domain::Context::Ptr context) override; - KJob *associate(Domain::Context::Ptr parent, Domain::Task::Ptr child) override; + KJob *associate(Domain::Context::Ptr context, Domain::Task::Ptr child) override; KJob *dissociate(Domain::Context::Ptr parent, Domain::Task::Ptr child) override; KJob *dissociateAll(Domain::Task::Ptr child) override; diff --git a/src/akonadi/akonadicontextrepository.cpp b/src/akonadi/akonadicontextrepository.cpp --- a/src/akonadi/akonadicontextrepository.cpp +++ b/src/akonadi/akonadicontextrepository.cpp @@ -39,45 +39,43 @@ } -KJob *ContextRepository::create(Domain::Context::Ptr context) +KJob *ContextRepository::create(Domain::Context::Ptr context, Domain::DataSource::Ptr source) { - auto tag = m_serializer->createTagFromContext(context); - Q_ASSERT(!tag.isValid()); - return m_storage->createTag(tag); + auto item = m_serializer->createItemFromContext(context); + Q_ASSERT(!item.isValid()); + auto collection = m_serializer->createCollectionFromDataSource(source); + Q_ASSERT(collection.isValid()); + return m_storage->createItem(item, collection); } KJob *ContextRepository::update(Domain::Context::Ptr context) { - auto tag = m_serializer->createTagFromContext(context); - Q_ASSERT(tag.isValid()); - return m_storage->updateTag(tag); + auto item = m_serializer->createItemFromContext(context); + Q_ASSERT(item.isValid()); + return m_storage->updateItem(item); } KJob *ContextRepository::remove(Domain::Context::Ptr context) { - auto tag = m_serializer->createTagFromContext(context); - Q_ASSERT(tag.isValid()); - return m_storage->removeTag(tag); + auto item = m_serializer->createItemFromContext(context); + Q_ASSERT(item.isValid()); + return m_storage->removeItem(item); } -KJob *ContextRepository::associate(Domain::Context::Ptr parent, Domain::Task::Ptr child) +KJob *ContextRepository::associate(Domain::Context::Ptr context, Domain::Task::Ptr child) { - Item childItem; - - childItem = m_serializer->createItemFromTask(child); + Item childItem = m_serializer->createItemFromTask(child); Q_ASSERT(childItem.isValid()); auto job = new Utils::CompositeJob(); ItemFetchJobInterface *fetchItemJob = m_storage->fetchItem(childItem); - job->install(fetchItemJob->kjob(), [fetchItemJob, parent, job, this] { + job->install(fetchItemJob->kjob(), [fetchItemJob, context, job, this] { if (fetchItemJob->kjob()->error() != KJob::NoError) return; Q_ASSERT(fetchItemJob->items().size() == 1); auto childItem = fetchItemJob->items().at(0); - auto tag = m_serializer->createTagFromContext(parent); - Q_ASSERT(tag.isValid()); - childItem.setTag(tag); + m_serializer->addContextToTask(context, childItem); auto updateJob = m_storage->updateItem(childItem); job->addSubjob(updateJob); diff --git a/src/domain/contextrepository.h b/src/domain/contextrepository.h --- a/src/domain/contextrepository.h +++ b/src/domain/contextrepository.h @@ -25,6 +25,7 @@ #define DOMAIN_CONTEXTREPOSITORY_H #include "context.h" +#include "datasource.h" #include "task.h" class KJob; @@ -39,7 +40,7 @@ ContextRepository(); virtual ~ContextRepository(); - virtual KJob *create(Context::Ptr context) = 0; + virtual KJob *create(Context::Ptr context, DataSource::Ptr source) = 0; virtual KJob *update(Context::Ptr context) = 0; virtual KJob *remove(Context::Ptr context) = 0; diff --git a/src/presentation/availablepagesmodel.h b/src/presentation/availablepagesmodel.h --- a/src/presentation/availablepagesmodel.h +++ b/src/presentation/availablepagesmodel.h @@ -62,7 +62,7 @@ public slots: void addProject(const QString &name, const Domain::DataSource::Ptr &source); - void addContext(const QString &name); + void addContext(const QString &name, const Domain::DataSource::Ptr &source); void removeItem(const QModelIndex &index); private: diff --git a/src/presentation/availablepagesmodel.cpp b/src/presentation/availablepagesmodel.cpp --- a/src/presentation/availablepagesmodel.cpp +++ b/src/presentation/availablepagesmodel.cpp @@ -129,11 +129,11 @@ installHandler(job, i18n("Cannot add project %1 in dataSource %2", name, source->name())); } -void AvailablePagesModel::addContext(const QString &name) +void AvailablePagesModel::addContext(const QString &name, const Domain::DataSource::Ptr &source) { auto context = Domain::Context::Ptr::create(); context->setName(name); - const auto job = m_contextRepository->create(context); + const auto job = m_contextRepository->create(context, source); installHandler(job, i18n("Cannot add context %1", name)); } diff --git a/src/widgets/availablepagesview.cpp b/src/widgets/availablepagesview.cpp --- a/src/widgets/availablepagesview.cpp +++ b/src/widgets/availablepagesview.cpp @@ -254,10 +254,15 @@ void AvailablePagesView::onAddContextTriggered() { - const QString name = m_messageBoxInterface->askTextInput(this, i18n("Add Context"), i18n("Context name")); - if (!name.isEmpty()) { + NewProjectDialogInterface::Ptr dialog = m_projectDialogFactory(this); + dialog->setWindowTitle(i18n("Add a context")); + dialog->setDataSourcesModel(m_sources); + + if (dialog->exec() == QDialog::Accepted) { + m_defaultSource = dialog->dataSource(); QMetaObject::invokeMethod(m_model, "addContext", - Q_ARG(QString, name)); + Q_ARG(QString, dialog->name()), + Q_ARG(Domain::DataSource::Ptr, dialog->dataSource())); } } diff --git a/src/widgets/messageboxinterface.h b/src/widgets/messageboxinterface.h --- a/src/widgets/messageboxinterface.h +++ b/src/widgets/messageboxinterface.h @@ -41,6 +41,8 @@ virtual ~MessageBoxInterface(); virtual QMessageBox::Button askConfirmation(QWidget *parent, const QString &title, const QString &text) = 0; + + // Now unused - remove? virtual QString askTextInput(QWidget *parent, const QString &title, const QString &text) = 0; }; diff --git a/src/widgets/newprojectdialog.h b/src/widgets/newprojectdialog.h --- a/src/widgets/newprojectdialog.h +++ b/src/widgets/newprojectdialog.h @@ -49,6 +49,7 @@ void accept() override; + void setWindowTitle(const QString &title) override; void setDataSourcesModel(QAbstractItemModel *model) override; QString name() const override; diff --git a/src/widgets/newprojectdialog.cpp b/src/widgets/newprojectdialog.cpp --- a/src/widgets/newprojectdialog.cpp +++ b/src/widgets/newprojectdialog.cpp @@ -92,6 +92,11 @@ QDialog::accept(); } +void NewProjectDialog::setWindowTitle(const QString &title) +{ + QDialog::setWindowTitle(title); +} + void NewProjectDialog::setDataSourcesModel(QAbstractItemModel *model) { m_flattenProxy->setSourceModel(model); diff --git a/src/widgets/newprojectdialoginterface.h b/src/widgets/newprojectdialoginterface.h --- a/src/widgets/newprojectdialoginterface.h +++ b/src/widgets/newprojectdialoginterface.h @@ -33,6 +33,7 @@ namespace Widgets { +// This is used to create both Projects and Contexts class NewProjectDialogInterface { public: @@ -42,6 +43,7 @@ virtual int exec() = 0; + virtual void setWindowTitle(const QString &text) = 0; virtual void setDataSourcesModel(QAbstractItemModel *model) = 0; virtual QString name() const = 0; virtual Domain::DataSource::Ptr dataSource() const = 0; diff --git a/tests/units/akonadi/akonadicontextrepositorytest.cpp b/tests/units/akonadi/akonadicontextrepositorytest.cpp --- a/tests/units/akonadi/akonadicontextrepositorytest.cpp +++ b/tests/units/akonadi/akonadicontextrepositorytest.cpp @@ -46,97 +46,98 @@ void shouldCreateContext() { // GIVEN + auto source = Domain::DataSource::Ptr::create(); + source->setName(QStringLiteral("Source1")); - // A Context and its corresponding Tag not existing in akonadi - Akonadi::Tag tag; + // A Context and its corresponding item not existing in akonadi + Akonadi::Item contextItem; + Akonadi::Collection collection(23); auto context = Domain::Context::Ptr::create(); // A mock creating job - auto tagCreateJob = new FakeJob(this); + auto itemCreateJob = new FakeJob(this); - // Storage mock returning the tagCreatejob + // Storage mock returning the context-item creation job Utils::MockObject storageMock; - storageMock(&Akonadi::StorageInterface::createTag).when(tag) - .thenReturn(tagCreateJob); + storageMock(&Akonadi::StorageInterface::createItem).when(contextItem, collection) + .thenReturn(itemCreateJob); // Serializer mock Utils::MockObject serializerMock; - serializerMock(&Akonadi::SerializerInterface::createTagFromContext).when(context).thenReturn(tag); - + serializerMock(&Akonadi::SerializerInterface::createItemFromContext).when(context).thenReturn(contextItem); + serializerMock(&Akonadi::SerializerInterface::createCollectionFromDataSource).when(source).thenReturn(collection); // WHEN QScopedPointer repository(new Akonadi::ContextRepository(storageMock.getInstance(), serializerMock.getInstance())); - repository->create(context)->exec(); + repository->create(context, source)->exec(); //THEN - QVERIFY(storageMock(&Akonadi::StorageInterface::createTag).when(tag).exactly(1)); + QVERIFY(storageMock(&Akonadi::StorageInterface::createItem).when(contextItem, collection).exactly(1)); } void shouldUpdateContext() { // GIVEN - Akonadi::Tag tag; - tag.setName(QStringLiteral("tag42")); - tag.setId(42); + Akonadi::Item contextItem; + contextItem.setId(42); auto context = Domain::Context::Ptr::create(); - // A mock creating job - auto tagModifyJob = new FakeJob(this); + // A mock job + auto itemModifyJob = new FakeJob(this); - // Storage mock returning the tagCreatejob + // Storage mock returning the item modify job Utils::MockObject storageMock; - storageMock(&Akonadi::StorageInterface::updateTag).when(tag) - .thenReturn(tagModifyJob); + storageMock(&Akonadi::StorageInterface::updateItem).when(contextItem, nullptr) + .thenReturn(itemModifyJob); // Serializer mock Utils::MockObject serializerMock; - serializerMock(&Akonadi::SerializerInterface::createTagFromContext).when(context).thenReturn(tag); + serializerMock(&Akonadi::SerializerInterface::createItemFromContext).when(context).thenReturn(contextItem); // WHEN QScopedPointer repository(new Akonadi::ContextRepository(storageMock.getInstance(), serializerMock.getInstance())); repository->update(context)->exec(); // THEN - QVERIFY(serializerMock(&Akonadi::SerializerInterface::createTagFromContext).when(context).exactly(1)); - QVERIFY(storageMock(&Akonadi::StorageInterface::updateTag).when(tag).exactly(1)); + QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromContext).when(context).exactly(1)); + QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(contextItem, nullptr).exactly(1)); } void shouldRemoveContext() { // GIVEN - Akonadi::Tag tag; - tag.setName(QStringLiteral("tag42")); - tag.setId(42); + Akonadi::Item contextItem; + contextItem.setId(42); auto context = Domain::Context::Ptr::create(); - // A mock creating job - auto tagDeleteJob= new FakeJob(this); + // A mock job + auto contextItemDeleteJob = new FakeJob(this); // Storage mock returning the tagCreatejob Utils::MockObject storageMock; - storageMock(&Akonadi::StorageInterface::removeTag).when(tag) - .thenReturn(tagDeleteJob); + storageMock(&Akonadi::StorageInterface::removeItem).when(contextItem) + .thenReturn(contextItemDeleteJob); // Serializer mock Utils::MockObject serializerMock; - serializerMock(&Akonadi::SerializerInterface::createTagFromContext).when(context).thenReturn(tag); + serializerMock(&Akonadi::SerializerInterface::createItemFromContext).when(context).thenReturn(contextItem); // WHEN QScopedPointer repository(new Akonadi::ContextRepository(storageMock.getInstance(), serializerMock.getInstance())); repository->remove(context)->exec(); // THEN - QVERIFY(serializerMock(&Akonadi::SerializerInterface::createTagFromContext).when(context).exactly(1)); - QVERIFY(storageMock(&Akonadi::StorageInterface::removeTag).when(tag).exactly(1)); + QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromContext).when(context).exactly(1)); + QVERIFY(storageMock(&Akonadi::StorageInterface::removeItem).when(contextItem).exactly(1)); } void shouldAssociateATaskToAContext_data() { - QTest::addColumn("associatedTag"); + QTest::addColumn("associatedContextItem"); QTest::addColumn("item"); QTest::addColumn("context"); QTest::addColumn("task"); @@ -149,22 +150,22 @@ item.setParentCollection(col); Domain::Task::Ptr task(new Domain::Task); - Akonadi::Tag associatedTag(qint64(43)); + Akonadi::Item associatedContextItem(43); auto associatedContext = Domain::Context::Ptr::create(); auto itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this); itemFetchJob->setItems(Akonadi::Item::List() << item); - QTest::newRow("nominal case") << associatedTag << item << associatedContext << task << itemFetchJob << true; + QTest::newRow("nominal case") << associatedContextItem << item << associatedContext << task << itemFetchJob << true; itemFetchJob = new Testlib::AkonadiFakeItemFetchJob(this); itemFetchJob->setExpectedError(KJob::KilledJobError); - QTest::newRow("task job error, cannot find task") << associatedTag << item << associatedContext << task << itemFetchJob << false; + QTest::newRow("task job error, cannot find task") << associatedContextItem << item << associatedContext << task << itemFetchJob << false; } void shouldAssociateATaskToAContext() { // GIVEN - QFETCH(Akonadi::Tag,associatedTag); + QFETCH(Akonadi::Item,associatedContextItem); QFETCH(Akonadi::Item,item); QFETCH(Domain::Context::Ptr,context); QFETCH(Domain::Task::Ptr,task); @@ -185,8 +186,8 @@ Utils::MockObject serializerMock; serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task) .thenReturn(item); - serializerMock(&Akonadi::SerializerInterface::createTagFromContext).when(context) - .thenReturn(associatedTag); + serializerMock(&Akonadi::SerializerInterface::addContextToTask).when(context, item) + .thenReturn(); // WHEN QScopedPointer repository(new Akonadi::ContextRepository(storageMock.getInstance(), @@ -199,7 +200,8 @@ // THEN QVERIFY(storageMock(&Akonadi::StorageInterface::fetchItem).when(item).exactly(1)); if (execJob) { - QVERIFY(serializerMock(&Akonadi::SerializerInterface::createTagFromContext).when(context).exactly(1)); + QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).exactly(1)); + QVERIFY(serializerMock(&Akonadi::SerializerInterface::addContextToTask).when(context, item).exactly(1)); QVERIFY(storageMock(&Akonadi::StorageInterface::updateItem).when(item, nullptr).exactly(1)); } } diff --git a/tests/units/akonadi/akonaditaskrepositorytest.cpp b/tests/units/akonadi/akonaditaskrepositorytest.cpp --- a/tests/units/akonadi/akonaditaskrepositorytest.cpp +++ b/tests/units/akonadi/akonaditaskrepositorytest.cpp @@ -262,12 +262,11 @@ void shouldCreateNewItemsInContext() { // GIVEN - // a tag - Akonadi::Tag tag; - tag.setName(QStringLiteral("tag42")); - tag.setId(42); + // a context item + Akonadi::Item contextItem; + contextItem.setId(42); - // the context related to the tag + // the context related to the item auto context = Domain::Context::Ptr::create(); // a default collection @@ -283,8 +282,8 @@ // serializer mock returning the item for the task Utils::MockObject serializerMock; - serializerMock(&Akonadi::SerializerInterface::createTagFromContext).when(context).thenReturn(tag); serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).thenReturn(taskItem); + serializerMock(&Akonadi::SerializerInterface::addContextToTask).when(context, taskItem).thenReturn(); // Storage mock returning the create job Utils::MockObject storageMock; @@ -301,7 +300,7 @@ // THEN QVERIFY(serializerMock(&Akonadi::SerializerInterface::createItemFromTask).when(task).exactly(1)); - QVERIFY(serializerMock(&Akonadi::SerializerInterface::createTagFromContext).when(context).exactly(1)); + QVERIFY(serializerMock(&Akonadi::SerializerInterface::addContextToTask).when(context, taskItem).exactly(1)); QVERIFY(storageMock(&Akonadi::StorageInterface::defaultCollection).when().exactly(1)); QVERIFY(storageMock(&Akonadi::StorageInterface::createItem).when(taskItem, defaultCollection).exactly(1)); 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 @@ -619,9 +619,11 @@ void shouldAddContexts() { // GIVEN + auto source = Domain::DataSource::Ptr::create(); + source->setName(QStringLiteral("Source1")); Utils::MockObject contextRepositoryMock; - contextRepositoryMock(&Domain::ContextRepository::create).when(any()) + contextRepositoryMock(&Domain::ContextRepository::create).when(any(), any()) .thenReturn(new FakeJob(this)); Presentation::AvailablePagesModel pages(Domain::DataSourceQueries::Ptr(), @@ -633,21 +635,23 @@ Domain::TaskRepository::Ptr()); // WHEN - pages.addContext(QStringLiteral("Foo")); + pages.addContext(QStringLiteral("Foo"), source); // THEN - QVERIFY(contextRepositoryMock(&Domain::ContextRepository::create).when(any()) + QVERIFY(contextRepositoryMock(&Domain::ContextRepository::create).when(any(), any()) .exactly(1)); } void shouldGetAnErrorMessageWhenAddContextFailed() { // GIVEN + auto source = Domain::DataSource::Ptr::create(); + source->setName(QStringLiteral("Source1")); Utils::MockObject contextRepositoryMock; auto job = new FakeJob(this); job->setExpectedError(KJob::KilledJobError, QStringLiteral("Foo")); - contextRepositoryMock(&Domain::ContextRepository::create).when(any()) + contextRepositoryMock(&Domain::ContextRepository::create).when(any(), any()) .thenReturn(job); Presentation::AvailablePagesModel pages(Domain::DataSourceQueries::Ptr(), @@ -661,7 +665,7 @@ pages.setErrorHandler(&errorHandler); // WHEN - pages.addContext(QStringLiteral("Foo")); + pages.addContext(QStringLiteral("Foo"), source); // THEN QTest::qWait(150); diff --git a/tests/units/widgets/availablepagesviewtest.cpp b/tests/units/widgets/availablepagesviewtest.cpp --- a/tests/units/widgets/availablepagesviewtest.cpp +++ b/tests/units/widgets/availablepagesviewtest.cpp @@ -78,10 +78,16 @@ return source; } + void setWindowTitle(const QString &title) override + { + windowTitle = title; + } + QWidget *parent; int execCount; QAbstractItemModel *sourceModel; Domain::DataSource::Ptr source; + QString windowTitle; }; class QuickSelectDialogStub : public Widgets::QuickSelectDialogInterface @@ -133,9 +139,10 @@ sources << source; } - void addContext(const QString &name) + void addContext(const QString &name, const Domain::DataSource::Ptr &source) { contextNames << name; + sources << source; } void addTag(const QString &name) @@ -299,24 +306,30 @@ 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); + available.setProjectDialogFactory([dialogStub] (QWidget *parent) { + dialogStub->parent = parent; + return dialogStub; + }); auto addContextAction = available.findChild(QStringLiteral("addContextAction")); // WHEN addContextAction->trigger(); // THEN - QVERIFY(msgBoxStub->called()); + QCOMPARE(dialogStub->execCount, 1); + QCOMPARE(dialogStub->parent, &available); + QCOMPARE(dialogStub->sourceModel, &sourceModel); + QCOMPARE(dialogStub->windowTitle, QStringLiteral("Add a context")); QCOMPARE(model.contextNames.size(), 1); - QCOMPARE(model.contextNames.first(), QStringLiteral("Foo")); + QCOMPARE(model.contextNames.first(), QStringLiteral("name")); + QCOMPARE(model.sources.size(), 1); + QCOMPARE(model.sources.first(), dialogStub->dataSource()); + QCOMPARE(available.defaultProjectSource(), dialogStub->dataSource()); } void shouldRemoveAPage_data()