diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -70,6 +70,7 @@ Ldap Runner Wallet + WindowSystem ) find_package(KF5Akonadi "5.1" CONFIG REQUIRED) diff --git a/src/akonadi/akonadiserializer.cpp b/src/akonadi/akonadiserializer.cpp --- a/src/akonadi/akonadiserializer.cpp +++ b/src/akonadi/akonadiserializer.cpp @@ -222,6 +222,7 @@ task->setProperty("parentCollectionId", item.parentCollection().id()); task->setProperty("todoUid", todo->uid()); task->setProperty("relatedUid", todo->relatedTo()); + task->setRunning(todo->customProperty("Zanshin", "Running") == QLatin1String("1")); if (todo->attendeeCount() > 0) { const auto attendees = todo->attendees(); @@ -277,6 +278,11 @@ KCalCore::Attendee::Accepted)); todo->addAttendee(attendee); } + if (task->isRunning()) { + todo->setCustomProperty("Zanshin", "Running", "1"); + } else { + todo->removeCustomProperty("Zanshin", "Running"); + } Akonadi::Item item; if (task->property("itemId").isValid()) { diff --git a/src/domain/task.h b/src/domain/task.h --- a/src/domain/task.h +++ b/src/domain/task.h @@ -33,6 +33,7 @@ class Task : public Artifact { Q_OBJECT + Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged) Q_PROPERTY(bool done READ isDone WRITE setDone NOTIFY doneChanged) Q_PROPERTY(QDateTime startDate READ startDate WRITE setStartDate NOTIFY startDateChanged) Q_PROPERTY(QDateTime dueDate READ dueDate WRITE setDueDate NOTIFY dueDateChanged) @@ -69,27 +70,31 @@ explicit Task(QObject *parent = Q_NULLPTR); virtual ~Task(); + bool isRunning() const; bool isDone() const; QDateTime startDate() const; QDateTime dueDate() const; QDateTime doneDate() const; Delegate delegate() const; public slots: + void setRunning(bool running); void setDone(bool done); void setDoneDate(const QDateTime &doneDate); void setStartDate(const QDateTime &startDate); void setDueDate(const QDateTime &dueDate); void setDelegate(const Domain::Task::Delegate &delegate); signals: + void runningChanged(bool isRunning); void doneChanged(bool isDone); void doneDateChanged(const QDateTime &doneDate); void startDateChanged(const QDateTime &startDate); void dueDateChanged(const QDateTime &dueDate); void delegateChanged(const Domain::Task::Delegate &delegate); private: + bool m_running; bool m_done; QDateTime m_startDate; QDateTime m_dueDate; diff --git a/src/domain/task.cpp b/src/domain/task.cpp --- a/src/domain/task.cpp +++ b/src/domain/task.cpp @@ -30,14 +30,20 @@ Task::Task(QObject *parent) : Artifact(parent), + m_running(false), m_done(false) { } Task::~Task() { } +bool Task::isRunning() const +{ + return m_running; +} + bool Task::isDone() const { return m_done; @@ -95,6 +101,14 @@ return m_delegate; } +void Task::setRunning(bool running) +{ + if (m_running == running) + return; + m_running = running; + emit runningChanged(running); +} + void Task::setDueDate(const QDateTime &dueDate) { if (m_dueDate == dueDate) diff --git a/src/presentation/CMakeLists.txt b/src/presentation/CMakeLists.txt --- a/src/presentation/CMakeLists.txt +++ b/src/presentation/CMakeLists.txt @@ -15,9 +15,12 @@ pagemodel.cpp projectpagemodel.cpp querytreemodelbase.cpp + runningtaskmodelinterface.cpp + runningtaskmodel.cpp tagpagemodel.cpp taskinboxpagemodel.cpp tasklistmodel.cpp + taskapplicationmodel.cpp workdaypagemodel.cpp ) diff --git a/src/presentation/runningtaskmodel.h b/src/presentation/runningtaskmodel.h new file mode 100644 --- /dev/null +++ b/src/presentation/runningtaskmodel.h @@ -0,0 +1,62 @@ +/* This file is part of Zanshin + + Copyright 2016-2017 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. +*/ + +#ifndef PRESENTATION_RUNNINGTASKMODEL_H +#define PRESENTATION_RUNNINGTASKMODEL_H + +#include "domain/taskqueries.h" +#include "domain/taskrepository.h" + +#include "runningtaskmodelinterface.h" + +namespace Presentation { + +class RunningTaskModel : public RunningTaskModelInterface +{ + Q_OBJECT +public: + typedef QSharedPointer Ptr; + + explicit RunningTaskModel(const Domain::TaskQueries::Ptr &taskQueries, + const Domain::TaskRepository::Ptr &taskRepository, + QObject *parent = nullptr); + ~RunningTaskModel(); + + Domain::Task::Ptr runningTask() const Q_DECL_OVERRIDE; + void setRunningTask(const Domain::Task::Ptr &runningTask) Q_DECL_OVERRIDE; + +public slots: + void stopTask() Q_DECL_OVERRIDE; + void doneTask() Q_DECL_OVERRIDE; + +private: + Domain::Task::Ptr m_runningTask; + + Domain::QueryResult::Ptr m_taskList; + Domain::TaskQueries::Ptr m_queries; + Domain::TaskRepository::Ptr m_taskRepository; +}; + +} + +#endif // PRESENTATION_RUNNINGTASKMODEL_H diff --git a/src/presentation/runningtaskmodel.cpp b/src/presentation/runningtaskmodel.cpp new file mode 100644 --- /dev/null +++ b/src/presentation/runningtaskmodel.cpp @@ -0,0 +1,82 @@ +/* This file is part of Zanshin + + Copyright 2016-2017 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 "runningtaskmodel.h" + +using namespace Presentation; + +RunningTaskModel::RunningTaskModel(const Domain::TaskQueries::Ptr &taskQueries, + const Domain::TaskRepository::Ptr &taskRepository, + QObject *parent) + : RunningTaskModelInterface(parent), + m_queries(taskQueries), + m_taskRepository(taskRepository) +{ + // List all tasks to find if any one is already set to "running" + if (m_queries) { + m_taskList = m_queries->findAll(); + Q_ASSERT(m_taskList); + m_taskList->addPostInsertHandler([this](const Domain::Task::Ptr &task, int) { + if (task->isRunning()) { + setRunningTask(task); + } + }); + // if there was a addFinishedHandler, we could reset m_queries and m_taskList to nullptr there to free memory. + } +} + +RunningTaskModel::~RunningTaskModel() +{ +} + +Domain::Task::Ptr RunningTaskModel::runningTask() const +{ + return m_runningTask; +} + +void RunningTaskModel::setRunningTask(const Domain::Task::Ptr &runningTask) +{ + if (m_runningTask) { + m_runningTask->setRunning(false); + KJob *job = m_taskRepository->update(m_runningTask); + installHandler(job, tr("Cannot update task %1 to 'not running'").arg(m_runningTask->title())); + } + m_runningTask = runningTask; + if (m_runningTask) { + m_runningTask->setRunning(true); + KJob *job = m_taskRepository->update(m_runningTask); + installHandler(job, tr("Cannot update task %1 to 'running'").arg(m_runningTask->title())); + } + emit runningTaskChanged(m_runningTask); +} + +void RunningTaskModel::stopTask() +{ + setRunningTask(nullptr); +} + +void RunningTaskModel::doneTask() +{ + m_runningTask->setDone(true); + stopTask(); +} diff --git a/src/presentation/runningtaskmodelinterface.h b/src/presentation/runningtaskmodelinterface.h new file mode 100644 --- /dev/null +++ b/src/presentation/runningtaskmodelinterface.h @@ -0,0 +1,58 @@ +/* This file is part of Zanshin + + Copyright 2017 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. +*/ + +#ifndef PRESENTATION_RUNNINGTASKMODELINTERFACE_H +#define PRESENTATION_RUNNINGTASKMODELINTERFACE_H + +#include + +#include "domain/task.h" + +#include "errorhandlingmodelbase.h" + +namespace Presentation { + +class RunningTaskModelInterface : public QObject, public ErrorHandlingModelBase +{ + Q_OBJECT + Q_PROPERTY(Domain::Task::Ptr runningTask READ runningTask WRITE setRunningTask NOTIFY runningTaskChanged) +public: + typedef QSharedPointer Ptr; + + explicit RunningTaskModelInterface(QObject *parent = nullptr); + ~RunningTaskModelInterface(); + + virtual Domain::Task::Ptr runningTask() const = 0; + virtual void setRunningTask(const Domain::Task::Ptr &runningTask) = 0; + +signals: + void runningTaskChanged(const Domain::Task::Ptr &task); + +public slots: + virtual void stopTask() = 0; + virtual void doneTask() = 0; +}; + +} + +#endif // PRESENTATION_RUNNINGTASKMODEL_H diff --git a/src/presentation/runningtaskmodelinterface.cpp b/src/presentation/runningtaskmodelinterface.cpp new file mode 100644 --- /dev/null +++ b/src/presentation/runningtaskmodelinterface.cpp @@ -0,0 +1,12 @@ +#include "runningtaskmodelinterface.h" + +using namespace Presentation; + +RunningTaskModelInterface::RunningTaskModelInterface(QObject *parent) + : QObject(parent) +{ +} + +RunningTaskModelInterface::~RunningTaskModelInterface() +{ +} diff --git a/src/presentation/taskapplicationmodel.h b/src/presentation/taskapplicationmodel.h new file mode 100644 --- /dev/null +++ b/src/presentation/taskapplicationmodel.h @@ -0,0 +1,50 @@ +/* This file is part of Zanshin + + Copyright 2016-2017 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. +*/ + +#ifndef TASKAPPLICATIONMODEL_H +#define TASKAPPLICATIONMODEL_H + +#include "applicationmodel.h" +#include "runningtaskmodelinterface.h" + +namespace Presentation { + +class TaskApplicationModel : public ApplicationModel +{ + Q_OBJECT + Q_PROPERTY(RunningTaskModelInterface* runningTaskModel READ runningTaskModel) +public: + typedef QSharedPointer Ptr; + + explicit TaskApplicationModel(QObject *parent = Q_NULLPTR); + ~TaskApplicationModel(); + + Presentation::RunningTaskModelInterface *runningTaskModel(); + +private: + RunningTaskModelInterface::Ptr m_runningTaskModel; +}; + +} + +#endif // TASKAPPLICATIONMODEL_H diff --git a/src/presentation/taskapplicationmodel.cpp b/src/presentation/taskapplicationmodel.cpp new file mode 100644 --- /dev/null +++ b/src/presentation/taskapplicationmodel.cpp @@ -0,0 +1,47 @@ +/* This file is part of Zanshin + + Copyright 2016-2017 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 "runningtaskmodel.h" +#include "taskapplicationmodel.h" +#include "utils/dependencymanager.h" + +using namespace Presentation; + +TaskApplicationModel::TaskApplicationModel(QObject *parent) + : ApplicationModel(parent) +{ +} + +TaskApplicationModel::~TaskApplicationModel() +{ +} + +RunningTaskModelInterface *TaskApplicationModel::runningTaskModel() +{ + if (!m_runningTaskModel) { + auto model = Utils::DependencyManager::globalInstance().create(); + m_runningTaskModel = model; + m_runningTaskModel->setErrorHandler(errorHandler()); + } + return m_runningTaskModel.data(); +} diff --git a/src/renku/app/org.kde.renku.appdata.xml b/src/renku/app/org.kde.renku.appdata.xml --- a/src/renku/app/org.kde.renku.appdata.xml +++ b/src/renku/app/org.kde.renku.appdata.xml @@ -30,7 +30,7 @@ Note Taking Application Aplicación para tomar notas Muistiinpanosovellus - Programa para tomar notas + Aplicativo para tomar notas Applicazione per prendere delle note Toepassing voor notities Aplikacja do robienia notatek @@ -52,7 +52,7 @@

Renku is an efficient and simple application for managing your notes. It helps you organise the knowledge you accumulate and acts as a personal wiki. You'll never forget anything any more, getting your mind like water.

Renku es una aplicación sencilla y eficiente para gestionar sus notas. Le ayuda a organizar el conocimiento que acumula y funciona como una wiki personal. Ya no volverá a olvidarse de nada, teniendo la mente clara como el agua.

Renku on yksinkertainen ja tehokas sovellus muistiinpanojesi hallitsemiseen. Se auttaa sinua järjestämään keräämiäsi tietoja ja toimii henkilökohtaisena wikinä. Et koskaan enää unohda mitään: se toimii kuin vettä vain.

-

Renku é un programa eficiente e sinxelo para xestionar notas. Axúdao a organizar o coñecemento que acumula, e actúa como un wiki persoal. Non volverá esquecer nada nunca máis, convertendo a súa mente en auga.

+

Renku é un aplicativo eficiente e sinxelo para xestionar notas. Axúdao a organizar o coñecemento que acumula, e actúa como un wiki persoal. Non volverá esquecer nada nunca máis, convertendo a súa mente en auga.

Renku è un'applicazione semplice ed efficiente per la gestione delle tue note. Consente di organizzare la conoscenza che accumuli e agisce come un wiki personale. Non dimenticherai mai più niente, lasciando la tua mente fluida come l'acqua.

Renku is een efficiënte en eenvoudige toepassing voor het beheer van uw notities. Het helpt u de verzamelde kennis te organiseren en werkt als een persoonlijke wiki. U zult nooit meer iets vergeten en uw geheugen is geen zeef meer.

Renku jest wydajną i prostą aplikacją do zarządzania notatkami. Pomaga uporządkować zbieraną przez ciebie wiedzę i działa jak osobista wikipedia. Nigdy już nie zapomnisz o niczym, twoje myśli staną się jak woda.

@@ -124,7 +124,7 @@
  • Akonadi-enabled application allowing to get the data from virtually anywhere (local, imap, web service...)
  • Aplicación que usa Akonadi para obtener datos de prácticamente cualquier lugar (locales, IMAP, servicios web...)
  • Akonadiin perustuva sovellus sallii etsiä tietoa käytännössä mistä vain (kiintolevyltä, IMAPista, verkkopalveluista…)
  • -
  • O programa é compatíbel con Akonadi, e permítelle obter datos de practicamente calquera lugar (local, IMAP, servizos web).
  • +
  • O aplicativo é compatíbel con Akonadi, e permítelle obter datos de practicamente calquera lugar (local, IMAP, servizos web).
  • Applicazione basata su Akonadi che consente di ottenere i dati praticamente ovunque (locale, imap, servizio web...)
  • In Akonadi opgenomen toepassing waarmee u gegevens werkelijk overal vandaan kunt halen (lokaal, imap, webservice...)
  • Program wykorzystuje Akonadi, więc można pobierać dane praktycznie z każdego miejsca (lokalnie, imap, usługa sieciowa...)
  • diff --git a/src/renku/app/org.kde.renku.desktop b/src/renku/app/org.kde.renku.desktop --- a/src/renku/app/org.kde.renku.desktop +++ b/src/renku/app/org.kde.renku.desktop @@ -28,7 +28,7 @@ GenericName[en_GB]=Note Taking Application GenericName[es]=Aplicación para tomar notas GenericName[fi]=Muistiinpanosovellus -GenericName[gl]=Programa para tomar notas +GenericName[gl]=Aplicativo para tomar notas GenericName[it]=Applicazione per prendere delle note GenericName[nl]=Toepassing voor notities GenericName[pl]=Aplikacja do robienia notatek diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt --- a/src/widgets/CMakeLists.txt +++ b/src/widgets/CMakeLists.txt @@ -12,9 +12,11 @@ newprojectdialoginterface.cpp pageview.cpp pageviewerrorhandler.cpp + runningtaskwidget.cpp quickselectdialog.cpp quickselectdialoginterface.cpp scripteditor.cpp + taskapplicationcomponents.cpp ) qt5_wrap_ui(widgets_SRCS @@ -29,4 +31,5 @@ Qt5::Widgets presentation zanshinkdepimstatic + KF5::WindowSystem ) diff --git a/src/widgets/applicationcomponents.h b/src/widgets/applicationcomponents.h --- a/src/widgets/applicationcomponents.h +++ b/src/widgets/applicationcomponents.h @@ -69,15 +69,21 @@ AvailableSourcesView *availableSourcesView() const; AvailablePagesView *availablePagesView() const; - PageView *pageView() const; + virtual PageView *pageView() const; EditorView *editorView() const; QuickSelectDialogFactory quickSelectDialogFactory() const; +protected: + QWidget *parentWidget() const; + public slots: - void setModel(const QObjectPtr &model); + virtual void setModel(const QObjectPtr &model); void setQuickSelectDialogFactory(const QuickSelectDialogFactory &factory); +protected: + PageView *m_pageView; + private slots: void onCurrentPageChanged(QObject *page); void onCurrentArtifactChanged(const Domain::Artifact::Ptr &artifact); @@ -93,7 +99,6 @@ QWidget *m_parent; QPointer m_availableSourcesView; QPointer m_availablePagesView; - PageView *m_pageView; QPointer m_editorView; QScopedPointer m_errorHandler; diff --git a/src/widgets/applicationcomponents.cpp b/src/widgets/applicationcomponents.cpp --- a/src/widgets/applicationcomponents.cpp +++ b/src/widgets/applicationcomponents.cpp @@ -44,10 +44,10 @@ ApplicationComponents::ApplicationComponents(QWidget *parent) : QObject(parent), + m_pageView(Q_NULLPTR), m_parent(parent), m_availableSourcesView(Q_NULLPTR), m_availablePagesView(Q_NULLPTR), - m_pageView(Q_NULLPTR), m_editorView(Q_NULLPTR), m_errorHandler(new PageViewErrorHandler) { @@ -160,6 +160,11 @@ return m_quickSelectDialogFactory; } +QWidget *ApplicationComponents::parentWidget() const +{ + return m_parent; +} + void ApplicationComponents::setModel(const QObjectPtr &model) { if (m_model == model) diff --git a/src/widgets/pageview.h b/src/widgets/pageview.h --- a/src/widgets/pageview.h +++ b/src/widgets/pageview.h @@ -34,14 +34,19 @@ #include #include "domain/artifact.h" +#include "domain/task.h" #include "messageboxinterface.h" class QLineEdit; class QModelIndex; class QMessageBox; class KMessageWidget; +namespace Presentation { +class RunningTaskModelInterface; +} + namespace Widgets { class FilterWidget; @@ -56,11 +61,13 @@ QHash globalActions() const; QObject *model() const; + Presentation::RunningTaskModelInterface *runningTaskModel() const; MessageBoxInterface::Ptr messageBoxInterface() const; QModelIndexList selectedIndexes() const; public slots: void setModel(QObject *model); + void setRunningTaskModel(Presentation::RunningTaskModelInterface *model); void setMessageBoxInterface(const MessageBoxInterface::Ptr &interface); void displayErrorMessage(const QString &message); @@ -74,18 +81,24 @@ void onPromoteItemRequested(); void onFilterToggled(bool show); void onCurrentChanged(const QModelIndex ¤t); + void onRunTaskTriggered(); + void onRunningTaskChanged(const Domain::Task::Ptr &task); private: bool eventFilter(QObject *object, QEvent *event) Q_DECL_OVERRIDE; + void updateRunTaskAction(); + Domain::Artifact::Ptr currentArtifact() const; QHash m_actions; QAction *m_cancelAction; + QAction *m_runTaskAction; QObject *m_model; KMessageWidget *m_messageWidget; FilterWidget *m_filterWidget; PageTreeView *m_centralView; QLineEdit *m_quickAddEdit; MessageBoxInterface::Ptr m_messageBoxInterface; + Presentation::RunningTaskModelInterface *m_runningTaskModel; }; } diff --git a/src/widgets/pageview.cpp b/src/widgets/pageview.cpp --- a/src/widgets/pageview.cpp +++ b/src/widgets/pageview.cpp @@ -45,6 +45,7 @@ #include "presentation/artifactfilterproxymodel.h" #include "presentation/metatypes.h" #include "presentation/querytreemodelbase.h" +#include "presentation/runningtaskmodelinterface.h" namespace Widgets { class PageTreeView : public QTreeView @@ -197,10 +198,19 @@ filterViewAction->setCheckable(true); connect(filterViewAction, &QAction::triggered, this, &PageView::onFilterToggled); + m_runTaskAction = new QAction(this); + m_runTaskAction->setObjectName(QStringLiteral("runTaskAction")); + m_runTaskAction->setShortcut(Qt::CTRL | Qt::Key_Space); + m_runTaskAction->setText(tr("Start now")); + m_runTaskAction->setIcon(QIcon::fromTheme(QStringLiteral("media-playback-start"))); + connect(m_runTaskAction, &QAction::triggered, this, &PageView::onRunTaskTriggered); + updateRunTaskAction(); + m_actions.insert(QStringLiteral("page_view_add"), addItemAction); m_actions.insert(QStringLiteral("page_view_remove"), removeItemAction); m_actions.insert(QStringLiteral("page_view_promote"), promoteItemAction); m_actions.insert(QStringLiteral("page_view_filter"), filterViewAction); + m_actions.insert(QStringLiteral("page_run_task"), m_runTaskAction); } QHash PageView::globalActions() const @@ -213,6 +223,11 @@ return m_model; } +Presentation::RunningTaskModelInterface *PageView::runningTaskModel() const +{ + return m_runningTaskModel; +} + void PageView::setModel(QObject *model) { if (model == m_model) @@ -228,6 +243,8 @@ setEnabled(m_model); + updateRunTaskAction(); + if (!m_model) return; @@ -257,6 +274,13 @@ return sourceIndices; } +void PageView::setRunningTaskModel(Presentation::RunningTaskModelInterface *model) +{ + m_runningTaskModel = model; + connect(m_runningTaskModel, SIGNAL(runningTaskChanged(Domain::Task::Ptr)), + this, SLOT(onRunningTaskChanged(Domain::Task::Ptr))); +} + void PageView::setMessageBoxInterface(const MessageBoxInterface::Ptr &interface) { m_messageBoxInterface = interface; @@ -365,13 +389,40 @@ m_filterWidget->clear(); } +void PageView::updateRunTaskAction() +{ + const auto artifact = currentArtifact(); + const auto task = artifact.objectCast(); + m_runTaskAction->setEnabled(task); +} + +void PageView::onRunTaskTriggered() +{ + auto task = currentArtifact().objectCast(); + Q_ASSERT(task); // the action is supposed to be disabled otherwise + if (task->startDate().isNull()) + task->setStartDate(QDateTime::currentDateTime()); + m_runningTaskModel->setProperty("runningTask", QVariant::fromValue(task)); +} + +void PageView::onRunningTaskChanged(const Domain::Task::Ptr &task) +{ + if (!task) { + QWidget *toplevel = window(); + toplevel->raise(); + toplevel->activateWindow(); + } +} + void PageView::onCurrentChanged(const QModelIndex ¤t) { + updateRunTaskAction(); + auto data = current.data(Presentation::QueryTreeModelBase::ObjectRole); if (!data.isValid()) return; - auto artifact = data.value(); + auto artifact = currentArtifact(); if (!artifact) return; @@ -395,4 +446,14 @@ return false; } +Domain::Artifact::Ptr PageView::currentArtifact() const +{ + const auto current = m_centralView->selectionModel()->currentIndex(); + const auto data = current.data(Presentation::QueryTreeModelBase::ObjectRole); + if (!data.isValid()) + return Domain::Artifact::Ptr(Q_NULLPTR); + + return data.value(); +} + #include "pageview.moc" diff --git a/src/widgets/runningtaskwidget.h b/src/widgets/runningtaskwidget.h new file mode 100644 --- /dev/null +++ b/src/widgets/runningtaskwidget.h @@ -0,0 +1,76 @@ +/* This file is part of Zanshin + + Copyright 2016 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. +*/ + +#ifndef RUNNINGTASKWIDGET_H +#define RUNNINGTASKWIDGET_H + +#include +#include "domain/task.h" + +class QLabel; +class QHBoxLayout; +class QPushButton; + +namespace Presentation { +class RunningTaskModelInterface; +} + +namespace Widgets { + +class RunningTaskWidget : public QWidget +{ + Q_OBJECT +public: + explicit RunningTaskWidget(QWidget *parent = Q_NULLPTR); + + void setModel(Presentation::RunningTaskModelInterface *model); + + Presentation::RunningTaskModelInterface *model() const; + +private slots: + // connected to the model + void onRunningTaskChanged(const Domain::Task::Ptr &task); + // connected to the push buttons + void onTaskRunStopped(); + void onTaskRunDone(); + + void setCollapsed(bool b); + +protected: + void enterEvent(QEvent *ev) Q_DECL_OVERRIDE; + void leaveEvent(QEvent *ev) Q_DECL_OVERRIDE; + +private: + void resize(); + + Presentation::RunningTaskModelInterface *m_model; + QHBoxLayout *m_layout; + QLabel *m_titleLabel; + QPushButton *m_stopButton; + QPushButton *m_doneButton; + bool m_collapsed; +}; + +} + +#endif // RUNNINGTASKWIDGET_H diff --git a/src/widgets/runningtaskwidget.cpp b/src/widgets/runningtaskwidget.cpp new file mode 100644 --- /dev/null +++ b/src/widgets/runningtaskwidget.cpp @@ -0,0 +1,138 @@ +/* This file is part of Zanshin + + Copyright 2016 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 "runningtaskwidget.h" +#include "runningtaskmodelinterface.h" +#include +#include +#include +#include +#include +#include + +using namespace Widgets; + +RunningTaskWidget::RunningTaskWidget(QWidget *parent) + : QWidget(parent), + m_layout(new QHBoxLayout(this)), + m_titleLabel(new QLabel(this)), + m_stopButton(new QPushButton(this)), + m_doneButton(new QPushButton(this)), + m_collapsed(false) +{ + // BypassWindowManagerHint allows to prevent the window from showing up in Alt-Tab + // This means no way to focus it with the keyboard, though, obviously. + + setWindowFlags(Qt::Window | Qt::BypassWindowManagerHint | Qt::FramelessWindowHint); + KWindowSystem::setOnAllDesktops(winId(), true); + KWindowSystem::setState(winId(), NET::KeepAbove | NET::SkipTaskbar | NET::SkipPager); + + setWindowTitle(tr("Zanshin Running Task Banner")); + + // Current idea for a good background color: + // the selection color, i.e. usually blue. Arguable ;) + QPalette pal; + pal.setBrush(QPalette::Background, pal.brush(QPalette::Highlight)); + setPalette(pal); + setAutoFillBackground(true); + + m_stopButton->setObjectName(QStringLiteral("stopButton")); + m_stopButton->setText(tr("Stop")); + connect(m_stopButton, &QAbstractButton::clicked, this, &RunningTaskWidget::onTaskRunStopped); + + m_doneButton->setObjectName(QStringLiteral("doneButton")); + m_doneButton->setText(tr("Done")); + connect(m_doneButton, &QAbstractButton::clicked, this, &RunningTaskWidget::onTaskRunDone); + + m_layout->setContentsMargins(0, 0, 0, 0); + m_layout->addWidget(m_stopButton); + m_layout->addWidget(m_titleLabel, 1, Qt::AlignCenter); + m_layout->addWidget(m_doneButton); + + setCollapsed(true); +} + +void RunningTaskWidget::setModel(Presentation::RunningTaskModelInterface *model) +{ + Q_ASSERT(model); + m_model = model; + connect(m_model, &Presentation::RunningTaskModelInterface::runningTaskChanged, + this, &RunningTaskWidget::onRunningTaskChanged); +} + +void RunningTaskWidget::setCollapsed(bool b) +{ + if (m_collapsed == b) { + return; + } + m_collapsed = b; + m_stopButton->setVisible(!b); + m_titleLabel->setVisible(!b); + m_doneButton->setVisible(!b); + m_layout->activate(); + resize(); +} + +void RunningTaskWidget::enterEvent(QEvent *) +{ + setCollapsed(false); +} + +void RunningTaskWidget::leaveEvent(QEvent *) +{ + setCollapsed(true); +} + +void RunningTaskWidget::onRunningTaskChanged(const Domain::Task::Ptr &task) +{ + if (task) { + m_titleLabel->setText(task->title()); + resize(); + show(); + } else { + hide(); + } +} + +void RunningTaskWidget::onTaskRunStopped() +{ + QMetaObject::invokeMethod(m_model, "stopTask"); +} + +void RunningTaskWidget::onTaskRunDone() +{ + QMetaObject::invokeMethod(m_model, "doneTask"); +} + +void RunningTaskWidget::resize() +{ + const auto screenGeometry = qApp->desktop()->availableGeometry(this); + const int screenWidth = screenGeometry.width(); + const int height = m_collapsed ? 5 : sizeHint().height(); + setGeometry(QRect(screenGeometry.left(), screenGeometry.top(), screenWidth, height)); +} + +Presentation::RunningTaskModelInterface *RunningTaskWidget::model() const +{ + return m_model; +} diff --git a/src/widgets/taskapplicationcomponents.h b/src/widgets/taskapplicationcomponents.h new file mode 100644 --- /dev/null +++ b/src/widgets/taskapplicationcomponents.h @@ -0,0 +1,51 @@ +/* This file is part of Zanshin + + Copyright 2016-2017 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. +*/ + +#ifndef WIDGETS_TASKAPPLICATIONCOMPONENTS_H +#define WIDGETS_TASKAPPLICATIONCOMPONENTS_H + +#include "applicationcomponents.h" + +namespace Widgets { + +class RunningTaskWidget; + +class TaskApplicationComponents : public ApplicationComponents +{ +public: + explicit TaskApplicationComponents(QWidget *parent = Q_NULLPTR); + ~TaskApplicationComponents(); + + virtual void setModel(const QObjectPtr &model) Q_DECL_OVERRIDE; + + virtual PageView *pageView() const; + + RunningTaskWidget *runningTaskWidget() const; + +private: + RunningTaskWidget *m_runningTaskWidget; +}; + +} + +#endif // WIDGETS_TASKAPPLICATIONCOMPONENTS_H diff --git a/src/widgets/taskapplicationcomponents.cpp b/src/widgets/taskapplicationcomponents.cpp new file mode 100644 --- /dev/null +++ b/src/widgets/taskapplicationcomponents.cpp @@ -0,0 +1,66 @@ +/* This file is part of Zanshin + + Copyright 2016-2017 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 "taskapplicationcomponents.h" + +#include "pageview.h" +#include "runningtaskwidget.h" +#include "runningtaskmodelinterface.h" + +using namespace Widgets; +using namespace Presentation; + +TaskApplicationComponents::TaskApplicationComponents(QWidget *parent) + : ApplicationComponents(parent), + m_runningTaskWidget(new RunningTaskWidget(parentWidget())) +{ +} + +TaskApplicationComponents::~TaskApplicationComponents() +{ +} + +void TaskApplicationComponents::setModel(const QObjectPtr &model) +{ + ApplicationComponents::setModel(model); + RunningTaskModelInterface *runningTaskModel = model ? model->property("runningTaskModel").value() + : nullptr; + m_runningTaskWidget->setModel(runningTaskModel); + if (m_pageView) { + m_pageView->setRunningTaskModel(runningTaskModel); + } +} + +PageView *TaskApplicationComponents::pageView() const +{ + auto pageView = ApplicationComponents::pageView(); + pageView->setRunningTaskModel(model() ? model()->property("runningTaskModel").value() + : nullptr); + return pageView; +} + +// Only used by the unittest +RunningTaskWidget *TaskApplicationComponents::runningTaskWidget() const +{ + return m_runningTaskWidget; +} diff --git a/src/zanshin/app/dependencies.cpp b/src/zanshin/app/dependencies.cpp --- a/src/zanshin/app/dependencies.cpp +++ b/src/zanshin/app/dependencies.cpp @@ -40,6 +40,7 @@ #include "presentation/artifacteditormodel.h" #include "presentation/availablesourcesmodel.h" #include "presentation/availabletaskpagesmodel.h" +#include "presentation/runningtaskmodel.h" #include "utils/dependencymanager.h" @@ -117,4 +118,8 @@ deps.add(); + + deps.add(); } diff --git a/src/zanshin/app/main.cpp b/src/zanshin/app/main.cpp --- a/src/zanshin/app/main.cpp +++ b/src/zanshin/app/main.cpp @@ -31,13 +31,13 @@ #include -#include "widgets/applicationcomponents.h" +#include "widgets/taskapplicationcomponents.h" #include "widgets/availablepagesview.h" #include "widgets/availablesourcesview.h" #include "widgets/editorview.h" #include "widgets/pageview.h" -#include "presentation/applicationmodel.h" +#include "presentation/taskapplicationmodel.h" #include "aboutdata.h" #include "dependencies.h" @@ -62,8 +62,8 @@ aboutData.processCommandLine(&parser); auto widget = new QWidget; - auto components = new Widgets::ApplicationComponents(widget); - components->setModel(Presentation::ApplicationModel::Ptr::create()); + auto components = new Widgets::TaskApplicationComponents(widget); + components->setModel(Presentation::TaskApplicationModel::Ptr::create()); auto layout = new QVBoxLayout; layout->setContentsMargins(0, 0, 0, 0); diff --git a/src/zanshin/app/org.kde.zanshin.appdata.xml b/src/zanshin/app/org.kde.zanshin.appdata.xml --- a/src/zanshin/app/org.kde.zanshin.appdata.xml +++ b/src/zanshin/app/org.kde.zanshin.appdata.xml @@ -32,7 +32,7 @@ TODO Management Application Aplicación de gestión de lista de cosas pendientes Tehtävienhallintasovellus - Programa de xestión de tarefas + Aplicativo de xestión de tarefas Applicazione di gestione delle COSE DA FARE Beheertoepassing voor taken Program do zarządzania zadaniami @@ -54,7 +54,7 @@

    Zanshin is a powerful yet simple application for managing your day to day actions. It helps you organise and reduce the cognitive pressure of what one has to do in his job and personal life. You'll never forget anything any more, getting your mind like water.

    Zanshin es una potente y sencilla aplicación para gestionar sus acciones diarias. Le ayuda a organizar y reducir la presión cognitiva de lo que debe hacer en su trabajo y en su vida personal. Nunca más volverá a olvidarse de nada, teniendo una mente clara como el agua.

    Zanshin on tehokas mutta yksinkertainen päivittäisten toimiesi hallintasovellus. Se auttaa sinua järjestämään työtäsi ja yksityiselämääsi ja vähentämään ajanhallinnan paineita. Et koskaan enää unohda mitään.

    -

    Zanshin é un programa potente pero sinxelo para xestionar as acciónsdo día a día. Axúdao a organizar o que ten que facer no seu traballo e na vida persoal para quitarlle ese peso de encima. Non volverá esquecer nada nunca máis, convertendo así a súa mente en auga.

    +

    Zanshin é un aplicativo potente pero sinxelo para xestionar as acciónsdo día a día. Axúdao a organizar o que ten que facer no seu traballo e na vida persoal para quitarlle ese peso de encima. Non volverá esquecer nada nunca máis, convertendo así a súa mente en auga.

    Zanshin è un'applicazione semplice ma potente per la gestione delle tue attività giornaliere. Ti aiuta a organizzarti e riduce lo stress mentale che ciascuno di noi sperimenta durante la propria vita privata e lavorativa. Non dimenticherai più nulla, e la tua mente sarà fresca e leggera come l'acqua.

    Zanshin is een krachtig en toch eenvoudige toepassing voor het beheer van uw dagelijkse acties. Het helpt u bij het organiseren en reduceert de mentale druk over wat er allemaal gedaan moet worden op het persoonlijke en zakelijke vlak. U zult nooit meer iets vergeten, uw geheugen is geen zeef meer.

    Zanshin jest zaawansowanym, a zarazem prostym programem do zarządzania codziennymi zadaniami. Pomaga zorganizować i zmniejszyć natłok czynności, które użytkownik musi wykonać w swojej pracy lub życiu osobistym. Nigdy już nie zapomnisz o niczym, twoje myśli staną się jak woda.

    @@ -123,7 +123,7 @@
  • Akonadi-enabled application allowing to get the data from virtually anywhere (local, imap, web service...)
  • Aplicación que usa Akonadi para obtener datos de prácticamente cualquier lugar (locales, IMAP, servicios web...)
  • Akonadiin perustuva sovellus sallii etsiä tietoa käytännössä mistä vain (kiintolevyltä, IMAPista, verkkopalveluista…)
  • -
  • O programa é compatíbel con Akonadi, e permítelle obter datos de practicamente calquera lugar (local, IMAP, servizos web).
  • +
  • O aplicativo é compatíbel con Akonadi, e permítelle obter datos de practicamente calquera lugar (local, IMAP, servizos web).
  • Applicazione abilitata da Akonadi, che permette di recuperare i dati virtualmente da qualsiasi posizione (locale, imap, servizi web...)
  • In Akonadi opgenomen toepassing waarmee de gegevens werkelijk overal vandaan kunt halen (lokaal, imap, webservice...)
  • Program wykorzystuje Akonadi, więc można pobierać dane praktycznie z każdego miejsca (lokalnie, imap, usługa sieciowa...)
  • diff --git a/src/zanshin/app/org.kde.zanshin.desktop b/src/zanshin/app/org.kde.zanshin.desktop --- a/src/zanshin/app/org.kde.zanshin.desktop +++ b/src/zanshin/app/org.kde.zanshin.desktop @@ -48,7 +48,7 @@ GenericName[fi]=Tehtävienhallintasovellus GenericName[fr]=Application de gestion de tâches à faire GenericName[ga]=Feidhmchlár Bainisteoireachta Tascanna -GenericName[gl]=Programa de xestión de tarefas +GenericName[gl]=Aplicativo de xestión de tarefas GenericName[hu]=Tennivaló kezelő alkalmazás GenericName[it]=Applicazione per la gestione delle COSE DA FARE GenericName[km]=កម្មវិធី​គ្រប់គ្រង​ការងារ​ត្រូវ​ធ្វើ diff --git a/src/zanshin/app/zanshinui.rc b/src/zanshin/app/zanshinui.rc --- a/src/zanshin/app/zanshinui.rc +++ b/src/zanshin/app/zanshinui.rc @@ -1,5 +1,5 @@ - + @@ -37,5 +37,7 @@ + + diff --git a/src/zanshin/kontact/part.cpp b/src/zanshin/kontact/part.cpp --- a/src/zanshin/kontact/part.cpp +++ b/src/zanshin/kontact/part.cpp @@ -34,9 +34,9 @@ #include "../app/aboutdata.h" #include "../app/dependencies.h" -#include "presentation/applicationmodel.h" +#include "presentation/taskapplicationmodel.h" -#include "widgets/applicationcomponents.h" +#include "widgets/taskapplicationcomponents.h" #include "widgets/availablepagesview.h" #include "widgets/availablesourcesview.h" #include "widgets/editorview.h" @@ -56,8 +56,8 @@ auto splitter = new QSplitter(parentWidget); auto sidebar = new QSplitter(Qt::Vertical, parentWidget); - auto components = new Widgets::ApplicationComponents(parentWidget); - components->setModel(Presentation::ApplicationModel::Ptr::create()); + auto components = new Widgets::TaskApplicationComponents(parentWidget); + components->setModel(Presentation::TaskApplicationModel::Ptr::create()); sidebar->addWidget(components->availablePagesView()); sidebar->addWidget(components->availableSourcesView()); diff --git a/tests/units/akonadi/akonadiserializertest.cpp b/tests/units/akonadi/akonadiserializertest.cpp --- a/tests/units/akonadi/akonadiserializertest.cpp +++ b/tests/units/akonadi/akonadiserializertest.cpp @@ -703,9 +703,11 @@ QTest::addColumn("updatedRelated"); QTest::addColumn("updatedDelegateName"); QTest::addColumn("updatedDelegateEmail"); + QTest::addColumn("updatedRunning"); - QTest::newRow("no change") << "summary" << "content" << false << QDateTime() << QDateTime(QDate(2013, 11, 24)) << QDateTime(QDate(2014, 03, 01)) << "my-uid" << "John Doe" << "j@d.com"; - QTest::newRow("changed") << "new summary" << "new content" << true << QDateTime(QDate(2013, 11, 28)) << QDateTime(QDate(2013, 11, 25)) << QDateTime(QDate(2014, 03, 02)) << "my-new-uid" << "John Smith" << "j@s.com"; + QTest::newRow("no change") << "summary" << "content" << false << QDateTime() << QDateTime(QDate(2013, 11, 24)) << QDateTime(QDate(2014, 03, 01)) << "my-uid" << "John Doe" << "j@d.com" << false; + QTest::newRow("changed") << "new summary" << "new content" << true << QDateTime(QDate(2013, 11, 28)) << QDateTime(QDate(2013, 11, 25)) << QDateTime(QDate(2014, 03, 02)) << "my-new-uid" << "John Smith" << "j@s.com" << false; + QTest::newRow("set_to_running") << "summary" << "content" << false << QDateTime() << QDateTime(QDate(2013, 11, 24)) << QDateTime(QDate(2014, 03, 01)) << "my-uid" << "John Doe" << "j@d.com" << true; } void shouldUpdateTaskFromItem() @@ -752,6 +754,7 @@ QFETCH(QString, updatedRelated); QFETCH(QString, updatedDelegateName); QFETCH(QString, updatedDelegateEmail); + QFETCH(bool, updatedRunning); // Switch to UTC updatedDoneDate.setTimeSpec(Qt::UTC); @@ -778,6 +781,11 @@ KCalCore::Attendee::Accepted)); updatedTodo->addAttendee(updatedAttendee); } + if (updatedRunning) { + updatedTodo->setCustomProperty("Zanshin", "Running", "1"); + } else { + updatedTodo->removeCustomProperty("Zanshin", "Running"); + } // ... as payload of a new item Akonadi::Item updatedItem; @@ -804,6 +812,7 @@ QCOMPARE(task->property("parentCollectionId").toLongLong(), updatedCollection.id()); QCOMPARE(task->delegate().name(), updatedDelegateName); QCOMPARE(task->delegate().email(), updatedDelegateEmail); + QCOMPARE(task->isRunning(), updatedRunning); task = artifact.dynamicCast(); QCOMPARE(task->title(), updatedSummary); @@ -818,6 +827,7 @@ QCOMPARE(task->property("parentCollectionId").toLongLong(), updatedCollection.id()); QCOMPARE(task->delegate().name(), updatedDelegateName); QCOMPARE(task->delegate().email(), updatedDelegateEmail); + QCOMPARE(task->isRunning(), updatedRunning); } void shouldNotUpdateTaskFromInvalidItem() @@ -958,36 +968,49 @@ QTest::addColumn("parentCollectionId"); QTest::addColumn("todoUid"); QTest::addColumn("delegate"); + QTest::addColumn("running"); QTest::newRow("nominal case (no id)") << "summary" << "content" << false << QDateTime() << QDateTime(QDate(2013, 11, 24)) << QDateTime(QDate(2014, 03, 01)) << qint64(-1) << qint64(-1) << QString() - << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")); + << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) + << false; QTest::newRow("done case (no id)") << "summary" << "content" << true << QDateTime(QDate(2013, 11, 30)) << QDateTime(QDate(2013, 11, 24)) << QDateTime(QDate(2014, 03, 01)) << qint64(-1) << qint64(-1) << QString() - << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")); + << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) + << false; QTest::newRow("empty case (no id)") << QString() << QString() << false << QDateTime() << QDateTime() << QDateTime() << qint64(-1) << qint64(-1) << QString() - << Domain::Task::Delegate(); + << Domain::Task::Delegate() + << false; QTest::newRow("nominal_with_time_info_noid") << "summary" << "content" << true << QDateTime(QDate(2015, 3, 1), QTime(1, 2, 3), Qt::UTC) << QDateTime(QDate(2013, 11, 24), QTime(0, 1, 2), Qt::UTC) << QDateTime(QDate(2016, 3, 1), QTime(4, 5, 6), Qt::UTC) << qint64(-1) << qint64(-1) << QString() - << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")); + << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) + << false; QTest::newRow("nominal case (with id)") << "summary" << "content" << false << QDateTime() << QDateTime(QDate(2013, 11, 24)) << QDateTime(QDate(2014, 03, 01)) << qint64(42) << qint64(43) << "my-uid" - << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")); + << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) + << false; QTest::newRow("done case (with id)") << "summary" << "content" << true << QDateTime(QDate(2013, 11, 30)) << QDateTime(QDate(2013, 11, 24)) << QDateTime(QDate(2014, 03, 01)) << qint64(42) << qint64(43) << "my-uid" - << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")); + << Domain::Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("j@d.com")) + << false; QTest::newRow("empty case (with id)") << QString() << QString() << false << QDateTime() << QDateTime() << QDateTime() << qint64(42) << qint64(43) << "my-uid" - << Domain::Task::Delegate(); + << Domain::Task::Delegate() + << false; + QTest::newRow("nominal case (running)") << "running" << QString() << false << QDateTime() + << QDateTime(QDate(2013, 11, 24)) << QDateTime(QDate(2014, 03, 01)) + << qint64(-1) << qint64(-1) << QString() + << Domain::Task::Delegate() + << true; } void shouldCreateItemFromTask() @@ -1005,6 +1028,7 @@ QFETCH(qint64, parentCollectionId); QFETCH(QString, todoUid); QFETCH(Domain::Task::Delegate, delegate); + QFETCH(bool, running); // Switch to UTC doneDate.setTimeSpec(Qt::UTC); @@ -1020,6 +1044,7 @@ task->setStartDate(startDate); task->setDueDate(dueDate); task->setDelegate(delegate); + task->setRunning(running); if (itemId > 0) task->setProperty("itemId", itemId); @@ -1073,6 +1098,7 @@ } QCOMPARE(todo->relatedTo(), QStringLiteral("parent-uid")); + QCOMPARE(todo->customProperty("Zanshin", "Running"), running ? QStringLiteral("1") : QString()); } void shouldVerifyIfAnItemIsATaskChild_data() 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 @@ -13,7 +13,9 @@ pagemodeltest projectpagemodeltest querytreemodeltest + runningtaskmodeltest tagpagemodeltest + taskapplicationmodeltest taskinboxpagemodeltest tasklistmodeltest contextpagemodeltest diff --git a/tests/units/presentation/runningtaskmodeltest.cpp b/tests/units/presentation/runningtaskmodeltest.cpp new file mode 100644 --- /dev/null +++ b/tests/units/presentation/runningtaskmodeltest.cpp @@ -0,0 +1,170 @@ +/* This file is part of Zanshin + + Copyright 2016-2017 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 "utils/mockobject.h" +#include "utils/jobhandler.h" + +#include "presentation/runningtaskmodel.h" + +#include "testhelpers.h" + +using namespace mockitopp; +using namespace mockitopp::matcher; + +class TestDependencies +{ +public: + TestDependencies() + { + m_taskProvider = Domain::QueryResultProvider::Ptr::create(); + auto taskResult = Domain::QueryResult::create(m_taskProvider); + + m_taskQueriesMock(&Domain::TaskQueries::findAll).when().thenReturn(taskResult); + m_taskQueriesMockInstance = m_taskQueriesMock.getInstance(); + + Utils::MockObject taskRepositoryMock; + taskRepositoryMock(&Domain::TaskRepository::update).when(any()) + .thenReturn(0); + m_taskRepositoryMockInstance = taskRepositoryMock.getInstance(); + } + Utils::MockObject m_taskQueriesMock; + + Domain::TaskQueries::Ptr m_taskQueriesMockInstance; + Domain::TaskRepository::Ptr m_taskRepositoryMockInstance; + Domain::QueryResultProvider::Ptr m_taskProvider; +}; + +class RunningTaskModelTest : public QObject +{ + Q_OBJECT +private slots: + void shouldDoInitialListing() + { + // GIVEN + TestDependencies deps; + // Three tasks, one being marked as running + auto firstTask = Domain::Task::Ptr::create(); + firstTask->setTitle(QStringLiteral("rootTask")); + auto initialTask = Domain::Task::Ptr::create(); + initialTask->setTitle(QStringLiteral("initialTask")); + initialTask->setRunning(true); + auto otherTask = Domain::Task::Ptr::create(); + otherTask->setTitle(QStringLiteral("otherTask")); + + // WHEN + Presentation::RunningTaskModel model(deps.m_taskQueriesMockInstance, deps.m_taskRepositoryMockInstance); + QVERIFY(!model.runningTask()); + deps.m_taskProvider->append(firstTask); + deps.m_taskProvider->append(initialTask); + deps.m_taskProvider->append(otherTask); + + // THEN + QCOMPARE(model.runningTask(), initialTask); + } + + void shouldStartTask() + { + // GIVEN + TestDependencies deps; + Presentation::RunningTaskModel model(deps.m_taskQueriesMockInstance, deps.m_taskRepositoryMockInstance); + Domain::Task::Ptr task = Domain::Task::Ptr::create(); + QSignalSpy spy(&model, &Presentation::RunningTaskModel::runningTaskChanged); + + // WHEN + model.setRunningTask(task); + + // THEN + QCOMPARE(model.runningTask(), task); + QVERIFY(task->isRunning()); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0).value(), task); + } + + void shouldHandleStopTask() + { + // GIVEN + TestDependencies deps; + Presentation::RunningTaskModel model(deps.m_taskQueriesMockInstance, deps.m_taskRepositoryMockInstance); + Domain::Task::Ptr task = Domain::Task::Ptr::create(); + model.setRunningTask(task); + QSignalSpy spy(&model, &Presentation::RunningTaskModel::runningTaskChanged); + + // WHEN + model.stopTask(); + + // THEN + QCOMPARE(model.runningTask(), Domain::Task::Ptr(nullptr)); + QVERIFY(!task->isRunning()); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0).value(), Domain::Task::Ptr(nullptr)); + } + + void shouldHandleDoneTask() + { + // GIVEN + TestDependencies deps; + Presentation::RunningTaskModel model(deps.m_taskQueriesMockInstance, deps.m_taskRepositoryMockInstance); + Domain::Task::Ptr task = Domain::Task::Ptr::create(); + model.setRunningTask(task); + QSignalSpy spy(&model, &Presentation::RunningTaskModel::runningTaskChanged); + + // WHEN + model.doneTask(); + + // THEN + QCOMPARE(model.runningTask(), Domain::Task::Ptr(nullptr)); + QVERIFY(!task->isRunning()); + QVERIFY(task->isDone()); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0).value(), Domain::Task::Ptr(nullptr)); + } + + void shouldHandleSwitchingToAnotherTask() + { + // GIVEN + TestDependencies deps; + Presentation::RunningTaskModel model(deps.m_taskQueriesMockInstance, deps.m_taskRepositoryMockInstance); + Domain::Task::Ptr task = Domain::Task::Ptr::create(); + model.setRunningTask(task); + Domain::Task::Ptr task2 = Domain::Task::Ptr::create(); + QSignalSpy spy(&model, &Presentation::RunningTaskModel::runningTaskChanged); + + // WHEN + model.setRunningTask(task2); + + // THEN + QCOMPARE(model.runningTask(), task2); + QVERIFY(!task->isRunning()); + QVERIFY(task2->isRunning()); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.at(0).at(0).value(), task2); + } + +private: +}; + +ZANSHIN_TEST_MAIN(RunningTaskModelTest) + +#include "runningtaskmodeltest.moc" diff --git a/tests/units/presentation/taskapplicationmodeltest.cpp b/tests/units/presentation/taskapplicationmodeltest.cpp new file mode 100644 --- /dev/null +++ b/tests/units/presentation/taskapplicationmodeltest.cpp @@ -0,0 +1,70 @@ +/* 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/taskapplicationmodel.h" +#include "presentation/runningtaskmodel.h" + +#include "testlib/fakejob.h" + +using namespace mockitopp; +using namespace mockitopp::matcher; + + +class TaskApplicationModelTest : public QObject +{ + Q_OBJECT +public: + explicit TaskApplicationModelTest(QObject *parent = Q_NULLPTR) + : QObject(parent) + { + Utils::DependencyManager::globalInstance().add( + [] (Utils::DependencyManager *) { + return new Presentation::RunningTaskModel(Domain::TaskQueries::Ptr(), + Domain::TaskRepository::Ptr()); + }); + } + +private slots: + void shouldProvideRunningTaskModel() + { + // GIVEN + Presentation::TaskApplicationModel app; + + // WHEN + QObject *model = app.runningTaskModel(); + + // THEN + QVERIFY(qobject_cast(model)); + } + +}; + +ZANSHIN_TEST_MAIN(TaskApplicationModelTest) + +#include "taskapplicationmodeltest.moc" diff --git a/tests/units/widgets/CMakeLists.txt b/tests/units/widgets/CMakeLists.txt --- a/tests/units/widgets/CMakeLists.txt +++ b/tests/units/widgets/CMakeLists.txt @@ -9,7 +9,9 @@ pageviewerrorhandlertest pageviewtest quickselectdialogtest + runningtaskwidgettest scripteditortest + taskapplicationcomponentstest ) # These tests need a window that takes focus diff --git a/tests/units/widgets/pageviewtest.cpp b/tests/units/widgets/pageviewtest.cpp --- a/tests/units/widgets/pageviewtest.cpp +++ b/tests/units/widgets/pageviewtest.cpp @@ -32,13 +32,15 @@ #include #include #include +#include #include #include "domain/task.h" #include "presentation/artifactfilterproxymodel.h" #include "presentation/metatypes.h" +#include "presentation/querytreemodelbase.h" #include "widgets/filterwidget.h" #include "widgets/itemdelegate.h" @@ -56,7 +58,7 @@ return &itemModel; } - void addStubItem(const QString &title, QStandardItem *parentItem = Q_NULLPTR) + QStandardItem *addStubItem(const QString &title, QStandardItem *parentItem = Q_NULLPTR) { QStandardItem *item = new QStandardItem; item->setData(title, Qt::DisplayRole); @@ -66,6 +68,16 @@ parentItem->appendRow(item); taskNames << title; + return item; + } + + Domain::Task::Ptr addTaskItem(const QString &title, QStandardItem *parentItem = Q_NULLPTR) + { + auto item = addStubItem(title, parentItem); + auto task = Domain::Task::Ptr::create(); + task->setTitle(title); + item->setData(QVariant::fromValue(task), Presentation::QueryTreeModelBase::ObjectRole); + return task; } void addStubItems(const QStringList &list) @@ -100,6 +112,19 @@ QStandardItemModel itemModel; }; +class RunningTaskModelStub : public Presentation::RunningTaskModelInterface +{ + Q_OBJECT +public: + Domain::Task::Ptr runningTask() const Q_DECL_OVERRIDE { return m_runningTask; } + void setRunningTask(const Domain::Task::Ptr &task) Q_DECL_OVERRIDE { m_runningTask = task; } +public slots: + void stopTask() Q_DECL_OVERRIDE {} + void doneTask() Q_DECL_OVERRIDE {} +private: + Domain::Task::Ptr m_runningTask; +}; + class PageViewTest : public QObject { Q_OBJECT @@ -153,12 +178,16 @@ QVERIFY(filterAction); QVERIFY(filterAction->isCheckable()); QVERIFY(!filterAction->isChecked()); + auto runTaskAction = page.findChild(QStringLiteral("runTaskAction")); + QVERIFY(runTaskAction); + QVERIFY(!runTaskAction->isEnabled()); auto actions = page.globalActions(); QCOMPARE(actions.value(QStringLiteral("page_view_add")), addAction); QCOMPARE(actions.value(QStringLiteral("page_view_remove")), removeAction); QCOMPARE(actions.value(QStringLiteral("page_view_promote")), promoteAction); QCOMPARE(actions.value(QStringLiteral("page_view_filter")), filterAction); + QCOMPARE(actions.value(QStringLiteral("page_run_task")), runTaskAction); } void shouldDisplayListFromPageModel() @@ -466,6 +495,7 @@ QTreeView *centralView = page.findChild(QStringLiteral("centralView")); centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); + QVERIFY(centralView->selectionModel()->currentIndex().isValid()); centralView->setFocus(); // Needed for shortcuts to work @@ -671,6 +701,44 @@ QVERIFY(!messageWidget->isShowAnimationRunning()); QVERIFY(!messageWidget->isHideAnimationRunning()); } + + void shouldRunTask() + { + // GIVEN + PageModelStub stubPageModel; + Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); + auto task1 = stubPageModel.addTaskItem(QStringLiteral("Task1")); + auto task2 = stubPageModel.addTaskItem(QStringLiteral("Task2")); + Widgets::PageView page; + page.setModel(&stubPageModel); + RunningTaskModelStub stubRunningTaskModel; + page.setRunningTaskModel(&stubRunningTaskModel); + auto centralView = page.findChild(QStringLiteral("centralView")); + + QModelIndex index = stubPageModel.itemModel.index(0, 0); + centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); + QVERIFY(centralView->selectionModel()->currentIndex().isValid()); + + auto runTaskAction = page.findChild(QStringLiteral("runTaskAction")); + QVERIFY(runTaskAction); + QVERIFY(runTaskAction->isEnabled()); + + // WHEN starting the first task + runTaskAction->trigger(); + + // THEN + QCOMPARE(stubRunningTaskModel.property("runningTask").value(), task1); + QCOMPARE(task1->startDate().date(), QDate::currentDate()); + + // WHEN starting the second task + QModelIndex index2 = stubPageModel.itemModel.index(1, 0); + centralView->selectionModel()->setCurrentIndex(index2, QItemSelectionModel::ClearAndSelect); + runTaskAction->trigger(); + + // THEN + QCOMPARE(stubRunningTaskModel.property("runningTask").value(), task2); + QCOMPARE(task2->startDate().date(), QDate::currentDate()); + } }; ZANSHIN_TEST_MAIN(PageViewTest) diff --git a/tests/units/widgets/runningtaskwidgettest.cpp b/tests/units/widgets/runningtaskwidgettest.cpp new file mode 100644 --- /dev/null +++ b/tests/units/widgets/runningtaskwidgettest.cpp @@ -0,0 +1,175 @@ +/* This file is part of Zanshin + + Copyright 2016-2017 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 "widgets/runningtaskwidget.h" +#include "presentation/runningtaskmodelinterface.h" +#include + +class RunningTaskModelStub : public Presentation::RunningTaskModelInterface +{ + Q_OBJECT +public: + Domain::Task::Ptr runningTask() const Q_DECL_OVERRIDE { return m_runningTask; } + void setRunningTask(const Domain::Task::Ptr &runningTask) Q_DECL_OVERRIDE + { + m_runningTask = runningTask; + emit runningTaskChanged(m_runningTask); + } + +public slots: + void stopTask() Q_DECL_OVERRIDE + { + Q_ASSERT(m_runningTask); + setRunningTask(nullptr); + } + + void doneTask() Q_DECL_OVERRIDE + { + Q_ASSERT(m_runningTask); + m_runningTask->setDone(true); + stopTask(); + } + +private: + Domain::Task::Ptr m_runningTask; +}; + +class RunningTaskWidgetTest : public QObject +{ + Q_OBJECT +private slots: + void shouldHaveDefaultState() + { + Widgets::RunningTaskWidget widget; + QVERIFY(widget.isHidden()); + } + + void shouldShowWhenRunningATask() + { + // GIVEN + Widgets::RunningTaskWidget widget; + auto task = Domain::Task::Ptr::create(); + RunningTaskModelStub model; + widget.setModel(&model); + + // WHEN + model.setRunningTask(task); + + // THEN + QVERIFY(!widget.isHidden()); + } + + void shouldShowWhenRunningADifferentTask() + { + // GIVEN + Widgets::RunningTaskWidget widget; + auto task1 = Domain::Task::Ptr::create(); + auto task2 = Domain::Task::Ptr::create(); + RunningTaskModelStub model; + widget.setModel(&model); + model.setRunningTask(task1); + + // WHEN + model.setRunningTask(task2); + + // THEN + QVERIFY(!widget.isHidden()); + } + + void shouldStopAndHideOnClickingStop() + { + // GIVEN + Widgets::RunningTaskWidget widget; + auto task = Domain::Task::Ptr::create(); + RunningTaskModelStub model; + widget.setModel(&model); + model.setRunningTask(task); + auto button = widget.findChild("stopButton"); + QVERIFY(button); + + // WHEN + button->click(); + + // THEN stopTask should have been called + QCOMPARE(model.runningTask(), Domain::Task::Ptr(nullptr)); + QVERIFY(widget.isHidden()); + } + + void shouldMarkAsDoneAndHideOnClickingDone() + { + // GIVEN + Widgets::RunningTaskWidget widget; + auto task = Domain::Task::Ptr::create(); + RunningTaskModelStub model; + widget.setModel(&model); + model.setRunningTask(task); + QVERIFY(!task->isDone()); + auto button = widget.findChild("doneButton"); + QVERIFY(button); + + // WHEN + button->click(); + + // THEN doneTask should have been called + QVERIFY(task->isDone()); + QVERIFY(widget.isHidden()); + } + + void shouldHideOnExternalStop() + { + // GIVEN + Widgets::RunningTaskWidget widget; + auto task = Domain::Task::Ptr::create(); + RunningTaskModelStub model; + widget.setModel(&model); + model.setRunningTask(task); + + // WHEN + model.stopTask(); + + // THEN + QVERIFY(widget.isHidden()); + } + + void shouldHideOnExternalDone() + { + // GIVEN + Widgets::RunningTaskWidget widget; + auto task = Domain::Task::Ptr::create(); + RunningTaskModelStub model; + widget.setModel(&model); + model.setRunningTask(task); + + // WHEN + model.doneTask(); + + // THEN + QVERIFY(widget.isHidden()); + } +}; + +ZANSHIN_TEST_MAIN(RunningTaskWidgetTest) + +#include "runningtaskwidgettest.moc" diff --git a/tests/units/widgets/taskapplicationcomponentstest.cpp b/tests/units/widgets/taskapplicationcomponentstest.cpp new file mode 100644 --- /dev/null +++ b/tests/units/widgets/taskapplicationcomponentstest.cpp @@ -0,0 +1,89 @@ +/* This file is part of Zanshin + + Copyright 2017 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 "widgets/pageview.h" +#include "domain/task.h" + +#include "widgets/taskapplicationcomponents.h" +#include "widgets/runningtaskwidget.h" +#include "presentation/runningtaskmodelinterface.h" + +class RunningTaskModelStub : public Presentation::RunningTaskModelInterface +{ + Q_OBJECT +public: + Domain::Task::Ptr runningTask() const Q_DECL_OVERRIDE { return {}; } + void setRunningTask(const Domain::Task::Ptr &) Q_DECL_OVERRIDE {} +public slots: + void stopTask() Q_DECL_OVERRIDE {} + void doneTask() Q_DECL_OVERRIDE {} +}; + +class TaskApplicationComponentsTest : public QObject +{ + Q_OBJECT +public: + explicit TaskApplicationComponentsTest(QObject *parent = Q_NULLPTR) + : QObject(parent) + { + } + +private slots: + void shouldApplyRunningTaskModelToPageView() + { + // GIVEN + Widgets::TaskApplicationComponents components; + auto appModelStub = QObjectPtr::create(); + RunningTaskModelStub runningTaskModelStub; + appModelStub->setProperty("runningTaskModel", QVariant::fromValue(&runningTaskModelStub)); + + // WHEN + components.setModel(appModelStub); + auto pageView = components.pageView(); + + // THEN + QCOMPARE(pageView->runningTaskModel(), &runningTaskModelStub); + } + + void shouldApplyRunningTaskModelToRunningTaskWidget() + { + // GIVEN + Widgets::TaskApplicationComponents components; + auto appModelStub = QObjectPtr::create(); + RunningTaskModelStub runningTaskModelStub; + appModelStub->setProperty("runningTaskModel", QVariant::fromValue(&runningTaskModelStub)); + + // WHEN + components.setModel(appModelStub); + auto runningTaskWidget = components.runningTaskWidget(); + + // THEN + QCOMPARE(runningTaskWidget->model(), &runningTaskModelStub); + } +}; + +ZANSHIN_TEST_MAIN(TaskApplicationComponentsTest) + +#include "taskapplicationcomponentstest.moc"