1// Copyright (C) 2018 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "qmlpreviewfilesystemwatcher.h"
5
6#include <QtCore/qdebug.h>
7#include <QtCore/qdir.h>
8#include <QtCore/qfilesystemwatcher.h>
9
10QmlPreviewFileSystemWatcher::QmlPreviewFileSystemWatcher(QObject *parent) :
11 QObject(parent), m_watcher(new QFileSystemWatcher(this))
12{
13 connect(sender: m_watcher, signal: &QFileSystemWatcher::fileChanged,
14 context: this, slot: &QmlPreviewFileSystemWatcher::fileChanged);
15 connect(sender: m_watcher, signal: &QFileSystemWatcher::directoryChanged,
16 context: this, slot: &QmlPreviewFileSystemWatcher::onDirectoryChanged);
17}
18
19bool QmlPreviewFileSystemWatcher::watchesFile(const QString &file) const
20{
21 return m_files.contains(value: file);
22}
23
24void QmlPreviewFileSystemWatcher::addFile(const QString &file)
25{
26 if (watchesFile(file)) {
27 qWarning() << "FileSystemWatcher: File" << file << "is already being watched.";
28 return;
29 }
30
31 QStringList toAdd(file);
32 m_files.insert(value: file);
33
34 const QString directory = QFileInfo(file).path();
35 const int dirCount = ++m_directoryCount[directory];
36 Q_ASSERT(dirCount > 0);
37
38 if (dirCount == 1)
39 toAdd.append(t: directory);
40
41 m_watcher->addPaths(files: toAdd);
42}
43
44void QmlPreviewFileSystemWatcher::removeFile(const QString &file)
45{
46 WatchEntrySetIterator it = m_files.find(value: file);
47 if (it == m_files.end()) {
48 qWarning() << "FileSystemWatcher: File" << file << "is not watched.";
49 return;
50 }
51
52 QStringList toRemove(file);
53 m_files.erase(i: it);
54 m_watcher->removePath(file);
55
56 const QString directory = QFileInfo(file).path();
57 const int dirCount = --m_directoryCount[directory];
58 Q_ASSERT(dirCount >= 0);
59
60 if (!dirCount)
61 toRemove.append(t: directory);
62
63 m_watcher->removePaths(files: toRemove);
64}
65
66bool QmlPreviewFileSystemWatcher::watchesDirectory(const QString &directory) const
67{
68 return m_directories.contains(value: directory);
69}
70
71void QmlPreviewFileSystemWatcher::addDirectory(const QString &directory)
72{
73 if (watchesDirectory(directory)) {
74 qWarning() << "FileSystemWatcher: Directory" << directory << "is already being watched.";
75 return;
76 }
77
78 m_directories.insert(value: directory);
79 const int count = ++m_directoryCount[directory];
80 Q_ASSERT(count > 0);
81
82 if (count == 1)
83 m_watcher->addPath(file: directory);
84}
85
86void QmlPreviewFileSystemWatcher::removeDirectory(const QString &directory)
87{
88 WatchEntrySetIterator it = m_directories.find(value: directory);
89 if (it == m_directories.end()) {
90 qWarning() << "FileSystemWatcher: Directory" << directory << "is not watched.";
91 return;
92 }
93
94 m_directories.erase(i: it);
95
96 const int count = --m_directoryCount[directory];
97 Q_ASSERT(count >= 0);
98
99 if (!count)
100 m_watcher->removePath(file: directory);
101}
102
103void QmlPreviewFileSystemWatcher::onDirectoryChanged(const QString &path)
104{
105 if (m_directories.contains(value: path))
106 emit directoryChanged(path);
107
108 QStringList toReadd;
109 const QDir dir(path);
110 for (const QFileInfo &entry : dir.entryInfoList(filters: QDir::Files)) {
111 const QString file = entry.filePath();
112 if (m_files.contains(value: file))
113 toReadd.append(t: file);
114 }
115
116 if (!toReadd.isEmpty()) {
117 const QStringList remove = m_watcher->addPaths(files: toReadd);
118 for (const QString &rejected : remove)
119 toReadd.removeOne(t: rejected);
120
121 // If we've successfully added the file, that means it was deleted and replaced.
122 for (const QString &reAdded : std::as_const(t&: toReadd))
123 emit fileChanged(path: reAdded);
124 }
125}
126

source code of qtdeclarative/tools/qmlpreview/qmlpreviewfilesystemwatcher.cpp