Index: branches/2015Q1/x11/kdelibs4/Makefile =================================================================== --- branches/2015Q1/x11/kdelibs4/Makefile (revision 378598) +++ branches/2015Q1/x11/kdelibs4/Makefile (revision 378599) @@ -1,114 +1,114 @@ # Created by: arved@FreeBSD.org # $FreeBSD$ PORTNAME= kdelibs PORTVERSION= ${KDE4_VERSION} -PORTREVISION= 3 +PORTREVISION= 4 CATEGORIES= x11 kde MASTER_SITES= KDE/${KDE4_BRANCH}/${PORTVERSION}/src DIST_SUBDIR= KDE/${PORTVERSION} MAINTAINER= kde@FreeBSD.org COMMENT= Base set of libraries needed by KDE programs LIB_DEPENDS= libIlmImf.so:${PORTSDIR}/graphics/OpenEXR \ libjasper.so:${PORTSDIR}/graphics/jasper \ libpcre.so:${PORTSDIR}/devel/pcre \ libavahi-core.so:${PORTSDIR}/net/avahi-app \ libenchant.so:${PORTSDIR}/textproc/enchant \ libgif.so:${PORTSDIR}/graphics/giflib \ libpng.so:${PORTSDIR}/graphics/png \ libjpeg.so:${PORTSDIR}/graphics/jpeg \ libhal.so:${PORTSDIR}/sysutils/hal \ libqca.so:${PORTSDIR}/devel/qca \ libHUpnp.so:${PORTSDIR}/net/hupnp \ libpolkit-qt-core-1.so:${PORTSDIR}/sysutils/polkit-qt \ libdbusmenu-qt.so:${PORTSDIR}/devel/libdbusmenu-qt \ libgrantlee_gui.so:${PORTSDIR}/devel/grantlee BUILD_DEPENDS= ${LOCALBASE}/share/xml/docbook/4.2:${PORTSDIR}/textproc/docbook-xml \ ${LOCALBASE}/share/xsl/docbook/html/docbook.xsl:${PORTSDIR}/textproc/docbook-xsl RUN_DEPENDS= ${LOCALBASE}/share/icons/hicolor/index.theme:${PORTSDIR}/misc/hicolor-icon-theme \ xauth:${PORTSDIR}/x11/xauth \ ${LOCALBASE}/share/xml/docbook/4.2:${PORTSDIR}/textproc/docbook-xml \ ${LOCALBASE}/share/xsl/docbook/html/docbook.xsl:${PORTSDIR}/textproc/docbook-xsl USE_GNOME= libxml2 libxslt USE_KDE4= kdeprefix oxygen \ attica automoc4 ontologies soprano strigi USES= cmake:outsource fam gettext perl5 shared-mime-info shebangfix tar:xz USE_OPENSSL= yes USE_QT4= corelib dbus declarative designer_build gui \ network opengl phonon qt3support \ qtestlib script sql svg webkit xml \ moc_build qmake_build rcc_build uic_build \ imageformats_run qdbusviewer_run USE_XORG= sm x11 xcursor xext xfixes xft xpm xrender xtst USE_LDCONFIG= yes MAKE_ENV= XDG_CONFIG_HOME=/dev/null CMAKE_ARGS+= -DWITH_ACL:BOOL=Off \ -DWITH_FAM:BOOL=On \ -DWITH_ASPELL:BOOL=Off \ -DWITH_HSPELL:BOOL=Off \ -DWITH_UDev:BOOL=Off \ -DHUPNP_ENABLED:BOOL=On \ -DKDE_DISTRIBUTION_TEXT:STRING="${OPSYS}" \ -DKDE_DEFAULT_HOME:STRING=".kde4" SHEBANG_FILES= kdecore/kconfig_compiler/checkkcfg.pl \ kdeui/preparetips \ khtml/bindings/scripts/generate-bindings.pl \ kio/misc/fileshareset \ kio/useragent.pl \ kio/proxytype.pl \ kioslave/http/kcookiejar/kcookiescfg.pl .include .if ${OPSYS} == FreeBSD && ${OSVERSION} < 900004 LIB_DEPENDS+= libutempter.so:${PORTSDIR}/sysutils/libutempter EXTRA_PATCHES= ${FILESDIR}/extra-patch-ConfigureChecks.cmake .endif post-patch: ${REINPLACE_CMD} -e 's,/usr/local,${LOCALBASE},g' \ ${PATCH_WRKSRC}/kde3support/kdeui/k3sconfig.cpp \ ${PATCH_WRKSRC}/kdecore/network/k3socks.cpp \ ${PATCH_WRKSRC}/kdecore/kernel/kstandarddirs.cpp \ ${PATCH_WRKSRC}/kdeui/dialogs/kcupsoptionswidget_p.cpp \ ${PATCH_WRKSRC}/kdeui/kernel/start-session-bus.sh \ ${PATCH_WRKSRC}/kio/kssl/kopenssl.cpp \ ${PATCH_WRKSRC}/kio/kio/ksambashare.cpp \ ${PATCH_WRKSRC}/kjsembed/qtonly/FindQJSInternal.cmake # Fix rgb named colors database path. ${REINPLACE_CMD} -e 's|/usr/X11R6|${LOCALBASE}|g' \ ${PATCH_WRKSRC}/kdeui/colors/kcolordialog.cpp pre-configure: ${REINPLACE_CMD} -e 's|/usr/local|${LOCALBASE}|g' \ -e 's|/usr/X11R6|${LOCALBASE}|g' \ ${PATCH_WRKSRC}/cmake/modules/*.cmake \ ${PATCH_WRKSRC}/ConfigureChecks.cmake \ ${PATCH_WRKSRC}/doc/api/doxygen.sh ${REINPLACE_CMD} -e 's|/usr/include|${LOCALBASE}/include|g' \ ${PATCH_WRKSRC}/cmake/modules/FindDNSSD.cmake ${REINPLACE_CMD} -e 's|soprano/cmake|cmake/Modules|g' \ ${PATCH_WRKSRC}/cmake/modules/FindSoprano.cmake # FindBerkeleyDB.cmake should be rewritten to support multiple version # provided by ports, instead of hardcoding one of them # ${REINPLACE_CMD} -e 's|/usr/local/include/db4|${BDB_INCLUDE_DIR}|' \ # -e 's|NAMES db|NAMES ${BDB_LIB_NAME} ${LOCALBASE}/lib|' \ # ${PATCH_WRKSRC}/cmake/modules/FindBerkeleyDB.cmake # When XSync (xext) is found, xscreensaver is just used as a fallback, # then we can disable it. ${REINPLACE_CMD} -e '/macro_bool_to_01/ s|^.*X11_Xscreensaver.*$$|set(HAVE_XSCREENSAVER 0)|' \ ${PATCH_WRKSRC}/CMakeLists.txt post-install: # workaround for non-standard mime files and directories ${MKDIR} ${STAGEDIR}/${PREFIX}/share/mime/all \ ${STAGEDIR}/${PREFIX}/share/mime/uri .include Index: branches/2015Q1/x11/kdelibs4/files/patch-git_0df92439 =================================================================== --- branches/2015Q1/x11/kdelibs4/files/patch-git_0df92439 (nonexistent) +++ branches/2015Q1/x11/kdelibs4/files/patch-git_0df92439 (revision 378599) @@ -0,0 +1,355 @@ +commit 0df92439241a76c6a67efa9485bd95c3c25d63a0 +Author: Christian Mollekopf +Date: Thu Jan 22 15:04:16 2015 +0100 + + 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 included in the model by default but D not, and A & B only get included due to C, we have the following model: + + - A + - B + - C + + 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. + + REVIEW: 120119 + BUG: 338950 + +--- kdeui/itemviews/krecursivefilterproxymodel.cpp ++++ kdeui/itemviews/krecursivefilterproxymodel.cpp +@@ -108,12 +108,9 @@ public: + void sourceRowsRemoved(const QModelIndex &source_parent, int start, int end); + + /** +- Given that @p index does not match the filter, clear mappings in the QSortFilterProxyModel up to and excluding the +- first ascendant that does match, and remake the mappings. +- +- If @p refreshAll is true, this method also refreshes intermediate mappings. This is significant when removing rows. ++ Given that @p index does not match the filter, clear mappings in the QSortFilterProxyModel up to roo, and remake the mappings. + */ +- void refreshAscendantMapping(const QModelIndex &index, bool refreshAll = false); ++ void refreshAscendantMapping(const QModelIndex &index); + + bool ignoreRemove; + bool completeInsert; +@@ -126,7 +123,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; +@@ -146,27 +143,20 @@ void KRecursiveFilterProxyModelPrivate::sourceDataChanged(const QModelIndex &sou + refreshAscendantMapping(source_parent); + } + +-void KRecursiveFilterProxyModelPrivate::refreshAscendantMapping(const QModelIndex &index, bool refreshAll) ++void KRecursiveFilterProxyModelPrivate::refreshAscendantMapping(const QModelIndex &index) + { + 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) +@@ -261,7 +251,7 @@ void KRecursiveFilterProxyModelPrivate::sourceRowsRemoved(const QModelIndex &sou + // This is needed because QSFPM only invalidates the mapping for the + // index range given to dataChanged, not its children. + if (source_parent.isValid()) +- refreshAscendantMapping(source_parent, true); ++ refreshAscendantMapping(source_parent); + } + + KRecursiveFilterProxyModel::KRecursiveFilterProxyModel(QObject* parent) +--- kdeui/tests/CMakeLists.txt ++++ kdeui/tests/CMakeLists.txt +@@ -82,6 +82,7 @@ KDEUI_PROXYMODEL_TESTS( + kdescendantsproxymodeltest + kselectionproxymodeltest + testmodelqueuedconnections ++ krecursivefilterproxymodeltest + ) + + KDEUI_EXECUTABLE_TESTS( +--- /dev/null ++++ kdeui/tests/krecursivefilterproxymodeltest.cpp +@@ -0,0 +1,220 @@ ++/* ++ Copyright (c) 2014 Christian Mollekopf ++ ++ 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 ++ ++#include ++#include ++ ++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(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(); ++} ++ ++class KRecursiveFilterProxyModelTest : public QObject ++{ ++ Q_OBJECT ++private: ++ ++private slots: ++ // 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 *index1 = new QStandardItem("1"); ++ index1->setData(false); ++ model.appendRow(index1); ++ ++ QVERIFY(!getIndex("1", proxy).isValid()); ++ ++ QStandardItem *index1_1_1 = new QStandardItem("1.1.1"); ++ index1_1_1->setData(false); ++ QStandardItem *index1_1 = new QStandardItem("1.1"); ++ index1_1->setData(false); ++ index1_1->appendRow(index1_1_1); ++ index1->appendRow(index1_1); ++ ++ ModelSignalSpy spy(proxy); ++ index1_1_1->setData(true); ++ ++ QVERIFY(getIndex("1", proxy).isValid()); ++ QVERIFY(getIndex("1.1", proxy).isValid()); ++ QVERIFY(getIndex("1.1.1", proxy).isValid()); ++ ++ QCOMPARE(spy.mSignals, QStringList() << QLatin1String("rowsInserted")); ++ } ++ ++ void testInsert() ++ { ++ QStandardItemModel model; ++ TestModel proxy; ++ proxy.setSourceModel(&model); ++ ++ QStandardItem *index1 = new QStandardItem("index1"); ++ index1->setData(false); ++ model.appendRow(index1); ++ ++ QStandardItem *index1_1 = new QStandardItem("index1_1"); ++ index1_1->setData(false); ++ index1->appendRow(index1_1); ++ ++ QStandardItem *index1_1_1 = new QStandardItem("index1_1_1"); ++ index1_1_1->setData(false); ++ index1_1->appendRow(index1_1_1); ++ ++ QVERIFY(!getIndex("index1", proxy).isValid()); ++ QVERIFY(!getIndex("index1_1", proxy).isValid()); ++ QVERIFY(!getIndex("index1_1_1", proxy).isValid()); ++ ++ ModelSignalSpy spy(proxy); ++ { ++ QStandardItem *index1_1_1_1 = new QStandardItem("index1_1_1_1"); ++ index1_1_1_1->setData(true); ++ index1_1_1->appendRow(index1_1_1_1); ++ } ++ ++ QVERIFY(getIndex("index1", proxy).isValid()); ++ QVERIFY(getIndex("index1_1", proxy).isValid()); ++ QVERIFY(getIndex("index1_1_1", proxy).isValid()); ++ QVERIFY(getIndex("index1_1_1_1", proxy).isValid()); ++ QCOMPARE(spy.mSignals, QStringList() << QLatin1String("rowsInserted")); ++ QCOMPARE(spy.parent, QModelIndex()); ++ } ++ ++ ++ // We want to get index1_1_1_1 into the model which is a descendant of index1_1. ++ // index1_1 is already in the model from the neighbor2 branch. We must ensure dataChange is called on index1_1, ++ // so index1_1_1_1 is included in the model. ++ void testNeighborPath() ++ { ++ QStandardItemModel model; ++ TestModel proxy; ++ proxy.setSourceModel(&model); ++ ++ QStandardItem *index1 = new QStandardItem("index1"); ++ index1->setData(false); ++ model.appendRow(index1); ++ ++ QStandardItem *index1_1 = new QStandardItem("index1_1"); ++ index1_1->setData(false); ++ index1->appendRow(index1_1); ++ ++ QStandardItem *index1_1_1 = new QStandardItem("index1_1_1"); ++ index1_1_1->setData(false); ++ index1_1->appendRow(index1_1_1); ++ ++ { ++ QStandardItem *nb1 = new QStandardItem("neighbor"); ++ nb1->setData(false); ++ index1_1->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 didn't react to the added index1_1_1_1 as it should. ++ QVERIFY(!getIndex("index1_1_1", proxy).isValid()); ++ QVERIFY(getIndex("index1_1", proxy).isValid()); ++ QVERIFY(getIndex("neighbor", proxy).isValid()); ++ QVERIFY(getIndex("neighbor2", proxy).isValid()); ++ ++ ModelSignalSpy spy(proxy); ++ ++ { ++ QStandardItem *index1_1_1_1 = new QStandardItem("index1_1_1_1"); ++ index1_1_1_1->setData(true); ++ index1_1_1->appendRow(index1_1_1_1); ++ } ++ ++ QVERIFY(getIndex("index1_1_1", proxy).isValid()); ++ QVERIFY(getIndex("index1_1_1_1", proxy).isValid()); ++ //The dataChanged signals are not intentional and caused 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" Property changes on: branches/2015Q1/x11/kdelibs4/files/patch-git_0df92439 ___________________________________________________________________ Added: fbsd:nokeywords ## -0,0 +1 ## +yes \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: branches/2015Q1 =================================================================== --- branches/2015Q1 (revision 378598) +++ branches/2015Q1 (revision 378599) Property changes on: branches/2015Q1 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r378101