File indexing completed on 2024-05-19 04:56:07
0001 /** 0002 * \file modeliterator.h 0003 * Iterator for Qt models. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 26-Mar-2011 0008 * 0009 * Copyright (C) 2011-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 #pragma once 0028 0029 #include <QPersistentModelIndex> 0030 #include <QStack> 0031 #include <QQueue> 0032 #include "kid3api.h" 0033 0034 class QItemSelectionModel; 0035 class TaggedFile; 0036 class FileProxyModel; 0037 0038 /** 0039 * Generic Java-style iterator for Qt models. 0040 * Iterates using preorder traversal. Supports only one column. 0041 * 0042 * Typical usage: 0043 * @code 0044 * // get rootIndex... 0045 * ModelIterator it(rootIndex); 0046 * while (it.hasNext()) { 0047 * TaggedFile* taggedFile; 0048 * if (ModelIterator::getTaggedFileOfIndex(it.peekNext(), &taggedFile) 0049 * && taggedFile) { 0050 * // do something with taggedFile... 0051 * } 0052 * it.next(); 0053 * } 0054 * @endcode 0055 */ 0056 class ModelIterator { 0057 public: 0058 /** 0059 * Constructor. 0060 * 0061 * @param rootIdx root of model to iterate 0062 */ 0063 explicit ModelIterator(const QPersistentModelIndex& rootIdx); 0064 0065 /** 0066 * Check if a next item exists. 0067 * @return true if there is a next index 0068 */ 0069 bool hasNext() const; 0070 0071 /** 0072 * Advance iterator and return next item. 0073 * @return next index 0074 */ 0075 QPersistentModelIndex next(); 0076 0077 /** 0078 * Get next item without moving iterator. 0079 * @return next index 0080 */ 0081 QPersistentModelIndex peekNext() const; 0082 0083 /** 0084 * Advance iterator and return data of next index. 0085 * @param role model item role to get 0086 * @return data of next index 0087 */ 0088 QVariant nextData(int role); 0089 0090 /** 0091 * Get data of next item without moving iterator. 0092 * @param role model item role to get 0093 * @return data of next index 0094 */ 0095 QVariant peekNextData(int role) const; 0096 0097 private: 0098 QStack<QPersistentModelIndex> m_nodes; 0099 const QAbstractItemModel* m_model; 0100 QPersistentModelIndex m_nextIdx; 0101 }; 0102 0103 /** 0104 * Generic Java-style iterator for Qt models. 0105 * Iterates using breadth-first-search. Supports only one column. 0106 */ 0107 class ModelBfsIterator { 0108 public: 0109 /** 0110 * Constructor. 0111 * 0112 * @param rootIdx root of model to iterate 0113 */ 0114 explicit ModelBfsIterator(const QPersistentModelIndex& rootIdx); 0115 0116 /** 0117 * Check if a next item exists. 0118 * @return true if there is a next index 0119 */ 0120 bool hasNext() const; 0121 0122 /** 0123 * Advance iterator and return next item. 0124 * @return next index 0125 */ 0126 QPersistentModelIndex next(); 0127 0128 /** 0129 * Get next item without moving iterator. 0130 * @return next index 0131 */ 0132 QPersistentModelIndex peekNext() const; 0133 0134 /** 0135 * Advance iterator and return data of next index. 0136 * @param role model item role to get 0137 * @return data of next index 0138 */ 0139 QVariant nextData(int role); 0140 0141 /** 0142 * Get data of next item without moving iterator. 0143 * @param role model item role to get 0144 * @return data of next index 0145 */ 0146 QVariant peekNextData(int role) const; 0147 0148 private: 0149 QQueue<QPersistentModelIndex> m_nodes; 0150 const QAbstractItemModel* m_model; 0151 QPersistentModelIndex m_nextIdx; 0152 QPersistentModelIndex m_parentIdx; 0153 int m_row; 0154 }; 0155 0156 /** 0157 * Abstract base class for tagged file iterators. 0158 */ 0159 class KID3_CORE_EXPORT AbstractTaggedFileIterator { 0160 public: 0161 /** 0162 * Destructor. 0163 */ 0164 virtual ~AbstractTaggedFileIterator(); 0165 0166 /** 0167 * Check if a next item exists. 0168 * @return true if there is a next file 0169 */ 0170 virtual bool hasNext() const = 0; 0171 0172 /** 0173 * Advance iterator and return next item. 0174 * @return next file 0175 */ 0176 virtual TaggedFile* next() = 0; 0177 0178 /** 0179 * Get next item without moving iterator. 0180 * @return next file 0181 */ 0182 virtual TaggedFile* peekNext() const = 0; 0183 }; 0184 0185 /** 0186 * Iterator to iterate over model indexes with tagged files. 0187 * All TaggedFiles returned while hasNext() is true are not null. 0188 * 0189 * Typical usage: 0190 * @code 0191 * // get rootIndex... 0192 * TaggedFileIterator it(rootIndex); 0193 * while (it.hasNext()) { 0194 * TaggedFile* taggedFile = it.next(); 0195 * // do something with taggedFile... 0196 * } 0197 * @endcode 0198 */ 0199 class KID3_CORE_EXPORT TaggedFileIterator : public AbstractTaggedFileIterator { 0200 public: 0201 /** 0202 * Constructor. 0203 * 0204 * @param rootIdx root of model to iterate 0205 */ 0206 explicit TaggedFileIterator(const QPersistentModelIndex& rootIdx); 0207 0208 /** 0209 * Check if a next item exists. 0210 * @return true if there is a next file 0211 */ 0212 bool hasNext() const override { return m_nextFile != nullptr; } 0213 0214 /** 0215 * Advance iterator and return next item. 0216 * @return next file 0217 */ 0218 TaggedFile* next() override; 0219 0220 /** 0221 * Get next item without moving iterator. 0222 * @return next file 0223 */ 0224 TaggedFile* peekNext() const override { return m_nextFile; } 0225 0226 /** 0227 * Try to close the file handles. 0228 * 0229 * @param index root of model to iterate 0230 */ 0231 static void closeFileHandles(const QPersistentModelIndex& index); 0232 0233 private: 0234 ModelIterator m_it; 0235 TaggedFile* m_nextFile; 0236 }; 0237 0238 /** 0239 * Iterator to iterate over model indexes with selected tagged files. 0240 * All TaggedFiles returned while hasNext() is true are not null. 0241 * 0242 * Typical usage: 0243 * @code 0244 * // get rootIndex, selectionModel... 0245 * SelectedTaggedFileIterator it(rootIndex, selectionModel, false); 0246 * while (it.hasNext()) { 0247 * TaggedFile* taggedFile = it.next(); 0248 * // do something with taggedFile... 0249 * } 0250 * @endcode 0251 */ 0252 class SelectedTaggedFileIterator : public AbstractTaggedFileIterator { 0253 public: 0254 /** 0255 * Constructor. 0256 * 0257 * @param rootIdx root of model to iterate 0258 * @param selectModel selection model 0259 * @param allIfNoneSelected treat all files as selected when nothing is 0260 * selected 0261 */ 0262 SelectedTaggedFileIterator(const QPersistentModelIndex& rootIdx, 0263 const QItemSelectionModel* selectModel, 0264 bool allIfNoneSelected); 0265 0266 /** 0267 * Check if a next item exists. 0268 * @return true if there is a next file 0269 */ 0270 bool hasNext() const override { return m_nextFile != nullptr; } 0271 0272 /** 0273 * Advance iterator and return next item. 0274 * @return next file 0275 */ 0276 TaggedFile* next() override; 0277 0278 /** 0279 * Get next item without moving iterator. 0280 * @return next file 0281 */ 0282 TaggedFile* peekNext() const override { return m_nextFile; } 0283 0284 /** 0285 * Check if nothing is selected. 0286 * @return true if nothing is selected. 0287 */ 0288 bool hasNoSelection() const; 0289 0290 private: 0291 ModelIterator m_it; 0292 TaggedFile* m_nextFile; 0293 const QItemSelectionModel* m_selectModel; 0294 bool m_allSelected; 0295 }; 0296 0297 /** 0298 * Iterator to iterate tagged files from a single directory. 0299 * All TaggedFiles returned while hasNext() is true are not null. 0300 * 0301 * Typical usage: 0302 * @code 0303 * // get currentIndex... 0304 * TaggedFileOfDirectoryIterator it(currentIndex); 0305 * while (it.hasNext()) { 0306 * TaggedFile* taggedFile = it.next(); 0307 * // do something with taggedFile... 0308 * } 0309 * @endcode 0310 */ 0311 class KID3_CORE_EXPORT TaggedFileOfDirectoryIterator : public AbstractTaggedFileIterator { 0312 public: 0313 /** 0314 * Constructor. 0315 * 0316 * @param index of the directory or a file in it 0317 */ 0318 explicit TaggedFileOfDirectoryIterator(const QPersistentModelIndex& index); 0319 0320 /** 0321 * Check if a next item exists. 0322 * @return true if there is a next file 0323 */ 0324 bool hasNext() const override; 0325 0326 /** 0327 * Advance iterator and return next item. 0328 * @return next file 0329 */ 0330 TaggedFile* next() override; 0331 0332 /** 0333 * Get next item without moving iterator. 0334 * @return next file 0335 */ 0336 TaggedFile* peekNext() const override; 0337 0338 /** 0339 * Get first tagged file in directory. 0340 * @param index of the directory or a file in it 0341 * @return first tagged file in directory, 0 if none. 0342 */ 0343 static TaggedFile* first(const QPersistentModelIndex& index); 0344 0345 private: 0346 int m_row; 0347 const QAbstractItemModel* m_model; 0348 QPersistentModelIndex m_parentIdx; 0349 TaggedFile* m_nextFile; 0350 }; 0351 0352 /** 0353 * Iterator to iterate selected tagged files from a single directory. 0354 * All TaggedFiles returned while hasNext() is true are not null. 0355 * 0356 * Typical usage: 0357 * @code 0358 * // get currentIndex, selectionModel... 0359 * SelectedTaggedFileOfDirectoryIterator it(currentIndex, selectionModel, false); 0360 * while (it.hasNext()) { 0361 * TaggedFile* taggedFile = it.next(); 0362 * // do something with taggedFile... 0363 * } 0364 * @endcode 0365 */ 0366 class SelectedTaggedFileOfDirectoryIterator 0367 : public AbstractTaggedFileIterator { 0368 public: 0369 /** 0370 * Constructor. 0371 * 0372 * @param index of the directory or a file in it 0373 * @param selectModel selection model 0374 * @param allIfNoneSelected treat all files as selected when nothing is 0375 * selected 0376 */ 0377 SelectedTaggedFileOfDirectoryIterator( 0378 const QPersistentModelIndex& index, 0379 const QItemSelectionModel* selectModel, 0380 bool allIfNoneSelected); 0381 0382 /** 0383 * Check if a next item exists. 0384 * @return true if there is a next file 0385 */ 0386 bool hasNext() const override; 0387 0388 /** 0389 * Advance iterator and return next item. 0390 * @return next file 0391 */ 0392 TaggedFile* next() override; 0393 0394 /** 0395 * Get next item without moving iterator. 0396 * @return next file 0397 */ 0398 TaggedFile* peekNext() const override; 0399 0400 private: 0401 int m_row; 0402 const QAbstractItemModel* m_model; 0403 QPersistentModelIndex m_parentIdx; 0404 TaggedFile* m_nextFile; 0405 const QItemSelectionModel* m_selectModel; 0406 bool m_allSelected; 0407 }; 0408 0409 /** 0410 * Iterator to iterate all tagged files from selected directories. 0411 * All TaggedFiles returned while hasNext() is true are not null. 0412 * 0413 * Typical usage: 0414 * @code 0415 * // get selectionModel... 0416 * TaggedFileOfSelectedDirectoriesIterator it(selectionModel); 0417 * while (it.hasNext()) { 0418 * TaggedFile* taggedFile = it.next(); 0419 * // do something with taggedFile... 0420 * } 0421 * @endcode 0422 */ 0423 class TaggedFileOfSelectedDirectoriesIterator 0424 : public AbstractTaggedFileIterator { 0425 public: 0426 /** 0427 * Constructor. 0428 * 0429 * @param selectModel selection model 0430 */ 0431 explicit TaggedFileOfSelectedDirectoriesIterator( 0432 const QItemSelectionModel* selectModel); 0433 0434 /** 0435 * Check if a next item exists. 0436 * @return true if there is a next file 0437 */ 0438 bool hasNext() const override; 0439 0440 /** 0441 * Advance iterator and return next item. 0442 * @return next file 0443 */ 0444 TaggedFile* next() override; 0445 0446 /** 0447 * Get next item without moving iterator. 0448 * @return next file 0449 */ 0450 TaggedFile* peekNext() const override; 0451 0452 private: 0453 /** 0454 * Get indexes of directory and recursively all subdirectories. 0455 * @param dirIndex index of directory 0456 * @return list with dirIndex and its subdirectories. 0457 */ 0458 QList<QPersistentModelIndex> getIndexesOfDirWithSubDirs( 0459 const QModelIndex& dirIndex) const; 0460 0461 const FileProxyModel* m_model; 0462 QList<QPersistentModelIndex> m_dirIndexes; 0463 int m_dirIdx; 0464 int m_row; 0465 TaggedFile* m_nextFile; 0466 };