diff --git a/krusader/Panel/krview.h b/krusader/Panel/krview.h --- a/krusader/Panel/krview.h +++ b/krusader/Panel/krview.h @@ -229,6 +229,7 @@ void cleared(); void fileAdded(vfile *vf); + void fileDeleted(const QString& name); void fileUpdated(vfile *vf); protected: diff --git a/krusader/Panel/krview.cpp b/krusader/Panel/krview.cpp --- a/krusader/Panel/krview.cpp +++ b/krusader/Panel/krview.cpp @@ -94,6 +94,11 @@ _view->addItem(vf); } +void KrViewOperator::fileDeleted(const QString& name) +{ + _view->delItem(name); +} + void KrViewOperator::fileUpdated(vfile *vf) { _view->updateItem(vf); @@ -1045,6 +1050,7 @@ QObject::connect(_files, SIGNAL(cleared()), op(), SLOT(cleared())); QObject::connect(_files, SIGNAL(addedVfile(vfile*)), op(), SLOT(fileAdded(vfile*))); QObject::connect(_files, SIGNAL(updatedVfile(vfile*)), op(), SLOT(fileUpdated(vfile*))); + QObject::connect(_files, SIGNAL(deletedVfile(const QString&)), op(), SLOT(fileDeleted(const QString&))); } void KrView::setFilter(KrViewProperties::FilterSpec filter, FilterSettings customFilter, bool applyToDirs) diff --git a/krusader/VFS/default_vfs.h b/krusader/VFS/default_vfs.h --- a/krusader/VFS/default_vfs.h +++ b/krusader/VFS/default_vfs.h @@ -79,7 +79,7 @@ /// Handle result after dir listing job is finished void slotListResult(KJob *job); /// Fill directory file list with new files from the dir lister - void slotAddFiles(KIO::Job *job, const KIO::UDSEntryList &entries); + void slotAddPendingFiles(KIO::Job *job, const KIO::UDSEntryList &entries); /// URL redirection signal from dir lister void slotRedirection(KIO::Job *job, const QUrl &url); // React to filesystem changes nofified by watcher diff --git a/krusader/VFS/default_vfs.cpp b/krusader/VFS/default_vfs.cpp --- a/krusader/VFS/default_vfs.cpp +++ b/krusader/VFS/default_vfs.cpp @@ -189,7 +189,7 @@ // start the listing job KIO::ListJob *job = KIO::listDir(_currentDirectory, KIO::HideProgressInfo, showHidden); connect(job, SIGNAL(entries(KIO::Job *, const KIO::UDSEntryList &)), this, - SLOT(slotAddFiles(KIO::Job *, const KIO::UDSEntryList &))); + SLOT(slotAddPendingFiles(KIO::Job *, const KIO::UDSEntryList &))); connect(job, &KIO::ListJob::redirection, this, &default_vfs::slotRedirection); connect(job, &KIO::ListJob::permanentRedirection, this, &default_vfs::slotRedirection); connect(job, SIGNAL(result(KJob*)), this, SLOT(slotListResult(KJob*))); @@ -221,12 +221,12 @@ } } -void default_vfs::slotAddFiles(KIO::Job *, const KIO::UDSEntryList& entries) +void default_vfs::slotAddPendingFiles(KIO::Job *, const KIO::UDSEntryList& entries) { for (const KIO::UDSEntry entry : entries) { vfile *vfile = vfs::createVFileFromKIO(entry, _currentDirectory); if (vfile) { - addVfile(vfile); + addPendingVfile(vfile); } } } @@ -337,7 +337,7 @@ if (name == "." || name == "..") continue; vfile* temp = createLocalVFile(name); - addVfile(temp); + addPendingVfile(temp); } // clean up QT_CLOSEDIR(dir); diff --git a/krusader/VFS/vfilecontainer.h b/krusader/VFS/vfilecontainer.h --- a/krusader/VFS/vfilecontainer.h +++ b/krusader/VFS/vfilecontainer.h @@ -48,6 +48,7 @@ void addedVfile(vfile *vf); void updatedVfile(vfile *vf); + void deletedVfile(const QString&); }; #endif // VFILECONTAINER_H diff --git a/krusader/VFS/vfs.h b/krusader/VFS/vfs.h --- a/krusader/VFS/vfs.h +++ b/krusader/VFS/vfs.h @@ -154,6 +154,7 @@ /// If the directory was read true is returned else false. // optional TODO: add an async version of this bool refresh(const QUrl &directory = QUrl()); + void storeAndEmitUpdates(const bool dirChange); /// Notify this VFS that the current directory content may have changed. void mayRefresh(); @@ -175,7 +176,9 @@ /// Returns true if showing hidden files is set in config. bool showHiddenFiles(); - /// Add a new vfile to the internal dictionary (while refreshing). + /// Add a new vfile to the pending internal dictionary (while refreshing). + inline void addPendingVfile(vfile *vf) { _pendingVfiles.insert(vf->vfile_getName(), vf); } + /// Add a new vfile to the internal dictionary. inline void addVfile(vfile *vf) { _vfiles.insert(vf->vfile_getName(), vf); } /// Calculate the size of a file or directory (recursive). @@ -212,10 +215,15 @@ private: /// Delete and clear vfiles. - void clear(vfileDict vfiles); + void clear(vfileDict &vfiles); vfileDict _vfiles; // The list of files in the current dictionary + // Fresh list of files to replace _vfiles. + // They are used to determine "diff" between _vfiles and _pendingVfiles. + // The information is then used to emit selective changes to KrView. + vfileDict _pendingVfiles; + // used in the calcSpace function bool *_calcKdsBusy; bool _calcStatBusy; diff --git a/krusader/VFS/vfs.cpp b/krusader/VFS/vfs.cpp --- a/krusader/VFS/vfs.cpp +++ b/krusader/VFS/vfs.cpp @@ -119,7 +119,6 @@ bool vfs::refresh(const QUrl &directory) { - if (_isRefreshing) { // NOTE: this does not happen (unless async)"; return false; @@ -136,30 +135,88 @@ _isRefreshing = true; - vfileDict tempVfiles(_vfiles); // old vfiles are still used during refresh - _vfiles.clear(); if (dirChange) // show an empty directory while loading the new one and clear selection emit cleared(); const bool res = refreshInternal(toRefresh, showHiddenFiles()); - _isRefreshing = false; if (!res) { // cleanup and abort + clear(_pendingVfiles); + clear(_vfiles); + _isRefreshing = false; if (!dirChange) emit cleared(); - clear(tempVfiles); return false; } - emit refreshDone(dirChange); + // makes changes in _vfiles + // emit those changes + // also clears _pendingVfiles + storeAndEmitUpdates(dirChange); - clear(tempVfiles); + _isRefreshing = false; return true; } +void vfs::storeAndEmitUpdates(const bool dirChange) +{ + int allowedNumberOfChanges = 10; + + // check if the maximum incremental refresh number is not exceeded + int numberOfChanges = _vfiles.count() - _pendingVfiles.count(); + if (numberOfChanges < 0) + numberOfChanges = -numberOfChanges; + if (dirChange || numberOfChanges > allowedNumberOfChanges) { + + _vfiles.swap(_pendingVfiles); + + // emit full refresh + emit refreshDone(dirChange); + + clear(_pendingVfiles); + return; + } + + // find and emit delete or update changes + for (const QString &name : QStringList(_vfiles.keys())) { + vfile* vf = _vfiles[name]; + if (!vf) { + // this is needed when renaming a file, but why?! + continue; + } + vfile* newVf = _pendingVfiles.take(name); + + if (!newVf) { + + // the file was deleted.. + emit deletedVfile(name); + delete vf; + _vfiles.remove(name); + } else { + if (*vf != *newVf) { + + // the file was changed.. + *vf = *newVf; + emit updatedVfile(vf); + } + } + + delete newVf; + } + + // everything left is a new file + for (vfile* newVf : _pendingVfiles.values()) { + addVfile(newVf); + emit addedVfile(newVf); + } + + // clear the list of pointers in _pendingVfiles + _pendingVfiles.clear(); +} + void vfs::mayRefresh() { if (ignoreRefresh()) { @@ -420,7 +477,7 @@ // ==== private ==== -void vfs::clear(vfileDict vfiles) +void vfs::clear(vfileDict &vfiles) { QHashIterator lit(vfiles); while (lit.hasNext()) { diff --git a/krusader/VFS/virt_vfs.cpp b/krusader/VFS/virt_vfs.cpp --- a/krusader/VFS/virt_vfs.cpp +++ b/krusader/VFS/virt_vfs.cpp @@ -247,7 +247,7 @@ if (!vf) { // remove URL from the list for a file that no longer exists it.remove(); } else { - addVfile(vf); + addPendingVfile(vf); } }