--- a/src/eric7/UI/BrowserModel.py Tue Mar 26 10:55:04 2024 +0100 +++ b/src/eric7/UI/BrowserModel.py Wed Apr 10 17:03:56 2024 +0200 @@ -17,7 +17,6 @@ QAbstractItemModel, QCoreApplication, QDir, - QFileSystemWatcher, QModelIndex, QProcess, Qt, @@ -26,6 +25,7 @@ from PyQt6.QtWidgets import QApplication from eric7 import Preferences +from eric7.EricCore import EricFileSystemWatcher from eric7.EricGui import EricPixmapCache from eric7.SystemUtilities import FileSystemUtilities from eric7.Utilities import ClassBrowsers @@ -84,11 +84,14 @@ self.__remotefsInterface = fsInterface if not nopopulate: - self.watchedItems = {} + self.watchedDirItems = {} self.watchedFileItems = {} - self.watcher = QFileSystemWatcher(self) - self.watcher.directoryChanged.connect(self.directoryChanged) - self.watcher.fileChanged.connect(self.fileChanged) + 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)) + watcher.fileModified.connect(self.fileChanged) rootData = QCoreApplication.translate("BrowserModel", "Name") self.rootItem = BrowserItem(None, rootData) @@ -334,13 +337,12 @@ and not FileSystemUtilities.isRemoteFileName(dirName) and not dirName.startswith(("//", "\\\\")) ): - if dirName not in self.watcher.directories(): - self.watcher.addPath(dirName) - if dirName in self.watchedItems: - if itm not in self.watchedItems[dirName]: - self.watchedItems[dirName].append(itm) + EricFileSystemWatcher.instance().addPath(dirName) + if dirName in self.watchedDirItems: + if itm not in self.watchedDirItems[dirName]: + self.watchedDirItems[dirName].append(itm) else: - self.watchedItems[dirName] = [itm] + self.watchedDirItems[dirName] = [itm] def _removeWatchedItem(self, itm): """ @@ -353,81 +355,66 @@ dirName = itm.dirName() with contextlib.suppress(KeyError): with contextlib.suppress(ValueError): - self.watchedItems[dirName].remove(itm) - if len(self.watchedItems[dirName]) == 0: - del self.watchedItems[dirName] - self.watcher.removePath(dirName) + self.watchedDirItems[dirName].remove(itm) + if len(self.watchedDirItems[dirName]) == 0: + del self.watchedDirItems[dirName] + EricFileSystemWatcher.instance().removePath(dirName) - 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 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 - dirFilter = ( - QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot | QDir.Filter.Hidden - ) - - for itm in self.watchedItems[path]: - oldCnt = itm.childCount() - - qdir = QDir(itm.dirName()) - - entryInfoList = qdir.entryInfoList(dirFilter) - - # 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 + for itm in self.watchedDirItems[parentPath]: + cnt = itm.childCount() + self.beginInsertRows(self.createIndex(itm.row(), 0, itm), cnt, cnt) + node = ( + BrowserDirectoryItem( + itm, + FileSystemUtilities.toNativeSeparators(path), + False, + ) + if isDir + else BrowserFileItem( + itm, + FileSystemUtilities.toNativeSeparators(path), + ) + ) + self._addItem(node, itm) + self.endInsertRows() - cnt = itm.childCount() - self.beginInsertRows(self.createIndex(itm.row(), 0, itm), cnt, cnt) - node = ( - BrowserDirectoryItem( - itm, - FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), - False, - ) - if f.isDir() - else BrowserFileItem( - itm, - FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()), - ) - ) - self._addItem(node, itm) - self.endInsertRows() + def entryDeleted(self, path, isDir=False): # noqa: U100 + """ + 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) + """ + 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 + for itm in self.watchedDirItems[parentPath]: + for row in range(itm.childCount() - 1, -1, -1): + child = itm.child(row) + if child.name() == path: self._removeWatchedItem(child) self.beginRemoveRows(self.createIndex(itm.row(), 0, itm), row, row) itm.removeChild(child) self.endRemoveRows() + break def __populateModel(self): """ @@ -843,7 +830,8 @@ and fileName not in self.watchedFileItems ): # watch the file only in the file browser not the project viewer - self.watcher.addPath(fileName) + watcher = EricFileSystemWatcher.instance() + watcher.addPath(fileName) self.watchedFileItems[fileName] = parentItem def repopulateFileItem(self, itm): @@ -879,6 +867,8 @@ self.repopulateFileItem(self.watchedFileItems[fileName]) else: # the file does not exist anymore + watcher = EricFileSystemWatcher.instance() + watcher.removePath(fileName) del self.watchedFileItems[fileName] def populateClassItem(self, parentItem, repopulate=False): @@ -1204,6 +1194,24 @@ """ return self.symlink + def lineno(self): + """ + Public method to return the line number of the item. + + @return line number defining the object + @rtype int + """ + return 0 # just a placeholder implementation + + def colOffset(self): + """ + Public method to return the column offset of the item definition. + + @return column offset defining the object + @rtype int + """ + return 0 # default value + class BrowserSimpleDirectoryItem(BrowserItem): """ @@ -1916,6 +1924,15 @@ """ return (self._classObject.lineno, self._classObject.endlineno) + def colOffset(self): + """ + Public method to return the column offset of the item definition. + + @return column offset defining the object + @rtype int + """ + return self._classObject.coloffset + def lessThan(self, other, column, order): """ Public method to check, if the item is less than the other one. @@ -2047,6 +2064,15 @@ """ return (self._functionObject.lineno, self._functionObject.endlineno) + def colOffset(self): + """ + Public method to return the column offset of the item definition. + + @return column offset defining the object + @rtype int + """ + return self._functionObject.coloffset + def lessThan(self, other, column, order): """ Public method to check, if the item is less than the other one. @@ -2239,6 +2265,15 @@ """ return self._attributeObject.linenos[:] + def colOffset(self): + """ + Public method to return the column offset of the item definition. + + @return column offset defining the object + @rtype int + """ + return self._attributeObject.coloffset + def lessThan(self, other, column, order): """ Public method to check, if the item is less than the other one.