File indexing completed on 2024-05-19 04:56:03
0001 /** 0002 * \file filesystemmodel_p.h 0003 * \cond 0004 * Taken from Qt Git, revision e73bd4a 0005 * qtbase/src/widgets/dialogs/qfilesystemmodel_p.h 0006 * Adapted for Kid3 with the following changes: 0007 * - Remove Q prefix from class names 0008 * - Remove QT_..._CONFIG, QT_..._NAMESPACE, Q_..._EXPORT... 0009 * - Allow compilation without Qt private headers (USE_QT_PRIVATE_HEADERS) 0010 * - Allow compilation with Qt versions < 5.7 0011 * - Replace include guards by #pragma once 0012 * - Remove dependencies to Qt5::Widgets 0013 */ 0014 /**************************************************************************** 0015 ** 0016 ** Copyright (C) 2016 The Qt Company Ltd. 0017 ** Contact: https://www.qt.io/licensing/ 0018 ** 0019 ** This file is part of the QtWidgets module of the Qt Toolkit. 0020 ** 0021 ** $QT_BEGIN_LICENSE:LGPL$ 0022 ** Commercial License Usage 0023 ** Licensees holding valid commercial Qt licenses may use this file in 0024 ** accordance with the commercial license agreement provided with the 0025 ** Software or, alternatively, in accordance with the terms contained in 0026 ** a written agreement between you and The Qt Company. For licensing terms 0027 ** and conditions see https://www.qt.io/terms-conditions. For further 0028 ** information use the contact form at https://www.qt.io/contact-us. 0029 ** 0030 ** GNU Lesser General Public License Usage 0031 ** Alternatively, this file may be used under the terms of the GNU Lesser 0032 ** General Public License version 3 as published by the Free Software 0033 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 0034 ** packaging of this file. Please review the following information to 0035 ** ensure the GNU Lesser General Public License version 3 requirements 0036 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 0037 ** 0038 ** GNU General Public License Usage 0039 ** Alternatively, this file may be used under the terms of the GNU 0040 ** General Public License version 2.0 or (at your option) the GNU General 0041 ** Public license version 3 or any later version approved by the KDE Free 0042 ** Qt Foundation. The licenses are as published by the Free Software 0043 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 0044 ** included in the packaging of this file. Please review the following 0045 ** information to ensure the GNU General Public License requirements will 0046 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 0047 ** https://www.gnu.org/licenses/gpl-3.0.html. 0048 ** 0049 ** $QT_END_LICENSE$ 0050 ** 0051 ****************************************************************************/ 0052 0053 #pragma once 0054 0055 // 0056 // W A R N I N G 0057 // ------------- 0058 // 0059 // This file is not part of the Qt API. It exists purely as an 0060 // implementation detail. This header file may change from version to 0061 // version without notice, or even be removed. 0062 // 0063 // We mean it. 0064 // 0065 0066 #ifdef USE_QT_PRIVATE_HEADERS 0067 #include <private/qabstractitemmodel_p.h> 0068 #endif 0069 #include <qabstractitemmodel.h> 0070 #include "filesystemmodel.h" 0071 #include "fileinfogatherer_p.h" 0072 #include <qpair.h> 0073 #include <qdir.h> 0074 #include <qfileinfo.h> 0075 #include <qtimer.h> 0076 #include <qhash.h> 0077 #include "abstractfiledecorationprovider.h" 0078 0079 class ExtendedInformation; 0080 class FileSystemModelPrivate; 0081 class AbstractFileDecorationProvider; 0082 0083 #if defined(Q_OS_WIN) 0084 class FileSystemModelNodePathKey : public QString 0085 { 0086 public: 0087 FileSystemModelNodePathKey() {} 0088 FileSystemModelNodePathKey(const QString &other) : QString(other) {} 0089 FileSystemModelNodePathKey(const FileSystemModelNodePathKey &other) : QString(other) {} 0090 bool operator==(const FileSystemModelNodePathKey &other) const { return !compare(other, Qt::CaseInsensitive); } 0091 }; 0092 0093 Q_DECLARE_TYPEINFO(FileSystemModelNodePathKey, Q_MOVABLE_TYPE); 0094 0095 inline uint qHash(const FileSystemModelNodePathKey &key) { return qHash(key.toCaseFolded()); } 0096 #else // Q_OS_WIN 0097 typedef QString FileSystemModelNodePathKey; 0098 #endif 0099 0100 #ifdef USE_QT_PRIVATE_HEADERS 0101 class FileSystemModelPrivate : public QAbstractItemModelPrivate 0102 #else 0103 class FileSystemModelPrivate 0104 #endif 0105 { 0106 Q_DECLARE_PUBLIC(FileSystemModel) 0107 0108 public: 0109 enum { NumColumns = 4 }; 0110 0111 class FileSystemNode 0112 { 0113 public: 0114 explicit FileSystemNode(const QString &filename = QString(), FileSystemNode *p = 0) 0115 : fileName(filename), populatedChildren(false), isVisible(false), dirtyChildrenIndex(-1), parent(p), info(0) {} 0116 ~FileSystemNode() { 0117 qDeleteAll(children); 0118 delete info; 0119 info = 0; 0120 parent = 0; 0121 } 0122 void clear() { 0123 fileName.clear(); 0124 populatedChildren = false; 0125 isVisible = false; 0126 qDeleteAll(children); 0127 children.clear(); 0128 visibleChildren.clear(); 0129 dirtyChildrenIndex = -1; 0130 parent = Q_NULLPTR; 0131 delete info; 0132 info = Q_NULLPTR; 0133 } 0134 0135 QString fileName; 0136 #if defined(Q_OS_WIN) 0137 QString volumeName; 0138 #endif 0139 0140 inline qint64 size() const { if (info && !info->isDir()) return info->size(); return 0; } 0141 inline QString type() const { if (info) return info->displayType; return QLatin1String(""); } 0142 inline QDateTime lastModified() const { if (info) return info->lastModified(); return QDateTime(); } 0143 inline QFile::Permissions permissions() const { if (info) return info->permissions(); return {}; } 0144 inline bool isReadable() const { return ((permissions() & QFile::ReadUser) != 0); } 0145 inline bool isWritable() const { return ((permissions() & QFile::WriteUser) != 0); } 0146 inline bool isExecutable() const { return ((permissions() & QFile::ExeUser) != 0); } 0147 inline bool isDir() const { 0148 if (info) 0149 return info->isDir(); 0150 if (children.count() > 0) 0151 return true; 0152 return false; 0153 } 0154 inline QFileInfo fileInfo() const { if (info) return info->fileInfo(); return QFileInfo(); } 0155 inline bool isFile() const { if (info) return info->isFile(); return true; } 0156 inline bool isSystem() const { if (info) return info->isSystem(); return true; } 0157 inline bool isHidden() const { if (info) return info->isHidden(); return false; } 0158 inline bool isSymLink(bool ignoreNtfsSymLinks = false) const { return info && info->isSymLink(ignoreNtfsSymLinks); } 0159 inline bool caseSensitive() const { if (info) return info->isCaseSensitive(); return false; } 0160 inline QVariant icon() const { if (info) return info->icon; return QVariant(); } 0161 0162 inline bool operator <(const FileSystemNode &node) const { 0163 if (caseSensitive() || node.caseSensitive()) 0164 return fileName < node.fileName; 0165 return QString::compare(fileName, node.fileName, Qt::CaseInsensitive) < 0; 0166 } 0167 inline bool operator >(const QString &name) const { 0168 if (caseSensitive()) 0169 return fileName > name; 0170 return QString::compare(fileName, name, Qt::CaseInsensitive) > 0; 0171 } 0172 inline bool operator <(const QString &name) const { 0173 if (caseSensitive()) 0174 return fileName < name; 0175 return QString::compare(fileName, name, Qt::CaseInsensitive) < 0; 0176 } 0177 inline bool operator !=(const ExtendedInformation &fileInfo) const { 0178 return !operator==(fileInfo); 0179 } 0180 bool operator ==(const QString &name) const { 0181 if (caseSensitive()) 0182 return fileName == name; 0183 return QString::compare(fileName, name, Qt::CaseInsensitive) == 0; 0184 } 0185 bool operator ==(const ExtendedInformation &fileInfo) const { 0186 return info && (*info == fileInfo); 0187 } 0188 0189 inline bool hasInformation() const { return info != 0; } 0190 0191 void populate(const ExtendedInformation &fileInfo) { 0192 if (!info) 0193 info = new ExtendedInformation(fileInfo.fileInfo()); 0194 (*info) = fileInfo; 0195 } 0196 0197 // children shouldn't normally be accessed directly, use node() 0198 inline int visibleLocation(const QString &childName) { 0199 return visibleChildren.indexOf(childName); 0200 } 0201 void updateIcon(AbstractFileDecorationProvider *iconProvider, const QString &path) { 0202 if (!iconProvider) 0203 return; 0204 if (info) 0205 info->icon = iconProvider->decoration(QFileInfo(path)); 0206 #if QT_VERSION >= 0x050700 0207 for (FileSystemNode *child : qAsConst(children)) { 0208 #else 0209 const auto constChildren = children; 0210 for (FileSystemNode *child : constChildren) { 0211 #endif 0212 //On windows the root (My computer) has no path so we don't want to add a / for nothing (e.g. /C:/) 0213 if (!path.isEmpty()) { 0214 if (path.endsWith(QLatin1Char('/'))) 0215 child->updateIcon(iconProvider, path + child->fileName); 0216 else 0217 child->updateIcon(iconProvider, path + QLatin1Char('/') + child->fileName); 0218 } else 0219 child->updateIcon(iconProvider, child->fileName); 0220 } 0221 } 0222 0223 void retranslateStrings(AbstractFileDecorationProvider *iconProvider, const QString &path) { 0224 if (!iconProvider) 0225 return; 0226 if (info) 0227 info->displayType = iconProvider->type(QFileInfo(path)); 0228 #if QT_VERSION >= 0x050700 0229 for (FileSystemNode *child : qAsConst(children)) { 0230 #else 0231 const auto constChildren = children; 0232 for (FileSystemNode *child : constChildren) { 0233 #endif 0234 //On windows the root (My computer) has no path so we don't want to add a / for nothing (e.g. /C:/) 0235 if (!path.isEmpty()) { 0236 if (path.endsWith(QLatin1Char('/'))) 0237 child->retranslateStrings(iconProvider, path + child->fileName); 0238 else 0239 child->retranslateStrings(iconProvider, path + QLatin1Char('/') + child->fileName); 0240 } else 0241 child->retranslateStrings(iconProvider, child->fileName); 0242 } 0243 } 0244 0245 bool populatedChildren; 0246 bool isVisible; 0247 QHash<FileSystemModelNodePathKey, FileSystemNode *> children; 0248 QList<QString> visibleChildren; 0249 int dirtyChildrenIndex; 0250 FileSystemNode *parent; 0251 0252 0253 ExtendedInformation *info; 0254 0255 }; 0256 0257 FileSystemModelPrivate( 0258 #ifndef USE_QT_PRIVATE_HEADERS 0259 QObject *q 0260 #endif 0261 ) : 0262 forceSort(true), 0263 sortColumn(0), 0264 sortOrder(Qt::AscendingOrder), 0265 readOnly(true), 0266 setRootPath(false), 0267 filters(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs), 0268 nameFilterDisables(true), // false on windows, true on mac and unix 0269 disableRecursiveSort(false), 0270 sortIgnoringPunctuation(false) 0271 #ifndef USE_QT_PRIVATE_HEADERS 0272 , q_ptr(q) 0273 #endif 0274 { 0275 delayedSortTimer.setSingleShot(true); 0276 } 0277 0278 void clear(); 0279 void init(); 0280 /* 0281 \internal 0282 0283 Return true if index which is owned by node is hidden by the filter. 0284 */ 0285 inline bool isHiddenByFilter(FileSystemNode *indexNode, const QModelIndex &index) const 0286 { 0287 return (indexNode != &root && !index.isValid()); 0288 } 0289 FileSystemNode *node(const QModelIndex &index) const; 0290 FileSystemNode *node(const QString &path, bool fetch = true) const; 0291 inline QModelIndex index(const QString &path, int column = 0) { return index(node(path), column); } 0292 QModelIndex index(const FileSystemNode *node, int column = 0) const; 0293 bool filtersAcceptsNode(const FileSystemNode *node) const; 0294 bool passNameFilters(const FileSystemNode *node) const; 0295 void removeNode(FileSystemNode *parentNode, const QString &name); 0296 FileSystemNode* addNode(FileSystemNode *parentNode, const QString &fileName, const QFileInfo &info); 0297 void addVisibleFiles(FileSystemNode *parentNode, const QStringList &newFiles); 0298 void removeVisibleFile(FileSystemNode *parentNode, int vLocation); 0299 void sortChildren(int column, const QModelIndex &parent); 0300 0301 inline int translateVisibleLocation(FileSystemNode *parent, int row) const { 0302 if (sortOrder != Qt::AscendingOrder) { 0303 if (parent->dirtyChildrenIndex == -1) 0304 return parent->visibleChildren.count() - row - 1; 0305 0306 if (row < parent->dirtyChildrenIndex) 0307 return parent->dirtyChildrenIndex - row - 1; 0308 } 0309 0310 return row; 0311 } 0312 0313 inline static QString myComputer() { 0314 // ### TODO We should query the system to find out what the string should be 0315 // XP == "My Computer", 0316 // Vista == "Computer", 0317 // OS X == "Computer" (sometime user generated) "Benjamin's PowerBook G4" 0318 #ifdef Q_OS_WIN 0319 return FileSystemModel::tr("My Computer"); 0320 #else 0321 return FileSystemModel::tr("Computer"); 0322 #endif 0323 } 0324 0325 inline void delayedSort() { 0326 if (!delayedSortTimer.isActive()) 0327 delayedSortTimer.start(0); 0328 } 0329 0330 QVariant icon(const QModelIndex &index) const; 0331 QString name(const QModelIndex &index) const; 0332 QString displayName(const QModelIndex &index) const; 0333 QString filePath(const QModelIndex &index) const; 0334 QString size(const QModelIndex &index) const; 0335 static QString size(qint64 bytes); 0336 QString type(const QModelIndex &index) const; 0337 QString time(const QModelIndex &index) const; 0338 0339 void _q_directoryChanged(const QString &directory, const QStringList &files); 0340 void _q_performDelayedSort(); 0341 void _q_fileSystemChanged(const QString &path, const QVector<QPair<QString, QFileInfo> > &); 0342 void _q_resolvedName(const QString &fileName, const QString &resolvedName); 0343 0344 static int naturalCompare(const QString &s1, const QString &s2, Qt::CaseSensitivity cs); 0345 0346 #ifndef USE_QT_PRIVATE_HEADERS 0347 inline bool indexValid(const QModelIndex &index) const { 0348 return (index.row() >= 0) && (index.column() >= 0) && (index.model() == q_func()); 0349 } 0350 0351 QHash<int, QByteArray> roleNames; 0352 #endif 0353 0354 QDir rootDir; 0355 #ifndef QT_NO_FILESYSTEMWATCHER 0356 FileInfoGatherer fileInfoGatherer; 0357 #endif 0358 QTimer delayedSortTimer; 0359 bool forceSort; 0360 int sortColumn; 0361 Qt::SortOrder sortOrder; 0362 bool readOnly; 0363 bool setRootPath; 0364 QDir::Filters filters; 0365 QHash<const FileSystemNode*, bool> bypassFilters; 0366 bool nameFilterDisables; 0367 //This flag is an optimization for the QFileDialog 0368 //It enable a sort which is not recursive, it means 0369 //we sort only what we see. 0370 bool disableRecursiveSort; 0371 bool sortIgnoringPunctuation; 0372 #ifndef QT_NO_REGEXP 0373 QStringList nameFilters; 0374 #endif 0375 QHash<QString, QString> resolvedSymLinks; 0376 0377 FileSystemNode root; 0378 0379 QBasicTimer fetchingTimer; 0380 struct Fetching { 0381 QString dir; 0382 QString file; 0383 const FileSystemNode *node; 0384 }; 0385 QVector<Fetching> toFetch; 0386 0387 #ifndef USE_QT_PRIVATE_HEADERS 0388 QObject * const q_ptr; 0389 #endif 0390 }; 0391 Q_DECLARE_TYPEINFO(FileSystemModelPrivate::Fetching, Q_MOVABLE_TYPE); 0392 /** \endcond */