diff --git a/src/domain/task.cpp b/src/domain/task.cpp index 8d104ca4..f98579ea 100644 --- a/src/domain/task.cpp +++ b/src/domain/task.cpp @@ -1,318 +1,333 @@ /* 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 "task.h" #include "utils/datetime.h" using namespace Domain; Task::Task(QObject *parent) : Artifact(parent), m_running(false), - m_done(false) + m_done(false), + m_recurrence(NoRecurrence) { } Task::~Task() { } bool Task::isRunning() const { return m_running; } bool Task::isDone() const { return m_done; } void Task::setDone(bool done) { if (m_done == done) return; const QDateTime doneDate = done ? Utils::DateTime::currentDateTime() : QDateTime(); m_done = done; m_doneDate = doneDate; emit doneChanged(done); emit doneDateChanged(doneDate); } void Task::setDoneDate(const QDateTime &doneDate) { if (m_doneDate == doneDate) return; m_doneDate = doneDate; emit doneDateChanged(doneDate); } QDateTime Task::startDate() const { return m_startDate; } void Task::setStartDate(const QDateTime &startDate) { if (m_startDate == startDate) return; m_startDate = startDate; emit startDateChanged(startDate); } QDateTime Task::dueDate() const { return m_dueDate; } QDateTime Task::doneDate() const { return m_doneDate; } +Task::Recurrence Task::recurrence() const +{ + return m_recurrence; +} + Task::Attachments Task::attachments() const { return m_attachments; } Task::Delegate Task::delegate() const { 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) return; m_dueDate = dueDate; emit dueDateChanged(dueDate); } +void Task::setRecurrence(Task::Recurrence recurrence) +{ + if (m_recurrence == recurrence) + return; + + m_recurrence = recurrence; + emit recurrenceChanged(recurrence); +} + void Task::setAttachments(const Task::Attachments &attachments) { if (m_attachments == attachments) return; m_attachments = attachments; emit attachmentsChanged(attachments); } void Task::setDelegate(const Task::Delegate &delegate) { if (m_delegate == delegate) return; m_delegate = delegate; emit delegateChanged(delegate); } Task::Attachment::Attachment() { } Task::Attachment::Attachment(const QByteArray &data) { setData(data); } Task::Attachment::Attachment(const QUrl &uri) { setUri(uri); } Task::Attachment::Attachment(const Task::Attachment &other) : m_uri(other.m_uri), m_data(other.m_data), m_label(other.m_label), m_mimeType(other.m_mimeType), m_iconName(other.m_iconName) { } Task::Attachment::~Attachment() { } Task::Attachment &Task::Attachment::operator=(const Task::Attachment &other) { Attachment copy(other); std::swap(m_uri, copy.m_uri); std::swap(m_data, copy.m_data); std::swap(m_label, copy.m_label); std::swap(m_mimeType, copy.m_mimeType); std::swap(m_iconName, copy.m_iconName); return *this; } bool Task::Attachment::operator==(const Task::Attachment &other) const { return m_uri == other.m_uri && m_data == other.m_data && m_label == other.m_label && m_mimeType == other.m_mimeType && m_iconName == other.m_iconName; } bool Task::Attachment::isValid() const { return m_uri.isValid() || !m_data.isEmpty(); } bool Task::Attachment::isUri() const { return m_uri.isValid(); } QUrl Task::Attachment::uri() const { return m_uri; } void Task::Attachment::setUri(const QUrl &uri) { m_uri = uri; m_data.clear(); } QByteArray Task::Attachment::data() const { return m_data; } void Task::Attachment::setData(const QByteArray &data) { m_data = data; m_uri.clear(); } QString Task::Attachment::label() const { return m_label; } void Task::Attachment::setLabel(const QString &label) { m_label = label; } QString Task::Attachment::mimeType() const { return m_mimeType; } void Task::Attachment::setMimeType(const QString &mimeType) { m_mimeType = mimeType; } QString Task::Attachment::iconName() const { return m_iconName; } void Task::Attachment::setIconName(const QString &iconName) { m_iconName = iconName; } Task::Delegate::Delegate() { } Task::Delegate::Delegate(const QString &name, const QString &email) : m_name(name), m_email(email) { } Task::Delegate::Delegate(const Task::Delegate &other) : m_name(other.m_name), m_email(other.m_email) { } Task::Delegate::~Delegate() { } Task::Delegate &Task::Delegate::operator=(const Task::Delegate &other) { Delegate copy(other); std::swap(m_name, copy.m_name); std::swap(m_email, copy.m_email); return *this; } bool Task::Delegate::operator==(const Task::Delegate &other) const { return m_name == other.m_name && m_email == other.m_email; } bool Task::Delegate::isValid() const { return !m_email.isEmpty(); } QString Task::Delegate::display() const { return !isValid() ? QString() : !m_name.isEmpty() ? m_name : m_email; } QString Task::Delegate::name() const { return m_name; } void Task::Delegate::setName(const QString &name) { m_name = name; } QString Task::Delegate::email() const { return m_email; } void Task::Delegate::setEmail(const QString &email) { m_email = email; } diff --git a/src/domain/task.h b/src/domain/task.h index 5ce88731..04e78008 100644 --- a/src/domain/task.h +++ b/src/domain/task.h @@ -1,159 +1,172 @@ /* This file is part of Zanshin Copyright 2014 Kevin Ottens This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License or (at your option) version 3 or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 14 of version 3 of the license. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef DOMAIN_TASK_H #define DOMAIN_TASK_H #include "artifact.h" #include #include namespace Domain { 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) + Q_PROPERTY(Domain::Task::Recurrence recurrence READ recurrence WRITE setRecurrence NOTIFY recurrenceChanged) Q_PROPERTY(Domain::Task::Delegate delegate READ delegate WRITE setDelegate NOTIFY delegateChanged) Q_PROPERTY(Domain::Task::Attachments attachements READ attachments WRITE setAttachments NOTIFY attachmentsChanged) public: typedef QSharedPointer Ptr; typedef QList List; + enum Recurrence { + NoRecurrence = 0, + RecursDaily, + RecursWeekly, + RecursMonthly // for now only monthly on the same day (say 11th day of the month) + }; + Q_ENUM(Recurrence) + class Attachment { public: Attachment(); explicit Attachment(const QByteArray &data); explicit Attachment(const QUrl &uri); Attachment(const Attachment &other); ~Attachment(); Attachment &operator=(const Attachment &other); bool operator==(const Attachment &other) const; bool isValid() const; bool isUri() const; QUrl uri() const; void setUri(const QUrl &uri); QByteArray data() const; void setData(const QByteArray &data); QString label() const; void setLabel(const QString &label); QString mimeType() const; void setMimeType(const QString &mimeType); QString iconName() const; void setIconName(const QString &iconName); private: QUrl m_uri; QByteArray m_data; QString m_label; QString m_mimeType; QString m_iconName; }; typedef QList Attachments; class Delegate { public: Delegate(); Delegate(const QString &name, const QString &email); Delegate(const Delegate &other); ~Delegate(); Delegate &operator=(const Delegate &other); bool operator==(const Delegate &other) const; bool isValid() const; QString display() const; QString name() const; void setName(const QString &name); QString email() const; void setEmail(const QString &email); private: QString m_name; QString m_email; }; explicit Task(QObject *parent = Q_NULLPTR); virtual ~Task(); bool isRunning() const; bool isDone() const; QDateTime startDate() const; QDateTime dueDate() const; QDateTime doneDate() const; + Recurrence recurrence() const; Attachments attachments() 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 setRecurrence(Domain::Task::Recurrence recurrence); void setAttachments(const Domain::Task::Attachments &attachments); 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 recurrenceChanged(Domain::Task::Recurrence recurrence); void attachmentsChanged(const Domain::Task::Attachments &attachments); void delegateChanged(const Domain::Task::Delegate &delegate); private: bool m_running; bool m_done; QDateTime m_startDate; QDateTime m_dueDate; QDateTime m_doneDate; + Recurrence m_recurrence; Attachments m_attachments; Delegate m_delegate; }; } Q_DECLARE_METATYPE(Domain::Task::Ptr) Q_DECLARE_METATYPE(Domain::Task::List) Q_DECLARE_METATYPE(Domain::Task::Attachment) Q_DECLARE_METATYPE(Domain::Task::Attachments) Q_DECLARE_METATYPE(Domain::Task::Delegate) #endif // DOMAIN_TASK_H diff --git a/tests/units/domain/tasktest.cpp b/tests/units/domain/tasktest.cpp index d57ed25a..58380558 100644 --- a/tests/units/domain/tasktest.cpp +++ b/tests/units/domain/tasktest.cpp @@ -1,299 +1,319 @@ /* 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 "domain/task.h" #include "utils/datetime.h" using namespace Domain; class TaskTest : public QObject { Q_OBJECT public: explicit TaskTest(QObject *parent = Q_NULLPTR) : QObject(parent) { + qRegisterMetaType(); qRegisterMetaType(); qRegisterMetaType(); } private slots: void shouldHaveEmptyPropertiesByDefault() { Task t; QCOMPARE(t.text(), QString()); QCOMPARE(t.title(), QString()); QCOMPARE(t.isDone(), false); QCOMPARE(t.startDate(), QDateTime()); QCOMPARE(t.dueDate(), QDateTime()); QCOMPARE(t.doneDate(), QDateTime()); + QCOMPARE(t.recurrence(), Domain::Task::NoRecurrence); QVERIFY(t.attachments().isEmpty()); QVERIFY(!t.delegate().isValid()); } void shouldHaveValueBasedAttachment() { Task::Attachment a; QVERIFY(!a.isValid()); QVERIFY(!a.isUri()); QCOMPARE(a.uri(), QUrl()); QCOMPARE(a.data(), QByteArray()); QCOMPARE(a.label(), QString()); QCOMPARE(a.mimeType(), QString()); QCOMPARE(a.iconName(), QString()); a.setUri(QUrl("https://www.kde.org")); QVERIFY(a.isValid()); QVERIFY(a.isUri()); QCOMPARE(a.uri(), QUrl("https://www.kde.org")); QCOMPARE(a.data(), QByteArray()); QCOMPARE(a.label(), QString()); QCOMPARE(a.mimeType(), QString()); QCOMPARE(a.iconName(), QString()); a.setData(QByteArrayLiteral("foobar")); QVERIFY(a.isValid()); QVERIFY(!a.isUri()); QCOMPARE(a.uri(), QUrl()); QCOMPARE(a.data(), QByteArrayLiteral("foobar")); QCOMPARE(a.label(), QString()); QCOMPARE(a.mimeType(), QString()); QCOMPARE(a.iconName(), QString()); a.setLabel(QStringLiteral("baz")); QVERIFY(a.isValid()); QVERIFY(!a.isUri()); QCOMPARE(a.uri(), QUrl()); QCOMPARE(a.data(), QByteArrayLiteral("foobar")); QCOMPARE(a.label(), QStringLiteral("baz")); QCOMPARE(a.mimeType(), QString()); QCOMPARE(a.iconName(), QString()); a.setMimeType(QStringLiteral("text/plain")); QVERIFY(a.isValid()); QVERIFY(!a.isUri()); QCOMPARE(a.uri(), QUrl()); QCOMPARE(a.data(), QByteArrayLiteral("foobar")); QCOMPARE(a.label(), QStringLiteral("baz")); QCOMPARE(a.mimeType(), QStringLiteral("text/plain")); QCOMPARE(a.iconName(), QString()); a.setIconName(QStringLiteral("text")); QVERIFY(a.isValid()); QVERIFY(!a.isUri()); QCOMPARE(a.uri(), QUrl()); QCOMPARE(a.data(), QByteArrayLiteral("foobar")); QCOMPARE(a.label(), QStringLiteral("baz")); QCOMPARE(a.mimeType(), QStringLiteral("text/plain")); QCOMPARE(a.iconName(), QStringLiteral("text")); a.setUri(QUrl("https://www.kde.org")); QVERIFY(a.isValid()); QVERIFY(a.isUri()); QCOMPARE(a.uri(), QUrl("https://www.kde.org")); QCOMPARE(a.data(), QByteArray()); QCOMPARE(a.label(), QStringLiteral("baz")); QCOMPARE(a.mimeType(), QStringLiteral("text/plain")); QCOMPARE(a.iconName(), QStringLiteral("text")); a.setUri(QUrl()); QVERIFY(!a.isValid()); QVERIFY(!a.isUri()); QCOMPARE(a.uri(), QUrl()); QCOMPARE(a.data(), QByteArray()); QCOMPARE(a.label(), QStringLiteral("baz")); QCOMPARE(a.mimeType(), QStringLiteral("text/plain")); QCOMPARE(a.iconName(), QStringLiteral("text")); } void shouldHaveValueBasedDelegate() { Task::Delegate d; QVERIFY(!d.isValid()); QCOMPARE(d.name(), QString()); QCOMPARE(d.email(), QString()); QCOMPARE(d.display(), QString()); d.setName(QStringLiteral("John Doe")); QVERIFY(!d.isValid()); QCOMPARE(d.name(), QStringLiteral("John Doe")); QCOMPARE(d.email(), QString()); QCOMPARE(d.display(), QString()); d.setEmail(QStringLiteral("doe@somewhere.com")); QVERIFY(d.isValid()); QCOMPARE(d.name(), QStringLiteral("John Doe")); QCOMPARE(d.email(), QStringLiteral("doe@somewhere.com")); QCOMPARE(d.display(), QStringLiteral("John Doe")); d.setName(QString()); QVERIFY(d.isValid()); QCOMPARE(d.name(), QString()); QCOMPARE(d.email(), QStringLiteral("doe@somewhere.com")); QCOMPARE(d.display(), QStringLiteral("doe@somewhere.com")); } void shouldNotifyStatusChanges() { Task t; QSignalSpy spy(&t, &Task::doneChanged); t.setDone(true); QCOMPARE(spy.count(), 1); QCOMPARE(spy.first().first().toBool(), true); } void shouldNotNotifyIdenticalStatusChanges() { Task t; t.setDone(true); QSignalSpy spy(&t, &Task::doneChanged); t.setDone(true); QCOMPARE(spy.count(), 0); } void shouldNotifyStartDateChanges() { Task t; QSignalSpy spy(&t, &Task::startDateChanged); t.setStartDate(QDateTime(QDate(2014, 1, 13))); QCOMPARE(spy.count(), 1); QCOMPARE(spy.first().first().toDateTime(), QDateTime(QDate(2014, 1, 13))); } void shouldNotNotifyIdenticalStartDateChanges() { Task t; t.setStartDate(QDateTime(QDate(2014, 1, 13))); QSignalSpy spy(&t, &Task::startDateChanged); t.setStartDate(QDateTime(QDate(2014, 1, 13))); QCOMPARE(spy.count(), 0); } void shouldNotifyDueDateChanges() { Task t; QSignalSpy spy(&t, &Task::dueDateChanged); t.setDueDate(QDateTime(QDate(2014, 1, 13))); QCOMPARE(spy.count(), 1); QCOMPARE(spy.first().first().toDateTime(), QDateTime(QDate(2014, 1, 13))); } void shouldNotNotifyIdenticalDueDateChanges() { Task t; t.setDueDate(QDateTime(QDate(2014, 1, 13))); QSignalSpy spy(&t, &Task::dueDateChanged); t.setDueDate(QDateTime(QDate(2014, 1, 13))); QCOMPARE(spy.count(), 0); } + void shouldNotifyRecurrenceChanges() + { + Task t; + QSignalSpy spy(&t, &Task::recurrenceChanged); + t.setRecurrence(Task::RecursWeekly); + QCOMPARE(spy.count(), 1); + QCOMPARE(spy.first().first().value(), Task::RecursWeekly); + } + + void shouldNotNotifyIdenticalRecurrenceChanges() + { + Task t; + t.setRecurrence(Task::RecursWeekly); + QSignalSpy spy(&t, &Task::recurrenceChanged); + t.setRecurrence(Task::RecursWeekly); + QCOMPARE(spy.count(), 0); + } + void shouldNotifyAttachmentsChanges() { Task::Attachments attachments; attachments.append(Task::Attachment(QByteArrayLiteral("foobar"))); attachments.append(Task::Attachment(QUrl("https://www.kde.org"))); Task t; QSignalSpy spy(&t, &Task::attachmentsChanged); t.setAttachments(attachments); QCOMPARE(spy.count(), 1); QCOMPARE(spy.first().first().value(), attachments); } void shouldNotNotifyIdenticalAttachmentsChanges() { Task::Attachments attachments; attachments.append(Task::Attachment(QByteArrayLiteral("foobar"))); attachments.append(Task::Attachment(QUrl("https://www.kde.org"))); Task t; t.setAttachments(attachments); QSignalSpy spy(&t, &Task::attachmentsChanged); t.setAttachments(attachments); QCOMPARE(spy.count(), 0); } void shouldNotifyDelegateChanges() { Task t; QSignalSpy spy(&t, &Task::delegateChanged); t.setDelegate(Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("doe@somewhere.com"))); QCOMPARE(spy.count(), 1); QCOMPARE(spy.first().first().value(), Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("doe@somewhere.com"))); } void shouldNotNotifyIdenticalDelegateChanges() { Task t; t.setDelegate(Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("doe@somewhere.com"))); QSignalSpy spy(&t, &Task::delegateChanged); t.setDelegate(Task::Delegate(QStringLiteral("John Doe"), QStringLiteral("doe@somewhere.com"))); QCOMPARE(spy.count(), 0); } void shouldNotifyDoneDateChanges() { Task t; QSignalSpy spy(&t, &Task::doneDateChanged); t.setDoneDate(QDateTime(QDate(2014, 1, 13))); QCOMPARE(spy.count(), 1); QCOMPARE(spy.first().first().toDateTime(), QDateTime(QDate(2014, 1, 13))); } void shouldNotNotifyIdenticalDoneDateChanges() { Task t; t.setDoneDate(QDateTime(QDate(2014, 1, 13))); QSignalSpy spy(&t, &Task::doneDateChanged); t.setDoneDate(QDateTime(QDate(2014, 1, 13))); QCOMPARE(spy.count(), 0); } void shouldNotifyDoneDateSet() { Task t; QSignalSpy spy(&t, &Task::doneDateChanged); t.setDone(true); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toDateTime().date(), Utils::DateTime::currentDateTime().date()); } void shouldNotifyDoneDateUnset() { Task t; t.setDone(true); QSignalSpy spy(&t, &Task::doneDateChanged); t.setDone(false); QCOMPARE(spy.count(), 1); QCOMPARE(spy.takeFirst().at(0).toDateTime(), QDateTime()); } }; ZANSHIN_TEST_MAIN(TaskTest) #include "tasktest.moc"