1/****************************************************************************
2**
3** Copyright (C) 2018 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "qmlpreviewfilesystemwatcher.h"
30
31#include <QtCore/qdebug.h>
32#include <QtCore/qdir.h>
33#include <QtCore/qfilesystemwatcher.h>
34
35QmlPreviewFileSystemWatcher::QmlPreviewFileSystemWatcher(QObject *parent) :
36 QObject(parent), m_watcher(new QFileSystemWatcher(this))
37{
38 connect(sender: m_watcher, signal: &QFileSystemWatcher::fileChanged,
39 receiver: this, slot: &QmlPreviewFileSystemWatcher::fileChanged);
40 connect(sender: m_watcher, signal: &QFileSystemWatcher::directoryChanged,
41 receiver: this, slot: &QmlPreviewFileSystemWatcher::onDirectoryChanged);
42}
43
44bool QmlPreviewFileSystemWatcher::watchesFile(const QString &file) const
45{
46 return m_files.contains(value: file);
47}
48
49void QmlPreviewFileSystemWatcher::addFile(const QString &file)
50{
51 if (watchesFile(file)) {
52 qWarning() << "FileSystemWatcher: File" << file << "is already being watched.";
53 return;
54 }
55
56 QStringList toAdd(file);
57 m_files.insert(value: file);
58
59 const QString directory = QFileInfo(file).path();
60 const int dirCount = ++m_directoryCount[directory];
61 Q_ASSERT(dirCount > 0);
62
63 if (dirCount == 1)
64 toAdd.append(t: directory);
65
66 m_watcher->addPaths(files: toAdd);
67}
68
69void QmlPreviewFileSystemWatcher::removeFile(const QString &file)
70{
71 WatchEntrySetIterator it = m_files.find(value: file);
72 if (it == m_files.end()) {
73 qWarning() << "FileSystemWatcher: File" << file << "is not watched.";
74 return;
75 }
76
77 QStringList toRemove(file);
78 m_files.erase(i: it);
79 m_watcher->removePath(file);
80
81 const QString directory = QFileInfo(file).path();
82 const int dirCount = --m_directoryCount[directory];
83 Q_ASSERT(dirCount >= 0);
84
85 if (!dirCount)
86 toRemove.append(t: directory);
87
88 m_watcher->removePaths(files: toRemove);
89}
90
91bool QmlPreviewFileSystemWatcher::watchesDirectory(const QString &directory) const
92{
93 return m_directories.contains(value: directory);
94}
95
96void QmlPreviewFileSystemWatcher::addDirectory(const QString &directory)
97{
98 if (watchesDirectory(directory)) {
99 qWarning() << "FileSystemWatcher: Directory" << directory << "is already being watched.";
100 return;
101 }
102
103 m_directories.insert(value: directory);
104 const int count = ++m_directoryCount[directory];
105 Q_ASSERT(count > 0);
106
107 if (count == 1)
108 m_watcher->addPath(file: directory);
109}
110
111void QmlPreviewFileSystemWatcher::removeDirectory(const QString &directory)
112{
113 WatchEntrySetIterator it = m_directories.find(value: directory);
114 if (it == m_directories.end()) {
115 qWarning() << "FileSystemWatcher: Directory" << directory << "is not watched.";
116 return;
117 }
118
119 m_directories.erase(i: it);
120
121 const int count = --m_directoryCount[directory];
122 Q_ASSERT(count >= 0);
123
124 if (!count)
125 m_watcher->removePath(file: directory);
126}
127
128void QmlPreviewFileSystemWatcher::onDirectoryChanged(const QString &path)
129{
130 if (m_directories.contains(value: path))
131 emit directoryChanged(path);
132
133 QStringList toReadd;
134 const QDir dir(path);
135 for (const QFileInfo &entry : dir.entryInfoList(filters: QDir::Files)) {
136 const QString file = entry.filePath();
137 if (m_files.contains(value: file))
138 toReadd.append(t: file);
139 }
140
141 if (!toReadd.isEmpty()) {
142 const QStringList remove = m_watcher->addPaths(files: toReadd);
143 for (const QString &rejected : remove)
144 toReadd.removeOne(t: rejected);
145
146 // If we've successfully added the file, that means it was deleted and replaced.
147 for (const QString &reAdded : qAsConst(t&: toReadd))
148 emit fileChanged(path: reAdded);
149 }
150}
151

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