File indexing completed on 2024-05-19 04:56:07

0001 /**
0002  * \file proxyitemselectionmodel.cpp
0003  * Item selection model to share selection with proxy model.
0004  *
0005  * This is a stripped down version of KLinkItemSelectionModel from kitemmodels.
0006  * Copyright (C) 2010 Klarälvdalens Datakonsult AB,
0007  *     a KDAB Group company, info@kdab.net,
0008  *     author Stephen Kelly <stephen@kdab.com>
0009  * Copyright (c) 2016 Ableton AG <info@ableton.com>
0010  *     Author Stephen Kelly <stephen.kelly@ableton.com>
0011  * Copyright (C) 2018  Urs Fleisch
0012  *
0013  * This library is free software; you can redistribute it and/or modify it
0014  * under the terms of the GNU Library General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or (at your
0016  * option) any later version.
0017 
0018  * This library is distributed in the hope that it will be useful, but WITHOUT
0019  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0020  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
0021  * License for more details.
0022 
0023  * You should have received a copy of the GNU Library General Public License
0024  * along with this library; see the file COPYING.LIB.  If not, write to the
0025  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0026  * 02110-1301, USA.
0027  */
0028 
0029 #include "proxyitemselectionmodel.h"
0030 #include <QAbstractProxyModel>
0031 
0032 ProxyItemSelectionModel::ProxyItemSelectionModel(
0033     QAbstractItemModel* proxyModel, QItemSelectionModel* sourceSelectionModel,
0034     QObject* parent)
0035   : QItemSelectionModel(proxyModel, parent),
0036     m_proxySelectionModel(sourceSelectionModel), m_ignoreCurrentChanged(false)
0037 {
0038   connect(this, &QItemSelectionModel::currentChanged,
0039           this, &ProxyItemSelectionModel::onCurrentChanged);
0040 #if QT_VERSION >= 0x050500
0041   connect(this, &QItemSelectionModel::modelChanged,
0042           this, &ProxyItemSelectionModel::onModelChanged);
0043 #endif
0044 
0045   connect(m_proxySelectionModel,
0046           &QItemSelectionModel::selectionChanged,
0047           this, &ProxyItemSelectionModel::onSelectionChanged);
0048   connect(m_proxySelectionModel,
0049           &QItemSelectionModel::currentChanged,
0050           this, &ProxyItemSelectionModel::onProxyCurrentChanged);
0051 #if QT_VERSION >= 0x050500
0052   connect(m_proxySelectionModel, &QItemSelectionModel::modelChanged,
0053           this, &ProxyItemSelectionModel::onModelChanged);
0054 #endif
0055   onModelChanged();
0056 }
0057 
0058 void ProxyItemSelectionModel::select(
0059     const QModelIndex& index, QItemSelectionModel::SelectionFlags command)
0060 {
0061   if (m_ignoreCurrentChanged) {
0062     return;
0063   }
0064   QItemSelection itemSelection(index, index);
0065   QItemSelectionModel::select(itemSelection, command);
0066   if (index.isValid()) {
0067     m_proxySelectionModel->select(
0068           mapSelectionFromProxy(itemSelection), command);
0069   } else {
0070     m_proxySelectionModel->clearSelection();
0071   }
0072 }
0073 
0074 void ProxyItemSelectionModel::select(
0075     const QItemSelection& selection,
0076     QItemSelectionModel::SelectionFlags command)
0077 {
0078   m_ignoreCurrentChanged = true;
0079   QItemSelection itemSelection = selection;
0080   QItemSelectionModel::select(itemSelection, command);
0081   m_proxySelectionModel->select(mapSelectionFromProxy(itemSelection), command);
0082   m_ignoreCurrentChanged = false;
0083 }
0084 
0085 void ProxyItemSelectionModel::onCurrentChanged(const QModelIndex& current)
0086 {
0087   const QItemSelection selection =
0088       mapSelectionFromProxy(QItemSelection(current, current));
0089   if (selection.isEmpty()) {
0090     return;
0091   }
0092   m_proxySelectionModel->setCurrentIndex(selection.indexes().first(),
0093                                          QItemSelectionModel::NoUpdate);
0094 }
0095 
0096 void ProxyItemSelectionModel::onSelectionChanged(const QItemSelection& selected,
0097                                                const QItemSelection& deselected)
0098 {
0099   QItemSelectionModel::select(mapSelectionFromModel(deselected),
0100                               QItemSelectionModel::Deselect);
0101   QItemSelectionModel::select(mapSelectionFromModel(selected),
0102                               QItemSelectionModel::Select);
0103 }
0104 
0105 void ProxyItemSelectionModel::onProxyCurrentChanged(const QModelIndex& current)
0106 {
0107   const QItemSelection selection =
0108       mapSelectionFromModel(QItemSelection(current, current));
0109   if (selection.isEmpty()) {
0110     return;
0111   }
0112   setCurrentIndex(selection.indexes().first(), QItemSelectionModel::NoUpdate);
0113 }
0114 
0115 void ProxyItemSelectionModel::onModelChanged()
0116 {
0117   if (!model() || !m_proxySelectionModel || !m_proxySelectionModel->model()) {
0118     return;
0119   }
0120   QItemSelectionModel::select(
0121         mapSelectionFromModel(m_proxySelectionModel->selection()),
0122         QItemSelectionModel::ClearAndSelect);
0123 }
0124 
0125 QItemSelection ProxyItemSelectionModel::mapSelectionFromProxy(
0126     const QItemSelection& selection) const
0127 {
0128   if (selection.isEmpty() || !model()) {
0129     return QItemSelection();
0130   }
0131 
0132   Q_ASSERT(qobject_cast<const QAbstractProxyModel*>(model()));
0133   return static_cast<const QAbstractProxyModel*>(model())
0134       ->mapSelectionToSource(selection);
0135 }
0136 
0137 QItemSelection ProxyItemSelectionModel::mapSelectionFromModel(
0138     const QItemSelection& selection) const
0139 {
0140   if (selection.isEmpty() || !model()) {
0141     return QItemSelection();
0142   }
0143 
0144   Q_ASSERT(qobject_cast<const QAbstractProxyModel*>(model()));
0145   return static_cast<const QAbstractProxyModel*>(model())
0146       ->mapSelectionFromSource(selection);
0147 }