Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
fileinfothread.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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
4#include "fileinfothread_p.h"
5#include <qdiriterator.h>
6#include <qpointer.h>
7#include <qtimer.h>
8
9#include <QDebug>
10#include <QtCore/qloggingcategory.h>
11
13
14Q_LOGGING_CATEGORY(lcFileInfoThread, "qt.labs.folderlistmodel.fileinfothread")
15
17 : QThread(parent),
18 abort(false),
19 scanPending(false),
20#if QT_CONFIG(filesystemwatcher)
21 watcher(nullptr),
22#endif
23 sortFlags(QDir::Name),
24 needUpdate(true),
25 updateTypes(UpdateType::None),
26 showFiles(true),
27 showDirs(true),
28 showDirsFirst(false),
29 showDotAndDotDot(false),
30 showHidden(false),
31 showOnlyReadable(false),
32 caseSensitive(true)
33{
34#if QT_CONFIG(filesystemwatcher)
35 watcher = new QFileSystemWatcher(this);
36 connect(watcher, SIGNAL(directoryChanged(QString)), this, SLOT(dirChanged(QString)));
37 connect(watcher, SIGNAL(fileChanged(QString)), this, SLOT(updateFile(QString)));
38#endif // filesystemwatcher
39}
40
42{
43 QMutexLocker locker(&mutex);
44 abort = true;
45 condition.wakeOne();
46 locker.unlock();
47 wait();
48}
49
51{
52 QMutexLocker locker(&mutex);
53#if QT_CONFIG(filesystemwatcher)
54 watcher->removePaths(watcher->files());
55 watcher->removePaths(watcher->directories());
56#endif
57}
58
60{
61 QMutexLocker locker(&mutex);
62#if QT_CONFIG(filesystemwatcher)
63 if (!path.startsWith(QLatin1Char(':')))
64 watcher->removePath(path);
65#else
67#endif
68 currentPath.clear();
69}
70
72{
73 qCDebug(lcFileInfoThread) << "setPath called with path" << path;
74 Q_ASSERT(!path.isEmpty());
75
76 QMutexLocker locker(&mutex);
77#if QT_CONFIG(filesystemwatcher)
78 if (!path.startsWith(QLatin1Char(':')))
79 watcher->addPath(path);
80#endif
81 currentPath = path;
82 needUpdate = true;
84}
85
87{
88 qCDebug(lcFileInfoThread) << "setRootPath called with path" << path;
89 Q_ASSERT(!path.isEmpty());
90
91 QMutexLocker locker(&mutex);
92 rootPath = path;
93}
94
95#if QT_CONFIG(filesystemwatcher)
96void FileInfoThread::dirChanged(const QString &directoryPath)
97{
98 qCDebug(lcFileInfoThread) << "dirChanged called with directoryPath" << directoryPath;
99 Q_UNUSED(directoryPath);
100 QMutexLocker locker(&mutex);
101 updateTypes |= UpdateType::Contents;
102 initiateScan();
103}
104#endif
105
107{
108 qCDebug(lcFileInfoThread) << "setSortFlags called with flags" << flags;
109 Q_ASSERT(flags != sortFlags);
110 QMutexLocker locker(&mutex);
111 sortFlags = flags;
112 updateTypes |= UpdateType::Sort;
113 needUpdate = true;
114 initiateScan();
115}
116
118{
119 qCDebug(lcFileInfoThread) << "setNameFilters called with filters" << filters;
120 QMutexLocker locker(&mutex);
121 nameFilters = filters;
122 updateTypes |= UpdateType::Contents;
123 initiateScan();
124}
125
127{
128 qCDebug(lcFileInfoThread) << "setShowFiles called with show" << show;
129 QMutexLocker locker(&mutex);
130 showFiles = show;
131 updateTypes |= UpdateType::Contents;
132 initiateScan();
133}
134
135void FileInfoThread::setShowDirs(bool showFolders)
136{
137 qCDebug(lcFileInfoThread) << "setShowDirs called with showFolders" << showFolders;
138 QMutexLocker locker(&mutex);
139 showDirs = showFolders;
140 updateTypes |= UpdateType::Contents;
141 initiateScan();
142}
143
145{
146 qCDebug(lcFileInfoThread) << "setShowDirsFirst called with show" << show;
147 QMutexLocker locker(&mutex);
148 showDirsFirst = show;
149 updateTypes |= UpdateType::Contents;
150 initiateScan();
151}
152
154{
155 qCDebug(lcFileInfoThread) << "setShowDotAndDotDot called with on" << on;
156 QMutexLocker locker(&mutex);
157 showDotAndDotDot = on;
158 updateTypes |= UpdateType::Contents;
159 needUpdate = true;
160 initiateScan();
161}
162
164{
165 qCDebug(lcFileInfoThread) << "setShowHidden called with on" << on;
166 QMutexLocker locker(&mutex);
167 showHidden = on;
168 updateTypes |= UpdateType::Contents;
169 needUpdate = true;
170 initiateScan();
171}
172
174{
175 qCDebug(lcFileInfoThread) << "setShowOnlyReadable called with on" << on;
176 QMutexLocker locker(&mutex);
177 showOnlyReadable = on;
178 updateTypes |= UpdateType::Contents;
179 initiateScan();
180}
181
183{
184 qCDebug(lcFileInfoThread) << "setCaseSensitive called with on" << on;
185 QMutexLocker locker(&mutex);
186 caseSensitive = on;
187 updateTypes |= UpdateType::Contents;
188 initiateScan();
189}
190
191#if QT_CONFIG(filesystemwatcher)
192void FileInfoThread::updateFile(const QString &path)
193{
194 qCDebug(lcFileInfoThread) << "updateFile called with path" << path;
195 Q_UNUSED(path);
196 QMutexLocker locker(&mutex);
197 updateTypes |= UpdateType::Contents;
198 initiateScan();
199}
200#endif
201
203{
204 forever {
205 bool updateFiles = false;
206 QMutexLocker locker(&mutex);
207 if (abort) {
208 return;
209 }
210 if (currentPath.isEmpty() || !needUpdate) {
212 condition.wait(&mutex);
213 }
214
215 if (abort) {
216 return;
217 }
218
219 if (!currentPath.isEmpty()) {
220 updateFiles = true;
222 }
223 if (updateFiles)
224 getFileInfos(currentPath);
225 locker.unlock();
226 }
227}
228
230{
231 if (scanPending)
232 return;
233 scanPending = true;
234 QPointer<FileInfoThread> guardedThis(this);
235
236 auto getFileInfosAsync = [guardedThis](){
237 if (!guardedThis)
238 return;
239 guardedThis->scanPending = false;
240 if (guardedThis->currentPath.isEmpty()) {
241 emit guardedThis->statusChanged(QQuickFolderListModel::Null);
242 return;
243 }
244 emit guardedThis->statusChanged(QQuickFolderListModel::Loading);
245 guardedThis->getFileInfos(guardedThis->currentPath);
246 emit guardedThis->statusChanged(QQuickFolderListModel::Ready);
247 };
248
249 QTimer::singleShot(0, getFileInfosAsync);
250}
251
253{
254#if QT_CONFIG(thread)
255 qCDebug(lcFileInfoThread) << "initiateScan is about to call condition.wakeAll()";
256 condition.wakeAll();
257#else
258 qCDebug(lcFileInfoThread) << "initiateScan is about to call runOnce()";
259 runOnce();
260#endif
261}
262
264{
265 return fileInfoList.size() <= 10
266 ? QDebug::toString(fileInfoList)
267 : QString::fromLatin1("%1 files").arg(fileInfoList.size());
268}
269
271{
272 qCDebug(lcFileInfoThread) << "getFileInfos called with path" << path << "- updateType" << updateTypes;
273
274 QDir::Filters filter;
275 if (caseSensitive)
277 if (showFiles)
279 if (showDirs)
281 if (!showDotAndDotDot)
283 else if (path == rootPath)
285 if (showHidden)
287 if (showOnlyReadable)
289 if (showDirsFirst)
290 sortFlags = sortFlags | QDir::DirsFirst;
291
292 QDir currentDir(path, QString(), sortFlags);
293 QList<FileProperty> filePropertyList;
294
295 const QFileInfoList fileInfoList = currentDir.entryInfoList(nameFilters, filter, sortFlags);
296
297 if (!fileInfoList.isEmpty()) {
298 filePropertyList.reserve(fileInfoList.size());
299 for (const QFileInfo &info : fileInfoList)
300 filePropertyList << FileProperty(info);
301
302 if (updateTypes & UpdateType::Contents) {
303 int fromIndex = 0;
304 int toIndex = currentFileList.size()-1;
305 findChangeRange(filePropertyList, fromIndex, toIndex);
306 currentFileList = filePropertyList;
307 qCDebug(lcFileInfoThread) << "- about to emit directoryUpdated with fromIndex" << fromIndex
308 << "toIndex" << toIndex << "fileInfoList" << fileInfoListToString(fileInfoList);
309 emit directoryUpdated(path, filePropertyList, fromIndex, toIndex);
310 } else {
311 currentFileList = filePropertyList;
312 if (updateTypes & UpdateType::Sort) {
313 qCDebug(lcFileInfoThread) << "- about to emit sortFinished - fileInfoList:"
314 << fileInfoListToString(fileInfoList);
315 emit sortFinished(filePropertyList);
316 } else {
317 qCDebug(lcFileInfoThread) << "- about to emit directoryChanged - fileInfoList:"
318 << fileInfoListToString(fileInfoList);
319 emit directoryChanged(path, filePropertyList);
320 }
321 }
322 } else {
323 // The directory is empty
324 if (updateTypes & UpdateType::Contents) {
325 int fromIndex = 0;
326 int toIndex = currentFileList.size()-1;
327 currentFileList.clear();
328 qCDebug(lcFileInfoThread) << "- directory is empty, about to emit directoryUpdated with fromIndex"
329 << fromIndex << "toIndex" << toIndex;
330 emit directoryUpdated(path, filePropertyList, fromIndex, toIndex);
331 } else {
332 currentFileList.clear();
333 qCDebug(lcFileInfoThread) << "- directory is empty, about to emit directoryChanged";
334 emit directoryChanged(path, filePropertyList);
335 }
336 }
337 updateTypes = UpdateType::None;
338 needUpdate = false;
339}
340
341void FileInfoThread::findChangeRange(const QList<FileProperty> &list, int &fromIndex, int &toIndex)
342{
343 if (currentFileList.size() == 0) {
344 fromIndex = 0;
345 toIndex = list.size();
346 return;
347 }
348
349 int i;
350 int listSize = list.size() < currentFileList.size() ? list.size() : currentFileList.size();
351 bool changeFound = false;
352
353 for (i=0; i < listSize; i++) {
354 if (list.at(i) != currentFileList.at(i)) {
355 changeFound = true;
356 break;
357 }
358 }
359
360 if (changeFound)
361 fromIndex = i;
362 else
363 fromIndex = i-1;
364
365 // For now I let the rest of the list be updated..
366 toIndex = list.size() > currentFileList.size() ? list.size() - 1 : currentFileList.size() - 1;
367}
368
369constexpr FileInfoThread::UpdateTypes operator|(FileInfoThread::UpdateType f1, FileInfoThread::UpdateTypes f2) noexcept
370{
371 return f2 | f1;
372}
373
374constexpr FileInfoThread::UpdateTypes operator&(FileInfoThread::UpdateType f1, FileInfoThread::UpdateTypes f2) noexcept
375{
376 return f2 & f1;
377}
378
380
381#include "moc_fileinfothread_p.cpp"
void removePath(const QString &path)
void setRootPath(const QString &path)
void setShowFiles(bool show)
void directoryUpdated(const QString &directory, const QList< FileProperty > &list, int fromIndex, int toIndex) const
void setShowDotAndDotDot(bool on)
void statusChanged(QQuickFolderListModel::Status status) const
void directoryChanged(const QString &directory, const QList< FileProperty > &list) const
void setNameFilters(const QStringList &nameFilters)
void setShowDirsFirst(bool show)
void setCaseSensitive(bool on)
void setShowDirs(bool showFolders)
void sortFinished(const QList< FileProperty > &list) const
void findChangeRange(const QList< FileProperty > &list, int &fromIndex, int &toIndex)
void setShowHidden(bool on)
void getFileInfos(const QString &path)
void setShowOnlyReadable(bool on)
void setPath(const QString &path)
void run() override
void setSortFlags(QDir::SortFlags flags)
\inmodule QtCore
Definition qdir.h:20
QFileInfoList entryInfoList(Filters filters=NoFilter, SortFlags sort=NoSort) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qdir.cpp:1388
@ DirsFirst
Definition qdir.h:56
@ Name
Definition qdir.h:50
@ CaseSensitive
Definition qdir.h:41
@ Files
Definition qdir.h:23
@ Hidden
Definition qdir.h:35
@ Drives
Definition qdir.h:24
@ AllDirs
Definition qdir.h:40
@ NoDotDot
Definition qdir.h:43
@ Readable
Definition qdir.h:29
@ NoDot
Definition qdir.h:42
qsizetype size() const noexcept
Definition qlist.h:397
bool isEmpty() const noexcept
Definition qlist.h:401
const_reference at(qsizetype i) const noexcept
Definition qlist.h:446
void reserve(qsizetype size)
Definition qlist.h:753
void clear()
Definition qlist.h:434
\inmodule QtCore
Definition qmutex.h:313
void unlock() noexcept
Unlocks this mutex locker.
Definition qmutex.h:319
\inmodule QtCore
Definition qobject.h:103
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5871
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1252
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
Definition qthread.cpp:1023
bool singleShot
whether the timer is a single-shot timer
Definition qtimer.h:22
QString fileInfoListToString(const QFileInfoList &fileInfoList)
constexpr FileInfoThread::UpdateTypes operator|(FileInfoThread::UpdateType f1, FileInfoThread::UpdateTypes f2) noexcept
constexpr FileInfoThread::UpdateTypes operator&(FileInfoThread::UpdateType f1, FileInfoThread::UpdateTypes f2) noexcept
Combined button and popup list for selecting options.
#define forever
Definition qforeach.h:78
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLenum condition
GLbitfield flags
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLsizei const GLchar *const * path
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
bool updateFile(const QString &fileName, const QHash< QString, QString > &replacements)
Definition main.cpp:1620
#define emit
#define Q_UNUSED(x)
static uint toIndex(ExecutionEngine *e, const Value &v)
view show()
[18] //! [19]
QList< int > list
[14]
QFutureWatcher< int > watcher
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
const QStringList filters({"Image files (*.png *.xpm *.jpg)", "Text files (*.txt)", "Any files (*)" })
[6]
QHostInfo info
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18