diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 587ee27..44c57b5 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -1,116 +1,116 @@ set(kitemmodels_SRCS kbreadcrumbselectionmodel.cpp kcheckableproxymodel.cpp kconcatenaterowsproxymodel.cpp kdescendantsproxymodel.cpp kextracolumnsproxymodel.cpp klinkitemselectionmodel.cpp kmodelindexproxymapper.cpp knumbermodel.cpp krearrangecolumnsproxymodel.cpp krecursivefilterproxymodel.cpp kselectionproxymodel.cpp ) ecm_qt_declare_logging_category(kitemmodels_SRCS HEADER kitemmodels_debug.h IDENTIFIER KITEMMODELS_LOG CATEGORY_NAME kf5.kitemmodels) add_library(KF5ItemModels ${kitemmodels_SRCS}) add_library(KF5::ItemModels ALIAS KF5ItemModels) ecm_generate_export_header(KF5ItemModels BASE_NAME KItemModels GROUP_BASE_NAME KF VERSION ${KF5_VERSION} DEPRECATED_BASE_VERSION 0 - DEPRECATION_VERSIONS 4.8 + DEPRECATION_VERSIONS 4.8 5.65 EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} ) # reminder trigger to apply KITEMMODELS_ENABLE_DEPRECATED_SINCE & friends to KConcatenateRowsProxyModel when the time is there if (REQUIRED_QT_VERSION VERSION_GREATER 5.12.0) message(WARNING "With Qt 5.13 as min dep, mark KConcatenateRowsProxyModel as deprecated to the compiler & remove this warning") endif() target_include_directories(KF5ItemModels INTERFACE "$") target_link_libraries(KF5ItemModels PUBLIC Qt5::Core) set_target_properties(KF5ItemModels PROPERTIES VERSION ${KITEMMODELS_VERSION_STRING} SOVERSION ${KITEMMODELS_SOVERSION} EXPORT_NAME ItemModels ) ecm_generate_headers(KItemModels_HEADERS HEADER_NAMES KBreadcrumbSelectionModel KConcatenateRowsProxyModel KCheckableProxyModel KExtraColumnsProxyModel KLinkItemSelectionModel KRearrangeColumnsProxyModel KRecursiveFilterProxyModel KDescendantsProxyModel KModelIndexProxyMapper KSelectionProxyModel KNumberModel REQUIRED_HEADERS KItemModels_HEADERS ) find_package(PythonModuleGeneration) if (PythonModuleGeneration_FOUND) ecm_generate_python_binding( TARGET KF5::ItemModels PYTHONNAMESPACE PyKF5 MODULENAME KItemModels SIP_DEPENDS QtCore/QtCoremod.sip HEADERS kbreadcrumbselectionmodel.h kconcatenaterowsproxymodel.h kcheckableproxymodel.h kextracolumnsproxymodel.h klinkitemselectionmodel.h krearrangecolumnsproxymodel.h krecursivefilterproxymodel.h kdescendantsproxymodel.h kmodelindexproxymapper.h kselectionproxymodel.h ) endif() install(TARGETS KF5ItemModels EXPORT KF5ItemModelsTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/kitemmodels_export.h ${KItemModels_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KItemModels COMPONENT Devel ) if(BUILD_QCH) ecm_add_qch( KF5ItemModels_QCH NAME KItemModels BASE_NAME KF5ItemModels VERSION ${KF5_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${KItemModels_HEADERS} MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" IMAGE_DIRS "${CMAKE_SOURCE_DIR}/docs/pics" LINK_QCHS Qt5Core_QCH INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} BLANK_MACROS KITEMMODELS_EXPORT "KITEMMODELS_DEPRECATED_VERSION(x, y, t)" TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR} COMPONENT Devel ) endif() include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KItemModels LIB_NAME KF5ItemModels DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}/KItemModels) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/core/krecursivefilterproxymodel.cpp b/src/core/krecursivefilterproxymodel.cpp index 00e6547..09a2342 100644 --- a/src/core/krecursivefilterproxymodel.cpp +++ b/src/core/krecursivefilterproxymodel.cpp @@ -1,427 +1,429 @@ /* Copyright (c) 2009 Stephen Kelly 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 "krecursivefilterproxymodel.h" +#if KITEMMODELS_BUILD_DEPRECATED_SINCE(5, 65) #include // Maintainability note: // This class invokes some Q_PRIVATE_SLOTs in QSortFilterProxyModel which are // private API and could be renamed or removed at any time. // If they are renamed, the invocations can be updated with an #if (QT_VERSION(...)) // If they are removed, then layout{AboutToBe}Changed Q_SIGNALS should be used when the source model // gets new rows or has rowsremoved or moved. The Q_PRIVATE_SLOT invocation is an optimization // because layout{AboutToBe}Changed is expensive and causes the entire mapping of the tree in QSFPM // to be cleared, even if only a part of it is dirty. // Stephen Kelly, 30 April 2010. // All this is temporary anyway, the long term solution is support in QSFPM: https://codereview.qt-project.org/151000 class KRecursiveFilterProxyModelPrivate { Q_DECLARE_PUBLIC(KRecursiveFilterProxyModel) KRecursiveFilterProxyModel *q_ptr; public: KRecursiveFilterProxyModelPrivate(KRecursiveFilterProxyModel *model) : q_ptr(model), completeInsert(false) { qRegisterMetaType("QModelIndex"); } inline QMetaMethod findMethod(const char *signature) const { Q_Q(const KRecursiveFilterProxyModel); const int idx = q->metaObject()->indexOfMethod(signature); Q_ASSERT(idx != -1); return q->metaObject()->method(idx); } // Convenience methods for invoking the QSFPM Q_SLOTS. Those slots must be invoked with invokeMethod // because they are Q_PRIVATE_SLOTs inline void invokeDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles = QVector()) { Q_Q(KRecursiveFilterProxyModel); // required for Qt 5.5 and upwards, see commit f96baeb75fc in qtbase static const QMetaMethod m = findMethod("_q_sourceDataChanged(QModelIndex,QModelIndex,QVector)"); bool success = m.invoke(q, Qt::DirectConnection, Q_ARG(QModelIndex, topLeft), Q_ARG(QModelIndex, bottomRight), Q_ARG(QVector, roles)); Q_UNUSED(success); Q_ASSERT(success); } inline void invokeRowsInserted(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); static const QMetaMethod m = findMethod("_q_sourceRowsInserted(QModelIndex,int,int)"); bool success = m.invoke(q, Qt::DirectConnection, Q_ARG(QModelIndex, source_parent), Q_ARG(int, start), Q_ARG(int, end)); Q_UNUSED(success); Q_ASSERT(success); } inline void invokeRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); static const QMetaMethod m = findMethod("_q_sourceRowsAboutToBeInserted(QModelIndex,int,int)"); bool success = m.invoke(q, Qt::DirectConnection, Q_ARG(QModelIndex, source_parent), Q_ARG(int, start), Q_ARG(int, end)); Q_UNUSED(success); Q_ASSERT(success); } inline void invokeRowsRemoved(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); static const QMetaMethod m = findMethod("_q_sourceRowsRemoved(QModelIndex,int,int)"); bool success = m.invoke(q, Qt::DirectConnection, Q_ARG(QModelIndex, source_parent), Q_ARG(int, start), Q_ARG(int, end)); Q_UNUSED(success); Q_ASSERT(success); } inline void invokeRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); static const QMetaMethod m = findMethod("_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int)"); bool success = m.invoke(q, Qt::DirectConnection, Q_ARG(QModelIndex, source_parent), Q_ARG(int, start), Q_ARG(int, end)); Q_UNUSED(success); Q_ASSERT(success); } void sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right, const QVector &roles = QVector()); void sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end); void sourceRowsInserted(const QModelIndex &source_parent, int start, int end); void sourceRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end); void sourceRowsRemoved(const QModelIndex &source_parent, int start, int end); /** Force QSortFilterProxyModel to re-evaluate whether to hide or show index and its parents. */ void refreshAscendantMapping(const QModelIndex &index); QModelIndex lastFilteredOutAscendant(const QModelIndex &index); bool completeInsert; QModelIndex lastHiddenAscendantForInsert; }; void KRecursiveFilterProxyModelPrivate::sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right, const QVector &roles) { QModelIndex source_parent = source_top_left.parent(); Q_ASSERT(source_bottom_right.parent() == source_parent); // don't know how to handle different parents in this code... // Tell the world. invokeDataChanged(source_top_left, source_bottom_right, roles); // We can't find out if the change really matters to us or not, for a lack of a dataAboutToBeChanged signal (or a cache). // TODO: add a set of roles that we care for, so we can at least ignore the rest. // Even if we knew the visibility was just toggled, we also can't find out what // was the last filtered out ascendant (on show, like sourceRowsAboutToBeInserted does) // or the last to-be-filtered-out ascendant (on hide, like sourceRowsRemoved does) // So we have to refresh all parents. QModelIndex sourceParent = source_parent; while (sourceParent.isValid()) { invokeDataChanged(sourceParent, sourceParent, roles); sourceParent = sourceParent.parent(); } } QModelIndex KRecursiveFilterProxyModelPrivate::lastFilteredOutAscendant(const QModelIndex &idx) { Q_Q(KRecursiveFilterProxyModel); QModelIndex last = idx; QModelIndex index = idx.parent(); while (index.isValid() && !q->filterAcceptsRow(index.row(), index.parent())) { last = index; index = index.parent(); } return last; } void KRecursiveFilterProxyModelPrivate::sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); if (!source_parent.isValid() || q->filterAcceptsRow(source_parent.row(), source_parent.parent())) { // If the parent is already in the model (directly or indirectly), we can just pass on the signal. invokeRowsAboutToBeInserted(source_parent, start, end); completeInsert = true; } else { // OK, so parent is not in the model. // Maybe the grand parent neither.. Go up until the first one that is. lastHiddenAscendantForInsert = lastFilteredOutAscendant(source_parent); } } void KRecursiveFilterProxyModelPrivate::sourceRowsInserted(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); if (completeInsert) { // If the parent is already in the model, we can just pass on the signal. completeInsert = false; invokeRowsInserted(source_parent, start, end); return; } bool requireRow = false; for (int row = start; row <= end; ++row) { if (q->filterAcceptsRow(row, source_parent)) { requireRow = true; break; } } if (!requireRow) { // The new rows doesn't have any descendants that match the filter. Filter them out. return; } // Make QSFPM realize that lastHiddenAscendantForInsert should be shown now invokeDataChanged(lastHiddenAscendantForInsert, lastHiddenAscendantForInsert); } void KRecursiveFilterProxyModelPrivate::sourceRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end) { invokeRowsAboutToBeRemoved(source_parent, start, end); } void KRecursiveFilterProxyModelPrivate::sourceRowsRemoved(const QModelIndex &source_parent, int start, int end) { Q_Q(KRecursiveFilterProxyModel); invokeRowsRemoved(source_parent, start, end); // Find out if removing this visible row means that some ascendant // row can now be hidden. // We go up until we find a row that should still be visible // and then make QSFPM re-evaluate the last one we saw before that, to hide it. QModelIndex toHide; QModelIndex sourceAscendant = source_parent; while (sourceAscendant.isValid()) { if (q->filterAcceptsRow(sourceAscendant.row(), sourceAscendant.parent())) { break; } toHide = sourceAscendant; sourceAscendant = sourceAscendant.parent(); } if (toHide.isValid()) { invokeDataChanged(toHide, toHide); } } KRecursiveFilterProxyModel::KRecursiveFilterProxyModel(QObject *parent) : QSortFilterProxyModel(parent), d_ptr(new KRecursiveFilterProxyModelPrivate(this)) { setDynamicSortFilter(true); } KRecursiveFilterProxyModel::~KRecursiveFilterProxyModel() { delete d_ptr; } bool KRecursiveFilterProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const { // TODO: Implement some caching so that if one match is found on the first pass, we can return early results // when the subtrees are checked by QSFPM. if (acceptRow(sourceRow, sourceParent)) { return true; } QModelIndex source_index = sourceModel()->index(sourceRow, 0, sourceParent); Q_ASSERT(source_index.isValid()); bool accepted = false; const int numChildren = sourceModel()->rowCount(source_index); for (int row = 0, rows = numChildren; row < rows; ++row) { if (filterAcceptsRow(row, source_index)) { accepted = true; break; } } return accepted; } QModelIndexList KRecursiveFilterProxyModel::match(const QModelIndex &start, int role, const QVariant &value, int hits, Qt::MatchFlags flags) const { if (role < Qt::UserRole) { return QSortFilterProxyModel::match(start, role, value, hits, flags); } QModelIndexList list; if (!sourceModel()) return list; QModelIndex proxyIndex; const auto lst = sourceModel()->match(mapToSource(start), role, value, hits, flags); for (const QModelIndex &idx : lst) { proxyIndex = mapFromSource(idx); if (proxyIndex.isValid()) { list << proxyIndex; } } return list; } bool KRecursiveFilterProxyModel::acceptRow(int sourceRow, const QModelIndex &sourceParent) const { return QSortFilterProxyModel::filterAcceptsRow(sourceRow, sourceParent); } void KRecursiveFilterProxyModel::setSourceModel(QAbstractItemModel *model) { // Standard disconnect of the previous source model, if present if (sourceModel()) { disconnect(sourceModel(), SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), this, SLOT(sourceDataChanged(QModelIndex,QModelIndex,QVector))); disconnect(sourceModel(), SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int))); disconnect(sourceModel(), SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(sourceRowsInserted(QModelIndex,int,int))); disconnect(sourceModel(), SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int))); disconnect(sourceModel(), SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(sourceRowsRemoved(QModelIndex,int,int))); } QSortFilterProxyModel::setSourceModel(model); // Disconnect in the QSortFilterProxyModel. These methods will be invoked manually // in invokeDataChanged, invokeRowsInserted etc. // // The reason for that is that when the source model adds new rows for example, the new rows // May not match the filter, but maybe their child items do match. // // Source model before insert: // // - A // - B // - - C // - - D // - - - E // - - - F // - - - G // - H // - I // // If the A F and L (which doesn't exist in the source model yet) match the filter // the proxy will be: // // - A // - B // - - D // - - - F // // New rows are inserted in the source model below H: // // - A // - B // - - C // - - D // - - - E // - - - F // - - - G // - H // - - J // - - K // - - - L // - I // // As L matches the filter, it should be part of the KRecursiveFilterProxyModel. // // - A // - B // - - D // - - - F // - H // - - K // - - - L // // when the QSortFilterProxyModel gets a notification about new rows in H, it only checks // J and K to see if they match, ignoring L, and therefore not adding it to the proxy. // To work around that, we make sure that the QSFPM slot which handles that change in // the source model (_q_sourceRowsAboutToBeInserted) does not get called directly. // Instead we connect the sourceModel signal to our own slot in *this (sourceRowsAboutToBeInserted) // Inside that method, the entire new subtree is queried (J, K *and* L) to see if there is a match, // then the relevant Q_SLOTS in QSFPM are invoked. // In the example above, we need to tell the QSFPM that H should be queried again to see if // it matches the filter. It did not before, because L did not exist before. Now it does. That is // achieved by telling the QSFPM that the data changed for H, which causes it to requery this class // to see if H matches the filter (which it now does as L now exists). // That is done in sourceRowsInserted. if (!model) { return; } disconnect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), this, SLOT(_q_sourceDataChanged(QModelIndex,QModelIndex,QVector))); disconnect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(_q_sourceRowsAboutToBeInserted(QModelIndex,int,int))); disconnect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(_q_sourceRowsInserted(QModelIndex,int,int))); disconnect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceRowsAboutToBeRemoved(QModelIndex,int,int))); disconnect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(_q_sourceRowsRemoved(QModelIndex,int,int))); // Slots for manual invoking of QSortFilterProxyModel methods. connect(model, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)), this, SLOT(sourceDataChanged(QModelIndex,QModelIndex,QVector))); connect(model, SIGNAL(rowsAboutToBeInserted(QModelIndex,int,int)), this, SLOT(sourceRowsAboutToBeInserted(QModelIndex,int,int))); connect(model, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(sourceRowsInserted(QModelIndex,int,int))); connect(model, SIGNAL(rowsAboutToBeRemoved(QModelIndex,int,int)), this, SLOT(sourceRowsAboutToBeRemoved(QModelIndex,int,int))); connect(model, SIGNAL(rowsRemoved(QModelIndex,int,int)), this, SLOT(sourceRowsRemoved(QModelIndex,int,int))); } #include "moc_krecursivefilterproxymodel.cpp" +#endif diff --git a/src/core/krecursivefilterproxymodel.h b/src/core/krecursivefilterproxymodel.h index 25d4a01..c319373 100644 --- a/src/core/krecursivefilterproxymodel.h +++ b/src/core/krecursivefilterproxymodel.h @@ -1,138 +1,142 @@ /* Copyright (c) 2009 Stephen Kelly 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. */ #ifndef KRECURSIVEFILTERPROXYMODEL_H #define KRECURSIVEFILTERPROXYMODEL_H -#include - #include "kitemmodels_export.h" +#if KITEMMODELS_ENABLE_DEPRECATED_SINCE(5, 65) +#include + class KRecursiveFilterProxyModelPrivate; /** @class KRecursiveFilterProxyModel krecursivefilterproxymodel.h KRecursiveFilterProxyModel @brief Implements recursive filtering of models Until Qt 5.10, QSortFilterProxyModel did not recurse when invoking a filtering stage, so that if a particular row is filtered out, its children are not even checked to see if they match the filter. If you can depend on Qt >= 5.10, then just use QSortFilterProxyModel::setRecursiveFilteringEnabled(true), and you don't need to use KRecursiveFilterProxyModel. For example, given a source model: @verbatim - A - B - - C - - - D - - - - E - - - F - - G - - H - I @endverbatim If a QSortFilterProxyModel is used with a filter matching A, D, G and I, the QSortFilterProxyModel will contain @verbatim - A - I @endverbatim That is, even though D and G match the filter, they are not represented in the proxy model because B does not match the filter and is filtered out. The KRecursiveFilterProxyModel checks child indexes for filter matching and ensures that all matching indexes are represented in the model. In the above example, the KRecursiveFilterProxyModel will contain @verbatim - A - B - - C - - - D - - G - I @endverbatim That is, the leaves in the model match the filter, but not necessarily the inner branches. QSortFilterProxyModel provides the virtual method filterAcceptsRow to allow custom filter implementations. Custom filter implementations can be written for KRecuriveFilterProxyModel using the acceptRow virtual method. Note that using this proxy model is additional overhead compared to QSortFilterProxyModel as every index in the model must be visited and queried. @author Stephen Kelly @since 4.5 + @deprecated since 5.65, use QSortFilterProxyModel::setRecursiveFilteringEnabled(true) instead. See detailed description. */ class KITEMMODELS_EXPORT KRecursiveFilterProxyModel : public QSortFilterProxyModel { Q_OBJECT public: /** Constructor */ + KITEMMODELS_DEPRECATED_VERSION(5, 65, "Use QSortFilterProxyModel directly and QSortFilterProxyModel::setRecursiveFilteringEnabled(true)") explicit KRecursiveFilterProxyModel(QObject *parent = nullptr); /** Destructor */ ~KRecursiveFilterProxyModel() override; /** @reimp */ void setSourceModel(QAbstractItemModel *model) override; /** * @reimplemented */ QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const override; protected: /** Reimplement this method for custom filtering strategies. */ virtual bool acceptRow(int sourceRow, const QModelIndex &sourceParent) const; /** @reimp */ bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; KRecursiveFilterProxyModelPrivate *const d_ptr; private: //@cond PRIVATE Q_DECLARE_PRIVATE(KRecursiveFilterProxyModel) Q_PRIVATE_SLOT(d_func(), void sourceDataChanged(const QModelIndex &source_top_left, const QModelIndex &source_bottom_right, const QVector &roles = QVector())) Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeInserted(const QModelIndex &source_parent, int start, int end)) Q_PRIVATE_SLOT(d_func(), void sourceRowsInserted(const QModelIndex &source_parent, int start, int end)) Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeRemoved(const QModelIndex &source_parent, int start, int end)) Q_PRIVATE_SLOT(d_func(), void sourceRowsRemoved(const QModelIndex &source_parent, int start, int end)) //@endcond }; #endif +#endif