eric7/UI/BrowserModel.py

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

eric ide

mercurial