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 */