Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qfileinfogatherer.cpp
Go to the documentation of this file.
1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include <qdebug.h>
6#include <qdiriterator.h>
7#include <private/qfileinfo_p.h>
8#ifndef Q_OS_WIN
9# include <unistd.h>
10# include <sys/types.h>
11#endif
12#if defined(Q_OS_VXWORKS)
13# include "qplatformdefs.h"
14#endif
15
17
18using namespace Qt::StringLiterals;
19
20#ifdef QT_BUILD_INTERNAL
21Q_CONSTINIT static QBasicAtomicInt fetchedRoot = Q_BASIC_ATOMIC_INITIALIZER(false);
22Q_AUTOTEST_EXPORT void qt_test_resetFetchedRoot()
23{
24 fetchedRoot.storeRelaxed(false);
25}
26
27Q_AUTOTEST_EXPORT bool qt_test_isFetchedRoot()
28{
29 return fetchedRoot.loadRelaxed();
30}
31#endif
32
34{
35 QString driveName = drive.absoluteFilePath();
36#ifdef Q_OS_WIN
37 if (driveName.startsWith(u'/')) // UNC host
38 return drive.fileName();
39 if (driveName.endsWith(u'/'))
40 driveName.chop(1);
41#endif // Q_OS_WIN
42 return driveName;
43}
44
50 , m_iconProvider(&defaultProvider)
51{
53}
54
59{
60 abort.storeRelaxed(true);
61 QMutexLocker locker(&mutex);
62 condition.wakeAll();
63 locker.unlock();
64 wait();
65}
66
68{
70#ifdef Q_OS_WIN
71 m_resolveSymlinks = enable;
72#endif
73}
74
75void QFileInfoGatherer::driveAdded()
76{
78}
79
80void QFileInfoGatherer::driveRemoved()
81{
82 QStringList drives;
83 const QFileInfoList driveInfoList = QDir::drives();
84 for (const QFileInfo &fi : driveInfoList)
86 emit newListOfFiles(QString(), drives);
87}
88
90{
91#ifdef Q_OS_WIN
92 return m_resolveSymlinks;
93#else
94 return false;
95#endif
96}
97
99{
100 m_iconProvider = provider;
101}
102
104{
105 return m_iconProvider;
106}
107
114{
115 QMutexLocker locker(&mutex);
116 // See if we already have this dir/file in our queue
117 int loc = this->path.lastIndexOf(path);
118 while (loc > 0) {
119 if (this->files.at(loc) == files) {
120 return;
121 }
122 loc = this->path.lastIndexOf(path, loc - 1);
123 }
124#if QT_CONFIG(thread)
125 this->path.push(path);
126 this->files.push(files);
127 condition.wakeAll();
128#else // !QT_CONFIG(thread)
129 getFileInfos(path, files);
130#endif // QT_CONFIG(thread)
131
132#if QT_CONFIG(filesystemwatcher)
133 if (files.isEmpty()
134 && !path.isEmpty()
135 && !path.startsWith("//"_L1) /*don't watch UNC path*/) {
138 }
139#endif
140}
141
148{
149 QString dir = filePath.mid(0, filePath.lastIndexOf(u'/'));
150 QString fileName = filePath.mid(dir.size() + 1);
152}
153
155{
156#if QT_CONFIG(filesystemwatcher)
157 if (m_watcher)
158 return m_watcher->files();
159#endif
160 return {};
161}
162
164{
165#if QT_CONFIG(filesystemwatcher)
166 if (m_watcher)
167 return m_watcher->directories();
168#endif
169 return {};
170}
171
172void QFileInfoGatherer::createWatcher()
173{
174#if QT_CONFIG(filesystemwatcher)
175 m_watcher = new QFileSystemWatcher(this);
178# if defined(Q_OS_WIN)
179 const QVariant listener = m_watcher->property("_q_driveListener");
180 if (listener.canConvert<QObject *>()) {
181 if (QObject *driveListener = listener.value<QObject *>()) {
182 connect(driveListener, SIGNAL(driveAdded()), this, SLOT(driveAdded()));
183 connect(driveListener, SIGNAL(driveRemoved()), this, SLOT(driveRemoved()));
184 }
185 }
186# endif // Q_OS_WIN
187#endif
188}
189
191{
192#if QT_CONFIG(filesystemwatcher)
193 if (m_watching) {
194 if (m_watcher == nullptr)
195 createWatcher();
196 m_watcher->addPaths(paths);
197 }
198#else
200#endif
201}
202
204{
205#if QT_CONFIG(filesystemwatcher)
206 if (m_watcher && !paths.isEmpty())
207 m_watcher->removePaths(paths);
208#else
210#endif
211}
212
214{
215 bool result = false;
216#if QT_CONFIG(filesystemwatcher)
217 QMutexLocker locker(&mutex);
218 result = m_watching;
219#endif
220 return result;
221}
222
224{
225#if QT_CONFIG(filesystemwatcher)
226 QMutexLocker locker(&mutex);
227 if (v != m_watching) {
228 if (!v) {
229 delete m_watcher;
230 m_watcher = nullptr;
231 }
232 m_watching = v;
233 }
234#else
235 Q_UNUSED(v);
236#endif
237}
238
239/*
240 List all files in \a directoryPath
241
242 \sa listed()
243*/
245{
246#if QT_CONFIG(filesystemwatcher)
247 QMutexLocker locker(&mutex);
250#endif
251}
252
253/*
254 Remove a \a path from the watcher
255
256 \sa listed()
257*/
259{
260#if QT_CONFIG(filesystemwatcher)
261 QMutexLocker locker(&mutex);
263#else
264 Q_UNUSED(path);
265#endif
266}
267
268/*
269 List all files in \a directoryPath
270
271 \sa listed()
272*/
273void QFileInfoGatherer::list(const QString &directoryPath)
274{
275 fetchExtendedInformation(directoryPath, QStringList());
276}
277
278/*
279 Until aborted wait to fetch a directory or files
280*/
282{
283 forever {
284 QMutexLocker locker(&mutex);
285 while (!abort.loadRelaxed() && path.isEmpty())
286 condition.wait(&mutex);
287 if (abort.loadRelaxed())
288 return;
289 const QString thisPath = std::as_const(path).front();
290 path.pop_front();
291 const QStringList thisList = std::as_const(files).front();
292 files.pop_front();
293 locker.unlock();
294
295 getFileInfos(thisPath, thisList);
296 }
297}
298
300{
301 QExtendedInformation info(fileInfo);
302 info.icon = m_iconProvider->icon(fileInfo);
303 info.displayType = m_iconProvider->type(fileInfo);
304#if QT_CONFIG(filesystemwatcher)
305 // ### Not ready to listen all modifications by default
306 static const bool watchFiles = qEnvironmentVariableIsSet("QT_FILESYSTEMMODEL_WATCH_FILES");
307 if (watchFiles) {
308 if (!fileInfo.exists() && !fileInfo.isSymLink()) {
309 const_cast<QFileInfoGatherer *>(this)->
311 } else {
312 const QString path = fileInfo.absoluteFilePath();
313 if (!path.isEmpty() && fileInfo.exists() && fileInfo.isFile() && fileInfo.isReadable()
314 && !watchedFiles().contains(path)) {
315 const_cast<QFileInfoGatherer *>(this)->watchPaths(QStringList(path));
316 }
317 }
318 }
319#endif // filesystemwatcher
320
321#ifdef Q_OS_WIN
322 if (m_resolveSymlinks && info.isSymLink(/* ignoreNtfsSymLinks = */ true)) {
323 QFileInfo resolvedInfo(QFileInfo(fileInfo.symLinkTarget()).canonicalFilePath());
324 if (resolvedInfo.exists()) {
325 emit nameResolved(fileInfo.filePath(), resolvedInfo.fileName());
326 }
327 }
328#endif
329 return info;
330}
331
332/*
333 Get specific file info's, batch the files so update when we have 100
334 items and every 200ms after that
335 */
336void QFileInfoGatherer::getFileInfos(const QString &path, const QStringList &files)
337{
338 // List drives
339 if (path.isEmpty()) {
340#ifdef QT_BUILD_INTERNAL
341 fetchedRoot.storeRelaxed(true);
342#endif
343 QFileInfoList infoList;
344 if (files.isEmpty()) {
345 infoList = QDir::drives();
346 } else {
347 infoList.reserve(files.size());
348 for (const auto &file : files)
349 infoList << QFileInfo(file);
350 }
352 updatedFiles.reserve(infoList.size());
353 for (int i = infoList.size() - 1; i >= 0; --i) {
354 QFileInfo driveInfo = infoList.at(i);
355 driveInfo.stat();
356 QString driveName = translateDriveName(driveInfo);
357 updatedFiles.append(QPair<QString,QFileInfo>(driveName, driveInfo));
358 }
359 emit updates(path, updatedFiles);
360 return;
361 }
362
364 base.start();
365 QFileInfo fileInfo;
366 bool firstTime = true;
368 QStringList filesToCheck = files;
369
370 QStringList allFiles;
371 if (files.isEmpty()) {
373 while (!abort.loadRelaxed() && dirIt.hasNext()) {
374 fileInfo = dirIt.nextFileInfo();
375 fileInfo.stat();
376 allFiles.append(fileInfo.fileName());
377 fetch(fileInfo, base, firstTime, updatedFiles, path);
378 }
379 }
380 if (!allFiles.isEmpty())
381 emit newListOfFiles(path, allFiles);
382
383 QStringList::const_iterator filesIt = filesToCheck.constBegin();
384 while (!abort.loadRelaxed() && filesIt != filesToCheck.constEnd()) {
385 fileInfo.setFile(path + QDir::separator() + *filesIt);
386 ++filesIt;
387 fileInfo.stat();
388 fetch(fileInfo, base, firstTime, updatedFiles, path);
389 }
390 if (!updatedFiles.isEmpty())
391 emit updates(path, updatedFiles);
393}
394
395void QFileInfoGatherer::fetch(const QFileInfo &fileInfo, QElapsedTimer &base, bool &firstTime,
396 QList<QPair<QString, QFileInfo>> &updatedFiles, const QString &path)
397{
398 updatedFiles.append(QPair<QString, QFileInfo>(fileInfo.fileName(), fileInfo));
399 QElapsedTimer current;
400 current.start();
401 if ((firstTime && updatedFiles.size() > 100) || base.msecsTo(current) > 1000) {
402 emit updates(path, updatedFiles);
403 updatedFiles.clear();
404 base = current;
405 firstTime = false;
406 }
407}
408
410
411#include "moc_qfileinfogatherer_p.cpp"
virtual QIcon icon(IconType) const
Returns an icon set for the given type, using the current icon theme.
virtual QString type(const QFileInfo &) const
Returns the type of the file described by info.
void storeRelaxed(T newValue) noexcept
T loadRelaxed() const noexcept
The QDirIterator class provides an iterator for directory entrylists.
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
Definition qdir.h:206
static QFileInfoList drives()
Returns a list of the root directories on this system.
Definition qdir.cpp:1984
@ Hidden
Definition qdir.h:34
@ AllEntries
Definition qdir.h:25
@ System
Definition qdir.h:35
\inmodule QtCore
void start() noexcept
Starts this timer.
QAbstractFileIconProvider * iconProvider() const
QStringList watchedFiles() const
void list(const QString &directoryPath)
QFileInfoGatherer(QObject *parent=nullptr)
Creates thread.
void updates(const QString &directory, const QList< QPair< QString, QFileInfo > > &updates)
QStringList watchedDirectories() const
void setIconProvider(QAbstractFileIconProvider *provider)
void newListOfFiles(const QString &directory, const QStringList &listOfFiles) const
void unwatchPaths(const QStringList &paths)
void fetchExtendedInformation(const QString &path, const QStringList &files)
Fetch extended information for all files in path.
void setResolveSymlinks(bool enable)
void nameResolved(const QString &fileName, const QString &resolvedName) const
void directoryLoaded(const QString &path)
void updateFile(const QString &path)
Fetch extended information for all filePath.
bool resolveSymlinks() const
void watchPaths(const QStringList &paths)
QExtendedInformation getInfo(const QFileInfo &info) const
~QFileInfoGatherer()
Destroys thread.
void removePath(const QString &path)
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
bool isSymLink() const
Returns true if this object points to a symbolic link, shortcut, or alias; otherwise returns false.
QString symLinkTarget() const
void stat()
Reads all attributes from the file system.
QString fileName() const
Returns the name of the file, excluding the path.
void setFile(const QString &file)
Sets the file that the QFileInfo provides information about to file.
QString absoluteFilePath() const
Returns an absolute path including the file name.
bool isFile() const
Returns true if this object points to a file or to a symbolic link to a file.
QString canonicalFilePath() const
Returns the canonical path including the file name, i.e.
QString filePath() const
Returns the file name, including the path (which may be absolute or relative).
bool exists() const
Returns true if the file exists; otherwise returns false.
bool isReadable() const
Returns true if the user can read the file; otherwise returns false.
void fileChanged(const QString &path, QPrivateSignal)
This signal is emitted when the file at the specified path is modified, renamed or removed from disk.
void directoryChanged(const QString &path, QPrivateSignal)
This signal is emitted when the directory at a specified path is modified (e.g., when a file is added...
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
void reserve(qsizetype size)
Definition qlist.h:746
void pop_front() noexcept
Definition qlist.h:677
void append(parameter_type t)
Definition qlist.h:441
void clear()
Definition qlist.h:417
\inmodule QtCore
Definition qmutex.h:317
void unlock() noexcept
Unlocks this mutex locker.
Definition qmutex.h:323
\inmodule QtCore
Definition qobject.h:90
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
qsizetype lastIndexOf(QChar c, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qstring.h:279
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
void chop(qsizetype n)
Removes n characters from the end of the string.
Definition qstring.cpp:6180
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
QString mid(qsizetype position, qsizetype n=-1) const
Returns a string that contains n characters of this string, starting at the specified position index.
Definition qstring.cpp:5204
QChar front() const
Definition qstring.h:214
bool endsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string ends with s; otherwise returns false.
Definition qstring.cpp:5350
void start(Priority=InheritPriority)
Definition qthread.cpp:923
@ LowPriority
Definition qthread.h:45
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
Definition qthread.cpp:950
\inmodule QtCore
Definition qvariant.h:64
T value() const &
Definition qvariant.h:511
bool canConvert(QMetaType targetType) const
Definition qvariant.h:342
list append(new Employee("Blackpool", "Stephen"))
Combined button and popup list for selecting options.
#define Q_BASIC_ATOMIC_INITIALIZER(a)
std::pair< T1, T2 > QPair
static QString translateDriveName(const QFileInfo &drive)
#define forever
Definition qforeach.h:78
#define SLOT(a)
Definition qobjectdefs.h:51
#define SIGNAL(a)
Definition qobjectdefs.h:52
static bool contains(const QJsonArray &haystack, unsigned needle)
Definition qopengl.cpp:116
GLsizei const GLfloat * v
[13]
GLenum condition
GLsizei const GLuint * paths
GLboolean enable
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
#define Q_AUTOTEST_EXPORT
Q_CORE_EXPORT bool qEnvironmentVariableIsSet(const char *varName) noexcept
#define emit
#define Q_UNUSED(x)
QFile file
[0]
QFileInfo info(fileName)
[8]
QFileInfo fi("c:/temp/foo")
[newstuff]
QString dir
[11]
QStringList files
[8]
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent