File indexing completed on 2025-01-19 04:57:00

0001 /*
0002  * SPDX-FileCopyrightText: 2014 Kevin Ottens <ervin@kde.org>
0003  SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 
0007 #include <testlib/qtest_gui_zanshin.h>
0008 
0009 #include <QAbstractItemModel>
0010 #include <QSortFilterProxyModel>
0011 #include <QAction>
0012 #include <QHeaderView>
0013 #include <QLayout>
0014 #include <QLineEdit>
0015 #include <QMessageBox>
0016 #include <QStandardItemModel>
0017 #include <QToolButton>
0018 #include <QTreeView>
0019 #include <runningtaskmodelinterface.h>
0020 
0021 #include <KConfig>
0022 #include <KConfigGroup>
0023 #include <KLocalizedString>
0024 #include <KMessageWidget>
0025 #include <KSharedConfig>
0026 
0027 #include "domain/task.h"
0028 
0029 #include "presentation/taskfilterproxymodel.h"
0030 #include "presentation/metatypes.h"
0031 #include "presentation/querytreemodelbase.h"
0032 
0033 #include "widgets/filterwidget.h"
0034 #include "widgets/itemdelegate.h"
0035 #include "widgets/pageview.h"
0036 
0037 #include "messageboxstub.h"
0038 
0039 class PageModelStub : public QObject
0040 {
0041     Q_OBJECT
0042     Q_PROPERTY(QAbstractItemModel* centralListModel READ centralListModel)
0043 public:
0044     void setProxyModel(QAbstractProxyModel *proxy)
0045     {
0046         proxyModel = proxy;
0047         proxyModel->setSourceModel(&itemModel);
0048     }
0049 
0050     QAbstractItemModel *centralListModel()
0051     {
0052         if (proxyModel)
0053             return proxyModel;
0054         return &itemModel;
0055     }
0056 
0057     QStandardItem *addStubItem(const QString &title, QStandardItem *parentItem = nullptr)
0058     {
0059         QStandardItem *item = new QStandardItem;
0060         item->setData(title, Qt::DisplayRole);
0061         if (!parentItem)
0062             itemModel.appendRow(item);
0063         else
0064             parentItem->appendRow(item);
0065 
0066         taskNames << title;
0067         return item;
0068     }
0069 
0070     Domain::Task::Ptr addTaskItem(const QString &title, QStandardItem *parentItem = nullptr)
0071     {
0072         auto item = addStubItem(title, parentItem);
0073         auto task = Domain::Task::Ptr::create();
0074         task->setTitle(title);
0075         item->setData(QVariant::fromValue(task), Presentation::QueryTreeModelBase::ObjectRole);
0076         return task;
0077     }
0078 
0079     void addStubItems(const QStringList &list)
0080     {
0081         foreach (const QString &title, list) {
0082             addStubItem(title);
0083         }
0084     }
0085 
0086 public slots:
0087     void addItem(const QString &name, const QModelIndex &parentIndex)
0088     {
0089         taskNames << name;
0090         parentIndices << parentIndex;
0091     }
0092 
0093     void removeItem(const QModelIndex &index)
0094     {
0095         removedIndices << index;
0096     }
0097 
0098     void promoteItem(const QModelIndex &index)
0099     {
0100         promotedIndices << index;
0101     }
0102 
0103 public:
0104     QStringList taskNames;
0105     QList<QPersistentModelIndex> parentIndices;
0106     QList<QPersistentModelIndex> removedIndices;
0107     QList<QPersistentModelIndex> promotedIndices;
0108     QStandardItemModel itemModel;
0109     QAbstractProxyModel *proxyModel = nullptr;
0110 };
0111 
0112 class RunningTaskModelStub : public Presentation::RunningTaskModelInterface
0113 {
0114     Q_OBJECT
0115 public:
0116     Domain::Task::Ptr runningTask() const override { return m_runningTask; }
0117     void setRunningTask(const Domain::Task::Ptr &task) override { m_runningTask = task; }
0118     void taskDeleted(const Domain::Task::Ptr &task) override { m_deletedTask = task; }
0119     void stopTask() override {}
0120     void doneTask() override {}
0121 private:
0122     Domain::Task::Ptr m_runningTask;
0123     Domain::Task::Ptr m_deletedTask;
0124 };
0125 
0126 class PageViewTest : public QObject
0127 {
0128     Q_OBJECT
0129 private:
0130     KConfigGroup configGroup()
0131     {
0132         return KConfigGroup(KSharedConfig::openConfig(), "General");
0133     }
0134 
0135 private slots:
0136     void shouldHaveDefaultState()
0137     {
0138         Widgets::PageView page;
0139         QCOMPARE(page.contentsMargins(), QMargins(0, 0, 0, 0));
0140         QCOMPARE(page.layout()->contentsMargins(), QMargins(0, 0, 0, 3));
0141 
0142         auto messageWidget = page.findChild<KMessageWidget*>(QStringLiteral("messageWidget"));
0143         QVERIFY(messageWidget);
0144         QVERIFY(!messageWidget->isVisibleTo(&page));
0145         QVERIFY(!messageWidget->isCloseButtonVisible());
0146         QVERIFY(messageWidget->wordWrap());
0147         QVERIFY(messageWidget->text().isEmpty());
0148         QVERIFY(messageWidget->icon().isNull());
0149         QCOMPARE(messageWidget->messageType(), KMessageWidget::Error);
0150         QVERIFY(!messageWidget->isShowAnimationRunning());
0151         QVERIFY(!messageWidget->isHideAnimationRunning());
0152 
0153         auto centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0154         QVERIFY(centralView);
0155         QVERIFY(centralView->isVisibleTo(&page));
0156         QVERIFY(!centralView->header()->isVisibleTo(&page));
0157         QVERIFY(qobject_cast<Widgets::ItemDelegate*>(centralView->itemDelegate()));
0158         QVERIFY(centralView->alternatingRowColors());
0159         QCOMPARE(centralView->dragDropMode(), QTreeView::DragDrop);
0160 
0161         auto filter = page.findChild<Widgets::FilterWidget*>(QStringLiteral("filterWidget"));
0162         QVERIFY(filter);
0163         QVERIFY(!filter->isVisibleTo(&page));
0164         QVERIFY(filter->proxyModel());
0165         QCOMPARE(filter->proxyModel(), centralView->model());
0166 
0167         QLineEdit *quickAddEdit = page.findChild<QLineEdit*>(QStringLiteral("quickAddEdit"));
0168         QVERIFY(quickAddEdit);
0169         QVERIFY(quickAddEdit->isVisibleTo(&page));
0170         QVERIFY(quickAddEdit->text().isEmpty());
0171         QCOMPARE(quickAddEdit->placeholderText(), i18n("Type and press enter to add a task"));
0172 
0173         auto addAction = page.findChild<QAction*>(QStringLiteral("addItemAction"));
0174         QVERIFY(addAction);
0175         auto cancelAddAction = page.findChild<QAction*>(QStringLiteral("cancelAddItemAction"));
0176         QVERIFY(cancelAddAction);
0177         auto removeAction = page.findChild<QAction*>(QStringLiteral("removeItemAction"));
0178         QVERIFY(removeAction);
0179         auto promoteAction = page.findChild<QAction*>(QStringLiteral("promoteItemAction"));
0180         QVERIFY(promoteAction);
0181         auto filterAction = page.findChild<QAction*>(QStringLiteral("filterViewAction"));
0182         QVERIFY(filterAction);
0183         QVERIFY(filterAction->isCheckable());
0184         QVERIFY(!filterAction->isChecked());
0185     auto doneAction = page.findChild<QAction*>(QStringLiteral("doneViewAction"));
0186         QVERIFY(doneAction);
0187         QVERIFY(doneAction->isCheckable());
0188         QVERIFY(doneAction->isChecked());
0189         auto futureAction = page.findChild<QAction*>(QStringLiteral("futureViewAction"));
0190         QVERIFY(futureAction);
0191         QVERIFY(futureAction->isCheckable());
0192         QVERIFY(futureAction->isChecked());
0193         auto runTaskAction = page.findChild<QAction*>(QStringLiteral("runTaskAction"));
0194         QVERIFY(runTaskAction);
0195         QVERIFY(!runTaskAction->isEnabled());
0196 
0197         auto actions = page.globalActions();
0198         QCOMPARE(actions.value(QStringLiteral("page_view_add")), addAction);
0199         QCOMPARE(actions.value(QStringLiteral("page_view_remove")), removeAction);
0200         QCOMPARE(actions.value(QStringLiteral("page_view_promote")), promoteAction);
0201         QCOMPARE(actions.value(QStringLiteral("page_view_filter")), filterAction);
0202     QCOMPARE(actions.value(QStringLiteral("page_view_done")), doneAction);
0203         QCOMPARE(actions.value(QStringLiteral("page_view_future")), futureAction);
0204         QCOMPARE(actions.value(QStringLiteral("page_run_task")), runTaskAction);
0205     }
0206 
0207     void shouldDisplayListFromPageModel()
0208     {
0209         // GIVEN
0210         QStandardItemModel model;
0211 
0212         QObject stubPageModel;
0213         stubPageModel.setProperty("centralListModel", QVariant::fromValue(static_cast<QAbstractItemModel*>(&model)));
0214 
0215         Widgets::PageView page;
0216         auto centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0217         QVERIFY(centralView);
0218         auto proxyModel = qobject_cast<Presentation::TaskFilterProxyModel*>(centralView->model());
0219         QVERIFY(proxyModel);
0220         QVERIFY(!proxyModel->sourceModel());
0221 
0222         // WHEN
0223         page.setModel(&stubPageModel);
0224 
0225         // THEN
0226         QCOMPARE(page.model(), &stubPageModel);
0227         QVERIFY(page.isEnabled());
0228         QCOMPARE(proxyModel->sourceModel(), &model);
0229     }
0230 
0231     void shouldNotCrashWithNullModel()
0232     {
0233         // GIVEN
0234         QStandardItemModel model;
0235         QObject stubPageModel;
0236         stubPageModel.setProperty("centralListModel", QVariant::fromValue(static_cast<QAbstractItemModel*>(&model)));
0237 
0238         Widgets::PageView page;
0239         page.setModel(&stubPageModel);
0240 
0241         auto centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0242         QVERIFY(centralView);
0243         auto proxyModel = qobject_cast<Presentation::TaskFilterProxyModel*>(centralView->model());
0244         QVERIFY(proxyModel);
0245         QCOMPARE(proxyModel->sourceModel(), &model);
0246 
0247         // WHEN
0248         page.setModel(nullptr);
0249 
0250         // THEN
0251         QVERIFY(!page.model());
0252         QVERIFY(!page.isEnabled());
0253         QVERIFY(!proxyModel->sourceModel());
0254     }
0255 
0256     void shouldManageFocusThroughActions()
0257     {
0258         // GIVEN
0259         Widgets::PageView page;
0260         auto centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0261         auto quickAddEdit = page.findChild<QLineEdit*>(QStringLiteral("quickAddEdit"));
0262         auto filter = page.findChild<Widgets::FilterWidget*>(QStringLiteral("filterWidget"));
0263         auto filterEdit = filter->findChild<QLineEdit*>();
0264         QVERIFY(filterEdit);
0265         page.show();
0266         page.activateWindow();
0267         QVERIFY(QTest::qWaitForWindowActive(&page));
0268 
0269         centralView->setFocus();
0270         QVERIFY(centralView->hasFocus());
0271         QVERIFY(!quickAddEdit->hasFocus());
0272         QVERIFY(!filter->isVisibleTo(&page));
0273         QVERIFY(!filterEdit->hasFocus());
0274 
0275         auto addAction = page.findChild<QAction*>(QStringLiteral("addItemAction"));
0276         auto cancelAddAction = page.findChild<QAction*>(QStringLiteral("cancelAddItemAction"));
0277         auto filterAction = page.findChild<QAction*>(QStringLiteral("filterViewAction"));
0278 
0279         // WHEN
0280         addAction->trigger();
0281 
0282         // THEN
0283         QVERIFY(!centralView->hasFocus());
0284         QVERIFY(quickAddEdit->hasFocus());
0285         QVERIFY(!filter->isVisibleTo(&page));
0286         QVERIFY(!filterEdit->hasFocus());
0287 
0288         // WHEN
0289         cancelAddAction->trigger();
0290 
0291         // THEN
0292         QVERIFY(centralView->hasFocus());
0293         QVERIFY(!quickAddEdit->hasFocus());
0294         QVERIFY(!filter->isVisibleTo(&page));
0295         QVERIFY(!filterEdit->hasFocus());
0296 
0297         // WHEN
0298         filterAction->trigger();
0299 
0300         // THEN
0301         QVERIFY(!centralView->hasFocus());
0302         QVERIFY(!quickAddEdit->hasFocus());
0303         QVERIFY(filter->isVisibleTo(&page));
0304         QVERIFY(filterEdit->hasFocus());
0305 
0306         // WHEN
0307         cancelAddAction->trigger();
0308 
0309         // THEN
0310         QVERIFY(centralView->hasFocus());
0311         QVERIFY(!quickAddEdit->hasFocus());
0312         QVERIFY(filter->isVisibleTo(&page));
0313         QVERIFY(!filterEdit->hasFocus());
0314     }
0315 
0316     void shouldManageFilterVisibilityThroughAction()
0317     {
0318         // GIVEN
0319         Widgets::PageView page;
0320         auto centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0321         auto filter = page.findChild<Widgets::FilterWidget*>(QStringLiteral("filterWidget"));
0322         auto filterEdit = filter->findChild<QLineEdit*>();
0323         QVERIFY(filterEdit);
0324         page.show();
0325         page.activateWindow();
0326         QVERIFY(QTest::qWaitForWindowActive(&page));
0327 
0328         centralView->setFocus();
0329         QVERIFY(centralView->hasFocus());
0330         QVERIFY(!filter->isVisibleTo(&page));
0331         QVERIFY(!filterEdit->hasFocus());
0332 
0333         auto filterAction = page.findChild<QAction*>(QStringLiteral("filterViewAction"));
0334 
0335         // WHEN
0336         filterAction->trigger();
0337 
0338         // THEN
0339         QVERIFY(!centralView->hasFocus());
0340         QVERIFY(filter->isVisibleTo(&page));
0341         QVERIFY(filterEdit->hasFocus());
0342 
0343         // WHEN
0344         filterEdit->setText("Foo");
0345 
0346         // THEN
0347         QCOMPARE(filterEdit->text(), QString("Foo"));
0348 
0349         // WHEN
0350         filterAction->trigger();
0351 
0352         // THEN
0353         QVERIFY(centralView->hasFocus());
0354         QVERIFY(!filter->isVisibleTo(&page));
0355         QVERIFY(!filterEdit->hasFocus());
0356         QVERIFY(filterEdit->text().isEmpty());
0357     }
0358 
0359     void shouldManageDoneTasksVisibilityThroughAction()
0360     {
0361         // GIVEN
0362         Widgets::PageView page;
0363         auto filter = page.findChild<Widgets::FilterWidget*>(QStringLiteral("filterWidget"));
0364         auto filterProxy = filter->proxyModel();
0365         QVERIFY(filterProxy);
0366 
0367         QVERIFY(filterProxy->showDoneTasks());
0368 
0369         auto doneAction = page.findChild<QAction*>(QStringLiteral("doneViewAction"));
0370 
0371         // WHEN
0372         doneAction->trigger();
0373 
0374         // THEN
0375         QVERIFY(!filterProxy->showDoneTasks());
0376 
0377         // WHEN
0378         doneAction->trigger();
0379 
0380         // THEN
0381         QVERIFY(filterProxy->showDoneTasks());
0382     }
0383 
0384     void shouldStoreDoneTasksVisibilityDefaultState()
0385     {
0386         // GIVEN
0387         configGroup().deleteEntry("ShowDone");
0388 
0389         {
0390             Widgets::PageView page;
0391             auto doneAction = page.findChild<QAction*>(QStringLiteral("doneViewAction"));
0392 
0393             // THEN
0394             QVERIFY(doneAction->isChecked());
0395         }
0396 
0397         // WHEN
0398         configGroup().writeEntry("ShowDone", false);
0399 
0400         {
0401             Widgets::PageView page;
0402             auto doneAction = page.findChild<QAction*>(QStringLiteral("doneViewAction"));
0403 
0404             // THEN
0405             QVERIFY(!doneAction->isChecked());
0406         }
0407 
0408         // WHEN
0409         configGroup().writeEntry("ShowDone", true);
0410 
0411         {
0412             Widgets::PageView page;
0413             auto doneAction = page.findChild<QAction*>(QStringLiteral("doneViewAction"));
0414 
0415             // THEN
0416             QVERIFY(doneAction->isChecked());
0417         }
0418 
0419         // WHEN
0420         configGroup().deleteEntry("ShowDone");
0421 
0422         {
0423             Widgets::PageView page;
0424             auto doneAction = page.findChild<QAction*>(QStringLiteral("doneViewAction"));
0425 
0426             // THEN
0427             QVERIFY(doneAction->isChecked());
0428         }
0429 
0430         // WHEN
0431         Widgets::PageView page;
0432         auto doneAction = page.findChild<QAction*>(QStringLiteral("doneViewAction"));
0433         doneAction->trigger();
0434 
0435         // THEN
0436         QVERIFY(configGroup().hasKey("ShowDone"));
0437         QVERIFY(!configGroup().readEntry("ShowDone", true));
0438 
0439         // WHEN
0440         doneAction->trigger();
0441 
0442         // THEN
0443         QVERIFY(configGroup().hasKey("ShowDone"));
0444         QVERIFY(configGroup().readEntry("ShowDone", false));
0445     }
0446 
0447     void shouldManageFutureTasksVisibilityThroughAction()
0448     {
0449         // GIVEN
0450         Widgets::PageView page;
0451         auto filter = page.findChild<Widgets::FilterWidget*>(QStringLiteral("filterWidget"));
0452         auto filterProxy = filter->proxyModel();
0453         QVERIFY(filterProxy);
0454 
0455         QVERIFY(filterProxy->showFutureTasks());
0456 
0457         auto futureAction = page.findChild<QAction*>(QStringLiteral("futureViewAction"));
0458 
0459         // WHEN
0460         futureAction->trigger();
0461 
0462         // THEN
0463         QVERIFY(!filterProxy->showFutureTasks());
0464 
0465         // WHEN
0466         futureAction->trigger();
0467 
0468         // THEN
0469         QVERIFY(filterProxy->showFutureTasks());
0470     }
0471 
0472     void shouldStoreFutureTasksVisibilityDefaultState()
0473     {
0474         // GIVEN
0475         configGroup().deleteEntry("ShowFuture");
0476 
0477         {
0478             Widgets::PageView page;
0479             auto futureAction = page.findChild<QAction*>(QStringLiteral("futureViewAction"));
0480 
0481             // THEN
0482             QVERIFY(futureAction->isChecked());
0483         }
0484 
0485         // WHEN
0486         configGroup().writeEntry("ShowFuture", false);
0487 
0488         {
0489             Widgets::PageView page;
0490             auto futureAction = page.findChild<QAction*>(QStringLiteral("futureViewAction"));
0491 
0492             // THEN
0493             QVERIFY(!futureAction->isChecked());
0494         }
0495 
0496         // WHEN
0497         configGroup().writeEntry("ShowFuture", true);
0498 
0499         {
0500             Widgets::PageView page;
0501             auto futureAction = page.findChild<QAction*>(QStringLiteral("futureViewAction"));
0502 
0503             // THEN
0504             QVERIFY(futureAction->isChecked());
0505         }
0506 
0507         // WHEN
0508         configGroup().deleteEntry("ShowFuture");
0509 
0510         {
0511             Widgets::PageView page;
0512             auto futureAction = page.findChild<QAction*>(QStringLiteral("futureViewAction"));
0513 
0514             // THEN
0515             QVERIFY(futureAction->isChecked());
0516         }
0517 
0518         // WHEN
0519         Widgets::PageView page;
0520         auto futureAction = page.findChild<QAction*>(QStringLiteral("futureViewAction"));
0521         futureAction->trigger();
0522 
0523         // THEN
0524         QVERIFY(configGroup().hasKey("ShowFuture"));
0525         QVERIFY(!configGroup().readEntry("ShowFuture", true));
0526 
0527         // WHEN
0528         futureAction->trigger();
0529 
0530         // THEN
0531         QVERIFY(configGroup().hasKey("ShowFuture"));
0532         QVERIFY(configGroup().readEntry("ShowFuture", false));
0533     }
0534 
0535     void shouldCreateTasksWithNoParentWhenHittingReturnWithoutSelectedIndex()
0536     {
0537         // GIVEN
0538         PageModelStub stubPageModel;
0539         Widgets::PageView page;
0540         page.setModel(&stubPageModel);
0541         auto quickAddEdit = page.findChild<QLineEdit*>(QStringLiteral("quickAddEdit"));
0542 
0543         // WHEN
0544         QTest::keyClick(quickAddEdit, Qt::Key_Return); // Does nothing (edit empty)
0545         QTest::keyClicks(quickAddEdit, QStringLiteral("Foo"));
0546         QTest::keyClick(quickAddEdit, Qt::Key_Return);
0547         QTest::keyClick(quickAddEdit, Qt::Key_Return); // Does nothing (edit empty)
0548         QTest::keyClicks(quickAddEdit, QStringLiteral("Bar"));
0549         QTest::keyClick(quickAddEdit, Qt::Key_Return);
0550         QTest::keyClick(quickAddEdit, Qt::Key_Return); // Does nothing (edit empty)
0551 
0552         // THEN
0553         QCOMPARE(stubPageModel.taskNames, QStringList() << QStringLiteral("Foo") << QStringLiteral("Bar"));
0554         QCOMPARE(stubPageModel.parentIndices.size(), 2);
0555         QCOMPARE(stubPageModel.parentIndices.first(), QPersistentModelIndex());
0556         QCOMPARE(stubPageModel.parentIndices.last(), QPersistentModelIndex());
0557     }
0558 
0559     void shouldCreateTasksWithNoParentWhenHittingReturnWithSeveralSelectedIndices()
0560     {
0561         // GIVEN
0562         PageModelStub stubPageModel;
0563         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0564         stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C"));
0565         QPersistentModelIndex index0 = stubPageModel.itemModel.index(0, 0);
0566         QPersistentModelIndex index1 = stubPageModel.itemModel.index(1, 0);
0567 
0568         Widgets::PageView page;
0569         page.setModel(&stubPageModel);
0570 
0571         auto centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0572         centralView->selectionModel()->select(index0, QItemSelectionModel::ClearAndSelect);
0573         centralView->selectionModel()->select(index1, QItemSelectionModel::Select);
0574 
0575         auto quickAddEdit = page.findChild<QLineEdit*>(QStringLiteral("quickAddEdit"));
0576 
0577         // WHEN
0578         QTest::keyClicks(quickAddEdit, QStringLiteral("Foo"));
0579         QTest::keyClick(quickAddEdit, Qt::Key_Return);
0580 
0581         // THEN
0582         QCOMPARE(stubPageModel.taskNames, QStringList() << QStringLiteral("A")
0583                                                         << QStringLiteral("B")
0584                                                         << QStringLiteral("C")
0585                                                         << QStringLiteral("Foo"));
0586         QCOMPARE(stubPageModel.parentIndices.size(), 1);
0587         QCOMPARE(stubPageModel.parentIndices.first(), QPersistentModelIndex());
0588     }
0589 
0590     void shouldCreateTasksWithParentWhenHittingReturnWithOneSelectedIndex()
0591     {
0592         // GIVEN
0593         PageModelStub stubPageModel;
0594         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0595         stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C"));
0596         QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0);
0597 
0598         Widgets::PageView page;
0599         page.setModel(&stubPageModel);
0600 
0601         auto centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0602         centralView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
0603 
0604         auto quickAddEdit = page.findChild<QLineEdit*>(QStringLiteral("quickAddEdit"));
0605 
0606         // WHEN
0607         QTest::keyClicks(quickAddEdit, QStringLiteral("Foo"));
0608         QTest::keyClick(quickAddEdit, Qt::Key_Return);
0609 
0610         // THEN
0611         QCOMPARE(stubPageModel.taskNames, QStringList() << QStringLiteral("A")
0612                                                         << QStringLiteral("B")
0613                                                         << QStringLiteral("C")
0614                                                         << QStringLiteral("Foo"));
0615         QCOMPARE(stubPageModel.parentIndices.size(), 1);
0616         QCOMPARE(stubPageModel.parentIndices.first(), index);
0617     }
0618 
0619     void shouldDeleteItemWhenHittingTheDeleteKey()
0620     {
0621         // GIVEN
0622         PageModelStub stubPageModel;
0623         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0624         stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C"));
0625         QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0);
0626 
0627         Widgets::PageView page;
0628         page.setModel(&stubPageModel);
0629 
0630         QTreeView *centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0631         centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
0632         centralView->setFocus();
0633 
0634         // Needed for shortcuts to work
0635         page.show();
0636         page.activateWindow();
0637         QVERIFY(QTest::qWaitForWindowActive(&page));
0638 
0639         // WHEN
0640         QTest::keyPress(centralView, Qt::Key_Delete);
0641 
0642         // THEN
0643         QCOMPARE(stubPageModel.removedIndices.size(), 1);
0644         QCOMPARE(stubPageModel.removedIndices.first(), index);
0645     }
0646 
0647     void shouldNotTryToDeleteIfThereIsNoSelection()
0648     {
0649         // GIVEN
0650         PageModelStub stubPageModel;
0651         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0652         stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C"));
0653 
0654         Widgets::PageView page;
0655         page.setModel(&stubPageModel);
0656 
0657         QTreeView *centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0658         centralView->clearSelection();
0659         page.findChild<QLineEdit*>(QStringLiteral("quickAddEdit"))->setFocus();
0660 
0661         // Needed for shortcuts to work
0662         page.show();
0663         page.activateWindow();
0664         QVERIFY(QTest::qWaitForWindowActive(&page));
0665 
0666         // WHEN
0667         QTest::keyPress(centralView, Qt::Key_Delete);
0668 
0669         // THEN
0670         QVERIFY(stubPageModel.removedIndices.isEmpty());
0671     }
0672 
0673     void shouldDisplayNotificationWhenHittingTheDeleteKeyOnAnItemWithChildren()
0674     {
0675         // GIVEN
0676         PageModelStub stubPageModel;
0677         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0678         stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B"));
0679         QStandardItem *parentIndex = stubPageModel.itemModel.item(1, 0);
0680         stubPageModel.addStubItem(QStringLiteral("C"), parentIndex);
0681         QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0);
0682 
0683         Widgets::PageView page;
0684         page.setModel(&stubPageModel);
0685         auto msgbox = MessageBoxStub::Ptr::create();
0686         page.setMessageBoxInterface(msgbox);
0687 
0688         QTreeView *centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0689         centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
0690         QVERIFY(centralView->selectionModel()->currentIndex().isValid());
0691         centralView->setFocus();
0692 
0693         // Needed for shortcuts to work
0694         page.show();
0695         page.activateWindow();
0696         QVERIFY(QTest::qWaitForWindowActive(&page));
0697 
0698         // WHEN
0699         QTest::keyPress(centralView, Qt::Key_Delete);
0700 
0701         // THEN
0702         QVERIFY(msgbox->called());
0703         QCOMPARE(stubPageModel.removedIndices.size(), 1);
0704         QCOMPARE(stubPageModel.removedIndices.first(), index);
0705     }
0706 
0707     void shouldDisplayNotificationWhenHittingTheDeleteKeyOnAnItemWithHiddenChildren()
0708     {
0709         // GIVEN
0710         PageModelStub stubPageModel;
0711         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0712         stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B"));
0713         QStandardItem *parentIndex = stubPageModel.itemModel.item(1, 0);
0714         stubPageModel.addStubItem(QStringLiteral("C"), parentIndex);
0715 
0716         QSortFilterProxyModel proxyModel;
0717         stubPageModel.setProxyModel(&proxyModel);
0718         proxyModel.setFilterRegularExpression(QStringLiteral("B"));
0719 
0720         QPersistentModelIndex index = stubPageModel.centralListModel()->index(0, 0);
0721         QCOMPARE(index.data().toString(), QLatin1StringView("B"));
0722         Widgets::PageView page;
0723         page.setModel(&stubPageModel);
0724         auto msgbox = MessageBoxStub::Ptr::create();
0725         page.setMessageBoxInterface(msgbox);
0726 
0727         QTreeView *centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0728         centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
0729         QVERIFY(centralView->selectionModel()->currentIndex().isValid());
0730         centralView->setFocus();
0731 
0732         // Needed for shortcuts to work
0733         page.show();
0734         page.activateWindow();
0735         QVERIFY(QTest::qWaitForWindowActive(&page));
0736 
0737         // WHEN
0738         QTest::keyPress(centralView, Qt::Key_Delete);
0739 
0740         // THEN
0741         QVERIFY(msgbox->called());
0742         QCOMPARE(stubPageModel.removedIndices.size(), 1);
0743         QCOMPARE(stubPageModel.removedIndices.first(), index);
0744     }
0745 
0746     void shouldDeleteItemsWhenHittingTheDeleteKey()
0747     {
0748         // GIVEN
0749         PageModelStub stubPageModel;
0750         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0751         stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C"));
0752         QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0);
0753         QPersistentModelIndex index2 = stubPageModel.itemModel.index(2, 0);
0754 
0755         Widgets::PageView page;
0756         page.setModel(&stubPageModel);
0757         auto msgbox = MessageBoxStub::Ptr::create();
0758         page.setMessageBoxInterface(msgbox);
0759 
0760         QTreeView *centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0761         centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
0762         centralView->selectionModel()->setCurrentIndex(index2, QItemSelectionModel::Select);
0763         centralView->setFocus();
0764 
0765         // Needed for shortcuts to work
0766         page.show();
0767         page.activateWindow();
0768         QVERIFY(QTest::qWaitForWindowActive(&page));
0769 
0770         // WHEN
0771         QTest::keyPress(centralView, Qt::Key_Delete);
0772 
0773         // THEN
0774         QVERIFY(msgbox->called());
0775         QCOMPARE(stubPageModel.removedIndices.size(), 2);
0776         QCOMPARE(stubPageModel.removedIndices.first(), index);
0777         QCOMPARE(stubPageModel.removedIndices.at(1), index2);
0778     }
0779 
0780     void shouldPromoteItem()
0781     {
0782         // GIVEN
0783         PageModelStub stubPageModel;
0784         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0785         stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C"));
0786         QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0);
0787 
0788         Widgets::PageView page;
0789         page.setModel(&stubPageModel);
0790 
0791         auto promoteAction = page.findChild<QAction*>(QStringLiteral("promoteItemAction"));
0792         QVERIFY(promoteAction);
0793 
0794         QTreeView *centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0795         centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
0796         centralView->setFocus();
0797 
0798         // WHEN
0799         promoteAction->trigger();
0800 
0801         // THEN
0802         QCOMPARE(stubPageModel.promotedIndices.size(), 1);
0803         QCOMPARE(stubPageModel.promotedIndices.first(), index);
0804     }
0805 
0806     void shouldNotTryToPromoteItemIfThereIsNoSelection()
0807     {
0808         // GIVEN
0809         PageModelStub stubPageModel;
0810         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0811         stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C"));
0812 
0813         Widgets::PageView page;
0814         page.setModel(&stubPageModel);
0815 
0816         auto promoteAction = page.findChild<QAction*>(QStringLiteral("promoteItemAction"));
0817         QVERIFY(promoteAction);
0818 
0819         QTreeView *centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0820         centralView->selectionModel()->clear();
0821         centralView->setFocus();
0822 
0823         // WHEN
0824         promoteAction->trigger();
0825 
0826         // THEN
0827         QVERIFY(stubPageModel.promotedIndices.isEmpty());
0828     }
0829 
0830     void shouldClearCentralViewSelectionOnEscape()
0831     {
0832         // GIVEN
0833         PageModelStub stubPageModel;
0834         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0835         stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C"));
0836         QPersistentModelIndex index = stubPageModel.itemModel.index(1, 0);
0837 
0838         Widgets::PageView page;
0839         page.setModel(&stubPageModel);
0840 
0841         auto centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0842         centralView->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect);
0843         QVERIFY(!centralView->selectionModel()->selectedIndexes().isEmpty());
0844 
0845         // WHEN
0846         QTest::keyClick(centralView, Qt::Key_Escape);
0847 
0848         // THEN
0849         QVERIFY(centralView->selectionModel()->selectedIndexes().isEmpty());
0850     }
0851 
0852     void shouldReturnSelectedIndexes()
0853     {
0854         // GIVEN
0855         PageModelStub stubPageModel;
0856         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0857         stubPageModel.addStubItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C"));
0858         auto index = stubPageModel.itemModel.index(1, 0);
0859         auto index2 = stubPageModel.itemModel.index(2, 0);
0860 
0861         Widgets::PageView page;
0862         page.setModel(&stubPageModel);
0863 
0864         auto centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0865         auto filterWidget = page.findChild<Widgets::FilterWidget*>(QStringLiteral("filterWidget"));
0866 
0867         auto displayedModel = filterWidget->proxyModel();
0868         auto displayedIndex = displayedModel->index(1, 0);
0869         auto displayedIndex2 = displayedModel->index(2, 0);
0870 
0871         // WHEN
0872         centralView->selectionModel()->setCurrentIndex(displayedIndex, QItemSelectionModel::ClearAndSelect);
0873         centralView->selectionModel()->setCurrentIndex(displayedIndex2, QItemSelectionModel::Select);
0874 
0875         // THEN
0876         auto selectedIndexes = page.selectedIndexes();
0877         QCOMPARE(selectedIndexes.size(), 2);
0878 
0879         QCOMPARE(selectedIndexes.at(0), index);
0880         QCOMPARE(selectedIndexes.at(1), index2);
0881 
0882         QCOMPARE(selectedIndexes.at(0).model(), index.model());
0883         QCOMPARE(selectedIndexes.at(1).model(), index2.model());
0884     }
0885 
0886     void shouldDisplayMessageOnError()
0887     {
0888         // GIVEN
0889         Widgets::PageView page;
0890         page.show();
0891         QVERIFY(QTest::qWaitForWindowExposed(&page));
0892         QTest::qWait(100);
0893 
0894         auto messageWidget = page.findChild<KMessageWidget*>(QStringLiteral("messageWidget"));
0895         QVERIFY(messageWidget);
0896         QVERIFY(!messageWidget->isVisibleTo(&page));
0897 
0898         QCOMPARE(messageWidget->findChildren<QToolButton*>().size(), 1);
0899         auto closeButton = messageWidget->findChildren<QToolButton*>().first();
0900         QVERIFY(closeButton);
0901 
0902         // WHEN
0903         page.displayErrorMessage(QStringLiteral("Foo Error"));
0904 
0905         // THEN
0906         QVERIFY(messageWidget->isVisibleTo(&page));
0907         QVERIFY(messageWidget->isCloseButtonVisible());
0908         QCOMPARE(messageWidget->text(), QStringLiteral("Foo Error"));
0909         QVERIFY(messageWidget->icon().isNull());
0910         QCOMPARE(messageWidget->messageType(), KMessageWidget::Error);
0911         QVERIFY(messageWidget->isShowAnimationRunning());
0912         QVERIFY(!messageWidget->isHideAnimationRunning());
0913 
0914         // WHEN
0915         QTest::qWait(800);
0916 
0917         // THEN
0918         QVERIFY(!messageWidget->isShowAnimationRunning());
0919         QVERIFY(!messageWidget->isHideAnimationRunning());
0920 
0921         // WHEN
0922         closeButton->click();
0923 
0924         // THEN
0925         QVERIFY(!messageWidget->isShowAnimationRunning());
0926         QVERIFY(messageWidget->isHideAnimationRunning());
0927 
0928         // WHEN
0929         QTest::qWait(800);
0930 
0931         // THEN
0932         QVERIFY(!messageWidget->isShowAnimationRunning());
0933         QVERIFY(!messageWidget->isHideAnimationRunning());
0934     }
0935 
0936     void shouldRunTask()
0937     {
0938         // GIVEN
0939         PageModelStub stubPageModel;
0940         Q_ASSERT(stubPageModel.property("centralListModel").canConvert<QAbstractItemModel*>());
0941         auto task1 = stubPageModel.addTaskItem(QStringLiteral("Task1"));
0942         auto task2 = stubPageModel.addTaskItem(QStringLiteral("Task2"));
0943         Widgets::PageView page;
0944         page.setModel(&stubPageModel);
0945         RunningTaskModelStub stubRunningTaskModel;
0946         page.setRunningTaskModel(&stubRunningTaskModel);
0947         auto centralView = page.findChild<QTreeView*>(QStringLiteral("centralView"));
0948 
0949         QModelIndex index = stubPageModel.itemModel.index(0, 0);
0950         centralView->selectionModel()->setCurrentIndex(index, QItemSelectionModel::ClearAndSelect);
0951         QVERIFY(centralView->selectionModel()->currentIndex().isValid());
0952 
0953         auto runTaskAction = page.findChild<QAction*>(QStringLiteral("runTaskAction"));
0954         QVERIFY(runTaskAction);
0955         QVERIFY(runTaskAction->isEnabled());
0956 
0957         // WHEN starting the first task
0958         runTaskAction->trigger();
0959 
0960         // THEN
0961         QCOMPARE(stubRunningTaskModel.property("runningTask").value<Domain::Task::Ptr>(), task1);
0962         QCOMPARE(task1->startDate(), QDate::currentDate());
0963 
0964         // WHEN starting the second task
0965         QModelIndex index2 = stubPageModel.itemModel.index(1, 0);
0966         centralView->selectionModel()->setCurrentIndex(index2, QItemSelectionModel::ClearAndSelect);
0967         runTaskAction->trigger();
0968 
0969         // THEN
0970         QCOMPARE(stubRunningTaskModel.property("runningTask").value<Domain::Task::Ptr>(), task2);
0971         QCOMPARE(task2->startDate(), QDate::currentDate());
0972     }
0973 };
0974 
0975 ZANSHIN_TEST_MAIN(PageViewTest)
0976 
0977 #include "pageviewtest.moc"