diff --git a/src/autotests/koeventpopupmenutest.cpp b/src/autotests/koeventpopupmenutest.cpp index 64f3a53f..91b8f25e 100644 --- a/src/autotests/koeventpopupmenutest.cpp +++ b/src/autotests/koeventpopupmenutest.cpp @@ -1,265 +1,266 @@ /* Copyright (c) 2014 Sandro Knauß This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. 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 "koeventpopupmenutest.h" #include "koeventpopupmenu.h" #include "dialog/noteeditdialog.h" #include #include #include #include #include -KoEventPopupMenuTest::KoEventPopupMenuTest() +KoEventPopupMenuTest::KoEventPopupMenuTest(QObject *parent) + : QObject(parent) { QStandardPaths::setTestModeEnabled(true); } void KoEventPopupMenuTest::createEventFromEvent() { Akonadi::ETMCalendar::Ptr calendar(new Akonadi::ETMCalendar()); KOEventPopupMenu menu(nullptr); KCalCore::Event::Ptr event(new KCalCore::Event()); Akonadi::Item item; item.setMimeType(KCalCore::Event::eventMimeType()); item.setPayload(event); menu.setCalendar(calendar); menu.showIncidencePopup(item, QDate()); QAction *createevent = menu.findChild(QStringLiteral("createevent")); createevent->trigger(); IncidenceEditorNG::IncidenceDialog *dlg = menu.findChild(QStringLiteral( "incidencedialog")); QVERIFY(!dlg); } void KoEventPopupMenuTest::createTodoFromTodo() { Akonadi::ETMCalendar::Ptr calendar(new Akonadi::ETMCalendar()); KOEventPopupMenu menu(nullptr); KCalCore::Todo::Ptr todo(new KCalCore::Todo()); Akonadi::Item item; item.setMimeType(KCalCore::Todo::todoMimeType()); item.setPayload(todo); menu.setCalendar(calendar); menu.showIncidencePopup(item, QDate()); QAction *createtodo = menu.findChild(QStringLiteral("createtodo")); createtodo->trigger(); IncidenceEditorNG::IncidenceDialog *dlg = menu.findChild(QStringLiteral( "incidencedialog")); QVERIFY(!dlg); } void KoEventPopupMenuTest::createEventFromTodo() { Akonadi::ETMCalendar::Ptr calendar(new Akonadi::ETMCalendar()); KOEventPopupMenu menu(nullptr); KCalCore::Todo::Ptr todo(new KCalCore::Todo()); Akonadi::Item item; item.setMimeType(KCalCore::Todo::todoMimeType()); item.setPayload(todo); QDateTime start, end; QString summary(QStringLiteral("a test")); start = QDateTime::fromSecsSinceEpoch(1402593346); end = QDateTime::fromSecsSinceEpoch(1403593346); todo->setDtStart(start); todo->setDtDue(end); todo->setSummary(summary); menu.setCalendar(calendar); menu.showIncidencePopup(item, QDate()); QAction *createevent = menu.findChild(QStringLiteral("createevent")); createevent->trigger(); IncidenceEditorNG::IncidenceDialog *dlg = menu.findChild(); QVERIFY(dlg); IncidenceEditorNG::IncidenceEditor *editor = menu.findChild(); QVERIFY(editor); KCalCore::Event::Ptr event(editor->incidence()); QVERIFY(event->uid() != todo->uid()); QCOMPARE(event->dtStart(), start); QCOMPARE(event->dtEnd(), end); QCOMPARE(event->allDay(), false); QCOMPARE(event->summary(), summary); } void KoEventPopupMenuTest::createTodoFromEvent() { Akonadi::ETMCalendar::Ptr calendar(new Akonadi::ETMCalendar()); KOEventPopupMenu menu(nullptr); KCalCore::Event::Ptr event(new KCalCore::Event()); Akonadi::Item item; item.setMimeType(KCalCore::Event::eventMimeType()); item.setPayload(event); QDateTime start, end; QString summary(QStringLiteral("a test")); start = QDateTime::fromSecsSinceEpoch(1402593346); end = QDateTime::fromSecsSinceEpoch(1403593346); event->setDtStart(start); event->setDtEnd(end); event->setSummary(summary); menu.setCalendar(calendar); menu.showIncidencePopup(item, QDate()); QAction *createtodo = menu.findChild(QStringLiteral("createtodo")); createtodo->trigger(); IncidenceEditorNG::IncidenceDialog *dlg = menu.findChild(); QVERIFY(dlg); IncidenceEditorNG::IncidenceEditor *editor = menu.findChild(); QVERIFY(editor); KCalCore::Todo::Ptr todo(editor->incidence()); QVERIFY(todo->uid() != event->uid()); QCOMPARE(todo->dtStart(), start); QCOMPARE(todo->dtDue(), end); QCOMPARE(todo->allDay(), false); QCOMPARE(todo->summary(), summary); } void KoEventPopupMenuTest::createNoteFromEvent() { Akonadi::ETMCalendar::Ptr calendar(new Akonadi::ETMCalendar()); KOEventPopupMenu menu(nullptr); KCalCore::Event::Ptr event(new KCalCore::Event()); Akonadi::Item item; item.setMimeType(KCalCore::Event::eventMimeType()); item.setPayload(event); QDateTime start, end; QString summary(QStringLiteral("A test")); QString description(QStringLiteral("A long description")); start = QDateTime::fromSecsSinceEpoch(1402593346); end = QDateTime::fromSecsSinceEpoch(1403593346); event->setDtStart(start); event->setDtEnd(end); event->setSummary(summary); event->setDescription(description, true); menu.setCalendar(calendar); menu.showIncidencePopup(item, QDate()); QAction *createnote = menu.findChild(QStringLiteral("createnote")); NoteEditDialog *noteedit = menu.findChild(); QVERIFY(!noteedit); createnote->trigger(); noteedit = menu.findChild(); QVERIFY(noteedit); Akonadi::NoteUtils::NoteMessageWrapper note(noteedit->note()); QCOMPARE(note.title(), summary); QCOMPARE(note.text(), description); QCOMPARE(note.textFormat(), Qt::RichText); QCOMPARE(note.attachments().count(), 1); QCOMPARE(note.attachments().at(0).mimetype(), KCalCore::Event::eventMimeType()); QCOMPARE(note.attachments().at(0).url(), (QUrl)item.url()); QCOMPARE(note.attachments().at(0).data(), QByteArray()); } void KoEventPopupMenuTest::createNoteFromTodo() { Akonadi::ETMCalendar::Ptr calendar(new Akonadi::ETMCalendar()); KOEventPopupMenu menu(nullptr); KCalCore::Todo::Ptr todo(new KCalCore::Todo()); Akonadi::Item item; item.setMimeType(KCalCore::Todo::todoMimeType()); item.setPayload(todo); QDateTime start, end; QString summary(QStringLiteral("a test")); QString description(QStringLiteral("A long description")); start = QDateTime::fromSecsSinceEpoch(1402593346); end = QDateTime::fromSecsSinceEpoch(1403593346); todo->setDtStart(start); todo->setDtDue(end); todo->setSummary(summary); todo->setDescription(description); menu.setCalendar(calendar); menu.showIncidencePopup(item, QDate()); QAction *createnote = menu.findChild(QStringLiteral("createnote")); NoteEditDialog *noteedit = menu.findChild(); QVERIFY(!noteedit); createnote->trigger(); noteedit = menu.findChild(); QVERIFY(noteedit); Akonadi::NoteUtils::NoteMessageWrapper note(noteedit->note()); QCOMPARE(note.title(), summary); QCOMPARE(note.text(), description); QCOMPARE(note.attachments().count(), 1); QCOMPARE(note.attachments().at(0).mimetype(), KCalCore::Todo::todoMimeType()); QCOMPARE(note.attachments().at(0).url(), (QUrl)item.url()); QCOMPARE(note.attachments().at(0).data(), QByteArray()); } void KoEventPopupMenuTest::defaultMenuEventVisible() { Akonadi::ETMCalendar::Ptr calendar(new Akonadi::ETMCalendar()); KOEventPopupMenu menu(nullptr); KCalCore::Event::Ptr event(new KCalCore::Event()); Akonadi::Item item; item.setMimeType(KCalCore::Event::eventMimeType()); item.setPayload(event); menu.setCalendar(calendar); menu.showIncidencePopup(item, QDate()); QAction *createevent = menu.findChild(QStringLiteral("createevent")); QAction *createnote = menu.findChild(QStringLiteral("createnote")); QAction *createtodo = menu.findChild(QStringLiteral("createtodo")); QVERIFY(!createevent->isVisible()); QVERIFY(createnote->isVisible()); QVERIFY(createtodo->isVisible()); } void KoEventPopupMenuTest::defaultMenuTodoVisible() { Akonadi::ETMCalendar::Ptr calendar(new Akonadi::ETMCalendar()); KOEventPopupMenu menu(nullptr); KCalCore::Todo::Ptr todo(new KCalCore::Todo()); Akonadi::Item item; item.setMimeType(KCalCore::Todo::todoMimeType()); item.setPayload(todo); menu.setCalendar(calendar); menu.showIncidencePopup(item, QDate()); QAction *createevent = menu.findChild(QStringLiteral("createevent")); QAction *createnote = menu.findChild(QStringLiteral("createnote")); QAction *createtodo = menu.findChild(QStringLiteral("createtodo")); QVERIFY(createevent->isVisible()); QVERIFY(createnote->isVisible()); QVERIFY(!createtodo->isVisible()); } QTEST_MAIN(KoEventPopupMenuTest) diff --git a/src/autotests/koeventpopupmenutest.h b/src/autotests/koeventpopupmenutest.h index 0865cb6a..5ba888ca 100644 --- a/src/autotests/koeventpopupmenutest.h +++ b/src/autotests/koeventpopupmenutest.h @@ -1,45 +1,45 @@ /* Copyright (c) 2014 Sandro Knauß This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License, version 2, as published by the Free Software Foundation. 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 KOEVENTPOPUPMENUTESTTEST_H #define KOEVENTPOPUPMENUTESTTEST_H #include #include namespace Akonadi { class Collection; } class KoEventPopupMenuTest : public QObject { Q_OBJECT public: - KoEventPopupMenuTest(); + explicit KoEventPopupMenuTest(QObject *parent = nullptr); private Q_SLOTS: void createEventFromTodo(); void createTodoFromEvent(); void createEventFromEvent(); void createTodoFromTodo(); void createNoteFromEvent(); void createNoteFromTodo(); void defaultMenuEventVisible(); void defaultMenuTodoVisible(); }; #endif // KOEVENTPOPUPMENUTESTTEST_H diff --git a/src/korganizer.cpp b/src/korganizer.cpp index ab53b846..af811944 100644 --- a/src/korganizer.cpp +++ b/src/korganizer.cpp @@ -1,293 +1,293 @@ /* This file is part of KOrganizer. Copyright (c) 1997, 1998, 1999 Preston Brown Fester Zigterman Ian Dawes Laszlo Boloni Copyright (c) 2000-2003 Cornelius Schumacher Copyright (C) 2003-2004 Reinhold Kainhofer 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) any later version. 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. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include "korganizer.h" #include "actionmanager.h" #include "calendarview.h" #include "kocore.h" #include "koglobals.h" #include "impl/korganizerifaceimpl.h" #include "plugininterface/korganizerplugininterface.h" #include #include #include #include "korganizer_debug.h" #include #include #include #include #include KOrganizer::KOrganizer() : KParts::MainWindow() , KOrg::MainWindow() { // Set this to be the group leader for all subdialogs - this means // modal subdialogs will only affect this dialog, not the other windows setAttribute(Qt::WA_GroupLeader); KOCore::self()->addXMLGUIClient(this, this); // setMinimumSize(600,400); // make sure we don't get resized too small... mCalendarView = new CalendarView(this); mCalendarView->setObjectName(QStringLiteral("KOrganizer::CalendarView")); setCentralWidget(mCalendarView); mActionManager = new ActionManager(this, mCalendarView, this, this, false, menuBar()); (void)new KOrganizerIfaceImpl(mActionManager, this, QStringLiteral("IfaceImpl")); } KOrganizer::~KOrganizer() { delete mActionManager; KOCore::self()->removeXMLGUIClient(this); } void KOrganizer::init(bool document) { setHasDocument(document); // Create calendar object, which manages all calendar information associated // with this calendar view window. mActionManager->createCalendarAkonadi(); mActionManager->init(); mActionManager->loadParts(); KOrganizerPluginInterface::self()->setActionCollection(actionCollection()); KOrganizerPluginInterface::self()->initializePlugins(); initActions(); readSettings(); QStatusBar *bar = statusBar(); bar->addWidget(new QLabel(this)); KPIM::ProgressStatusBarWidget *progressBar = new KPIM::ProgressStatusBarWidget(statusBar(), this); bar->addPermanentWidget(progressBar->littleProgress()); connect(mActionManager->view(), &CalendarView::statusMessage, this, &KOrganizer::showStatusMessage); setStandardToolBarMenuEnabled(true); setTitle(); } #if 0 void KOrganizer::initializePluginActions() { #if 0 if (mXmlGuiClient->factory()) { QHashIterator > localActionsType( mPluginInterface->actionsType()); while (localActionsType.hasNext()) { localActionsType.next(); QList lst = localActionsType.value(); if (!lst.isEmpty()) { const QString actionlistname = QStringLiteral("korganizer") + PimCommon::PluginInterface::actionXmlExtension( localActionsType.key()); mXmlGuiClient->unplugActionList(actionlistname); mXmlGuiClient->plugActionList(actionlistname, lst); } } } #else qCDebug(KORGANIZER_LOG) << " Plugins not implemented yet"; #endif } #endif void KOrganizer::newMainWindow(const QUrl &url) { KOrganizer *korg = new KOrganizer(); if (url.isValid() || url.isEmpty()) { korg->init(true); if (mActionManager->importURL(url, false) || url.isEmpty()) { korg->show(); } else { delete korg; } } else { korg->init(false); korg->show(); } } void KOrganizer::readSettings() { // read settings from the KConfig, supplying reasonable // defaults where none are to be found KSharedConfig::Ptr config = KSharedConfig::openConfig(); mActionManager->readSettings(); config->sync(); } void KOrganizer::writeSettings() { KSharedConfig::Ptr config = KSharedConfig::openConfig(); mActionManager->writeSettings(); config->sync(); } void KOrganizer::initActions() { setStandardToolBarMenuEnabled(true); createStandardStatusBarAction(); KStandardAction::keyBindings(this, &KOrganizer::slotEditKeys, actionCollection()); KStandardAction::configureToolbars(this, &KOrganizer::configureToolbars, actionCollection()); KStandardAction::quit(this, &KOrganizer::close, actionCollection()); setXMLFile(QStringLiteral("korganizerui.rc"), true); createGUI(nullptr); setAutoSaveSettings(); } void KOrganizer::slotEditKeys() { KShortcutsDialog::configure(actionCollection(), KShortcutsEditor::LetterShortcutsAllowed); } bool KOrganizer::queryClose() { bool close = mActionManager->queryClose(); // Write configuration. I don't know if it really makes sense doing it this // way, when having opened multiple calendars in different CalendarViews. if (close) { writeSettings(); } return close; } void KOrganizer::showStatusMessage(const QString &message) { statusBar()->showMessage(message, 2000); } bool KOrganizer::openURL(const QUrl &url, bool merge) { return mActionManager->importURL(url, merge); } bool KOrganizer::saveURL() { return mActionManager->saveURL(); } bool KOrganizer::saveAsURL(const QUrl &kurl) { return mActionManager->saveAsURL(kurl); } QUrl KOrganizer::getCurrentURL() const { return mActionManager->url(); } KXMLGUIFactory *KOrganizer::mainGuiFactory() { return factory(); } KXMLGUIClient *KOrganizer::mainGuiClient() { return this; } QWidget *KOrganizer::topLevelWidget() { return this; } void KOrganizer::saveProperties(KConfigGroup &config) { - return mActionManager->saveProperties(config); + mActionManager->saveProperties(config); } void KOrganizer::readProperties(const KConfigGroup &config) { - return mActionManager->readProperties(config); + mActionManager->readProperties(config); } KOrg::CalendarViewBase *KOrganizer::view() const { return mActionManager->view(); } ActionManager *KOrganizer::actionManager() { return mActionManager; } KActionCollection *KOrganizer::getActionCollection() const { return actionCollection(); } void KOrganizer::setTitle() { QString title; if (hasDocument()) { QUrl url = mActionManager->url(); if (!url.isEmpty()) { if (url.isLocalFile()) { title = url.fileName(); } else { title = url.toDisplayString(); } } else { title = i18n("New Calendar"); } if (mCalendarView->isReadOnly()) { title += QLatin1String(" [") + i18nc("the calendar is read-only", "read-only") + QLatin1Char(']'); } } else { title = i18n("Calendar"); } if (mCalendarView->isFiltered()) { title += QLatin1String(" - <") + mCalendarView->currentFilterName() + QLatin1String("> "); } setCaption(title, false); } diff --git a/src/prefs/koprefs.cpp b/src/prefs/koprefs.cpp index a3159027..aebdc931 100644 --- a/src/prefs/koprefs.cpp +++ b/src/prefs/koprefs.cpp @@ -1,127 +1,127 @@ /* This file is part of KOrganizer. Copyright (c) 2001,2003 Cornelius Schumacher Copyright (C) 2003-2004 Reinhold Kainhofer 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) any later version. 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. As a special exception, permission is given to link this program with any edition of Qt, and distribute the resulting executable, without including the source code for Qt in the source distribution. */ #include "koprefs.h" #include "korganizer_debug.h" #include class KOPrefsPrivate { public: KOPrefsPrivate() : prefs(new KOPrefs) { } ~KOPrefsPrivate() { delete prefs; } KOPrefs *prefs = nullptr; }; Q_GLOBAL_STATIC(KOPrefsPrivate, sInstance) KOPrefs::KOPrefs() : KOPrefsBase() { mEventViewsPrefs = EventViews::PrefsPtr(new EventViews::Prefs(this)); mDefaultMonthViewFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont); // make it a bit smaller mDefaultMonthViewFont.setPointSize( qMax(mDefaultMonthViewFont.pointSize() - 2, 6)); KConfigSkeleton::setCurrentGroup(QStringLiteral("General")); monthViewFontItem()->setDefaultValue(mDefaultMonthViewFont); } KOPrefs::~KOPrefs() { mEventViewsPrefs->writeConfig(); } KOPrefs *KOPrefs::instance() { if (!sInstance.exists()) { sInstance->prefs->load(); sInstance->prefs->mEventViewsPrefs->readConfig(); } return sInstance->prefs; } void KOPrefs::usrSetDefaults() { setMonthViewFont(mDefaultMonthViewFont); KConfigSkeleton::usrSetDefaults(); } void KOPrefs::usrRead() { KConfigGroup timeScaleConfig(config(), "Timescale"); setTimeScaleTimezones(timeScaleConfig.readEntry("Timescale Timezones", QStringList())); KConfigSkeleton::usrRead(); } bool KOPrefs::usrSave() { KConfigGroup timeScaleConfig(config(), "Timescale"); timeScaleConfig.writeEntry("Timescale Timezones", timeScaleTimezones()); return KConfigSkeleton::usrSave(); } void KOPrefs::setResourceColor(const QString &cal, const QColor &color) { - return mEventViewsPrefs->setResourceColor(cal, color); + mEventViewsPrefs->setResourceColor(cal, color); } QColor KOPrefs::resourceColor(const QString &cal) { return mEventViewsPrefs->resourceColor(cal); } QColor KOPrefs::resourceColorKnown(const QString &cal) const { return mEventViewsPrefs->resourceColorKnown(cal); } QStringList KOPrefs::timeScaleTimezones() const { return mTimeScaleTimeZones; } void KOPrefs::setTimeScaleTimezones(const QStringList &list) { mTimeScaleTimeZones = list; } EventViews::PrefsPtr KOPrefs::eventViewsPreferences() const { return mEventViewsPrefs; } diff --git a/src/views/collectionview/autotests/reparentingmodeltest.cpp b/src/views/collectionview/autotests/reparentingmodeltest.cpp index a10109bf..f67df528 100644 --- a/src/views/collectionview/autotests/reparentingmodeltest.cpp +++ b/src/views/collectionview/autotests/reparentingmodeltest.cpp @@ -1,839 +1,839 @@ /* * Copyright (C) 2014 Christian Mollekopf * * 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) any later version. * * 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. * * As a special exception, permission is given to link this program * with any edition of Qt, and distribute the resulting executable, * without including the source code for Qt in the source distribution. */ #include #include #include #include #include "korganizer_debug.h" #include "reparentingmodel.h" class DummyNode : public ReparentingModel::Node { public: DummyNode(ReparentingModel &personModel, const QString &name, const QString &data = QString()) : ReparentingModel::Node(personModel) , mUid(name) , mParent(QStringLiteral("orphan")) , mName(name) , mData(data) { } virtual ~DummyNode() { } bool operator==(const Node &node) const override { const DummyNode *dummyNode = dynamic_cast(&node); if (dummyNode) { return dummyNode->mUid == mUid; } return false; } QString mUid; QString mParent; private: QVariant data(int role) const override { if (role == Qt::DisplayRole) { if (mName != mUid) { return QString(mUid + QLatin1Char('-') + mName); } else { return mName; } } else if (role == Qt::UserRole) { return mData; } return QVariant(); } bool setData(const QVariant &variant, int role) override { Q_UNUSED(variant); Q_UNUSED(role); return false; } bool isDuplicateOf(const QModelIndex &sourceIndex) override { return sourceIndex.data().toString() == mUid; } bool adopts(const QModelIndex &sourceIndex) override { return sourceIndex.data().toString().contains(mParent); } void update(const Node::Ptr &node) override { mName = node.staticCast()->mName; mData = node.staticCast()->mData; } QString mName; QString mData; }; class ModelSignalSpy : public QObject { Q_OBJECT public: explicit ModelSignalSpy(QAbstractItemModel &model) : start(0) , end(0) { - connect(&model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, - SLOT(onRowsInserted(QModelIndex,int,int))); - connect(&model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, - SLOT(onRowsRemoved(QModelIndex,int,int))); - connect(&model, SIGNAL(rowsMoved(QModelIndex,int,int,QModelIndex,int)), this, - SLOT(onRowsMoved(QModelIndex,int,int,QModelIndex,int))); - connect(&model, SIGNAL(dataChanged(QModelIndex,QModelIndex)), this, - SLOT(onDataChanged(QModelIndex,QModelIndex))); + connect(&model, &QAbstractItemModel::rowsInserted, this, + &ModelSignalSpy::onRowsInserted); + connect(&model, &QAbstractItemModel::rowsRemoved, this, + &ModelSignalSpy::onRowsRemoved); + connect(&model, &QAbstractItemModel::rowsMoved, this, + &ModelSignalSpy::onRowsMoved); + connect(&model, &QAbstractItemModel::dataChanged, this, + &ModelSignalSpy::onDataChanged); connect(&model, &QAbstractItemModel::layoutChanged, this, &ModelSignalSpy::onLayoutChanged); connect(&model, &QAbstractItemModel::modelReset, this, &ModelSignalSpy::onModelReset); } QStringList mSignals; QModelIndex parent; QModelIndex topLeft, bottomRight; int start; int end; public Q_SLOTS: void onRowsInserted(const QModelIndex &p, int s, int e) { mSignals << QStringLiteral("rowsInserted"); parent = p; start = s; end = e; } void onRowsRemoved(const QModelIndex &p, int s, int e) { mSignals << QStringLiteral("rowsRemoved"); parent = p; start = s; end = e; } void onRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int) { mSignals << QStringLiteral("rowsMoved"); } void onDataChanged(const QModelIndex &t, const QModelIndex &b) { mSignals << QStringLiteral("dataChanged"); topLeft = t; bottomRight = b; } void onLayoutChanged() { mSignals << QStringLiteral("layoutChanged"); } void onModelReset() { mSignals << QStringLiteral("modelReset"); } }; QModelIndex getIndex(const char *string, const QAbstractItemModel &model) { QModelIndexList list = model.match(model.index(0, 0), Qt::DisplayRole, QString::fromLatin1( string), 1, Qt::MatchRecursive); if (list.isEmpty()) { return QModelIndex(); } return list.first(); } QModelIndexList getIndexList(const char *string, const QAbstractItemModel &model) { return model.match(model.index(0, 0), Qt::DisplayRole, QString::fromLatin1( string), 1, Qt::MatchRecursive); } class ReparentingModelTest : public QObject { Q_OBJECT private Q_SLOTS: void testPopulation(); void testAddRemoveSourceItem(); void testInsertSourceRow(); void testInsertSourceRowSubnode(); void testAddRemoveProxyNode(); void testDeduplicate(); void testDeduplicateNested(); void testDeduplicateProxyNodeFirst(); void testNestedDeduplicateProxyNodeFirst(); void testUpdateNode(); void testReparent(); void testReparentSubcollections(); void testReparentResetWithoutCrash(); void testAddReparentedSourceItem(); void testRemoveReparentedSourceItem(); void testNestedReparentedSourceItem(); void testAddNestedReparentedSourceItem(); void testSourceDataChanged(); void testSourceLayoutChanged(); void testInvalidLayoutChanged(); void testAddRemoveNodeByNodeManager(); void testRemoveNodeByNodeManagerWithDataChanged(); void testDataChanged(); }; void ReparentingModelTest::testPopulation() { QStandardItemModel sourceModel; sourceModel.appendRow(new QStandardItem(QStringLiteral("row1"))); sourceModel.appendRow(new QStandardItem(QStringLiteral("row2"))); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 2); QVERIFY(getIndex("row1", reparentingModel).isValid()); QVERIFY(getIndex("row2", reparentingModel).isValid()); } void ReparentingModelTest::testAddRemoveSourceItem() { QStandardItemModel sourceModel; sourceModel.appendRow(new QStandardItem(QStringLiteral("row1"))); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); ModelSignalSpy spy(reparentingModel); sourceModel.appendRow(new QStandardItem(QStringLiteral("row2"))); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 2); QVERIFY(getIndex("row1", reparentingModel).isValid()); QVERIFY(getIndex("row2", reparentingModel).isValid()); QCOMPARE(spy.parent, QModelIndex()); QCOMPARE(spy.start, 1); QCOMPARE(spy.end, 1); sourceModel.removeRows(1, 1, QModelIndex()); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QVERIFY(getIndex("row1", reparentingModel).isValid()); QVERIFY(!getIndex("row2", reparentingModel).isValid()); QCOMPARE(spy.parent, QModelIndex()); QCOMPARE(spy.start, 1); QCOMPARE(spy.end, 1); QCOMPARE(spy.mSignals, QStringList() << QStringLiteral("rowsInserted") << QStringLiteral("rowsRemoved")); } //Ensure the model can deal with rows that are inserted out of order void ReparentingModelTest::testInsertSourceRow() { QStandardItemModel sourceModel; QStandardItem *row2 = new QStandardItem(QStringLiteral("row2")); sourceModel.appendRow(row2); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); ModelSignalSpy spy(reparentingModel); QStandardItem *row1 = new QStandardItem(QStringLiteral("row1")); sourceModel.insertRow(0, row1); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 2); QVERIFY(getIndex("row1", reparentingModel).isValid()); QVERIFY(getIndex("row2", reparentingModel).isValid()); //The model does not try to reorder. First come, first serve. QCOMPARE(getIndex("row1", reparentingModel).row(), 1); QCOMPARE(getIndex("row2", reparentingModel).row(), 0); reparentingModel.setData(reparentingModel.index(1, 0, QModelIndex()), QStringLiteral( "row1foo"), Qt::DisplayRole); reparentingModel.setData(reparentingModel.index(0, 0, QModelIndex()), QStringLiteral( "row2foo"), Qt::DisplayRole); QCOMPARE(row1->data(Qt::DisplayRole).toString(), QStringLiteral("row1foo")); QCOMPARE(row2->data(Qt::DisplayRole).toString(), QStringLiteral("row2foo")); } //Ensure the model can deal with rows that are inserted out of order in a subnode void ReparentingModelTest::testInsertSourceRowSubnode() { QStandardItem *parent = new QStandardItem(QStringLiteral("parent")); QStandardItemModel sourceModel; sourceModel.appendRow(parent); QStandardItem *row2 = new QStandardItem(QStringLiteral("row2")); parent->appendRow(row2); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); ModelSignalSpy spy(reparentingModel); QStandardItem *row1 = new QStandardItem(QStringLiteral("row1")); parent->insertRow(0, row1); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QVERIFY(getIndex("row1", reparentingModel).isValid()); QVERIFY(getIndex("row2", reparentingModel).isValid()); //The model does not try to reorder. First come, first serve. QCOMPARE(getIndex("row1", reparentingModel).row(), 1); QCOMPARE(getIndex("row2", reparentingModel).row(), 0); reparentingModel.setData(reparentingModel.index(1, 0, getIndex("parent", reparentingModel)), QStringLiteral("row1foo"), Qt::DisplayRole); reparentingModel.setData(reparentingModel.index(0, 0, getIndex("parent", reparentingModel)), QStringLiteral("row2foo"), Qt::DisplayRole); QCOMPARE(row1->data(Qt::DisplayRole).toString(), QStringLiteral("row1foo")); QCOMPARE(row2->data(Qt::DisplayRole).toString(), QStringLiteral("row2foo")); } void ReparentingModelTest::testAddRemoveProxyNode() { QStandardItemModel sourceModel; sourceModel.appendRow(new QStandardItem(QStringLiteral("row1"))); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); ModelSignalSpy spy(reparentingModel); reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("proxy1")))); QTest::qWait(0); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 2); QVERIFY(getIndex("row1", reparentingModel).isValid()); QVERIFY(getIndex("proxy1", reparentingModel).isValid()); reparentingModel.removeNode(DummyNode(reparentingModel, QStringLiteral("proxy1"))); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QVERIFY(getIndex("row1", reparentingModel).isValid()); QVERIFY(!getIndex("proxy1", reparentingModel).isValid()); QCOMPARE(spy.mSignals, QStringList() << QStringLiteral("rowsInserted") << QStringLiteral("rowsRemoved")); } void ReparentingModelTest::testDeduplicate() { QStandardItemModel sourceModel; sourceModel.appendRow(new QStandardItem(QStringLiteral("row1"))); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("row1")))); QTest::qWait(0); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QCOMPARE(getIndexList("row1", reparentingModel).size(), 1); //TODO ensure we actually have the source index and not the proxy index } /** * rebuildAll detects and handles nested duplicates */ void ReparentingModelTest::testDeduplicateNested() { QStandardItemModel sourceModel; QStandardItem *item = new QStandardItem(QStringLiteral("row1")); item->appendRow(new QStandardItem(QStringLiteral("child1"))); sourceModel.appendRow(item); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("child1")))); QTest::qWait(0); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QCOMPARE(getIndexList("child1", reparentingModel).size(), 1); } /** * onSourceRowsInserted detects and removes duplicates */ void ReparentingModelTest::testDeduplicateProxyNodeFirst() { QStandardItemModel sourceModel; ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("row1")))); QTest::qWait(0); sourceModel.appendRow(new QStandardItem(QStringLiteral("row1"))); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QCOMPARE(getIndexList("row1", reparentingModel).size(), 1); //TODO ensure we actually have the source index and not the proxy index } /** * onSourceRowsInserted detects and removes nested duplicates */ void ReparentingModelTest::testNestedDeduplicateProxyNodeFirst() { QStandardItemModel sourceModel; ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("child1")))); QTest::qWait(0); QStandardItem *item = new QStandardItem(QStringLiteral("row1")); item->appendRow(new QStandardItem(QStringLiteral("child1"))); sourceModel.appendRow(item); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QCOMPARE(getIndexList("child1", reparentingModel).size(), 1); //TODO ensure we actually have the source index and not the proxy index } /** * updateNode should update the node data */ void ReparentingModelTest::testUpdateNode() { QStandardItemModel sourceModel; ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("proxy1"), QStringLiteral("blub")))); QTest::qWait(0); QModelIndex index = getIndex("proxy1", reparentingModel); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QVERIFY(index.isValid()); QCOMPARE(reparentingModel.data(index, Qt::UserRole).toString(), QStringLiteral("blub")); ModelSignalSpy spy(reparentingModel); reparentingModel.updateNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("proxy1"), QStringLiteral( "new data")))); QTest::qWait(0); QModelIndex i2 = getIndex("proxy1", reparentingModel); QCOMPARE(i2.column(), index.column()); QCOMPARE(i2.row(), index.row()); QCOMPARE(spy.mSignals.count(), 1); QCOMPARE(spy.mSignals.takeLast(), QStringLiteral("dataChanged")); QCOMPARE(spy.topLeft, i2); QCOMPARE(spy.bottomRight, i2); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QCOMPARE(reparentingModel.data(i2, Qt::UserRole).toString(), QStringLiteral("new data")); } void ReparentingModelTest::testReparent() { QStandardItemModel sourceModel; sourceModel.appendRow(new QStandardItem(QStringLiteral("orphan"))); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("proxy1")))); QTest::qWait(0); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QVERIFY(getIndex("proxy1", reparentingModel).isValid()); QCOMPARE(reparentingModel.rowCount(getIndex("proxy1", reparentingModel)), 1); } void ReparentingModelTest::testReparentSubcollections() { QStandardItemModel sourceModel; ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); /* Source structure -- + -- + orphan -- + col1 -- sub1 -- sub2 -- col2 */ sourceModel.appendRow(new QStandardItem(QStringLiteral("orphan"))); sourceModel.item(0, 0)->appendRow(new QStandardItem(QStringLiteral("col1"))); sourceModel.item(0, 0)->child(0, 0)->appendRow(new QStandardItem(QStringLiteral("sub1"))); sourceModel.item(0, 0)->child(0, 0)->appendRow(new QStandardItem(QStringLiteral("sub2"))); sourceModel.item(0, 0)->appendRow(new QStandardItem(QStringLiteral("col2"))); DummyNode *node = new DummyNode(reparentingModel, QStringLiteral("col1")); node->mUid = QStringLiteral("uid"); node->mParent = QStringLiteral("col"); /* new srutcure: -- + -- orphan -- + uid-col1 -- + col1 -- sub1 -- sub2 -- col2 */ reparentingModel.addNode(ReparentingModel::Node::Ptr(node)); QTest::qWait(0); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 2); QVERIFY(getIndex("col1", reparentingModel).isValid()); QCOMPARE(getIndex("col1", reparentingModel).parent(), getIndex("uid-col1", reparentingModel)); QCOMPARE(reparentingModel.rowCount(getIndex("col1", reparentingModel)), 2); QCOMPARE(reparentingModel.rowCount(getIndex("uid-col1", reparentingModel)), 2); node = new DummyNode(reparentingModel, QStringLiteral("xxx")); node->mUid = QStringLiteral("uid"); node->mParent = QStringLiteral("col"); // same structure but new data reparentingModel.updateNode(ReparentingModel::Node::Ptr(node)); QTest::qWait(0); QCOMPARE(getIndex("col1", reparentingModel).parent(), getIndex("uid-xxx", reparentingModel)); QCOMPARE(reparentingModel.rowCount(getIndex("col1", reparentingModel)), 2); QCOMPARE(reparentingModel.rowCount(getIndex("uid-xxx", reparentingModel)), 2); } /* * This test ensures we properly deal with reparented source nodes if the model is reset. * This is important since source nodes are removed during the model reset while the proxy nodes (to which the source nodes have been reparented) remain. * * Note that this test is only useful with the model internal asserts. */ void ReparentingModelTest::testReparentResetWithoutCrash() { QStandardItemModel sourceModel; sourceModel.appendRow(new QStandardItem(QStringLiteral("orphan"))); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("proxy1")))); QTest::qWait(0); reparentingModel.setSourceModel(&sourceModel); QTest::qWait(0); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); } void ReparentingModelTest::testAddReparentedSourceItem() { QStandardItemModel sourceModel; ReparentingModel reparentingModel; reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("proxy1")))); reparentingModel.setSourceModel(&sourceModel); QTest::qWait(0); ModelSignalSpy spy(reparentingModel); sourceModel.appendRow(new QStandardItem(QStringLiteral("orphan"))); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QVERIFY(getIndex("proxy1", reparentingModel).isValid()); QCOMPARE(spy.mSignals, QStringList() << QStringLiteral("rowsInserted")); QCOMPARE(spy.parent, getIndex("proxy1", reparentingModel)); QCOMPARE(spy.start, 0); QCOMPARE(spy.end, 0); } void ReparentingModelTest::testRemoveReparentedSourceItem() { QStandardItemModel sourceModel; sourceModel.appendRow(new QStandardItem(QStringLiteral("orphan"))); ReparentingModel reparentingModel; reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("proxy1")))); reparentingModel.setSourceModel(&sourceModel); QTest::qWait(0); ModelSignalSpy spy(reparentingModel); sourceModel.removeRows(0, 1, QModelIndex()); QTest::qWait(0); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 1); QVERIFY(getIndex("proxy1", reparentingModel).isValid()); QVERIFY(!getIndex("orphan", reparentingModel).isValid()); QCOMPARE(spy.mSignals, QStringList() << QStringLiteral("rowsRemoved")); QCOMPARE(spy.parent, getIndex("proxy1", reparentingModel)); QCOMPARE(spy.start, 0); QCOMPARE(spy.end, 0); } void ReparentingModelTest::testNestedReparentedSourceItem() { QStandardItemModel sourceModel; QStandardItem *item = new QStandardItem(QStringLiteral("parent")); item->appendRow(QList() << new QStandardItem(QStringLiteral("orphan"))); sourceModel.appendRow(item); ReparentingModel reparentingModel; reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("proxy1")))); reparentingModel.setSourceModel(&sourceModel); QTest::qWait(0); //toplevel should have both parent and proxy QCOMPARE(reparentingModel.rowCount(QModelIndex()), 2); QVERIFY(getIndex("orphan", reparentingModel).isValid()); QCOMPARE(getIndex("orphan", reparentingModel).parent(), getIndex("proxy1", reparentingModel)); } void ReparentingModelTest::testAddNestedReparentedSourceItem() { QStandardItemModel sourceModel; ReparentingModel reparentingModel; reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("proxy1")))); reparentingModel.setSourceModel(&sourceModel); QTest::qWait(0); ModelSignalSpy spy(reparentingModel); QStandardItem *item = new QStandardItem(QStringLiteral("parent")); item->appendRow(QList() << new QStandardItem(QStringLiteral("orphan"))); sourceModel.appendRow(item); QTest::qWait(0); //toplevel should have both parent and proxy QCOMPARE(reparentingModel.rowCount(QModelIndex()), 2); QVERIFY(getIndex("orphan", reparentingModel).isValid()); QCOMPARE(getIndex("orphan", reparentingModel).parent(), getIndex("proxy1", reparentingModel)); QCOMPARE(spy.mSignals, QStringList() << QStringLiteral("rowsInserted") << QStringLiteral("rowsInserted")); } void ReparentingModelTest::testSourceDataChanged() { QStandardItemModel sourceModel; QStandardItem *item = new QStandardItem(QStringLiteral("row1")); sourceModel.appendRow(item); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&sourceModel); item->setText(QStringLiteral("rowX")); QVERIFY(!getIndex("row1", reparentingModel).isValid()); QVERIFY(getIndex("rowX", reparentingModel).isValid()); } void ReparentingModelTest::testSourceLayoutChanged() { QStandardItemModel sourceModel; sourceModel.appendRow(new QStandardItem(QStringLiteral("row2"))); sourceModel.appendRow(new QStandardItem(QStringLiteral("row1"))); QSortFilterProxyModel filter; filter.setSourceModel(&sourceModel); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&filter); ModelSignalSpy spy(reparentingModel); QPersistentModelIndex index1 = reparentingModel.index(0, 0, QModelIndex()); QPersistentModelIndex index2 = reparentingModel.index(1, 0, QModelIndex()); //Emits layout changed and sorts the items the other way around filter.sort(0, Qt::AscendingOrder); QCOMPARE(reparentingModel.rowCount(QModelIndex()), 2); QVERIFY(getIndex("row1", reparentingModel).isValid()); //Right now we don't even care about the order // QCOMPARE(spy.mSignals, QStringList() << QStringLiteral("layoutChanged")); QCOMPARE(index1.data().toString(), QStringLiteral("row2")); QCOMPARE(index2.data().toString(), QStringLiteral("row1")); } /* * This is a very implementation specific test that tries to crash the model */ //Test for invalid implementation of layoutChanged //*have proxy node in model //*insert duplicate from source //*issue layout changed so the model get's rebuilt //*access node (which is not actually existing anymore) // => crash void ReparentingModelTest::testInvalidLayoutChanged() { QStandardItemModel sourceModel; QSortFilterProxyModel filter; filter.setSourceModel(&sourceModel); ReparentingModel reparentingModel; reparentingModel.setSourceModel(&filter); reparentingModel.addNode(ReparentingModel::Node::Ptr(new DummyNode(reparentingModel, QStringLiteral("row1")))); QTest::qWait(0); //Take reference to proxy node const QModelIndexList row1List = getIndexList("row1", reparentingModel); QVERIFY(!row1List.isEmpty()); QPersistentModelIndex persistentIndex = row1List.first(); QVERIFY(persistentIndex.isValid()); sourceModel.appendRow(new QStandardItem(QStringLiteral("row1"))); sourceModel.appendRow(new QStandardItem(QStringLiteral("row2"))); //This rebuilds the model and invalidates the reference //Emits layout changed and sorts the items the other way around filter.sort(0, Qt::AscendingOrder); //This fails because the persistenIndex is no longer valid persistentIndex.data().toString(); QVERIFY(!persistentIndex.isValid()); } class DummyNodeManager : public ReparentingModel::NodeManager { public: DummyNodeManager(ReparentingModel &m) : ReparentingModel::NodeManager(m) { } private: void checkSourceIndex(const QModelIndex &sourceIndex) override { if (sourceIndex.data().toString() == QLatin1String("personfolder")) { model.addNode(ReparentingModel::Node::Ptr(new DummyNode(model, QStringLiteral("personnode")))); } } void checkSourceIndexRemoval(const QModelIndex &sourceIndex) override { if (sourceIndex.data().toString() == QLatin1String("personfolder")) { model.removeNode(DummyNode(model, QStringLiteral("personnode"))); } } }; void ReparentingModelTest::testAddRemoveNodeByNodeManager() { QStandardItemModel sourceModel; sourceModel.appendRow(new QStandardItem(QStringLiteral("personfolder"))); ReparentingModel reparentingModel; reparentingModel.setNodeManager(ReparentingModel::NodeManager::Ptr(new DummyNodeManager( reparentingModel))); reparentingModel.setSourceModel(&sourceModel); QTest::qWait(0); QVERIFY(getIndex("personnode", reparentingModel).isValid()); QVERIFY(getIndex("personfolder", reparentingModel).isValid()); sourceModel.removeRows(0, 1, QModelIndex()); QTest::qWait(0); QVERIFY(!getIndex("personnode", reparentingModel).isValid()); QVERIFY(!getIndex("personfolder", reparentingModel).isValid()); } /* * This tests a special case that is caused by the delayed doAddNode call, * causing a removed node to be readded immediately if it's removed while * a doAddNode call is pending (that can be triggered by dataChanged). */ void ReparentingModelTest::testRemoveNodeByNodeManagerWithDataChanged() { QStandardItemModel sourceModel; QStandardItem *item = new QStandardItem(QStringLiteral("personfolder")); sourceModel.appendRow(item); ReparentingModel reparentingModel; reparentingModel.setNodeManager(ReparentingModel::NodeManager::Ptr(new DummyNodeManager( reparentingModel))); reparentingModel.setSourceModel(&sourceModel); QTest::qWait(0); QVERIFY(getIndex("personnode", reparentingModel).isValid()); QVERIFY(getIndex("personfolder", reparentingModel).isValid()); //Trigger data changed item->setStatusTip(QStringLiteral("sldkfjlfsj")); sourceModel.removeRows(0, 1, QModelIndex()); QTest::qWait(0); QVERIFY(!getIndex("personnode", reparentingModel).isValid()); QVERIFY(!getIndex("personfolder", reparentingModel).isValid()); } void ReparentingModelTest::testDataChanged() { QStandardItemModel sourceModel; QStandardItem *item = new QStandardItem(QStringLiteral("folder")); sourceModel.appendRow(item); ReparentingModel reparentingModel; reparentingModel.setNodeManager(ReparentingModel::NodeManager::Ptr(new DummyNodeManager( reparentingModel))); reparentingModel.setSourceModel(&sourceModel); ModelSignalSpy spy(reparentingModel); QTest::qWait(0); //Trigger data changed item->setStatusTip(QStringLiteral("sldkfjlfsj")); QTest::qWait(0); QCOMPARE(spy.mSignals, QStringList() << QStringLiteral("dataChanged")); } QTEST_MAIN(ReparentingModelTest) #include "reparentingmodeltest.moc"