File indexing completed on 2024-05-12 05:09:52

0001 /***************************************************************************
0002     Copyright (C) 2011 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include "entryselectionmodel.h"
0026 #include "models.h"
0027 #include "../tellico_debug.h"
0028 
0029 #include <QSet>
0030 
0031 using Tellico::EntrySelectionModel;
0032 
0033 EntrySelectionModel::EntrySelectionModel(QAbstractItemModel* targetModel_,
0034                                          QItemSelectionModel* selModel_,
0035                                          QObject* parent_)
0036     : KLinkItemSelectionModel(targetModel_, selModel_, parent_)
0037     , m_processing(false) {
0038   addSelectionProxy(selModel_);
0039   // when the entry model is reset, the selection signal is not triggered
0040   // using the modelReset signal does not work
0041   connect(targetModel_, &QAbstractItemModel::modelAboutToBeReset,
0042           this, &QItemSelectionModel::clear);
0043 }
0044 
0045 void EntrySelectionModel::addSelectionProxy(QItemSelectionModel* selModel_) {
0046   Q_ASSERT(selModel_);
0047   m_modelList += selModel_;
0048   connect(selModel_, &QItemSelectionModel::selectionChanged,
0049           this, &EntrySelectionModel::selectedEntriesChanged);
0050   connect(selModel_->model(), &QAbstractItemModel::modelAboutToBeReset,
0051           this, [this]() { m_selectedEntries.clear();});
0052 }
0053 
0054 void EntrySelectionModel::selectedEntriesChanged(const QItemSelection& selected_, const QItemSelection& deselected_) {
0055   // when clearSelection() is called on the other models, then there's a cascading series of calls to
0056   // selectedEntriesChanged(). But we only care about the first one
0057   if(m_processing) {
0058     return;
0059   }
0060   m_processing = true;
0061 
0062   QItemSelectionModel* selectionModel = qobject_cast<QItemSelectionModel*>(sender());
0063   Q_ASSERT(selectionModel);
0064   if(!selectionModel) {
0065     m_processing = false;
0066     return;
0067   }
0068 
0069   if(m_recentSelectionModel != selectionModel) {
0070     m_selectedEntries.clear();
0071   }
0072   m_recentSelectionModel = selectionModel;
0073 
0074   // clearing the selection in the other models will have cascading calls to selectionChanged()
0075   // now, add and remove selected entries from the list
0076   // the selection will include an index for every column, need to check for duplicates
0077   // can't use a QSet of entries since we want to retain the selection ordering
0078   QSet<Data::ID> IDlist;
0079   foreach(const QModelIndex& index, deselected_.indexes()) {
0080     Data::EntryPtr entry = index.data(EntryPtrRole).value<Data::EntryPtr>();
0081     if(entry && !IDlist.contains(entry->id())) {
0082       m_selectedEntries.removeOne(entry);
0083       IDlist += entry->id();
0084     }
0085   }
0086   IDlist.clear();
0087   foreach(const QModelIndex& index, selected_.indexes()) {
0088     Data::EntryPtr entry = index.data(EntryPtrRole).value<Data::EntryPtr>();
0089     if(entry && !IDlist.contains(entry->id())) {
0090       m_selectedEntries += entry;
0091       IDlist += entry->id();
0092     }
0093   }
0094 
0095   emit entriesSelected(m_selectedEntries);
0096   // for every selection model which did not call this function, clear the selection
0097   foreach(const QPointer<QItemSelectionModel>& ptr, m_modelList) { //krazy:exclude=foreach
0098     QItemSelectionModel* const otherModel = ptr.data();
0099     if(otherModel && otherModel != selectionModel) {
0100       otherModel->clearSelection();
0101     } else if(!otherModel) {
0102       // since the filter or loan view could be created multiple times
0103       // the selection model might be added multiple times
0104       // since foreach() creates a copy of the list, it's ok to remove this here
0105       m_modelList.removeOne(ptr);
0106     }
0107   }
0108   m_processing = false;
0109 }