diff --git a/src/widgets/editorview.cpp b/src/widgets/editorview.cpp index 0ed001e8..6c308bab 100644 --- a/src/widgets/editorview.cpp +++ b/src/widgets/editorview.cpp @@ -1,276 +1,280 @@ /* 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 "editorview.h" #include #include #include #include #include #include #include "kdateedit.h" #include "addressline/addresseelineedit.h" #include "domain/artifact.h" #include "ui_editorview.h" using namespace Widgets; EditorView::EditorView(QWidget *parent) : QWidget(parent), m_model(Q_NULLPTR), ui(new Ui::EditorView), m_delegateEdit(Q_NULLPTR) { ui->setupUi(this); // To avoid having unit tests talking to akonadi // while we don't need the completion for them if (qEnvironmentVariableIsEmpty("ZANSHIN_UNIT_TEST_RUN")) m_delegateEdit = new KPIM::AddresseeLineEdit(ui->delegateEditPlaceHolder); else m_delegateEdit = new KLineEdit(ui->delegateEditPlaceHolder); // placing our special DelegateEdit into the placeholder we prepared m_delegateEdit->setObjectName("delegateEdit"); ui->delegateToLabel->setBuddy(m_delegateEdit); ui->delegateEditPlaceHolder->layout()->addWidget(m_delegateEdit); ui->startDateEdit->setMinimumContentsLength(10); ui->dueDateEdit->setMinimumContentsLength(10); // Make sure our minimum width is always the one with // the task group visible ui->layout->activate(); setMinimumWidth(minimumSizeHint().width()); ui->delegateLabel->setVisible(false); ui->taskGroup->setVisible(false); ui->textEdit->installEventFilter(this); ui->startDateEdit->installEventFilter(this); ui->dueDateEdit->installEventFilter(this); ui->doneButton->installEventFilter(this); m_delegateEdit->installEventFilter(this); connect(ui->textEdit, &QPlainTextEdit::textChanged, this, &EditorView::onTextEditChanged); connect(ui->startDateEdit, &KPIM::KDateEdit::dateEntered, this, &EditorView::onStartEditEntered); connect(ui->dueDateEdit, &KPIM::KDateEdit::dateEntered, this, &EditorView::onDueEditEntered); connect(ui->doneButton, &QAbstractButton::toggled, this, &EditorView::onDoneButtonChanged); connect(ui->startTodayButton, &QAbstractButton::clicked, this, &EditorView::onStartTodayClicked); connect(m_delegateEdit, &KLineEdit::returnPressed, this, &EditorView::onDelegateEntered); setEnabled(false); } EditorView::~EditorView() { delete ui; } QObject *EditorView::model() const { return m_model; } void EditorView::setModel(QObject *model) { if (model == m_model) return; if (m_model) { + ui->attachmentList->setModel(Q_NULLPTR); disconnect(m_model, Q_NULLPTR, this, Q_NULLPTR); disconnect(this, Q_NULLPTR, m_model, Q_NULLPTR); } m_model = model; setEnabled(m_model); if (!m_model) { ui->taskGroup->setVisible(false); ui->textEdit->clear(); return; } + auto attachments = m_model->property("attachmentModel").value(); + ui->attachmentList->setModel(attachments); + onArtifactChanged(); onTextOrTitleChanged(); onHasTaskPropertiesChanged(); onStartDateChanged(); onDueDateChanged(); onDoneChanged(); onDelegateTextChanged(); connect(m_model, SIGNAL(artifactChanged(Domain::Artifact::Ptr)), this, SLOT(onArtifactChanged())); connect(m_model, SIGNAL(hasTaskPropertiesChanged(bool)), this, SLOT(onHasTaskPropertiesChanged())); connect(m_model, SIGNAL(titleChanged(QString)), this, SLOT(onTextOrTitleChanged())); connect(m_model, SIGNAL(textChanged(QString)), this, SLOT(onTextOrTitleChanged())); connect(m_model, SIGNAL(startDateChanged(QDateTime)), this, SLOT(onStartDateChanged())); connect(m_model, SIGNAL(dueDateChanged(QDateTime)), this, SLOT(onDueDateChanged())); connect(m_model, SIGNAL(doneChanged(bool)), this, SLOT(onDoneChanged())); connect(m_model, SIGNAL(delegateTextChanged(QString)), this, SLOT(onDelegateTextChanged())); connect(this, SIGNAL(titleChanged(QString)), m_model, SLOT(setTitle(QString))); connect(this, SIGNAL(textChanged(QString)), m_model, SLOT(setText(QString))); connect(this, SIGNAL(startDateChanged(QDateTime)), m_model, SLOT(setStartDate(QDateTime))); connect(this, SIGNAL(dueDateChanged(QDateTime)), m_model, SLOT(setDueDate(QDateTime))); connect(this, SIGNAL(doneChanged(bool)), m_model, SLOT(setDone(bool))); } bool EditorView::eventFilter(QObject *watched, QEvent *event) { Q_UNUSED(watched); switch (event->type()) { case QEvent::FocusIn: // We don't want to replace text being edited by the user with older text // coming from akonadi notifications (async, after some older save job) m_model->setProperty("editingInProgress", true); break; case QEvent::FocusOut: // We do react to notifications, however, when not having the focus, // for instance when changing the title using the central list. m_model->setProperty("editingInProgress", false); break; default: break; } return false; } void EditorView::onArtifactChanged() { auto artifact = m_model->property("artifact").value(); setEnabled(artifact); m_delegateEdit->clear(); } void EditorView::onHasTaskPropertiesChanged() { ui->taskGroup->setVisible(m_model->property("hasTaskProperties").toBool()); } void EditorView::onTextOrTitleChanged() { const auto title = m_model->property("title").toString(); const auto text = m_model->property("text").toString(); const auto fullText = QString(title + '\n' + text); if (ui->textEdit->toPlainText() != fullText) // QPlainTextEdit doesn't do this check ui->textEdit->setPlainText(fullText); } void EditorView::onStartDateChanged() { ui->startDateEdit->setDate(m_model->property("startDate").toDateTime().date()); } void EditorView::onDueDateChanged() { ui->dueDateEdit->setDate(m_model->property("dueDate").toDateTime().date()); } void EditorView::onDoneChanged() { ui->doneButton->setChecked(m_model->property("done").toBool()); } void EditorView::onDelegateTextChanged() { const auto delegateText = m_model->property("delegateText").toString(); const auto labelText = delegateText.isEmpty() ? QString() : i18n("Delegated to: %1", delegateText); ui->delegateLabel->setVisible(!labelText.isEmpty()); ui->delegateLabel->setText(labelText); } void EditorView::onTextEditChanged() { const QString plainText = ui->textEdit->toPlainText(); const int index = plainText.indexOf('\n'); if (index < 0) { emit titleChanged(plainText); emit textChanged(QString()); } else { const QString title = plainText.left(index); const QString text = plainText.mid(index + 1); emit titleChanged(title); emit textChanged(text); } } void EditorView::onStartEditEntered(const QDate &start) { emit startDateChanged(QDateTime(start, QTime(), Qt::UTC)); } void EditorView::onDueEditEntered(const QDate &due) { emit dueDateChanged(QDateTime(due, QTime(), Qt::UTC)); } void EditorView::onDoneButtonChanged(bool checked) { emit doneChanged(checked); } void EditorView::onStartTodayClicked() { QDate today(QDate::currentDate()); ui->startDateEdit->setDate(today); emit startDateChanged(QDateTime(today, QTime(), Qt::UTC)); } void EditorView::onDelegateEntered() { const auto input = m_delegateEdit->text(); auto name = QString(); auto email = QString(); auto gotMatch = false; QRegExp fullRx("\\s*(.*) <([\\w\\.]+@[\\w\\.]+)>\\s*"); QRegExp emailOnlyRx("\\s*?\\s*"); if (input.contains(fullRx)) { name = fullRx.cap(1); email = fullRx.cap(2); gotMatch = true; } else if (input.contains(emailOnlyRx)) { email = emailOnlyRx.cap(1); gotMatch = true; } if (gotMatch) { QMetaObject::invokeMethod(m_model, "delegate", Q_ARG(QString, name), Q_ARG(QString, email)); m_delegateEdit->clear(); } } diff --git a/src/widgets/editorview.ui b/src/widgets/editorview.ui index 1e446d10..2f55d16c 100644 --- a/src/widgets/editorview.ui +++ b/src/widgets/editorview.ui @@ -1,150 +1,172 @@ EditorView 0 0 343 - 344 + 390 Editor - + 6 Delegate To: 0 0 0 0 - + + + + + 0 + 0 + + + + + 16777215 + 100 + + + + QListView::LeftToRight + + + true + + + + St&art Date 4 startDateEdit - + Select for &Today - + D&ue Date 4 dueDateEdit - + - + De&legate to 4 - + 0 0 0 0 - + 3 Done Editor KPIM::KDateEdit QComboBox
kdateedit.h
diff --git a/tests/units/widgets/editorviewtest.cpp b/tests/units/widgets/editorviewtest.cpp index 60f79caf..e129ce38 100644 --- a/tests/units/widgets/editorviewtest.cpp +++ b/tests/units/widgets/editorviewtest.cpp @@ -1,700 +1,718 @@ /* 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 #include +#include #include +#include #include #include "domain/note.h" #include "domain/task.h" #include "widgets/editorview.h" #include "addressline/addresseelineedit.h" #include "kdateedit.h" class EditorModelStub : public QObject { Q_OBJECT public: EditorModelStub() { setProperty("editingInProgress", false); + setProperty("attachmentModel", QVariant::fromValue(&attachmentModel)); } void setPropertyAndSignal(const QByteArray &name, const QVariant &value) { if (property(name) == value) return; if (property("editingInProgress").toBool()) return; setProperty(name, value); if (name == "artifact") emit artifactChanged(value.value()); else if (name == "text") emit textChanged(value.toString()); else if (name == "title") emit titleChanged(value.toString()); else if (name == "done") emit doneChanged(value.toBool()); else if (name == "startDate") emit startDateChanged(value.toDateTime()); else if (name == "dueDate") emit dueDateChanged(value.toDateTime()); else if (name == "delegateText") emit delegateTextChanged(value.toString()); else if (name == "hasTaskProperties") emit hasTaskPropertiesChanged(value.toBool()); else qFatal("Unsupported property %s", name.constData()); } public slots: void setArtifact(const Domain::Artifact::Ptr &artifact) { setPropertyAndSignal("artifact", QVariant::fromValue(artifact)); } void setTitle(const QString &title) { setPropertyAndSignal("title", title); } void setText(const QString &text) { setPropertyAndSignal("text", text); } void setDone(bool done) { setPropertyAndSignal("done", done); } void setStartDate(const QDateTime &start) { setPropertyAndSignal("startDate", start); } void setDueDate(const QDateTime &due) { setPropertyAndSignal("dueDate", due); } void setDelegateText(const QString &text) { setPropertyAndSignal("delegateText", text); } void makeTaskAvailable() { setArtifact(Domain::Artifact::Ptr(new Domain::Task)); } void delegate(const QString &name, const QString &email) { delegateNames << name; delegateEmails << email; } signals: void artifactChanged(const Domain::Artifact::Ptr &artifact); void hasTaskPropertiesChanged(bool hasTaskProperties); void textChanged(const QString &text); void titleChanged(const QString &title); void doneChanged(bool done); void startDateChanged(const QDateTime &date); void dueDateChanged(const QDateTime &due); void delegateTextChanged(const QString &delegateText); public: QStringList delegateNames; QStringList delegateEmails; + QStandardItemModel attachmentModel; }; class EditorViewTest : public QObject { Q_OBJECT public: explicit EditorViewTest(QObject *parent = Q_NULLPTR) : QObject(parent) { qputenv("ZANSHIN_UNIT_TEST_RUN", "1"); } private slots: void shouldHaveDefaultState() { Widgets::EditorView editor; QVERIFY(!editor.isEnabled()); auto textEdit = editor.findChild(QStringLiteral("textEdit")); QVERIFY(textEdit); QVERIFY(textEdit->isVisibleTo(&editor)); auto startDateEdit = editor.findChild(QStringLiteral("startDateEdit")); QVERIFY(startDateEdit); QVERIFY(!startDateEdit->isVisibleTo(&editor)); auto dueDateEdit = editor.findChild(QStringLiteral("dueDateEdit")); QVERIFY(dueDateEdit); QVERIFY(!dueDateEdit->isVisibleTo(&editor)); auto doneButton = editor.findChild(QStringLiteral("doneButton")); QVERIFY(doneButton); QVERIFY(!doneButton->isVisibleTo(&editor)); + auto attachmentList = editor.findChild(QStringLiteral("attachmentList")); + QVERIFY(attachmentList); + QVERIFY(!attachmentList->isVisibleTo(&editor)); + auto delegateLabel = editor.findChild(QStringLiteral("delegateLabel")); QVERIFY(delegateLabel); QVERIFY(!delegateLabel->isVisibleTo(&editor)); auto delegateEdit = editor.findChild(QStringLiteral("delegateEdit")); QVERIFY(delegateEdit); QVERIFY(!delegateEdit->isVisibleTo(&editor)); } void shouldNotCrashForNullModel() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.setTitle(QStringLiteral("Foo")); model.setText(QStringLiteral("Bar")); model.setPropertyAndSignal("hasTaskProperties", true); editor.setModel(&model); auto textEdit = editor.findChild(QStringLiteral("textEdit")); QVERIFY(textEdit); auto startDateEdit = editor.findChild(QStringLiteral("startDateEdit")); QVERIFY(startDateEdit); auto dueDateEdit = editor.findChild(QStringLiteral("dueDateEdit")); QVERIFY(dueDateEdit); auto doneButton = editor.findChild(QStringLiteral("doneButton")); QVERIFY(doneButton); + auto attachmentList = editor.findChild(QStringLiteral("attachmentList")); + QVERIFY(attachmentList); + QCOMPARE(attachmentList->model(), &model.attachmentModel); + auto delegateLabel = editor.findChild(QStringLiteral("delegateLabel")); QVERIFY(delegateLabel); auto delegateEdit = editor.findChild(QStringLiteral("delegateEdit")); QVERIFY(delegateEdit); // WHEN editor.setModel(Q_NULLPTR); // THEN QVERIFY(!editor.isEnabled()); QVERIFY(textEdit->toPlainText().isEmpty()); QVERIFY(!startDateEdit->isVisibleTo(&editor)); QVERIFY(!dueDateEdit->isVisibleTo(&editor)); QVERIFY(!doneButton->isVisibleTo(&editor)); + QVERIFY(!attachmentList->isVisibleTo(&editor)); + QVERIFY(attachmentList->model() == nullptr); QVERIFY(!delegateLabel->isVisibleTo(&editor)); QVERIFY(!delegateEdit->isVisibleTo(&editor)); } void shouldShowTaskPropertiesEditorsOnlyForTasks() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.setPropertyAndSignal("hasTaskProperties", true); auto startDateEdit = editor.findChild(QStringLiteral("startDateEdit")); QVERIFY(!startDateEdit->isVisibleTo(&editor)); auto dueDateEdit = editor.findChild(QStringLiteral("dueDateEdit")); QVERIFY(!dueDateEdit->isVisibleTo(&editor)); auto doneButton = editor.findChild(QStringLiteral("doneButton")); QVERIFY(!doneButton->isVisibleTo(&editor)); + auto attachmentList = editor.findChild(QStringLiteral("attachmentList")); + QVERIFY(attachmentList); + auto delegateLabel = editor.findChild(QStringLiteral("delegateLabel")); QVERIFY(!delegateLabel->isVisibleTo(&editor)); auto delegateEdit = editor.findChild(QStringLiteral("delegateEdit")); QVERIFY(!delegateEdit->isVisibleTo(&editor)); // WHEN editor.setModel(&model); // THEN QVERIFY(startDateEdit->isVisibleTo(&editor)); QVERIFY(dueDateEdit->isVisibleTo(&editor)); QVERIFY(doneButton->isVisibleTo(&editor)); + QVERIFY(attachmentList->isVisibleTo(&editor)); QVERIFY(!delegateLabel->isVisibleTo(&editor)); QVERIFY(delegateEdit->isVisibleTo(&editor)); } void shouldDisplayDelegateLabelOnlyWhenNeeded() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); model.setDelegateText(QStringLiteral("John Doe")); auto delegateLabel = editor.findChild(QStringLiteral("delegateLabel")); QVERIFY(!delegateLabel->isVisibleTo(&editor)); // WHEN editor.setModel(&model); // THEN auto expectedText = i18n("Delegated to: %1", model.property("delegateText").toString()); QVERIFY(delegateLabel->isVisibleTo(&editor)); QCOMPARE(delegateLabel->text(), expectedText); } void shouldBeEnabledOnlyWhenAnArtifactIsAvailable() { // GIVEN Widgets::EditorView editor; EditorModelStub model; // WHEN editor.setModel(&model); // THEN QVERIFY(!editor.isEnabled()); // WHEN // like model.makeTaskAvailable() does: Domain::Artifact::Ptr artifact(new Domain::Task); model.setPropertyAndSignal("artifact", QVariant::fromValue(artifact)); // THEN QVERIFY(editor.isEnabled()); // WHEN model.setPropertyAndSignal("artifact", QVariant::fromValue(Domain::Artifact::Ptr())); // THEN QVERIFY(!editor.isEnabled()); // GIVEN EditorModelStub model2; model2.setPropertyAndSignal("artifact", QVariant::fromValue(artifact)); // WHEN editor.setModel(&model2); // THEN QVERIFY(editor.isEnabled()); } void shouldReactToHasTaskPropertiesChanged() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); editor.setModel(&model); auto startDateEdit = editor.findChild(QStringLiteral("startDateEdit")); QVERIFY(!startDateEdit->isVisibleTo(&editor)); auto dueDateEdit = editor.findChild(QStringLiteral("dueDateEdit")); QVERIFY(!dueDateEdit->isVisibleTo(&editor)); auto doneButton = editor.findChild(QStringLiteral("doneButton")); QVERIFY(!doneButton->isVisibleTo(&editor)); // WHEN model.setPropertyAndSignal("hasTaskProperties", true); // THEN QVERIFY(startDateEdit->isVisibleTo(&editor)); QVERIFY(dueDateEdit->isVisibleTo(&editor)); QVERIFY(doneButton->isVisibleTo(&editor)); } void shouldDisplayModelProperties() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); model.setProperty("hasTaskProperties", true); model.setProperty("title", "My title"); model.setProperty("text", "\nMy text"); model.setProperty("startDate", QDateTime::currentDateTime()); model.setProperty("dueDate", QDateTime::currentDateTime().addDays(2)); model.setProperty("done", true); auto textEdit = editor.findChild(QStringLiteral("textEdit")); auto startDateEdit = editor.findChild(QStringLiteral("startDateEdit")); auto dueDateEdit = editor.findChild(QStringLiteral("dueDateEdit")); auto doneButton = editor.findChild(QStringLiteral("doneButton")); // WHEN editor.setModel(&model); // THEN QCOMPARE(textEdit->toPlainText(), QString(model.property("title").toString() + '\n' + model.property("text").toString())); QCOMPARE(startDateEdit->date(), model.property("startDate").toDateTime().date()); QCOMPARE(dueDateEdit->date(), model.property("dueDate").toDateTime().date()); QCOMPARE(doneButton->isChecked(), model.property("done").toBool()); } void shouldNotReactToChangesWhileEditing() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); model.setProperty("title", "My title"); model.setProperty("text", "\nMy text"); model.setProperty("startDate", QDateTime::currentDateTime()); model.setProperty("dueDate", QDateTime::currentDateTime().addDays(2)); model.setProperty("done", true); editor.setModel(&model); auto textEdit = editor.findChild(QStringLiteral("textEdit")); auto startDateEdit = editor.findChild(QStringLiteral("startDateEdit")); auto dueDateEdit = editor.findChild(QStringLiteral("dueDateEdit")); auto doneButton = editor.findChild(QStringLiteral("doneButton")); auto delegateLabel = editor.findChild(QStringLiteral("delegateLabel")); auto delegateEdit = editor.findChild(QStringLiteral("delegateEdit")); model.setDelegateText(QStringLiteral("John Doe")); editor.setModel(&model); // WHEN editor.show(); QTest::qWaitForWindowShown(&editor); editor.activateWindow(); textEdit->setFocus(); model.setTitle("New title"); model.setText("New text"); startDateEdit->setFocus(); model.setStartDate(QDateTime::currentDateTime().addDays(1)); dueDateEdit->setFocus(); model.setDueDate(QDateTime::currentDateTime().addDays(3)); doneButton->setFocus(); model.setDone(false); delegateEdit->setFocus(); model.setDelegateText(QStringLiteral("John Smith")); // THEN (nothing changed) QCOMPARE(textEdit->toPlainText(), QStringLiteral("My title\n\nMy text")); QCOMPARE(startDateEdit->date(), QDate::currentDate()); QCOMPARE(dueDateEdit->date(), QDate::currentDate().addDays(2)); QVERIFY(doneButton->isChecked()); auto expectedText = i18n("Delegated to: %1", QStringLiteral("John Doe")); QCOMPARE(delegateLabel->text(), expectedText); } void shouldReactToTitleChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); model.setProperty("title", "My title"); model.setProperty("text", "\nMy text"); model.setProperty("startDate", QDateTime::currentDateTime()); model.setProperty("dueDate", QDateTime::currentDateTime().addDays(2)); model.setProperty("done", true); editor.setModel(&model); auto textEdit = editor.findChild(QStringLiteral("textEdit")); // WHEN model.setPropertyAndSignal("title", "New title"); // THEN QCOMPARE(textEdit->toPlainText(), QString(model.property("title").toString() + '\n' + model.property("text").toString())); } void shouldReactToTextChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); model.setProperty("title", "My title"); model.setProperty("text", "\nMy text"); model.setProperty("startDate", QDateTime::currentDateTime()); model.setProperty("dueDate", QDateTime::currentDateTime().addDays(2)); model.setProperty("done", true); editor.setModel(&model); auto textEdit = editor.findChild(QStringLiteral("textEdit")); // WHEN model.setPropertyAndSignal("text", "\nNew text"); // THEN QCOMPARE(textEdit->toPlainText(), QString(model.property("title").toString() + '\n' + model.property("text").toString())); } void shouldApplyTextEditChanges_data() { QTest::addColumn("plainText"); QTest::addColumn("expectedTitle"); QTest::addColumn("expectedText"); QTest::newRow("nominal case") << "Title\n\nText" << "Title" << "\nText"; QTest::newRow("single line") << "Title" << "Title" << ""; } void shouldApplyTextEditChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); editor.setModel(&model); auto textEdit = editor.findChild(QStringLiteral("textEdit")); // WHEN QFETCH(QString, plainText); textEdit->setPlainText(plainText); // THEN QFETCH(QString, expectedTitle); QCOMPARE(model.property("title").toString(), expectedTitle); QFETCH(QString, expectedText); QCOMPARE(model.property("text").toString(), expectedText); } void shouldReactToDoneChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); model.setProperty("title", "My title"); model.setProperty("text", "\nMy text"); model.setProperty("startDate", QDateTime::currentDateTime()); model.setProperty("dueDate", QDateTime::currentDateTime().addDays(2)); model.setProperty("done", false); editor.setModel(&model); auto doneButton = editor.findChild(QStringLiteral("doneButton")); QVERIFY(!doneButton->isChecked()); // WHEN model.setPropertyAndSignal("done", true); // THEN QVERIFY(doneButton->isChecked()); } void shouldApplyDoneButtonChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); editor.setModel(&model); auto doneButton = editor.findChild(QStringLiteral("doneButton")); // WHEN doneButton->setChecked(true); // THEN QCOMPARE(model.property("done").toBool(), true); } void shouldReactToStartDateChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); model.setProperty("title", "My title"); model.setProperty("text", "\nMy text"); model.setProperty("startDate", QDateTime::currentDateTime()); model.setProperty("dueDate", QDateTime::currentDateTime().addDays(2)); model.setProperty("done", false); editor.setModel(&model); auto startDateEdit = editor.findChild(QStringLiteral("startDateEdit")); // WHEN model.setPropertyAndSignal("startDate", QDateTime::currentDateTime().addDays(-2)); // THEN QCOMPARE(startDateEdit->date(), model.property("startDate").toDateTime().date()); } void shouldApplyStartDateEditChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); editor.setModel(&model); auto startDateEdit = editor.findChild(QStringLiteral("startDateEdit")); auto today = QDate::currentDate(); // WHEN startDateEdit->setEditText(today.toString(QStringLiteral("dd/MM/yyyy"))); QTest::keyClick(startDateEdit, Qt::Key_Enter); // THEN const QDateTime newStartDateTime = model.property("startDate").toDateTime(); QCOMPARE(newStartDateTime.date(), today); QCOMPARE(newStartDateTime.timeSpec(), Qt::UTC); } void shouldReactToDueDateChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.setProperty("title", "My title"); model.setProperty("text", "\nMy text"); model.setProperty("startDate", QDateTime::currentDateTime()); model.setProperty("dueDate", QDateTime::currentDateTime().addDays(2)); model.setProperty("done", false); editor.setModel(&model); auto dueDateEdit = editor.findChild(QStringLiteral("dueDateEdit")); // WHEN model.setPropertyAndSignal("dueDate", QDateTime::currentDateTime().addDays(-2)); // THEN QCOMPARE(dueDateEdit->date(), model.property("dueDate").toDateTime().date()); } void shouldApplyDueDateEditChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); editor.setModel(&model); auto dueDateEdit = editor.findChild(QStringLiteral("dueDateEdit")); auto today = QDate::currentDate(); // WHEN QVERIFY(dueDateEdit->isEnabled()); dueDateEdit->setEditText(today.toString(QStringLiteral("dd/MM/yyyy"))); QTest::keyClick(dueDateEdit, Qt::Key_Enter); // THEN QCOMPARE(model.property("dueDate").toDateTime().date(), today); } void shouldApplyStartTodayChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); editor.setModel(&model); QAbstractButton *startTodayButton = editor.findChild(QStringLiteral("startTodayButton")); QVERIFY(startTodayButton); auto startDateEdit = editor.findChild(QStringLiteral("startDateEdit")); auto today = QDate::currentDate(); // WHEN QVERIFY(startTodayButton->isEnabled()); startTodayButton->click(); // THEN QCOMPARE(startDateEdit->currentText(), today.toString(QStringLiteral("dd/MM/yyyy"))); QCOMPARE(model.property("startDate").toDateTime().date(), today); } void shouldReactToDelegateTextChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); model.setDelegateText(QStringLiteral("John Doe")); editor.setModel(&model); auto delegateLabel = editor.findChild(QStringLiteral("delegateLabel")); // WHEN model.setDelegateText(QStringLiteral("John Smith")); // THEN auto expectedText = i18n("Delegated to: %1", model.property("delegateText").toString()); QCOMPARE(delegateLabel->text(), expectedText); } void shouldClearDelegateEditOnArtifactChanges() { // GIVEN Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); editor.setModel(&model); auto delegateEdit = editor.findChild(QStringLiteral("delegateEdit")); delegateEdit->setText(QStringLiteral("Foo")); // WHEN model.makeTaskAvailable(); // simulates an artifact change // THEN QVERIFY(delegateEdit->text().isEmpty()); } void shouldRequestDelegationOnInput_data() { QTest::addColumn("userInput"); QTest::addColumn("expectedName"); QTest::addColumn("expectedEmail"); QTest::addColumn("expectedCall"); QTest::newRow("nominal case") << "John Doe " << "John Doe" << "john@doe.com" << true; QTest::newRow("nominal case") << "John Doe " << "John Doe" << "j.doe@some.server.com" << true; QTest::newRow("only name") << "John Doe" << QString() << QString() << false; QTest::newRow("only email") << "john@doe.com" << QString() << "john@doe.com" << true; QTest::newRow("only email again") << "" << QString() << "john@doe.com" << true; QTest::newRow("nonsense case") << "bleh" << QString() << QString() << false; } void shouldRequestDelegationOnInput() { // GIVEN QFETCH(QString, userInput); QFETCH(QString, expectedName); QFETCH(QString, expectedEmail); QFETCH(bool, expectedCall); Widgets::EditorView editor; EditorModelStub model; model.makeTaskAvailable(); editor.setModel(&model); auto delegateEdit = editor.findChild(QStringLiteral("delegateEdit")); // WHEN QVERIFY(delegateEdit->isEnabled()); delegateEdit->setText(userInput); QTest::keyClick(delegateEdit, Qt::Key_Enter); // THEN if (expectedCall) { QCOMPARE(model.delegateNames.size(), 1); QCOMPARE(model.delegateNames.first(), expectedName); QCOMPARE(model.delegateEmails.size(), 1); QCOMPARE(model.delegateEmails.first(), expectedEmail); QVERIFY(delegateEdit->text().isEmpty()); } else { QCOMPARE(model.delegateNames.size(), 0); QCOMPARE(model.delegateEmails.size(), 0); } } }; ZANSHIN_TEST_MAIN(EditorViewTest) #include "editorviewtest.moc"