Hello community, here is the log from the commit of package kitemmodels for openSUSE:Factory checked in at 2016-03-16 10:30:12 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/kitemmodels (Old) and /work/SRC/openSUSE:Factory/.kitemmodels.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "kitemmodels" Changes: -------- --- /work/SRC/openSUSE:Factory/kitemmodels/kitemmodels.changes 2016-02-24 18:55:49.000000000 +0100 +++ /work/SRC/openSUSE:Factory/.kitemmodels.new/kitemmodels.changes 2016-03-16 10:30:13.000000000 +0100 @@ -1,0 +2,18 @@ +Sun Mar 6 09:59:36 UTC 2016 - hrvoje.sen...@gmail.com + +- Update to 5.20.0 (boo#970856) + * KLinkItemSelectionModel: Add new default constructor + * KLinkItemSelectionModel: Make the linked selection + model settable + * KLinkItemSelectionModel: Handle changes to the + selectionModel model + * KLinkItemSelectionModel: Don't store model locally + * KSelectionProxyModel: Fix iteration bug + * Reset KSelectionProxyModel state when needed + * Add a property indicating whether the models form a + connected chain + * KModelIndexProxyMapper: Simplify logic of connected check + * For more details please see: + https://www.kde.org/announcements/kde-frameworks-5.20.0.php + +------------------------------------------------------------------- Old: ---- kitemmodels-5.19.0.tar.xz New: ---- kitemmodels-5.20.0.tar.xz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ kitemmodels.spec ++++++ --- /var/tmp/diff_new_pack.4xarMF/_old 2016-03-16 10:30:14.000000000 +0100 +++ /var/tmp/diff_new_pack.4xarMF/_new 2016-03-16 10:30:14.000000000 +0100 @@ -17,9 +17,9 @@ %define lname libKF5ItemModels5 -%define _tar_path 5.19 +%define _tar_path 5.20 Name: kitemmodels -Version: 5.19.0 +Version: 5.20.0 Release: 0 BuildRequires: cmake >= 2.8.12 BuildRequires: extra-cmake-modules >= %{_tar_path} ++++++ kitemmodels-5.19.0.tar.xz -> kitemmodels-5.20.0.tar.xz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.19.0/CMakeLists.txt new/kitemmodels-5.20.0/CMakeLists.txt --- old/kitemmodels-5.19.0/CMakeLists.txt 2016-02-06 10:38:41.000000000 +0100 +++ new/kitemmodels-5.20.0/CMakeLists.txt 2016-03-04 23:18:50.000000000 +0100 @@ -3,7 +3,7 @@ project(KItemModels) include(FeatureSummary) -find_package(ECM 5.19.0 NO_MODULE) +find_package(ECM 5.20.0 NO_MODULE) set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules") feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES) @@ -23,7 +23,7 @@ include(ECMSetupVersion) include(ECMGenerateHeaders) -set(KF5_VERSION "5.19.0") # handled by release scripts +set(KF5_VERSION "5.20.0") # handled by release scripts ecm_setup_version(${KF5_VERSION} VARIABLE_PREFIX KITEMMODELS VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/kitemmodels_version.h" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.19.0/autotests/CMakeLists.txt new/kitemmodels-5.20.0/autotests/CMakeLists.txt --- old/kitemmodels-5.19.0/autotests/CMakeLists.txt 2016-02-06 10:38:41.000000000 +0100 +++ new/kitemmodels-5.20.0/autotests/CMakeLists.txt 2016-03-04 23:18:50.000000000 +0100 @@ -21,6 +21,7 @@ klinkitemselectionmodeltest.cpp testmodelqueuedconnections.cpp kselectionproxymodeltest.cpp + kmodelindexproxymappertest.cpp krecursivefilterproxymodeltest.cpp krearrangecolumnsproxymodeltest.cpp LINK_LIBRARIES KF5::ItemModels Qt5::Test Qt5::Widgets proxymodeltestsuite diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.19.0/autotests/klinkitemselectionmodeltest.cpp new/kitemmodels-5.20.0/autotests/klinkitemselectionmodeltest.cpp --- old/kitemmodels-5.19.0/autotests/klinkitemselectionmodeltest.cpp 2016-02-06 10:38:41.000000000 +0100 +++ new/kitemmodels-5.20.0/autotests/klinkitemselectionmodeltest.cpp 2016-03-04 23:18:50.000000000 +0100 @@ -23,6 +23,7 @@ #include <QItemSelectionModel> #include <QSortFilterProxyModel> +#include <QIdentityProxyModel> #include <QStandardItem> #include <QStandardItemModel> @@ -105,5 +106,166 @@ QCOMPARE(mainIndex, m_mainModel->index(m_mainModel->rowCount() - 1, 0)); } +void KLinkItemSelectionModelTest::testChangeModel() +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + QVERIFY(m_mainSelectionModel->selection().isEmpty()); + + { + auto idx = m_mainModel->index(6, 0); + m_mainSelectionModel->select(idx, QItemSelectionModel::Select); + } + + QVERIFY(!m_mainSelectionModel->selection().isEmpty()); + QVERIFY(!m_subSelectionModel->selection().isEmpty()); + QCOMPARE(m_mainSelectionModel->selection().indexes().first().row(), 6); + QCOMPARE(m_subSelectionModel->selection().indexes().first().row(), 1); + + QIdentityProxyModel newIntermediateProxy; + + newIntermediateProxy.setSourceModel(m_mainModel); + + // Change the model of the KLinkItemSelectionModel + m_subSelectionModel->setModel(&newIntermediateProxy); + + QVERIFY(m_mainSelectionModel->selection().isEmpty()); + QVERIFY(m_subSelectionModel->selection().isEmpty()); +#endif +} + +void KLinkItemSelectionModelTest::testChangeModelOfExternal() +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + QVERIFY(m_mainSelectionModel->selection().isEmpty()); + + { + auto idx = m_mainModel->index(6, 0); + m_mainSelectionModel->select(idx, QItemSelectionModel::Select); + } + + QVERIFY(!m_mainSelectionModel->selection().isEmpty()); + QVERIFY(!m_subSelectionModel->selection().isEmpty()); + QCOMPARE(m_mainSelectionModel->selection().indexes().first().row(), 6); + QCOMPARE(m_subSelectionModel->selection().indexes().first().row(), 1); + + QIdentityProxyModel newIntermediateProxy; + + newIntermediateProxy.setSourceModel(m_mainModel); + + // Change the model of the external QISM + m_mainSelectionModel->setModel(&newIntermediateProxy); + + QVERIFY(m_mainSelectionModel->selection().isEmpty()); + QVERIFY(m_subSelectionModel->selection().isEmpty()); +#endif +} + +void KLinkItemSelectionModelTest::testChangeLinkedSelectionModel() +{ + QVERIFY(m_mainSelectionModel->selection().isEmpty()); + + { + auto idx = m_mainModel->index(6, 0); + m_mainSelectionModel->select(idx, QItemSelectionModel::Select); + } + + QVERIFY(!m_mainSelectionModel->selection().isEmpty()); + QVERIFY(!m_subSelectionModel->selection().isEmpty()); + QCOMPARE(m_mainSelectionModel->selection().indexes().first().row(), 6); + QCOMPARE(m_subSelectionModel->selection().indexes().first().row(), 1); + + QItemSelectionModel replacementSelectionModel(m_mainModel, 0); + { + auto idx = m_mainModel->index(7, 0); + replacementSelectionModel.select(idx, QItemSelectionModel::Select); + } + + m_subSelectionModel->setLinkedItemSelectionModel(&replacementSelectionModel); + + QVERIFY(!replacementSelectionModel.selection().isEmpty()); + QVERIFY(!m_subSelectionModel->selection().isEmpty()); + QCOMPARE(replacementSelectionModel.selection().indexes().first().row(), 7); + QCOMPARE(m_subSelectionModel->selection().indexes().first().row(), 2); +} + +void KLinkItemSelectionModelTest::testAdditionalLink() +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + { + auto idx = m_mainModel->index(6, 0); + m_mainSelectionModel->select(idx, QItemSelectionModel::Select); + } + + QVERIFY(!m_mainSelectionModel->selection().isEmpty()); + QVERIFY(!m_subSelectionModel->selection().isEmpty()); + QCOMPARE(m_mainSelectionModel->selection().indexes().first().row(), 6); + QCOMPARE(m_subSelectionModel->selection().indexes().first().row(), 1); + + { + QSortFilterProxyModel additionalProxy; + additionalProxy.setFilterRegExp(QRegExp(QStringLiteral("^[3-9]"))); + additionalProxy.setSourceModel(m_mainModel); + + KLinkItemSelectionModel additionalLink; + additionalLink.setModel(&additionalProxy); + additionalLink.setLinkedItemSelectionModel(m_mainSelectionModel); + QVERIFY(!additionalLink.selection().isEmpty()); + QCOMPARE(additionalLink.selection().indexes().first().row(), 3); + + auto idx = additionalProxy.index(4, 0); + QVERIFY(idx.isValid()); + additionalLink.select(idx, QItemSelectionModel::ClearAndSelect); + + QVERIFY(!additionalLink.selection().isEmpty()); + QCOMPARE(additionalLink.selection().indexes().first().row(), 4); + + QVERIFY(!m_mainSelectionModel->selection().isEmpty()); + QVERIFY(!m_subSelectionModel->selection().isEmpty()); + QCOMPARE(m_mainSelectionModel->selection().indexes().first().row(), 7); + QCOMPARE(m_subSelectionModel->selection().indexes().first().row(), 2); + } + + QVERIFY(!m_mainSelectionModel->selection().isEmpty()); + QVERIFY(!m_subSelectionModel->selection().isEmpty()); + QCOMPARE(m_mainSelectionModel->selection().indexes().first().row(), 7); + QCOMPARE(m_subSelectionModel->selection().indexes().first().row(), 2); +#endif +} + +void KLinkItemSelectionModelTest::testClearSelection() +{ + QVERIFY(m_mainSelectionModel->selection().isEmpty()); + + { + auto idx = m_mainModel->index(6, 0); + m_mainSelectionModel->select(idx, QItemSelectionModel::Select); + } + + QVERIFY(!m_mainSelectionModel->selection().isEmpty()); + QVERIFY(!m_subSelectionModel->selection().isEmpty()); + QCOMPARE(m_mainSelectionModel->selection().indexes().first().row(), 6); + QCOMPARE(m_subSelectionModel->selection().indexes().first().row(), 1); + + m_subSelectionModel->clear(); + + QVERIFY(m_mainSelectionModel->selection().isEmpty()); + QVERIFY(m_subSelectionModel->selection().isEmpty()); + + { + auto idx = m_mainModel->index(6, 0); + m_mainSelectionModel->select(idx, QItemSelectionModel::Select); + } + + QVERIFY(!m_mainSelectionModel->selection().isEmpty()); + QVERIFY(!m_subSelectionModel->selection().isEmpty()); + QCOMPARE(m_mainSelectionModel->selection().indexes().first().row(), 6); + QCOMPARE(m_subSelectionModel->selection().indexes().first().row(), 1); + + m_mainSelectionModel->clear(); + + QVERIFY(m_mainSelectionModel->selection().isEmpty()); + QVERIFY(m_subSelectionModel->selection().isEmpty()); +} + QTEST_MAIN(KLinkItemSelectionModelTest) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.19.0/autotests/klinkitemselectionmodeltest.h new/kitemmodels-5.20.0/autotests/klinkitemselectionmodeltest.h --- old/kitemmodels-5.19.0/autotests/klinkitemselectionmodeltest.h 2016-02-06 10:38:41.000000000 +0100 +++ new/kitemmodels-5.20.0/autotests/klinkitemselectionmodeltest.h 2016-03-04 23:18:50.000000000 +0100 @@ -37,6 +37,11 @@ void testToggle(); void testMainSetCurrent(); void testSubSetCurrent(); + void testChangeModel(); + void testChangeModelOfExternal(); + void testChangeLinkedSelectionModel(); + void testAdditionalLink(); + void testClearSelection(); private: QStandardItemModel *m_mainModel; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.19.0/autotests/kmodelindexproxymappertest.cpp new/kitemmodels-5.20.0/autotests/kmodelindexproxymappertest.cpp --- old/kitemmodels-5.19.0/autotests/kmodelindexproxymappertest.cpp 1970-01-01 01:00:00.000000000 +0100 +++ new/kitemmodels-5.20.0/autotests/kmodelindexproxymappertest.cpp 2016-03-04 23:18:50.000000000 +0100 @@ -0,0 +1,208 @@ +/* + Copyright (c) 2016 Ableton AG <i...@ableton.com> + Author Stephen Kelly <stephen.ke...@ableton.com> + + This library is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This library 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 Library General Public + License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301, USA. +*/ + +#include <QSignalSpy> +#include <QTest> +#include <QStringListModel> +#include <QIdentityProxyModel> +#include <QItemSelection> + +#include "kmodelindexproxymapper.h" + +class ModelIndexProxyMapperTest : public QObject +{ + Q_OBJECT +private Q_SLOTS: + + void init(); + + void testIndexMapping(); + void testSelectionMapping(); + void selfConnection(); + void connectedChangedSimple(); + void connectedChangedComplex(); + void crossWires(); + void isConnected(); + +private: + QStringListModel baseModel; + + QIdentityProxyModel proxy_common1; + + QIdentityProxyModel proxy_left1; + QIdentityProxyModel proxy_left2; + QIdentityProxyModel proxy_left3; + + QIdentityProxyModel proxy_right1; + QIdentityProxyModel proxy_right2; + QIdentityProxyModel proxy_right3; + QIdentityProxyModel proxy_right4; +}; + +void ModelIndexProxyMapperTest::init() +{ + baseModel.setStringList({"Monday", "Tuesday", "Wednesday"}); + + proxy_common1.setSourceModel(&baseModel); + + proxy_left1.setSourceModel(&proxy_common1); + proxy_left2.setSourceModel(&proxy_left1); + proxy_left3.setSourceModel(&proxy_left2); + + proxy_right1.setSourceModel(&proxy_common1); + proxy_right2.setSourceModel(&proxy_right1); + proxy_right3.setSourceModel(&proxy_right2); + proxy_right4.setSourceModel(&proxy_right3); +} + +void ModelIndexProxyMapperTest::testIndexMapping() +{ + KModelIndexProxyMapper mapper(&proxy_left3, &proxy_right4); + + auto leftIdx = proxy_left3.index(0, 0); + auto rightIdx = proxy_right4.index(0, 0); + + QVERIFY(leftIdx.isValid()); + QVERIFY(rightIdx.isValid()); + + QCOMPARE(mapper.mapLeftToRight(leftIdx), rightIdx); + QCOMPARE(mapper.mapRightToLeft(rightIdx), leftIdx); +} + +void ModelIndexProxyMapperTest::testSelectionMapping() +{ + KModelIndexProxyMapper mapper(&proxy_left3, &proxy_right4); + + auto leftIdx = proxy_left3.index(0, 0); + auto rightIdx = proxy_right4.index(0, 0); + + auto leftSel = QItemSelection(leftIdx, leftIdx); + auto rightSel = QItemSelection(rightIdx, rightIdx); + + QCOMPARE(leftSel.indexes().size(), 1); + QCOMPARE(rightSel.indexes().size(), 1); + + QVERIFY(leftSel.indexes().first().isValid()); + QVERIFY(rightSel.indexes().first().isValid()); + + QCOMPARE(mapper.mapSelectionLeftToRight(leftSel), rightSel); + QCOMPARE(mapper.mapSelectionRightToLeft(rightSel), leftSel); +} + +void ModelIndexProxyMapperTest::selfConnection() +{ + KModelIndexProxyMapper mapper(&baseModel, &baseModel); + QVERIFY(mapper.isConnected()); + + auto idx = baseModel.index(0, 0); + QVERIFY(idx.isValid()); + + QCOMPARE(mapper.mapLeftToRight(idx), idx); +} + +void ModelIndexProxyMapperTest::connectedChangedSimple() +{ + QIdentityProxyModel proxy1; + Q_SET_OBJECT_NAME(proxy1); + + KModelIndexProxyMapper mapper(&proxy1, &baseModel); + + QSignalSpy spy(&mapper, SIGNAL(isConnectedChanged())); + + QVERIFY(!mapper.isConnected()); + proxy1.setSourceModel(&baseModel); + + QVERIFY(mapper.isConnected()); + QCOMPARE(spy.count(), 1); +} + +void ModelIndexProxyMapperTest::connectedChangedComplex() +{ + KModelIndexProxyMapper mapper(&proxy_left3, &proxy_right4); + + QSignalSpy spy(&mapper, SIGNAL(isConnectedChanged())); + + QVERIFY(mapper.isConnected()); + + proxy_right2.setSourceModel(Q_NULLPTR); + + QVERIFY(!mapper.isConnected()); + QCOMPARE(spy.count(), 1); + + proxy_right2.setSourceModel(&proxy_right1); + + QVERIFY(mapper.isConnected()); + QCOMPARE(spy.count(), 2); + + auto leftIdx = proxy_left3.index(0, 0); + QVERIFY(leftIdx.isValid()); + auto rightIdx = mapper.mapLeftToRight(leftIdx); + QVERIFY(rightIdx.isValid()); + QCOMPARE(mapper.mapRightToLeft(rightIdx), leftIdx); + + QIdentityProxyModel replacement_right1; + replacement_right1.setSourceModel(&proxy_right1); + proxy_right2.setSourceModel(&replacement_right1); + + QVERIFY(mapper.isConnected()); + QCOMPARE(spy.count(), 2); +} + +void ModelIndexProxyMapperTest::crossWires() +{ + KModelIndexProxyMapper mapper(&proxy_left3, &proxy_right4); + + QSignalSpy spy(&mapper, SIGNAL(isConnectedChanged())); + + QVERIFY(mapper.isConnected()); + + proxy_left3.setSourceModel(&proxy_right3); + + QVERIFY(mapper.isConnected()); + QCOMPARE(spy.count(), 0); + + { + auto leftIdx = proxy_left3.index(0, 0); + auto rightIdx = proxy_right4.index(0, 0); + QCOMPARE(mapper.mapLeftToRight(leftIdx), rightIdx); + } + + proxy_right4.setSourceModel(&proxy_left2); + + QVERIFY(mapper.isConnected()); + QCOMPARE(spy.count(), 0); + + { + auto leftIdx = proxy_left3.index(0, 0); + auto rightIdx = proxy_right4.index(0, 0); + QCOMPARE(mapper.mapLeftToRight(leftIdx), rightIdx); + } +} + +void ModelIndexProxyMapperTest::isConnected() +{ + KModelIndexProxyMapper mapper1(&proxy_left1, &baseModel); + QVERIFY(mapper1.isConnected()); + KModelIndexProxyMapper mapper2(&baseModel, &proxy_left1); + QVERIFY(mapper2.isConnected()); +} + +QTEST_MAIN(ModelIndexProxyMapperTest) +#include "kmodelindexproxymappertest.moc" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.19.0/autotests/kselectionproxymodeltest.cpp new/kitemmodels-5.20.0/autotests/kselectionproxymodeltest.cpp --- old/kitemmodels-5.19.0/autotests/kselectionproxymodeltest.cpp 2016-02-06 10:38:41.000000000 +0100 +++ new/kitemmodels-5.20.0/autotests/kselectionproxymodeltest.cpp 2016-03-04 23:18:50.000000000 +0100 @@ -1,6 +1,8 @@ /* Copyright (c) 2015 Stephen Kelly <steve...@gmail.com> Copyright (c) 2015 David Faure <fa...@kde.org> + Copyright (c) 2016 Ableton AG <i...@ableton.com> + Author Stephen Kelly <stephen.ke...@ableton.com> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -45,6 +47,7 @@ private Q_SLOTS: void columnCountShouldBeStable(); void selectOnSourceReset(); + void selectionMapping(); #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) void selectionModelModelChange(); @@ -134,7 +137,13 @@ QStringLiteral("Tomorrow") }); + QSignalSpy resetSpy(&proxy, &QAbstractItemModel::modelReset); + selectionModel.setModel(&strings2); + + QCOMPARE(resetSpy.size(), 1); + QCOMPARE(proxy.rowCount(), 0); + proxy.setSourceModel(&strings2); selectionModel.select(strings2.index(0, 0), QItemSelectionModel::Select); @@ -162,6 +171,25 @@ } #endif +void KSelectionProxyModelTest::selectionMapping() +{ + QStringListModel strings(days); + QItemSelectionModel selectionModel(&strings); + KSelectionProxyModel proxy(&selectionModel); + proxy.setFilterBehavior(KSelectionProxyModel::SubTrees); + proxy.setSourceModel(&strings); + auto idx1 = strings.index(0, 0); + auto idx2 = strings.index(2, 0); + QItemSelection sourceSel; + sourceSel << QItemSelectionRange(idx1, idx2); + selectionModel.select(sourceSel, QItemSelectionModel::Select); + + QItemSelection proxySel; + proxySel << QItemSelectionRange(proxy.index(0, 0), proxy.index(2, 0)); + + QCOMPARE(proxy.mapSelectionToSource(proxySel), sourceSel); +} + QTEST_MAIN(KSelectionProxyModelTest) #include "kselectionproxymodeltest.moc" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.19.0/src/klinkitemselectionmodel.cpp new/kitemmodels-5.20.0/src/klinkitemselectionmodel.cpp --- old/kitemmodels-5.19.0/src/klinkitemselectionmodel.cpp 2016-02-06 10:38:41.000000000 +0100 +++ new/kitemmodels-5.20.0/src/klinkitemselectionmodel.cpp 2016-03-04 23:18:50.000000000 +0100 @@ -2,6 +2,8 @@ Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, i...@kdab.net, author Stephen Kelly <step...@kdab.com> + Copyright (c) 2016 Ableton AG <i...@ableton.com> + Author Stephen Kelly <stephen.ke...@ableton.com> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -29,14 +31,20 @@ class KLinkItemSelectionModelPrivate { public: - KLinkItemSelectionModelPrivate(KLinkItemSelectionModel *proxySelectionModel, QAbstractItemModel *model, - QItemSelectionModel *linkedItemSelectionModel) + KLinkItemSelectionModelPrivate(KLinkItemSelectionModel *proxySelectionModel) : q_ptr(proxySelectionModel), - m_model(model), - m_linkedItemSelectionModel(linkedItemSelectionModel), + m_linkedItemSelectionModel(Q_NULLPTR), m_ignoreCurrentChanged(false), - m_indexMapper(new KModelIndexProxyMapper(model, linkedItemSelectionModel->model(), proxySelectionModel)) + m_indexMapper(Q_NULLPTR) { + QObject::connect(q_ptr, &QItemSelectionModel::currentChanged, q_ptr, + [this](const QModelIndex& idx) { slotCurrentChanged(idx); } ); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + QObject::connect(q_ptr, &QItemSelectionModel::modelChanged, q_ptr, [this] { + reinitializeIndexMapper(); + }); +#endif } Q_DECLARE_PUBLIC(KLinkItemSelectionModel) @@ -53,23 +61,43 @@ return true; } + void reinitializeIndexMapper() + { + delete m_indexMapper; + m_indexMapper = Q_NULLPTR; + if (!q_ptr->model() + || !m_linkedItemSelectionModel + || !m_linkedItemSelectionModel->model()) { + return; + } + m_indexMapper = new KModelIndexProxyMapper( + q_ptr->model(), + m_linkedItemSelectionModel->model(), + q_ptr); + const QItemSelection mappedSelection = m_indexMapper->mapSelectionRightToLeft(m_linkedItemSelectionModel->selection()); + q_ptr->QItemSelectionModel::select(mappedSelection, QItemSelectionModel::ClearAndSelect); + } + void sourceSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); void sourceCurrentChanged(const QModelIndex ¤t); void slotCurrentChanged(const QModelIndex ¤t); - QAbstractItemModel *const m_model; - QItemSelectionModel *const m_linkedItemSelectionModel; + QItemSelectionModel *m_linkedItemSelectionModel; bool m_ignoreCurrentChanged; - KModelIndexProxyMapper *const m_indexMapper; + KModelIndexProxyMapper * m_indexMapper; }; KLinkItemSelectionModel::KLinkItemSelectionModel(QAbstractItemModel *model, QItemSelectionModel *proxySelector, QObject *parent) : QItemSelectionModel(model, parent), - d_ptr(new KLinkItemSelectionModelPrivate(this, model, proxySelector)) + d_ptr(new KLinkItemSelectionModelPrivate(this)) +{ + setLinkedItemSelectionModel(proxySelector); +} + +KLinkItemSelectionModel::KLinkItemSelectionModel(QObject *parent) + : QItemSelectionModel(Q_NULLPTR, parent), + d_ptr(new KLinkItemSelectionModelPrivate(this)) { - connect(proxySelector, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(sourceSelectionChanged(QItemSelection,QItemSelection))); - connect(proxySelector, SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(sourceCurrentChanged(QModelIndex))); - connect(this, SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(slotCurrentChanged(QModelIndex))); } KLinkItemSelectionModel::~KLinkItemSelectionModel() @@ -77,6 +105,38 @@ delete d_ptr; } +QItemSelectionModel *KLinkItemSelectionModel::linkedItemSelectionModel() const +{ + Q_D(const KLinkItemSelectionModel); + return d->m_linkedItemSelectionModel; +} + +void KLinkItemSelectionModel::setLinkedItemSelectionModel(QItemSelectionModel *selectionModel) +{ + Q_D(KLinkItemSelectionModel); + if (d->m_linkedItemSelectionModel != selectionModel) { + + if (d->m_linkedItemSelectionModel) { + disconnect(d->m_linkedItemSelectionModel); + } + + d->m_linkedItemSelectionModel = selectionModel; + + if (d->m_linkedItemSelectionModel) { + connect(d->m_linkedItemSelectionModel, SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(sourceSelectionChanged(QItemSelection,QItemSelection))); + connect(d->m_linkedItemSelectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), SLOT(sourceCurrentChanged(QModelIndex))); + +#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) + connect(d->m_linkedItemSelectionModel, &QItemSelectionModel::modelChanged, this, [this] { + d_ptr->reinitializeIndexMapper(); + }); +#endif + } + d->reinitializeIndexMapper(); + Q_EMIT linkedItemSelectionModelChanged(); + } +} + void KLinkItemSelectionModel::select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) { Q_D(KLinkItemSelectionModel); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.19.0/src/klinkitemselectionmodel.h new/kitemmodels-5.20.0/src/klinkitemselectionmodel.h --- old/kitemmodels-5.19.0/src/klinkitemselectionmodel.h 2016-02-06 10:38:41.000000000 +0100 +++ new/kitemmodels-5.20.0/src/klinkitemselectionmodel.h 2016-03-04 23:18:50.000000000 +0100 @@ -2,6 +2,8 @@ Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, i...@kdab.net, author Stephen Kelly <step...@kdab.com> + Copyright (c) 2016 Ableton AG <i...@ableton.com> + Author Stephen Kelly <stephen.ke...@ableton.com> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -95,15 +97,27 @@ class KITEMMODELS_EXPORT KLinkItemSelectionModel : public QItemSelectionModel { Q_OBJECT + Q_PROPERTY(QItemSelectionModel *linkedItemSelectionModel READ linkedItemSelectionModel + WRITE setLinkedItemSelectionModel NOTIFY linkedItemSelectionModelChanged) public: /** Constructor. */ KLinkItemSelectionModel(QAbstractItemModel *targetModel, QItemSelectionModel *linkedItemSelectionModel, QObject *parent = 0); + + explicit KLinkItemSelectionModel(QObject *parent = Q_NULLPTR); + ~KLinkItemSelectionModel(); + + QItemSelectionModel *linkedItemSelectionModel() const; + void setLinkedItemSelectionModel(QItemSelectionModel *selectionModel); + void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) Q_DECL_OVERRIDE; void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) Q_DECL_OVERRIDE; +Q_SIGNALS: + void linkedItemSelectionModelChanged(); + protected: KLinkItemSelectionModelPrivate *const d_ptr; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.19.0/src/kmodelindexproxymapper.cpp new/kitemmodels-5.20.0/src/kmodelindexproxymapper.cpp --- old/kitemmodels-5.19.0/src/kmodelindexproxymapper.cpp 2016-02-06 10:38:41.000000000 +0100 +++ new/kitemmodels-5.20.0/src/kmodelindexproxymapper.cpp 2016-03-04 23:18:50.000000000 +0100 @@ -2,6 +2,8 @@ Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, i...@kdab.net, author Stephen Kelly <step...@kdab.com> + Copyright (c) 2016 Ableton AG <i...@ableton.com> + Author Stephen Kelly <stephen.ke...@ableton.com> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -30,13 +32,14 @@ class KModelIndexProxyMapperPrivate { KModelIndexProxyMapperPrivate(const QAbstractItemModel *leftModel, const QAbstractItemModel *rightModel, KModelIndexProxyMapper *qq) - : q_ptr(qq), m_leftModel(leftModel), m_rightModel(rightModel) + : q_ptr(qq), m_leftModel(leftModel), m_rightModel(rightModel), mConnected(false) { createProxyChain(); } void createProxyChain(); - bool assertValid(); + void checkConnected(); + void setConnected(bool connected); bool assertSelectionValid(const QItemSelection &selection) const { @@ -57,6 +60,8 @@ QPointer<const QAbstractItemModel> m_leftModel; QPointer<const QAbstractItemModel> m_rightModel; + + bool mConnected; }; /* @@ -97,25 +102,28 @@ void KModelIndexProxyMapperPrivate::createProxyChain() { - QPointer<const QAbstractItemModel> targetModel = m_rightModel; - - if (!targetModel) { - return; + Q_FOREACH (auto p, m_proxyChainUp) { + p->disconnect(q_ptr); } - - if (m_leftModel == targetModel) { - return; + Q_FOREACH (auto p, m_proxyChainDown) { + p->disconnect(q_ptr); } + m_proxyChainUp.clear(); + m_proxyChainDown.clear(); + QPointer<const QAbstractItemModel> targetModel = m_rightModel; QList<QPointer<const QAbstractProxyModel> > proxyChainDown; QPointer<const QAbstractProxyModel> selectionTargetProxyModel = qobject_cast<const QAbstractProxyModel *>(targetModel); while (selectionTargetProxyModel) { proxyChainDown.prepend(selectionTargetProxyModel); + QObject::connect(selectionTargetProxyModel.data(), &QAbstractProxyModel::sourceModelChanged, q_ptr, + [this]{ createProxyChain(); }); selectionTargetProxyModel = qobject_cast<const QAbstractProxyModel *>(selectionTargetProxyModel->sourceModel()); if (selectionTargetProxyModel == m_leftModel) { m_proxyChainDown = proxyChainDown; + checkConnected(); return; } } @@ -125,6 +133,8 @@ while (sourceProxyModel) { m_proxyChainUp.append(sourceProxyModel); + QObject::connect(sourceProxyModel.data(), &QAbstractProxyModel::sourceModelChanged, q_ptr, + [this]{ createProxyChain(); }); sourceProxyModel = qobject_cast<const QAbstractProxyModel *>(sourceProxyModel->sourceModel()); @@ -132,25 +142,28 @@ if (targetIndex != -1) { m_proxyChainDown = proxyChainDown.mid(targetIndex + 1, proxyChainDown.size()); + checkConnected(); return; } } m_proxyChainDown = proxyChainDown; - Q_ASSERT(assertValid()); + checkConnected(); +} + +void KModelIndexProxyMapperPrivate::checkConnected() +{ + auto konamiRight = m_proxyChainUp.isEmpty() ? m_leftModel : m_proxyChainUp.last()->sourceModel(); + auto konamiLeft = m_proxyChainDown.isEmpty() ? m_rightModel : m_proxyChainDown.first()->sourceModel(); + setConnected(konamiLeft && (konamiLeft == konamiRight)); } -bool KModelIndexProxyMapperPrivate::assertValid() +void KModelIndexProxyMapperPrivate::setConnected(bool connected) { - if (m_proxyChainDown.isEmpty()) { - Q_ASSERT(!m_proxyChainUp.isEmpty()); - Q_ASSERT(m_proxyChainUp.last()->sourceModel() == m_rightModel); - } else if (m_proxyChainUp.isEmpty()) { - Q_ASSERT(!m_proxyChainDown.isEmpty()); - Q_ASSERT(m_proxyChainDown.first()->sourceModel() == m_leftModel); - } else { - Q_ASSERT(m_proxyChainDown.first()->sourceModel() == m_proxyChainUp.last()->sourceModel()); + if (mConnected != connected) { + Q_Q(KModelIndexProxyMapper); + mConnected = connected; + Q_EMIT q->isConnectedChanged(); } - return true; } KModelIndexProxyMapper::KModelIndexProxyMapper(const QAbstractItemModel *leftModel, const QAbstractItemModel *rightModel, QObject *parent) @@ -210,7 +223,7 @@ { Q_D(const KModelIndexProxyMapper); - if (selection.isEmpty()) { + if (selection.isEmpty() || !d->mConnected) { return QItemSelection(); } @@ -228,7 +241,10 @@ if (!proxy) { return QItemSelection(); } + + Q_ASSERT(seekSelection.isEmpty() || seekSelection.first().model() == proxy); seekSelection = proxy->mapSelectionToSource(seekSelection); + Q_ASSERT(seekSelection.isEmpty() || seekSelection.first().model() == proxy->sourceModel()); #ifdef RANGE_FIX_HACK seekSelection = removeInvalidRanges(seekSelection); @@ -243,7 +259,9 @@ if (!proxy) { return QItemSelection(); } + Q_ASSERT(seekSelection.isEmpty() || seekSelection.first().model() == proxy->sourceModel()); seekSelection = proxy->mapSelectionFromSource(seekSelection); + Q_ASSERT(seekSelection.isEmpty() || seekSelection.first().model() == proxy); #ifdef RANGE_FIX_HACK seekSelection = removeInvalidRanges(seekSelection); @@ -259,7 +277,7 @@ { Q_D(const KModelIndexProxyMapper); - if (selection.isEmpty()) { + if (selection.isEmpty() || !d->mConnected) { return QItemSelection(); } @@ -306,3 +324,8 @@ return seekSelection; } +bool KModelIndexProxyMapper::isConnected() const +{ + Q_D(const KModelIndexProxyMapper); + return d->mConnected; +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.19.0/src/kmodelindexproxymapper.h new/kitemmodels-5.20.0/src/kmodelindexproxymapper.h --- old/kitemmodels-5.19.0/src/kmodelindexproxymapper.h 2016-02-06 10:38:41.000000000 +0100 +++ new/kitemmodels-5.20.0/src/kmodelindexproxymapper.h 2016-03-04 23:18:50.000000000 +0100 @@ -2,6 +2,8 @@ Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, i...@kdab.net, author Stephen Kelly <step...@kdab.com> + Copyright (c) 2016 Ableton AG <i...@ableton.com> + Author Stephen Kelly <stephen.ke...@ableton.com> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -73,12 +75,22 @@ * Proxy 2 Proxy 4 * @endverbatim * + * The isConnected property indicates whether there is a + * path from the left side to the right side. + * * @author Stephen Kelly <steve...@gmail.com> * */ class KITEMMODELS_EXPORT KModelIndexProxyMapper : public QObject { Q_OBJECT + + /** + * Indicates whether there is a chain that can be followed from leftModel to rightModel. + * + * This value can change if the sourceModel of an intermediate proxy is changed. + */ + Q_PROPERTY(bool isConnected READ isConnected NOTIFY isConnectedChanged) public: /** * Constructor @@ -107,6 +119,11 @@ */ QItemSelection mapSelectionRightToLeft(const QItemSelection &selection) const; + bool isConnected() const; + +Q_SIGNALS: + void isConnectedChanged(); + private: //@cond PRIVATE Q_DECLARE_PRIVATE(KModelIndexProxyMapper) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/kitemmodels-5.19.0/src/kselectionproxymodel.cpp new/kitemmodels-5.20.0/src/kselectionproxymodel.cpp --- old/kitemmodels-5.19.0/src/kselectionproxymodel.cpp 2016-02-06 10:38:41.000000000 +0100 +++ new/kitemmodels-5.20.0/src/kselectionproxymodel.cpp 2016-03-04 23:18:50.000000000 +0100 @@ -1,5 +1,7 @@ /* Copyright (c) 2009 Stephen Kelly <steve...@gmail.com> + Copyright (c) 2016 Ableton AG <i...@ableton.com> + Author Stephen Kelly <stephen.ke...@ableton.com> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by @@ -2466,6 +2468,7 @@ SLOT(selectionChanged(QItemSelection,QItemSelection))); auto handleSelectionModelModel = [ &, d] { + beginResetModel(); if (d->selectionModelModelAboutToBeResetConnection) { disconnect(d->selectionModelModelAboutToBeResetConnection); @@ -2482,7 +2485,11 @@ d->selectionModelModelResetConnection = connect( d->m_selectionModel->model(), SIGNAL(modelReset()), this, SLOT(sourceModelReset())); + d->m_rootIndexList.clear(); + delete d->m_indexMapper; + d->m_indexMapper = new KModelIndexProxyMapper(sourceModel(), d->m_selectionModel->model(), this); } + endResetModel(); }; #if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0) connect(d->m_selectionModel.data(), &QItemSelectionModel::modelChanged, @@ -2651,7 +2658,7 @@ const QModelIndex sourceIdx = mapToSource(idx); Q_ASSERT(sourceIdx.isValid()); topSelection.append(QItemSelectionRange(sourceTopLeft, sourceIdx)); - for (int i = it->top() + 1; i < it->bottom(); ++it) { + for (int i = it->top() + 1; i <= it->bottom(); ++i) { const QModelIndex left = mapToSource(createIndex(i, 0)); const QModelIndex right = mapToSource(createIndex(i, it->right())); Q_ASSERT(left.isValid());