diff --git a/src/widgets/availablepagesview.cpp b/src/widgets/availablepagesview.cpp index 2b97d9c6..e4800e21 100644 --- a/src/widgets/availablepagesview.cpp +++ b/src/widgets/availablepagesview.cpp @@ -1,341 +1,346 @@ /* 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 "availablepagesview.h" #include #include #include #include #include #include #include #include "presentation/metatypes.h" #include "presentation/querytreemodelbase.h" #include "widgets/messagebox.h" #include "widgets/newprojectdialog.h" #include "widgets/quickselectdialog.h" #include "domain/project.h" #include "domain/context.h" #include "domain/tag.h" using namespace Widgets; using namespace Presentation; AvailablePagesView::AvailablePagesView(QWidget *parent) : QWidget(parent), m_addProjectAction(new QAction(this)), m_addContextAction(new QAction(this)), m_addTagAction(new QAction(this)), m_removeAction(new QAction(this)), m_model(Q_NULLPTR), m_sources(Q_NULLPTR), m_pagesView(new QTreeView(this)) { m_pagesView->setObjectName("pagesView"); m_pagesView->header()->hide(); m_pagesView->setDragDropMode(QTreeView::DropOnly); auto actionBar = new QToolBar(this); actionBar->setObjectName("actionBar"); actionBar->setIconSize(QSize(16, 16)); m_addProjectAction->setObjectName("addProjectAction"); m_addProjectAction->setText(tr("New project")); m_addProjectAction->setIcon(QIcon::fromTheme("view-pim-tasks")); connect(m_addProjectAction, SIGNAL(triggered()), this, SLOT(onAddProjectTriggered())); actionBar->addAction(m_addProjectAction); m_addContextAction->setObjectName("addContextAction"); m_addContextAction->setText(tr("New context")); m_addContextAction->setIcon(QIcon::fromTheme("view-pim-notes")); connect(m_addContextAction, SIGNAL(triggered()), this, SLOT(onAddContextTriggered())); actionBar->addAction(m_addContextAction); m_addTagAction->setObjectName("addTagAction"); m_addTagAction->setText(tr("New tag")); m_addTagAction->setIcon(QIcon::fromTheme("view-pim-tasks")); connect(m_addTagAction, SIGNAL(triggered()), this, SLOT(onAddTagTriggered())); actionBar->addAction(m_addTagAction); m_removeAction->setObjectName("removeAction"); m_removeAction->setText(tr("Remove page")); m_removeAction->setIcon(QIcon::fromTheme("list-remove")); connect(m_removeAction, SIGNAL(triggered()), this, SLOT(onRemoveTriggered())); actionBar->addAction(m_removeAction); auto actionBarLayout = new QHBoxLayout; actionBarLayout->setAlignment(Qt::AlignRight); actionBarLayout->addWidget(actionBar); auto layout = new QVBoxLayout; layout->addWidget(m_pagesView); layout->addLayout(actionBarLayout); setLayout(layout); m_projectDialogFactory = [] (QWidget *parent) { return NewProjectDialogPtr(new NewProjectDialog(parent)); }; m_quickSelectDialogFactory = [] (QWidget *parent) { return QuickSelectDialogPtr(new QuickSelectDialog(parent)); }; m_messageBoxInterface = MessageBox::Ptr::create(); auto goPreviousAction = new QAction(this); goPreviousAction->setObjectName("goPreviousAction"); goPreviousAction->setText(tr("Previous page")); goPreviousAction->setIcon(QIcon::fromTheme("go-up")); goPreviousAction->setShortcut(Qt::ALT | Qt::Key_Up); connect(goPreviousAction, SIGNAL(triggered(bool)), this, SLOT(onGoPreviousTriggered())); auto goNextAction = new QAction(this); goNextAction->setObjectName("goNextAction"); goNextAction->setText(tr("Next page")); goNextAction->setIcon(QIcon::fromTheme("go-down")); goNextAction->setShortcut(Qt::ALT | Qt::Key_Down); connect(goNextAction, SIGNAL(triggered(bool)), this, SLOT(onGoNextTriggered())); auto goToAction = new QAction(this); goToAction->setObjectName("goToAction"); goToAction->setText(tr("Go to page...")); goToAction->setShortcut(Qt::Key_J); connect(goToAction, SIGNAL(triggered(bool)), this, SLOT(onGoToTriggered())); m_actions.insert("pages_project_add", m_addProjectAction); m_actions.insert("pages_context_add", m_addContextAction); m_actions.insert("pages_tag_add", m_addTagAction); m_actions.insert("pages_remove", m_removeAction); m_actions.insert("pages_go_previous", goPreviousAction); m_actions.insert("pages_go_next", goNextAction); m_actions.insert("pages_go_to", goToAction); } QHash AvailablePagesView::globalActions() const { return m_actions; } QObject *AvailablePagesView::model() const { return m_model; } QAbstractItemModel *AvailablePagesView::projectSourcesModel() const { return m_sources; } Domain::DataSource::Ptr AvailablePagesView::defaultProjectSource() const { return m_defaultSource; } AvailablePagesView::ProjectDialogFactory AvailablePagesView::projectDialogFactory() const { return m_projectDialogFactory; } AvailablePagesView::QuickSelectDialogFactory AvailablePagesView::quickSelectDialogFactory() const { return m_quickSelectDialogFactory; } void AvailablePagesView::setModel(QObject *model) { if (model == m_model) return; if (m_pagesView->selectionModel()) { disconnect(m_pagesView->selectionModel(), Q_NULLPTR, this, Q_NULLPTR); } m_pagesView->setModel(Q_NULLPTR); m_model = model; + setEnabled(m_model); + + if (!m_model) + return; + m_addProjectAction->setVisible(m_model->property("hasProjectPages").toBool()); m_addContextAction->setVisible(m_model->property("hasContextPages").toBool()); m_addTagAction->setVisible(m_model->property("hasTagPages").toBool()); QVariant modelProperty = m_model->property("pageListModel"); if (modelProperty.canConvert()) m_pagesView->setModel(modelProperty.value()); connect(m_pagesView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(onCurrentChanged(QModelIndex))); QMetaObject::invokeMethod(this, "onInitTimeout", Qt::QueuedConnection); } void AvailablePagesView::setProjectSourcesModel(QAbstractItemModel *sources) { m_sources = sources; } void AvailablePagesView::setDefaultProjectSource(const Domain::DataSource::Ptr &source) { m_defaultSource = source; } void AvailablePagesView::setProjectDialogFactory(const AvailablePagesView::ProjectDialogFactory &factory) { m_projectDialogFactory = factory; } void AvailablePagesView::setQuickSelectDialogFactory(const AvailablePagesView::QuickSelectDialogFactory &factory) { m_quickSelectDialogFactory = factory; } void AvailablePagesView::setMessageBoxInterface(const MessageBoxInterface::Ptr &interface) { m_messageBoxInterface = interface; } void AvailablePagesView::onCurrentChanged(const QModelIndex ¤t) { QObject *page = Q_NULLPTR; QMetaObject::invokeMethod(m_model, "createPageForIndex", Q_RETURN_ARG(QObject*, page), Q_ARG(QModelIndex, current)); emit currentPageChanged(page); const auto object = current.data(QueryTreeModelBase::ObjectRole).value(); m_removeAction->setEnabled(object.objectCast() || object.objectCast() || object.objectCast()); } void AvailablePagesView::onAddProjectTriggered() { NewProjectDialogInterface::Ptr dialog = m_projectDialogFactory(this); dialog->setDataSourcesModel(m_sources); if (dialog->exec() == QDialog::Accepted) { m_defaultSource = dialog->dataSource(); QMetaObject::invokeMethod(m_model, "addProject", Q_ARG(QString, dialog->name()), Q_ARG(Domain::DataSource::Ptr, dialog->dataSource())); } } void AvailablePagesView::onAddContextTriggered() { const QString name = m_messageBoxInterface->askTextInput(this, tr("Add Context"), tr("Context name")); if (!name.isEmpty()) { QMetaObject::invokeMethod(m_model, "addContext", Q_ARG(QString, name)); } } void AvailablePagesView::onAddTagTriggered() { const QString name = m_messageBoxInterface->askTextInput(this, tr("Add Tag"), tr("Tag name")); if (!name.isEmpty()) { QMetaObject::invokeMethod(m_model, "addTag", Q_ARG(QString, name)); } } void AvailablePagesView::onRemoveTriggered() { const QModelIndex current = m_pagesView->currentIndex(); if (!current.isValid()) return; QString title; QString text; QObjectPtr object = current.data(QueryTreeModelBase::ObjectRole).value(); if (!object) { qDebug() << "Model doesn't have ObjectRole for" << current; return; } if (Domain::Project::Ptr project = object.objectCast()) { title = tr("Delete Project"); text = tr("Do you really want to delete the project '%1', with all its actions?").arg(project->name()); } else if (Domain::Context::Ptr context = object.objectCast()) { title = tr("Delete Context"); text = tr("Do you really want to delete the context '%1'?").arg(context->name()); } else if (Domain::Tag::Ptr tag = object.objectCast()) { title = tr("Delete Tag"); text = tr("Do you really want to delete the tag '%1'?").arg(tag->name()); } else { qFatal("Unrecognized object type"); return; } QMessageBox::Button button = m_messageBoxInterface->askConfirmation(this, title, text); if (button != QMessageBox::Yes) { return; } QMetaObject::invokeMethod(m_model, "removeItem", Q_ARG(QModelIndex, current)); } void AvailablePagesView::onGoPreviousTriggered() { auto index = m_pagesView->indexAbove(m_pagesView->currentIndex()); while (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { index = m_pagesView->indexAbove(index); } if (index.isValid()) m_pagesView->setCurrentIndex(index); } void AvailablePagesView::onGoNextTriggered() { auto index = m_pagesView->indexBelow(m_pagesView->currentIndex()); while (index.isValid() && !(index.flags() & Qt::ItemIsSelectable)) { index = m_pagesView->indexBelow(index); } if (index.isValid()) m_pagesView->setCurrentIndex(index); } void AvailablePagesView::onGoToTriggered() { QuickSelectDialogInterface::Ptr dialog = m_quickSelectDialogFactory(this); dialog->setModel(m_pagesView->model()); if (dialog->exec() == QDialog::Accepted && dialog->selectedIndex().isValid()) { m_pagesView->setCurrentIndex(dialog->selectedIndex()); } } void AvailablePagesView::onInitTimeout() { if (m_pagesView->model()) { m_pagesView->setCurrentIndex(m_pagesView->model()->index(0, 0)); m_pagesView->expandAll(); } } diff --git a/tests/units/widgets/availablepagesviewtest.cpp b/tests/units/widgets/availablepagesviewtest.cpp index acd1ae48..6038ee9e 100644 --- a/tests/units/widgets/availablepagesviewtest.cpp +++ b/tests/units/widgets/availablepagesviewtest.cpp @@ -1,573 +1,598 @@ /* 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 "domain/project.h" #include "domain/context.h" #include "domain/tag.h" #include "presentation/metatypes.h" #include "presentation/querytreemodelbase.h" #include "widgets/availablepagesview.h" #include "widgets/newprojectdialog.h" #include "widgets/quickselectdialog.h" #include "messageboxstub.h" class NewProjectDialogStub : public Widgets::NewProjectDialogInterface { public: typedef QSharedPointer Ptr; explicit NewProjectDialogStub() : parent(Q_NULLPTR), execCount(0), sourceModel(Q_NULLPTR), source(Domain::DataSource::Ptr::create()) { } int exec() { execCount++; return QDialog::Accepted; } void setDataSourcesModel(QAbstractItemModel *model) Q_DECL_OVERRIDE { sourceModel = model; } QString name() const Q_DECL_OVERRIDE { return "name"; } Domain::DataSource::Ptr dataSource() const Q_DECL_OVERRIDE { return source; } QWidget *parent; int execCount; QAbstractItemModel *sourceModel; Domain::DataSource::Ptr source; }; class QuickSelectDialogStub : public Widgets::QuickSelectDialogInterface { public: typedef QSharedPointer Ptr; explicit QuickSelectDialogStub() : parent(Q_NULLPTR), execCount(0), itemModel(Q_NULLPTR) { } int exec() { 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 AvailablePagesModelStub : public QObject { Q_OBJECT public: explicit AvailablePagesModelStub(QObject *parent = Q_NULLPTR) : QObject(parent) { } public slots: void addProject(const QString &name, const Domain::DataSource::Ptr &source) { projectNames << name; sources << source; } void addContext(const QString &name) { contextNames << name; } void addTag(const QString &name) { tagNames << name; } void removeItem(const QModelIndex &index) { projectRemoved = index.data().toString(); } public Q_SLOTS: QObject *createPageForIndex(const QModelIndex &) { return Q_NULLPTR; } public: QStringList projectNames; QStringList contextNames; QStringList tagNames; QList sources; QString projectRemoved; }; class AvailablePagesViewTest : public QObject { Q_OBJECT private slots: void shouldHaveDefaultState() { Widgets::AvailablePagesView available; QVERIFY(!available.model()); QVERIFY(!available.projectSourcesModel()); QVERIFY(available.defaultProjectSource().isNull()); auto pagesView = available.findChild("pagesView"); QVERIFY(pagesView); QVERIFY(pagesView->isVisibleTo(&available)); QVERIFY(!pagesView->header()->isVisibleTo(&available)); QCOMPARE(pagesView->dragDropMode(), QTreeView::DropOnly); auto actionBar = available.findChild("actionBar"); QVERIFY(actionBar); QVERIFY(actionBar->isVisibleTo(&available)); auto addProjectAction = available.findChild("addProjectAction"); QVERIFY(addProjectAction); auto addContextAction = available.findChild("addContextAction"); QVERIFY(addContextAction); auto addTagAction = available.findChild("addTagAction"); QVERIFY(addTagAction); auto removeAction = available.findChild("removeAction"); QVERIFY(removeAction); auto goPreviousAction = available.findChild("goPreviousAction"); QVERIFY(goPreviousAction); auto goNextAction = available.findChild("goNextAction"); QVERIFY(goNextAction); auto goToAction = available.findChild("goToAction"); QVERIFY(goToAction); auto projectDialogFactory = available.projectDialogFactory(); QVERIFY(projectDialogFactory(&available).dynamicCast()); auto quickSelectDialogFactory = available.quickSelectDialogFactory(); QVERIFY(quickSelectDialogFactory(&available).dynamicCast()); auto actions = available.globalActions(); QCOMPARE(actions.value("pages_project_add"), addProjectAction); QCOMPARE(actions.value("pages_context_add"), addContextAction); QCOMPARE(actions.value("pages_tag_add"), addTagAction); QCOMPARE(actions.value("pages_remove"), removeAction); QCOMPARE(actions.value("pages_go_previous"), goPreviousAction); QCOMPARE(actions.value("pages_go_next"), goNextAction); QCOMPARE(actions.value("pages_go_to"), goToAction); } void shouldShowOnlyAddActionsNeededByTheModel_data() { QTest::addColumn("hasProjects"); QTest::addColumn("hasContexts"); QTest::addColumn("hasTags"); QTest::newRow("!projects !contexts !tags") << false << false << false; QTest::newRow("!projects !contexts tags") << false << false << true; QTest::newRow("!projects contexts !tags") << false << true << false; QTest::newRow("!projects contexts tags") << false << true << true; QTest::newRow("projects !contexts !tags") << true << false << false; QTest::newRow("projects !contexts tags") << true << false << true; QTest::newRow("projects contexts !tags") << true << true << false; QTest::newRow("projects contexts tags") << true << true << true; } void shouldShowOnlyAddActionsNeededByTheModel() { // GIVEN QFETCH(bool, hasProjects); QFETCH(bool, hasContexts); QFETCH(bool, hasTags); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("hasProjectPages", hasProjects); stubPagesModel.setProperty("hasContextPages", hasContexts); stubPagesModel.setProperty("hasTagPages", hasTags); Widgets::AvailablePagesView available; auto addProjectAction = available.findChild("addProjectAction"); QVERIFY(addProjectAction); auto addContextAction = available.findChild("addContextAction"); QVERIFY(addContextAction); auto addTagAction = available.findChild("addTagAction"); QVERIFY(addTagAction); // WHEN available.setModel(&stubPagesModel); // THEN QCOMPARE(addProjectAction->isVisible(), hasProjects); QCOMPARE(addContextAction->isVisible(), hasContexts); QCOMPARE(addTagAction->isVisible(), hasTags); } void shouldDisplayListFromPageModel() { // GIVEN QStringListModel model(QStringList() << "A" << "B" << "C" ); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); Widgets::AvailablePagesView available; auto pagesView = available.findChild("pagesView"); QVERIFY(pagesView); QVERIFY(!pagesView->model()); // WHEN available.setModel(&stubPagesModel); QTest::qWait(10); // THEN QCOMPARE(pagesView->model(), &model); QCOMPARE(pagesView->selectionModel()->currentIndex(), model.index(0, 0)); } + void shouldNotCrashWithNullModel() + { + // GIVEN + QStringListModel model(QStringList() << "A" << "B" << "C" ); + + AvailablePagesModelStub stubPagesModel; + stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); + + Widgets::AvailablePagesView available; + available.setModel(&stubPagesModel); + QTest::qWait(10); + + auto pagesView = available.findChild("pagesView"); + QVERIFY(pagesView); + QCOMPARE(pagesView->model(), &model); + + // WHEN + available.setModel(Q_NULLPTR); + QTest::qWait(10); + + // THEN + QVERIFY(!available.isEnabled()); + QVERIFY(!pagesView->model()); + } + void shouldAddNewProjects() { // GIVEN AvailablePagesModelStub model; QStringListModel sourceModel; auto dialogStub = NewProjectDialogStub::Ptr::create(); auto source = Domain::DataSource::Ptr::create(); Widgets::AvailablePagesView available; available.setModel(&model); available.setProjectSourcesModel(&sourceModel); available.setDefaultProjectSource(source); available.setProjectDialogFactory([dialogStub] (QWidget *parent) { dialogStub->parent = parent; return dialogStub; }); auto addProjectAction = available.findChild("addProjectAction"); // WHEN addProjectAction->trigger(); // THEN QCOMPARE(dialogStub->execCount, 1); QCOMPARE(dialogStub->parent, &available); QCOMPARE(dialogStub->sourceModel, &sourceModel); QCOMPARE(model.projectNames.size(), 1); QCOMPARE(model.projectNames.first(), dialogStub->name()); QCOMPARE(model.sources.size(), 1); QCOMPARE(model.sources.first(), dialogStub->dataSource()); QCOMPARE(available.defaultProjectSource(), dialogStub->dataSource()); } void shouldAddNewContexts() { // GIVEN AvailablePagesModelStub model; QStringListModel sourceModel; auto dialogStub = NewProjectDialogStub::Ptr::create(); auto source = Domain::DataSource::Ptr::create(); auto msgBoxStub = MessageBoxStub::Ptr::create(); msgBoxStub->setTextInput("Foo"); Widgets::AvailablePagesView available; available.setModel(&model); available.setProjectSourcesModel(&sourceModel); available.setDefaultProjectSource(source); available.setMessageBoxInterface(msgBoxStub); auto addContextAction = available.findChild("addContextAction"); // WHEN addContextAction->trigger(); // THEN QVERIFY(msgBoxStub->called()); QCOMPARE(model.contextNames.size(), 1); QCOMPARE(model.contextNames.first(), QString("Foo")); } void shouldAddNewTags() { // GIVEN AvailablePagesModelStub model; QStringListModel sourceModel; auto dialogStub = NewProjectDialogStub::Ptr::create(); auto source = Domain::DataSource::Ptr::create(); auto msgBoxStub = MessageBoxStub::Ptr::create(); msgBoxStub->setTextInput("Foo"); Widgets::AvailablePagesView available; available.setModel(&model); available.setProjectSourcesModel(&sourceModel); available.setDefaultProjectSource(source); available.setMessageBoxInterface(msgBoxStub); auto addTagAction = available.findChild("addTagAction"); // WHEN addTagAction->trigger(); // THEN QVERIFY(msgBoxStub->called()); QCOMPARE(model.tagNames.size(), 1); QCOMPARE(model.tagNames.first(), QString("Foo")); } void shouldRemoveAPage_data() { QTest::addColumn("object"); QTest::addColumn("actionEnabled"); auto project1 = Domain::Project::Ptr::create(); project1->setName("Project 1"); QTest::newRow("project") << QObjectPtr(project1) << true; auto context1 = Domain::Context::Ptr::create(); context1->setName("Context 1"); QTest::newRow("context") << QObjectPtr(context1) << true; auto tag1 = Domain::Tag::Ptr::create(); tag1->setName("Tag 1"); QTest::newRow("tag") << QObjectPtr(tag1) << true; QTest::newRow("non removable") << QObjectPtr::create() << false; } void shouldRemoveAPage() { QFETCH(QObjectPtr, object); QFETCH(bool, actionEnabled); // GIVEN QStringList list; list << "A" << "B" << "C"; QStandardItemModel model; for (int row = 0; row < list.count(); ++row) { model.setItem(row, new QStandardItem(list.at(row))); } QVERIFY(model.setData(model.index(0, 0), QVariant::fromValue(object), Presentation::QueryTreeModelBase::ObjectRole)); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); Widgets::AvailablePagesView available; auto pagesView = available.findChild("pagesView"); QVERIFY(pagesView); QVERIFY(!pagesView->model()); available.setModel(&stubPagesModel); QTest::qWait(10); auto removeAction = available.findChild("removeAction"); auto msgbox = MessageBoxStub::Ptr::create(); available.setMessageBoxInterface(msgbox); // WHEN if (actionEnabled) removeAction->trigger(); // THEN QCOMPARE(removeAction->isEnabled(), actionEnabled); if (actionEnabled) { QCOMPARE(stubPagesModel.projectRemoved, list.first()); } } void shouldGoToPreviousSelectablePage() { // GIVEN QStandardItemModel model; model.appendRow(new QStandardItem("Inbox")); auto projects = new QStandardItem("Projects"); projects->setFlags(Qt::NoItemFlags); model.appendRow(projects); projects->appendRow(new QStandardItem("Project 1")); projects->appendRow(new QStandardItem("Project 2")); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); Widgets::AvailablePagesView available; auto pagesView = available.findChild("pagesView"); QVERIFY(pagesView); QVERIFY(!pagesView->model()); available.setModel(&stubPagesModel); QTest::qWait(10); auto goPreviousAction = available.findChild("goPreviousAction"); pagesView->setCurrentIndex(model.index(1, 0, model.indexFromItem(projects))); // WHEN goPreviousAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(0, 0, model.indexFromItem(projects))); // WHEN goPreviousAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(0, 0)); // WHEN goPreviousAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(0, 0)); } void shouldGoToNextSelectablePage() { // GIVEN QStandardItemModel model; model.appendRow(new QStandardItem("Inbox")); auto projects = new QStandardItem("Projects"); projects->setFlags(Qt::NoItemFlags); model.appendRow(projects); projects->appendRow(new QStandardItem("Project 1")); projects->appendRow(new QStandardItem("Project 2")); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); Widgets::AvailablePagesView available; auto pagesView = available.findChild("pagesView"); QVERIFY(pagesView); QVERIFY(!pagesView->model()); available.setModel(&stubPagesModel); QTest::qWait(10); auto goNextAction = available.findChild("goNextAction"); pagesView->setCurrentIndex(model.index(0, 0)); // WHEN goNextAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(0, 0, model.indexFromItem(projects))); // WHEN goNextAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(1, 0, model.indexFromItem(projects))); // WHEN goNextAction->trigger(); // THEN QCOMPARE(pagesView->currentIndex(), model.index(1, 0, model.indexFromItem(projects))); } void shouldGoToUserSelectedIndex() { // GIVEN QStandardItemModel model; model.appendRow(new QStandardItem("Inbox")); auto projects = new QStandardItem("Projects"); projects->setFlags(Qt::NoItemFlags); model.appendRow(projects); projects->appendRow(new QStandardItem("Project 1")); projects->appendRow(new QStandardItem("Project 2")); AvailablePagesModelStub stubPagesModel; stubPagesModel.setProperty("pageListModel", QVariant::fromValue(static_cast(&model))); auto dialogStub = QuickSelectDialogStub::Ptr::create(); // Project 2 will be selected dialogStub->index = model.index(1, 0, model.index(1, 0)); Widgets::AvailablePagesView available; available.setModel(&stubPagesModel); available.setQuickSelectDialogFactory([dialogStub] (QWidget *parent) { dialogStub->parent = parent; return dialogStub; }); auto pagesView = available.findChild("pagesView"); QVERIFY(pagesView); QCOMPARE(pagesView->model(), &model); auto goToAction = available.findChild("goToAction"); // WHEN goToAction->trigger(); // THEN QCOMPARE(dialogStub->execCount, 1); QCOMPARE(dialogStub->parent, &available); QCOMPARE(dialogStub->itemModel, &model); QCOMPARE(QPersistentModelIndex(pagesView->currentIndex()), dialogStub->index); } }; QTEST_MAIN(AvailablePagesViewTest) #include "availablepagesviewtest.moc"