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

0001 /**
0002  * \file bidirfileproxymodeliterator.cpp
0003  * Birdirectional iterator for FileProxyModel.
0004  *
0005  * \b Project: Kid3
0006  * \author Urs Fleisch
0007  * \date 21-Feb-2014
0008  *
0009  * Copyright (C) 2014-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 "bidirfileproxymodeliterator.h"
0028 #include <QTimer>
0029 #include "fileproxymodel.h"
0030 
0031 /**
0032  * Constructor.
0033  *
0034  * @param model file proxy model
0035  * @param parent parent object
0036  */
0037 BiDirFileProxyModelIterator::BiDirFileProxyModelIterator(FileProxyModel* model,
0038                                                          QObject *parent)
0039   : QObject(parent), m_model(model), m_backwards(false),
0040     m_aborted(false), m_suspended(false)
0041 {
0042 }
0043 
0044 /**
0045  * Abort operation.
0046  */
0047 void BiDirFileProxyModelIterator::abort()
0048 {
0049   m_aborted = true;
0050 }
0051 
0052 /**
0053  * Check if operation is aborted.
0054  *
0055  * @return true if aborted.
0056  */
0057 bool BiDirFileProxyModelIterator::isAborted() const
0058 {
0059   return m_aborted;
0060 }
0061 
0062 /**
0063  * Clear state which is reported by isAborted().
0064  */
0065 void BiDirFileProxyModelIterator::clearAborted()
0066 {
0067   m_aborted = false;
0068 }
0069 
0070 /**
0071  * Set root index of file proxy model.
0072  *
0073  * @param rootIdx index of root element
0074  */
0075 void BiDirFileProxyModelIterator::setRootIndex(
0076     const QPersistentModelIndex& rootIdx)
0077 {
0078   m_rootIndex = rootIdx;
0079 }
0080 
0081 /**
0082  * Set index of current file.
0083  *
0084  * @param index index of current file
0085  */
0086 void BiDirFileProxyModelIterator::setCurrentIndex(
0087     const QPersistentModelIndex& index)
0088 {
0089   m_currentIndex = index;
0090 }
0091 
0092 /**
0093  * Start iteration.
0094  */
0095 void BiDirFileProxyModelIterator::start()
0096 {
0097   m_aborted = false;
0098   m_suspended = false;
0099   if (m_currentIndex.isValid()) {
0100     emit nextReady(m_currentIndex);
0101   }
0102   fetchNext();
0103 }
0104 
0105 /**
0106  * Fetch next index.
0107  */
0108 void BiDirFileProxyModelIterator::fetchNext()
0109 {
0110   int count = 0;
0111   while (!m_aborted) {
0112     if (m_suspended) {
0113       return;
0114     }
0115     QModelIndex next;
0116     if (!m_backwards) {
0117       if (!m_currentIndex.isValid()) {
0118         m_currentIndex = m_rootIndex;
0119       }
0120       if (m_model->rowCount(m_currentIndex) > 0) {
0121         // to first child
0122         next = m_model->index(0, 0, m_currentIndex);
0123       } else {
0124         QModelIndex parent = m_currentIndex;
0125         while (!next.isValid() && parent.isValid()) {
0126           // to next sibling or next sibling of parent
0127           int row = parent.row();
0128           if (parent == m_rootIndex) {
0129             // do not move beyond root index
0130             break;
0131           }
0132           parent = parent.parent();
0133           if (row + 1 < m_model->rowCount(parent)) {
0134             // to next sibling
0135             next = m_model->index(row + 1, 0, parent);
0136           }
0137         }
0138       }
0139     } else {
0140       if (m_currentIndex.isValid()) {
0141         if (int row = m_currentIndex.row() - 1; row >= 0) {
0142           // to last leafnode of previous sibling
0143           next = m_currentIndex.sibling(row, 0);
0144           row = m_model->rowCount(next) - 1;
0145           while (row >= 0) {
0146             next = m_model->index(row, 0, next);
0147             row = m_model->rowCount(next) - 1;
0148           }
0149         } else {
0150           // to parent
0151           next = m_currentIndex.parent();
0152         }
0153         if (next == m_rootIndex)
0154           next = QPersistentModelIndex();
0155       } else {
0156         // to last node
0157         int row;
0158         QModelIndex last = m_rootIndex;
0159         while ((row = m_model->rowCount(last)) > 0 &&
0160                (last = m_model->index(row - 1, 0, last)).isValid()) {
0161           next = last;
0162         }
0163       }
0164     }
0165     if (next.isValid()) {
0166       if (m_model->isDir(next) && m_model->canFetchMore(next)) {
0167         connect(m_model, &FileProxyModel::sortingFinished,
0168                 this, &BiDirFileProxyModelIterator::onDirectoryLoaded);
0169         m_model->fetchMore(next);
0170         return;
0171       }
0172       if (++count >= 10) {
0173         // Avoid spinning too long to keep the GUI responsive.
0174         QTimer::singleShot(0, this, &BiDirFileProxyModelIterator::fetchNext);
0175         return;
0176       }
0177       m_currentIndex = next;
0178       emit nextReady(m_currentIndex);
0179     } else {
0180       break;
0181     }
0182   }
0183   m_currentIndex = QPersistentModelIndex();
0184   emit nextReady(m_currentIndex);
0185 }
0186 
0187 /**
0188  * Called when the gatherer thread has finished to load.
0189  */
0190 void BiDirFileProxyModelIterator::onDirectoryLoaded()
0191 {
0192   disconnect(m_model, &FileProxyModel::sortingFinished,
0193              this, &BiDirFileProxyModelIterator::onDirectoryLoaded);
0194   fetchNext();
0195 }
0196 
0197 /**
0198  * Suspend iteration.
0199  * The iteration can be continued with resume().
0200  */
0201 void BiDirFileProxyModelIterator::suspend()
0202 {
0203   m_suspended = true;
0204 }
0205 
0206 /**
0207  * Resume iteration which has been suspended with suspend().
0208  */
0209 void BiDirFileProxyModelIterator::resume()
0210 {
0211   m_suspended = false;
0212   fetchNext();
0213 }