src/eric7/UI/BrowserModel.py

branch
eric7
changeset 10679
4d3e0ce54322
parent 10677
6ee2e475490c
child 10680
306373ccf8fd
child 10683
779cda568acb
equal deleted inserted replaced
10678:665f1084ebf9 10679:4d3e0ce54322
15 15
16 from PyQt6.QtCore import ( 16 from PyQt6.QtCore import (
17 QAbstractItemModel, 17 QAbstractItemModel,
18 QCoreApplication, 18 QCoreApplication,
19 QDir, 19 QDir,
20 QFileSystemWatcher,
21 QModelIndex, 20 QModelIndex,
22 QProcess, 21 QProcess,
23 Qt, 22 Qt,
24 ) 23 )
25 from PyQt6.QtGui import QFont, QImageReader 24 from PyQt6.QtGui import QFont, QImageReader
26 from PyQt6.QtWidgets import QApplication 25 from PyQt6.QtWidgets import QApplication
27 26
28 from eric7 import Preferences 27 from eric7 import Preferences
28 from eric7.EricCore import EricFileSystemWatcher
29 from eric7.EricGui import EricPixmapCache 29 from eric7.EricGui import EricPixmapCache
30 from eric7.SystemUtilities import FileSystemUtilities 30 from eric7.SystemUtilities import FileSystemUtilities
31 from eric7.Utilities import ClassBrowsers 31 from eric7.Utilities import ClassBrowsers
32 from eric7.Utilities.ClassBrowsers import ClbrBaseClasses 32 from eric7.Utilities.ClassBrowsers import ClbrBaseClasses
33 33
77 77
78 self.__sysPathInterpreter = "" 78 self.__sysPathInterpreter = ""
79 self.__sysPathItem = None 79 self.__sysPathItem = None
80 80
81 if not nopopulate: 81 if not nopopulate:
82 self.watchedItems = {} 82 self.watchedDirItems = {}
83 self.watchedFileItems = {} 83 self.watchedFileItems = {}
84 self.watcher = QFileSystemWatcher(self) 84 watcher = EricFileSystemWatcher.instance()
85 self.watcher.directoryChanged.connect(self.directoryChanged) 85 watcher.directoryCreated.connect(lambda x: self.entryCreated(x, isDir=True))
86 self.watcher.fileChanged.connect(self.fileChanged) 86 watcher.directoryDeleted.connect(lambda x: self.entryDeleted(x, isDir=True))
87 watcher.fileCreated.connect(lambda x: self.entryCreated(x, isDir=False))
88 watcher.fileDeleted.connect(lambda x: self.entryDeleted(x, isDir=False))
89 watcher.fileModified.connect(self.fileChanged)
87 90
88 rootData = QCoreApplication.translate("BrowserModel", "Name") 91 rootData = QCoreApplication.translate("BrowserModel", "Name")
89 self.rootItem = BrowserItem(None, rootData) 92 self.rootItem = BrowserItem(None, rootData)
90 93
91 self.__populateModel() 94 self.__populateModel()
327 if ( 330 if (
328 dirName != "" 331 dirName != ""
329 and not dirName.startswith("//") 332 and not dirName.startswith("//")
330 and not dirName.startswith("\\\\") 333 and not dirName.startswith("\\\\")
331 ): 334 ):
332 if dirName not in self.watcher.directories(): 335 EricFileSystemWatcher.instance().addPath(dirName)
333 self.watcher.addPath(dirName) 336 if dirName in self.watchedDirItems:
334 if dirName in self.watchedItems: 337 if itm not in self.watchedDirItems[dirName]:
335 if itm not in self.watchedItems[dirName]: 338 self.watchedDirItems[dirName].append(itm)
336 self.watchedItems[dirName].append(itm)
337 else: 339 else:
338 self.watchedItems[dirName] = [itm] 340 self.watchedDirItems[dirName] = [itm]
339 341
340 def _removeWatchedItem(self, itm): 342 def _removeWatchedItem(self, itm):
341 """ 343 """
342 Protected method to remove a watched item. 344 Protected method to remove a watched item.
343 345
346 """ 348 """
347 if isinstance(itm, BrowserDirectoryItem): 349 if isinstance(itm, BrowserDirectoryItem):
348 dirName = itm.dirName() 350 dirName = itm.dirName()
349 with contextlib.suppress(KeyError): 351 with contextlib.suppress(KeyError):
350 with contextlib.suppress(ValueError): 352 with contextlib.suppress(ValueError):
351 self.watchedItems[dirName].remove(itm) 353 self.watchedDirItems[dirName].remove(itm)
352 if len(self.watchedItems[dirName]) == 0: 354 if len(self.watchedDirItems[dirName]) == 0:
353 del self.watchedItems[dirName] 355 del self.watchedDirItems[dirName]
354 self.watcher.removePath(dirName) 356 EricFileSystemWatcher.instance().removePath(dirName)
355 357
356 def directoryChanged(self, path): 358 def entryCreated(self, path, isDir=False):
357 """ 359 """
358 Public slot to handle the directoryChanged signal of the watcher. 360 Public method to handle the creation of a file or directory.
359 361
360 @param path path of the directory 362 @param path path of the created file or directory
361 @type str 363 @type str
362 """ 364 @param isDir flag indicating a created directory (defaults to False)
363 if path not in self.watchedItems: 365 @type bool (optional)
366 """
367 parentPath = os.path.dirname(path)
368 if parentPath not in self.watchedDirItems:
364 # just ignore the situation we don't have a reference to the item 369 # just ignore the situation we don't have a reference to the item
365 return 370 return
366 371
367 dirFilter = ( 372 for itm in self.watchedDirItems[parentPath]:
368 QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot | QDir.Filter.Hidden 373 cnt = itm.childCount()
369 ) 374 self.beginInsertRows(self.createIndex(itm.row(), 0, itm), cnt, cnt)
370 375 node = (
371 for itm in self.watchedItems[path]: 376 BrowserDirectoryItem(
372 oldCnt = itm.childCount() 377 itm,
373 378 FileSystemUtilities.toNativeSeparators(path),
374 qdir = QDir(itm.dirName()) 379 False,
375
376 entryInfoList = qdir.entryInfoList(dirFilter)
377
378 # step 1: check for new entries
379 children = itm.children()
380 for f in entryInfoList:
381 fpath = FileSystemUtilities.toNativeSeparators(f.absoluteFilePath())
382 childFound = False
383 for child in children[:]:
384 if child.name() == fpath:
385 childFound = True
386 children.remove(child)
387 break
388 if childFound:
389 continue
390
391 cnt = itm.childCount()
392 self.beginInsertRows(self.createIndex(itm.row(), 0, itm), cnt, cnt)
393 node = (
394 BrowserDirectoryItem(
395 itm,
396 FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()),
397 False,
398 )
399 if f.isDir()
400 else BrowserFileItem(
401 itm,
402 FileSystemUtilities.toNativeSeparators(f.absoluteFilePath()),
403 )
404 ) 380 )
405 self._addItem(node, itm) 381 if isDir
406 self.endInsertRows() 382 else BrowserFileItem(
407 383 itm,
408 # step 2: check for removed entries 384 FileSystemUtilities.toNativeSeparators(path),
409 if len(entryInfoList) != itm.childCount(): 385 )
410 for row in range(oldCnt - 1, -1, -1): 386 )
411 child = itm.child(row) 387 self._addItem(node, itm)
412 childname = FileSystemUtilities.fromNativeSeparators(child.name()) 388 self.endInsertRows()
413 entryFound = False 389
414 for f in entryInfoList[:]: 390 def entryDeleted(self, path, isDir=False): # noqa: U100
415 if f.absoluteFilePath() == childname: 391 """
416 entryFound = True 392 Public method to handle the deletion of a file or directory.
417 entryInfoList.remove(f) 393
418 break 394 @param path path of the deleted file or directory
419 if entryFound: 395 @type str
420 continue 396 @param isDir flag indicating a deleted directory (defaults to False)
421 397 @type bool (optional)
398 """
399 parentPath = os.path.dirname(path)
400 if parentPath not in self.watchedDirItems:
401 # just ignore the situation we don't have a reference to the item
402 return
403
404 for itm in self.watchedDirItems[parentPath]:
405 for row in range(itm.childCount() - 1, -1, -1):
406 child = itm.child(row)
407 if child.name() == path:
422 self._removeWatchedItem(child) 408 self._removeWatchedItem(child)
423 self.beginRemoveRows(self.createIndex(itm.row(), 0, itm), row, row) 409 self.beginRemoveRows(self.createIndex(itm.row(), 0, itm), row, row)
424 itm.removeChild(child) 410 itm.removeChild(child)
425 self.endRemoveRows() 411 self.endRemoveRows()
412 break
426 413
427 def __populateModel(self): 414 def __populateModel(self):
428 """ 415 """
429 Private method to populate the browser model. 416 Private method to populate the browser model.
430 """ 417 """
784 if ( 771 if (
785 parentItem.type_ == BrowserItemType.File 772 parentItem.type_ == BrowserItemType.File
786 and fileName not in self.watchedFileItems 773 and fileName not in self.watchedFileItems
787 ): 774 ):
788 # watch the file only in the file browser not the project viewer 775 # watch the file only in the file browser not the project viewer
789 self.watcher.addPath(fileName) 776 watcher = EricFileSystemWatcher.instance()
777 watcher.addPath(fileName)
790 self.watchedFileItems[fileName] = parentItem 778 self.watchedFileItems[fileName] = parentItem
791 779
792 def repopulateFileItem(self, itm): 780 def repopulateFileItem(self, itm):
793 """ 781 """
794 Public method to repopulate a file item. 782 Public method to repopulate a file item.
820 if os.path.exists(fileName): 808 if os.path.exists(fileName):
821 # the file was changed 809 # the file was changed
822 self.repopulateFileItem(self.watchedFileItems[fileName]) 810 self.repopulateFileItem(self.watchedFileItems[fileName])
823 else: 811 else:
824 # the file does not exist anymore 812 # the file does not exist anymore
813 watcher = EricFileSystemWatcher.instance()
814 watcher.removePath(fileName)
825 del self.watchedFileItems[fileName] 815 del self.watchedFileItems[fileName]
826 816
827 def populateClassItem(self, parentItem, repopulate=False): 817 def populateClassItem(self, parentItem, repopulate=False):
828 """ 818 """
829 Public method to populate a class item's subtree. 819 Public method to populate a class item's subtree.

eric ide

mercurial