--- /dev/null
+include($$PWD/private/private.pri)
+
+HEADERS += \
+ $$PWD/dobject.h \
+ $$PWD/dsingleton.h
+
+SOURCES += \
+ $$PWD/dobject.cpp
+
+includes.files += $$PWD/*.h
+includes.files += $$PWD/*.cpp
+includes.files += \
+ $$PWD/DObject \
+ $$PWD/DSingleton
+++ /dev/null
-include($$PWD/private/private.pri)
-
-HEADERS += \
- $$PWD/dobject.h \
- $$PWD/dsingleton.h
-
-SOURCES += \
- $$PWD/dobject.cpp
+++ /dev/null
-DCOMMON_DIR = $$PWD/../common
-include($$DCOMMON_DIR/lib.pri)
-include($$PWD/dbase.pri)
-
-QT -= gui
-
-TARGET = dtkbase
-
-DEFINES += LIBDTKBASE_LIBRARY
-
-includes.path = $${DTK_INCLUDEPATH}/DBase
-includes.files += *.h
-includes.files += DObject
-
-QMAKE_PKGCONFIG_NAME = DTK_BASE
-QMAKE_PKGCONFIG_DESCRIPTION = Deepin Tool Kit Base Header Files
-QMAKE_PKGCONFIG_INCDIR = $$includes.path
-
-DISTFILES += \
- DSingleton
--- /dev/null
+#include "dbasefilewatcher.h"
--- /dev/null
+#include "dfilesystemwatcher.h"
--- /dev/null
+#include "dfilewatcher.h"
--- /dev/null
+#include "dfilewatchermanager.h"
--- /dev/null
+#include "dpathbuf.h"
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+
+#include "dbasefilewatcher.h"
+#include "private/dbasefilewatcher_p.h"
+
+#include <QEvent>
+#include <QDebug>
+
+DCORE_BEGIN_NAMESPACE
+
+QList<DBaseFileWatcher*> DBaseFileWatcherPrivate::watcherList;
+DBaseFileWatcherPrivate::DBaseFileWatcherPrivate(DBaseFileWatcher *qq)
+ : DObjectPrivate(qq)
+{
+
+}
+
+DBaseFileWatcher::~DBaseFileWatcher()
+{
+ stopWatcher();
+ DBaseFileWatcherPrivate::watcherList.removeOne(this);
+}
+
+QUrl DBaseFileWatcher::fileUrl() const
+{
+ Q_D(const DBaseFileWatcher);
+
+ return d->url;
+}
+
+bool DBaseFileWatcher::startWatcher()
+{
+ Q_D(DBaseFileWatcher);
+
+ if (d->started)
+ return true;
+
+ if (d->start()) {
+ d->started = true;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool DBaseFileWatcher::stopWatcher()
+{
+ Q_D(DBaseFileWatcher);
+
+ if (!d->started)
+ return false;
+
+ if (d->stop()) {
+ d->started = false;
+
+ return true;
+ }
+
+ return false;
+}
+
+bool DBaseFileWatcher::restartWatcher()
+{
+ bool ok = stopWatcher();
+ return ok && startWatcher();
+}
+
+void DBaseFileWatcher::setEnabledSubfileWatcher(const QUrl &subfileUrl, bool enabled)
+{
+ Q_UNUSED(subfileUrl)
+ Q_UNUSED(enabled)
+}
+
+bool DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::SignalType1 signal, const QUrl &arg1)
+{
+ if (!signal)
+ return false;
+
+ bool ok = false;
+
+ for (DBaseFileWatcher *watcher : DBaseFileWatcherPrivate::watcherList) {
+ if (watcher->fileUrl() == targetUrl) {
+ ok = true;
+ (watcher->*signal)(arg1);
+ }
+ }
+
+ return ok;
+}
+
+bool DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::SignalType2 signal, const QUrl &arg1, const QUrl &arg2)
+{
+ if (!signal)
+ return false;
+
+ bool ok = false;
+
+ for (DBaseFileWatcher *watcher : DBaseFileWatcherPrivate::watcherList) {
+ if (watcher->fileUrl() == targetUrl) {
+ ok = true;
+ (watcher->*signal)(arg1, arg2);
+ }
+ }
+
+ return ok;
+}
+
+DBaseFileWatcher::DBaseFileWatcher(DBaseFileWatcherPrivate &dd,
+ const QUrl &url, QObject *parent)
+ : QObject(parent)
+ , DObject(dd)
+{
+ Q_ASSERT(url.isValid());
+
+ d_func()->url = url;
+ DBaseFileWatcherPrivate::watcherList << this;
+}
+
+DCORE_END_NAMESPACE
+
+#include "moc_dbasefilewatcher.cpp"
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+
+#ifndef DBASEFILEWATCHER_H
+#define DBASEFILEWATCHER_H
+
+#include "dtkcore_global.h"
+#include "base/dobject.h"
+
+#include <QObject>
+
+DCORE_BEGIN_NAMESPACE
+
+class DBaseFileWatcherPrivate;
+class DBaseFileWatcher : public QObject, public DObject
+{
+ Q_OBJECT
+
+public:
+ ~DBaseFileWatcher();
+
+ QUrl fileUrl() const;
+
+ bool startWatcher();
+ bool stopWatcher();
+ bool restartWatcher();
+
+ virtual void setEnabledSubfileWatcher(const QUrl &subfileUrl, bool enabled = true);
+
+ using SignalType1 = void(DBaseFileWatcher::*)(const QUrl &);
+ using SignalType2 = void(DBaseFileWatcher::*)(const QUrl &, const QUrl &);
+ static bool ghostSignal(const QUrl &targetUrl, SignalType1 signal, const QUrl &arg1);
+ static bool ghostSignal(const QUrl &targetUrl, SignalType2 signal, const QUrl &arg1, const QUrl &arg2);
+
+Q_SIGNALS:
+ void fileDeleted(const QUrl &url);
+ void fileAttributeChanged(const QUrl &url);
+ void fileMoved(const QUrl &fromUrl, const QUrl &toUrl);
+ void subfileCreated(const QUrl &url);
+ void fileModified(const QUrl &url);
+ void fileClosed(const QUrl &url);
+
+protected:
+ explicit DBaseFileWatcher(DBaseFileWatcherPrivate &dd, const QUrl &url, QObject *parent = 0);
+
+private:
+ Q_DISABLE_COPY(DBaseFileWatcher)
+ D_DECLARE_PRIVATE(DBaseFileWatcher)
+};
+
+DCORE_END_NAMESPACE
+
+#endif // DBASEFILEWATCHER_H
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+
+#ifndef DFILESYSTEMWATCHER_H
+#define DFILESYSTEMWATCHER_H
+
+#include "dtkcore_global.h"
+#include "base/dobject.h"
+
+#include <QObject>
+
+DCORE_BEGIN_NAMESPACE
+
+class DFileSystemWatcherPrivate;
+class DFileSystemWatcher : public QObject, public DObject
+{
+ Q_OBJECT
+ D_DECLARE_PRIVATE(DFileSystemWatcher)
+
+public:
+ DFileSystemWatcher(QObject *parent = Q_NULLPTR);
+ DFileSystemWatcher(const QStringList &paths, QObject *parent = Q_NULLPTR);
+ ~DFileSystemWatcher();
+
+ bool addPath(const QString &file);
+ QStringList addPaths(const QStringList &files);
+ bool removePath(const QString &file);
+ QStringList removePaths(const QStringList &files);
+
+ QStringList files() const;
+ QStringList directories() const;
+
+Q_SIGNALS:
+ void fileDeleted(const QString &path, const QString &name, QPrivateSignal);
+ void fileAttributeChanged(const QString &path, const QString &name, QPrivateSignal);
+ void fileClosed(const QString &path, const QString &name, QPrivateSignal);
+ void fileMoved(const QString &fromPath, const QString &fromName,
+ const QString &toPath, const QString &toName, QPrivateSignal);
+ void fileCreated(const QString &path, const QString &name, QPrivateSignal);
+ void fileModified(const QString &path, const QString &name, QPrivateSignal);
+
+private:
+ Q_PRIVATE_SLOT(d_func(), void _q_readFromInotify())
+};
+
+DCORE_END_NAMESPACE
+
+#endif // DFILESYSTEMWATCHER_H
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+
+#include "dfilesystemwatcher.h"
+#include "private/dfilesystemwatcher_linux_p.h"
+
+#include <QFileInfo>
+#include <QDir>
+#include <QSocketNotifier>
+#include <QDebug>
+
+#include <sys/inotify.h>
+#include <sys/fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+
+DCORE_BEGIN_NAMESPACE
+
+DFileSystemWatcherPrivate::DFileSystemWatcherPrivate(int fd, DFileSystemWatcher *qq)
+ : DObjectPrivate(qq)
+ , inotifyFd(fd)
+ , notifier(fd, QSocketNotifier::Read, qq)
+{
+ fcntl(inotifyFd, F_SETFD, FD_CLOEXEC);
+ qq->connect(¬ifier, SIGNAL(activated(int)), qq, SLOT(_q_readFromInotify()));
+}
+
+DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate()
+{
+ notifier.setEnabled(false);
+ Q_FOREACH (int id, pathToID)
+ inotify_rm_watch(inotifyFd, id < 0 ? -id : id);
+
+ ::close(inotifyFd);
+}
+
+QStringList DFileSystemWatcherPrivate::addPaths(const QStringList &paths, QStringList *files, QStringList *directories)
+{
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+ while (it.hasNext()) {
+ QString path = it.next();
+ QFileInfo fi(path);
+ bool isDir = fi.isDir();
+ if (isDir) {
+ if (directories->contains(path))
+ continue;
+ } else {
+ if (files->contains(path))
+ continue;
+ }
+
+ int wd = inotify_add_watch(inotifyFd,
+ QFile::encodeName(path),
+ (isDir
+ ? (0
+ | IN_ATTRIB
+ | IN_MOVE
+ | IN_MOVE_SELF
+ | IN_CREATE
+ | IN_DELETE
+ | IN_DELETE_SELF
+ | IN_MODIFY
+ )
+ : (0
+ | IN_ATTRIB
+ | IN_CLOSE_WRITE
+ | IN_MODIFY
+ | IN_MOVE
+ | IN_MOVE_SELF
+ | IN_DELETE_SELF
+ )));
+ if (wd < 0) {
+ perror("DFileSystemWatcherPrivate::addPaths: inotify_add_watch failed");
+ continue;
+ }
+
+ it.remove();
+
+ int id = isDir ? -wd : wd;
+ if (id < 0) {
+ directories->append(path);
+ } else {
+ files->append(path);
+ }
+
+ pathToID.insert(path, id);
+ idToPath.insert(id, path);
+ }
+
+ return p;
+}
+
+QStringList DFileSystemWatcherPrivate::removePaths(const QStringList &paths, QStringList *files, QStringList *directories)
+{
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+ while (it.hasNext()) {
+ QString path = it.next();
+ int id = pathToID.take(path);
+ QString x = idToPath.take(id);
+
+ it.remove();
+
+ if (x.isEmpty() || x != path)
+ continue;
+
+ int wd = id < 0 ? -id : id;
+ // qDebug() << "removing watch for path" << path << "wd" << wd;
+ inotify_rm_watch(inotifyFd, wd);
+
+ if (id < 0) {
+ directories->removeAll(path);
+ } else {
+ files->removeAll(path);
+ }
+ }
+
+ return p;
+}
+
+void DFileSystemWatcherPrivate::_q_readFromInotify()
+{
+ Q_Q(DFileSystemWatcher);
+// qDebug() << "QInotifyFileSystemWatcherEngine::readFromInotify";
+
+ int buffSize = 0;
+ ioctl(inotifyFd, FIONREAD, (char *) &buffSize);
+ QVarLengthArray<char, 4096> buffer(buffSize);
+ buffSize = read(inotifyFd, buffer.data(), buffSize);
+ char *at = buffer.data();
+ char * const end = at + buffSize;
+
+ QList<inotify_event *> eventList;
+ QHash<int, QString> pathForId;
+ /// only save event: IN_MOVE_TO
+ QMap<int, QString> cookieToFilePath;
+ QMap<int, QString> cookieToFileName;
+ QSet<int> hasMoveFromByCookie;
+ while (at < end) {
+ inotify_event *event = reinterpret_cast<inotify_event *>(at);
+ QString path;
+
+ at += sizeof(inotify_event) + event->len;
+
+ int id = event->wd;
+ path = getPathFromID(id);
+ if (path.isEmpty()) {
+ // perhaps a directory?
+ id = -id;
+ path = getPathFromID(id);
+ if (path.isEmpty())
+ continue;
+ }
+
+ if (!(event->mask & IN_MOVED_TO) || !hasMoveFromByCookie.contains(event->cookie)) {
+ eventList.append(event);
+ pathForId.insert(id, path);
+ }
+
+ if (event->mask & IN_MOVED_TO) {
+ cookieToFilePath.insert(event->cookie, path);
+ cookieToFileName.insert(event->cookie, QString::fromUtf8(event->name));
+ }
+
+ if (event->mask & IN_MOVED_FROM)
+ hasMoveFromByCookie << event->cookie;
+ }
+
+// qDebug() << "event count:" << eventList.count();
+
+ QList<inotify_event *>::const_iterator it = eventList.constBegin();
+ while (it != eventList.constEnd()) {
+ const inotify_event &event = **it;
+ ++it;
+
+// qDebug() << "inotify event, wd" << event.wd << "cookie" << event.cookie << "mask" << hex << event.mask;
+
+ int id = event.wd;
+ QString path = pathForId.value(id);
+
+ if (path.isEmpty()) {
+ id = -id;
+ path = pathForId.value(id);
+
+ if (path.isEmpty())
+ continue;
+ }
+ const QString &name = QString::fromUtf8(event.name);
+
+// qDebug() << "event for path" << path;
+
+// /// TODO: Existence of invalid utf8 characters QFile can not read the file information
+// if (event.name != QString::fromLocal8Bit(event.name).toLocal8Bit()) {
+// if (event.mask & (IN_CREATE | IN_MOVED_TO)) {
+// DFMGlobal::fileNameCorrection(path);
+// }
+// }
+
+ if ((event.mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT)) != 0) {
+ do {
+ if (event.mask & IN_MOVE_SELF) {
+ QMap<int, QString>::const_iterator iterator = cookieToFilePath.constBegin();
+
+ bool isMove = false;
+
+ while (iterator != cookieToFilePath.constEnd()) {
+ const QString &_path = iterator.value();
+ const QString &_name = cookieToFileName.value(iterator.key());
+
+ if (QFileInfo(_path + QDir::separator() + _name) == QFileInfo(path)) {
+ isMove = true;
+ break;
+ }
+
+ ++iterator;
+ }
+
+ if (isMove)
+ break;
+ }
+
+ /// Keep watcher
+// pathToID.remove(path);
+// idToPath.remove(id, getPathFromID(id));
+// if (!idToPath.contains(id))
+// inotify_rm_watch(inotifyFd, event.wd);
+
+// if (id < 0)
+// onDirectoryChanged(path, true);
+// else
+// onFileChanged(path, true);
+
+ Q_EMIT q->fileDeleted(path, QString(), DFileSystemWatcher::QPrivateSignal());
+ } while (false);
+ } else {
+ if (id < 0)
+ onDirectoryChanged(path, false);
+ else
+ onFileChanged(path, false);
+ }
+
+ QString filePath = path;
+
+ if (id < 0) {
+ if (path.endsWith(QDir::separator()))
+ filePath = path + name;
+ else
+ filePath = path + QDir::separator() + name;
+ }
+
+ if (event.mask & IN_CREATE) {
+// qDebug() << "IN_CREATE" << filePath << name;
+
+ if (name.isEmpty()) {
+ if (pathToID.contains(path)) {
+ q->removePath(path);
+ q->addPath(path);
+ }
+ } else if (pathToID.contains(filePath)) {
+ q->removePath(filePath);
+ q->addPath(filePath);
+ }
+
+ Q_EMIT q->fileCreated(path, name, DFileSystemWatcher::QPrivateSignal());
+ }
+
+ if (event.mask & IN_DELETE) {
+// qDebug() << "IN_DELETE" << filePath;
+
+ Q_EMIT q->fileDeleted(path, name, DFileSystemWatcher::QPrivateSignal());
+ }
+
+ if (event.mask & IN_MOVED_FROM) {
+ const QString &toPath = cookieToFilePath.value(event.cookie);
+ const QString toName = cookieToFileName.value(event.cookie);
+
+// qDebug() << "IN_MOVED_FROM" << filePath << "to path:" << toPath << "to name:" << toName;
+
+ Q_EMIT q->fileMoved(path, name, toPath, toName, DFileSystemWatcher::QPrivateSignal());
+ }
+
+ if (event.mask & IN_MOVED_TO) {
+// qDebug() << "IN_MOVED_TO" << filePath;
+
+ if (!hasMoveFromByCookie.contains(event.cookie))
+ Q_EMIT q->fileMoved(QString(), QString(), path, name, DFileSystemWatcher::QPrivateSignal());
+ }
+
+ if (event.mask & IN_ATTRIB) {
+// qDebug() << "IN_ATTRIB" << event.mask << filePath;
+
+ Q_EMIT q->fileAttributeChanged(path, name, DFileSystemWatcher::QPrivateSignal());
+ }
+
+ /*only monitor file close event which is opend by write mode*/
+ if (event.mask & IN_CLOSE_WRITE) {
+// qDebug() << "IN_CLOSE_WRITE" << event.mask << filePath;
+
+ Q_EMIT q->fileClosed(path, id < 0 ? name : QString(), DFileSystemWatcher::QPrivateSignal());
+ }
+
+ if (event.mask & IN_MODIFY) {
+// qDebug() << "IN_MODIFY" << event.mask << filePath << name;
+
+ Q_EMIT q->fileModified(path, name, DFileSystemWatcher::QPrivateSignal());
+ }
+ }
+}
+
+QString DFileSystemWatcherPrivate::getPathFromID(int id) const
+{
+ QHash<int, QString>::const_iterator i = idToPath.find(id);
+ while (i != idToPath.constEnd() && i.key() == id) {
+ if ((i + 1) == idToPath.constEnd() || (i + 1).key() != id) {
+ return i.value();
+ }
+ ++i;
+ }
+ return QString();
+}
+
+void DFileSystemWatcherPrivate::onFileChanged(const QString &path, bool removed)
+{
+ Q_Q(DFileSystemWatcher);
+ if (!files.contains(path)) {
+ // the path was removed after a change was detected, but before we delivered the signal
+ return;
+ }
+ if (removed) {
+ files.removeAll(path);
+ }
+// Q_EMIT q->fileChanged(path, DFileSystemWatcher::QPrivateSignal());
+}
+
+void DFileSystemWatcherPrivate::onDirectoryChanged(const QString &path, bool removed)
+{
+ Q_Q(DFileSystemWatcher);
+ if (!directories.contains(path)) {
+ // perhaps the path was removed after a change was detected, but before we delivered the signal
+ return;
+ }
+ if (removed) {
+ directories.removeAll(path);
+ }
+// Q_EMIT q->directoryChanged(path, DFileSystemWatcher::QPrivateSignal());
+}
+
+/*!
+ \class DFileSystemWatcher
+ \inmodule QtCore
+ \brief The DFileSystemWatcher class provides an interface for monitoring files and directories for modifications.
+ \ingroup io
+ \since 4.2
+ \reentrant
+
+ DFileSystemWatcher monitors the file system for changes to files
+ and directories by watching a list of specified paths.
+
+ Call addPath() to watch a particular file or directory. Multiple
+ paths can be added using the addPaths() function. Existing paths can
+ be removed by using the removePath() and removePaths() functions.
+
+ DFileSystemWatcher examines each path added to it. Files that have
+ been added to the DFileSystemWatcher can be accessed using the
+ files() function, and directories using the directories() function.
+
+ The fileChanged() signal is emitted when a file has been modified,
+ renamed or removed from disk. Similarly, the directoryChanged()
+ signal is emitted when a directory or its contents is modified or
+ removed. Note that DFileSystemWatcher stops monitoring files once
+ they have been renamed or removed from disk, and directories once
+ they have been removed from disk.
+
+ \note On systems running a Linux kernel without inotify support,
+ file systems that contain watched paths cannot be unmounted.
+
+ \note Windows CE does not support directory monitoring by
+ default as this depends on the file system driver installed.
+
+ \note The act of monitoring files and directories for
+ modifications consumes system resources. This implies there is a
+ limit to the number of files and directories your process can
+ monitor simultaneously. On all BSD variants, for
+ example, an open file descriptor is required for each monitored
+ file. Some system limits the number of open file descriptors to 256
+ by default. This means that addPath() and addPaths() will fail if
+ your process tries to add more than 256 files or directories to
+ the file system monitor. Also note that your process may have
+ other file descriptors open in addition to the ones for files
+ being monitored, and these other open descriptors also count in
+ the total. OS X uses a different backend and does not
+ suffer from this issue.
+
+
+ \sa QFile, QDir
+*/
+
+
+/*!
+ Constructs a new file system watcher object with the given \a parent.
+*/
+DFileSystemWatcher::DFileSystemWatcher(QObject *parent)
+ : QObject(parent)
+ , DObject()
+{
+ int fd = -1;
+#ifdef IN_CLOEXEC
+ fd = inotify_init1(IN_CLOEXEC);
+#endif
+ if (fd == -1) {
+ fd = inotify_init();
+ }
+
+ if (fd != -1)
+ d_d_ptr.reset(new DFileSystemWatcherPrivate(fd, this));
+}
+
+/*!
+ Constructs a new file system watcher object with the given \a parent
+ which monitors the specified \a paths list.
+*/
+DFileSystemWatcher::DFileSystemWatcher(const QStringList &paths, QObject *parent)
+ : DFileSystemWatcher(parent)
+{
+ addPaths(paths);
+}
+
+/*!
+ Destroys the file system watcher.
+*/
+DFileSystemWatcher::~DFileSystemWatcher()
+{ }
+
+/*!
+ Adds \a path to the file system watcher if \a path exists. The
+ path is not added if it does not exist, or if it is already being
+ monitored by the file system watcher.
+
+ If \a path specifies a directory, the directoryChanged() signal
+ will be emitted when \a path is modified or removed from disk;
+ otherwise the fileChanged() signal is emitted when \a path is
+ modified, renamed or removed.
+
+ If the watch was successful, true is returned.
+
+ Reasons for a watch failure are generally system-dependent, but
+ may include the resource not existing, access failures, or the
+ total watch count limit, if the platform has one.
+
+ \note There may be a system dependent limit to the number of
+ files and directories that can be monitored simultaneously.
+ If this limit is been reached, \a path will not be monitored,
+ and false is returned.
+
+ \sa addPaths(), removePath()
+*/
+bool DFileSystemWatcher::addPath(const QString &path)
+{
+ if (path.isEmpty()) {
+ qWarning("DFileSystemWatcher::addPath: path is empty");
+ return true;
+ }
+
+ QStringList paths = addPaths(QStringList(path));
+ return paths.isEmpty();
+}
+
+/*!
+ Adds each path in \a paths to the file system watcher. Paths are
+ not added if they not exist, or if they are already being
+ monitored by the file system watcher.
+
+ If a path specifies a directory, the directoryChanged() signal
+ will be emitted when the path is modified or removed from disk;
+ otherwise the fileChanged() signal is emitted when the path is
+ modified, renamed, or removed.
+
+ The return value is a list of paths that could not be watched.
+
+ Reasons for a watch failure are generally system-dependent, but
+ may include the resource not existing, access failures, or the
+ total watch count limit, if the platform has one.
+
+ \note There may be a system dependent limit to the number of
+ files and directories that can be monitored simultaneously.
+ If this limit has been reached, the excess \a paths will not
+ be monitored, and they will be added to the returned QStringList.
+
+ \sa addPath(), removePaths()
+*/
+QStringList DFileSystemWatcher::addPaths(const QStringList &paths)
+{
+ Q_D(DFileSystemWatcher);
+
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+
+ while (it.hasNext()) {
+ const QString &path = it.next();
+ if (path.isEmpty())
+ it.remove();
+ }
+
+ if (p.isEmpty()) {
+ qWarning("DFileSystemWatcher::addPaths: list is empty");
+ return QStringList();
+ }
+
+ if (d)
+ p = d->addPaths(p, &d->files, &d->directories);
+
+ return p;
+}
+
+/*!
+ Removes the specified \a path from the file system watcher.
+
+ If the watch is successfully removed, true is returned.
+
+ Reasons for watch removal failing are generally system-dependent,
+ but may be due to the path having already been deleted, for example.
+
+ \sa removePaths(), addPath()
+*/
+bool DFileSystemWatcher::removePath(const QString &path)
+{
+ if (path.isEmpty()) {
+ qWarning("DFileSystemWatcher::removePath: path is empty");
+ return true;
+ }
+
+ QStringList paths = removePaths(QStringList(path));
+ return paths.isEmpty();
+}
+
+/*!
+ Removes the specified \a paths from the file system watcher.
+
+ The return value is a list of paths which were not able to be
+ unwatched successfully.
+
+ Reasons for watch removal failing are generally system-dependent,
+ but may be due to the path having already been deleted, for example.
+
+ \sa removePath(), addPaths()
+*/
+QStringList DFileSystemWatcher::removePaths(const QStringList &paths)
+{
+ Q_D(DFileSystemWatcher);
+
+ QStringList p = paths;
+ QMutableListIterator<QString> it(p);
+
+ while (it.hasNext()) {
+ const QString &path = it.next();
+ if (path.isEmpty())
+ it.remove();
+ }
+
+ if (p.isEmpty()) {
+ qWarning("DFileSystemWatcher::removePaths: list is empty");
+ return QStringList();
+ }
+
+ if (d)
+ p = d->removePaths(p, &d->files, &d->directories);
+
+ return p;
+}
+
+/*!
+ \fn void DFileSystemWatcher::fileChanged(const QString &path)
+
+ This signal is emitted when the file at the specified \a path is
+ modified, renamed or removed from disk.
+
+ \sa directoryChanged()
+*/
+
+/*!
+ \fn void DFileSystemWatcher::directoryChanged(const QString &path)
+
+ This signal is emitted when the directory at a specified \a path
+ is modified (e.g., when a file is added or deleted) or removed
+ from disk. Note that if there are several changes during a short
+ period of time, some of the changes might not Q_EMIT this signal.
+ However, the last change in the sequence of changes will always
+ generate this signal.
+
+ \sa fileChanged()
+*/
+
+/*!
+ \fn QStringList DFileSystemWatcher::directories() const
+
+ Returns a list of paths to directories that are being watched.
+
+ \sa files()
+*/
+
+/*!
+ \fn QStringList DFileSystemWatcher::files() const
+
+ Returns a list of paths to files that are being watched.
+
+ \sa directories()
+*/
+
+QStringList DFileSystemWatcher::directories() const
+{
+ Q_D(const DFileSystemWatcher);
+
+ if (!d)
+ return QStringList();
+
+ return d->directories;
+}
+
+QStringList DFileSystemWatcher::files() const
+{
+ Q_D(const DFileSystemWatcher);
+
+ if (!d)
+ return QStringList();
+
+ return d->files;
+}
+
+DCORE_END_NAMESPACE
+
+#include "moc_dfilesystemwatcher.cpp"
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+
+#include "dfilesystemwatcher.h"
+#include "private/dfilesystemwatcher_win_p.h"
+
+DCORE_BEGIN_NAMESPACE
+
+DFileSystemWatcherPrivate::DFileSystemWatcherPrivate(int fd, DFileSystemWatcher *qq)
+ : DObjectPrivate(qq)
+{
+
+}
+
+DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate()
+{
+
+}
+
+/*!
+ \class DFileSystemWatcher
+ \inmodule QtCore
+ \brief The DFileSystemWatcher class provides an interface for monitoring files and directories for modifications.
+ \ingroup io
+ \since 4.2
+ \reentrant
+
+ DFileSystemWatcher monitors the file system for changes to files
+ and directories by watching a list of specified paths.
+
+ Call addPath() to watch a particular file or directory. Multiple
+ paths can be added using the addPaths() function. Existing paths can
+ be removed by using the removePath() and removePaths() functions.
+
+ DFileSystemWatcher examines each path added to it. Files that have
+ been added to the DFileSystemWatcher can be accessed using the
+ files() function, and directories using the directories() function.
+
+ The fileChanged() signal is emitted when a file has been modified,
+ renamed or removed from disk. Similarly, the directoryChanged()
+ signal is emitted when a directory or its contents is modified or
+ removed. Note that DFileSystemWatcher stops monitoring files once
+ they have been renamed or removed from disk, and directories once
+ they have been removed from disk.
+
+ \note On systems running a Linux kernel without inotify support,
+ file systems that contain watched paths cannot be unmounted.
+
+ \note Windows CE does not support directory monitoring by
+ default as this depends on the file system driver installed.
+
+ \note The act of monitoring files and directories for
+ modifications consumes system resources. This implies there is a
+ limit to the number of files and directories your process can
+ monitor simultaneously. On all BSD variants, for
+ example, an open file descriptor is required for each monitored
+ file. Some system limits the number of open file descriptors to 256
+ by default. This means that addPath() and addPaths() will fail if
+ your process tries to add more than 256 files or directories to
+ the file system monitor. Also note that your process may have
+ other file descriptors open in addition to the ones for files
+ being monitored, and these other open descriptors also count in
+ the total. OS X uses a different backend and does not
+ suffer from this issue.
+
+
+ \sa QFile, QDir
+*/
+
+
+/*!
+ Constructs a new file system watcher object with the given \a parent.
+*/
+DFileSystemWatcher::DFileSystemWatcher(QObject *parent)
+ : QObject(parent)
+ , DObject()
+{
+
+}
+
+/*!
+ Constructs a new file system watcher object with the given \a parent
+ which monitors the specified \a paths list.
+*/
+DFileSystemWatcher::DFileSystemWatcher(const QStringList &paths, QObject *parent)
+ : DFileSystemWatcher(parent)
+{
+ addPaths(paths);
+}
+
+/*!
+ Destroys the file system watcher.
+*/
+DFileSystemWatcher::~DFileSystemWatcher()
+{ }
+
+/*!
+ Adds \a path to the file system watcher if \a path exists. The
+ path is not added if it does not exist, or if it is already being
+ monitored by the file system watcher.
+
+ If \a path specifies a directory, the directoryChanged() signal
+ will be emitted when \a path is modified or removed from disk;
+ otherwise the fileChanged() signal is emitted when \a path is
+ modified, renamed or removed.
+
+ If the watch was successful, true is returned.
+
+ Reasons for a watch failure are generally system-dependent, but
+ may include the resource not existing, access failures, or the
+ total watch count limit, if the platform has one.
+
+ \note There may be a system dependent limit to the number of
+ files and directories that can be monitored simultaneously.
+ If this limit is been reached, \a path will not be monitored,
+ and false is returned.
+
+ \sa addPaths(), removePath()
+*/
+bool DFileSystemWatcher::addPath(const QString &path)
+{
+ return false;
+}
+
+/*!
+ Adds each path in \a paths to the file system watcher. Paths are
+ not added if they not exist, or if they are already being
+ monitored by the file system watcher.
+
+ If a path specifies a directory, the directoryChanged() signal
+ will be emitted when the path is modified or removed from disk;
+ otherwise the fileChanged() signal is emitted when the path is
+ modified, renamed, or removed.
+
+ The return value is a list of paths that could not be watched.
+
+ Reasons for a watch failure are generally system-dependent, but
+ may include the resource not existing, access failures, or the
+ total watch count limit, if the platform has one.
+
+ \note There may be a system dependent limit to the number of
+ files and directories that can be monitored simultaneously.
+ If this limit has been reached, the excess \a paths will not
+ be monitored, and they will be added to the returned QStringList.
+
+ \sa addPath(), removePaths()
+*/
+QStringList DFileSystemWatcher::addPaths(const QStringList &paths)
+{
+ return QStringList();
+}
+
+/*!
+ Removes the specified \a path from the file system watcher.
+
+ If the watch is successfully removed, true is returned.
+
+ Reasons for watch removal failing are generally system-dependent,
+ but may be due to the path having already been deleted, for example.
+
+ \sa removePaths(), addPath()
+*/
+bool DFileSystemWatcher::removePath(const QString &path)
+{
+ return false;
+}
+
+/*!
+ Removes the specified \a paths from the file system watcher.
+
+ The return value is a list of paths which were not able to be
+ unwatched successfully.
+
+ Reasons for watch removal failing are generally system-dependent,
+ but may be due to the path having already been deleted, for example.
+
+ \sa removePath(), addPaths()
+*/
+QStringList DFileSystemWatcher::removePaths(const QStringList &paths)
+{
+ return QStringList();
+}
+
+/*!
+ \fn void DFileSystemWatcher::fileChanged(const QString &path)
+
+ This signal is emitted when the file at the specified \a path is
+ modified, renamed or removed from disk.
+
+ \sa directoryChanged()
+*/
+
+/*!
+ \fn void DFileSystemWatcher::directoryChanged(const QString &path)
+
+ This signal is emitted when the directory at a specified \a path
+ is modified (e.g., when a file is added or deleted) or removed
+ from disk. Note that if there are several changes during a short
+ period of time, some of the changes might not Q_EMIT this signal.
+ However, the last change in the sequence of changes will always
+ generate this signal.
+
+ \sa fileChanged()
+*/
+
+/*!
+ \fn QStringList DFileSystemWatcher::directories() const
+
+ Returns a list of paths to directories that are being watched.
+
+ \sa files()
+*/
+
+/*!
+ \fn QStringList DFileSystemWatcher::files() const
+
+ Returns a list of paths to files that are being watched.
+
+ \sa directories()
+*/
+
+QStringList DFileSystemWatcher::directories() const
+{
+ return QStringList();
+}
+
+QStringList DFileSystemWatcher::files() const
+{
+ return QStringList();
+}
+
+DCORE_END_NAMESPACE
+
+#include "moc_dfilesystemwatcher.cpp"
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+
+#include "dfilewatcher.h"
+#include "private/dbasefilewatcher_p.h"
+
+#include "dfilesystemwatcher.h"
+
+#include <QDir>
+#include <QDebug>
+
+DCORE_BEGIN_NAMESPACE
+
+static QString joinFilePath(const QString &path, const QString &name)
+{
+ if (path.endsWith(QDir::separator()))
+ return path + name;
+
+ return path + QDir::separator() + name;
+}
+
+class DFileWatcherPrivate : DBaseFileWatcherPrivate
+{
+public:
+ DFileWatcherPrivate(DFileWatcher *qq)
+ : DBaseFileWatcherPrivate(qq) {}
+
+ bool start() Q_DECL_OVERRIDE;
+ bool stop() Q_DECL_OVERRIDE;
+
+ void _q_handleFileDeleted(const QString &path, const QString &parentPath);
+ void _q_handleFileAttributeChanged(const QString &path, const QString &parentPath);
+ void _q_handleFileMoved(const QString &from, const QString &fromParent, const QString &to, const QString &toParent);
+ void _q_handleFileCreated(const QString &path, const QString &parentPath);
+ void _q_handleFileModified(const QString &path, const QString &parentPath);
+ void _q_handleFileClose(const QString &path, const QString &parentPath);
+
+ static QString formatPath(const QString &path);
+
+ QString path;
+ QStringList watchFileList;
+
+ static QMap<QString, int> filePathToWatcherCount;
+
+ Q_DECLARE_PUBLIC(DFileWatcher)
+};
+
+QMap<QString, int> DFileWatcherPrivate::filePathToWatcherCount;
+Q_GLOBAL_STATIC(DFileSystemWatcher, watcher_file_private)
+
+QStringList parentPathList(const QString &path)
+{
+ QStringList list;
+ QDir dir(path);
+
+ list << path;
+
+ while (dir.cdUp()) {
+ list << dir.absolutePath();
+ }
+
+ return list;
+}
+
+bool DFileWatcherPrivate::start()
+{
+ Q_Q(DFileWatcher);
+
+ started = true;
+
+ Q_FOREACH (const QString &path, parentPathList(this->path)) {
+ if (watchFileList.contains(path))
+ continue;
+
+ if (filePathToWatcherCount.value(path, -1) <= 0) {
+ if (!watcher_file_private->addPath(path)) {
+ qWarning() << Q_FUNC_INFO << "start watch failed, file path =" << path;
+ q->stopWatcher();
+ started = false;
+ return false;
+ }
+ }
+
+ watchFileList << path;
+ filePathToWatcherCount[path] = filePathToWatcherCount.value(path, 0) + 1;
+ }
+
+ q->connect(watcher_file_private, &DFileSystemWatcher::fileDeleted,
+ q, &DFileWatcher::onFileDeleted);
+ q->connect(watcher_file_private, &DFileSystemWatcher::fileAttributeChanged,
+ q, &DFileWatcher::onFileAttributeChanged);
+ q->connect(watcher_file_private, &DFileSystemWatcher::fileMoved,
+ q, &DFileWatcher::onFileMoved);
+ q->connect(watcher_file_private, &DFileSystemWatcher::fileCreated,
+ q, &DFileWatcher::onFileCreated);
+ q->connect(watcher_file_private, &DFileSystemWatcher::fileModified,
+ q, &DFileWatcher::onFileModified);
+ q->connect(watcher_file_private, &DFileSystemWatcher::fileClosed,
+ q, &DFileWatcher::onFileClosed);
+
+ return true;
+}
+
+bool DFileWatcherPrivate::stop()
+{
+ Q_Q(DFileWatcher);
+
+ q->disconnect(watcher_file_private, 0, q, 0);
+
+ bool ok = true;
+
+ Q_FOREACH (const QString &path, watchFileList) {
+ int count = filePathToWatcherCount.value(path, 0);
+
+ --count;
+
+ if (count <= 0) {
+ filePathToWatcherCount.remove(path);
+ watchFileList.removeOne(path);
+ ok = ok && watcher_file_private->removePath(path);
+ } else {
+ filePathToWatcherCount[path] = count;
+ }
+ }
+
+ return ok;
+}
+
+void DFileWatcherPrivate::_q_handleFileDeleted(const QString &path, const QString &parentPath)
+{
+ if (path != this->path && parentPath != this->path)
+ return;
+
+ Q_Q(DFileWatcher);
+
+ Q_EMIT q->fileDeleted(QUrl::fromLocalFile(path));
+}
+
+void DFileWatcherPrivate::_q_handleFileAttributeChanged(const QString &path, const QString &parentPath)
+{
+ if (path != this->path && parentPath != this->path)
+ return;
+
+ Q_Q(DFileWatcher);
+
+ Q_EMIT q->fileAttributeChanged(QUrl::fromLocalFile(path));
+}
+
+void DFileWatcherPrivate::_q_handleFileMoved(const QString &from, const QString &fromParent, const QString &to, const QString &toParent)
+{
+ Q_Q(DFileWatcher);
+
+ if ((fromParent == this->path && toParent == this->path) || from == this->path) {
+ Q_EMIT q->fileMoved(QUrl::fromLocalFile(from), QUrl::fromLocalFile(to));
+ } else if (fromParent == this->path) {
+ Q_EMIT q->fileDeleted(QUrl::fromLocalFile(from));
+ } else if (watchFileList.contains(from)) {
+ Q_EMIT q->fileDeleted(url);
+ } else if (toParent == this->path) {
+ Q_EMIT q->subfileCreated(QUrl::fromLocalFile(to));
+ }
+}
+
+void DFileWatcherPrivate::_q_handleFileCreated(const QString &path, const QString &parentPath)
+{
+ if (path != this->path && parentPath != this->path)
+ return;
+
+ Q_Q(DFileWatcher);
+
+ Q_EMIT q->subfileCreated(QUrl::fromLocalFile(path));
+}
+
+void DFileWatcherPrivate::_q_handleFileModified(const QString &path, const QString &parentPath)
+{
+ if (path != this->path && parentPath != this->path)
+ return;
+
+ Q_Q(DFileWatcher);
+
+ Q_EMIT q->fileModified(QUrl::fromLocalFile(path));
+}
+
+void DFileWatcherPrivate::_q_handleFileClose(const QString &path, const QString &parentPath)
+{
+ if (path != this->path && parentPath != this->path)
+ return;
+
+ Q_Q(DFileWatcher);
+
+ Q_EMIT q->fileClosed(QUrl::fromLocalFile(path));
+}
+
+QString DFileWatcherPrivate::formatPath(const QString &path)
+{
+ QString p = QFileInfo(path).absoluteFilePath();
+
+ if (p.endsWith(QDir::separator()))
+ p.chop(1);
+
+ return p.isEmpty() ? path : p;
+}
+
+DFileWatcher::DFileWatcher(const QString &filePath, QObject *parent)
+ : DBaseFileWatcher(*new DFileWatcherPrivate(this), QUrl::fromLocalFile(filePath), parent)
+{
+ d_func()->path = DFileWatcherPrivate::formatPath(filePath);
+}
+
+void DFileWatcher::onFileDeleted(const QString &path, const QString &name)
+{
+ if (name.isEmpty())
+ d_func()->_q_handleFileDeleted(path, QString());
+ else
+ d_func()->_q_handleFileDeleted(joinFilePath(path, name), path);
+}
+
+void DFileWatcher::onFileAttributeChanged(const QString &path, const QString &name)
+{
+ if (name.isEmpty())
+ d_func()->_q_handleFileAttributeChanged(path, QString());
+ else
+ d_func()->_q_handleFileAttributeChanged(joinFilePath(path, name), path);
+}
+
+void DFileWatcher::onFileMoved(const QString &from, const QString &fname, const QString &to, const QString &tname)
+{
+ QString fromPath, fpPath;
+ QString toPath, tpPath;
+
+ if (fname.isEmpty()) {
+ fromPath = from;
+ } else {
+ fromPath = joinFilePath(from, fname);
+ fpPath = from;
+ }
+
+ if (tname.isEmpty()) {
+ toPath = to;
+ } else {
+ toPath = joinFilePath(to, tname);
+ tpPath = to;
+ }
+
+ d_func()->_q_handleFileMoved(fromPath, fpPath, toPath, tpPath);
+}
+
+void DFileWatcher::onFileCreated(const QString &path, const QString &name)
+{
+ d_func()->_q_handleFileCreated(joinFilePath(path, name), path);
+}
+
+void DFileWatcher::onFileModified(const QString &path, const QString &name)
+{
+ if (name.isEmpty())
+ d_func()->_q_handleFileModified(path, QString());
+ else
+ d_func()->_q_handleFileModified(joinFilePath(path, name), path);
+}
+
+void DFileWatcher::onFileClosed(const QString &path, const QString &name)
+{
+ if (name.isEmpty())
+ d_func()->_q_handleFileClose(path, QString());
+ else
+ d_func()->_q_handleFileClose(joinFilePath(path, name), path);
+}
+
+DCORE_END_NAMESPACE
+
+#include "moc_dfilewatcher.cpp"
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+
+#ifndef DFILEWATCHER_H
+#define DFILEWATCHER_H
+
+#include "dbasefilewatcher.h"
+
+DCORE_BEGIN_NAMESPACE
+
+class DFileWatcherPrivate;
+class DFileWatcher : public DBaseFileWatcher
+{
+ Q_OBJECT
+
+public:
+ explicit DFileWatcher(const QString &filePath, QObject *parent = 0);
+
+private Q_SLOTS:
+ void onFileDeleted(const QString &path, const QString &name);
+ void onFileAttributeChanged(const QString &path, const QString &name);
+ void onFileMoved(const QString &fromPath, const QString &fromName,
+ const QString &toPath, const QString &toName);
+ void onFileCreated(const QString &path, const QString &name);
+ void onFileModified(const QString &path, const QString &name);
+ void onFileClosed(const QString &path, const QString &name);
+
+private:
+ D_DECLARE_PRIVATE(DFileWatcher)
+};
+
+DCORE_END_NAMESPACE
+
+#endif // DFILEWATCHER_H
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+
+#include "dfilewatchermanager.h"
+#include "dfilewatcher.h"
+#include "base/private/dobject_p.h"
+
+#include <QMap>
+#include <QUrl>
+
+DCORE_BEGIN_NAMESPACE
+
+class DFileWatcherManagerPrivate : public DObjectPrivate
+{
+public:
+ DFileWatcherManagerPrivate(DFileWatcherManager *qq);
+
+ QMap<QString, DFileWatcher *> watchersMap;
+
+ D_DECLARE_PUBLIC(DFileWatcherManager)
+};
+
+DFileWatcherManagerPrivate::DFileWatcherManagerPrivate(DFileWatcherManager *qq)
+ : DObjectPrivate(qq)
+{
+
+}
+
+DFileWatcherManager::DFileWatcherManager(QObject *parent)
+ : QObject(parent)
+ , DObject(*new DFileWatcherManagerPrivate(this))
+{
+
+}
+
+DFileWatcherManager::~DFileWatcherManager()
+{
+
+}
+
+DFileWatcher *DFileWatcherManager::add(const QString &filePath)
+{
+ Q_D(DFileWatcherManager);
+
+ DFileWatcher *watcher = d->watchersMap.value(filePath);
+
+ if (watcher) {
+ return watcher;
+ }
+
+ watcher = new DFileWatcher(filePath, this);
+
+ connect(watcher, &DFileWatcher::fileAttributeChanged, this, [this](const QUrl & url) {
+ Q_EMIT fileAttributeChanged(url.toLocalFile());
+ });
+ connect(watcher, &DFileWatcher::fileClosed, this, [this](const QUrl & url) {
+ Q_EMIT fileClosed(url.toLocalFile());
+ });
+ connect(watcher, &DFileWatcher::fileDeleted, this, [this](const QUrl & url) {
+ Q_EMIT fileDeleted(url.toLocalFile());
+ });
+ connect(watcher, &DFileWatcher::fileModified, this, [this](const QUrl & url) {
+ Q_EMIT fileModified(url.toLocalFile());
+ });
+ connect(watcher, &DFileWatcher::fileMoved, this, [this](const QUrl & fromUrl, const QUrl & toUrl) {
+ Q_EMIT fileMoved(fromUrl.toLocalFile(), toUrl.toLocalFile());
+ });
+ connect(watcher, &DFileWatcher::subfileCreated, this, [this](const QUrl & url) {
+ Q_EMIT subfileCreated(url.toLocalFile());
+ });
+
+ d->watchersMap[filePath] = watcher;
+ watcher->startWatcher();
+
+ return watcher;
+}
+
+void DFileWatcherManager::remove(const QString &filePath)
+{
+ Q_D(DFileWatcherManager);
+
+ DFileWatcher *watcher = d->watchersMap.take(filePath);
+
+ if (watcher) {
+ watcher->deleteLater();
+ }
+}
+
+DCORE_END_NAMESPACE
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+
+#ifndef DFILEWATCHERMANAGER_H
+#define DFILEWATCHERMANAGER_H
+
+#include "dtkcore_global.h"
+#include "base/dobject.h"
+
+#include <QObject>
+
+DCORE_BEGIN_NAMESPACE
+
+class DFileWatcher;
+
+class DFileWatcherManagerPrivate;
+class DFileWatcherManager : public QObject, public DObject
+{
+ Q_OBJECT
+
+public:
+ explicit DFileWatcherManager(QObject *parent = 0);
+ ~DFileWatcherManager();
+
+ DFileWatcher *add(const QString &filePath);
+ void remove(const QString &filePath);
+
+Q_SIGNALS:
+ void fileDeleted(const QString &filePath);
+ void fileAttributeChanged(const QString &filePath);
+ void fileMoved(const QString &fromFilePath, const QString &toFilePath);
+ void subfileCreated(const QString &filePath);
+ void fileModified(const QString &filePath);
+ void fileClosed(const QString &filePath);
+
+private:
+ QScopedPointer<DFileWatcherManagerPrivate> d_ptr;
+
+ D_DECLARE_PRIVATE(DFileWatcherManager)
+ Q_DISABLE_COPY(DFileWatcherManager)
+};
+
+DCORE_END_NAMESPACE
+
+#endif // DFILEWATCHERMANAGER_H
--- /dev/null
+#pragma once
+
+#include <QDir>
+
+#include "dtkcore_global.h"
+
+DCORE_BEGIN_NAMESPACE
+
+class DPathBuf
+{
+public:
+ DPathBuf(const QString &path)
+ {
+ m_path = QDir(path).absolutePath();
+ }
+
+ DPathBuf operator/(const QString &p) const
+ {
+ return DPathBuf(m_path + "/" + p);
+ }
+
+ DPathBuf &operator/=(const QString &p)
+ {
+ return join(p);
+ }
+
+ DPathBuf operator/(const char *p) const
+ {
+ return operator /(QString(p));
+ }
+
+ DPathBuf &operator/=(const char *p)
+ {
+ return operator /=(QString(p));
+ }
+
+ DPathBuf &join(const QString &p)
+ {
+ m_path += "/" + p;
+ m_path = QDir(m_path).absolutePath();
+ return *this;
+ }
+
+ QString toString() const
+ {
+ return QDir::toNativeSeparators(m_path);
+ }
+
+private:
+ QString m_path;
+};
+
+DCORE_END_NAMESPACE
--- /dev/null
+include($$PWD/private/private.pri)
+
+HEADERS += \
+ $$PWD/dbasefilewatcher.h \
+ $$PWD/dfilesystemwatcher.h \
+ $$PWD/dfilewatcher.h \
+ $$PWD/dfilewatchermanager.h \
+ $$PWD/dpathbuf.h
+
+SOURCES += \
+ $$PWD/dbasefilewatcher.cpp \
+ $$PWD/dfilewatcher.cpp \
+ $$PWD/dfilewatchermanager.cpp
+
+
+linux {
+ CONFIG += link_pkgconfig
+ PKGCONFIG += gsettings-qt
+
+ SOURCES += \
+ $$PWD/dfilesystemwatcher_linux.cpp
+} else:win* {
+ SOURCES += \
+ $$PWD/dfilesystemwatcher_win.cpp
+} else:mac* {
+ SOURCES += \
+ $$PWD/dfilesystemwatcher_win.cpp
+}
+
+includes.files += $$PWD/*.h
+includes.files += $$PWD/*.cpp
+includes.files += \
+ $$PWD/DFileWatcher \
+ $$PWD/DBaseFileWatcher \
+ $$PWD/DFileSystemWatcher \
+ $$PWD/DFileWatcherManager \
+ $$PWD/DPathBuf
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+
+#ifndef DBASEFILEWATCHER_P_H
+#define DBASEFILEWATCHER_P_H
+
+#include "base/private/dobject_p.h"
+
+#include <QUrl>
+
+DCORE_BEGIN_NAMESPACE
+
+class DBaseFileWatcher;
+class DBaseFileWatcherPrivate : public DObjectPrivate
+{
+public:
+ DBaseFileWatcherPrivate(DBaseFileWatcher *qq);
+
+ virtual bool start() = 0;
+ virtual bool stop() = 0;
+
+ QUrl url;
+ bool started = false;
+ static QList<DBaseFileWatcher *> watcherList;
+
+ D_DECLARE_PUBLIC(DBaseFileWatcher)
+};
+
+DCORE_END_NAMESPACE
+
+#endif // DBASEFILEWATCHER_P_H
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+
+#ifndef DFILESYSTEMWATCHER_P_H
+#define DFILESYSTEMWATCHER_P_H
+
+#include "base/private/dobject_p.h"
+
+#include <QSocketNotifier>
+#include <QHash>
+#include <QMap>
+
+DCORE_BEGIN_NAMESPACE
+
+class DFileSystemWatcher;
+class DFileSystemWatcherPrivate : public DObjectPrivate
+{
+ Q_DECLARE_PUBLIC(DFileSystemWatcher)
+
+public:
+ DFileSystemWatcherPrivate(int fd, DFileSystemWatcher *qq);
+ ~DFileSystemWatcherPrivate();
+
+ QStringList addPaths(const QStringList &paths, QStringList *files, QStringList *directories);
+ QStringList removePaths(const QStringList &paths, QStringList *files, QStringList *directories);
+
+ QStringList files, directories;
+ int inotifyFd;
+ QHash<QString, int> pathToID;
+ QMultiHash<int, QString> idToPath;
+ QSocketNotifier notifier;
+
+ // private slots
+ void _q_readFromInotify();
+
+private:
+ QString getPathFromID(int id) const;
+ void onFileChanged(const QString &path, bool removed);
+ void onDirectoryChanged(const QString &path, bool removed);
+};
+
+DCORE_END_NAMESPACE
+
+#endif // DFILESYSTEMWATCHER_P_H
--- /dev/null
+/**
+ * Copyright (C) 2017 Deepin Technology Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ **/
+#ifndef DFILESYSTEMWATCHER_WIN_P_H
+#define DFILESYSTEMWATCHER_WIN_P_H
+
+#include "base/private/dobject_p.h"
+
+DCORE_BEGIN_NAMESPACE
+
+class DFileSystemWatcher;
+class DFileSystemWatcherPrivate : public DObjectPrivate
+{
+ Q_DECLARE_PUBLIC(DFileSystemWatcher)
+
+public:
+ DFileSystemWatcherPrivate(int fd, DFileSystemWatcher *qq);
+ ~DFileSystemWatcherPrivate();
+
+ // private slots
+ void _q_readFromInotify();
+};
+
+void DFileSystemWatcherPrivate::_q_readFromInotify()
+{
+
+}
+
+DCORE_END_NAMESPACE
+
+#endif // DFILESYSTEMWATCHER_WIN_P_H
--- /dev/null
+HEADERS += \
+ $$PWD/dbasefilewatcher_p.h
+
+linux {
+ HEADERS += \
+ $$PWD/dfilesystemwatcher_linux_p.h
+} else:win* {
+ HEADERS += \
+ $$PWD/dfilesystemwatcher_win_p.h
+}
includes.path = $${DTK_INCLUDEPATH}/DCore
-includes.files += $$PWD/base/*.h
-includes.files += $$PWD/base/*.cpp
-includes.files += \
- $$PWD/base/DObject \
- $$PWD/base/DSingleton
-
-includes.files += $$PWD/log/*.h
-includes.files += $$PWD/log/*.cpp
-includes.files += \
- $$PWD/log/DLog
INSTALLS += includes target
-
QMAKE_PKGCONFIG_LIBDIR = $$target.path
QMAKE_PKGCONFIG_VERSION = $$VERSION
QMAKE_PKGCONFIG_DESTDIR = pkgconfig
include(cutelogger.pri)
+
+includes.files += $$PWD/*.h
+includes.files += $$PWD/*.cpp
+includes.files += \
+ $$PWD/DLog
include($$PWD/lib.pri)
-include($$PWD/install.pri)
QT -= gui
+QT += dbus
TARGET = dtkcore
HEADERS += \
$$PWD/dtkcore_global.h \
-include($$PWD/base/dbase.pri)
+include($$PWD/base/base.pri)
include($$PWD/log/log.pri)
+include($$PWD/filesystem/filesystem.pri)
+
+include($$PWD/install.pri)
+