src/eric7/UI/BrowserModel.py

branch
eric7
changeset 9209
b99e7fd55fd3
parent 8881
54e42bc2437a
child 9221
bf71ee032bb4
equal deleted inserted replaced
9208:3fc8dfeb6ebe 9209:b99e7fd55fd3
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2006 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
4 #
5
6 """
7 Module implementing the browser model.
8 """
9
10 import os
11 import fnmatch
12 import json
13 import contextlib
14
15 from PyQt6.QtCore import (
16 QDir, QModelIndex, QAbstractItemModel, QFileSystemWatcher, Qt, QProcess,
17 QCoreApplication
18 )
19 from PyQt6.QtGui import QImageReader, QFont
20 from PyQt6.QtWidgets import QApplication
21
22 import UI.PixmapCache
23 import Preferences
24 import Utilities
25
26 BrowserItemRoot = 0
27 BrowserItemDirectory = 1
28 BrowserItemSysPath = 2
29 BrowserItemFile = 3
30 BrowserItemClass = 4
31 BrowserItemMethod = 5
32 BrowserItemAttributes = 6
33 BrowserItemAttribute = 7
34 BrowserItemCoding = 8
35 BrowserItemImports = 9
36 BrowserItemImport = 10
37
38
39 class BrowserModel(QAbstractItemModel):
40 """
41 Class implementing the browser model.
42 """
43 def __init__(self, parent=None, nopopulate=False):
44 """
45 Constructor
46
47 @param parent reference to parent object (QObject)
48 @param nopopulate flag indicating to not populate the model
49 (boolean)
50 """
51 super().__init__(parent)
52
53 self.progDir = None
54
55 self.__sysPathInterpreter = ""
56 self.__sysPathItem = None
57
58 if not nopopulate:
59 self.watchedItems = {}
60 self.watchedFileItems = {}
61 self.watcher = QFileSystemWatcher(self)
62 self.watcher.directoryChanged.connect(self.directoryChanged)
63 self.watcher.fileChanged.connect(self.fileChanged)
64
65 rootData = QCoreApplication.translate("BrowserModel", "Name")
66 self.rootItem = BrowserItem(None, rootData)
67
68 self.__populateModel()
69
70 def columnCount(self, parent=None):
71 """
72 Public method to get the number of columns.
73
74 @param parent index of parent item (QModelIndex)
75 @return number of columns (integer)
76 """
77 if parent is None:
78 parent = QModelIndex()
79
80 item = (parent.internalPointer() if parent.isValid()
81 else self.rootItem)
82
83 return item.columnCount() + 1
84
85 def data(self, index, role):
86 """
87 Public method to get data of an item.
88
89 @param index index of the data to retrieve (QModelIndex)
90 @param role role of data (Qt.ItemDataRole)
91 @return requested data
92 """
93 if not index.isValid():
94 return None
95
96 if role == Qt.ItemDataRole.DisplayRole:
97 item = index.internalPointer()
98 if index.column() < item.columnCount():
99 return item.data(index.column())
100 elif (
101 index.column() == item.columnCount() and
102 index.column() < self.columnCount(self.parent(index))
103 ):
104 # This is for the case where an item under a multi-column
105 # parent doesn't have a value for all the columns
106 return ""
107 elif role == Qt.ItemDataRole.DecorationRole:
108 if index.column() == 0:
109 return index.internalPointer().getIcon()
110 elif role == Qt.ItemDataRole.FontRole:
111 item = index.internalPointer()
112 if item.isSymlink():
113 font = QFont(QApplication.font("QTreeView"))
114 font.setItalic(True)
115 return font
116
117 return None
118
119 def flags(self, index):
120 """
121 Public method to get the item flags.
122
123 @param index index of the data to retrieve (QModelIndex)
124 @return requested flags (Qt.ItemFlags)
125 """
126 if not index.isValid():
127 return Qt.ItemFlag.ItemIsEnabled
128
129 return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable
130
131 def headerData(self, section, orientation,
132 role=Qt.ItemDataRole.DisplayRole):
133 """
134 Public method to get the header data.
135
136 @param section number of section to get data for (integer)
137 @param orientation header orientation (Qt.Orientation)
138 @param role role of data (Qt.ItemDataRole)
139 @return requested header data
140 """
141 if (
142 orientation == Qt.Orientation.Horizontal and
143 role == Qt.ItemDataRole.DisplayRole
144 ):
145 if section >= self.rootItem.columnCount():
146 return ""
147 else:
148 return self.rootItem.data(section)
149
150 return None
151
152 def index(self, row, column, parent=None):
153 """
154 Public method to create an index.
155
156 @param row row number of the new index (integer)
157 @param column column number of the new index (integer)
158 @param parent index of parent item (QModelIndex)
159 @return index object (QModelIndex)
160 """
161 if parent is None:
162 parent = QModelIndex()
163
164 # The model/view framework considers negative values out-of-bounds,
165 # however in python they work when indexing into lists. So make sure
166 # we return an invalid index for out-of-bounds row/col
167 if (
168 row < 0 or
169 column < 0 or
170 row >= self.rowCount(parent) or
171 column >= self.columnCount(parent)
172 ):
173 return QModelIndex()
174
175 parentItem = (
176 parent.internalPointer()
177 if parent.isValid() else
178 self.rootItem
179 )
180
181 try:
182 if not parentItem.isPopulated():
183 self.populateItem(parentItem)
184 childItem = parentItem.child(row)
185 except IndexError:
186 childItem = None
187 if childItem:
188 return self.createIndex(row, column, childItem)
189 else:
190 return QModelIndex()
191
192 def parent(self, index):
193 """
194 Public method to get the index of the parent object.
195
196 @param index index of the item (QModelIndex)
197 @return index of parent item (QModelIndex)
198 """
199 if not index.isValid():
200 return QModelIndex()
201
202 childItem = index.internalPointer()
203 parentItem = childItem.parent()
204
205 if parentItem is None or parentItem == self.rootItem:
206 return QModelIndex()
207
208 return self.createIndex(parentItem.row(), 0, parentItem)
209
210 def rowCount(self, parent=None):
211 """
212 Public method to get the number of rows.
213
214 @param parent index of parent item (QModelIndex)
215 @return number of rows (integer)
216 """
217 if parent is None:
218 parent = QModelIndex()
219
220 # Only the first column should have children
221 if parent.column() > 0:
222 return 0
223
224 if not parent.isValid():
225 parentItem = self.rootItem
226 else:
227 parentItem = parent.internalPointer()
228 if not parentItem.isPopulated(): # lazy population
229 self.populateItem(parentItem)
230
231 return parentItem.childCount()
232
233 def hasChildren(self, parent=None):
234 """
235 Public method to check for the presence of child items.
236
237 We always return True for normal items in order to do lazy
238 population of the tree.
239
240 @param parent index of parent item (QModelIndex)
241 @return flag indicating the presence of child items (boolean)
242 """
243 if parent is None:
244 parent = QModelIndex()
245
246 # Only the first column should have children
247 if parent.column() > 0:
248 return 0
249
250 if not parent.isValid():
251 return self.rootItem.childCount() > 0
252
253 if parent.internalPointer().isLazyPopulated():
254 return True
255 else:
256 return parent.internalPointer().childCount() > 0
257
258 def clear(self):
259 """
260 Public method to clear the model.
261 """
262 self.beginResetModel()
263 self.rootItem.removeChildren()
264 self.endResetModel()
265
266 def item(self, index):
267 """
268 Public method to get a reference to an item.
269
270 @param index index of the data to retrieve (QModelIndex)
271 @return requested item reference (BrowserItem)
272 """
273 if not index.isValid():
274 return None
275
276 return index.internalPointer()
277
278 def _addWatchedItem(self, itm):
279 """
280 Protected method to watch an item.
281
282 @param itm item to be watched (BrowserDirectoryItem)
283 """
284 if isinstance(itm, BrowserDirectoryItem):
285 dirName = itm.dirName()
286 if (
287 dirName != "" and
288 not dirName.startswith("//") and
289 not dirName.startswith("\\\\")
290 ):
291 if dirName not in self.watcher.directories():
292 self.watcher.addPath(dirName)
293 if dirName in self.watchedItems:
294 if itm not in self.watchedItems[dirName]:
295 self.watchedItems[dirName].append(itm)
296 else:
297 self.watchedItems[dirName] = [itm]
298
299 def _removeWatchedItem(self, itm):
300 """
301 Protected method to remove a watched item.
302
303 @param itm item to be removed (BrowserDirectoryItem)
304 """
305 if isinstance(itm, BrowserDirectoryItem):
306 dirName = itm.dirName()
307 if dirName in self.watchedItems:
308 if itm in self.watchedItems[dirName]:
309 self.watchedItems[dirName].remove(itm)
310 if len(self.watchedItems[dirName]) == 0:
311 del self.watchedItems[dirName]
312 self.watcher.removePath(dirName)
313
314 def directoryChanged(self, path):
315 """
316 Public slot to handle the directoryChanged signal of the watcher.
317
318 @param path path of the directory (string)
319 """
320 if path not in self.watchedItems:
321 # just ignore the situation we don't have a reference to the item
322 return
323
324 dirFilter = QDir.Filter.AllEntries | QDir.Filter.NoDotAndDotDot
325
326 for itm in self.watchedItems[path]:
327 oldCnt = itm.childCount()
328
329 qdir = QDir(itm.dirName())
330
331 entryInfoList = qdir.entryInfoList(dirFilter)
332
333 # step 1: check for new entries
334 children = itm.children()
335 for f in entryInfoList:
336 fpath = Utilities.toNativeSeparators(f.absoluteFilePath())
337 childFound = False
338 for child in children:
339 if child.name() == fpath:
340 childFound = True
341 children.remove(child)
342 break
343 if childFound:
344 continue
345
346 cnt = itm.childCount()
347 self.beginInsertRows(
348 self.createIndex(itm.row(), 0, itm), cnt, cnt)
349 node = (
350 BrowserDirectoryItem(
351 itm,
352 Utilities.toNativeSeparators(f.absoluteFilePath()),
353 False)
354 if f.isDir() else
355 BrowserFileItem(
356 itm,
357 Utilities.toNativeSeparators(f.absoluteFilePath()))
358 )
359 self._addItem(node, itm)
360 self.endInsertRows()
361
362 # step 2: check for removed entries
363 if len(entryInfoList) != itm.childCount():
364 for row in range(oldCnt - 1, -1, -1):
365 child = itm.child(row)
366 childname = Utilities.fromNativeSeparators(child.name())
367 entryFound = False
368 for f in entryInfoList:
369 if f.absoluteFilePath() == childname:
370 entryFound = True
371 entryInfoList.remove(f)
372 break
373 if entryFound:
374 continue
375
376 self._removeWatchedItem(child)
377 self.beginRemoveRows(
378 self.createIndex(itm.row(), 0, itm), row, row)
379 itm.removeChild(child)
380 self.endRemoveRows()
381
382 def __populateModel(self):
383 """
384 Private method to populate the browser model.
385 """
386 self.toplevelDirs = []
387 tdp = Preferences.getSettings().value('BrowserModel/ToplevelDirs')
388 if tdp:
389 self.toplevelDirs = tdp
390 else:
391 self.toplevelDirs.append(
392 Utilities.toNativeSeparators(QDir.homePath()))
393 for d in QDir.drives():
394 self.toplevelDirs.append(Utilities.toNativeSeparators(
395 d.absoluteFilePath()))
396
397 for d in self.toplevelDirs:
398 itm = BrowserDirectoryItem(self.rootItem, d)
399 self._addItem(itm, self.rootItem)
400
401 def interpreterChanged(self, interpreter):
402 """
403 Public method to handle a change of the debug client's interpreter.
404
405 @param interpreter interpreter of the debug client (string)
406 """
407 if interpreter and "python" in interpreter.lower():
408 if interpreter.endswith("w.exe"):
409 interpreter = interpreter.replace("w.exe", ".exe")
410 if self.__sysPathInterpreter != interpreter:
411 self.__sysPathInterpreter = interpreter
412 # step 1: remove sys.path entry
413 if self.__sysPathItem is not None:
414 self.beginRemoveRows(
415 QModelIndex(), self.__sysPathItem.row(),
416 self.__sysPathItem.row())
417 self.rootItem.removeChild(self.__sysPathItem)
418 self.endRemoveRows()
419 self.__sysPathItem = None
420
421 if self.__sysPathInterpreter:
422 # step 2: add a new one
423 self.__sysPathItem = BrowserSysPathItem(self.rootItem)
424 self.addItem(self.__sysPathItem)
425 else:
426 # remove sys.path entry
427 if self.__sysPathItem is not None:
428 self.beginRemoveRows(
429 QModelIndex(), self.__sysPathItem.row(),
430 self.__sysPathItem.row())
431 self.rootItem.removeChild(self.__sysPathItem)
432 self.endRemoveRows()
433 self.__sysPathItem = None
434 self.__sysPathInterpreter = ""
435
436 def programChange(self, dirname):
437 """
438 Public method to change the entry for the directory of file being
439 debugged.
440
441 @param dirname name of the directory containing the file (string)
442 """
443 if self.progDir:
444 if dirname == self.progDir.dirName():
445 return
446
447 # remove old entry
448 self._removeWatchedItem(self.progDir)
449 self.beginRemoveRows(
450 QModelIndex(), self.progDir.row(), self.progDir.row())
451 self.rootItem.removeChild(self.progDir)
452 self.endRemoveRows()
453 self.progDir = None
454
455 itm = BrowserDirectoryItem(self.rootItem, dirname)
456 self.addItem(itm)
457 self.progDir = itm
458
459 def addTopLevelDir(self, dirname):
460 """
461 Public method to add a new toplevel directory.
462
463 @param dirname name of the new toplevel directory (string)
464 """
465 if dirname not in self.toplevelDirs:
466 itm = BrowserDirectoryItem(self.rootItem, dirname)
467 self.addItem(itm)
468 self.toplevelDirs.append(itm.dirName())
469
470 def removeToplevelDir(self, index):
471 """
472 Public method to remove a toplevel directory.
473
474 @param index index of the toplevel directory to be removed
475 (QModelIndex)
476 """
477 if not index.isValid():
478 return
479
480 item = index.internalPointer()
481 self.beginRemoveRows(index.parent(), index.row(), index.row())
482 self.rootItem.removeChild(item)
483 self.endRemoveRows()
484
485 self.toplevelDirs.remove(item.dirName())
486 self._removeWatchedItem(item)
487
488 def saveToplevelDirs(self):
489 """
490 Public slot to save the toplevel directories.
491 """
492 Preferences.getSettings().setValue(
493 'BrowserModel/ToplevelDirs', self.toplevelDirs)
494
495 def _addItem(self, itm, parentItem):
496 """
497 Protected slot to add an item.
498
499 @param itm reference to item to add (BrowserItem)
500 @param parentItem reference to item to add to (BrowserItem)
501 """
502 parentItem.appendChild(itm)
503
504 def addItem(self, itm, parent=None):
505 """
506 Public slot to add an item.
507
508 @param itm item to add (BrowserItem)
509 @param parent index of parent item (QModelIndex)
510 """
511 if parent is None:
512 parent = QModelIndex()
513
514 parentItem = (
515 parent.internalPointer()
516 if parent.isValid() else
517 self.rootItem
518 )
519
520 cnt = parentItem.childCount()
521 self.beginInsertRows(parent, cnt, cnt)
522 self._addItem(itm, parentItem)
523 self.endInsertRows()
524
525 def populateItem(self, parentItem, repopulate=False):
526 """
527 Public method to populate an item's subtree.
528
529 @param parentItem reference to the item to be populated
530 @param repopulate flag indicating a repopulation (boolean)
531 """
532 if parentItem.type() == BrowserItemDirectory:
533 self.populateDirectoryItem(parentItem, repopulate)
534 elif parentItem.type() == BrowserItemSysPath:
535 self.populateSysPathItem(parentItem, repopulate)
536 elif parentItem.type() == BrowserItemFile:
537 self.populateFileItem(parentItem, repopulate)
538 elif parentItem.type() == BrowserItemClass:
539 self.populateClassItem(parentItem, repopulate)
540 elif parentItem.type() == BrowserItemMethod:
541 self.populateMethodItem(parentItem, repopulate)
542 elif parentItem.type() == BrowserItemAttributes:
543 self.populateClassAttributesItem(parentItem, repopulate)
544
545 def populateDirectoryItem(self, parentItem, repopulate=False):
546 """
547 Public method to populate a directory item's subtree.
548
549 @param parentItem reference to the directory item to be populated
550 @param repopulate flag indicating a repopulation (boolean)
551 """
552 self._addWatchedItem(parentItem)
553
554 qdir = QDir(parentItem.dirName())
555
556 dirFilter = (QDir.Filter.AllEntries |
557 QDir.Filter.NoDotAndDotDot)
558 entryInfoList = qdir.entryInfoList(dirFilter)
559 if len(entryInfoList) > 0:
560 if repopulate:
561 self.beginInsertRows(
562 self.createIndex(parentItem.row(), 0, parentItem),
563 0, len(entryInfoList) - 1)
564 for f in entryInfoList:
565 if f.isDir():
566 node = BrowserDirectoryItem(
567 parentItem,
568 Utilities.toNativeSeparators(f.absoluteFilePath()),
569 False)
570 else:
571 fileFilters = Preferences.getUI(
572 "BrowsersFileFilters").split(";")
573 if fileFilters:
574 fn = f.fileName()
575 if any(fnmatch.fnmatch(fn, ff.strip())
576 for ff in fileFilters):
577 continue
578 node = BrowserFileItem(
579 parentItem,
580 Utilities.toNativeSeparators(f.absoluteFilePath()))
581 self._addItem(node, parentItem)
582 if repopulate:
583 self.endInsertRows()
584
585 def populateSysPathItem(self, parentItem, repopulate=False):
586 """
587 Public method to populate a sys.path item's subtree.
588
589 @param parentItem reference to the sys.path item to be populated
590 @param repopulate flag indicating a repopulation (boolean)
591 """
592 if self.__sysPathInterpreter:
593 script = "import sys, json; print(json.dumps(sys.path))"
594 proc = QProcess()
595 proc.start(self.__sysPathInterpreter, ["-c", script])
596 finished = proc.waitForFinished(3000)
597 if finished:
598 procOutput = str(proc.readAllStandardOutput(),
599 Preferences.getSystem("IOEncoding"),
600 'replace')
601 syspath = [p for p in json.loads(procOutput) if p]
602 if len(syspath) > 0:
603 if repopulate:
604 self.beginInsertRows(
605 self.createIndex(parentItem.row(), 0, parentItem),
606 0, len(syspath) - 1)
607 for p in syspath:
608 node = (
609 BrowserDirectoryItem(parentItem, p)
610 if os.path.isdir(p) else
611 BrowserFileItem(parentItem, p)
612 )
613 self._addItem(node, parentItem)
614 if repopulate:
615 self.endInsertRows()
616 else:
617 proc.kill()
618
619 def populateFileItem(self, parentItem, repopulate=False):
620 """
621 Public method to populate a file item's subtree.
622
623 @param parentItem reference to the file item to be populated
624 @param repopulate flag indicating a repopulation (boolean)
625 """
626 import Utilities.ClassBrowsers
627 moduleName = parentItem.moduleName()
628 fileName = parentItem.fileName()
629 try:
630 dictionary = Utilities.ClassBrowsers.readmodule(
631 moduleName, [parentItem.dirName()],
632 parentItem.isPython3File() or parentItem.isCythonFile())
633 except ImportError:
634 return
635
636 keys = list(dictionary.keys())
637 if len(keys) > 0:
638 if repopulate:
639 last = len(keys) - 1
640 if (
641 "@@Coding@@" in keys and
642 not Preferences.getUI("BrowserShowCoding")
643 ):
644 last -= 1
645 self.beginInsertRows(
646 self.createIndex(parentItem.row(), 0, parentItem),
647 0, last)
648
649 for key in keys:
650 if key.startswith("@@"):
651 # special treatment done later
652 continue
653 cl = dictionary[key]
654 with contextlib.suppress(AttributeError):
655 if cl.module == moduleName:
656 node = BrowserClassItem(parentItem, cl, fileName)
657 self._addItem(node, parentItem)
658 if "@@Coding@@" in keys and Preferences.getUI("BrowserShowCoding"):
659 node = BrowserCodingItem(
660 parentItem,
661 QCoreApplication.translate("BrowserModel", "Coding: {0}")
662 .format(dictionary["@@Coding@@"].coding),
663 dictionary["@@Coding@@"].linenumber)
664 self._addItem(node, parentItem)
665 if "@@Globals@@" in keys:
666 node = BrowserGlobalsItem(
667 parentItem,
668 dictionary["@@Globals@@"].globals,
669 QCoreApplication.translate("BrowserModel", "Globals"))
670 self._addItem(node, parentItem)
671 if "@@Import@@" in keys or "@@ImportFrom@@" in keys:
672 node = BrowserImportsItem(
673 parentItem,
674 QCoreApplication.translate("BrowserModel", "Imports"))
675 self._addItem(node, parentItem)
676 if "@@Import@@" in keys:
677 for importedModule in (
678 dictionary["@@Import@@"].getImports().values()
679 ):
680 m_node = BrowserImportItem(
681 node,
682 importedModule.importedModuleName,
683 importedModule.file,
684 importedModule.linenos)
685 self._addItem(m_node, node)
686 for importedName, linenos in (
687 importedModule.importedNames.items()
688 ):
689 mn_node = BrowserImportItem(
690 m_node,
691 importedName,
692 importedModule.file,
693 linenos,
694 isModule=False)
695 self._addItem(mn_node, m_node)
696
697 if repopulate:
698 self.endInsertRows()
699
700 parentItem._populated = True
701 if (
702 parentItem.type_ == BrowserItemFile and
703 fileName not in self.watchedFileItems
704 ):
705 # watch the file only in the file browser not the project viewer
706 self.watcher.addPath(fileName)
707 self.watchedFileItems[fileName] = parentItem
708
709 def repopulateFileItem(self, itm):
710 """
711 Public method to repopulate a file item.
712
713 @param itm reference to the item to be repopulated
714 @type BrowserFileItem
715 """
716 if isinstance(itm, BrowserFileItem) and itm.isLazyPopulated():
717 if not itm.isPopulated():
718 # item is not populated yet, nothing to do
719 return
720
721 if itm.childCount():
722 index = self.createIndex(itm.row(), 0, itm)
723 self.beginRemoveRows(index, 0, itm.childCount() - 1)
724 itm.removeChildren()
725 self.endRemoveRows()
726
727 self.populateFileItem(itm, True)
728
729 def fileChanged(self, fileName):
730 """
731 Public method to react upon file changes.
732
733 @param fileName path of the changed file
734 @type str
735 """
736 if fileName in self.watchedFileItems:
737 if os.path.exists(fileName):
738 # the file was changed
739 self.repopulateFileItem(self.watchedFileItems[fileName])
740 else:
741 # the file does not exist anymore
742 del self.watchedFileItems[fileName]
743
744 def populateClassItem(self, parentItem, repopulate=False):
745 """
746 Public method to populate a class item's subtree.
747
748 @param parentItem reference to the class item to be populated
749 @param repopulate flag indicating a repopulation (boolean)
750 """
751 cl = parentItem.classObject()
752 file_ = parentItem.fileName()
753
754 if cl is None:
755 return
756
757 # build sorted list of names
758 keys = []
759 for name in list(cl.classes.keys()):
760 keys.append((name, 'c'))
761 for name in list(cl.methods.keys()):
762 keys.append((name, 'm'))
763
764 if len(cl.attributes):
765 node = BrowserClassAttributesItem(
766 parentItem, cl.attributes,
767 QCoreApplication.translate("BrowserModel", "Attributes"))
768 if repopulate:
769 self.addItem(
770 node, self.createIndex(parentItem.row(), 0, parentItem))
771 else:
772 self._addItem(node, parentItem)
773
774 if len(cl.globals):
775 node = BrowserClassAttributesItem(
776 parentItem, cl.globals,
777 QCoreApplication.translate("BrowserModel", "Class Attributes"),
778 True)
779 if repopulate:
780 self.addItem(
781 node, self.createIndex(parentItem.row(), 0, parentItem))
782 else:
783 self._addItem(node, parentItem)
784
785 if len(keys) > 0:
786 if repopulate:
787 self.beginInsertRows(
788 self.createIndex(parentItem.row(), 0, parentItem),
789 0, len(keys) - 1)
790 for key, kind in keys:
791 if kind == 'c':
792 node = BrowserClassItem(parentItem, cl.classes[key], file_)
793 elif kind == 'm':
794 node = BrowserMethodItem(parentItem, cl.methods[key],
795 file_)
796 self._addItem(node, parentItem)
797 if repopulate:
798 self.endInsertRows()
799
800 def populateMethodItem(self, parentItem, repopulate=False):
801 """
802 Public method to populate a method item's subtree.
803
804 @param parentItem reference to the method item to be populated
805 @param repopulate flag indicating a repopulation (boolean)
806 """
807 fn = parentItem.functionObject()
808 file_ = parentItem.fileName()
809
810 if fn is None:
811 return
812
813 # build sorted list of names
814 keys = []
815 for name in list(fn.classes.keys()):
816 keys.append((name, 'c'))
817 for name in list(fn.methods.keys()):
818 keys.append((name, 'm'))
819
820 if len(keys) > 0:
821 if repopulate:
822 self.beginInsertRows(
823 self.createIndex(parentItem.row(), 0, parentItem),
824 0, len(keys) - 1)
825 for key, kind in keys:
826 if kind == 'c':
827 node = BrowserClassItem(parentItem, fn.classes[key], file_)
828 elif kind == 'm':
829 node = BrowserMethodItem(parentItem, fn.methods[key],
830 file_)
831 self._addItem(node, parentItem)
832 if repopulate:
833 self.endInsertRows()
834
835 def populateClassAttributesItem(self, parentItem, repopulate=False):
836 """
837 Public method to populate a class attributes item's subtree.
838
839 @param parentItem reference to the class attributes item to be
840 populated
841 @param repopulate flag indicating a repopulation (boolean)
842 """
843 classAttributes = parentItem.isClassAttributes()
844 attributes = parentItem.attributes()
845 if not attributes:
846 return
847
848 keys = list(attributes.keys())
849 if len(keys) > 0:
850 if repopulate:
851 self.beginInsertRows(
852 self.createIndex(parentItem.row(), 0, parentItem),
853 0, len(keys) - 1)
854 for key in keys:
855 node = BrowserClassAttributeItem(parentItem, attributes[key],
856 classAttributes)
857 self._addItem(node, parentItem)
858 if repopulate:
859 self.endInsertRows()
860
861
862 class BrowserItem:
863 """
864 Class implementing the data structure for browser items.
865 """
866 def __init__(self, parent, data):
867 """
868 Constructor
869
870 @param parent reference to the parent item
871 @param data single data of the item
872 """
873 self.childItems = []
874
875 self.parentItem = parent
876 self.itemData = [data]
877 self.type_ = BrowserItemRoot
878 self.icon = UI.PixmapCache.getIcon("empty")
879 self._populated = True
880 self._lazyPopulation = False
881 self.symlink = False
882
883 def appendChild(self, child):
884 """
885 Public method to add a child to this item.
886
887 @param child reference to the child item to add (BrowserItem)
888 """
889 self.childItems.append(child)
890 self._populated = True
891
892 def removeChild(self, child):
893 """
894 Public method to remove a child.
895
896 @param child reference to the child to remove (BrowserItem)
897 """
898 self.childItems.remove(child)
899
900 def removeChildren(self):
901 """
902 Public method to remove all children.
903 """
904 self.childItems = []
905
906 def child(self, row):
907 """
908 Public method to get a child id.
909
910 @param row number of child to get the id of (integer)
911 @return reference to the child item (BrowserItem)
912 """
913 return self.childItems[row]
914
915 def children(self):
916 """
917 Public method to get the ids of all child items.
918
919 @return references to all child items (list of BrowserItem)
920 """
921 return self.childItems[:]
922
923 def childCount(self):
924 """
925 Public method to get the number of available child items.
926
927 @return number of child items (integer)
928 """
929 return len(self.childItems)
930
931 def columnCount(self):
932 """
933 Public method to get the number of available data items.
934
935 @return number of data items (integer)
936 """
937 return len(self.itemData)
938
939 def data(self, column):
940 """
941 Public method to get a specific data item.
942
943 @param column number of the requested data item (integer)
944 @return stored data item
945 """
946 try:
947 return self.itemData[column]
948 except IndexError:
949 return ""
950
951 def parent(self):
952 """
953 Public method to get the reference to the parent item.
954
955 @return reference to the parent item
956 """
957 return self.parentItem
958
959 def row(self):
960 """
961 Public method to get the row number of this item.
962
963 @return row number (integer)
964 """
965 try:
966 return self.parentItem.childItems.index(self)
967 except ValueError:
968 return 0
969
970 def type(self):
971 """
972 Public method to get the item type.
973
974 @return type of the item
975 """
976 return self.type_
977
978 def isPublic(self):
979 """
980 Public method returning the public visibility status.
981
982 @return flag indicating public visibility (boolean)
983 """
984 return True
985
986 def getIcon(self):
987 """
988 Public method to get the items icon.
989
990 @return the icon (QIcon)
991 """
992 return self.icon
993
994 def isPopulated(self):
995 """
996 Public method to chek, if this item is populated.
997
998 @return population status (boolean)
999 """
1000 return self._populated
1001
1002 def isLazyPopulated(self):
1003 """
1004 Public method to check, if this item should be populated lazyly.
1005
1006 @return lazy population flag (boolean)
1007 """
1008 return self._lazyPopulation
1009
1010 def lessThan(self, other, column, order):
1011 """
1012 Public method to check, if the item is less than the other one.
1013
1014 @param other reference to item to compare against (BrowserItem)
1015 @param column column number to use for the comparison (integer)
1016 @param order sort order (Qt.SortOrder) (for special sorting)
1017 @return true, if this item is less than other (boolean)
1018 """
1019 try:
1020 return self.itemData[column] < other.itemData[column]
1021 except IndexError:
1022 return False
1023
1024 def isSymlink(self):
1025 """
1026 Public method to check, if the items is a symbolic link.
1027
1028 @return flag indicating a symbolic link (boolean)
1029 """
1030 return self.symlink
1031
1032
1033 class BrowserDirectoryItem(BrowserItem):
1034 """
1035 Class implementing the data structure for browser directory items.
1036 """
1037 def __init__(self, parent, dinfo, full=True):
1038 """
1039 Constructor
1040
1041 @param parent parent item
1042 @param dinfo dinfo is the string for the directory (string)
1043 @param full flag indicating full pathname should be displayed (boolean)
1044 """
1045 self._dirName = os.path.abspath(dinfo)
1046 dn = self._dirName if full else os.path.basename(self._dirName)
1047 BrowserItem.__init__(self, parent, dn)
1048
1049 self.type_ = BrowserItemDirectory
1050 if (
1051 not Utilities.isDrive(self._dirName) and
1052 os.path.lexists(self._dirName) and
1053 os.path.islink(self._dirName)
1054 ):
1055 self.symlink = True
1056 self.icon = UI.PixmapCache.getSymlinkIcon("dirClosed")
1057 else:
1058 self.icon = UI.PixmapCache.getIcon("dirClosed")
1059 self._populated = False
1060 self._lazyPopulation = True
1061
1062 def setName(self, dinfo, full=True):
1063 """
1064 Public method to set the directory name.
1065
1066 @param dinfo dinfo is the string for the directory (string)
1067 @param full flag indicating full pathname should be displayed (boolean)
1068 """
1069 self._dirName = os.path.abspath(dinfo)
1070 dn = self._dirName if full else os.path.basename(self._dirName)
1071 self.itemData[0] = dn
1072
1073 def dirName(self):
1074 """
1075 Public method returning the directory name.
1076
1077 @return directory name (string)
1078 """
1079 return self._dirName
1080
1081 def name(self):
1082 """
1083 Public method to return the name of the item.
1084
1085 @return name of the item (string)
1086 """
1087 return self._dirName
1088
1089 def lessThan(self, other, column, order):
1090 """
1091 Public method to check, if the item is less than the other one.
1092
1093 @param other reference to item to compare against (BrowserItem)
1094 @param column column number to use for the comparison (integer)
1095 @param order sort order (Qt.SortOrder) (for special sorting)
1096 @return true, if this item is less than other (boolean)
1097 """
1098 if (
1099 issubclass(other.__class__, BrowserFileItem) and
1100 Preferences.getUI("BrowsersListFoldersFirst")
1101 ):
1102 return order == Qt.SortOrder.AscendingOrder
1103
1104 return BrowserItem.lessThan(self, other, column, order)
1105
1106
1107 class BrowserSysPathItem(BrowserItem):
1108 """
1109 Class implementing the data structure for browser sys.path items.
1110 """
1111 def __init__(self, parent):
1112 """
1113 Constructor
1114
1115 @param parent parent item
1116 """
1117 BrowserItem.__init__(self, parent, "sys.path")
1118
1119 self.type_ = BrowserItemSysPath
1120 self.icon = UI.PixmapCache.getIcon("filePython")
1121 self._populated = False
1122 self._lazyPopulation = True
1123
1124 def name(self):
1125 """
1126 Public method to return the name of the item.
1127
1128 @return name of the item (string)
1129 """
1130 return "sys.path"
1131
1132
1133 class BrowserFileItem(BrowserItem):
1134 """
1135 Class implementing the data structure for browser file items.
1136 """
1137 def __init__(self, parent, finfo, full=True, sourceLanguage=""):
1138 """
1139 Constructor
1140
1141 @param parent parent item
1142 @param finfo the string for the file (string)
1143 @param full flag indicating full pathname should be displayed (boolean)
1144 @param sourceLanguage source code language of the project (string)
1145 """
1146 BrowserItem.__init__(self, parent, os.path.basename(finfo))
1147
1148 self.type_ = BrowserItemFile
1149 self.fileext = os.path.splitext(finfo)[1].lower()
1150 self._filename = os.path.abspath(finfo)
1151 self._dirName = os.path.dirname(finfo)
1152 self.sourceLanguage = sourceLanguage
1153
1154 self._moduleName = ''
1155
1156 pixName = ""
1157 if self.isPython3File():
1158 pixName = "filePython"
1159 self._populated = False
1160 self._lazyPopulation = True
1161 self._moduleName = os.path.basename(finfo)
1162 elif self.isCythonFile():
1163 pixName = "lexerCython"
1164 self._populated = False
1165 self._lazyPopulation = True
1166 self._moduleName = os.path.basename(finfo)
1167 elif self.isRubyFile():
1168 pixName = "fileRuby"
1169 self._populated = False
1170 self._lazyPopulation = True
1171 self._moduleName = os.path.basename(finfo)
1172 elif self.isDesignerFile():
1173 pixName = "fileDesigner"
1174 elif self.isLinguistFile():
1175 if self.fileext == '.ts':
1176 pixName = "fileLinguist"
1177 else:
1178 pixName = "fileLinguist2"
1179 elif self.isResourcesFile():
1180 pixName = "fileResource"
1181 elif self.isProjectFile():
1182 pixName = "fileProject"
1183 elif self.isMultiProjectFile():
1184 pixName = "fileMultiProject"
1185 elif self.isIdlFile():
1186 pixName = "fileIDL"
1187 self._populated = False
1188 self._lazyPopulation = True
1189 self._moduleName = os.path.basename(finfo)
1190 elif self.isProtobufFile():
1191 pixName = "protobuf"
1192 self._populated = False
1193 self._lazyPopulation = True
1194 self._moduleName = os.path.basename(finfo)
1195 elif self.isSvgFile():
1196 pixName = "fileSvg"
1197 elif self.isPixmapFile():
1198 pixName = "filePixmap"
1199 elif self.isDFile():
1200 pixName = "fileD"
1201 elif self.isJavaScriptFile():
1202 pixName = "fileJavascript"
1203 self._populated = False
1204 self._lazyPopulation = True
1205 self._moduleName = os.path.basename(finfo)
1206 elif self.isEricGraphicsFile():
1207 pixName = "fileUML"
1208 else:
1209 pixName = "fileMisc"
1210
1211 if os.path.lexists(self._filename) and os.path.islink(self._filename):
1212 self.symlink = True
1213 self.icon = UI.PixmapCache.getSymlinkIcon(pixName)
1214 else:
1215 self.icon = UI.PixmapCache.getIcon(pixName)
1216
1217 def setName(self, finfo, full=True):
1218 """
1219 Public method to set the directory name.
1220
1221 @param finfo the string for the file (string)
1222 @param full flag indicating full pathname should be displayed (boolean)
1223 """
1224 self._filename = os.path.abspath(finfo)
1225 self.itemData[0] = os.path.basename(finfo)
1226 if (
1227 self.isPython3File() or
1228 self.isRubyFile() or
1229 self.isIdlFile() or
1230 self.isProtobufFile()
1231 ):
1232 self._dirName = os.path.dirname(finfo)
1233 self._moduleName = os.path.basename(finfo)
1234
1235 def fileName(self):
1236 """
1237 Public method returning the filename.
1238
1239 @return filename (string)
1240 """
1241 return self._filename
1242
1243 def name(self):
1244 """
1245 Public method to return the name of the item.
1246
1247 @return name of the item (string)
1248 """
1249 return self._filename
1250
1251 def fileExt(self):
1252 """
1253 Public method returning the file extension.
1254
1255 @return file extension (string)
1256 """
1257 return self.fileext
1258
1259 def dirName(self):
1260 """
1261 Public method returning the directory name.
1262
1263 @return directory name (string)
1264 """
1265 return self._dirName
1266
1267 def moduleName(self):
1268 """
1269 Public method returning the module name.
1270
1271 @return module name (string)
1272 """
1273 return self._moduleName
1274
1275 def isPython3File(self):
1276 """
1277 Public method to check, if this file is a Python3 script.
1278
1279 @return flag indicating a Python3 file
1280 @rtype bool
1281 """
1282 return (
1283 self.fileext in Preferences.getPython("Python3Extensions") or
1284 (self.fileext == "" and self.sourceLanguage == "Python3")
1285 )
1286
1287 def isCythonFile(self):
1288 """
1289 Public method to check, if this file is a Cython file.
1290
1291 @return flag indicating a Cython file
1292 @rtype bool
1293 """
1294 return (
1295 self.fileext in (".pyx", ".pxd", ".pxi") or
1296 (self.fileext == "" and self.sourceLanguage == "Cython")
1297 )
1298
1299 def isRubyFile(self):
1300 """
1301 Public method to check, if this file is a Ruby script.
1302
1303 @return flag indicating a Ruby file
1304 @rtype bool
1305 """
1306 return (
1307 self.fileext == '.rb' or
1308 (self.fileext == "" and self.sourceLanguage == "Ruby")
1309 )
1310
1311 def isDesignerFile(self):
1312 """
1313 Public method to check, if this file is a Qt-Designer file.
1314
1315 @return flag indicating a Qt-Designer file
1316 @rtype bool
1317 """
1318 return self.fileext == '.ui'
1319
1320 def isLinguistFile(self):
1321 """
1322 Public method to check, if this file is a Qt-Linguist file.
1323
1324 @return flag indicating a Qt-Linguist file
1325 @rtype bool
1326 """
1327 return self.fileext in ['.ts', '.qm']
1328
1329 def isResourcesFile(self):
1330 """
1331 Public method to check, if this file is a Qt-Resources file.
1332
1333 @return flag indicating a Qt-Resources file
1334 @rtype bool
1335 """
1336 return self.fileext == '.qrc'
1337
1338 def isProjectFile(self):
1339 """
1340 Public method to check, if this file is an eric project file.
1341
1342 @return flag indicating an eric project file
1343 @rtype bool
1344 """
1345 return self.fileext in ('.epj', '.e4p')
1346
1347 def isMultiProjectFile(self):
1348 """
1349 Public method to check, if this file is an eric multi project file.
1350
1351 @return flag indicating an eric project file
1352 @rtype bool
1353 """
1354 return self.fileext in ('.emj', '.e4m', '.e5m')
1355
1356 def isIdlFile(self):
1357 """
1358 Public method to check, if this file is a CORBA IDL file.
1359
1360 @return flag indicating a CORBA IDL file
1361 @rtype bool
1362 """
1363 return self.fileext == '.idl'
1364
1365 def isProtobufFile(self):
1366 """
1367 Public method to check, if this file is a Google Protocol Buffer file.
1368
1369 @return flag indicating a protobuf file
1370 @rtype bool
1371 """
1372 return self.fileext == ".proto"
1373
1374 def isJavaScriptFile(self):
1375 """
1376 Public method to check, if this file is a JavaScript file.
1377
1378 @return flag indicating a JavaScript file
1379 @rtype bool
1380 """
1381 return self.fileext == '.js'
1382
1383 def isPixmapFile(self):
1384 """
1385 Public method to check, if this file is a pixmap file.
1386
1387 @return flag indicating a pixmap file
1388 @rtype bool
1389 """
1390 return self.fileext[1:] in QImageReader.supportedImageFormats()
1391
1392 def isSvgFile(self):
1393 """
1394 Public method to check, if this file is a SVG file.
1395
1396 @return flag indicating a SVG file
1397 @rtype bool
1398 """
1399 return self.fileext == '.svg'
1400
1401 def isDFile(self):
1402 """
1403 Public method to check, if this file is a D file.
1404
1405 @return flag indicating a D file (boolean)
1406 """
1407 return (
1408 self.fileext in ['.d', '.di'] or
1409 (self.fileext == "" and self.sourceLanguage == "D")
1410 )
1411
1412 def isEricGraphicsFile(self):
1413 """
1414 Public method to check, if this is an eric graphics file.
1415
1416 @return flag indicating an eric graphics file
1417 @rtype bool
1418 """
1419 return self.fileext in ('.egj', '.e5g')
1420
1421 def lessThan(self, other, column, order):
1422 """
1423 Public method to check, if the item is less than the other one.
1424
1425 @param other reference to item to compare against (BrowserItem)
1426 @param column column number to use for the comparison (integer)
1427 @param order sort order (Qt.SortOrder) (for special sorting)
1428 @return true, if this item is less than other (boolean)
1429 """
1430 if (
1431 not issubclass(other.__class__, BrowserFileItem) and
1432 Preferences.getUI("BrowsersListFoldersFirst")
1433 ):
1434 return order == Qt.SortOrder.DescendingOrder
1435
1436 if issubclass(other.__class__, BrowserFileItem):
1437 sinit = os.path.basename(self._filename).startswith('__init__.py')
1438 oinit = os.path.basename(other.fileName()).startswith(
1439 '__init__.py')
1440 if sinit and not oinit:
1441 return order == Qt.SortOrder.AscendingOrder
1442 if not sinit and oinit:
1443 return order == Qt.SortOrder.DescendingOrder
1444
1445 return BrowserItem.lessThan(self, other, column, order)
1446
1447
1448 class BrowserClassItem(BrowserItem):
1449 """
1450 Class implementing the data structure for browser class items.
1451 """
1452 def __init__(self, parent, cl, filename):
1453 """
1454 Constructor
1455
1456 @param parent parent item
1457 @param cl Class object to be shown
1458 @param filename filename of the file defining this class
1459 """
1460 name = cl.name
1461 if hasattr(cl, 'super') and cl.super:
1462 supers = []
1463 for sup in cl.super:
1464 try:
1465 sname = sup.name
1466 if sup.module != cl.module:
1467 sname = "{0}.{1}".format(sup.module, sname)
1468 except AttributeError:
1469 sname = sup
1470 supers.append(sname)
1471 name += "({0})".format(", ".join(supers))
1472
1473 BrowserItem.__init__(self, parent, name)
1474
1475 self.type_ = BrowserItemClass
1476 self._name = name
1477 self._classObject = cl
1478 self._filename = filename
1479
1480 import Utilities.ClassBrowsers.ClbrBaseClasses
1481 self.isfunction = isinstance(
1482 self._classObject,
1483 Utilities.ClassBrowsers.ClbrBaseClasses.Function)
1484 self.ismodule = isinstance(
1485 self._classObject,
1486 Utilities.ClassBrowsers.ClbrBaseClasses.Module)
1487 self.isenum = isinstance(
1488 self._classObject,
1489 Utilities.ClassBrowsers.ClbrBaseClasses.Enum)
1490 if self.isfunction:
1491 if cl.isPrivate():
1492 self.icon = UI.PixmapCache.getIcon("method_private")
1493 elif cl.isProtected():
1494 self.icon = UI.PixmapCache.getIcon("method_protected")
1495 else:
1496 self.icon = UI.PixmapCache.getIcon("method")
1497 self.itemData[0] = "{0}({1})".format(
1498 name, ", ".join(self._classObject.parameters))
1499 if self._classObject.annotation:
1500 self.itemData[0] = "{0} {1}".format(
1501 self.itemData[0], self._classObject.annotation)
1502 #- if no defaults are wanted
1503 #- ....format(name,
1504 #- ", ".join([e.split('=')[0].strip()
1505 #- for e in self._classObject.parameters]))
1506 elif self.ismodule:
1507 self.icon = UI.PixmapCache.getIcon("module")
1508 elif self.isenum:
1509 self.icon = UI.PixmapCache.getIcon("attribute")
1510 else:
1511 if cl.isPrivate():
1512 self.icon = UI.PixmapCache.getIcon("class_private")
1513 elif cl.isProtected():
1514 self.icon = UI.PixmapCache.getIcon("class_protected")
1515 else:
1516 self.icon = UI.PixmapCache.getIcon("class")
1517 if (
1518 self._classObject and
1519 (self._classObject.methods or
1520 self._classObject.classes or
1521 self._classObject.attributes or
1522 self._classObject.globals)
1523 ):
1524 self._populated = False
1525 self._lazyPopulation = True
1526
1527 def name(self):
1528 """
1529 Public method to return the name of the item.
1530
1531 @return name of the item (string)
1532 """
1533 return '{0}@@{1}'.format(self._filename, self.lineno())
1534
1535 def fileName(self):
1536 """
1537 Public method returning the filename.
1538
1539 @return filename (string)
1540 """
1541 return self._filename
1542
1543 def classObject(self):
1544 """
1545 Public method returning the class object.
1546
1547 @return reference to the class object
1548 """
1549 return self._classObject
1550
1551 def lineno(self):
1552 """
1553 Public method returning the line number defining this object.
1554
1555 @return line number defining the object (integer)
1556 """
1557 return self._classObject.lineno
1558
1559 def boundaries(self):
1560 """
1561 Public method returning the boundaries of the method definition.
1562
1563 @return tuple with start end end line number (integer, integer)
1564 """
1565 return (self._classObject.lineno, self._classObject.endlineno)
1566
1567 def lessThan(self, other, column, order):
1568 """
1569 Public method to check, if the item is less than the other one.
1570
1571 @param other reference to item to compare against (BrowserItem)
1572 @param column column number to use for the comparison (integer)
1573 @param order sort order (Qt.SortOrder) (for special sorting)
1574 @return true, if this item is less than other (boolean)
1575 """
1576 if issubclass(
1577 other.__class__,
1578 (BrowserCodingItem, BrowserClassAttributesItem)
1579 ):
1580 return order == Qt.SortOrder.DescendingOrder
1581
1582 if (
1583 Preferences.getUI("BrowsersListContentsByOccurrence") and
1584 column == 0
1585 ):
1586 if order == Qt.SortOrder.AscendingOrder:
1587 return self.lineno() < other.lineno()
1588 else:
1589 return self.lineno() > other.lineno()
1590
1591 return BrowserItem.lessThan(self, other, column, order)
1592
1593 def isPublic(self):
1594 """
1595 Public method returning the public visibility status.
1596
1597 @return flag indicating public visibility (boolean)
1598 """
1599 return self._classObject.isPublic()
1600
1601
1602 class BrowserMethodItem(BrowserItem):
1603 """
1604 Class implementing the data structure for browser method items.
1605 """
1606 def __init__(self, parent, fn, filename):
1607 """
1608 Constructor
1609
1610 @param parent parent item
1611 @param fn Function object to be shown
1612 @param filename filename of the file defining this class (string)
1613 """
1614 name = fn.name
1615 BrowserItem.__init__(self, parent, name)
1616
1617 import Utilities.ClassBrowsers.ClbrBaseClasses
1618 self.type_ = BrowserItemMethod
1619 self._name = name
1620 self._functionObject = fn
1621 self._filename = filename
1622 if (
1623 self._functionObject.modifier ==
1624 Utilities.ClassBrowsers.ClbrBaseClasses.Function.Static
1625 ):
1626 self.icon = UI.PixmapCache.getIcon("method_static")
1627 elif (
1628 self._functionObject.modifier ==
1629 Utilities.ClassBrowsers.ClbrBaseClasses.Function.Class
1630 ):
1631 self.icon = UI.PixmapCache.getIcon("method_class")
1632 elif self._functionObject.isPrivate():
1633 self.icon = UI.PixmapCache.getIcon("method_private")
1634 elif self._functionObject.isProtected():
1635 self.icon = UI.PixmapCache.getIcon("method_protected")
1636 else:
1637 self.icon = UI.PixmapCache.getIcon("method")
1638 self.itemData[0] = "{0}({1})".format(
1639 name, ", ".join(self._functionObject.parameters))
1640 if self._functionObject.annotation:
1641 self.itemData[0] = "{0} {1}".format(
1642 self.itemData[0], self._functionObject.annotation)
1643 # if no defaults are wanted
1644 # ....format(name,
1645 # ", ".join([e.split('=')[0].strip()
1646 # for e in self._functionObject.parameters]))
1647 if (
1648 self._functionObject and
1649 (self._functionObject.methods or self._functionObject.classes)
1650 ):
1651 self._populated = False
1652 self._lazyPopulation = True
1653
1654 def name(self):
1655 """
1656 Public method to return the name of the item.
1657
1658 @return name of the item (string)
1659 """
1660 return '{0}@@{1}'.format(self._filename, self.lineno())
1661
1662 def fileName(self):
1663 """
1664 Public method returning the filename.
1665
1666 @return filename (string)
1667 """
1668 return self._filename
1669
1670 def functionObject(self):
1671 """
1672 Public method returning the function object.
1673
1674 @return reference to the function object
1675 """
1676 return self._functionObject
1677
1678 def lineno(self):
1679 """
1680 Public method returning the line number defining this object.
1681
1682 @return line number defining the object (integer)
1683 """
1684 return self._functionObject.lineno
1685
1686 def boundaries(self):
1687 """
1688 Public method returning the boundaries of the method definition.
1689
1690 @return tuple with start end end line number (integer, integer)
1691 """
1692 return (self._functionObject.lineno, self._functionObject.endlineno)
1693
1694 def lessThan(self, other, column, order):
1695 """
1696 Public method to check, if the item is less than the other one.
1697
1698 @param other reference to item to compare against (BrowserItem)
1699 @param column column number to use for the comparison (integer)
1700 @param order sort order (Qt.SortOrder) (for special sorting)
1701 @return true, if this item is less than other (boolean)
1702 """
1703 if issubclass(other.__class__, BrowserMethodItem):
1704 if self._name.startswith('__init__'):
1705 return order == Qt.SortOrder.AscendingOrder
1706 if other._name.startswith('__init__'):
1707 return order == Qt.SortOrder.DescendingOrder
1708 elif issubclass(other.__class__, BrowserClassAttributesItem):
1709 return order == Qt.SortOrder.DescendingOrder
1710
1711 if (
1712 Preferences.getUI("BrowsersListContentsByOccurrence") and
1713 column == 0
1714 ):
1715 if order == Qt.SortOrder.AscendingOrder:
1716 return self.lineno() < other.lineno()
1717 else:
1718 return self.lineno() > other.lineno()
1719
1720 return BrowserItem.lessThan(self, other, column, order)
1721
1722 def isPublic(self):
1723 """
1724 Public method returning the public visibility status.
1725
1726 @return flag indicating public visibility (boolean)
1727 """
1728 return self._functionObject.isPublic()
1729
1730
1731 class BrowserClassAttributesItem(BrowserItem):
1732 """
1733 Class implementing the data structure for browser class attributes items.
1734 """
1735 def __init__(self, parent, attributes, text, isClass=False):
1736 """
1737 Constructor
1738
1739 @param parent parent item
1740 @param attributes list of attributes
1741 @param text text to be shown by this item (string)
1742 @param isClass flag indicating class attributes (boolean)
1743 """
1744 BrowserItem.__init__(self, parent, text)
1745
1746 self.type_ = BrowserItemAttributes
1747 self._attributes = attributes.copy()
1748 self._populated = False
1749 self._lazyPopulation = True
1750 if isClass:
1751 self.icon = UI.PixmapCache.getIcon("attributes_class")
1752 else:
1753 self.icon = UI.PixmapCache.getIcon("attributes")
1754 self.__isClass = isClass
1755
1756 def name(self):
1757 """
1758 Public method to return the name of the item.
1759
1760 @return name of the item (string)
1761 """
1762 return '{0}@@{1}'.format(self.parentItem.name(), self.data(0))
1763
1764 def attributes(self):
1765 """
1766 Public method returning the attribute list.
1767
1768 @return reference to the list of attributes
1769 """
1770 return self._attributes
1771
1772 def isClassAttributes(self):
1773 """
1774 Public method returning the attributes type.
1775
1776 @return flag indicating class attributes (boolean)
1777 """
1778 return self.__isClass
1779
1780 def lessThan(self, other, column, order):
1781 """
1782 Public method to check, if the item is less than the other one.
1783
1784 @param other reference to item to compare against (BrowserItem)
1785 @param column column number to use for the comparison (integer)
1786 @param order sort order (Qt.SortOrder) (for special sorting)
1787 @return true, if this item is less than other (boolean)
1788 """
1789 if issubclass(other.__class__, BrowserCodingItem):
1790 return order == Qt.SortOrder.DescendingOrder
1791 elif issubclass(
1792 other.__class__,
1793 (BrowserClassItem, BrowserMethodItem)
1794 ):
1795 return order == Qt.SortOrder.AscendingOrder
1796
1797 return BrowserItem.lessThan(self, other, column, order)
1798
1799
1800 class BrowserClassAttributeItem(BrowserItem):
1801 """
1802 Class implementing the data structure for browser class attribute items.
1803 """
1804 def __init__(self, parent, attribute, isClass=False):
1805 """
1806 Constructor
1807
1808 @param parent parent item
1809 @param attribute reference to the attribute object
1810 @param isClass flag indicating a class attribute (boolean)
1811 """
1812 BrowserItem.__init__(self, parent, attribute.name)
1813
1814 self.type_ = BrowserItemAttribute
1815 self._attributeObject = attribute
1816 self.__public = attribute.isPublic()
1817 if isClass:
1818 self.icon = UI.PixmapCache.getIcon("attribute_class")
1819 elif attribute.isPrivate():
1820 self.icon = UI.PixmapCache.getIcon("attribute_private")
1821 elif attribute.isProtected():
1822 self.icon = UI.PixmapCache.getIcon("attribute_protected")
1823 else:
1824 self.icon = UI.PixmapCache.getIcon("attribute")
1825
1826 def isPublic(self):
1827 """
1828 Public method returning the public visibility status.
1829
1830 @return flag indicating public visibility (boolean)
1831 """
1832 return self.__public
1833
1834 def attributeObject(self):
1835 """
1836 Public method returning the class object.
1837
1838 @return reference to the class object
1839 """
1840 return self._attributeObject
1841
1842 def fileName(self):
1843 """
1844 Public method returning the filename.
1845
1846 @return filename (string)
1847 """
1848 return self._attributeObject.file
1849
1850 def lineno(self):
1851 """
1852 Public method returning the line number defining this object.
1853
1854 @return line number defining the object (integer)
1855 """
1856 return self._attributeObject.lineno
1857
1858 def linenos(self):
1859 """
1860 Public method returning the line numbers this object is assigned to.
1861
1862 @return line number the object is assigned to (list of integers)
1863 """
1864 return self._attributeObject.linenos[:]
1865
1866 def lessThan(self, other, column, order):
1867 """
1868 Public method to check, if the item is less than the other one.
1869
1870 @param other reference to item to compare against (BrowserItem)
1871 @param column column number to use for the comparison (integer)
1872 @param order sort order (Qt.SortOrder) (for special sorting)
1873 @return true, if this item is less than other (boolean)
1874 """
1875 if (
1876 Preferences.getUI("BrowsersListContentsByOccurrence") and
1877 column == 0
1878 ):
1879 if order == Qt.SortOrder.AscendingOrder:
1880 return self.lineno() < other.lineno()
1881 else:
1882 return self.lineno() > other.lineno()
1883
1884 return BrowserItem.lessThan(self, other, column, order)
1885
1886
1887 class BrowserGlobalsItem(BrowserClassAttributesItem):
1888 """
1889 Class implementing the data structure for browser globals items.
1890 """
1891 def __init__(self, parent, attributes, text):
1892 """
1893 Constructor
1894
1895 @param parent parent item
1896 @param attributes list of attributes
1897 @param text text to be shown by this item (string)
1898 """
1899 BrowserClassAttributesItem.__init__(self, parent, attributes, text)
1900
1901
1902 class BrowserCodingItem(BrowserItem):
1903 """
1904 Class implementing the data structure for browser coding items.
1905 """
1906 def __init__(self, parent, text, linenumber):
1907 """
1908 Constructor
1909
1910 @param parent parent item
1911 @type BrowserItem
1912 @param text text to be shown by this item
1913 @type str
1914 @param linenumber line number of the coding line
1915 @type int
1916 """
1917 BrowserItem.__init__(self, parent, text)
1918
1919 self.type_ = BrowserItemCoding
1920 self.icon = UI.PixmapCache.getIcon("textencoding")
1921
1922 self.__lineno = linenumber
1923
1924 def lineno(self):
1925 """
1926 Public method returning the line number of the coding line.
1927
1928 @return line number defining the coding line
1929 @rtype int
1930 """
1931 return self.__lineno
1932
1933 def lessThan(self, other, column, order):
1934 """
1935 Public method to check, if the item is less than the other one.
1936
1937 @param other reference to item to compare against (BrowserItem)
1938 @param column column number to use for the comparison (integer)
1939 @param order sort order (Qt.SortOrder) (for special sorting)
1940 @return true, if this item is less than other (boolean)
1941 """
1942 if issubclass(
1943 other.__class__,
1944 (BrowserClassItem, BrowserClassAttributesItem, BrowserImportItem)
1945 ):
1946 return order == Qt.SortOrder.AscendingOrder
1947
1948 return BrowserItem.lessThan(self, other, column, order)
1949
1950
1951 class BrowserImportsItem(BrowserItem):
1952 """
1953 Class implementing the data structure for browser import items.
1954 """
1955 def __init__(self, parent, text):
1956 """
1957 Constructor
1958
1959 @param parent parent item
1960 @param text text to be shown by this item (string)
1961 """
1962 BrowserItem.__init__(self, parent, text)
1963
1964 self.type_ = BrowserItemImports
1965 self.icon = UI.PixmapCache.getIcon("imports")
1966
1967 def lessThan(self, other, column, order):
1968 """
1969 Public method to check, if the item is less than the other one.
1970
1971 @param other reference to item to compare against (BrowserItem)
1972 @param column column number to use for the comparison (integer)
1973 @param order sort order (Qt.SortOrder) (for special sorting)
1974 @return true, if this item is less than other (boolean)
1975 """
1976 if issubclass(
1977 other.__class__,
1978 (BrowserClassItem, BrowserClassAttributesItem)
1979 ):
1980 return order == Qt.SortOrder.AscendingOrder
1981
1982 return BrowserItem.lessThan(self, other, column, order)
1983
1984
1985 class BrowserImportItem(BrowserItem):
1986 """
1987 Class implementing the data structure for browser imported module and
1988 imported names items.
1989 """
1990 def __init__(self, parent, text, filename, lineNumbers, isModule=True):
1991 """
1992 Constructor
1993
1994 @param parent parent item
1995 @param text text to be shown by this item (string)
1996 @param filename name of the file (string)
1997 @param lineNumbers list of line numbers of the import statement
1998 (list of integer)
1999 @param isModule flag indicating a module item entry (boolean)
2000 """
2001 BrowserItem.__init__(self, parent, text)
2002
2003 self.__filename = filename
2004 self.__linenos = lineNumbers[:]
2005
2006 self.type_ = BrowserItemImport
2007 if isModule:
2008 self.icon = UI.PixmapCache.getIcon("importedModule")
2009 else:
2010 self.icon = UI.PixmapCache.getIcon("importedName")
2011
2012 def fileName(self):
2013 """
2014 Public method returning the filename.
2015
2016 @return filename (string)
2017 """
2018 return self.__filename
2019
2020 def lineno(self):
2021 """
2022 Public method returning the line number of the first import.
2023
2024 @return line number of the first import (integer)
2025 """
2026 return self.__linenos[0]
2027
2028 def linenos(self):
2029 """
2030 Public method returning the line numbers of all imports.
2031
2032 @return line numbers of all imports (list of integers)
2033 """
2034 return self.__linenos[:]
2035
2036 def lessThan(self, other, column, order):
2037 """
2038 Public method to check, if the item is less than the other one.
2039
2040 @param other reference to item to compare against (BrowserItem)
2041 @param column column number to use for the comparison (integer)
2042 @param order sort order (Qt.SortOrder) (for special sorting)
2043 @return true, if this item is less than other (boolean)
2044 """
2045 if (
2046 Preferences.getUI("BrowsersListContentsByOccurrence") and
2047 column == 0
2048 ):
2049 if order == Qt.SortOrder.AscendingOrder:
2050 return self.lineno() < other.lineno()
2051 else:
2052 return self.lineno() > other.lineno()
2053
2054 return BrowserItem.lessThan(self, other, column, order)

eric ide

mercurial