File indexing completed on 2024-07-21 06:38:22

0001 /*
0002     SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
0003     SPDX-FileContributor: Stephen Kelly <stephen@kdab.com>
0004     SPDX-FileCopyrightText: 2016 Ableton AG <info@ableton.com>
0005     SPDX-FileContributor: Stephen Kelly <stephen.kelly@ableton.com>
0006 
0007     SPDX-License-Identifier: LGPL-2.0-or-later
0008 */
0009 
0010 #ifndef KLINKITEMSELECTIONMODEL_H
0011 #define KLINKITEMSELECTIONMODEL_H
0012 
0013 #include <QItemSelectionModel>
0014 
0015 #include "kitemmodels_export.h"
0016 
0017 #include <memory>
0018 
0019 class KLinkItemSelectionModelPrivate;
0020 
0021 /**
0022   @class KLinkItemSelectionModel klinkitemselectionmodel.h KLinkItemSelectionModel
0023 
0024   @brief Makes it possible to share a selection in multiple views which do not have the same source model
0025 
0026   Although <a href="https://doc.qt.io/qt-5/model-view-programming.html#handling-selections-of-items">multiple views can share the same QItemSelectionModel</a>,
0027   the views then need to have the same source model.
0028 
0029   If there is a proxy model between the model and one of the views, or different proxy models in each, this class makes
0030   it possible to share the selection between the views.
0031 
0032   @image html kproxyitemselectionmodel-simple.png "Sharing a QItemSelectionModel between views on the same model is trivial"
0033   @image html kproxyitemselectionmodel-error.png "If a proxy model is used, it is no longer possible to share the QItemSelectionModel directly"
0034   @image html kproxyitemselectionmodel-solution.png "A KLinkItemSelectionModel can be used to map the selection through the proxy model"
0035 
0036   @code
0037     QAbstractItemModel *model = getModel();
0038 
0039     QSortFilterProxyModel *proxy = new QSortFilterProxyModel();
0040     proxy->setSourceModel(model);
0041 
0042     QTreeView *view1 = new QTreeView(splitter);
0043     view1->setModel(model);
0044 
0045     KLinkItemSelectionModel *view2SelectionModel = new KLinkItemSelectionModel( proxy, view1->selectionModel());
0046 
0047     QTreeView *view2 = new QTreeView(splitter);
0048     // Note that the QAbstractItemModel passed to KLinkItemSelectionModel must be the same as what is used in the view
0049     view2->setModel(proxy);
0050     view2->setSelectionModel( view2SelectionModel );
0051   @endcode
0052 
0053   @image html kproxyitemselectionmodel-complex.png "Arbitrarily complex proxy configurations on the same root model can be used"
0054 
0055   @code
0056     QAbstractItemModel *model = getModel();
0057 
0058     QSortFilterProxyModel *proxy1 = new QSortFilterProxyModel();
0059     proxy1->setSourceModel(model);
0060     QSortFilterProxyModel *proxy2 = new QSortFilterProxyModel();
0061     proxy2->setSourceModel(proxy1);
0062     QSortFilterProxyModel *proxy3 = new QSortFilterProxyModel();
0063     proxy3->setSourceModel(proxy2);
0064 
0065     QTreeView *view1 = new QTreeView(splitter);
0066     view1->setModel(proxy3);
0067 
0068     QSortFilterProxyModel *proxy4 = new QSortFilterProxyModel();
0069     proxy4->setSourceModel(model);
0070     QSortFilterProxyModel *proxy5 = new QSortFilterProxyModel();
0071     proxy5->setSourceModel(proxy4);
0072 
0073     KLinkItemSelectionModel *view2SelectionModel = new KLinkItemSelectionModel( proxy5, view1->selectionModel());
0074 
0075     QTreeView *view2 = new QTreeView(splitter);
0076     // Note that the QAbstractItemModel passed to KLinkItemSelectionModel must be the same as what is used in the view
0077     view2->setModel(proxy5);
0078     view2->setSelectionModel( view2SelectionModel );
0079   @endcode
0080 
0081   See also <a href="https://commits.kde.org/kitemmodels?path=tests/proxymodeltestapp/proxyitemselectionwidget.cpp">kitemmodels:
0082   tests/proxymodeltestapp/proxyitemselectionwidget.cpp</a>.
0083 
0084   @since 4.5
0085   @author Stephen Kelly <steveire@gmail.com>
0086 
0087 */
0088 class KITEMMODELS_EXPORT KLinkItemSelectionModel : public QItemSelectionModel
0089 {
0090     Q_OBJECT
0091     Q_PROPERTY(
0092         QItemSelectionModel *linkedItemSelectionModel READ linkedItemSelectionModel WRITE setLinkedItemSelectionModel NOTIFY linkedItemSelectionModelChanged)
0093 public:
0094     /**
0095       Constructor.
0096     */
0097     KLinkItemSelectionModel(QAbstractItemModel *targetModel, QItemSelectionModel *linkedItemSelectionModel, QObject *parent = nullptr);
0098 
0099     explicit KLinkItemSelectionModel(QObject *parent = nullptr);
0100 
0101     ~KLinkItemSelectionModel() override;
0102 
0103     QItemSelectionModel *linkedItemSelectionModel() const;
0104     void setLinkedItemSelectionModel(QItemSelectionModel *selectionModel);
0105 
0106     void select(const QModelIndex &index, QItemSelectionModel::SelectionFlags command) override;
0107     void select(const QItemSelection &selection, QItemSelectionModel::SelectionFlags command) override;
0108 
0109 Q_SIGNALS:
0110     void linkedItemSelectionModelChanged();
0111 
0112 protected:
0113     std::unique_ptr<KLinkItemSelectionModelPrivate> const d_ptr;
0114 
0115 private:
0116     Q_DECLARE_PRIVATE(KLinkItemSelectionModel)
0117     Q_PRIVATE_SLOT(d_func(), void sourceSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected))
0118     Q_PRIVATE_SLOT(d_func(), void sourceCurrentChanged(const QModelIndex &current))
0119     Q_PRIVATE_SLOT(d_func(), void slotCurrentChanged(const QModelIndex &current))
0120 };
0121 
0122 #endif