diff --git a/src/klinkitemselectionmodel.h b/src/klinkitemselectionmodel.h index 5956c15..2788a1a 100644 --- a/src/klinkitemselectionmodel.h +++ b/src/klinkitemselectionmodel.h @@ -1,131 +1,131 @@ /* Copyright (C) 2010 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.net, author Stephen Kelly Copyright (c) 2016 Ableton AG Author 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 KLINKITEMSELECTIONMODEL_H #define KLINKITEMSELECTIONMODEL_H #include #include #include "kitemmodels_export.h" class KLinkItemSelectionModelPrivate; /** @brief Makes it possible to share a selection in multiple views which do not have the same source model - Although multiple views can share the same QItemSelectionModel, the views then need to have the same source model. + Although multiple views can share the same QItemSelectionModel, the views then need to have the same source model. If there is a proxy model between the model and one of the views, or different proxy models in each, this class makes it possible to share the selection between the views. @image html kproxyitemselectionmodel-simple.png "Sharing a QItemSelectionModel between views on the same model is trivial" @image html kproxyitemselectionmodel-error.png "If a proxy model is used, it is no longer possible to share the QItemSelectionModel directly" @image html kproxyitemselectionmodel-solution.png "A KLinkItemSelectionModel can be used to map the selection through the proxy model" @code QAbstractItemModel *model = getModel(); QSortFilterProxyModel *proxy = new QSortFilterProxyModel(); proxy->setSourceModel(model); QTreeView *view1 = new QTreeView(splitter); view1->setModel(model); KLinkItemSelectionModel *view2SelectionModel = new KLinkItemSelectionModel( proxy, view1->selectionModel()); QTreeView *view2 = new QTreeView(splitter); // Note that the QAbstractItemModel passed to KLinkItemSelectionModel must be the same as what is used in the view view2->setModel(proxy); view2->setSelectionModel( view2SelectionModel ); @endcode @image html kproxyitemselectionmodel-complex.png "Arbitrarily complex proxy configurations on the same root model can be used" @code QAbstractItemModel *model = getModel(); QSortFilterProxyModel *proxy1 = new QSortFilterProxyModel(); proxy1->setSourceModel(model); QSortFilterProxyModel *proxy2 = new QSortFilterProxyModel(); proxy2->setSourceModel(proxy1); QSortFilterProxyModel *proxy3 = new QSortFilterProxyModel(); proxy3->setSourceModel(proxy2); QTreeView *view1 = new QTreeView(splitter); view1->setModel(proxy3); QSortFilterProxyModel *proxy4 = new QSortFilterProxyModel(); proxy4->setSourceModel(model); QSortFilterProxyModel *proxy5 = new QSortFilterProxyModel(); proxy5->setSourceModel(proxy4); KLinkItemSelectionModel *view2SelectionModel = new KLinkItemSelectionModel( proxy5, view1->selectionModel()); QTreeView *view2 = new QTreeView(splitter); // Note that the QAbstractItemModel passed to KLinkItemSelectionModel must be the same as what is used in the view view2->setModel(proxy5); view2->setSelectionModel( view2SelectionModel ); @endcode See also kdelibs/kdeui/tests/proxymodeltestapp/proxyitemselectionwidget.cpp. @since 4.5 @author Stephen Kelly */ 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; private: Q_DECLARE_PRIVATE(KLinkItemSelectionModel) Q_PRIVATE_SLOT(d_func(), void sourceSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected)) Q_PRIVATE_SLOT(d_func(), void sourceCurrentChanged(const QModelIndex ¤t)) Q_PRIVATE_SLOT(d_func(), void slotCurrentChanged(const QModelIndex ¤t)) }; #endif diff --git a/src/kselectionproxymodel.h b/src/kselectionproxymodel.h index 129c94c..fbd5577 100644 --- a/src/kselectionproxymodel.h +++ b/src/kselectionproxymodel.h @@ -1,336 +1,336 @@ /* 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 KSELECTIONPROXYMODEL_H #define KSELECTIONPROXYMODEL_H #include #include #include "kitemmodels_export.h" class KSelectionProxyModelPrivate; /** @brief A Proxy Model which presents a subset of its source model to observers. The KSelectionProxyModel is most useful as a convenience for displaying the selection in one view in another view. The selectionModel of the initial view is used to create a proxied model which is filtered based on the configuration of this class. For example, when a user clicks a mail folder in one view in an email application, the contained emails should be displayed in another view. This takes away the need for the developer to handle the selection between the views, including all the mapToSource, mapFromSource and setRootIndex calls. @code MyModel *sourceModel = new MyModel(this); QTreeView *leftView = new QTreeView(this); leftView->setModel(sourceModel); KSelectionProxyModel *selectionProxy = new KSelectionProxyModel(leftView->selectionModel(), this); selectionProxy->setSourceModel(sourceModel); QTreeView *rightView = new QTreeView(this); rightView->setModel(selectionProxy); @endcode \image html selectionproxymodelsimpleselection.png "A Selection in one view creating a model for use with another view." The KSelectionProxyModel can handle complex selections. \image html selectionproxymodelmultipleselection.png "Non-contiguous selection creating a new simple model in a second view." The contents of the secondary view depends on the selection in the primary view, and the configuration of the proxy model. See KSelectionProxyModel::setFilterBehavior for the different possible configurations. For example, if the filterBehavior is SubTrees, selecting another item in an already selected subtree has no effect. \image html selectionproxymodelmultipleselection-withdescendant.png "Selecting an item and its descendant." See the test application in KDE/kdelibs/kdeui/tests/proxymodeltestapp to try out the valid configurations. \image html kselectionproxymodel-testapp.png "KSelectionProxyModel test application" Obviously, the KSelectionProxyModel may be used in a view, or further processed with other proxy models. See KAddressBook and AkonadiConsole in kdepim for examples which use a further KDescendantsProxyModel and QSortFilterProxyModel on top of a KSelectionProxyModel. Additionally, this class can be used to programmatically choose some items from the source model to display in the view. For example, this is how the Favourite Folder View in KMail works, and is also used in unit testing. - See also: http://doc.trolltech.com/4.5/model-view-proxy-models.html + See also: https://doc.qt.io/qt-5/model-view-programming.html#proxy-models @since 4.4 @author Stephen Kelly */ class KITEMMODELS_EXPORT KSelectionProxyModel : public QAbstractProxyModel { Q_OBJECT Q_PROPERTY(FilterBehavior filterBehavior READ filterBehavior WRITE setFilterBehavior NOTIFY filterBehaviorChanged) Q_PROPERTY(QItemSelectionModel *selectionModel READ selectionModel WRITE setSelectionModel NOTIFY selectionModelChanged) public: /** ctor. @p selectionModel The selection model used to filter what is presented by the proxy. */ // KF6: Remove the selectionModel from the constructor here. explicit KSelectionProxyModel(QItemSelectionModel *selectionModel, QObject *parent = 0); /** Default constructor. Allow the creation of a KSelectionProxyModel in QML code. QML will assign a parent after construction. */ // KF6: Remove in favor of the constructor above. explicit KSelectionProxyModel(); /** dtor */ virtual ~KSelectionProxyModel(); /** reimp. */ void setSourceModel(QAbstractItemModel *sourceModel) Q_DECL_OVERRIDE; QItemSelectionModel *selectionModel() const; void setSelectionModel(QItemSelectionModel *selectionModel); enum FilterBehavior { SubTrees, SubTreeRoots, SubTreesWithoutRoots, ExactSelection, ChildrenOfExactSelection, InvalidBehavior }; Q_ENUM(FilterBehavior) /** Set the filter behaviors of this model. The filter behaviors of the model govern the content of the model based on the selection of the contained QItemSelectionModel. See kdeui/proxymodeltestapp to try out the different proxy model behaviors. The most useful behaviors are SubTrees, ExactSelection and ChildrenOfExactSelection. The default behavior is SubTrees. This means that this proxy model will contain the roots of the items in the source model. Any descendants which are also selected have no additional effect. For example if the source model is like: @verbatim (root) - A - B - C - D - E - F - G - H - I - J - K - L @endverbatim And A, B, C and D are selected, the proxy will contain: @verbatim (root) - A - B - C - D - E - F - G @endverbatim That is, selecting 'D' or 'C' if 'B' is also selected has no effect. If 'B' is de-selected, then 'C' amd 'D' become top-level items: @verbatim (root) - A - C - D - E - F - G @endverbatim This is the behavior used by KJots when rendering books. If the behavior is set to SubTreeRoots, then the children of selected indexes are not part of the model. If 'A', 'B' and 'D' are selected, @verbatim (root) - A - B @endverbatim Note that although 'D' is selected, it is not part of the proxy model, because its parent 'B' is already selected. SubTreesWithoutRoots has the effect of not making the selected items part of the model, but making their children part of the model instead. If 'A', 'B' and 'I' are selected: @verbatim (root) - C - D - E - F - G - J - K - L @endverbatim Note that 'A' has no children, so selecting it has no outward effect on the model. ChildrenOfExactSelection causes the proxy model to contain the children of the selected indexes,but further descendants are omitted. Additionally, if descendants of an already selected index are selected, their children are part of the proxy model. For example, if 'A', 'B', 'D' and 'I' are selected: @verbatim (root) - C - D - E - G - J - K - L @endverbatim This would be useful for example if showing containers (for example maildirs) in one view and their items in another. Sub-maildirs would still appear in the proxy, but could be filtered out using a QSortfilterProxyModel. The ExactSelection behavior causes the selected items to be part of the proxy model, even if their ancestors are already selected, but children of selected items are not included. Again, if 'A', 'B', 'D' and 'I' are selected: @verbatim (root) - A - B - D - I @endverbatim This is the behavior used by the Favourite Folder View in KMail. */ void setFilterBehavior(FilterBehavior behavior); FilterBehavior filterBehavior() const; QModelIndex mapFromSource(const QModelIndex &sourceIndex) const Q_DECL_OVERRIDE; QModelIndex mapToSource(const QModelIndex &proxyIndex) const Q_DECL_OVERRIDE; QItemSelection mapSelectionFromSource(const QItemSelection &selection) const Q_DECL_OVERRIDE; QItemSelection mapSelectionToSource(const QItemSelection &selection) const Q_DECL_OVERRIDE; Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE; QMimeData *mimeData(const QModelIndexList &indexes) const Q_DECL_OVERRIDE; QStringList mimeTypes() const Q_DECL_OVERRIDE; Qt::DropActions supportedDropActions() const Q_DECL_OVERRIDE; bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) Q_DECL_OVERRIDE; bool hasChildren(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex index(int, int, const QModelIndex & = QModelIndex()) const Q_DECL_OVERRIDE; QModelIndex parent(const QModelIndex &) const Q_DECL_OVERRIDE; int columnCount(const QModelIndex & = QModelIndex()) const Q_DECL_OVERRIDE; virtual QModelIndexList match(const QModelIndex &start, int role, const QVariant &value, int hits = 1, Qt::MatchFlags flags = Qt::MatchFlags(Qt::MatchStartsWith | Qt::MatchWrap)) const Q_DECL_OVERRIDE; Q_SIGNALS: #if !defined(Q_MOC_RUN) && !defined(DOXYGEN_SHOULD_SKIP_THIS) && !defined(IN_IDE_PARSER) private: // Don't allow subclasses to emit these Q_SIGNALS. #endif /** @internal Emitted before @p removeRootIndex, an index in the sourceModel is removed from the root selected indexes. This may be unrelated to rows removed from the model, depending on configuration. */ void rootIndexAboutToBeRemoved(const QModelIndex &removeRootIndex); /** @internal Emitted when @p newIndex, an index in the sourceModel is added to the root selected indexes. This may be unrelated to rows inserted to the model, depending on configuration. */ void rootIndexAdded(const QModelIndex &newIndex); /** @internal Emitted before @p selection, a selection in the sourceModel, is removed from the root selection. */ void rootSelectionAboutToBeRemoved(const QItemSelection &selection); /** @internal Emitted after @p selection, a selection in the sourceModel, is added to the root selection. */ void rootSelectionAdded(const QItemSelection &selection); void selectionModelChanged(); void filterBehaviorChanged(); protected: QList sourceRootIndexes() const; private: Q_DECLARE_PRIVATE(KSelectionProxyModel) //@cond PRIVATE KSelectionProxyModelPrivate *d_ptr; Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeInserted(const QModelIndex &, int, int)) Q_PRIVATE_SLOT(d_func(), void sourceRowsInserted(const QModelIndex &, int, int)) Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeRemoved(const QModelIndex &, int, int)) Q_PRIVATE_SLOT(d_func(), void sourceRowsRemoved(const QModelIndex &, int, int)) Q_PRIVATE_SLOT(d_func(), void sourceRowsAboutToBeMoved(const QModelIndex &, int, int, const QModelIndex &, int)) Q_PRIVATE_SLOT(d_func(), void sourceRowsMoved(const QModelIndex &, int, int, const QModelIndex &, int)) Q_PRIVATE_SLOT(d_func(), void sourceModelAboutToBeReset()) Q_PRIVATE_SLOT(d_func(), void sourceModelReset()) Q_PRIVATE_SLOT(d_func(), void sourceLayoutAboutToBeChanged()) Q_PRIVATE_SLOT(d_func(), void sourceLayoutChanged()) Q_PRIVATE_SLOT(d_func(), void sourceDataChanged(const QModelIndex &, const QModelIndex &)) Q_PRIVATE_SLOT(d_func(), void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected)) Q_PRIVATE_SLOT(d_func(), void sourceModelDestroyed()) //@endcond }; #endif