diff --git a/src/presentation/CMakeLists.txt b/src/presentation/CMakeLists.txt index 660cddec..737efeca 100644 --- a/src/presentation/CMakeLists.txt +++ b/src/presentation/CMakeLists.txt @@ -1,25 +1,25 @@ set(presentation_SRCS applicationmodel.cpp editormodel.cpp - artifactfilterproxymodel.cpp availablepagesmodelinterface.cpp availablepagessortfilterproxymodel.cpp availabletaskpagesmodel.cpp availablesourcesmodel.cpp contextpagemodel.cpp errorhandler.cpp errorhandlingmodelbase.cpp metatypes.cpp pagemodel.cpp projectpagemodel.cpp querytreemodelbase.cpp runningtaskmodelinterface.cpp runningtaskmodel.cpp + taskfilterproxymodel.cpp taskinboxpagemodel.cpp tasklistmodel.cpp taskapplicationmodel.cpp workdaypagemodel.cpp ) add_library(presentation STATIC ${presentation_SRCS}) target_link_libraries(presentation Qt5::Core Qt5::Gui KF5::I18n domain utils) diff --git a/src/presentation/artifactfilterproxymodel.cpp b/src/presentation/taskfilterproxymodel.cpp similarity index 67% rename from src/presentation/artifactfilterproxymodel.cpp rename to src/presentation/taskfilterproxymodel.cpp index c5641b50..6625d972 100644 --- a/src/presentation/artifactfilterproxymodel.cpp +++ b/src/presentation/taskfilterproxymodel.cpp @@ -1,140 +1,135 @@ /* 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 "artifactfilterproxymodel.h" +#include "taskfilterproxymodel.h" #include -#include "domain/artifact.h" #include "domain/task.h" #include "utils/datetime.h" #include "presentation/querytreemodelbase.h" using namespace Presentation; -ArtifactFilterProxyModel::ArtifactFilterProxyModel(QObject *parent) +TaskFilterProxyModel::TaskFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent), m_sortType(TitleSort), m_showFuture(false) { setDynamicSortFilter(true); setSortCaseSensitivity(Qt::CaseInsensitive); setSortOrder(Qt::AscendingOrder); } -ArtifactFilterProxyModel::SortType ArtifactFilterProxyModel::sortType() const +TaskFilterProxyModel::SortType TaskFilterProxyModel::sortType() const { return m_sortType; } -void ArtifactFilterProxyModel::setSortType(ArtifactFilterProxyModel::SortType type) +void TaskFilterProxyModel::setSortType(TaskFilterProxyModel::SortType type) { m_sortType = type; invalidate(); } -void ArtifactFilterProxyModel::setSortOrder(Qt::SortOrder order) +void TaskFilterProxyModel::setSortOrder(Qt::SortOrder order) { sort(0, order); } -bool ArtifactFilterProxyModel::showFutureTasks() const +bool TaskFilterProxyModel::showFutureTasks() const { return m_showFuture; } -void ArtifactFilterProxyModel::setShowFutureTasks(bool show) +void TaskFilterProxyModel::setShowFutureTasks(bool show) { if (m_showFuture == show) return; m_showFuture = show; invalidate(); } -static bool isFutureTask(const Domain::Artifact::Ptr &artifact) +static bool isFutureTask(const Domain::Task::Ptr &task) { - auto task = artifact.objectCast(); if (!task) return false; if (!task->startDate().isValid()) return false; return task->startDate() > Utils::DateTime::currentDate(); } -bool ArtifactFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const +bool TaskFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); - const auto artifact = index.data(QueryTreeModelBase::ObjectRole).value(); - if (artifact) { + const auto task = index.data(QueryTreeModelBase::ObjectRole).value(); + if (task) { QRegExp regexp = filterRegExp(); regexp.setCaseSensitivity(Qt::CaseInsensitive); - if (artifact->title().contains(regexp) - || artifact->text().contains(regexp)) { - return m_showFuture || !isFutureTask(artifact); + if (task->title().contains(regexp) + || task->text().contains(regexp)) { + return m_showFuture || !isFutureTask(task); } } for (int childRow = 0; childRow < sourceModel()->rowCount(index); childRow++) { if (filterAcceptsRow(childRow, index)) return true; } return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); } static QDate validDate(const QDate &date = QDate()) { if (date.isValid()) return date; return QDate(80000, 12, 31); } -bool ArtifactFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +bool TaskFilterProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { if (m_sortType != DateSort) return QSortFilterProxyModel::lessThan(left, right); - const auto leftArtifact = left.data(QueryTreeModelBase::ObjectRole).value(); - const auto rightArtifact = right.data(QueryTreeModelBase::ObjectRole).value(); - - const auto leftTask = leftArtifact.objectCast(); - const auto rightTask = rightArtifact.objectCast(); + const auto leftTask = left.data(QueryTreeModelBase::ObjectRole).value(); + const auto rightTask = right.data(QueryTreeModelBase::ObjectRole).value(); // The addDays(1) is so that we sort non-tasks (e.g. notes) at the end const QDate leftDue = leftTask ? validDate(leftTask->dueDate()) : validDate().addDays(1); const QDate rightDue = rightTask ? validDate(rightTask->dueDate()) : validDate().addDays(1); const QDate leftStart = leftTask ? validDate(leftTask->startDate()) : validDate().addDays(1); const QDate rightStart = rightTask ? validDate(rightTask->startDate()) : validDate().addDays(1); return leftDue < rightDue || leftStart < rightStart; } diff --git a/src/presentation/artifactfilterproxymodel.h b/src/presentation/taskfilterproxymodel.h similarity index 85% rename from src/presentation/artifactfilterproxymodel.h rename to src/presentation/taskfilterproxymodel.h index 23000a02..1d89cfaa 100644 --- a/src/presentation/artifactfilterproxymodel.h +++ b/src/presentation/taskfilterproxymodel.h @@ -1,63 +1,63 @@ /* 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 PRESENTATION_ARTIFACTFILTERPROXYMODEL_H -#define PRESENTATION_ARTIFACTFILTERPROXYMODEL_H +#ifndef PRESENTATION_TASKFILTERPROXYMODEL_H +#define PRESENTATION_TASKFILTERPROXYMODEL_H #include namespace Presentation { -class ArtifactFilterProxyModel : public QSortFilterProxyModel +class TaskFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT Q_ENUMS(SortType) public: enum SortType { TitleSort = 0, DateSort }; - explicit ArtifactFilterProxyModel(QObject *parent = Q_NULLPTR); + explicit TaskFilterProxyModel(QObject *parent = Q_NULLPTR); SortType sortType() const; void setSortType(SortType type); void setSortOrder(Qt::SortOrder order); bool showFutureTasks() const; void setShowFutureTasks(bool show); protected: bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE; bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE; private: SortType m_sortType; bool m_showFuture; }; } -#endif // PRESENTATION_ARTIFACTFILTERPROXYMODEL_H +#endif // PRESENTATION_TASKFILTERPROXYMODEL_H diff --git a/src/widgets/filterwidget.cpp b/src/widgets/filterwidget.cpp index a97d2cc8..23739609 100644 --- a/src/widgets/filterwidget.cpp +++ b/src/widgets/filterwidget.cpp @@ -1,96 +1,96 @@ /* 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 "filterwidget.h" #include #include #include #include #include -#include "presentation/artifactfilterproxymodel.h" +#include "presentation/taskfilterproxymodel.h" #include "ui_filterwidget.h" using namespace Widgets; FilterWidget::FilterWidget(QWidget *parent) : QWidget(parent), ui(new Ui::FilterWidget), - m_model(new Presentation::ArtifactFilterProxyModel(this)) + m_model(new Presentation::TaskFilterProxyModel(this)) { ui->setupUi(this); ui->extension->hide(); - ui->sortTypeCombo->addItem(i18n("Sort by title"), Presentation::ArtifactFilterProxyModel::TitleSort); - ui->sortTypeCombo->addItem(i18n("Sort by date"), Presentation::ArtifactFilterProxyModel::DateSort); + ui->sortTypeCombo->addItem(i18n("Sort by title"), Presentation::TaskFilterProxyModel::TitleSort); + ui->sortTypeCombo->addItem(i18n("Sort by date"), Presentation::TaskFilterProxyModel::DateSort); setFocusProxy(ui->filterEdit); connect(ui->filterEdit, &QLineEdit::textChanged, this, &FilterWidget::onTextChanged); connect(ui->sortTypeCombo, static_cast(&QComboBox::currentIndexChanged), this, &FilterWidget::onSortTypeChanged); connect(ui->ascendingButton, &QToolButton::clicked, this, &FilterWidget::onAscendingClicked); connect(ui->descendingButton, &QToolButton::clicked, this, &FilterWidget::onDescendingClicked); } FilterWidget::~FilterWidget() { delete ui; } -Presentation::ArtifactFilterProxyModel *FilterWidget::proxyModel() const +Presentation::TaskFilterProxyModel *FilterWidget::proxyModel() const { return m_model; } void FilterWidget::clear() { ui->filterEdit->clear(); } void FilterWidget::setShowFutureTasks(bool show) { m_model->setShowFutureTasks(show); } void FilterWidget::onTextChanged(const QString &text) { m_model->setFilterFixedString(text); } void FilterWidget::onSortTypeChanged(int index) { const int data = ui->sortTypeCombo->itemData(index).toInt(); - m_model->setSortType(Presentation::ArtifactFilterProxyModel::SortType(data)); + m_model->setSortType(Presentation::TaskFilterProxyModel::SortType(data)); } void FilterWidget::onAscendingClicked() { m_model->setSortOrder(Qt::AscendingOrder); } void FilterWidget::onDescendingClicked() { m_model->setSortOrder(Qt::DescendingOrder); } diff --git a/src/widgets/filterwidget.h b/src/widgets/filterwidget.h index d9f28fba..8831ed2a 100644 --- a/src/widgets/filterwidget.h +++ b/src/widgets/filterwidget.h @@ -1,70 +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. */ #ifndef WIDGETS_FILTERWIDGET_H #define WIDGETS_FILTERWIDGET_H #include class QComboBox; class QLineEdit; namespace Presentation { - class ArtifactFilterProxyModel; + class TaskFilterProxyModel; } namespace Ui { class FilterWidget; } namespace Widgets { class FilterWidget : public QWidget { Q_OBJECT public: explicit FilterWidget(QWidget *parent = Q_NULLPTR); ~FilterWidget(); - Presentation::ArtifactFilterProxyModel *proxyModel() const; + Presentation::TaskFilterProxyModel *proxyModel() const; public slots: void clear(); void setShowFutureTasks(bool show); private slots: void onTextChanged(const QString &text); void onSortTypeChanged(int index); void onAscendingClicked(); void onDescendingClicked(); private: Ui::FilterWidget *ui; - Presentation::ArtifactFilterProxyModel *m_model; + Presentation::TaskFilterProxyModel *m_model; }; } #endif // WIDGETS_FILTERWIDGET_H diff --git a/src/widgets/pageview.cpp b/src/widgets/pageview.cpp index 46e474fb..9922006c 100644 --- a/src/widgets/pageview.cpp +++ b/src/widgets/pageview.cpp @@ -1,486 +1,486 @@ /* 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 "pageview.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "filterwidget.h" #include "itemdelegate.h" #include "messagebox.h" #include -#include "presentation/artifactfilterproxymodel.h" #include "presentation/metatypes.h" #include "presentation/querytreemodelbase.h" #include "presentation/runningtaskmodelinterface.h" +#include "presentation/taskfilterproxymodel.h" #include "utils/datetime.h" namespace Widgets { class PageTreeView : public QTreeView { Q_OBJECT public: using QTreeView::QTreeView; protected: void keyPressEvent(QKeyEvent *event) Q_DECL_OVERRIDE { if (event->key() == Qt::Key_Escape && state() != EditingState) { selectionModel()->clear(); } QTreeView::keyPressEvent(event); } void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE { header()->resizeSection(0, event->size().width()); QTreeView::resizeEvent(event); } }; } class PassivePopup : public QFrame { Q_OBJECT public: explicit PassivePopup(QWidget *parent = Q_NULLPTR) : QFrame(parent), m_hideTimer(new QTimer(this)), m_label(new QLabel(this)) { setWindowFlags(Qt::Tool | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint); setFrameStyle(QFrame::Box | QFrame::Plain); setLineWidth(2); setAttribute(Qt::WA_DeleteOnClose); setLayout(new QVBoxLayout); layout()->addWidget(m_label); connect(m_hideTimer, &QTimer::timeout, this, &QWidget::hide); } void setVisible(bool visible) Q_DECL_OVERRIDE { if (visible) { m_hideTimer->start(2000); } QFrame::setVisible(visible); } void setText(const QString &text) { m_label->setText(text); } private: QTimer *m_hideTimer; QLabel *m_label; }; using namespace Widgets; PageView::PageView(QWidget *parent) : QWidget(parent), m_cancelAction(new QAction(this)), m_model(Q_NULLPTR), m_messageWidget(new KMessageWidget(this)), m_filterWidget(new FilterWidget(this)), m_centralView(new PageTreeView(this)), m_quickAddEdit(new QLineEdit(this)) { m_messageWidget->setObjectName(QStringLiteral("messageWidget")); m_messageWidget->setCloseButtonVisible(true); m_messageWidget->setMessageType(KMessageWidget::Error); m_messageWidget->setWordWrap(true); m_messageWidget->hide(); m_filterWidget->setObjectName(QStringLiteral("filterWidget")); m_filterWidget->hide(); m_centralView->setObjectName(QStringLiteral("centralView")); m_centralView->header()->hide(); m_centralView->setAlternatingRowColors(true); m_centralView->setItemDelegate(new ItemDelegate(this)); m_centralView->setDragDropMode(QTreeView::DragDrop); m_centralView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_centralView->setModel(m_filterWidget->proxyModel()); m_centralView->installEventFilter(this); m_centralView->setItemsExpandable(false); m_centralView->setRootIsDecorated(false); connect(m_centralView->model(), &QAbstractItemModel::rowsInserted, m_centralView, &QTreeView::expandAll); connect(m_centralView->model(), &QAbstractItemModel::layoutChanged, m_centralView, &QTreeView::expandAll); connect(m_centralView->model(), &QAbstractItemModel::modelReset, m_centralView, &QTreeView::expandAll); m_centralView->setStyleSheet(QStringLiteral("QTreeView::branch { border-image: url(none.png); }")); m_quickAddEdit->setObjectName(QStringLiteral("quickAddEdit")); m_quickAddEdit->setPlaceholderText(i18n("Type and press enter to add an item")); connect(m_quickAddEdit, &QLineEdit::returnPressed, this, &PageView::onReturnPressed); auto layout = new QVBoxLayout; layout->setContentsMargins(0, 0, 0, 3); layout->addWidget(m_messageWidget); layout->addWidget(m_filterWidget); layout->addWidget(m_centralView); layout->addWidget(m_quickAddEdit); setLayout(layout); m_messageBoxInterface = MessageBox::Ptr::create(); auto addItemAction = new QAction(this); addItemAction->setObjectName(QStringLiteral("addItemAction")); addItemAction->setText(i18n("New Item")); addItemAction->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); addItemAction->setShortcut(Qt::CTRL | Qt::Key_N); connect(addItemAction, &QAction::triggered, this, &PageView::onAddItemRequested); m_cancelAction->setObjectName(QStringLiteral("cancelAddItemAction")); m_cancelAction->setShortcut(Qt::Key_Escape); addAction(m_cancelAction); connect(m_cancelAction, &QAction::triggered, m_centralView, static_cast(&QWidget::setFocus)); auto removeItemAction = new QAction(this); removeItemAction->setObjectName(QStringLiteral("removeItemAction")); removeItemAction->setText(i18n("Remove Item")); removeItemAction->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); removeItemAction->setShortcut(Qt::Key_Delete); connect(removeItemAction, &QAction::triggered, this, &PageView::onRemoveItemRequested); addAction(removeItemAction); auto promoteItemAction = new QAction(this); promoteItemAction->setObjectName(QStringLiteral("promoteItemAction")); promoteItemAction->setText(i18n("Promote Item as Project")); promoteItemAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_P); connect(promoteItemAction, &QAction::triggered, this, &PageView::onPromoteItemRequested); auto filterViewAction = new QAction(this); filterViewAction->setObjectName(QStringLiteral("filterViewAction")); filterViewAction->setText(i18n("Filter...")); filterViewAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-find"))); filterViewAction->setShortcut(Qt::CTRL | Qt::Key_F); filterViewAction->setCheckable(true); connect(filterViewAction, &QAction::triggered, this, &PageView::onFilterToggled); auto futureViewAction = new QAction(this); futureViewAction->setObjectName(QStringLiteral("futureViewAction")); futureViewAction->setText(i18n("Show future items")); futureViewAction->setIcon(QIcon::fromTheme(QStringLiteral("view-calendar-whatsnext"))); futureViewAction->setShortcut(Qt::CTRL | Qt::SHIFT | Qt::Key_F); futureViewAction->setCheckable(true); connect(futureViewAction, &QAction::triggered, m_filterWidget, &FilterWidget::setShowFutureTasks); auto configGroup = KConfigGroup(KSharedConfig::openConfig(), "General"); if (configGroup.readEntry("ShowFuture", true)) futureViewAction->trigger(); connect(futureViewAction, &QAction::triggered, futureViewAction, [configGroup] (bool checked) mutable { configGroup.writeEntry("ShowFuture", checked); }); m_runTaskAction = new QAction(this); m_runTaskAction->setObjectName(QStringLiteral("runTaskAction")); m_runTaskAction->setShortcut(Qt::CTRL | Qt::Key_Space); m_runTaskAction->setText(i18n("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_view_future"), futureViewAction); m_actions.insert(QStringLiteral("page_run_task"), m_runTaskAction); } QHash PageView::globalActions() const { return m_actions; } QObject *PageView::model() const { return m_model; } Presentation::RunningTaskModelInterface *PageView::runningTaskModel() const { return m_runningTaskModel; } void PageView::setModel(QObject *model) { if (model == m_model) return; if (m_centralView->selectionModel()) { disconnect(m_centralView->selectionModel(), Q_NULLPTR, this, Q_NULLPTR); } m_filterWidget->proxyModel()->setSourceModel(Q_NULLPTR); m_model = model; setEnabled(m_model); updateRunTaskAction(); if (!m_model) return; QVariant modelProperty = m_model->property("centralListModel"); if (modelProperty.canConvert()) m_filterWidget->proxyModel()->setSourceModel(modelProperty.value()); connect(m_centralView->selectionModel(), &QItemSelectionModel::currentChanged, this, &PageView::onCurrentChanged); } MessageBoxInterface::Ptr PageView::messageBoxInterface() const { return m_messageBoxInterface; } QModelIndexList PageView::selectedIndexes() const { using namespace std::placeholders; const auto selection = m_centralView->selectionModel()->selectedIndexes(); auto sourceIndices = QModelIndexList(); std::transform(selection.constBegin(), selection.constEnd(), std::back_inserter(sourceIndices ), std::bind(&QSortFilterProxyModel::mapToSource, m_filterWidget->proxyModel(), _1)); 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; } void PageView::displayErrorMessage(const QString &message) { m_messageWidget->setText(message); m_messageWidget->animatedShow(); } void PageView::onReturnPressed() { if (m_quickAddEdit->text().isEmpty()) return; auto parentIndex = QModelIndex(); if (m_centralView->selectionModel()->selectedIndexes().size() == 1) parentIndex = m_centralView->selectionModel()->selectedIndexes().first(); QMetaObject::invokeMethod(m_model, "addItem", Q_ARG(QString, m_quickAddEdit->text()), Q_ARG(QModelIndex, parentIndex)); m_quickAddEdit->clear(); } void PageView::onAddItemRequested() { if (m_quickAddEdit->hasFocus()) return; const auto editTopLeft = m_quickAddEdit->geometry().topLeft(); const auto pos = mapToGlobal(editTopLeft); auto popup = new PassivePopup(m_quickAddEdit); popup->setText(i18n("Type and press enter to add an item")); popup->show(); popup->move(pos - QPoint(0, popup->height())); m_quickAddEdit->selectAll(); m_quickAddEdit->setFocus(); } void PageView::onRemoveItemRequested() { const QModelIndexList ¤tIndexes = m_centralView->selectionModel()->selectedIndexes(); if (currentIndexes.isEmpty()) return; auto indexHasChildren = [](QModelIndex index) { if (const QAbstractProxyModel *proxy = qobject_cast(index.model())) { index = proxy->mapToSource(index); } return index.model()->rowCount(index) > 0; }; QString text; if (currentIndexes.size() > 1) { const bool hasDescendants = std::any_of(currentIndexes.constBegin(), currentIndexes.constEnd(), [&](const QModelIndex ¤tIndex) { return currentIndex.isValid() && indexHasChildren(currentIndex); }); if (hasDescendants) text = i18n("Do you really want to delete the selected items and their children?"); else text = i18n("Do you really want to delete the selected items?"); } else { const QModelIndex ¤tIndex = currentIndexes.first(); if (!currentIndex.isValid()) return; if (indexHasChildren(currentIndex)) text = i18n("Do you really want to delete the selected task and all its children?"); } if (!text.isEmpty()) { QMessageBox::Button button = m_messageBoxInterface->askConfirmation(this, i18n("Delete Tasks"), text); bool canRemove = (button == QMessageBox::Yes); if (!canRemove) return; } foreach (const QModelIndex ¤tIndex, currentIndexes) { if (!currentIndex.isValid()) continue; QMetaObject::invokeMethod(m_model, "removeItem", Q_ARG(QModelIndex, currentIndex)); const auto data = currentIndex.data(Presentation::QueryTreeModelBase::ObjectRole); if (data.isValid()) { auto task = data.value().objectCast(); if (task) m_runningTaskModel->taskDeleted(task); } } } void PageView::onPromoteItemRequested() { QModelIndex currentIndex = m_centralView->currentIndex(); if (!currentIndex.isValid()) return; QMetaObject::invokeMethod(m_model, "promoteItem", Q_ARG(QModelIndex, currentIndex)); } void PageView::onFilterToggled(bool show) { m_filterWidget->setVisible(show); if (show) m_filterWidget->setFocus(); else 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(Utils::DateTime::currentDate()); m_runningTaskModel->setRunningTask(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 = currentArtifact(); if (!artifact) return; emit currentTaskChanged(artifact); } bool PageView::eventFilter(QObject *object, QEvent *event) { Q_ASSERT(object == m_centralView); switch(event->type()) { case QEvent::FocusIn: m_cancelAction->setEnabled(false); break; case QEvent::FocusOut: m_cancelAction->setEnabled(true); break; default: break; } 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(); return data.value(); } #include "pageview.moc" diff --git a/tests/units/presentation/CMakeLists.txt b/tests/units/presentation/CMakeLists.txt index 7ecd2588..d10342c5 100644 --- a/tests/units/presentation/CMakeLists.txt +++ b/tests/units/presentation/CMakeLists.txt @@ -1,20 +1,20 @@ zanshin_auto_tests( applicationmodeltest editormodeltest - artifactfilterproxymodeltest availablepagessortfilterproxymodeltest availablesourcesmodeltest availabletaskpagesmodeltest errorhandlertest errorhandlingmodelbasetest metatypestest pagemodeltest projectpagemodeltest querytreemodeltest runningtaskmodeltest taskapplicationmodeltest + taskfilterproxymodeltest taskinboxpagemodeltest tasklistmodeltest contextpagemodeltest workdaypagemodeltest ) diff --git a/tests/units/presentation/artifactfilterproxymodeltest.cpp b/tests/units/presentation/taskfilterproxymodeltest.cpp similarity index 90% rename from tests/units/presentation/artifactfilterproxymodeltest.cpp rename to tests/units/presentation/taskfilterproxymodeltest.cpp index 215efeda..05b23738 100644 --- a/tests/units/presentation/artifactfilterproxymodeltest.cpp +++ b/tests/units/presentation/taskfilterproxymodeltest.cpp @@ -1,271 +1,271 @@ /* 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 "domain/task.h" -#include "presentation/artifactfilterproxymodel.h" #include "presentation/querytreemodelbase.h" +#include "presentation/taskfilterproxymodel.h" #include "utils/datetime.h" Q_DECLARE_METATYPE(QList) -class ArtifactFilterProxyModelTest : public QObject +class TaskFilterProxyModelTest : public QObject { Q_OBJECT private: QStandardItem *createTaskItem(const QString &title, const QString &text, const QDate &start = QDate(), const QDate &due = QDate()) const { auto task = Domain::Task::Ptr::create(); task->setTitle(title); task->setText(text); task->setStartDate(start); task->setDueDate(due); auto item = new QStandardItem; item->setData(task->title(), Qt::DisplayRole); - item->setData(QVariant::fromValue(Domain::Artifact::Ptr(task)), + item->setData(QVariant::fromValue(task), Presentation::QueryTreeModelBase::ObjectRole); return item; } private slots: void initTestCase() { qputenv("ZANSHIN_OVERRIDE_DATE", "2015-03-11"); } void shouldHaveDefaultState() { - Presentation::ArtifactFilterProxyModel proxy; + Presentation::TaskFilterProxyModel proxy; QVERIFY(!proxy.sourceModel()); QCOMPARE(proxy.sortColumn(), 0); QCOMPARE(proxy.sortOrder(), Qt::AscendingOrder); - QCOMPARE(proxy.sortType(), Presentation::ArtifactFilterProxyModel::TitleSort); + QCOMPARE(proxy.sortType(), Presentation::TaskFilterProxyModel::TitleSort); QCOMPARE(proxy.sortCaseSensitivity(), Qt::CaseInsensitive); QVERIFY(!proxy.showFutureTasks()); } void shouldFilterByTextAndTitle() { // GIVEN QStandardItemModel input; input.appendRow(createTaskItem(QStringLiteral("1. foo"), QStringLiteral("find me"))); input.appendRow(createTaskItem(QStringLiteral("2. Find Me"), QStringLiteral("bar"))); input.appendRow(createTaskItem(QStringLiteral("3. baz"), QStringLiteral("baz"))); - Presentation::ArtifactFilterProxyModel output; + Presentation::TaskFilterProxyModel output; output.setSourceModel(&input); // WHEN output.setFilterFixedString(QStringLiteral("find me")); // THEN QCOMPARE(output.rowCount(), 2); QCOMPARE(output.index(0, 0).data().toString(), QStringLiteral("1. foo")); QCOMPARE(output.index(1, 0).data().toString(), QStringLiteral("2. Find Me")); } void shouldFilterByStartDate() { // GIVEN QStandardItemModel input; const auto today = Utils::DateTime::currentDate(); input.appendRow(createTaskItem(QStringLiteral("1. past"), QStringLiteral(""), today.addDays(-1))); input.appendRow(createTaskItem(QStringLiteral("2. present"), QStringLiteral(""), today)); input.appendRow(createTaskItem(QStringLiteral("3. future"), QStringLiteral(""), today.addDays(1))); input.appendRow(createTaskItem(QStringLiteral("4. whatever"), QStringLiteral(""))); - Presentation::ArtifactFilterProxyModel output; + Presentation::TaskFilterProxyModel output; output.setSourceModel(&input); // WHEN output.setShowFutureTasks(true); // THEN QCOMPARE(output.rowCount(), 4); QCOMPARE(output.index(0, 0).data().toString(), QStringLiteral("1. past")); QCOMPARE(output.index(1, 0).data().toString(), QStringLiteral("2. present")); QCOMPARE(output.index(2, 0).data().toString(), QStringLiteral("3. future")); QCOMPARE(output.index(3, 0).data().toString(), QStringLiteral("4. whatever")); // WHEN output.setShowFutureTasks(false); // THEN QCOMPARE(output.rowCount(), 3); QCOMPARE(output.index(0, 0).data().toString(), QStringLiteral("1. past")); QCOMPARE(output.index(1, 0).data().toString(), QStringLiteral("2. present")); QCOMPARE(output.index(2, 0).data().toString(), QStringLiteral("4. whatever")); } void shouldKeepRowIfItHasAcceptableChildren() { // GIVEN QStandardItemModel input; input.appendRow(createTaskItem(QStringLiteral("1. foo"), QStringLiteral("find me"))); QStandardItem *item = createTaskItem(QStringLiteral("2. baz"), QStringLiteral("baz")); item->appendRow(createTaskItem(QStringLiteral("21. bar"), QStringLiteral("bar"))); item->appendRow(createTaskItem(QStringLiteral("22. find me"), QStringLiteral("foo"))); input.appendRow(item); input.appendRow(createTaskItem(QStringLiteral("3. baz"), QStringLiteral("baz"))); - Presentation::ArtifactFilterProxyModel output; + Presentation::TaskFilterProxyModel output; output.setSourceModel(&input); // WHEN output.setFilterFixedString(QStringLiteral("find me")); // THEN QCOMPARE(output.rowCount(), 2); QCOMPARE(output.index(0, 0).data().toString(), QStringLiteral("1. foo")); QCOMPARE(output.index(1, 0).data().toString(), QStringLiteral("2. baz")); const QModelIndex parent = output.index(1, 0); QCOMPARE(output.rowCount(parent), 1); QCOMPARE(output.index(0, 0, parent).data().toString(), QStringLiteral("22. find me")); } void shouldSortFollowingType_data() { QTest::addColumn("sortType"); QTest::addColumn("sortOrder"); QTest::addColumn>("inputItems"); QTest::addColumn("expectedOutputTitles"); QList inputItems; QStringList expectedOutputTitles; inputItems.clear(); expectedOutputTitles.clear(); inputItems << createTaskItem(QStringLiteral("B"), QStringLiteral("foo")) << createTaskItem(QStringLiteral("C"), QStringLiteral("foo")); expectedOutputTitles << QStringLiteral("B") << QStringLiteral("C"); - QTest::newRow("title ascending") << int(Presentation::ArtifactFilterProxyModel::TitleSort) + QTest::newRow("title ascending") << int(Presentation::TaskFilterProxyModel::TitleSort) << int(Qt::AscendingOrder) << inputItems << expectedOutputTitles; inputItems.clear(); expectedOutputTitles.clear(); inputItems << createTaskItem(QStringLiteral("B"), QStringLiteral("foo")) << createTaskItem(QStringLiteral("C"), QStringLiteral("foo")); expectedOutputTitles << QStringLiteral("C") << QStringLiteral("B"); - QTest::newRow("title descending") << int(Presentation::ArtifactFilterProxyModel::TitleSort) + QTest::newRow("title descending") << int(Presentation::TaskFilterProxyModel::TitleSort) << int(Qt::DescendingOrder) << inputItems << expectedOutputTitles; inputItems.clear(); expectedOutputTitles.clear(); inputItems << createTaskItem(QStringLiteral("B"), QStringLiteral("foo"), QDate(2014, 03, 10)) << createTaskItem(QStringLiteral("C"), QStringLiteral("foo"), QDate(2014, 03, 01)) << createTaskItem(QStringLiteral("D"), QStringLiteral("foo")); expectedOutputTitles << QStringLiteral("C") << QStringLiteral("B") << QStringLiteral("D"); - QTest::newRow("start date ascending") << int(Presentation::ArtifactFilterProxyModel::DateSort) + QTest::newRow("start date ascending") << int(Presentation::TaskFilterProxyModel::DateSort) << int(Qt::AscendingOrder) << inputItems << expectedOutputTitles; inputItems.clear(); expectedOutputTitles.clear(); inputItems << createTaskItem(QStringLiteral("B"), QStringLiteral("foo"), QDate(2014, 03, 10)) << createTaskItem(QStringLiteral("C"), QStringLiteral("foo"), QDate(2014, 03, 01)) << createTaskItem(QStringLiteral("D"), QStringLiteral("foo")); expectedOutputTitles << QStringLiteral("D") << QStringLiteral("B") << QStringLiteral("C"); - QTest::newRow("start date descending") << int(Presentation::ArtifactFilterProxyModel::DateSort) + QTest::newRow("start date descending") << int(Presentation::TaskFilterProxyModel::DateSort) << int(Qt::DescendingOrder) << inputItems << expectedOutputTitles; inputItems.clear(); expectedOutputTitles.clear(); inputItems << createTaskItem(QStringLiteral("B"), QStringLiteral("foo"), QDate(), QDate(2014, 03, 10)) << createTaskItem(QStringLiteral("C"), QStringLiteral("foo"), QDate(), QDate(2014, 03, 01)) << createTaskItem(QStringLiteral("D"), QStringLiteral("foo")); expectedOutputTitles << QStringLiteral("C") << QStringLiteral("B") << QStringLiteral("D"); - QTest::newRow("due date ascending") << int(Presentation::ArtifactFilterProxyModel::DateSort) + QTest::newRow("due date ascending") << int(Presentation::TaskFilterProxyModel::DateSort) << int(Qt::AscendingOrder) << inputItems << expectedOutputTitles; inputItems.clear(); expectedOutputTitles.clear(); inputItems << createTaskItem(QStringLiteral("B"), QStringLiteral("foo"), QDate(), QDate(2014, 03, 10)) << createTaskItem(QStringLiteral("C"), QStringLiteral("foo"), QDate(), QDate(2014, 03, 01)) << createTaskItem(QStringLiteral("D"), QStringLiteral("foo")); expectedOutputTitles << QStringLiteral("D") << QStringLiteral("B") << QStringLiteral("C"); - QTest::newRow("due date descending") << int(Presentation::ArtifactFilterProxyModel::DateSort) + QTest::newRow("due date descending") << int(Presentation::TaskFilterProxyModel::DateSort) << int(Qt::DescendingOrder) << inputItems << expectedOutputTitles; inputItems.clear(); expectedOutputTitles.clear(); inputItems << createTaskItem(QStringLiteral("A"), QStringLiteral("foo"), QDate(2014, 03, 01), QDate(2014, 03, 10)) << createTaskItem(QStringLiteral("B"), QStringLiteral("foo"), QDate(2014, 03, 10), QDate(2014, 03, 01)); expectedOutputTitles << QStringLiteral("B") << QStringLiteral("A"); - QTest::newRow("due date over start date") << int(Presentation::ArtifactFilterProxyModel::DateSort) + QTest::newRow("due date over start date") << int(Presentation::TaskFilterProxyModel::DateSort) << int(Qt::AscendingOrder) << inputItems << expectedOutputTitles; inputItems.clear(); expectedOutputTitles.clear(); inputItems << createTaskItem(QStringLiteral("A"), QStringLiteral("foo"), QDate(), QDate(2014, 03, 10)) << createTaskItem(QStringLiteral("B"), QStringLiteral("foo"), QDate(2014, 03, 01), QDate()); expectedOutputTitles << QStringLiteral("B") << QStringLiteral("A"); - QTest::newRow("due date over start date") << int(Presentation::ArtifactFilterProxyModel::DateSort) + QTest::newRow("due date over start date") << int(Presentation::TaskFilterProxyModel::DateSort) << int(Qt::AscendingOrder) << inputItems << expectedOutputTitles; } void shouldSortFollowingType() { // GIVEN QFETCH(int, sortType); QFETCH(int, sortOrder); QFETCH(QList, inputItems); QFETCH(QStringList, expectedOutputTitles); QStandardItemModel input; foreach (QStandardItem *item, inputItems) { input.appendRow(item); } // WHEN - Presentation::ArtifactFilterProxyModel output; + Presentation::TaskFilterProxyModel output; output.setSourceModel(&input); - output.setSortType(Presentation::ArtifactFilterProxyModel::SortType(sortType)); + output.setSortType(Presentation::TaskFilterProxyModel::SortType(sortType)); output.setSortOrder(Qt::SortOrder(sortOrder)); QStringList outputTitles; outputTitles.reserve(output.rowCount()); for (int row = 0; row < output.rowCount(); row++) { outputTitles << output.index(row, 0).data().toString(); } // THEN QCOMPARE(outputTitles, expectedOutputTitles); } }; -ZANSHIN_TEST_MAIN(ArtifactFilterProxyModelTest) +ZANSHIN_TEST_MAIN(TaskFilterProxyModelTest) -#include "artifactfilterproxymodeltest.moc" +#include "taskfilterproxymodeltest.moc" diff --git a/tests/units/widgets/applicationcomponentstest.cpp b/tests/units/widgets/applicationcomponentstest.cpp index 1f1967e9..a8498cb3 100644 --- a/tests/units/widgets/applicationcomponentstest.cpp +++ b/tests/units/widgets/applicationcomponentstest.cpp @@ -1,684 +1,684 @@ /* 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 "utils/mem_fn.h" #include "domain/task.h" -#include "presentation/artifactfilterproxymodel.h" +#include "presentation/taskfilterproxymodel.h" #include "presentation/querytreemodelbase.h" #include "widgets/applicationcomponents.h" #include "widgets/availablepagesview.h" #include "widgets/availablesourcesview.h" #include "widgets/editorview.h" #include "widgets/filterwidget.h" #include "widgets/pageview.h" #include "widgets/pageviewerrorhandler.h" #include "widgets/quickselectdialog.h" class CustomModelStub : public QStandardItemModel { Q_OBJECT QMimeData *mimeData(const QModelIndexList &indexes) const override { QStringList dataString; std::transform(indexes.begin(), indexes.end(), std::back_inserter(dataString), [] (const QModelIndex &index) { return index.data().toString(); }); auto data = new QMimeData; data->setData(QStringLiteral("application/x-zanshin-object"), "object"); data->setProperty("objects", QVariant::fromValue(dataString)); return data; } bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &destination) override { Q_UNUSED(action); Q_ASSERT(row == -1); Q_ASSERT(column == -1); Q_ASSERT(destination.isValid()); Q_ASSERT(data->hasFormat(QStringLiteral("application/x-zanshin-object"))); auto dataString = data->property("objects").toStringList(); Q_ASSERT(!dataString.isEmpty()); droppedItemDataString = dataString; dropDestination = destination.data().toString(); return true; } public: QStringList droppedItemDataString; QString dropDestination; }; class ApplicationModelStub : public QObject { Q_OBJECT Q_PROPERTY(QObject* currentPage READ currentPage WRITE setCurrentPage) public: typedef QSharedPointer Ptr; explicit ApplicationModelStub(QObject *parent = Q_NULLPTR) : QObject(parent), m_currentPage(Q_NULLPTR) {} QObject *currentPage() { return m_currentPage; } void setCurrentPage(QObject *page) { if (page == m_currentPage) return; m_currentPage = page; emit currentPageChanged(m_currentPage); } signals: void currentPageChanged(QObject *page); private: QObject *m_currentPage; }; class AvailablePagesModelStub : public QObject { Q_OBJECT Q_PROPERTY(QAbstractItemModel* pageListModel READ pageListModel) public: explicit AvailablePagesModelStub(QObject *parent = Q_NULLPTR) : QObject(parent) { QStandardItem *inbox = new QStandardItem; inbox->setData("Inbox", Qt::DisplayRole); itemModel.appendRow(inbox); QStandardItem *project = new QStandardItem; project->setData("Project", Qt::DisplayRole); itemModel.appendRow(project); } QAbstractItemModel *pageListModel() { return &itemModel; } Q_SCRIPTABLE QObject *createPageForIndex(const QModelIndex &index) { auto page = new QObject(this); auto model = new QStringListModel(page); model->setStringList(QStringList() << QStringLiteral("Items") << QStringLiteral("from") << index.data().toString()); page->setProperty("centralListModel", QVariant::fromValue(model)); createdPages << page; return page; } public: QList createdPages; CustomModelStub itemModel; }; class PageModelStub : public QObject { Q_OBJECT Q_PROPERTY(QAbstractItemModel* centralListModel READ centralListModel) public: QAbstractItemModel *centralListModel() { return &itemModel; } template void addItem(const QString &title) { auto artifact = T::Ptr::create(); artifact->setTitle(title); addItem(artifact); } void addItem(const Domain::Artifact::Ptr &artifact) { QStandardItem *item = new QStandardItem; item->setData(QVariant::fromValue(artifact), Presentation::QueryTreeModelBase::ObjectRole); item->setData(artifact->title(), Qt::DisplayRole); itemModel.appendRow(item); } Domain::Artifact::Ptr itemAtRow(int row) const { return itemModel.index(row, 0).data(Presentation::QueryTreeModelBase::ObjectRole) .value(); } QModelIndexList selectedIndexes() const { return selectedItems; } public: QModelIndexList selectedItems; CustomModelStub itemModel; }; class EditorModelStub : public QObject { Q_OBJECT public: explicit EditorModelStub(QObject *parent = Q_NULLPTR) : QObject(parent) { } void setPropertyAndSignal(const QByteArray &name, const QVariant &value) { if (property(name) == value) return; setProperty(name, value); 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.toDate()); else if (name == "dueDate") emit dueDateChanged(value.toDate()); else qFatal("Unsupported property %s", name.constData()); } public slots: 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 QDate &start) { setPropertyAndSignal("startDate", start); } void setDueDate(const QDate &due) { setPropertyAndSignal("dueDate", due); } signals: void textChanged(const QString &text); void titleChanged(const QString &title); void doneChanged(bool done); void startDateChanged(const QDate &date); void dueDateChanged(const QDate &due); }; class QuickSelectDialogStub : public Widgets::QuickSelectDialogInterface { public: typedef QSharedPointer Ptr; explicit QuickSelectDialogStub() : parent(Q_NULLPTR), execCount(0), itemModel(Q_NULLPTR) { } int exec() Q_DECL_OVERRIDE { execCount++; return QDialog::Accepted; } void setModel(QAbstractItemModel *model) Q_DECL_OVERRIDE { itemModel = model; } QPersistentModelIndex selectedIndex() const Q_DECL_OVERRIDE { return index; } QWidget *parent; int execCount; QAbstractItemModel *itemModel; QPersistentModelIndex index; }; class ApplicationComponentsTest : public QObject { Q_OBJECT public: explicit ApplicationComponentsTest(QObject *parent = Q_NULLPTR) : QObject(parent) { qputenv("ZANSHIN_UNIT_TEST_RUN", "1"); } private slots: void shouldHaveApplicationModelAndSetErrorHandler() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); // WHEN components.setModel(model); // THEN QCOMPARE(components.model(), model); auto errorHandlerBase = model->property("errorHandler").value(); QVERIFY(errorHandlerBase); auto errorHandler = static_cast(errorHandlerBase); QVERIFY(errorHandler); QVERIFY(!errorHandler->pageView()); // WHEN auto pageView = components.pageView(); // THEN QCOMPARE(errorHandler->pageView(), pageView); } void shouldApplyAvailableSourcesModelToAvailableSourcesView() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); QObject availableSources; model->setProperty("availableSources", QVariant::fromValue(&availableSources)); // WHEN components.setModel(model); // THEN QCOMPARE(components.availableSourcesView()->model(), &availableSources); } void shouldApplyAvailableSourcesModelAlsoToCreatedAvailableSourcesView() { // GIVEN Widgets::ApplicationComponents components; // Force creation components.availableSourcesView(); auto model = QObjectPtr::create(); QObject availableSources; model->setProperty("availableSources", QVariant::fromValue(&availableSources)); // WHEN components.setModel(model); // THEN QCOMPARE(components.availableSourcesView()->model(), &availableSources); } void shouldApplyAvailablePagesModelToAvailablePagesView() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); QObject availablePages; model->setProperty("availablePages", QVariant::fromValue(&availablePages)); QObject availableSources; QAbstractItemModel *sourcesModel = new QStandardItemModel(model.data()); availableSources.setProperty("sourceListModel", QVariant::fromValue(sourcesModel)); model->setProperty("availableSources", QVariant::fromValue(&availableSources)); // WHEN components.setModel(model); // THEN QCOMPARE(components.availablePagesView()->model(), &availablePages); QCOMPARE(components.availablePagesView()->projectSourcesModel(), sourcesModel); } void shouldApplyAvailablePagesModelAlsoToCreatedAvailablePagesView() { // GIVEN Widgets::ApplicationComponents components; // Force creation components.availablePagesView(); auto model = QObjectPtr::create(); QObject availablePages; QAbstractItemModel *sourcesModel = new QStandardItemModel(model.data()); model->setProperty("dataSourcesModel", QVariant::fromValue(sourcesModel)); model->setProperty("availablePages", QVariant::fromValue(&availablePages)); // WHEN components.setModel(model); // THEN QCOMPARE(components.availablePagesView()->model(), &availablePages); QCOMPARE(components.availablePagesView()->projectSourcesModel(), sourcesModel); } void shouldApplyCurrentPageModelToPageView() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); QObject currentPage; model->setProperty("currentPage", QVariant::fromValue(¤tPage)); // WHEN components.setModel(model); // THEN QCOMPARE(components.pageView()->model(), ¤tPage); } void shouldApplyCurrentPageModelAlsoToCreatedPageView() { // GIVEN Widgets::ApplicationComponents components; // Force creation components.pageView(); auto model = QObjectPtr::create(); QObject currentPage; model->setProperty("currentPage", QVariant::fromValue(¤tPage)); // WHEN components.setModel(model); // THEN QCOMPARE(components.pageView()->model(), ¤tPage); } void shouldApplyEditorModelToEditorView() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); QObject *editorModel = new EditorModelStub(model.data()); model->setProperty("editor", QVariant::fromValue(editorModel)); // WHEN components.setModel(model); // THEN QCOMPARE(components.editorView()->model(), editorModel); } void shouldApplyEditorModelAltoToCreatedPageView() { // GIVEN Widgets::ApplicationComponents components; // Force creation components.editorView(); auto model = QObjectPtr::create(); QObject *editorModel = new EditorModelStub(model.data()); model->setProperty("editor", QVariant::fromValue(editorModel)); // WHEN components.setModel(model); // THEN QCOMPARE(components.editorView()->model(), editorModel); } void shouldPropageNullModelsToViews() { // GIVEN Widgets::ApplicationComponents components; auto model = QObjectPtr::create(); auto availableSources = new QObject(model.data()); model->setProperty("availableSources", QVariant::fromValue(availableSources)); auto availablePages = new QObject(model.data()); model->setProperty("availablePages", QVariant::fromValue(availablePages)); auto currentPage = new QObject(model.data()); model->setProperty("currentPage", QVariant::fromValue(currentPage)); auto editorModel = new EditorModelStub(model.data()); model->setProperty("editor", QVariant::fromValue(editorModel)); components.setModel(model); // WHEN components.setModel(QObjectPtr()); components.availableSourcesView(); components.availablePagesView(); components.pageView(); components.editorView(); // THEN QVERIFY(!components.availableSourcesView()->model()); QVERIFY(!components.availablePagesView()->model()); QVERIFY(!components.pageView()->model()); QVERIFY(!components.editorView()->model()); } void shouldPropageNullModelsToCreatedViews() { // GIVEN Widgets::ApplicationComponents components; components.availableSourcesView(); components.availablePagesView(); components.pageView(); components.editorView(); auto model = QObjectPtr::create(); auto availableSources = new QObject(model.data()); model->setProperty("availableSources", QVariant::fromValue(availableSources)); auto availablePages = new QObject(model.data()); model->setProperty("availablePages", QVariant::fromValue(availablePages)); auto currentPage = new QObject(model.data()); model->setProperty("currentPage", QVariant::fromValue(currentPage)); auto editorModel = new EditorModelStub(model.data()); model->setProperty("editor", QVariant::fromValue(editorModel)); components.setModel(model); // WHEN components.setModel(QObjectPtr()); // THEN QVERIFY(!components.availableSourcesView()->model()); QVERIFY(!components.availablePagesView()->model()); QVERIFY(!components.pageView()->model()); QVERIFY(!components.editorView()->model()); } void shouldApplyAvailablePagesSelectionToApplicationModel() { // GIVEN auto model = ApplicationModelStub::Ptr::create(); AvailablePagesModelStub availablePagesModel; model->setProperty("availablePages", QVariant::fromValue(&availablePagesModel)); model->setProperty("currentPage", QVariant::fromValue(Q_NULLPTR)); QObject editorModel; editorModel.setProperty("artifact", QVariant::fromValue(Domain::Task::Ptr::create())); model->setProperty("editor", QVariant::fromValue(&editorModel)); Widgets::ApplicationComponents components; components.setModel(model); Widgets::AvailablePagesView *availablePagesView = components.availablePagesView(); auto pagesView = availablePagesView->findChild(QStringLiteral("pagesView")); QVERIFY(pagesView); Widgets::PageView *pageView = components.pageView(); QVERIFY(pageView); QVERIFY(!pageView->model()); QModelIndex index = pagesView->model()->index(0, 0); // WHEN pagesView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); // THEN QCOMPARE(availablePagesModel.createdPages.size(), 1); QCOMPARE(model->property("currentPage").value(), availablePagesModel.createdPages.first()); QCOMPARE(pageView->model(), availablePagesModel.createdPages.first()); QVERIFY(editorModel.property("artifact").value().isNull()); } void shouldApplyPageViewSelectionToEditorModel() { // GIVEN auto model = QObjectPtr::create(); PageModelStub pageModel; pageModel.addItem(QStringLiteral("0. First task")); pageModel.addItem(QStringLiteral("1. Second task")); pageModel.addItem(QStringLiteral("2. Third task")); pageModel.addItem(QStringLiteral("3. Yet another task")); model->setProperty("currentPage", QVariant::fromValue(&pageModel)); EditorModelStub editorModel; model->setProperty("editor", QVariant::fromValue(&editorModel)); Widgets::ApplicationComponents components; components.setModel(model); Widgets::PageView *pageView = components.pageView(); auto centralView = pageView->findChild(QStringLiteral("centralView")); QModelIndex index = centralView->model()->index(2, 0); // WHEN centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); // THEN QCOMPARE(editorModel.property("artifact").value(), pageModel.itemAtRow(index.row())); } void shouldHaveDefaultActionsList() { // GIVEN Widgets::ApplicationComponents components; // WHEN auto actions = components.globalActions(); // THEN // availablePages view auto available = components.availablePagesView(); foreach (const auto &key, available->globalActions().keys()) QCOMPARE(actions.value(key), available->globalActions().value(key)); // availableSources view auto availableSources = components.availableSourcesView(); foreach (const auto &key, availableSources->globalActions().keys()) QCOMPARE(actions.value(key), availableSources->globalActions().value(key)); // page view auto page = components.pageView(); foreach (const auto &key, page->globalActions().keys()) QCOMPARE(actions.value(key), page->globalActions().value(key)); // application component own action auto moveAction = components.findChild(QStringLiteral("moveItemAction")); QCOMPARE(actions.value(QStringLiteral("page_view_move")), moveAction); } void shouldMoveItem() { // GIVEN auto model = QObjectPtr::create(); PageModelStub pageModel; pageModel.addItem(QStringLiteral("0. First task")); pageModel.addItem(QStringLiteral("1. Second task")); pageModel.addItem(QStringLiteral("2. Third task")); pageModel.addItem(QStringLiteral("3. Yet another task")); model->setProperty("currentPage", QVariant::fromValue(&pageModel)); AvailablePagesModelStub availablePagesModelStub; model->setProperty("availablePages", QVariant::fromValue(&availablePagesModelStub)); QWidget *mainWidget = new QWidget; Widgets::ApplicationComponents components(mainWidget); components.setModel(model); auto availablePageView = components.availablePagesView(); auto availablePagesTreeView = availablePageView->findChild(QStringLiteral("pagesView")); Q_ASSERT(availablePagesTreeView); auto dialogStub = QuickSelectDialogStub::Ptr::create(); dialogStub->index = availablePagesModelStub.pageListModel()->index(0, 0); // inbox selected components.setQuickSelectDialogFactory([dialogStub] (QWidget *parent) { dialogStub->parent = parent; return dialogStub; }); auto pageView = components.pageView(); auto centralView = pageView->findChild(QStringLiteral("centralView")); QModelIndex index1 = pageModel.itemModel.index(0,0); QModelIndex index2 = pageModel.itemModel.index(2,0); auto filterWidget = pageView->findChild(QStringLiteral("filterWidget")); auto displayedModel = filterWidget->proxyModel(); auto displayedIndex = displayedModel->index(0, 0); auto displayedIndex2 = displayedModel->index(2, 0); auto moveAction = components.findChild(QStringLiteral("moveItemAction")); // WHEN pageModel.selectedItems << index1 << index2; centralView->selectionModel()->setCurrentIndex(displayedIndex, QItemSelectionModel::ClearAndSelect); centralView->selectionModel()->setCurrentIndex(displayedIndex2, QItemSelectionModel::Select); moveAction->trigger(); // THEN QCOMPARE(dialogStub->execCount, 1); QCOMPARE(dialogStub->parent, pageView); QCOMPARE(dialogStub->itemModel, availablePagesModelStub.pageListModel()); QCOMPARE(availablePagesModelStub.itemModel.dropDestination, QStringLiteral("Inbox")); QCOMPARE(availablePagesModelStub.itemModel.droppedItemDataString.size(), 2); QCOMPARE(availablePagesModelStub.itemModel.droppedItemDataString.at(0), index1.data().toString()); QCOMPARE(availablePagesModelStub.itemModel.droppedItemDataString.at(1), index2.data().toString()); } }; ZANSHIN_TEST_MAIN(ApplicationComponentsTest) #include "applicationcomponentstest.moc" diff --git a/tests/units/widgets/filterwidgettest.cpp b/tests/units/widgets/filterwidgettest.cpp index 71049f02..123b72f9 100644 --- a/tests/units/widgets/filterwidgettest.cpp +++ b/tests/units/widgets/filterwidgettest.cpp @@ -1,217 +1,217 @@ /* 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 "widgets/filterwidget.h" -#include "presentation/artifactfilterproxymodel.h" +#include "presentation/taskfilterproxymodel.h" class FilterWidgetTest : public QObject { Q_OBJECT private slots: void shouldHaveDefaultState() { Widgets::FilterWidget filter; QVERIFY(filter.proxyModel()); QVERIFY(!filter.proxyModel()->sourceModel()); QCOMPARE(filter.proxyModel()->filterRegExp(), QRegExp()); QCOMPARE(filter.proxyModel()->sortOrder(), Qt::AscendingOrder); - QCOMPARE(filter.proxyModel()->sortType(), Presentation::ArtifactFilterProxyModel::TitleSort); + QCOMPARE(filter.proxyModel()->sortType(), Presentation::TaskFilterProxyModel::TitleSort); QLineEdit *filterEdit = filter.findChild(QStringLiteral("filterEdit")); QVERIFY(filterEdit); QVERIFY(filterEdit->isVisibleTo(&filter)); QVERIFY(filterEdit->text().isEmpty()); QCOMPARE(filterEdit->placeholderText(), i18n("Filter...")); auto extensionButton = filter.findChild(QStringLiteral("extensionButton")); QVERIFY(extensionButton); QVERIFY(extensionButton->isVisibleTo(&filter)); QVERIFY(!extensionButton->isChecked()); QVERIFY(extensionButton->autoRaise()); QComboBox *sortTypeCombo = filter.findChild(QStringLiteral("sortTypeCombo")); QVERIFY(sortTypeCombo); QVERIFY(!sortTypeCombo->isVisibleTo(&filter)); QCOMPARE(sortTypeCombo->currentIndex(), 0); auto ascendingButton = filter.findChild(QStringLiteral("ascendingButton")); QVERIFY(ascendingButton); QVERIFY(!ascendingButton->isVisibleTo(&filter)); QVERIFY(ascendingButton->isChecked()); QVERIFY(ascendingButton->autoRaise()); auto descendingButton = filter.findChild(QStringLiteral("descendingButton")); QVERIFY(descendingButton); QVERIFY(!descendingButton->isVisibleTo(&filter)); QVERIFY(!descendingButton->isChecked()); QVERIFY(descendingButton->autoRaise()); } void shouldChangeAppliedFilter() { // GIVEN Widgets::FilterWidget filter; QLineEdit *filterEdit = filter.findChild(QStringLiteral("filterEdit")); QVERIFY(filterEdit); // WHEN QTest::keyClicks(filterEdit, QStringLiteral("find me")); // THEN QCOMPARE(filter.proxyModel()->filterRegExp().pattern(), QStringLiteral("find me")); } void shouldClearFilter() { // GIVEN Widgets::FilterWidget filter; QLineEdit *filterEdit = filter.findChild(QStringLiteral("filterEdit")); QVERIFY(filterEdit); filterEdit->setText("Foo"); // WHEN filter.clear(); // THEN QVERIFY(filterEdit->text().isEmpty()); QVERIFY(filter.proxyModel()->filterRegExp().pattern().isEmpty()); } void shouldShowExtension() { // GIVEN Widgets::FilterWidget filter; QAbstractButton *extensionButton = filter.findChild(QStringLiteral("extensionButton")); QVERIFY(extensionButton); QComboBox *sortTypeCombo = filter.findChild(QStringLiteral("sortTypeCombo")); QVERIFY(sortTypeCombo); QAbstractButton *ascendingButton = filter.findChild(QStringLiteral("ascendingButton")); QVERIFY(ascendingButton); QAbstractButton *descendingButton = filter.findChild(QStringLiteral("descendingButton")); QVERIFY(descendingButton); // WHEN extensionButton->click(); // THEN QVERIFY(extensionButton->isChecked()); QVERIFY(sortTypeCombo->isVisibleTo(&filter)); QVERIFY(descendingButton->isVisibleTo(&filter)); QVERIFY(descendingButton->isVisibleTo(&filter)); // WHEN extensionButton->click(); // THEN QVERIFY(!extensionButton->isChecked()); QVERIFY(!sortTypeCombo->isVisibleTo(&filter)); QVERIFY(!descendingButton->isVisibleTo(&filter)); QVERIFY(!descendingButton->isVisibleTo(&filter)); } void shouldChangeSortType() { // GIVEN Widgets::FilterWidget filter; QComboBox *sortTypeCombo = filter.findChild(QStringLiteral("sortTypeCombo")); QVERIFY(sortTypeCombo); // WHEN sortTypeCombo->setCurrentIndex(1); // THEN - QCOMPARE(filter.proxyModel()->sortType(), Presentation::ArtifactFilterProxyModel::DateSort); + QCOMPARE(filter.proxyModel()->sortType(), Presentation::TaskFilterProxyModel::DateSort); // WHEN sortTypeCombo->setCurrentIndex(0); // THEN - QCOMPARE(filter.proxyModel()->sortType(), Presentation::ArtifactFilterProxyModel::TitleSort); + QCOMPARE(filter.proxyModel()->sortType(), Presentation::TaskFilterProxyModel::TitleSort); } void shouldChangeSortOrder() { // GIVEN Widgets::FilterWidget filter; QAbstractButton *ascendingButton = filter.findChild(QStringLiteral("ascendingButton")); QVERIFY(ascendingButton); QAbstractButton *descendingButton = filter.findChild(QStringLiteral("descendingButton")); QVERIFY(descendingButton); // WHEN descendingButton->click(); // THEN QVERIFY(!ascendingButton->isChecked()); QVERIFY(descendingButton->isChecked()); QCOMPARE(filter.proxyModel()->sortOrder(), Qt::DescendingOrder); // WHEN ascendingButton->click(); // THEN QVERIFY(ascendingButton->isChecked()); QVERIFY(!descendingButton->isChecked()); QCOMPARE(filter.proxyModel()->sortOrder(), Qt::AscendingOrder); } void shouldShowFutureTasks() { // GIVEN Widgets::FilterWidget filter; filter.setShowFutureTasks(false); // THEN QVERIFY(!filter.proxyModel()->showFutureTasks()); // WHEN filter.setShowFutureTasks(true); // THEN QVERIFY(filter.proxyModel()->showFutureTasks()); } }; ZANSHIN_TEST_MAIN(FilterWidgetTest) #include "filterwidgettest.moc" diff --git a/tests/units/widgets/pageviewtest.cpp b/tests/units/widgets/pageviewtest.cpp index 3a76a098..0cebe982 100644 --- a/tests/units/widgets/pageviewtest.cpp +++ b/tests/units/widgets/pageviewtest.cpp @@ -1,899 +1,899 @@ /* 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 #include #include #include #include #include #include #include #include #include #include "domain/task.h" -#include "presentation/artifactfilterproxymodel.h" +#include "presentation/taskfilterproxymodel.h" #include "presentation/metatypes.h" #include "presentation/querytreemodelbase.h" #include "widgets/filterwidget.h" #include "widgets/itemdelegate.h" #include "widgets/pageview.h" #include "messageboxstub.h" class PageModelStub : public QObject { Q_OBJECT Q_PROPERTY(QAbstractItemModel* centralListModel READ centralListModel) public: void setProxyModel(QAbstractProxyModel *proxy) { proxyModel = proxy; proxyModel->setSourceModel(&itemModel); } QAbstractItemModel *centralListModel() { if (proxyModel) return proxyModel; return &itemModel; } QStandardItem *addStubItem(const QString &title, QStandardItem *parentItem = Q_NULLPTR) { QStandardItem *item = new QStandardItem; item->setData(title, Qt::DisplayRole); if (!parentItem) itemModel.appendRow(item); else 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) { foreach (const QString &title, list) { addStubItem(title); } } public slots: void addItem(const QString &name, const QModelIndex &parentIndex) { taskNames << name; parentIndices << parentIndex; } void removeItem(const QModelIndex &index) { removedIndices << index; } void promoteItem(const QModelIndex &index) { promotedIndices << index; } public: QStringList taskNames; QList parentIndices; QList removedIndices; QList promotedIndices; QStandardItemModel itemModel; QAbstractProxyModel *proxyModel = nullptr; }; 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; } void taskDeleted(const Domain::Task::Ptr &task) Q_DECL_OVERRIDE { m_deletedTask = task; } void stopTask() Q_DECL_OVERRIDE {} void doneTask() Q_DECL_OVERRIDE {} private: Domain::Task::Ptr m_runningTask; Domain::Task::Ptr m_deletedTask; }; class PageViewTest : public QObject { Q_OBJECT private: KConfigGroup configGroup() { return KConfigGroup(KSharedConfig::openConfig(), "General"); } private slots: void shouldHaveDefaultState() { Widgets::PageView page; QCOMPARE(page.contentsMargins(), QMargins(0, 0, 0, 0)); QCOMPARE(page.layout()->contentsMargins(), QMargins(0, 0, 0, 3)); auto messageWidget = page.findChild(QStringLiteral("messageWidget")); QVERIFY(messageWidget); QVERIFY(!messageWidget->isVisibleTo(&page)); QVERIFY(!messageWidget->isCloseButtonVisible()); QVERIFY(messageWidget->wordWrap()); QVERIFY(messageWidget->text().isEmpty()); QVERIFY(messageWidget->icon().isNull()); QCOMPARE(messageWidget->messageType(), KMessageWidget::Error); QVERIFY(!messageWidget->isShowAnimationRunning()); QVERIFY(!messageWidget->isHideAnimationRunning()); auto centralView = page.findChild(QStringLiteral("centralView")); QVERIFY(centralView); QVERIFY(centralView->isVisibleTo(&page)); QVERIFY(!centralView->header()->isVisibleTo(&page)); QVERIFY(qobject_cast(centralView->itemDelegate())); QVERIFY(centralView->alternatingRowColors()); QCOMPARE(centralView->dragDropMode(), QTreeView::DragDrop); auto filter = page.findChild(QStringLiteral("filterWidget")); QVERIFY(filter); QVERIFY(!filter->isVisibleTo(&page)); QVERIFY(filter->proxyModel()); QCOMPARE(filter->proxyModel(), centralView->model()); QLineEdit *quickAddEdit = page.findChild(QStringLiteral("quickAddEdit")); QVERIFY(quickAddEdit); QVERIFY(quickAddEdit->isVisibleTo(&page)); QVERIFY(quickAddEdit->text().isEmpty()); QCOMPARE(quickAddEdit->placeholderText(), i18n("Type and press enter to add an item")); auto addAction = page.findChild(QStringLiteral("addItemAction")); QVERIFY(addAction); auto cancelAddAction = page.findChild(QStringLiteral("cancelAddItemAction")); QVERIFY(cancelAddAction); auto removeAction = page.findChild(QStringLiteral("removeItemAction")); QVERIFY(removeAction); auto promoteAction = page.findChild(QStringLiteral("promoteItemAction")); QVERIFY(promoteAction); auto filterAction = page.findChild(QStringLiteral("filterViewAction")); QVERIFY(filterAction); QVERIFY(filterAction->isCheckable()); QVERIFY(!filterAction->isChecked()); auto futureAction = page.findChild(QStringLiteral("futureViewAction")); QVERIFY(futureAction); QVERIFY(futureAction->isCheckable()); QVERIFY(futureAction->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_view_future")), futureAction); QCOMPARE(actions.value(QStringLiteral("page_run_task")), runTaskAction); } void shouldDisplayListFromPageModel() { // GIVEN QStandardItemModel model; QObject stubPageModel; stubPageModel.setProperty("centralListModel", QVariant::fromValue(static_cast(&model))); Widgets::PageView page; auto centralView = page.findChild(QStringLiteral("centralView")); QVERIFY(centralView); - auto proxyModel = qobject_cast(centralView->model()); + auto proxyModel = qobject_cast(centralView->model()); QVERIFY(proxyModel); QVERIFY(!proxyModel->sourceModel()); // WHEN page.setModel(&stubPageModel); // THEN QCOMPARE(page.model(), &stubPageModel); QVERIFY(page.isEnabled()); QCOMPARE(proxyModel->sourceModel(), &model); } void shouldNotCrashWithNullModel() { // GIVEN QStandardItemModel model; QObject stubPageModel; stubPageModel.setProperty("centralListModel", QVariant::fromValue(static_cast(&model))); Widgets::PageView page; page.setModel(&stubPageModel); auto centralView = page.findChild(QStringLiteral("centralView")); QVERIFY(centralView); - auto proxyModel = qobject_cast(centralView->model()); + auto proxyModel = qobject_cast(centralView->model()); QVERIFY(proxyModel); QCOMPARE(proxyModel->sourceModel(), &model); // WHEN page.setModel(Q_NULLPTR); // THEN QVERIFY(!page.model()); QVERIFY(!page.isEnabled()); QVERIFY(!proxyModel->sourceModel()); } void shouldManageFocusThroughActions() { // GIVEN Widgets::PageView page; auto centralView = page.findChild(QStringLiteral("centralView")); auto quickAddEdit = page.findChild(QStringLiteral("quickAddEdit")); auto filter = page.findChild(QStringLiteral("filterWidget")); auto filterEdit = filter->findChild(); QVERIFY(filterEdit); page.show(); QVERIFY(QTest::qWaitForWindowShown(&page)); centralView->setFocus(); QVERIFY(centralView->hasFocus()); QVERIFY(!quickAddEdit->hasFocus()); QVERIFY(!filter->isVisibleTo(&page)); QVERIFY(!filterEdit->hasFocus()); auto addAction = page.findChild(QStringLiteral("addItemAction")); auto cancelAddAction = page.findChild(QStringLiteral("cancelAddItemAction")); auto filterAction = page.findChild(QStringLiteral("filterViewAction")); // WHEN addAction->trigger(); // THEN QVERIFY(!centralView->hasFocus()); QVERIFY(quickAddEdit->hasFocus()); QVERIFY(!filter->isVisibleTo(&page)); QVERIFY(!filterEdit->hasFocus()); // WHEN cancelAddAction->trigger(); // THEN QVERIFY(centralView->hasFocus()); QVERIFY(!quickAddEdit->hasFocus()); QVERIFY(!filter->isVisibleTo(&page)); QVERIFY(!filterEdit->hasFocus()); // WHEN filterAction->trigger(); // THEN QVERIFY(!centralView->hasFocus()); QVERIFY(!quickAddEdit->hasFocus()); QVERIFY(filter->isVisibleTo(&page)); QVERIFY(filterEdit->hasFocus()); // WHEN cancelAddAction->trigger(); // THEN QVERIFY(centralView->hasFocus()); QVERIFY(!quickAddEdit->hasFocus()); QVERIFY(filter->isVisibleTo(&page)); QVERIFY(!filterEdit->hasFocus()); } void shouldManageFilterVisibilityThroughAction() { // GIVEN Widgets::PageView page; auto centralView = page.findChild(QStringLiteral("centralView")); auto filter = page.findChild(QStringLiteral("filterWidget")); auto filterEdit = filter->findChild(); QVERIFY(filterEdit); page.show(); QVERIFY(QTest::qWaitForWindowShown(&page)); centralView->setFocus(); QVERIFY(centralView->hasFocus()); QVERIFY(!filter->isVisibleTo(&page)); QVERIFY(!filterEdit->hasFocus()); auto filterAction = page.findChild(QStringLiteral("filterViewAction")); // WHEN filterAction->trigger(); // THEN QVERIFY(!centralView->hasFocus()); QVERIFY(filter->isVisibleTo(&page)); QVERIFY(filterEdit->hasFocus()); // WHEN filterEdit->setText("Foo"); // THEN QCOMPARE(filterEdit->text(), QString("Foo")); // WHEN filterAction->trigger(); // THEN QVERIFY(centralView->hasFocus()); QVERIFY(!filter->isVisibleTo(&page)); QVERIFY(!filterEdit->hasFocus()); QVERIFY(filterEdit->text().isEmpty()); } void shouldManageFutureTasksVisibilityThroughAction() { // GIVEN Widgets::PageView page; auto filter = page.findChild(QStringLiteral("filterWidget")); auto filterProxy = filter->proxyModel(); QVERIFY(filterProxy); QVERIFY(filterProxy->showFutureTasks()); auto futureAction = page.findChild(QStringLiteral("futureViewAction")); // WHEN futureAction->trigger(); // THEN QVERIFY(!filterProxy->showFutureTasks()); // WHEN futureAction->trigger(); // THEN QVERIFY(filterProxy->showFutureTasks()); } void shouldStoreFutureTasksVisibilityDefaultState() { // GIVEN configGroup().deleteEntry("ShowFuture"); { Widgets::PageView page; auto futureAction = page.findChild(QStringLiteral("futureViewAction")); // THEN QVERIFY(futureAction->isChecked()); } // WHEN configGroup().writeEntry("ShowFuture", false); { Widgets::PageView page; auto futureAction = page.findChild(QStringLiteral("futureViewAction")); // THEN QVERIFY(!futureAction->isChecked()); } // WHEN configGroup().writeEntry("ShowFuture", true); { Widgets::PageView page; auto futureAction = page.findChild(QStringLiteral("futureViewAction")); // THEN QVERIFY(futureAction->isChecked()); } // WHEN configGroup().deleteEntry("ShowFuture"); { Widgets::PageView page; auto futureAction = page.findChild(QStringLiteral("futureViewAction")); // THEN QVERIFY(futureAction->isChecked()); } // WHEN Widgets::PageView page; auto futureAction = page.findChild(QStringLiteral("futureViewAction")); futureAction->trigger(); // THEN QVERIFY(configGroup().hasKey("ShowFuture")); QVERIFY(!configGroup().readEntry("ShowFuture", true)); // WHEN futureAction->trigger(); // THEN QVERIFY(configGroup().hasKey("ShowFuture")); QVERIFY(configGroup().readEntry("ShowFuture", false)); } void shouldCreateTasksWithNoParentWhenHittingReturnWithoutSelectedIndex() { // GIVEN PageModelStub stubPageModel; Widgets::PageView page; page.setModel(&stubPageModel); auto quickAddEdit = page.findChild(QStringLiteral("quickAddEdit")); // WHEN QTest::keyClick(quickAddEdit, Qt::Key_Return); // Does nothing (edit empty) QTest::keyClicks(quickAddEdit, QStringLiteral("Foo")); QTest::keyClick(quickAddEdit, Qt::Key_Return); QTest::keyClick(quickAddEdit, Qt::Key_Return); // Does nothing (edit empty) QTest::keyClicks(quickAddEdit, QStringLiteral("Bar")); QTest::keyClick(quickAddEdit, Qt::Key_Return); QTest::keyClick(quickAddEdit, Qt::Key_Return); // Does nothing (edit empty) // THEN QCOMPARE(stubPageModel.taskNames, QStringList() << QStringLiteral("Foo") << QStringLiteral("Bar")); QCOMPARE(stubPageModel.parentIndices.size(), 2); QCOMPARE(stubPageModel.parentIndices.first(), QPersistentModelIndex()); QCOMPARE(stubPageModel.parentIndices.last(), QPersistentModelIndex()); } void shouldCreateTasksWithNoParentWhenHittingReturnWithSeveralSelectedIndices() { // GIVEN PageModelStub stubPageModel; Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C")); QPersistentModelIndex index0 = stubPageModel.itemModel.index(0, 0); QPersistentModelIndex index1 = stubPageModel.itemModel.index(1, 0); Widgets::PageView page; page.setModel(&stubPageModel); auto centralView = page.findChild(QStringLiteral("centralView")); centralView->selectionModel()->select(index0, QItemSelectionModel::ClearAndSelect); centralView->selectionModel()->select(index1, QItemSelectionModel::Select); auto quickAddEdit = page.findChild(QStringLiteral("quickAddEdit")); // WHEN QTest::keyClicks(quickAddEdit, QStringLiteral("Foo")); QTest::keyClick(quickAddEdit, Qt::Key_Return); // THEN QCOMPARE(stubPageModel.taskNames, QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C") << QStringLiteral("Foo")); QCOMPARE(stubPageModel.parentIndices.size(), 1); QCOMPARE(stubPageModel.parentIndices.first(), QPersistentModelIndex()); } void shouldCreateTasksWithParentWhenHittingReturnWithOneSelectedIndex() { // GIVEN PageModelStub stubPageModel; Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C")); QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0); Widgets::PageView page; page.setModel(&stubPageModel); auto centralView = page.findChild(QStringLiteral("centralView")); centralView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); auto quickAddEdit = page.findChild(QStringLiteral("quickAddEdit")); // WHEN QTest::keyClicks(quickAddEdit, QStringLiteral("Foo")); QTest::keyClick(quickAddEdit, Qt::Key_Return); // THEN QCOMPARE(stubPageModel.taskNames, QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C") << QStringLiteral("Foo")); QCOMPARE(stubPageModel.parentIndices.size(), 1); QCOMPARE(stubPageModel.parentIndices.first(), index); } void shouldDeleteItemWhenHittingTheDeleteKey() { // GIVEN PageModelStub stubPageModel; Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C")); QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0); Widgets::PageView page; page.setModel(&stubPageModel); QTreeView *centralView = page.findChild(QStringLiteral("centralView")); centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); centralView->setFocus(); // Needed for shortcuts to work page.show(); QVERIFY(QTest::qWaitForWindowShown(&page)); QTest::qWait(100); // WHEN QTest::keyPress(centralView, Qt::Key_Delete); // THEN QCOMPARE(stubPageModel.removedIndices.size(), 1); QCOMPARE(stubPageModel.removedIndices.first(), index); } void shouldNotTryToDeleteIfThereIsNoSelection() { // GIVEN PageModelStub stubPageModel; Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C")); Widgets::PageView page; page.setModel(&stubPageModel); QTreeView *centralView = page.findChild(QStringLiteral("centralView")); centralView->clearSelection(); page.findChild(QStringLiteral("quickAddEdit"))->setFocus(); // Needed for shortcuts to work page.show(); QVERIFY(QTest::qWaitForWindowShown(&page)); QTest::qWait(100); // WHEN QTest::keyPress(centralView, Qt::Key_Delete); // THEN QVERIFY(stubPageModel.removedIndices.isEmpty()); } void shouldDisplayNotificationWhenHittingTheDeleteKeyOnAnItemWithChildren() { // GIVEN PageModelStub stubPageModel; Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B")); QStandardItem *parentIndex = stubPageModel.itemModel.item(1, 0); stubPageModel.addStubItem(QStringLiteral("C"), parentIndex); QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0); Widgets::PageView page; page.setModel(&stubPageModel); auto msgbox = MessageBoxStub::Ptr::create(); page.setMessageBoxInterface(msgbox); QTreeView *centralView = page.findChild(QStringLiteral("centralView")); centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); QVERIFY(centralView->selectionModel()->currentIndex().isValid()); centralView->setFocus(); // Needed for shortcuts to work page.show(); QVERIFY(QTest::qWaitForWindowShown(&page)); QTest::qWait(100); // WHEN QTest::keyPress(centralView, Qt::Key_Delete); // THEN QVERIFY(msgbox->called()); QCOMPARE(stubPageModel.removedIndices.size(), 1); QCOMPARE(stubPageModel.removedIndices.first(), index); } void shouldDisplayNotificationWhenHittingTheDeleteKeyOnAnItemWithHiddenChildren() { // GIVEN PageModelStub stubPageModel; Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B")); QStandardItem *parentIndex = stubPageModel.itemModel.item(1, 0); stubPageModel.addStubItem(QStringLiteral("C"), parentIndex); QSortFilterProxyModel proxyModel; stubPageModel.setProxyModel(&proxyModel); proxyModel.setFilterFixedString("B"); QPersistentModelIndex index = stubPageModel.centralListModel()->index(0, 0); QCOMPARE(index.data().toString(), QLatin1String("B")); Widgets::PageView page; page.setModel(&stubPageModel); auto msgbox = MessageBoxStub::Ptr::create(); page.setMessageBoxInterface(msgbox); QTreeView *centralView = page.findChild(QStringLiteral("centralView")); centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); QVERIFY(centralView->selectionModel()->currentIndex().isValid()); centralView->setFocus(); // Needed for shortcuts to work page.show(); QVERIFY(QTest::qWaitForWindowShown(&page)); QTest::qWait(100); // WHEN QTest::keyPress(centralView, Qt::Key_Delete); // THEN QVERIFY(msgbox->called()); QCOMPARE(stubPageModel.removedIndices.size(), 1); QCOMPARE(stubPageModel.removedIndices.first(), index); } void shouldDeleteItemsWhenHittingTheDeleteKey() { // GIVEN PageModelStub stubPageModel; Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C")); QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0); QPersistentModelIndex index2 = stubPageModel.itemModel.index(2, 0); Widgets::PageView page; page.setModel(&stubPageModel); auto msgbox = MessageBoxStub::Ptr::create(); page.setMessageBoxInterface(msgbox); QTreeView *centralView = page.findChild(QStringLiteral("centralView")); centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); centralView->selectionModel()->setCurrentIndex(index2, QItemSelectionModel::Select); centralView->setFocus(); // Needed for shortcuts to work page.show(); QVERIFY(QTest::qWaitForWindowShown(&page)); QTest::qWait(100); // WHEN QTest::keyPress(centralView, Qt::Key_Delete); // THEN QVERIFY(msgbox->called()); QCOMPARE(stubPageModel.removedIndices.size(), 2); QCOMPARE(stubPageModel.removedIndices.first(), index); QCOMPARE(stubPageModel.removedIndices.at(1), index2); } void shouldPromoteItem() { // GIVEN PageModelStub stubPageModel; Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C")); QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0); Widgets::PageView page; page.setModel(&stubPageModel); auto promoteAction = page.findChild(QStringLiteral("promoteItemAction")); QVERIFY(promoteAction); QTreeView *centralView = page.findChild(QStringLiteral("centralView")); centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect); centralView->setFocus(); // WHEN promoteAction->trigger(); // THEN QCOMPARE(stubPageModel.promotedIndices.size(), 1); QCOMPARE(stubPageModel.promotedIndices.first(), index); } void shouldNotTryToPromoteItemIfThereIsNoSelection() { // GIVEN PageModelStub stubPageModel; Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C")); Widgets::PageView page; page.setModel(&stubPageModel); auto promoteAction = page.findChild(QStringLiteral("promoteItemAction")); QVERIFY(promoteAction); QTreeView *centralView = page.findChild(QStringLiteral("centralView")); centralView->selectionModel()->clear(); centralView->setFocus(); // WHEN promoteAction->trigger(); // THEN QVERIFY(stubPageModel.promotedIndices.isEmpty()); } void shouldClearCentralViewSelectionOnEscape() { // GIVEN PageModelStub stubPageModel; Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C")); QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0); Widgets::PageView page; page.setModel(&stubPageModel); auto centralView = page.findChild(QStringLiteral("centralView")); centralView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect); QVERIFY(!centralView->selectionModel()->selectedIndexes().isEmpty()); // WHEN QTest::keyClick(centralView, Qt::Key_Escape); // THEN QVERIFY(centralView->selectionModel()->selectedIndexes().isEmpty()); } void shouldReturnSelectedIndexes() { // GIVEN PageModelStub stubPageModel; Q_ASSERT(stubPageModel.property("centralListModel").canConvert()); stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C")); auto index = stubPageModel.itemModel.index(1, 0); auto index2 = stubPageModel.itemModel.index(2, 0); Widgets::PageView page; page.setModel(&stubPageModel); auto centralView = page.findChild(QStringLiteral("centralView")); auto filterWidget = page.findChild(QStringLiteral("filterWidget")); auto displayedModel = filterWidget->proxyModel(); auto displayedIndex = displayedModel->index(1, 0); auto displayedIndex2 = displayedModel->index(2, 0); // WHEN centralView->selectionModel()->setCurrentIndex(displayedIndex, QItemSelectionModel::ClearAndSelect); centralView->selectionModel()->setCurrentIndex(displayedIndex2, QItemSelectionModel::Select); // THEN auto selectedIndexes = page.selectedIndexes(); QCOMPARE(selectedIndexes.size(), 2); QCOMPARE(selectedIndexes.at(0), index); QCOMPARE(selectedIndexes.at(1), index2); QCOMPARE(selectedIndexes.at(0).model(), index.model()); QCOMPARE(selectedIndexes.at(1).model(), index2.model()); } void shouldDisplayMessageOnError() { // GIVEN Widgets::PageView page; page.show(); QVERIFY(QTest::qWaitForWindowShown(&page)); QTest::qWait(100); auto messageWidget = page.findChild(QStringLiteral("messageWidget")); QVERIFY(messageWidget); QVERIFY(!messageWidget->isVisibleTo(&page)); QCOMPARE(messageWidget->findChildren().size(), 1); auto closeButton = messageWidget->findChildren().first(); QVERIFY(closeButton); // WHEN page.displayErrorMessage(QStringLiteral("Foo Error")); // THEN QVERIFY(messageWidget->isVisibleTo(&page)); QVERIFY(messageWidget->isCloseButtonVisible()); QCOMPARE(messageWidget->text(), QStringLiteral("Foo Error")); QVERIFY(messageWidget->icon().isNull()); QCOMPARE(messageWidget->messageType(), KMessageWidget::Error); QVERIFY(messageWidget->isShowAnimationRunning()); QVERIFY(!messageWidget->isHideAnimationRunning()); // WHEN QTest::qWait(800); // THEN QVERIFY(!messageWidget->isShowAnimationRunning()); QVERIFY(!messageWidget->isHideAnimationRunning()); // WHEN closeButton->click(); // THEN QVERIFY(!messageWidget->isShowAnimationRunning()); QVERIFY(messageWidget->isHideAnimationRunning()); // WHEN QTest::qWait(800); // THEN 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(), 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(), QDate::currentDate()); } }; ZANSHIN_TEST_MAIN(PageViewTest) #include "pageviewtest.moc"