File indexing completed on 2024-04-14 04:46:11

0001 /*
0002     SPDX-FileCopyrightText: 2017 Jean-Baptiste Mardelle
0003     SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004 */
0005 
0006 #include "filewatcher.hpp"
0007 
0008 #include <KDirWatch>
0009 #include <QFileInfo>
0010 
0011 FileWatcher::FileWatcher(QObject *parent)
0012     : QObject(parent)
0013     , m_fileWatcher(new KDirWatch)
0014 {
0015     // Init clip modification tracker
0016     m_modifiedTimer.setInterval(2000);
0017     connect(m_fileWatcher.get(), &KDirWatch::dirty, this, &FileWatcher::slotUrlModified);
0018     connect(m_fileWatcher.get(), &KDirWatch::deleted, this, &FileWatcher::slotUrlMissing);
0019     connect(m_fileWatcher.get(), &KDirWatch::created, this, &FileWatcher::slotUrlAdded);
0020     connect(&m_modifiedTimer, &QTimer::timeout, this, &FileWatcher::slotProcessModifiedUrls);
0021     m_queueTimer.setInterval(300);
0022     m_queueTimer.setSingleShot(true);
0023     connect(&m_queueTimer, &QTimer::timeout, this, &FileWatcher::slotProcessQueue);
0024 }
0025 
0026 void FileWatcher::slotProcessQueue()
0027 {
0028     if (m_pendingUrls.size() == 0) {
0029         return;
0030     }
0031     auto iter = m_pendingUrls.begin();
0032     doAddFile(iter->first, iter->second);
0033     m_pendingUrls.erase(iter->first);
0034     if (m_pendingUrls.size() > 0 && !m_queueTimer.isActive()) {
0035         m_queueTimer.start();
0036     }
0037 }
0038 
0039 void FileWatcher::addFile(const QString &binId, const QString &url)
0040 {
0041     std::unordered_map<QString, std::unordered_set<QString>>::const_iterator pos = m_occurences.find(url);
0042     if (pos != m_occurences.end()) {
0043         // Url already queued, only add ref to binId if necessary
0044         if (pos->second.find(binId) == pos->second.end()) {
0045             m_occurences[url].insert(binId);
0046             m_binClipPaths[binId] = url;
0047         }
0048         return;
0049     }
0050     m_pendingUrls[binId] = url;
0051     if (!m_queueTimer.isActive()) {
0052         m_queueTimer.start();
0053     }
0054 }
0055 
0056 void FileWatcher::doAddFile(const QString &binId, const QString &url)
0057 {
0058     if (url.isEmpty()) {
0059         return;
0060     }
0061     if (m_occurences.count(url) == 0) {
0062         // QtConcurrent::run([=] { KDirWatch::self()->addFile(url); });
0063         m_fileWatcher->addFile(url);
0064     }
0065     m_occurences[url].insert(binId);
0066     m_binClipPaths[binId] = url;
0067 }
0068 
0069 void FileWatcher::removeFile(const QString &binId)
0070 {
0071     if (m_binClipPaths.count(binId) == 0) {
0072         return;
0073     }
0074     QString url = m_binClipPaths[binId];
0075     m_occurences[url].erase(binId);
0076     m_binClipPaths.erase(binId);
0077     if (m_occurences[url].empty()) {
0078         m_fileWatcher->removeFile(url);
0079         m_occurences.erase(url);
0080     }
0081 }
0082 
0083 void FileWatcher::slotUrlModified(const QString &path)
0084 {
0085     if (m_modifiedUrls.insert(path).second) {
0086         for (const QString &id : m_occurences[path]) {
0087             Q_EMIT binClipWaiting(id);
0088         }
0089     }
0090     if (!m_modifiedTimer.isActive()) {
0091         m_modifiedTimer.start();
0092     }
0093 }
0094 
0095 void FileWatcher::slotUrlAdded(const QString &path)
0096 {
0097     for (const QString &id : m_occurences[path]) {
0098         Q_EMIT binClipModified(id);
0099     }
0100 }
0101 
0102 void FileWatcher::slotUrlMissing(const QString &path)
0103 {
0104     for (const QString &id : m_occurences[path]) {
0105         Q_EMIT binClipMissing(id);
0106     }
0107 }
0108 
0109 void FileWatcher::slotProcessModifiedUrls()
0110 {
0111     auto checkList = m_modifiedUrls;
0112     for (const QString &path : checkList) {
0113         if (m_fileWatcher->ctime(path).msecsTo(QDateTime::currentDateTime()) > 2000) {
0114             for (const QString &id : m_occurences[path]) {
0115                 Q_EMIT binClipModified(id);
0116             }
0117             m_modifiedUrls.erase(path);
0118         }
0119     }
0120     if (m_modifiedUrls.empty()) {
0121         m_modifiedTimer.stop();
0122     }
0123 }
0124 
0125 void FileWatcher::clear()
0126 {
0127     m_queueTimer.stop();
0128     m_fileWatcher->stopScan();
0129     for (const auto &f : m_occurences) {
0130         m_fileWatcher->removeFile(f.first);
0131     }
0132     m_pendingUrls.clear();
0133     m_occurences.clear();
0134     m_modifiedUrls.clear();
0135     m_binClipPaths.clear();
0136     m_fileWatcher->startScan();
0137 }
0138 
0139 bool FileWatcher::contains(const QString &path) const
0140 {
0141     return m_fileWatcher->contains(path);
0142 }