由于Qt的体系过于庞大,即使是某个模块,分析起来也十分困难。对于QFileSystemModel,我们在这里对单个重要函数慢慢分析
1 /*! 2 \internal 3 4 The thread has received new information about files, 5 update and emit dataChanged if it has actually changed. 6 */ 7 void QFileSystemModelPrivate::_q_fileSystemChanged(const QString &path, const QVector<QPair<QString, QFileInfo> > &updates) 8 { 9 #ifndef QT_NO_FILESYSTEMWATCHER 10 Q_Q(QFileSystemModel); 11 QVector<QString> rowsToUpdate; 12 QStringList newFiles; 13 QFileSystemModelPrivate::QFileSystemNode *parentNode = node(path, false); 14 QModelIndex parentIndex = index(parentNode); 15 for (const auto &update : updates) { 16 QString fileName = update.first; 17 Q_ASSERT(!fileName.isEmpty()); 18 QExtendedInformation info = fileInfoGatherer.getInfo(update.second); 19 bool previouslyHere = parentNode->children.contains(fileName); 20 if (!previouslyHere) { 21 addNode(parentNode, fileName, info.fileInfo()); 22 } 23 QFileSystemModelPrivate::QFileSystemNode * node = parentNode->children.value(fileName); 24 bool isCaseSensitive = parentNode->caseSensitive(); 25 if (isCaseSensitive) { 26 if (node->fileName != fileName) 27 continue; 28 } else { 29 if (QString::compare(node->fileName,fileName,Qt::CaseInsensitive) != 0) 30 continue; 31 } 32 if (isCaseSensitive) { 33 Q_ASSERT(node->fileName == fileName); 34 } else { 35 node->fileName = fileName; 36 } 37 38 if (*node != info ) { 39 node->populate(info); 40 bypassFilters.remove(node); 41 // brand new information. 42 if (filtersAcceptsNode(node)) { 43 if (!node->isVisible) { 44 newFiles.append(fileName); 45 } else { 46 rowsToUpdate.append(fileName); 47 } 48 } else { 49 if (node->isVisible) { 50 int visibleLocation = parentNode->visibleLocation(fileName); 51 removeVisibleFile(parentNode, visibleLocation); 52 } else { 53 // The file is not visible, don't do anything 54 } 55 } 56 } 57 } 58 59 // bundle up all of the changed signals into as few as possible. 60 std::sort(rowsToUpdate.begin(), rowsToUpdate.end()); 61 QString min; 62 QString max; 63 for (int i = 0; i < rowsToUpdate.count(); ++i) { 64 QString value = rowsToUpdate.at(i); 65 //##TODO is there a way to bundle signals with QString as the content of the list? 66 /*if (min.isEmpty()) { 67 min = value; 68 if (i != rowsToUpdate.count() - 1) 69 continue; 70 } 71 if (i != rowsToUpdate.count() - 1) { 72 if ((value == min + 1 && max.isEmpty()) || value == max + 1) { 73 max = value; 74 continue; 75 } 76 }*/ 77 max = value; 78 min = value; 79 int visibleMin = parentNode->visibleLocation(min); 80 int visibleMax = parentNode->visibleLocation(max); 81 if (visibleMin >= 0 82 && visibleMin < parentNode->visibleChildren.count() 83 && parentNode->visibleChildren.at(visibleMin) == min 84 && visibleMax >= 0) { 85 QModelIndex bottom = q->index(translateVisibleLocation(parentNode, visibleMin), 0, parentIndex); 86 QModelIndex top = q->index(translateVisibleLocation(parentNode, visibleMax), 3, parentIndex); 87 emit q->dataChanged(bottom, top); 88 } 89 90 /*min = QString(); 91 max = QString();*/ 92 } 93 94 if (newFiles.count() > 0) { 95 addVisibleFiles(parentNode, newFiles); 96 } 97 98 if (newFiles.count() > 0 || (sortColumn != 0 && rowsToUpdate.count() > 0)) { 99 forceSort = true; 100 delayedSort(); 101 } 102 #else 103 Q_UNUSED(path) 104 Q_UNUSED(updates) 105 #endif // !QT_NO_FILESYSTEMWATCHER 106 }
针对程序,一一作出解释:Q_UNUSED宏,避免因为某个变量没有使用,而编译器报错:
1 /* 2 Avoid "unused parameter" warnings 3 */ 4 #define Q_UNUSED(x) (void)x;
接下来,解释下面这句,位于主代码18行的:
QExtendedInformation info = fileInfoGatherer.getInfo(update.second);
找到它所在的头文件qfileinfogatherer_p.h
40 #ifndef QFILEINFOGATHERER_H 41 #define QFILEINFOGATHERER_H 42 43 // 44 // W A R N I N G 45 // ------------- 46 // 47 // This file is not part of the Qt API. It exists purely as an 48 // implementation detail. This header file may change from version to 49 // version without notice, or even be removed. 50 // 51 // We mean it. 52 // 53 54 #include <QtWidgets/private/qtwidgetsglobal_p.h> 55 56 #include <qthread.h> 57 #include <qmutex.h> 58 #include <qwaitcondition.h> 59 #include <qfilesystemwatcher.h> 60 #include <qfileiconprovider.h> 61 #include <qpair.h> 62 #include <qstack.h> 63 #include <qdatetime.h> 64 #include <qdir.h> 65 #include <qelapsedtimer.h> 66 67 #include <private/qfilesystemengine_p.h> 68 69 QT_REQUIRE_CONFIG(filesystemmodel); 70 71 QT_BEGIN_NAMESPACE 72 73 class QExtendedInformation { 74 public: 75 enum Type { Dir, File, System }; 76 77 QExtendedInformation() {} 78 QExtendedInformation(const QFileInfo &info) : mFileInfo(info) {} 79 80 inline bool isDir() { return type() == Dir; } 81 inline bool isFile() { return type() == File; } 82 inline bool isSystem() { return type() == System; } 83 84 bool operator ==(const QExtendedInformation &fileInfo) const { 85 return mFileInfo == fileInfo.mFileInfo 86 && displayType == fileInfo.displayType 87 && permissions() == fileInfo.permissions(); 88 } 89 90 #ifndef QT_NO_FSFILEENGINE 91 bool isCaseSensitive() const { 92 return QFileSystemEngine::isCaseSensitive(); 93 } 94 #endif 95 96 QFile::Permissions permissions() const { 97 return mFileInfo.permissions(); 98 } 99 100 Type type() const { 101 if (mFileInfo.isDir()) { 102 return QExtendedInformation::Dir; 103 } 104 if (mFileInfo.isFile()) { 105 return QExtendedInformation::File; 106 } 107 if (!mFileInfo.exists() && mFileInfo.isSymLink()) { 108 return QExtendedInformation::System; 109 } 110 return QExtendedInformation::System; 111 } 112 113 bool isSymLink(bool ignoreNtfsSymLinks = false) const 114 { 115 if (ignoreNtfsSymLinks) { 116 #ifdef Q_OS_WIN 117 return !mFileInfo.suffix().compare(QLatin1String("lnk"), Qt::CaseInsensitive); 118 #endif 119 } 120 return mFileInfo.isSymLink(); 121 } 122 123 bool isHidden() const { 124 return mFileInfo.isHidden(); 125 } 126 127 QFileInfo fileInfo() const { 128 return mFileInfo; 129 } 130 131 QDateTime lastModified() const { 132 return mFileInfo.lastModified(); 133 } 134 135 qint64 size() const { 136 qint64 size = -1; 137 if (type() == QExtendedInformation::Dir) 138 size = 0; 139 if (type() == QExtendedInformation::File) 140 size = mFileInfo.size(); 141 if (!mFileInfo.exists() && !mFileInfo.isSymLink()) 142 size = -1; 143 return size; 144 } 145 146 QString displayType; 147 QIcon icon; 148 149 private : 150 QFileInfo mFileInfo; 151 }; 152 153 class QFileIconProvider; 154 155 class Q_AUTOTEST_EXPORT QFileInfoGatherer : public QThread 156 { 157 Q_OBJECT 158 159 Q_SIGNALS: 160 void updates(const QString &directory, const QVector<QPair<QString, QFileInfo> > &updates); 161 void newListOfFiles(const QString &directory, const QStringList &listOfFiles) const; 162 void nameResolved(const QString &fileName, const QString &resolvedName) const; 163 void directoryLoaded(const QString &path); 164 165 public: 166 explicit QFileInfoGatherer(QObject *parent = 0); 167 ~QFileInfoGatherer(); 168 169 // only callable from this->thread(): 170 void clear(); 171 void removePath(const QString &path); 172 QExtendedInformation getInfo(const QFileInfo &info) const; 173 QFileIconProvider *iconProvider() const; 174 bool resolveSymlinks() const; 175 176 public Q_SLOTS: 177 void list(const QString &directoryPath); 178 void fetchExtendedInformation(const QString &path, const QStringList &files); 179 void updateFile(const QString &path); 180 void setResolveSymlinks(bool enable); 181 void setIconProvider(QFileIconProvider *provider); 182 183 private Q_SLOTS: 184 void driveAdded(); 185 void driveRemoved(); 186 187 private: 188 void run() Q_DECL_OVERRIDE; 189 // called by run(): 190 void getFileInfos(const QString &path, const QStringList &files); 191 void fetch(const QFileInfo &info, QElapsedTimer &base, bool &firstTime, QVector<QPair<QString, QFileInfo> > &updatedFiles, const QString &path); 192 193 private: 194 mutable QMutex mutex; 195 // begin protected by mutex 196 QWaitCondition condition; 197 QStack<QString> path; 198 QStack<QStringList> files; 199 // end protected by mutex 200 QAtomicInt abort; 201 202 #ifndef QT_NO_FILESYSTEMWATCHER 203 QFileSystemWatcher *watcher; 204 #endif 205 #ifdef Q_OS_WIN 206 bool m_resolveSymlinks; // not accessed by run() 207 #endif 208 QFileIconProvider *m_iconProvider; // not accessed by run() 209 QFileIconProvider defaultProvider; 210 }; 211 212 QT_END_NAMESPACE 213 #endif // QFILEINFOGATHERER_H