4.14.5
This commit is contained in:
parent
a48aa99972
commit
714eb72aa9
2
.gitignore
vendored
2
.gitignore
vendored
@ -1 +1 @@
|
|||||||
/kdelibs-4.14.4.tar.xz
|
/kdelibs-4.14.5.tar.xz
|
||||||
|
@ -1,341 +0,0 @@
|
|||||||
From a932980cc7babe69613b9c6ad98faa4ec368258e Mon Sep 17 00:00:00 2001
|
|
||||||
From: Christian Mollekopf <chrigi_1@fastmail.fm>
|
|
||||||
Date: Tue, 9 Sep 2014 18:16:37 +0200
|
|
||||||
Subject: [PATCH] KRecursiveFilterProxyModel: Fixed the model
|
|
||||||
|
|
||||||
The model was not working properly and didn't include all items under
|
|
||||||
some circumstances.
|
|
||||||
This patch fixes the following scenarios in particular:
|
|
||||||
|
|
||||||
* The change in sourceDataChanged is required to fix the shortcut condition.
|
|
||||||
The idea is that if the parent is already part of the model (it must be if acceptRow returns true),
|
|
||||||
we can directly invoke dataChanged on the parent, resulting in the changed index
|
|
||||||
getting reevaluated. However, because the recursive filterAcceptsRow version was used
|
|
||||||
the shortcut was also used when only the current index matches the filter and
|
|
||||||
the parent index is in fact not yet in the model. In this case we failed to call
|
|
||||||
dataChanged on the right index and thus the complete branch was never added to the model.
|
|
||||||
|
|
||||||
* The change in refreshAscendantMapping is required to include indexes that were
|
|
||||||
included by descendants. The intended way how this was supposed to work is that we
|
|
||||||
traverse the tree upwards and find the last index that is not yet part of the model.
|
|
||||||
We would then call dataChanged on that index causing it and its descendants to get reevaluated.
|
|
||||||
However, acceptRow does not reflect wether an index is already in the model or not.
|
|
||||||
Consider the following model:
|
|
||||||
|
|
||||||
- A
|
|
||||||
- B
|
|
||||||
- C
|
|
||||||
- D
|
|
||||||
|
|
||||||
|
|
||||||
If C is include in the model by default but D not and A & B only gets included due to C, we have the following model:
|
|
||||||
- A
|
|
||||||
- B
|
|
||||||
- C
|
|
||||||
- D
|
|
||||||
|
|
||||||
If we then call refreshAscendantsMapping on D it will not consider B as already being part of the model.
|
|
||||||
This results in the toplevel index A being considered lastAscendant, and a call to dataChanged on A results in
|
|
||||||
a reevaluation of A only, which is already in the model. Thus D never gets added to the model.
|
|
||||||
|
|
||||||
Unfortunately there is no way to probe QSortFilterProxyModel for indexes that are
|
|
||||||
already part of the model. Even the const mapFromSource internally creates a mapping when called,
|
|
||||||
and thus instead of revealing indexes that are not yet part of the model, it silently
|
|
||||||
creates a mapping (without issuing the relevant signals!).
|
|
||||||
|
|
||||||
As the only possible workaround we have to issues dataChanged for all ancestors
|
|
||||||
which is ignored for indexes that are not yet mapped, and results in a rowsInserted
|
|
||||||
signal for the correct indexes. It also results in superfluous dataChanged signals,
|
|
||||||
since we don't know when to stop, but at least we have a properly behaving model
|
|
||||||
this way.
|
|
||||||
---
|
|
||||||
kdeui/itemviews/krecursivefilterproxymodel.cpp | 17 +-
|
|
||||||
kdeui/tests/CMakeLists.txt | 1 +
|
|
||||||
kdeui/tests/krecursivefilterproxymodeltest.cpp | 221 +++++++++++++++++++++++++
|
|
||||||
3 files changed, 227 insertions(+), 12 deletions(-)
|
|
||||||
create mode 100644 kdeui/tests/krecursivefilterproxymodeltest.cpp
|
|
||||||
|
|
||||||
diff --git a/kdeui/itemviews/krecursivefilterproxymodel.cpp b/kdeui/itemviews/krecursivefilterproxymodel.cpp
|
|
||||||
index 6d65631..089af79 100644
|
|
||||||
--- a/kdeui/itemviews/krecursivefilterproxymodel.cpp
|
|
||||||
+++ b/kdeui/itemviews/krecursivefilterproxymodel.cpp
|
|
||||||
@@ -126,7 +126,7 @@ void KRecursiveFilterProxyModelPrivate::sourceDataChanged(const QModelIndex &sou
|
|
||||||
|
|
||||||
QModelIndex source_parent = source_top_left.parent();
|
|
||||||
|
|
||||||
- if (!source_parent.isValid() || q->filterAcceptsRow(source_parent.row(), source_parent.parent()))
|
|
||||||
+ if (!source_parent.isValid() || q->acceptRow(source_parent.row(), source_parent.parent()))
|
|
||||||
{
|
|
||||||
invokeDataChanged(source_top_left, source_bottom_right);
|
|
||||||
return;
|
|
||||||
@@ -149,24 +149,17 @@ void KRecursiveFilterProxyModelPrivate::sourceDataChanged(const QModelIndex &sou
|
|
||||||
void KRecursiveFilterProxyModelPrivate::refreshAscendantMapping(const QModelIndex &index, bool refreshAll)
|
|
||||||
{
|
|
||||||
Q_Q(KRecursiveFilterProxyModel);
|
|
||||||
-
|
|
||||||
Q_ASSERT(index.isValid());
|
|
||||||
- QModelIndex lastAscendant = index;
|
|
||||||
- QModelIndex sourceAscendant = index.parent();
|
|
||||||
+
|
|
||||||
+ QModelIndex sourceAscendant = index;
|
|
||||||
// We got a matching descendant, so find the right place to insert the row.
|
|
||||||
// We need to tell the QSortFilterProxyModel that the first child between an existing row in the model
|
|
||||||
// has changed data so that it will get a mapping.
|
|
||||||
- while(sourceAscendant.isValid() && !q->acceptRow(sourceAscendant.row(), sourceAscendant.parent()))
|
|
||||||
+ while(sourceAscendant.isValid())
|
|
||||||
{
|
|
||||||
- if (refreshAll)
|
|
||||||
- invokeDataChanged(sourceAscendant, sourceAscendant);
|
|
||||||
-
|
|
||||||
- lastAscendant = sourceAscendant;
|
|
||||||
+ invokeDataChanged(sourceAscendant, sourceAscendant);
|
|
||||||
sourceAscendant = sourceAscendant.parent();
|
|
||||||
}
|
|
||||||
-
|
|
||||||
- // Inform the model that its data changed so that it creates new mappings and finds the rows which now match the filter.
|
|
||||||
- invokeDataChanged(lastAscendant, lastAscendant);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KRecursiveFilterProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end)
|
|
||||||
diff --git a/kdeui/tests/CMakeLists.txt b/kdeui/tests/CMakeLists.txt
|
|
||||||
index f661b91..948516b 100644
|
|
||||||
--- a/kdeui/tests/CMakeLists.txt
|
|
||||||
+++ b/kdeui/tests/CMakeLists.txt
|
|
||||||
@@ -81,6 +81,7 @@ KDEUI_PROXYMODEL_TESTS(
|
|
||||||
kdescendantsproxymodeltest
|
|
||||||
kselectionproxymodeltest
|
|
||||||
testmodelqueuedconnections
|
|
||||||
+ krecursivefilterproxymodeltest
|
|
||||||
)
|
|
||||||
|
|
||||||
KDEUI_EXECUTABLE_TESTS(
|
|
||||||
diff --git a/kdeui/tests/krecursivefilterproxymodeltest.cpp b/kdeui/tests/krecursivefilterproxymodeltest.cpp
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000..a336116
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/kdeui/tests/krecursivefilterproxymodeltest.cpp
|
|
||||||
@@ -0,0 +1,221 @@
|
|
||||||
+/*
|
|
||||||
+ Copyright (c) 2014 Christian Mollekopf <mollekopf@kolabsys.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 <qtest_kde.h>
|
|
||||||
+
|
|
||||||
+#include <krecursivefilterproxymodel.h>
|
|
||||||
+#include <QStandardItemModel>
|
|
||||||
+
|
|
||||||
+class ModelSignalSpy : public QObject {
|
|
||||||
+ Q_OBJECT
|
|
||||||
+public:
|
|
||||||
+ explicit ModelSignalSpy(QAbstractItemModel &model) {
|
|
||||||
+ 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, SIGNAL(layoutChanged()), this, SLOT(onLayoutChanged()));
|
|
||||||
+ connect(&model, SIGNAL(modelReset()), this, SLOT(onModelReset()));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ QStringList mSignals;
|
|
||||||
+ QModelIndex parent;
|
|
||||||
+ int start;
|
|
||||||
+ int end;
|
|
||||||
+
|
|
||||||
+public Q_SLOTS:
|
|
||||||
+ void onRowsInserted(QModelIndex p, int s, int e) {
|
|
||||||
+ mSignals << QLatin1String("rowsInserted");
|
|
||||||
+ parent = p;
|
|
||||||
+ start = s;
|
|
||||||
+ end = e;
|
|
||||||
+ }
|
|
||||||
+ void onRowsRemoved(QModelIndex p, int s, int e) {
|
|
||||||
+ mSignals << QLatin1String("rowsRemoved");
|
|
||||||
+ parent = p;
|
|
||||||
+ start = s;
|
|
||||||
+ end = e;
|
|
||||||
+ }
|
|
||||||
+ void onRowsMoved(QModelIndex,int,int,QModelIndex,int) {
|
|
||||||
+ mSignals << QLatin1String("rowsMoved");
|
|
||||||
+ }
|
|
||||||
+ void onDataChanged(QModelIndex,QModelIndex) {
|
|
||||||
+ mSignals << QLatin1String("dataChanged");
|
|
||||||
+ }
|
|
||||||
+ void onLayoutChanged() {
|
|
||||||
+ mSignals << QLatin1String("layoutChanged");
|
|
||||||
+ }
|
|
||||||
+ void onModelReset() {
|
|
||||||
+ mSignals << QLatin1String("modelReset");
|
|
||||||
+ }
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+class TestModel : public KRecursiveFilterProxyModel
|
|
||||||
+{
|
|
||||||
+ Q_OBJECT
|
|
||||||
+public:
|
|
||||||
+ virtual bool acceptRow(int sourceRow, const QModelIndex &sourceParent) const
|
|
||||||
+ {
|
|
||||||
+ // qDebug() << sourceModel()->index(sourceRow, 0, sourceParent).data().toString() << sourceModel()->index(sourceRow, 0, sourceParent).data(Qt::UserRole+1).toBool();
|
|
||||||
+ return sourceModel()->index(sourceRow, 0, sourceParent).data(Qt::UserRole+1).toBool();
|
|
||||||
+ }
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+static QModelIndex getIndex(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();
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
+class KRecursiveFilterProxyModelTest : public QObject
|
|
||||||
+{
|
|
||||||
+ Q_OBJECT
|
|
||||||
+private:
|
|
||||||
+
|
|
||||||
+private slots:
|
|
||||||
+ // Requires the acceptRow fix in sourceDataChanged to pass
|
|
||||||
+ // Test that we properly react to a data-changed signal in a descendant and include all required rows
|
|
||||||
+ void testDataChange()
|
|
||||||
+ {
|
|
||||||
+ QStandardItemModel model;
|
|
||||||
+ TestModel proxy;
|
|
||||||
+ proxy.setSourceModel(&model);
|
|
||||||
+
|
|
||||||
+ QStandardItem *row1 = new QStandardItem("row1");
|
|
||||||
+ row1->setData(false);
|
|
||||||
+ model.appendRow(row1);
|
|
||||||
+
|
|
||||||
+ QCOMPARE(getIndex("row1", proxy).isValid(), false);
|
|
||||||
+
|
|
||||||
+ QStandardItem *subchild = new QStandardItem("subchild");
|
|
||||||
+ subchild->setData(false);
|
|
||||||
+ {
|
|
||||||
+ QStandardItem *child = new QStandardItem("child");
|
|
||||||
+ child->setData(false);
|
|
||||||
+ child->appendRow(subchild);
|
|
||||||
+ row1->appendRow(child);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ ModelSignalSpy spy(proxy);
|
|
||||||
+ subchild->setData(true);
|
|
||||||
+
|
|
||||||
+ QCOMPARE(getIndex("row1", proxy).isValid(), true);
|
|
||||||
+ QCOMPARE(getIndex("child", proxy).isValid(), true);
|
|
||||||
+ QCOMPARE(getIndex("subchild", proxy).isValid(), true);
|
|
||||||
+
|
|
||||||
+ QCOMPARE(spy.mSignals, QStringList() << QLatin1String("rowsInserted"));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ void testInsert()
|
|
||||||
+ {
|
|
||||||
+ QStandardItemModel model;
|
|
||||||
+ TestModel proxy;
|
|
||||||
+ proxy.setSourceModel(&model);
|
|
||||||
+
|
|
||||||
+ QStandardItem *row1 = new QStandardItem("row1");
|
|
||||||
+ row1->setData(false);
|
|
||||||
+ model.appendRow(row1);
|
|
||||||
+
|
|
||||||
+ QStandardItem *child = new QStandardItem("child");
|
|
||||||
+ child->setData(false);
|
|
||||||
+ row1->appendRow(child);
|
|
||||||
+
|
|
||||||
+ QStandardItem *child2 = new QStandardItem("child2");
|
|
||||||
+ child2->setData(false);
|
|
||||||
+ child->appendRow(child2);
|
|
||||||
+
|
|
||||||
+ QCOMPARE(getIndex("row1", proxy).isValid(), false);
|
|
||||||
+ QCOMPARE(getIndex("child", proxy).isValid(), false);
|
|
||||||
+ QCOMPARE(getIndex("child2", proxy).isValid(), false);
|
|
||||||
+
|
|
||||||
+ ModelSignalSpy spy(proxy);
|
|
||||||
+ {
|
|
||||||
+ QStandardItem *subchild = new QStandardItem("subchild");
|
|
||||||
+ subchild->setData(true);
|
|
||||||
+ child2->appendRow(subchild);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ QCOMPARE(getIndex("row1", proxy).isValid(), true);
|
|
||||||
+ QCOMPARE(spy.mSignals, QStringList() << QLatin1String("rowsInserted"));
|
|
||||||
+ QCOMPARE(spy.parent, QModelIndex());
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+
|
|
||||||
+ // We want to get child2 into the model which is a descendant of child.
|
|
||||||
+ // child is already in the model from the neighbor2 branch. We must ensure dataChange is called on child,
|
|
||||||
+ // so child2 is included in the model.
|
|
||||||
+ void testNeighborPath()
|
|
||||||
+ {
|
|
||||||
+ QStandardItemModel model;
|
|
||||||
+ TestModel proxy;
|
|
||||||
+ proxy.setSourceModel(&model);
|
|
||||||
+
|
|
||||||
+ QStandardItem *row1 = new QStandardItem("row1");
|
|
||||||
+ row1->setData(false);
|
|
||||||
+ model.appendRow(row1);
|
|
||||||
+
|
|
||||||
+ QStandardItem *child = new QStandardItem("child");
|
|
||||||
+ child->setData(false);
|
|
||||||
+ row1->appendRow(child);
|
|
||||||
+
|
|
||||||
+ QStandardItem *child2 = new QStandardItem("child2");
|
|
||||||
+ child2->setData(false);
|
|
||||||
+ child->appendRow(child2);
|
|
||||||
+
|
|
||||||
+ {
|
|
||||||
+ QStandardItem *nb1 = new QStandardItem("neighbor");
|
|
||||||
+ nb1->setData(false);
|
|
||||||
+ child->appendRow(nb1);
|
|
||||||
+
|
|
||||||
+ QStandardItem *nb2 = new QStandardItem("neighbor2");
|
|
||||||
+ nb2->setData(true);
|
|
||||||
+ nb1->appendRow(nb2);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ //These tests affect the test. It seems without them the mapping is not created in qsortfilterproxymodel, resulting in the item
|
|
||||||
+ //simply getting added later on. With these the model doesn't react to the added subchild as it should. Piece of crap.
|
|
||||||
+ QCOMPARE(getIndex("child2", proxy).isValid(), false);
|
|
||||||
+ QCOMPARE(getIndex("child", proxy).isValid(), true);
|
|
||||||
+ QCOMPARE(getIndex("neighbor", proxy).isValid(), true);
|
|
||||||
+ QCOMPARE(getIndex("neighbor2", proxy).isValid(), true);
|
|
||||||
+
|
|
||||||
+ ModelSignalSpy spy(proxy);
|
|
||||||
+
|
|
||||||
+ {
|
|
||||||
+ qDebug() << "inserting";
|
|
||||||
+ QStandardItem *subchild = new QStandardItem("subchild");
|
|
||||||
+ subchild->setData(true);
|
|
||||||
+ child2->appendRow(subchild);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ QCOMPARE(getIndex("child2", proxy).isValid(), true);
|
|
||||||
+ QCOMPARE(getIndex("subchild", proxy).isValid(), true);
|
|
||||||
+ //The dataChanged signals are not intentional and cause by refreshAscendantMapping. Unfortunately we can't avoid them.
|
|
||||||
+ QCOMPARE(spy.mSignals, QStringList() << QLatin1String("rowsInserted") << QLatin1String("dataChanged") << QLatin1String("dataChanged"));
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+};
|
|
||||||
+
|
|
||||||
+QTEST_KDEMAIN(KRecursiveFilterProxyModelTest, NoGUI)
|
|
||||||
+
|
|
||||||
+#include "krecursivefilterproxymodeltest.moc"
|
|
||||||
--
|
|
||||||
1.8.2.3
|
|
||||||
|
|
12
kdelibs.spec
12
kdelibs.spec
@ -43,8 +43,8 @@
|
|||||||
Summary: KDE Libraries
|
Summary: KDE Libraries
|
||||||
# shipped with kde applications, version...
|
# shipped with kde applications, version...
|
||||||
%global apps_version 14.12.1
|
%global apps_version 14.12.1
|
||||||
Version: 4.14.4
|
Version: 4.14.5
|
||||||
Release: 3%{?dist}
|
Release: 1%{?dist}
|
||||||
|
|
||||||
Name: kdelibs
|
Name: kdelibs
|
||||||
Epoch: 6
|
Epoch: 6
|
||||||
@ -182,10 +182,6 @@ Patch63: kdelibs-4.11.3-klauncher-no-glib.patch
|
|||||||
# opening a terminal in Konqueror / Dolphin does not inherit environment variables
|
# opening a terminal in Konqueror / Dolphin does not inherit environment variables
|
||||||
Patch64: kdelibs-4.13.2-invokeTerminal.patch
|
Patch64: kdelibs-4.13.2-invokeTerminal.patch
|
||||||
|
|
||||||
# Kolab request
|
|
||||||
# https://obs.kolabsys.com/package/view_file/Kontact:4.13:Development/kdelibs/0001-KRecursiveFilterProxyModel-Fixed-the-model.patch
|
|
||||||
Patch65: 0001-KRecursiveFilterProxyModel-Fixed-the-model.patch
|
|
||||||
|
|
||||||
## upstream
|
## upstream
|
||||||
# 4.14 branch
|
# 4.14 branch
|
||||||
|
|
||||||
@ -439,7 +435,6 @@ sed -i -e "s|@@VERSION_RELEASE@@|%{version}-%{release}|" kio/kio/kprotocolmanage
|
|||||||
%patch62 -p1 -b .arm-plasma
|
%patch62 -p1 -b .arm-plasma
|
||||||
%patch63 -p1 -b .klauncher-no-glib
|
%patch63 -p1 -b .klauncher-no-glib
|
||||||
%patch64 -p1 -b .invokeTerminal
|
%patch64 -p1 -b .invokeTerminal
|
||||||
%patch65 -p1 -b .KRecursiveFilterProxyModel
|
|
||||||
|
|
||||||
# upstream patches
|
# upstream patches
|
||||||
|
|
||||||
@ -794,6 +789,9 @@ update-mime-database %{?fedora:-n} %{_datadir}/mime &> /dev/null || :
|
|||||||
|
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Feb 24 2015 Rex Dieter <rdieter@fedoraproject.org> - 6:4.14.5-1
|
||||||
|
- 4.14.5
|
||||||
|
|
||||||
* Wed Feb 18 2015 Rex Dieter <rdieter@fedoraproject.org> 6:4.14.4-3
|
* Wed Feb 18 2015 Rex Dieter <rdieter@fedoraproject.org> 6:4.14.4-3
|
||||||
- rebuild (gcc5)
|
- rebuild (gcc5)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user