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

0001 /**
0002  * \file fileproxymodeliterator.cpp
0003  * Iterator for FileProxyModel.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 03-Feb-2013
0008  *
0009  * Copyright (C) 2013-2024  Urs Fleisch
0010  *
0011  * This file is part of Kid3.
0012  *
0013  * Kid3 is free software; you can redistribute it and/or modify
0014  * it under the terms of the GNU General Public License as published by
0015  * the Free Software Foundation; either version 2 of the License, or
0016  * (at your option) any later version.
0017  *
0018  * Kid3 is distributed in the hope that it will be useful,
0019  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0020  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0021  * GNU General Public License for more details.
0022  *
0023  * You should have received a copy of the GNU General Public License
0024  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
0025  */
0026 
0027 #include "fileproxymodeliterator.h"
0028 #include <QTimer>
0029 #include "fileproxymodel.h"
0030 
0031 /**
0032  * Constructor.
0033  *
0034  * @param model file proxy model
0035  */
0036 FileProxyModelIterator::FileProxyModelIterator(FileProxyModel* model)
0037   : QObject(model), m_model(model), m_numDone(0), m_aborted(false)
0038 {
0039 }
0040 
0041 /**
0042  * Abort operation.
0043  */
0044 void FileProxyModelIterator::abort()
0045 {
0046   m_aborted = true;
0047 }
0048 
0049 /**
0050  * Check if operation is aborted.
0051  *
0052  * @return true if aborted.
0053  */
0054 bool FileProxyModelIterator::isAborted() const
0055 {
0056   return m_aborted;
0057 }
0058 
0059 /**
0060  * Clear state which is reported by isAborted().
0061  */
0062 void FileProxyModelIterator::clearAborted()
0063 {
0064   m_aborted = false;
0065 }
0066 
0067 /**
0068  * Start iteration.
0069  *
0070  * @param rootIdx index of root element
0071  */
0072 void FileProxyModelIterator::start(const QPersistentModelIndex& rootIdx)
0073 {
0074   m_nodes.clear();
0075   m_rootIndexes.clear();
0076   m_rootIndexes.append(rootIdx);
0077   m_numDone = 0;
0078   m_aborted = false;
0079   fetchNext();
0080 }
0081 
0082 /**
0083  * Start iteration.
0084  *
0085  * @param indexes indexes of root directories
0086  */
0087 void FileProxyModelIterator::start(const QList<QPersistentModelIndex>& indexes)
0088 {
0089   m_nodes.clear();
0090   m_rootIndexes = indexes;
0091   m_numDone = 0;
0092   m_aborted = false;
0093   fetchNext();
0094 }
0095 
0096 /**
0097  * Fetch next index.
0098  */
0099 void FileProxyModelIterator::fetchNext()
0100 {
0101   int count = 0;
0102   while (!m_aborted) {
0103     if (m_nodes.isEmpty()) {
0104       if (m_rootIndexes.isEmpty()) {
0105         break;
0106       }
0107       m_nodes.push(m_rootIndexes.takeFirst());
0108     }
0109     m_nextIdx = m_nodes.top();
0110     if (m_nextIdx.isValid()) {
0111       if (m_model->isDir(m_nextIdx) && m_model->canFetchMore(m_nextIdx)) {
0112         connect(m_model, &FileProxyModel::sortingFinished,
0113                 this, &FileProxyModelIterator::onDirectoryLoaded);
0114         m_model->fetchMore(m_nextIdx);
0115         return;
0116       }
0117       if (++count >= 10) {
0118         // Avoid spinning too long to keep the GUI responsive.
0119         QTimer::singleShot(0, this, &FileProxyModelIterator::fetchNext);
0120         return;
0121       }
0122       m_nodes.pop();
0123       ++m_numDone;
0124       const int numRows = m_model->rowCount(m_nextIdx);
0125       QStack<QPersistentModelIndex> childNodes;
0126       childNodes.reserve(numRows);
0127       for (int row = numRows - 1; row >= 0; --row) {
0128         childNodes.push(m_model->index(row, 0, m_nextIdx));
0129       }
0130       std::stable_sort(childNodes.begin(), childNodes.end(),
0131                   [](const QPersistentModelIndex& lhs,
0132                      const QPersistentModelIndex& rhs) {
0133         return lhs.data().toString().compare(rhs.data().toString()) > 0;
0134       });
0135       m_nodes += childNodes;
0136       emit nextReady(m_nextIdx);
0137     } else {
0138       m_nodes.pop();
0139     }
0140   }
0141   m_nodes.clear();
0142   m_rootIndexes.clear();
0143   m_nextIdx = QPersistentModelIndex();
0144   emit nextReady(m_nextIdx);
0145 }
0146 
0147 /**
0148  * Called when the gatherer thread has finished to load.
0149  */
0150 void FileProxyModelIterator::onDirectoryLoaded()
0151 {
0152   disconnect(m_model, &FileProxyModel::sortingFinished,
0153              this, &FileProxyModelIterator::onDirectoryLoaded);
0154   fetchNext();
0155 }