File indexing completed on 2024-05-19 04:56:02
0001 /** 0002 * \file fileproxymodel.h 0003 * Proxy for filesystem model which filters files. 0004 * 0005 * \b Project: Kid3 0006 * \author Urs Fleisch 0007 * \date 22-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 <QSortFilterProxyModel> 0030 #include <QHash> 0031 #include <QSet> 0032 #include <QFileInfo> 0033 #include <QStringList> 0034 #include <QScopedPointer> 0035 #include "taggedfile.h" 0036 #include "kid3api.h" 0037 0038 class QTimer; 0039 class QFileInfo; 0040 class TaggedFileSystemModel; 0041 class CoreTaggedFileIconProvider; 0042 class ITaggedFileFactory; 0043 0044 /** 0045 * Proxy for filesystem model which filters files. 0046 */ 0047 class KID3_CORE_EXPORT FileProxyModel : public QSortFilterProxyModel { 0048 Q_OBJECT 0049 public: 0050 /** 0051 * Constructor. 0052 * 0053 * @param parent parent object 0054 */ 0055 explicit FileProxyModel(QObject* parent = nullptr); 0056 0057 /** 0058 * Destructor. 0059 */ 0060 ~FileProxyModel() override; 0061 0062 /** 0063 * Get item flags. 0064 * @param index index of item 0065 * @return default flags plus drag enabled depending on 0066 * setExclusiveDraggableIndex(). 0067 */ 0068 Qt::ItemFlags flags(const QModelIndex& index) const override; 0069 0070 /** 0071 * Set source model. 0072 * @param sourceModel source model, must be TaggedFileSystemModel 0073 */ 0074 void setSourceModel(QAbstractItemModel* sourceModel) override; 0075 0076 /** 0077 * Check if more data is available. 0078 * @param parent parent index of items to fetch 0079 * @return true if more data available. 0080 */ 0081 bool canFetchMore(const QModelIndex& parent) const override; 0082 0083 /** 0084 * Fetches any available data. 0085 * @param parent parent index of items to fetch 0086 */ 0087 void fetchMore(const QModelIndex& parent) override; 0088 0089 /** 0090 * Sort model. 0091 * 0092 * This method will directly call FileSystemModel::sort() on the 0093 * sourceModel() to take advantage of that specialized behavior. This 0094 * will change the order in the source model. 0095 * 0096 * @param column column to sort 0097 * @param order ascending or descending order 0098 */ 0099 void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override; 0100 0101 /** 0102 * Map role identifiers to role property names in scripting languages. 0103 * @return hash mapping role identifiers to names. 0104 */ 0105 QHash<int, QByteArray> roleNames() const override; 0106 0107 /** 0108 * Check if the model is currently loading a directory. 0109 * @return true if loading is in progress. 0110 */ 0111 bool isLoading() const { return m_isLoading; } 0112 0113 /** 0114 * Sets the name filters to apply against the existing files. 0115 * @param filters list of strings containing wildcards like "*.mp3" 0116 */ 0117 void setNameFilters(const QStringList& filters); 0118 0119 /** 0120 * Filter out a model index. 0121 * @param index source model index which has to be filtered out 0122 */ 0123 void filterOutIndex(const QPersistentModelIndex& index); 0124 0125 /** 0126 * Stop filtering out indexes. 0127 */ 0128 void disableFilteringOutIndexes(); 0129 0130 /** 0131 * Check if index filter is active. 0132 * @return true if indexes are filtered out 0133 */ 0134 bool isFilteringOutIndexes() const; 0135 0136 /** 0137 * Make filter changes active after adding indexes to be filtered out. 0138 */ 0139 void applyFilteringOutIndexes(); 0140 0141 /** 0142 * Set filters for included and excluded folders. 0143 * @param includeFolders wildcard expressions for folders to be included 0144 * @param excludeFolders wildcard expressions for folders to be excluded 0145 */ 0146 void setFolderFilters(const QStringList& includeFolders, 0147 const QStringList& excludeFolders); 0148 0149 /** 0150 * Get file information of model index. 0151 * @return file information 0152 */ 0153 QFileInfo fileInfo(const QModelIndex& index) const; 0154 0155 /** 0156 * Get file path of model index. 0157 * @return path to file or directory 0158 */ 0159 QString filePath(const QModelIndex& index) const; 0160 0161 /** 0162 * Get file name of model index. 0163 * @return name of file or directory 0164 */ 0165 QString fileName(const QModelIndex& index) const; 0166 0167 /** 0168 * Check if model index represents directory. 0169 * @return true if directory 0170 */ 0171 bool isDir(const QModelIndex& index) const; 0172 0173 /** 0174 * Delete file of index. 0175 * @return true if ok 0176 */ 0177 bool remove(const QModelIndex& index) const; 0178 0179 /** 0180 * Delete directory of index. 0181 * @return true if ok 0182 */ 0183 bool rmdir(const QModelIndex& index) const; 0184 0185 /** 0186 * Create a directory with @a name in the @a parent model index. 0187 * @return index of created directory. 0188 */ 0189 QModelIndex mkdir(const QModelIndex& parent, const QString& name) const; 0190 0191 /** 0192 * Rename file or directory of @a index to @a newName. 0193 * @return true if ok 0194 */ 0195 bool rename(const QModelIndex& index, const QString& newName); 0196 0197 /** 0198 * Get index for given path and column. 0199 * @param path path to file or directory 0200 * @param column model column 0201 * @return model index, invalid if not found. 0202 */ 0203 QModelIndex index(const QString& path, int column = 0) const; 0204 0205 using QSortFilterProxyModel::index; 0206 0207 /** 0208 * Count items in model. 0209 * @param rootIndex index of root item 0210 * @param folderCount the folder count is returned here 0211 * @param fileCount the file count is returned here 0212 */ 0213 void countItems(const QModelIndex& rootIndex, 0214 int& folderCount, int& fileCount) const; 0215 0216 /** 0217 * Check if any file has been modified. 0218 * @return true if at least one of the files in the model has been modified. 0219 */ 0220 bool isModified() const { return m_numModifiedFiles > 0; } 0221 0222 /** 0223 * Set index of item which shall be the only item which can be dragged. 0224 * This can be used to retain the selection while dragging a single item, 0225 * e.g. a picture to be embedded. 0226 * @param index index of single item which is draggable 0227 */ 0228 void setExclusiveDraggableIndex(const QPersistentModelIndex& index) { 0229 m_exclusiveDraggableIndex = index; 0230 } 0231 0232 /** 0233 * Get icon provider. 0234 * @return icon provider. 0235 */ 0236 CoreTaggedFileIconProvider* getIconProvider() const; 0237 0238 /** 0239 * Access to tagged file factories. 0240 * @return reference to tagged file factories. 0241 */ 0242 static QList<ITaggedFileFactory*>& taggedFileFactories(); 0243 0244 /** 0245 * Get tagged file of model index. 0246 * 0247 * @param index model index 0248 * 0249 * @return tagged file, 0 is returned if the index does not contain a 0250 * TaggedFile or if has a TaggedFile which is null. 0251 */ 0252 static TaggedFile* getTaggedFileOfIndex(const QModelIndex& index); 0253 0254 /** 0255 * Get directory path if model index is of directory. 0256 * 0257 * @param index model index 0258 * 0259 * @return directory path, null if not directory 0260 */ 0261 static QString getPathIfIndexOfDir(const QModelIndex& index); 0262 0263 /** 0264 * Read tagged file with ID3v2.4.0. 0265 * 0266 * @param taggedFile tagged file 0267 * 0268 * @return tagged file (can be newly created tagged file). 0269 */ 0270 static TaggedFile* readWithId3V24(TaggedFile* taggedFile); 0271 0272 /** 0273 * Read tagged file with ID3v2.3.0. 0274 * 0275 * @param taggedFile tagged file 0276 * 0277 * @return tagged file (can be newly created tagged file). 0278 */ 0279 static TaggedFile* readWithId3V23(TaggedFile* taggedFile); 0280 0281 /** 0282 * Read file with ID3v2.4 if it has an ID3v2.4 or ID3v2.2 tag. 0283 * ID3v2.2 files are also read with ID3v2.4 because id3lib corrupts 0284 * images in ID3v2.2 tags. 0285 * 0286 * @param taggedFile tagged file 0287 * 0288 * @return tagged file (can be new TagLibFile). 0289 */ 0290 static TaggedFile* readWithId3V24IfId3V24(TaggedFile* taggedFile); 0291 0292 /** 0293 * Read tagged file with Ogg FLAC. 0294 * 0295 * @param taggedFile tagged file 0296 * 0297 * @return tagged file (can be newly created tagged file). 0298 */ 0299 static TaggedFile* readWithOggFlac(TaggedFile* taggedFile); 0300 0301 /** 0302 * Try to read Ogg file with invalid tag detail info as an Ogg FLAC file. 0303 * 0304 * @param taggedFile tagged file 0305 * 0306 * @return tagged file (can be new TagLibFile). 0307 */ 0308 static TaggedFile* readWithOggFlacIfInvalidOgg(TaggedFile* taggedFile); 0309 0310 /** 0311 * Call readTags() on tagged file. 0312 * Reread file with other metadata plugin if it is not supported by current 0313 * plugin. 0314 * 0315 * @param taggedFile tagged file 0316 * 0317 * @return tagged file (can be new TaggedFile). 0318 */ 0319 static TaggedFile* readTagsFromTaggedFile(TaggedFile* taggedFile); 0320 0321 /** 0322 * Create name-file pattern pairs for all supported types. 0323 * The order is the same as in createFilterString(). 0324 * 0325 * @return pairs containing name, pattern, e.g. ("MP3", "*.mp3"), ..., 0326 * ("All Files", "*"). 0327 */ 0328 static QList<QPair<QString, QString> > createNameFilters(); 0329 0330 signals: 0331 /** 0332 * Emitted after directory loading when sorting is probably finished. 0333 * This signal is not accurate, it will be emitted 100 ms after 0334 * directoryLoaded() because it is not known when sorting is really finished. 0335 */ 0336 void sortingFinished(); 0337 0338 /** 0339 * Emitted when the modification state of a file changes. 0340 * @param index model index 0341 * @param modified true if file is modified 0342 */ 0343 void fileModificationChanged(const QModelIndex& index, bool modified); 0344 0345 /** 0346 * Emitted when modification state changes. 0347 * @param modified true if any file has been modified 0348 * @see isModified() 0349 */ 0350 void modifiedChanged(bool modified); 0351 0352 protected slots: 0353 /** 0354 * Reset internal data of the model. 0355 * Is called from endResetModel(). 0356 */ 0357 #if QT_VERSION >= 0x060000 0358 void resetInternalData() override; 0359 #else 0360 void resetInternalData(); 0361 #endif 0362 0363 private slots: 0364 /** 0365 * Called when the source model emits fileModificationChanged(). 0366 * @param index model index 0367 * @param modified true if file is modified 0368 */ 0369 void onFileModificationChanged(const QModelIndex& srcIndex, bool modified); 0370 0371 /** 0372 * Called when the source model emits directoryLoaded(). 0373 */ 0374 void onDirectoryLoaded(); 0375 0376 /** 0377 * Emit sortingFinished(). 0378 */ 0379 void emitSortingFinished(); 0380 0381 /** 0382 * Called when loading the directory starts. 0383 */ 0384 void onStartLoading(); 0385 0386 protected: 0387 /** 0388 * Check if row should be included in model. 0389 * 0390 * @param srcRow source row 0391 * @param srcParent source parent 0392 * 0393 * @return true to include row. 0394 */ 0395 bool filterAcceptsRow(int srcRow, const QModelIndex& srcParent) const override; 0396 0397 private: 0398 /** 0399 * Check if a directory path passes the include folder filters. 0400 * @param dirPath absolute path to directory 0401 * @return true if path passes filters. 0402 */ 0403 bool passesIncludeFolderFilters(const QString& dirPath) const; 0404 0405 /** 0406 * Check if a directory path passes the exclude folder filters. 0407 * @param dirPath absolute path to directory 0408 * @return true if path passes filters. 0409 */ 0410 bool passesExcludeFolderFilters(const QString& dirPath) const; 0411 0412 QSet<QPersistentModelIndex> m_filteredOut; 0413 QPersistentModelIndex m_exclusiveDraggableIndex; 0414 QList<QRegularExpression> m_includeFolderFilters; 0415 QList<QRegularExpression> m_excludeFolderFilters; 0416 TaggedFileSystemModel* m_fsModel; 0417 QTimer* m_loadTimer; 0418 QTimer* m_sortTimer; 0419 QStringList m_extensions; 0420 unsigned int m_numModifiedFiles; 0421 bool m_isLoading; 0422 };