--- a/src/eric7/Project/ProjectBrowserModel.py Tue Mar 26 10:55:04 2024 +0100 +++ b/src/eric7/Project/ProjectBrowserModel.py Wed Apr 10 17:03:56 2024 +0200 @@ -11,10 +11,11 @@ import os import re -from PyQt6.QtCore import QDir, QFileSystemWatcher, QModelIndex, Qt, pyqtSignal +from PyQt6.QtCore import QDir, QModelIndex, Qt, pyqtSignal from PyQt6.QtGui import QColor from eric7 import Preferences +from eric7.EricCore import EricFileSystemWatcher from eric7.SystemUtilities import FileSystemUtilities from eric7.UI.BrowserModel import ( BrowserDirectoryItem, @@ -240,10 +241,14 @@ self.__remotefsInterface = fsInterface - self.watchedItems = {} + self.watchedDirItems = {} + self.__watcherActive = True - self.watcher = QFileSystemWatcher(self) - self.watcher.directoryChanged.connect(self.directoryChanged) + watcher = EricFileSystemWatcher.instance() + watcher.directoryCreated.connect(lambda x: self.entryCreated(x, isDir=True)) + watcher.directoryDeleted.connect(lambda x: self.entryDeleted(x, isDir=True)) + watcher.fileCreated.connect(lambda x: self.entryCreated(x, isDir=False)) + watcher.fileDeleted.connect(lambda x: self.entryDeleted(x, isDir=False)) self.inRefresh = False @@ -449,10 +454,11 @@ """ self.__vcsStatus = {} - self.watchedItems = {} - watchedDirs = self.watcher.directories() - if watchedDirs: - self.watcher.removePaths(watchedDirs) + paths = list(self.watchedDirItems.keys()) + if paths: + watcher = EricFileSystemWatcher.instance() + watcher.removePaths(paths) + self.watchedDirItems.clear() self.rootItem.removeChildren() self.beginResetModel() @@ -773,92 +779,63 @@ """ self.__watcherActive = False - def directoryChanged(self, path): + def entryCreated(self, path, isDir=False): """ - Public slot to handle the directoryChanged signal of the watcher. + Public method to handle the creation of a file or directory. - @param path path of the directory + @param path path of the created file or directory @type str + @param isDir flag indicating a created directory (defaults to False) + @type bool (optional) """ if not self.__watcherActive: return - if path not in self.watchedItems: + parentPath = os.path.dirname(path) + if parentPath not in self.watchedDirItems: # just ignore the situation we don't have a reference to the item return - fileFilter = ( - (QDir.Filter.AllEntries | QDir.Filter.Hidden | QDir.Filter.NoDotAndDotDot) - if Preferences.getProject("BrowsersListHiddenFiles") - else QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot - ) - - for itm in self.watchedItems[path]: - oldCnt = itm.childCount() - - qdir = QDir(itm.dirName()) - - entryInfoList = qdir.entryInfoList(fileFilter) - - # step 1: check for new entries - children = itm.children() - for f in entryInfoList: - fpath = FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()) - childFound = False - for child in children[:]: - if child.name() == fpath: - childFound = True - children.remove(child) - break - if childFound: - continue + if not Preferences.getProject("BrowsersListHiddenFiles") and os.path.basename( + path + ).startswith("."): + return - cnt = itm.childCount() - self.beginInsertRows(self.createIndex(itm.row(), 0, itm), cnt, cnt) - node = ( - ProjectBrowserDirectoryItem( - itm, - FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), - itm.getProjectTypes()[0], - False, - fsInterface=self.__remotefsInterface, - ) - if f.isDir() - else ProjectBrowserFileItem( - itm, - FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), - itm.getProjectTypes()[0], - fsInterface=self.__remotefsInterface, - ) + for itm in self.watchedDirItems[parentPath]: + cnt = itm.childCount() + self.beginInsertRows(self.createIndex(itm.row(), 0, itm), cnt, cnt) + node = ( + ProjectBrowserDirectoryItem( + itm, + FileSystemUtilities.toNativeSeparators(path), + itm.getProjectTypes()[0], + False, + fsInterface=self.__remotefsInterface, + ) + if isDir + else ProjectBrowserFileItem( + itm, + FileSystemUtilities.toNativeSeparators(path), + itm.getProjectTypes()[0], + fsInterface=self.__remotefsInterface, ) - self._addItem(node, itm) - if self.project.vcs is not None: - self.project.vcs.clearStatusCache() - state = self.project.vcs.vcsRegisteredState(node.name()) - if state == VersionControlState.Controlled: - node.addVcsStatus(self.project.vcs.vcsName()) - else: - node.addVcsStatus(self.tr("local")) - self.endInsertRows() + ) + self._addItem(node, itm) + self.endInsertRows() + + def entryDeleted(self, path, isDir=False): + """ + Public method to handle the deletion of a file or directory. - # step 2: check for removed entries - if len(entryInfoList) != itm.childCount(): - for row in range(oldCnt - 1, -1, -1): - child = itm.child(row) - childname = FileSystemUtilities.fromNativeSeparators(child.name()) - entryFound = False - for f in entryInfoList[:]: - if f.absoluteFilePath() == childname: - entryFound = True - entryInfoList.remove(f) - break - if entryFound: - continue + @param path path of the deleted file or directory + @type str + @param isDir flag indicating a deleted directory (defaults to False) + @type bool (optional) + """ + if not self.__watcherActive: + return - self._removeWatchedItem(child) - self.beginRemoveRows(self.createIndex(itm.row(), 0, itm), row, row) - itm.removeChild(child) - self.endRemoveRows() + super().entryDeleted(path, isDir=isDir) def __addVCSStatus(self, item, name): """ @@ -963,6 +940,8 @@ self.beginRemoveRows(index, 0, itm.childCount() - 1) itm.removeChildren() self.endRemoveRows() + + # reset the module parser cache ModuleParser.resetParsedModule(os.path.join(self.project.ppath, name)) self.populateItem(itm, True)