forked from quickshell/quickshell
io/fileview: add support for watching changes
This commit is contained in:
parent
ccf885081c
commit
69d13967c9
2 changed files with 71 additions and 3 deletions
|
@ -6,6 +6,7 @@
|
|||
#include <qdir.h>
|
||||
#include <qfiledevice.h>
|
||||
#include <qfileinfo.h>
|
||||
#include <qfilesystemwatcher.h>
|
||||
#include <qlogging.h>
|
||||
#include <qloggingcategory.h>
|
||||
#include <qmutex.h>
|
||||
|
@ -280,7 +281,6 @@ void FileViewWriter::write(
|
|||
if (shouldCancel.loadAcquire()) return;
|
||||
|
||||
if (doAtomicWrite) {
|
||||
qDebug() << "Atomic commit";
|
||||
if (!reinterpret_cast<QSaveFile*>(file.get())->commit()) { // NOLINT
|
||||
qmlWarning(view) << "Write of " << state.path << " failed: Atomic commit failed.";
|
||||
}
|
||||
|
@ -477,6 +477,49 @@ void FileView::updatePath() {
|
|||
} else {
|
||||
this->emitDataChanged();
|
||||
}
|
||||
|
||||
this->updateWatchedFiles();
|
||||
}
|
||||
|
||||
void FileView::updateWatchedFiles() {
|
||||
delete this->watcher;
|
||||
|
||||
if (!this->targetPath.isEmpty() && this->bWatchChanges) {
|
||||
qCDebug(logFileView) << "Creating watcher for" << this << "at" << this->targetPath;
|
||||
this->watcher = new QFileSystemWatcher(this);
|
||||
this->watcher->addPath(this->targetPath);
|
||||
this->watcher->addPath(QDir(this->targetPath).dirName());
|
||||
|
||||
QObject::connect(
|
||||
this->watcher,
|
||||
&QFileSystemWatcher::fileChanged,
|
||||
this,
|
||||
&FileView::onWatchedFileChanged
|
||||
);
|
||||
|
||||
QObject::connect(
|
||||
this->watcher,
|
||||
&QFileSystemWatcher::directoryChanged,
|
||||
this,
|
||||
&FileView::onWatchedDirectoryChanged
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void FileView::onWatchedFileChanged() {
|
||||
if (!this->watcher->files().contains(this->targetPath)) {
|
||||
this->watcher->addPath(this->targetPath);
|
||||
}
|
||||
|
||||
emit this->fileChanged();
|
||||
}
|
||||
|
||||
void FileView::onWatchedDirectoryChanged() {
|
||||
if (!this->watcher->files().contains(this->targetPath) && QFileInfo(this->targetPath).exists()) {
|
||||
// the file was just created
|
||||
this->watcher->addPath(this->targetPath);
|
||||
emit this->fileChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool FileView::shouldBlockRead() const {
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <qatomic.h>
|
||||
#include <qdebug.h>
|
||||
#include <qfilesystemwatcher.h>
|
||||
#include <qlogging.h>
|
||||
#include <qmutex.h>
|
||||
#include <qobject.h>
|
||||
|
@ -187,13 +188,13 @@ class FileView: public QObject {
|
|||
/// > [!WARNING] We cannot think of a valid use case for this.
|
||||
/// > You almost definitely want @@blockLoading.
|
||||
QSDOC_PROPERTY_OVERRIDE(bool blockAllReads READ blockAllReads WRITE setBlockAllReads NOTIFY blockAllReadsChanged);
|
||||
/// If true (default false), all calls to @@setText or @@setData will block the
|
||||
/// If true (default false), all calls to @@setText() or @@setData() will block the
|
||||
/// UI thread until the write succeeds or fails.
|
||||
///
|
||||
/// > [!WARNING] Blocking operations should be used carefully to avoid stutters and other performance
|
||||
/// > degradations. Blocking means that your interface **WILL NOT FUNCTION** during the call.
|
||||
Q_PROPERTY(bool blockWrites READ default WRITE default NOTIFY blockWritesChanged BINDABLE bindableBlockWrites);
|
||||
/// If true (default), all calls to @@setText or @@setData will be performed atomically,
|
||||
/// If true (default), all calls to @@setText() or @@setData() will be performed atomically,
|
||||
/// meaning if the write fails for any reason, the file will not be modified.
|
||||
///
|
||||
/// > [!NOTE] This works by creating another file with the desired content, and renaming
|
||||
|
@ -202,6 +203,18 @@ class FileView: public QObject {
|
|||
/// If true (default), read or write errors will be printed to the quickshell logs.
|
||||
/// If false, all known errors will not be printed.
|
||||
QSDOC_PROPERTY_OVERRIDE(bool printErrors READ default WRITE default NOTIFY printErrorsChanged);
|
||||
/// If true (defaule false), @@fileChanged() will be called whenever the content of the file
|
||||
/// changes on disk, including when @@setText() or @@setData() are used.
|
||||
///
|
||||
/// > [!NOTE] You can reload the file's content whenever it changes on disk like so:
|
||||
/// > ```qml
|
||||
/// > FileView {
|
||||
/// > // ...
|
||||
/// > watchChanges: true
|
||||
/// > onFileChanged: this.reload()
|
||||
/// > }
|
||||
/// > ```
|
||||
Q_PROPERTY(bool watchChanges READ default WRITE default NOTIFY watchChangesChanged BINDABLE bindableWatchChanges);
|
||||
|
||||
QSDOC_HIDE Q_PROPERTY(QString __path READ path WRITE setPath NOTIFY pathChanged);
|
||||
QSDOC_HIDE Q_PROPERTY(QString __text READ text NOTIFY internalTextChanged);
|
||||
|
@ -297,6 +310,7 @@ public:
|
|||
[[nodiscard]] QBindable<bool> bindableAtomicWrites() { return &this->bAtomicWrites; }
|
||||
|
||||
[[nodiscard]] QBindable<bool> bindablePrintErrors() { return &this->bPrintErrors; }
|
||||
[[nodiscard]] QBindable<bool> bindableWatchChanges() { return &this->bWatchChanges; }
|
||||
|
||||
signals:
|
||||
/// Emitted if the file was loaded successfully.
|
||||
|
@ -307,6 +321,8 @@ signals:
|
|||
void saved();
|
||||
/// Emitted if the file failed to save.
|
||||
void saveFailed(qs::io::FileViewError::Enum error);
|
||||
/// Emitted if the file changes on disk and @@watchChanges is true.
|
||||
void fileChanged();
|
||||
|
||||
void pathChanged();
|
||||
QSDOC_HIDE void internalTextChanged();
|
||||
|
@ -320,6 +336,7 @@ signals:
|
|||
void blockWritesChanged();
|
||||
void atomicWritesChanged();
|
||||
void printErrorsChanged();
|
||||
void watchChangesChanged();
|
||||
|
||||
private slots:
|
||||
void operationFinished();
|
||||
|
@ -332,6 +349,9 @@ private:
|
|||
void saveSync();
|
||||
void updateState(FileViewState& newState);
|
||||
void updatePath();
|
||||
void updateWatchedFiles();
|
||||
void onWatchedFileChanged();
|
||||
void onWatchedDirectoryChanged();
|
||||
|
||||
[[nodiscard]] bool shouldBlockRead() const;
|
||||
[[nodiscard]] FileViewReader* liveReader() const;
|
||||
|
@ -353,6 +373,8 @@ private:
|
|||
bool mBlockLoading = false;
|
||||
bool mBlockAllReads = false;
|
||||
|
||||
QFileSystemWatcher* watcher = nullptr;
|
||||
|
||||
GuardedEmitter<&FileView::internalTextChanged> textChangedEmitter;
|
||||
GuardedEmitter<&FileView::internalDataChanged> dataChangedEmitter;
|
||||
void emitDataChanged();
|
||||
|
@ -374,8 +396,11 @@ public:
|
|||
Q_OBJECT_BINDABLE_PROPERTY(FileView, bool, bBlockWrites, &FileView::blockWritesChanged);
|
||||
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(FileView, bool, bAtomicWrites, true, &FileView::atomicWritesChanged);
|
||||
Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS(FileView, bool, bPrintErrors, true, &FileView::printErrorsChanged);
|
||||
Q_OBJECT_BINDABLE_PROPERTY(FileView, bool, bWatchChanges, &FileView::watchChangesChanged);
|
||||
// clang-format on
|
||||
|
||||
QS_BINDING_SUBSCRIBE_METHOD(FileView, bWatchChanges, updateWatchedFiles, onValueChanged);
|
||||
|
||||
void setPreload(bool preload);
|
||||
void setBlockLoading(bool blockLoading);
|
||||
void setBlockAllReads(bool blockAllReads);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue