src/eric7/Project/ProjectBrowserModel.py

branch
eric7
changeset 9221
bf71ee032bb4
parent 9209
b99e7fd55fd3
child 9413
80c06d472826
equal deleted inserted replaced
9220:e9e7eca7efee 9221:bf71ee032bb4
13 13
14 from PyQt6.QtCore import QDir, QModelIndex, pyqtSignal, QFileSystemWatcher, Qt 14 from PyQt6.QtCore import QDir, QModelIndex, pyqtSignal, QFileSystemWatcher, Qt
15 from PyQt6.QtGui import QColor 15 from PyQt6.QtGui import QColor
16 16
17 from UI.BrowserModel import ( 17 from UI.BrowserModel import (
18 BrowserModel, BrowserItem, BrowserDirectoryItem, BrowserFileItem 18 BrowserModel,
19 BrowserItem,
20 BrowserDirectoryItem,
21 BrowserFileItem,
19 ) 22 )
20 23
21 import UI.PixmapCache 24 import UI.PixmapCache
22 import Preferences 25 import Preferences
23 import Utilities 26 import Utilities
39 42
40 43
41 class ProjectBrowserItemMixin: 44 class ProjectBrowserItemMixin:
42 """ 45 """
43 Class implementing common methods of project browser items. 46 Class implementing common methods of project browser items.
44 47
45 It is meant to be used as a mixin class. 48 It is meant to be used as a mixin class.
46 """ 49 """
50
47 def __init__(self, type_, bold=False): 51 def __init__(self, type_, bold=False):
48 """ 52 """
49 Constructor 53 Constructor
50 54
51 @param type_ type of file/directory in the project 55 @param type_ type of file/directory in the project
52 @param bold flag indicating a highlighted font 56 @param bold flag indicating a highlighted font
53 """ 57 """
54 self._projectTypes = [type_] 58 self._projectTypes = [type_]
55 self.bold = bold 59 self.bold = bold
56 self.vcsState = " " 60 self.vcsState = " "
57 61
58 def getTextColor(self): 62 def getTextColor(self):
59 """ 63 """
60 Public method to get the items text color. 64 Public method to get the items text color.
61 65
62 @return text color (QColor) 66 @return text color (QColor)
63 """ 67 """
64 if self.bold: 68 if self.bold:
65 return Preferences.getProjectBrowserColour("Highlighted") 69 return Preferences.getProjectBrowserColour("Highlighted")
66 else: 70 else:
67 return None 71 return None
68 72
69 def setVcsState(self, state): 73 def setVcsState(self, state):
70 """ 74 """
71 Public method to set the items VCS state. 75 Public method to set the items VCS state.
72 76
73 @param state VCS state (one of A, C, M, U or " ") (string) 77 @param state VCS state (one of A, C, M, U or " ") (string)
74 """ 78 """
75 self.vcsState = state 79 self.vcsState = state
76 80
77 def addVcsStatus(self, vcsStatus): 81 def addVcsStatus(self, vcsStatus):
78 """ 82 """
79 Public method to add the VCS status. 83 Public method to add the VCS status.
80 84
81 @param vcsStatus VCS status text (string) 85 @param vcsStatus VCS status text (string)
82 """ 86 """
83 self.itemData.append(vcsStatus) 87 self.itemData.append(vcsStatus)
84 88
85 def setVcsStatus(self, vcsStatus): 89 def setVcsStatus(self, vcsStatus):
86 """ 90 """
87 Public method to set the VCS status. 91 Public method to set the VCS status.
88 92
89 @param vcsStatus VCS status text (string) 93 @param vcsStatus VCS status text (string)
90 """ 94 """
91 self.itemData[1] = vcsStatus 95 self.itemData[1] = vcsStatus
92 96
93 def getProjectTypes(self): 97 def getProjectTypes(self):
94 """ 98 """
95 Public method to get the project type. 99 Public method to get the project type.
96 100
97 @return project type 101 @return project type
98 """ 102 """
99 return self._projectTypes[:] 103 return self._projectTypes[:]
100 104
101 def addProjectType(self, type_): 105 def addProjectType(self, type_):
102 """ 106 """
103 Public method to add a type to the list. 107 Public method to add a type to the list.
104 108
105 @param type_ type to add to the list 109 @param type_ type to add to the list
106 """ 110 """
107 self._projectTypes.append(type_) 111 self._projectTypes.append(type_)
108 112
109 113
110 class ProjectBrowserSimpleDirectoryItem(BrowserItem, ProjectBrowserItemMixin): 114 class ProjectBrowserSimpleDirectoryItem(BrowserItem, ProjectBrowserItemMixin):
111 """ 115 """
112 Class implementing the data structure for project browser simple directory 116 Class implementing the data structure for project browser simple directory
113 items. 117 items.
114 """ 118 """
119
115 def __init__(self, parent, projectType, text, path=""): 120 def __init__(self, parent, projectType, text, path=""):
116 """ 121 """
117 Constructor 122 Constructor
118 123
119 @param parent parent item 124 @param parent parent item
120 @param projectType type of file/directory in the project 125 @param projectType type of file/directory in the project
121 @param text text to be displayed (string) 126 @param text text to be displayed (string)
122 @param path path of the directory (string) 127 @param path path of the directory (string)
123 """ 128 """
124 BrowserItem.__init__(self, parent, text) 129 BrowserItem.__init__(self, parent, text)
125 ProjectBrowserItemMixin.__init__(self, projectType) 130 ProjectBrowserItemMixin.__init__(self, projectType)
126 131
127 self._dirName = path 132 self._dirName = path
128 if not os.path.isdir(self._dirName): 133 if not os.path.isdir(self._dirName):
129 self._dirName = os.path.dirname(self._dirName) 134 self._dirName = os.path.dirname(self._dirName)
130 135
131 self.type_ = ProjectBrowserItemSimpleDirectory 136 self.type_ = ProjectBrowserItemSimpleDirectory
132 if os.path.lexists(self._dirName) and os.path.islink(self._dirName): 137 if os.path.lexists(self._dirName) and os.path.islink(self._dirName):
133 self.symlink = True 138 self.symlink = True
134 self.icon = UI.PixmapCache.getSymlinkIcon("dirClosed") 139 self.icon = UI.PixmapCache.getSymlinkIcon("dirClosed")
135 else: 140 else:
136 self.icon = UI.PixmapCache.getIcon("dirClosed") 141 self.icon = UI.PixmapCache.getIcon("dirClosed")
137 142
138 def setName(self, dinfo, full=True): 143 def setName(self, dinfo, full=True):
139 """ 144 """
140 Public method to set the directory name. 145 Public method to set the directory name.
141 146
142 @param dinfo dinfo is the string for the directory (string) 147 @param dinfo dinfo is the string for the directory (string)
143 @param full flag indicating full pathname should be displayed (boolean) 148 @param full flag indicating full pathname should be displayed (boolean)
144 """ 149 """
145 self._dirName = os.path.abspath(dinfo) 150 self._dirName = os.path.abspath(dinfo)
146 self.itemData[0] = os.path.basename(self._dirName) 151 self.itemData[0] = os.path.basename(self._dirName)
147 152
148 def dirName(self): 153 def dirName(self):
149 """ 154 """
150 Public method returning the directory name. 155 Public method returning the directory name.
151 156
152 @return directory name (string) 157 @return directory name (string)
153 """ 158 """
154 return self._dirName 159 return self._dirName
155 160
156 def name(self): 161 def name(self):
157 """ 162 """
158 Public method to return the name of the item. 163 Public method to return the name of the item.
159 164
160 @return name of the item (string) 165 @return name of the item (string)
161 """ 166 """
162 return self._dirName 167 return self._dirName
163 168
164 def lessThan(self, other, column, order): 169 def lessThan(self, other, column, order):
165 """ 170 """
166 Public method to check, if the item is less than the other one. 171 Public method to check, if the item is less than the other one.
167 172
168 @param other reference to item to compare against (BrowserItem) 173 @param other reference to item to compare against (BrowserItem)
169 @param column column number to use for the comparison (integer) 174 @param column column number to use for the comparison (integer)
170 @param order sort order (Qt.SortOrder) (for special sorting) 175 @param order sort order (Qt.SortOrder) (for special sorting)
171 @return true, if this item is less than other (boolean) 176 @return true, if this item is less than other (boolean)
172 """ 177 """
173 if ( 178 if issubclass(other.__class__, BrowserFileItem) and Preferences.getUI(
174 issubclass(other.__class__, BrowserFileItem) and 179 "BrowsersListFoldersFirst"
175 Preferences.getUI("BrowsersListFoldersFirst")
176 ): 180 ):
177 return order == Qt.SortOrder.AscendingOrder 181 return order == Qt.SortOrder.AscendingOrder
178 182
179 return BrowserItem.lessThan(self, other, column, order) 183 return BrowserItem.lessThan(self, other, column, order)
180 184
181 185
182 class ProjectBrowserDirectoryItem(BrowserDirectoryItem, 186 class ProjectBrowserDirectoryItem(BrowserDirectoryItem, ProjectBrowserItemMixin):
183 ProjectBrowserItemMixin):
184 """ 187 """
185 Class implementing the data structure for project browser directory items. 188 Class implementing the data structure for project browser directory items.
186 """ 189 """
190
187 def __init__(self, parent, dinfo, projectType, full=True, bold=False): 191 def __init__(self, parent, dinfo, projectType, full=True, bold=False):
188 """ 192 """
189 Constructor 193 Constructor
190 194
191 @param parent parent item 195 @param parent parent item
192 @param dinfo dinfo is the string for the directory (string) 196 @param dinfo dinfo is the string for the directory (string)
193 @param projectType type of file/directory in the project 197 @param projectType type of file/directory in the project
194 @param full flag indicating full pathname should be displayed (boolean) 198 @param full flag indicating full pathname should be displayed (boolean)
195 @param bold flag indicating a highlighted font (boolean) 199 @param bold flag indicating a highlighted font (boolean)
196 """ 200 """
197 BrowserDirectoryItem.__init__(self, parent, dinfo, full) 201 BrowserDirectoryItem.__init__(self, parent, dinfo, full)
198 ProjectBrowserItemMixin.__init__(self, projectType, bold) 202 ProjectBrowserItemMixin.__init__(self, projectType, bold)
199 203
200 self.type_ = ProjectBrowserItemDirectory 204 self.type_ = ProjectBrowserItemDirectory
201 205
202 206
203 class ProjectBrowserFileItem(BrowserFileItem, ProjectBrowserItemMixin): 207 class ProjectBrowserFileItem(BrowserFileItem, ProjectBrowserItemMixin):
204 """ 208 """
205 Class implementing the data structure for project browser file items. 209 Class implementing the data structure for project browser file items.
206 """ 210 """
207 def __init__(self, parent, finfo, projectType, full=True, bold=False, 211
208 sourceLanguage=""): 212 def __init__(
213 self, parent, finfo, projectType, full=True, bold=False, sourceLanguage=""
214 ):
209 """ 215 """
210 Constructor 216 Constructor
211 217
212 @param parent parent item 218 @param parent parent item
213 @param finfo the string for the file (string) 219 @param finfo the string for the file (string)
214 @param projectType type of file/directory in the project 220 @param projectType type of file/directory in the project
215 @param full flag indicating full pathname should be displayed (boolean) 221 @param full flag indicating full pathname should be displayed (boolean)
216 @param bold flag indicating a highlighted font (boolean) 222 @param bold flag indicating a highlighted font (boolean)
217 @param sourceLanguage source code language of the project (string) 223 @param sourceLanguage source code language of the project (string)
218 """ 224 """
219 BrowserFileItem.__init__(self, parent, finfo, full, sourceLanguage) 225 BrowserFileItem.__init__(self, parent, finfo, full, sourceLanguage)
220 ProjectBrowserItemMixin.__init__(self, projectType, bold) 226 ProjectBrowserItemMixin.__init__(self, projectType, bold)
221 227
222 self.type_ = ProjectBrowserItemFile 228 self.type_ = ProjectBrowserItemFile
223 229
224 230
225 class ProjectBrowserModel(BrowserModel): 231 class ProjectBrowserModel(BrowserModel):
226 """ 232 """
227 Class implementing the project browser model. 233 Class implementing the project browser model.
228 234
229 @signal vcsStateChanged(str) emitted after the VCS state has changed 235 @signal vcsStateChanged(str) emitted after the VCS state has changed
230 """ 236 """
237
231 vcsStateChanged = pyqtSignal(str) 238 vcsStateChanged = pyqtSignal(str)
232 239
233 def __init__(self, parent): 240 def __init__(self, parent):
234 """ 241 """
235 Constructor 242 Constructor
236 243
237 @param parent reference to parent object (Project.Project) 244 @param parent reference to parent object (Project.Project)
238 """ 245 """
239 super().__init__(parent, nopopulate=True) 246 super().__init__(parent, nopopulate=True)
240 247
241 rootData = self.tr("Name") 248 rootData = self.tr("Name")
242 self.rootItem = BrowserItem(None, rootData) 249 self.rootItem = BrowserItem(None, rootData)
243 self.rootItem.itemData.append(self.tr("VCS Status")) 250 self.rootItem.itemData.append(self.tr("VCS Status"))
244 251
245 self.progDir = None 252 self.progDir = None
246 self.project = parent 253 self.project = parent
247 254
248 self.watchedItems = {} 255 self.watchedItems = {}
249 self.__watcherActive = True 256 self.__watcherActive = True
250 self.watcher = QFileSystemWatcher(self) 257 self.watcher = QFileSystemWatcher(self)
251 self.watcher.directoryChanged.connect(self.directoryChanged) 258 self.watcher.directoryChanged.connect(self.directoryChanged)
252 259
253 self.inRefresh = False 260 self.inRefresh = False
254 261
255 self.projectBrowserTypes = { 262 self.projectBrowserTypes = {
256 "SOURCES": ProjectBrowserSourceType, 263 "SOURCES": ProjectBrowserSourceType,
257 "FORMS": ProjectBrowserFormType, 264 "FORMS": ProjectBrowserFormType,
258 "RESOURCES": ProjectBrowserResourceType, 265 "RESOURCES": ProjectBrowserResourceType,
259 "INTERFACES": ProjectBrowserInterfaceType, 266 "INTERFACES": ProjectBrowserInterfaceType,
260 "PROTOCOLS": ProjectBrowserProtocolsType, 267 "PROTOCOLS": ProjectBrowserProtocolsType,
261 "TRANSLATIONS": ProjectBrowserTranslationType, 268 "TRANSLATIONS": ProjectBrowserTranslationType,
262 "OTHERS": ProjectBrowserOthersType, 269 "OTHERS": ProjectBrowserOthersType,
263 } 270 }
264 271
265 self.colorNames = { 272 self.colorNames = {
266 "A": "VcsAdded", 273 "A": "VcsAdded",
267 "M": "VcsModified", 274 "M": "VcsModified",
268 "O": "VcsRemoved", 275 "O": "VcsRemoved",
269 "R": "VcsReplaced", 276 "R": "VcsReplaced",
277 "O": Preferences.getProjectBrowserColour(self.colorNames["O"]), 284 "O": Preferences.getProjectBrowserColour(self.colorNames["O"]),
278 "R": Preferences.getProjectBrowserColour(self.colorNames["R"]), 285 "R": Preferences.getProjectBrowserColour(self.colorNames["R"]),
279 "U": Preferences.getProjectBrowserColour(self.colorNames["U"]), 286 "U": Preferences.getProjectBrowserColour(self.colorNames["U"]),
280 "Z": Preferences.getProjectBrowserColour(self.colorNames["Z"]), 287 "Z": Preferences.getProjectBrowserColour(self.colorNames["Z"]),
281 } 288 }
282 289
283 self.highLightColor = Preferences.getProjectBrowserColour( 290 self.highLightColor = Preferences.getProjectBrowserColour("Highlighted")
284 "Highlighted")
285 # needed by preferencesChanged() 291 # needed by preferencesChanged()
286 292
287 self.vcsStatusReport = {} 293 self.vcsStatusReport = {}
288 294
289 def data(self, index, role): 295 def data(self, index, role):
290 """ 296 """
291 Public method to get data of an item. 297 Public method to get data of an item.
292 298
293 @param index index of the data to retrieve (QModelIndex) 299 @param index index of the data to retrieve (QModelIndex)
294 @param role role of data (Qt.ItemDataRole) 300 @param role role of data (Qt.ItemDataRole)
295 @return requested data 301 @return requested data
296 """ 302 """
297 if not index.isValid(): 303 if not index.isValid():
298 return None 304 return None
299 305
300 if role == Qt.ItemDataRole.ForegroundRole: 306 if role == Qt.ItemDataRole.ForegroundRole:
301 if index.column() == 0: 307 if index.column() == 0:
302 try: 308 try:
303 return index.internalPointer().getTextColor() 309 return index.internalPointer().getTextColor()
304 except AttributeError: 310 except AttributeError:
305 return None 311 return None
306 elif role == Qt.ItemDataRole.BackgroundRole: 312 elif role == Qt.ItemDataRole.BackgroundRole:
307 try: 313 try:
308 col = self.itemBackgroundColors[ 314 col = self.itemBackgroundColors[index.internalPointer().vcsState]
309 index.internalPointer().vcsState]
310 if col.isValid(): 315 if col.isValid():
311 return col 316 return col
312 else: 317 else:
313 return None 318 return None
314 except AttributeError: 319 except AttributeError:
315 return None 320 return None
316 except KeyError: 321 except KeyError:
317 return None 322 return None
318 323
319 return BrowserModel.data(self, index, role) 324 return BrowserModel.data(self, index, role)
320 325
321 def populateItem(self, parentItem, repopulate=False): 326 def populateItem(self, parentItem, repopulate=False):
322 """ 327 """
323 Public method to populate an item's subtree. 328 Public method to populate an item's subtree.
324 329
325 @param parentItem reference to the item to be populated 330 @param parentItem reference to the item to be populated
326 @param repopulate flag indicating a repopulation (boolean) 331 @param repopulate flag indicating a repopulation (boolean)
327 """ 332 """
328 if parentItem.type() == ProjectBrowserItemSimpleDirectory: 333 if parentItem.type() == ProjectBrowserItemSimpleDirectory:
329 return # nothing to do 334 return # nothing to do
335 BrowserModel.populateItem(self, parentItem, repopulate) 340 BrowserModel.populateItem(self, parentItem, repopulate)
336 341
337 def populateProjectDirectoryItem(self, parentItem, repopulate=False): 342 def populateProjectDirectoryItem(self, parentItem, repopulate=False):
338 """ 343 """
339 Public method to populate a directory item's subtree. 344 Public method to populate a directory item's subtree.
340 345
341 @param parentItem reference to the directory item to be populated 346 @param parentItem reference to the directory item to be populated
342 @param repopulate flag indicating a repopulation (boolean) 347 @param repopulate flag indicating a repopulation (boolean)
343 """ 348 """
344 self._addWatchedItem(parentItem) 349 self._addWatchedItem(parentItem)
345 350
346 qdir = QDir(parentItem.dirName()) 351 qdir = QDir(parentItem.dirName())
347 352
348 fileFilter = ( 353 fileFilter = (
349 ( 354 (QDir.Filter.AllEntries | QDir.Filter.Hidden | QDir.Filter.NoDotAndDotDot)
350 QDir.Filter.AllEntries | 355 if Preferences.getProject("BrowsersListHiddenFiles")
351 QDir.Filter.Hidden | 356 else QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot
352 QDir.Filter.NoDotAndDotDot
353 )
354 if Preferences.getProject("BrowsersListHiddenFiles") else
355 QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot
356 ) 357 )
357 entryInfoList = qdir.entryInfoList(fileFilter) 358 entryInfoList = qdir.entryInfoList(fileFilter)
358 359
359 if len(entryInfoList) > 0: 360 if len(entryInfoList) > 0:
360 if repopulate: 361 if repopulate:
361 self.beginInsertRows(self.createIndex( 362 self.beginInsertRows(
362 parentItem.row(), 0, parentItem), 363 self.createIndex(parentItem.row(), 0, parentItem),
363 0, len(entryInfoList) - 1) 364 0,
365 len(entryInfoList) - 1,
366 )
364 states = {} 367 states = {}
365 if self.project.vcs is not None: 368 if self.project.vcs is not None:
366 for f in entryInfoList: 369 for f in entryInfoList:
367 fname = f.absoluteFilePath() 370 fname = f.absoluteFilePath()
368 states[os.path.normcase(fname)] = 0 371 states[os.path.normcase(fname)] = 0
369 dname = parentItem.dirName() 372 dname = parentItem.dirName()
370 self.project.vcs.clearStatusCache() 373 self.project.vcs.clearStatusCache()
371 states = self.project.vcs.vcsAllRegisteredStates(states, dname) 374 states = self.project.vcs.vcsAllRegisteredStates(states, dname)
372 375
373 for f in entryInfoList: 376 for f in entryInfoList:
374 node = ( 377 node = (
375 ProjectBrowserDirectoryItem( 378 ProjectBrowserDirectoryItem(
376 parentItem, 379 parentItem,
377 Utilities.toNativeSeparators(f.absoluteFilePath()), 380 Utilities.toNativeSeparators(f.absoluteFilePath()),
378 parentItem.getProjectTypes()[0], False) 381 parentItem.getProjectTypes()[0],
379 if f.isDir() else 382 False,
380 ProjectBrowserFileItem( 383 )
384 if f.isDir()
385 else ProjectBrowserFileItem(
381 parentItem, 386 parentItem,
382 Utilities.toNativeSeparators(f.absoluteFilePath()), 387 Utilities.toNativeSeparators(f.absoluteFilePath()),
383 parentItem.getProjectTypes()[0]) 388 parentItem.getProjectTypes()[0],
389 )
384 ) 390 )
385 if self.project.vcs is not None: 391 if self.project.vcs is not None:
386 fname = f.absoluteFilePath() 392 fname = f.absoluteFilePath()
387 if ( 393 if (
388 states[os.path.normcase(fname)] == 394 states[os.path.normcase(fname)]
389 self.project.vcs.canBeCommitted 395 == self.project.vcs.canBeCommitted
390 ): 396 ):
391 node.addVcsStatus(self.project.vcs.vcsName()) 397 node.addVcsStatus(self.project.vcs.vcsName())
392 self.project.clearStatusMonitorCachedState( 398 self.project.clearStatusMonitorCachedState(f.absoluteFilePath())
393 f.absoluteFilePath())
394 else: 399 else:
395 node.addVcsStatus(self.tr("local")) 400 node.addVcsStatus(self.tr("local"))
396 else: 401 else:
397 node.addVcsStatus("") 402 node.addVcsStatus("")
398 self._addItem(node, parentItem) 403 self._addItem(node, parentItem)
402 def projectClosed(self): 407 def projectClosed(self):
403 """ 408 """
404 Public method called after a project has been closed. 409 Public method called after a project has been closed.
405 """ 410 """
406 self.__vcsStatus = {} 411 self.__vcsStatus = {}
407 412
408 self.watchedItems = {} 413 self.watchedItems = {}
409 watchedDirs = self.watcher.directories() 414 watchedDirs = self.watcher.directories()
410 if watchedDirs: 415 if watchedDirs:
411 self.watcher.removePaths(watchedDirs) 416 self.watcher.removePaths(watchedDirs)
412 417
413 self.rootItem.removeChildren() 418 self.rootItem.removeChildren()
414 self.beginResetModel() 419 self.beginResetModel()
415 self.endResetModel() 420 self.endResetModel()
416 421
417 # reset the module parser cache 422 # reset the module parser cache
418 Utilities.ModuleParser.resetParsedModules() 423 Utilities.ModuleParser.resetParsedModules()
419 424
420 def projectOpened(self): 425 def projectOpened(self):
421 """ 426 """
422 Public method used to populate the model after a project has been 427 Public method used to populate the model after a project has been
423 opened. 428 opened.
424 """ 429 """
425 self.__vcsStatus = {} 430 self.__vcsStatus = {}
426 states = {} 431 states = {}
427 keys = list(self.projectBrowserTypes.keys())[:] 432 keys = list(self.projectBrowserTypes.keys())[:]
428 433
429 if self.project.vcs is not None: 434 if self.project.vcs is not None:
430 for key in keys: 435 for key in keys:
431 for fn in self.project.pdata[key]: 436 for fn in self.project.pdata[key]:
432 states[os.path.normcase( 437 states[os.path.normcase(os.path.join(self.project.ppath, fn))] = 0
433 os.path.join(self.project.ppath, fn))] = 0 438
434
435 self.project.vcs.clearStatusCache() 439 self.project.vcs.clearStatusCache()
436 states = self.project.vcs.vcsAllRegisteredStates( 440 states = self.project.vcs.vcsAllRegisteredStates(states, self.project.ppath)
437 states, self.project.ppath) 441
438
439 self.inRefresh = True 442 self.inRefresh = True
440 for key in keys: 443 for key in keys:
441 # Show the entry in bold in the others browser to make it more 444 # Show the entry in bold in the others browser to make it more
442 # distinguishable 445 # distinguishable
443 bold = key == "OTHERS" 446 bold = key == "OTHERS"
444 sourceLanguage = ( 447 sourceLanguage = (
445 self.project.getProjectLanguage() if key == "SOURCES" else "" 448 self.project.getProjectLanguage() if key == "SOURCES" else ""
446 ) 449 )
447 450
448 for fn in self.project.pdata[key]: 451 for fn in self.project.pdata[key]:
449 fname = os.path.join(self.project.ppath, fn) 452 fname = os.path.join(self.project.ppath, fn)
450 parentItem, dt = self.findParentItemByName( 453 parentItem, dt = self.findParentItemByName(
451 self.projectBrowserTypes[key], fn) 454 self.projectBrowserTypes[key], fn
455 )
452 itm = ( 456 itm = (
453 ProjectBrowserDirectoryItem( 457 ProjectBrowserDirectoryItem(
454 parentItem, fname, self.projectBrowserTypes[key], 458 parentItem, fname, self.projectBrowserTypes[key], False, bold
455 False, bold) 459 )
456 if os.path.isdir(fname) else 460 if os.path.isdir(fname)
457 ProjectBrowserFileItem( 461 else ProjectBrowserFileItem(
458 parentItem, fname, self.projectBrowserTypes[key], 462 parentItem,
459 False, bold, sourceLanguage=sourceLanguage) 463 fname,
464 self.projectBrowserTypes[key],
465 False,
466 bold,
467 sourceLanguage=sourceLanguage,
468 )
460 ) 469 )
461 self._addItem(itm, parentItem) 470 self._addItem(itm, parentItem)
462 if self.project.vcs is not None: 471 if self.project.vcs is not None:
463 if ( 472 if (
464 states[os.path.normcase(fname)] == 473 states[os.path.normcase(fname)]
465 self.project.vcs.canBeCommitted 474 == self.project.vcs.canBeCommitted
466 ): 475 ):
467 itm.addVcsStatus(self.project.vcs.vcsName()) 476 itm.addVcsStatus(self.project.vcs.vcsName())
468 else: 477 else:
469 itm.addVcsStatus(self.tr("local")) 478 itm.addVcsStatus(self.tr("local"))
470 else: 479 else:
474 self.endResetModel() 483 self.endResetModel()
475 484
476 def findParentItemByName(self, type_, name, dontSplit=False): 485 def findParentItemByName(self, type_, name, dontSplit=False):
477 """ 486 """
478 Public method to find an item given its name. 487 Public method to find an item given its name.
479 488
480 <b>Note</b>: This method creates all necessary parent items, if they 489 <b>Note</b>: This method creates all necessary parent items, if they
481 don't exist. 490 don't exist.
482 491
483 @param type_ type of the item 492 @param type_ type of the item
484 @param name name of the item (string) 493 @param name name of the item (string)
485 @param dontSplit flag indicating the name should not be split (boolean) 494 @param dontSplit flag indicating the name should not be split (boolean)
486 @return reference to the item found and the new display name (string) 495 @return reference to the item found and the new display name (string)
487 """ 496 """
488 if dontSplit: 497 if dontSplit:
489 pathlist = [] 498 pathlist = []
490 pathlist.append(name) 499 pathlist.append(name)
491 pathlist.append("ignore_me") 500 pathlist.append("ignore_me")
492 else: 501 else:
493 pathlist = re.split(r'/|\\', name) 502 pathlist = re.split(r"/|\\", name)
494 503
495 if len(pathlist) > 1: 504 if len(pathlist) > 1:
496 olditem = self.rootItem 505 olditem = self.rootItem
497 path = self.project.ppath 506 path = self.project.ppath
498 for p in pathlist[:-1]: 507 for p in pathlist[:-1]:
499 itm = self.findChildItem(p, 0, olditem) 508 itm = self.findChildItem(p, 0, olditem)
500 path = os.path.join(path, p) 509 path = os.path.join(path, p)
501 if itm is None: 510 if itm is None:
502 itm = ProjectBrowserSimpleDirectoryItem( 511 itm = ProjectBrowserSimpleDirectoryItem(olditem, type_, p, path)
503 olditem, type_, p, path)
504 self.__addVCSStatus(itm, path) 512 self.__addVCSStatus(itm, path)
505 if self.inRefresh: 513 if self.inRefresh:
506 self._addItem(itm, olditem) 514 self._addItem(itm, olditem)
507 else: 515 else:
508 if olditem == self.rootItem: 516 if olditem == self.rootItem:
509 oldindex = QModelIndex() 517 oldindex = QModelIndex()
510 else: 518 else:
511 oldindex = self.createIndex( 519 oldindex = self.createIndex(olditem.row(), 0, olditem)
512 olditem.row(), 0, olditem)
513 self.addItem(itm, oldindex) 520 self.addItem(itm, oldindex)
514 else: 521 else:
515 if type_ and type_ not in itm.getProjectTypes(): 522 if type_ and type_ not in itm.getProjectTypes():
516 itm.addProjectType(type_) 523 itm.addProjectType(type_)
517 olditem = itm 524 olditem = itm
518 return (itm, pathlist[-1]) 525 return (itm, pathlist[-1])
519 else: 526 else:
520 return (self.rootItem, name) 527 return (self.rootItem, name)
521 528
522 def findChildItem(self, text, column, parentItem=None): 529 def findChildItem(self, text, column, parentItem=None):
523 """ 530 """
524 Public method to find a child item given some text. 531 Public method to find a child item given some text.
525 532
526 @param text text to search for (string) 533 @param text text to search for (string)
527 @param column column to search in (integer) 534 @param column column to search in (integer)
528 @param parentItem reference to parent item 535 @param parentItem reference to parent item
529 @return reference to the item found 536 @return reference to the item found
530 """ 537 """
531 if parentItem is None: 538 if parentItem is None:
532 parentItem = self.rootItem 539 parentItem = self.rootItem
533 540
534 for itm in parentItem.children(): 541 for itm in parentItem.children():
535 if itm.data(column) == text: 542 if itm.data(column) == text:
536 return itm 543 return itm
537 544
538 return None 545 return None
539 546
540 def addNewItem(self, typeString, name, additionalTypeStrings=None): 547 def addNewItem(self, typeString, name, additionalTypeStrings=None):
541 """ 548 """
542 Public method to add a new item to the model. 549 Public method to add a new item to the model.
543 550
544 @param typeString string denoting the type of the new item (string) 551 @param typeString string denoting the type of the new item (string)
545 @param name name of the new item (string) 552 @param name name of the new item (string)
546 @param additionalTypeStrings names of additional types (list of string) 553 @param additionalTypeStrings names of additional types (list of string)
547 """ 554 """
548 # Show the entry in bold in the others browser to make it more 555 # Show the entry in bold in the others browser to make it more
549 # distinguishable 556 # distinguishable
550 bold = typeString == "OTHERS" 557 bold = typeString == "OTHERS"
551 558
552 fname = os.path.join(self.project.ppath, name) 559 fname = os.path.join(self.project.ppath, name)
553 parentItem, dt = self.findParentItemByName( 560 parentItem, dt = self.findParentItemByName(
554 self.projectBrowserTypes[typeString], name) 561 self.projectBrowserTypes[typeString], name
562 )
555 parentIndex = ( 563 parentIndex = (
556 QModelIndex() 564 QModelIndex()
557 if parentItem == self.rootItem else 565 if parentItem == self.rootItem
558 self.createIndex(parentItem.row(), 0, parentItem) 566 else self.createIndex(parentItem.row(), 0, parentItem)
559 ) 567 )
560 if os.path.isdir(fname): 568 if os.path.isdir(fname):
561 itm = ProjectBrowserDirectoryItem( 569 itm = ProjectBrowserDirectoryItem(
562 parentItem, fname, self.projectBrowserTypes[typeString], 570 parentItem, fname, self.projectBrowserTypes[typeString], False, bold
563 False, bold) 571 )
564 else: 572 else:
565 if typeString == "SOURCES": 573 if typeString == "SOURCES":
566 sourceLanguage = self.project.getProjectLanguage() 574 sourceLanguage = self.project.getProjectLanguage()
567 else: 575 else:
568 sourceLanguage = "" 576 sourceLanguage = ""
569 itm = ProjectBrowserFileItem( 577 itm = ProjectBrowserFileItem(
570 parentItem, fname, self.projectBrowserTypes[typeString], 578 parentItem,
571 False, bold, sourceLanguage=sourceLanguage) 579 fname,
580 self.projectBrowserTypes[typeString],
581 False,
582 bold,
583 sourceLanguage=sourceLanguage,
584 )
572 self.__addVCSStatus(itm, fname) 585 self.__addVCSStatus(itm, fname)
573 if additionalTypeStrings: 586 if additionalTypeStrings:
574 for additionalTypeString in additionalTypeStrings: 587 for additionalTypeString in additionalTypeStrings:
575 type_ = self.projectBrowserTypes[additionalTypeString] 588 type_ = self.projectBrowserTypes[additionalTypeString]
576 itm.addProjectType(type_) 589 itm.addProjectType(type_)
577 self.addItem(itm, parentIndex) 590 self.addItem(itm, parentIndex)
578 591
579 def renameItem(self, name, newFilename): 592 def renameItem(self, name, newFilename):
580 """ 593 """
581 Public method to rename an item. 594 Public method to rename an item.
582 595
583 @param name the old display name (string) 596 @param name the old display name (string)
584 @param newFilename new filename of the item (string) 597 @param newFilename new filename of the item (string)
585 """ 598 """
586 itm = self.findItem(name) 599 itm = self.findItem(name)
587 if itm is None: 600 if itm is None:
588 return 601 return
589 602
590 index = self.createIndex(itm.row(), 0, itm) 603 index = self.createIndex(itm.row(), 0, itm)
591 itm.setName(newFilename, full=False) 604 itm.setName(newFilename, full=False)
592 self.dataChanged.emit(index, index) 605 self.dataChanged.emit(index, index)
593 self.repopulateItem(newFilename) 606 self.repopulateItem(newFilename)
594 607
595 def findItem(self, name): 608 def findItem(self, name):
596 """ 609 """
597 Public method to find an item given its name. 610 Public method to find an item given its name.
598 611
599 @param name name of the item (string) 612 @param name name of the item (string)
600 @return reference to the item found 613 @return reference to the item found
601 """ 614 """
602 if QDir.isAbsolutePath(name): 615 if QDir.isAbsolutePath(name):
603 name = self.project.getRelativePath(name) 616 name = self.project.getRelativePath(name)
604 pathlist = re.split(r'/|\\', name) 617 pathlist = re.split(r"/|\\", name)
605 if len(pathlist) > 0: 618 if len(pathlist) > 0:
606 olditem = self.rootItem 619 olditem = self.rootItem
607 for p in pathlist: 620 for p in pathlist:
608 itm = self.findChildItem(p, 0, olditem) 621 itm = self.findChildItem(p, 0, olditem)
609 if itm is None: 622 if itm is None:
610 return None 623 return None
611 olditem = itm 624 olditem = itm
612 return itm 625 return itm
613 else: 626 else:
614 return None 627 return None
615 628
616 def itemIndexByName(self, name): 629 def itemIndexByName(self, name):
617 """ 630 """
618 Public method to find an item's index given its name. 631 Public method to find an item's index given its name.
619 632
620 @param name name of the item (string) 633 @param name name of the item (string)
621 @return index of the item found (QModelIndex) 634 @return index of the item found (QModelIndex)
622 """ 635 """
623 itm = self.findItem(name) 636 itm = self.findItem(name)
624 index = self.createIndex(itm.row(), 0, itm) if itm else QModelIndex() 637 index = self.createIndex(itm.row(), 0, itm) if itm else QModelIndex()
625 return index 638 return index
626 639
627 def itemIndexByNameAndLine(self, name, lineno): 640 def itemIndexByNameAndLine(self, name, lineno):
628 """ 641 """
629 Public method to find an item's index given its name. 642 Public method to find an item's index given its name.
630 643
631 @param name name of the item (string) 644 @param name name of the item (string)
632 @param lineno one based line number of the item (integer) 645 @param lineno one based line number of the item (integer)
633 @return index of the item found (QModelIndex) 646 @return index of the item found (QModelIndex)
634 """ 647 """
635 index = QModelIndex() 648 index = QModelIndex()
636 itm = self.findItem(name) 649 itm = self.findItem(name)
637 if ( 650 if itm is not None and isinstance(itm, ProjectBrowserFileItem):
638 itm is not None and
639 isinstance(itm, ProjectBrowserFileItem)
640 ):
641 olditem = itm 651 olditem = itm
642 autoPopulate = Preferences.getProject("AutoPopulateItems") 652 autoPopulate = Preferences.getProject("AutoPopulateItems")
643 while itm is not None: 653 while itm is not None:
644 if not itm.isPopulated(): 654 if not itm.isPopulated():
645 if itm.isLazyPopulated() and autoPopulate: 655 if itm.isLazyPopulated() and autoPopulate:
648 break 658 break
649 for child in itm.children(): 659 for child in itm.children():
650 with contextlib.suppress(AttributeError): 660 with contextlib.suppress(AttributeError):
651 start, end = child.boundaries() 661 start, end = child.boundaries()
652 if end == -1: 662 if end == -1:
653 end = 1000000 # assume end of file 663 end = 1000000 # assume end of file
654 if start <= lineno <= end: 664 if start <= lineno <= end:
655 itm = child 665 itm = child
656 break 666 break
657 else: 667 else:
658 itm = None 668 itm = None
659 if itm: 669 if itm:
660 olditem = itm 670 olditem = itm
661 index = self.createIndex(olditem.row(), 0, olditem) 671 index = self.createIndex(olditem.row(), 0, olditem)
662 672
663 return index 673 return index
664 674
665 def startFileSystemMonitoring(self): 675 def startFileSystemMonitoring(self):
666 """ 676 """
667 Public method to (re)start monitoring the project file system. 677 Public method to (re)start monitoring the project file system.
668 """ 678 """
669 self.__watcherActive = True 679 self.__watcherActive = True
670 680
671 def stopFileSystemMonitoring(self): 681 def stopFileSystemMonitoring(self):
672 """ 682 """
673 Public method to stop monitoring the project file system. 683 Public method to stop monitoring the project file system.
674 """ 684 """
675 self.__watcherActive = False 685 self.__watcherActive = False
676 686
677 def directoryChanged(self, path): 687 def directoryChanged(self, path):
678 """ 688 """
679 Public slot to handle the directoryChanged signal of the watcher. 689 Public slot to handle the directoryChanged signal of the watcher.
680 690
681 @param path path of the directory (string) 691 @param path path of the directory (string)
682 """ 692 """
683 if not self.__watcherActive: 693 if not self.__watcherActive:
684 return 694 return
685 695
686 if path not in self.watchedItems: 696 if path not in self.watchedItems:
687 # just ignore the situation we don't have a reference to the item 697 # just ignore the situation we don't have a reference to the item
688 return 698 return
689 699
690 fileFilter = ( 700 fileFilter = (
691 ( 701 (QDir.Filter.AllEntries | QDir.Filter.Hidden | QDir.Filter.NoDotAndDotDot)
692 QDir.Filter.AllEntries | 702 if Preferences.getProject("BrowsersListHiddenFiles")
693 QDir.Filter.Hidden | 703 else QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot
694 QDir.Filter.NoDotAndDotDot
695 )
696 if Preferences.getProject("BrowsersListHiddenFiles") else
697 QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot
698 ) 704 )
699 705
700 for itm in self.watchedItems[path]: 706 for itm in self.watchedItems[path]:
701 oldCnt = itm.childCount() 707 oldCnt = itm.childCount()
702 708
703 qdir = QDir(itm.dirName()) 709 qdir = QDir(itm.dirName())
704 710
705 entryInfoList = qdir.entryInfoList(fileFilter) 711 entryInfoList = qdir.entryInfoList(fileFilter)
706 712
707 # step 1: check for new entries 713 # step 1: check for new entries
708 children = itm.children() 714 children = itm.children()
709 for f in entryInfoList: 715 for f in entryInfoList:
710 fpath = Utilities.toNativeSeparators(f.absoluteFilePath()) 716 fpath = Utilities.toNativeSeparators(f.absoluteFilePath())
711 childFound = False 717 childFound = False
714 childFound = True 720 childFound = True
715 children.remove(child) 721 children.remove(child)
716 break 722 break
717 if childFound: 723 if childFound:
718 continue 724 continue
719 725
720 cnt = itm.childCount() 726 cnt = itm.childCount()
721 self.beginInsertRows( 727 self.beginInsertRows(self.createIndex(itm.row(), 0, itm), cnt, cnt)
722 self.createIndex(itm.row(), 0, itm), cnt, cnt)
723 node = ( 728 node = (
724 ProjectBrowserDirectoryItem( 729 ProjectBrowserDirectoryItem(
725 itm, 730 itm,
726 Utilities.toNativeSeparators(f.absoluteFilePath()), 731 Utilities.toNativeSeparators(f.absoluteFilePath()),
727 itm.getProjectTypes()[0], 732 itm.getProjectTypes()[0],
728 False) 733 False,
729 if f.isDir() else 734 )
730 ProjectBrowserFileItem( 735 if f.isDir()
736 else ProjectBrowserFileItem(
731 itm, 737 itm,
732 Utilities.toNativeSeparators(f.absoluteFilePath()), 738 Utilities.toNativeSeparators(f.absoluteFilePath()),
733 itm.getProjectTypes()[0]) 739 itm.getProjectTypes()[0],
740 )
734 ) 741 )
735 self._addItem(node, itm) 742 self._addItem(node, itm)
736 if self.project.vcs is not None: 743 if self.project.vcs is not None:
737 self.project.vcs.clearStatusCache() 744 self.project.vcs.clearStatusCache()
738 state = self.project.vcs.vcsRegisteredState(node.name()) 745 state = self.project.vcs.vcsRegisteredState(node.name())
739 if state == self.project.vcs.canBeCommitted: 746 if state == self.project.vcs.canBeCommitted:
740 node.addVcsStatus(self.project.vcs.vcsName()) 747 node.addVcsStatus(self.project.vcs.vcsName())
741 else: 748 else:
742 node.addVcsStatus(self.tr("local")) 749 node.addVcsStatus(self.tr("local"))
743 self.endInsertRows() 750 self.endInsertRows()
744 751
745 # step 2: check for removed entries 752 # step 2: check for removed entries
746 if len(entryInfoList) != itm.childCount(): 753 if len(entryInfoList) != itm.childCount():
747 for row in range(oldCnt - 1, -1, -1): 754 for row in range(oldCnt - 1, -1, -1):
748 child = itm.child(row) 755 child = itm.child(row)
749 childname = Utilities.fromNativeSeparators(child.name()) 756 childname = Utilities.fromNativeSeparators(child.name())
753 entryFound = True 760 entryFound = True
754 entryInfoList.remove(f) 761 entryInfoList.remove(f)
755 break 762 break
756 if entryFound: 763 if entryFound:
757 continue 764 continue
758 765
759 self._removeWatchedItem(child) 766 self._removeWatchedItem(child)
760 self.beginRemoveRows( 767 self.beginRemoveRows(self.createIndex(itm.row(), 0, itm), row, row)
761 self.createIndex(itm.row(), 0, itm), row, row)
762 itm.removeChild(child) 768 itm.removeChild(child)
763 self.endRemoveRows() 769 self.endRemoveRows()
764 770
765 def __addVCSStatus(self, item, name): 771 def __addVCSStatus(self, item, name):
766 """ 772 """
767 Private method used to set the vcs status of a node. 773 Private method used to set the vcs status of a node.
768 774
769 @param item item to work on 775 @param item item to work on
770 @param name filename belonging to this item (string) 776 @param name filename belonging to this item (string)
771 """ 777 """
772 if self.project.vcs is not None: 778 if self.project.vcs is not None:
773 state = self.project.vcs.vcsRegisteredState(name) 779 state = self.project.vcs.vcsRegisteredState(name)
775 item.addVcsStatus(self.project.vcs.vcsName()) 781 item.addVcsStatus(self.project.vcs.vcsName())
776 else: 782 else:
777 item.addVcsStatus(self.tr("local")) 783 item.addVcsStatus(self.tr("local"))
778 else: 784 else:
779 item.addVcsStatus("") 785 item.addVcsStatus("")
780 786
781 def __updateVCSStatus(self, item, name, recursive=True): 787 def __updateVCSStatus(self, item, name, recursive=True):
782 """ 788 """
783 Private method used to update the vcs status of a node. 789 Private method used to update the vcs status of a node.
784 790
785 @param item item to work on 791 @param item item to work on
786 @param name filename belonging to this item (string) 792 @param name filename belonging to this item (string)
787 @param recursive flag indicating a recursive update (boolean) 793 @param recursive flag indicating a recursive update (boolean)
788 """ 794 """
789 if self.project.vcs is not None: 795 if self.project.vcs is not None:
798 parentItem = item.parent() 804 parentItem = item.parent()
799 if name and parentItem is not self.rootItem: 805 if name and parentItem is not self.rootItem:
800 self.__updateVCSStatus(parentItem, name, recursive) 806 self.__updateVCSStatus(parentItem, name, recursive)
801 else: 807 else:
802 item.setVcsStatus("") 808 item.setVcsStatus("")
803 809
804 index = self.createIndex(item.row(), 0, item) 810 index = self.createIndex(item.row(), 0, item)
805 self.dataChanged.emit(index, index) 811 self.dataChanged.emit(index, index)
806 812
807 def updateVCSStatus(self, name, recursive=True): 813 def updateVCSStatus(self, name, recursive=True):
808 """ 814 """
809 Public method used to update the vcs status of a node. 815 Public method used to update the vcs status of a node.
810 816
811 @param name filename belonging to this item (string) 817 @param name filename belonging to this item (string)
812 @param recursive flag indicating a recursive update (boolean) 818 @param recursive flag indicating a recursive update (boolean)
813 """ 819 """
814 item = self.findItem(name) 820 item = self.findItem(name)
815 if item: 821 if item:
816 self.__updateVCSStatus(item, name, recursive) 822 self.__updateVCSStatus(item, name, recursive)
817 823
818 def removeItem(self, name): 824 def removeItem(self, name):
819 """ 825 """
820 Public method to remove a named item. 826 Public method to remove a named item.
821 827
822 @param name file or directory name of the item (string). 828 @param name file or directory name of the item (string).
823 """ 829 """
824 fname = os.path.basename(name) 830 fname = os.path.basename(name)
825 parentItem = self.findParentItemByName(0, name)[0] 831 parentItem = self.findParentItemByName(0, name)[0]
826 parentIndex = ( 832 parentIndex = (
827 QModelIndex() 833 QModelIndex()
828 if parentItem == self.rootItem else 834 if parentItem == self.rootItem
829 self.createIndex(parentItem.row(), 0, parentItem) 835 else self.createIndex(parentItem.row(), 0, parentItem)
830 ) 836 )
831 childItem = self.findChildItem(fname, 0, parentItem) 837 childItem = self.findChildItem(fname, 0, parentItem)
832 if childItem is not None: 838 if childItem is not None:
833 self.beginRemoveRows(parentIndex, childItem.row(), childItem.row()) 839 self.beginRemoveRows(parentIndex, childItem.row(), childItem.row())
834 parentItem.removeChild(childItem) 840 parentItem.removeChild(childItem)
835 self.endRemoveRows() 841 self.endRemoveRows()
836 842
837 def repopulateItem(self, name): 843 def repopulateItem(self, name):
838 """ 844 """
839 Public method to repopulate an item. 845 Public method to repopulate an item.
840 846
841 @param name name of the file relative to the project root (string) 847 @param name name of the file relative to the project root (string)
842 """ 848 """
843 itm = self.findItem(name) 849 itm = self.findItem(name)
844 if itm is None: 850 if itm is None:
845 return 851 return
846 852
847 if itm.isLazyPopulated(): 853 if itm.isLazyPopulated():
848 if not itm.isPopulated(): 854 if not itm.isPopulated():
849 # item is not populated yet, nothing to do 855 # item is not populated yet, nothing to do
850 return 856 return
851 857
852 if itm.childCount(): 858 if itm.childCount():
853 index = self.createIndex(itm.row(), 0, itm) 859 index = self.createIndex(itm.row(), 0, itm)
854 self.beginRemoveRows(index, 0, itm.childCount() - 1) 860 self.beginRemoveRows(index, 0, itm.childCount() - 1)
855 itm.removeChildren() 861 itm.removeChildren()
856 self.endRemoveRows() 862 self.endRemoveRows()
857 Utilities.ModuleParser.resetParsedModule( 863 Utilities.ModuleParser.resetParsedModule(
858 os.path.join(self.project.ppath, name)) 864 os.path.join(self.project.ppath, name)
859 865 )
866
860 self.populateItem(itm, True) 867 self.populateItem(itm, True)
861 868
862 def projectPropertiesChanged(self): 869 def projectPropertiesChanged(self):
863 """ 870 """
864 Public method to react on a change of the project properties. 871 Public method to react on a change of the project properties.
865 """ 872 """
866 # nothing to do for now 873 # nothing to do for now
867 return 874 return
868 875
869 def changeVCSStates(self, statesList): 876 def changeVCSStates(self, statesList):
870 """ 877 """
871 Public slot to record the (non normal) VCS states. 878 Public slot to record the (non normal) VCS states.
872 879
873 @param statesList list of VCS state entries (list of strings) giving 880 @param statesList list of VCS state entries (list of strings) giving
874 the states in the first column and the path relative to the project 881 the states in the first column and the path relative to the project
875 directory starting with the third column. The allowed status flags 882 directory starting with the third column. The allowed status flags
876 are: 883 are:
877 <ul> 884 <ul>
885 </ul> 892 </ul>
886 """ 893 """
887 statesList.sort() 894 statesList.sort()
888 lastHead = "" 895 lastHead = ""
889 itemCache = {} 896 itemCache = {}
890 if len(statesList) == 1 and statesList[0] == '--RESET--': 897 if len(statesList) == 1 and statesList[0] == "--RESET--":
891 statesList = [] 898 statesList = []
892 for name in list(self.__vcsStatus.keys()): 899 for name in list(self.__vcsStatus.keys()):
893 statesList.append(" {0}".format(name)) 900 statesList.append(" {0}".format(name))
894 901
895 for name in statesList: 902 for name in statesList:
896 state = name[0] 903 state = name[0]
897 if state in "AMORUZ ": 904 if state in "AMORUZ ":
898 name = name[1:].strip() 905 name = name[1:].strip()
899 if state == ' ': 906 if state == " ":
900 if name in self.__vcsStatus: 907 if name in self.__vcsStatus:
901 del self.__vcsStatus[name] 908 del self.__vcsStatus[name]
902 else: 909 else:
903 self.__vcsStatus[name] = state 910 self.__vcsStatus[name] = state
904 911
905 try: 912 try:
906 itm = itemCache[name] 913 itm = itemCache[name]
907 except KeyError: 914 except KeyError:
908 itm = self.findItem(name) 915 itm = self.findItem(name)
909 if itm: 916 if itm:
911 if itm: 918 if itm:
912 itm.setVcsState(state) 919 itm.setVcsState(state)
913 itm.setVcsStatus(self.project.vcs.vcsName()) 920 itm.setVcsStatus(self.project.vcs.vcsName())
914 index1 = self.createIndex(itm.row(), 0, itm) 921 index1 = self.createIndex(itm.row(), 0, itm)
915 index2 = self.createIndex( 922 index2 = self.createIndex(
916 itm.row(), self.rootItem.columnCount(), itm) 923 itm.row(), self.rootItem.columnCount(), itm
924 )
917 self.dataChanged.emit(index1, index2) 925 self.dataChanged.emit(index1, index2)
918 926
919 head, tail = os.path.split(name) 927 head, tail = os.path.split(name)
920 if head != lastHead: 928 if head != lastHead:
921 if lastHead: 929 if lastHead:
922 self.__changeParentsVCSState(lastHead, itemCache) 930 self.__changeParentsVCSState(lastHead, itemCache)
923 lastHead = head 931 lastHead = head
924 if lastHead: 932 if lastHead:
925 self.__changeParentsVCSState(lastHead, itemCache) 933 self.__changeParentsVCSState(lastHead, itemCache)
926 try: 934 try:
927 globalVcsStatus = sorted(self.__vcsStatus.values())[-1] 935 globalVcsStatus = sorted(self.__vcsStatus.values())[-1]
928 except IndexError: 936 except IndexError:
929 globalVcsStatus = ' ' 937 globalVcsStatus = " "
930 self.vcsStateChanged.emit(globalVcsStatus) 938 self.vcsStateChanged.emit(globalVcsStatus)
931 939
932 def __changeParentsVCSState(self, path, itemCache): 940 def __changeParentsVCSState(self, path, itemCache):
933 """ 941 """
934 Private method to recursively change the parents VCS state. 942 Private method to recursively change the parents VCS state.
935 943
936 @param path pathname of parent item (string) 944 @param path pathname of parent item (string)
937 @param itemCache reference to the item cache used to store 945 @param itemCache reference to the item cache used to store
938 references to named items 946 references to named items
939 """ 947 """
940 while path: 948 while path:
951 state = id_.vcsState 959 state = id_.vcsState
952 if state != itm.vcsState: 960 if state != itm.vcsState:
953 itm.setVcsState(state) 961 itm.setVcsState(state)
954 index1 = self.createIndex(itm.row(), 0, itm) 962 index1 = self.createIndex(itm.row(), 0, itm)
955 index2 = self.createIndex( 963 index2 = self.createIndex(
956 itm.row(), self.rootItem.columnCount(), itm) 964 itm.row(), self.rootItem.columnCount(), itm
965 )
957 self.dataChanged.emit(index1, index2) 966 self.dataChanged.emit(index1, index2)
958 path, tail = os.path.split(path) 967 path, tail = os.path.split(path)
959 968
960 def preferencesChanged(self): 969 def preferencesChanged(self):
961 """ 970 """
962 Public method used to handle a change in preferences. 971 Public method used to handle a change in preferences.
963 """ 972 """
964 for code in list(self.colorNames.keys()): 973 for code in list(self.colorNames.keys()):
965 color = Preferences.getProjectBrowserColour(self.colorNames[code]) 974 color = Preferences.getProjectBrowserColour(self.colorNames[code])
966 if color.name() == self.itemBackgroundColors[code].name(): 975 if color.name() == self.itemBackgroundColors[code].name():
967 continue 976 continue
968 977
969 self.itemBackgroundColors[code] = color 978 self.itemBackgroundColors[code] = color
970 979
971 color = Preferences.getProjectBrowserColour("Highlighted") 980 color = Preferences.getProjectBrowserColour("Highlighted")
972 if self.highLightColor.name() != color.name(): 981 if self.highLightColor.name() != color.name():
973 self.highLightColor = color 982 self.highLightColor = color

eric ide

mercurial